Data schema spec fix: TSON instead of JSON (#3566)
This commit is contained in:
@@ -105,6 +105,12 @@ repos:
|
||||
types: [javascript]
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: vitest-type-check
|
||||
name: vitest
|
||||
entry: bash -c 'cd skyvern-frontend && ([ -d node_modules ] || npm ci) && npm run test'
|
||||
language: system
|
||||
pass_filenames: false
|
||||
files: ^skyvern-frontend/
|
||||
- id: alembic-check
|
||||
name: Alembic Check
|
||||
entry: ./run_alembic_check.sh
|
||||
|
||||
519
skyvern-frontend/package-lock.json
generated
519
skyvern-frontend/package-lock.json
generated
@@ -85,7 +85,8 @@
|
||||
"prettier-plugin-tailwindcss": "^0.6.5",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.5.3",
|
||||
"vite": "^5.4.19"
|
||||
"vite": "^5.4.19",
|
||||
"vitest": "^3.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@aashutoshrathi/word-wrap": {
|
||||
@@ -946,9 +947,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.25",
|
||||
@@ -3810,6 +3812,16 @@
|
||||
"react": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/chai": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz",
|
||||
"integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/deep-eql": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/d3-color": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
|
||||
@@ -3853,6 +3865,13 @@
|
||||
"@types/d3-selection": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/deep-eql": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
|
||||
"integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||
@@ -4183,6 +4202,94 @@
|
||||
"vite": "^4 || ^5"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/expect": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz",
|
||||
"integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/spy": "3.2.4",
|
||||
"@vitest/utils": "3.2.4",
|
||||
"chai": "^5.2.0",
|
||||
"tinyrainbow": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/pretty-format": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz",
|
||||
"integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tinyrainbow": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/runner": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz",
|
||||
"integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/utils": "3.2.4",
|
||||
"pathe": "^2.0.3",
|
||||
"strip-literal": "^3.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/snapshot": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz",
|
||||
"integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "3.2.4",
|
||||
"magic-string": "^0.30.17",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/spy": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz",
|
||||
"integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tinyspy": "^4.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/utils": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz",
|
||||
"integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "3.2.4",
|
||||
"loupe": "^3.1.4",
|
||||
"tinyrainbow": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/@xyflow/react": {
|
||||
"version": "12.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.1.1.tgz",
|
||||
@@ -4350,6 +4457,16 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/assertion-error": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
|
||||
"integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
@@ -4529,6 +4646,16 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/cac": {
|
||||
"version": "6.7.14",
|
||||
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
|
||||
"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
@@ -4593,6 +4720,23 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/chai": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz",
|
||||
"integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"assertion-error": "^2.0.1",
|
||||
"check-error": "^2.1.1",
|
||||
"deep-eql": "^5.0.1",
|
||||
"loupe": "^3.1.0",
|
||||
"pathval": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
@@ -4609,6 +4753,16 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/check-error": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
|
||||
"integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
@@ -5010,6 +5164,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/deep-eql": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
|
||||
"integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-is": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
||||
@@ -5214,6 +5378,13 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
|
||||
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
@@ -5523,6 +5694,16 @@
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-walker": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
|
||||
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/esutils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
@@ -5569,6 +5750,16 @@
|
||||
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/expect-type": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz",
|
||||
"integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.21.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||
@@ -6635,6 +6826,23 @@
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/loupe": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz",
|
||||
"integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.19",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
|
||||
"integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
@@ -7085,6 +7293,23 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/pathe": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
|
||||
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pathval": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz",
|
||||
"integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.16"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
@@ -8112,6 +8337,13 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/siginfo": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
|
||||
"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||
@@ -8168,6 +8400,13 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/stackback": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
|
||||
"integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/statuses": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
@@ -8176,6 +8415,13 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/std-env": {
|
||||
"version": "3.9.0",
|
||||
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz",
|
||||
"integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/string-argv": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
|
||||
@@ -8303,6 +8549,26 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-literal": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz",
|
||||
"integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-tokens": "^9.0.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-literal/node_modules/js-tokens": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
|
||||
"integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/style-mod": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
|
||||
@@ -8478,6 +8744,98 @@
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/tinybench": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
|
||||
"integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinyexec": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
|
||||
"integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.15",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
||||
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.5.0",
|
||||
"picomatch": "^4.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/fdir": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"picomatch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/tinypool": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz",
|
||||
"integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyrainbow": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
|
||||
"integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyspy": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz",
|
||||
"integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@@ -8774,6 +9132,142 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vite-node": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz",
|
||||
"integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cac": "^6.7.14",
|
||||
"debug": "^4.4.1",
|
||||
"es-module-lexer": "^1.7.0",
|
||||
"pathe": "^2.0.3",
|
||||
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
|
||||
},
|
||||
"bin": {
|
||||
"vite-node": "vite-node.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
}
|
||||
},
|
||||
"node_modules/vitest": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz",
|
||||
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/expect": "3.2.4",
|
||||
"@vitest/mocker": "3.2.4",
|
||||
"@vitest/pretty-format": "^3.2.4",
|
||||
"@vitest/runner": "3.2.4",
|
||||
"@vitest/snapshot": "3.2.4",
|
||||
"@vitest/spy": "3.2.4",
|
||||
"@vitest/utils": "3.2.4",
|
||||
"chai": "^5.2.0",
|
||||
"debug": "^4.4.1",
|
||||
"expect-type": "^1.2.1",
|
||||
"magic-string": "^0.30.17",
|
||||
"pathe": "^2.0.3",
|
||||
"picomatch": "^4.0.2",
|
||||
"std-env": "^3.9.0",
|
||||
"tinybench": "^2.9.0",
|
||||
"tinyexec": "^0.3.2",
|
||||
"tinyglobby": "^0.2.14",
|
||||
"tinypool": "^1.1.1",
|
||||
"tinyrainbow": "^2.0.0",
|
||||
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0",
|
||||
"vite-node": "3.2.4",
|
||||
"why-is-node-running": "^2.3.0"
|
||||
},
|
||||
"bin": {
|
||||
"vitest": "vitest.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@edge-runtime/vm": "*",
|
||||
"@types/debug": "^4.1.12",
|
||||
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
|
||||
"@vitest/browser": "3.2.4",
|
||||
"@vitest/ui": "3.2.4",
|
||||
"happy-dom": "*",
|
||||
"jsdom": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@edge-runtime/vm": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/debug": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"@vitest/browser": {
|
||||
"optional": true
|
||||
},
|
||||
"@vitest/ui": {
|
||||
"optional": true
|
||||
},
|
||||
"happy-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"jsdom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vitest/node_modules/@vitest/mocker": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz",
|
||||
"integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/spy": "3.2.4",
|
||||
"estree-walker": "^3.0.3",
|
||||
"magic-string": "^0.30.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"msw": "^2.4.9",
|
||||
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"msw": {
|
||||
"optional": true
|
||||
},
|
||||
"vite": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vitest/node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/w3c-keyname": {
|
||||
"version": "2.2.8",
|
||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||
@@ -8793,6 +9287,23 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/why-is-node-running": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
|
||||
"integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"siginfo": "^2.0.0",
|
||||
"stackback": "0.0.2"
|
||||
},
|
||||
"bin": {
|
||||
"why-is-node-running": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"precommit": "lint-staged",
|
||||
"run-artifact-server": "node artifactServer.js",
|
||||
"serve": "npm run build && node localServer.js",
|
||||
"test": "vitest run",
|
||||
"start": "npm run serve & npm run run-artifact-server"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -93,7 +94,8 @@
|
||||
"prettier-plugin-tailwindcss": "^0.6.5",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.5.3",
|
||||
"vite": "^5.4.19"
|
||||
"vite": "^5.4.19",
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
"lint-staged": {
|
||||
"src/**/*.{js,jsx,ts,tsx}": [
|
||||
|
||||
@@ -17,6 +17,7 @@ import { AutoResizingTextarea } from "../AutoResizingTextarea/AutoResizingTextar
|
||||
import { Button } from "../ui/button";
|
||||
import { AxiosError } from "axios";
|
||||
import { toast } from "../ui/use-toast";
|
||||
import { TSON } from "@/util/tson";
|
||||
import { cn } from "@/util/utils";
|
||||
|
||||
type Props = {
|
||||
@@ -36,42 +37,13 @@ function WorkflowDataSchemaInputGroup({
|
||||
const [generateWithAIActive, setGenerateWithAIActive] = useState(false);
|
||||
const [generateWithAIPrompt, setGenerateWithAIPrompt] = useState("");
|
||||
|
||||
function computeJsonError(
|
||||
jsonText: string,
|
||||
): { message: string; line?: number; column?: number } | null {
|
||||
try {
|
||||
JSON.parse(jsonText);
|
||||
return null;
|
||||
} catch (e) {
|
||||
const message = e instanceof Error ? e.message : "Invalid JSON";
|
||||
// Try to extract position and compute line/column for friendlier feedback
|
||||
const match = message.match(/position\s+(\d+)/i);
|
||||
if (!match) {
|
||||
return { message };
|
||||
}
|
||||
const pos = Number(match[1]);
|
||||
if (Number.isNaN(pos)) {
|
||||
return { message };
|
||||
}
|
||||
let line = 1;
|
||||
let col = 1;
|
||||
for (let i = 0; i < Math.min(pos, jsonText.length); i++) {
|
||||
if (jsonText[i] === "\n") {
|
||||
line += 1;
|
||||
col = 1;
|
||||
} else {
|
||||
col += 1;
|
||||
}
|
||||
}
|
||||
return { message, line, column: col };
|
||||
}
|
||||
}
|
||||
|
||||
const jsonError = useMemo(() => {
|
||||
const tsonResult = useMemo(() => {
|
||||
if (value === "null") return null;
|
||||
return computeJsonError(value);
|
||||
return TSON.parse(value);
|
||||
}, [value]);
|
||||
|
||||
console.log({ tsonResult });
|
||||
|
||||
const getDataSchemaSuggestionMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
const client = await getClient(credentialGetter);
|
||||
@@ -161,7 +133,9 @@ function WorkflowDataSchemaInputGroup({
|
||||
<div
|
||||
className={cn(
|
||||
"rounded-md",
|
||||
jsonError ? "ring-1 ring-red-500" : undefined,
|
||||
tsonResult && !tsonResult.success
|
||||
? "ring-1 ring-red-500"
|
||||
: undefined,
|
||||
)}
|
||||
>
|
||||
<CodeEditor
|
||||
@@ -172,12 +146,8 @@ function WorkflowDataSchemaInputGroup({
|
||||
fontSize={8}
|
||||
/>
|
||||
</div>
|
||||
{jsonError && (
|
||||
<div className="text-xs text-red-400">
|
||||
{jsonError.line && jsonError.column
|
||||
? `Invalid JSON (${jsonError.line}:${jsonError.column}) — ${jsonError.message}`
|
||||
: `Invalid JSON — ${jsonError.message}`}
|
||||
</div>
|
||||
{tsonResult !== null && !tsonResult.success && tsonResult.error && (
|
||||
<div className="text-xs text-red-400">{tsonResult.error}</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -2,6 +2,9 @@ import Dagre from "@dagrejs/dagre";
|
||||
import type { Node } from "@xyflow/react";
|
||||
import { Edge } from "@xyflow/react";
|
||||
import { nanoid } from "nanoid";
|
||||
|
||||
import { TSON } from "@/util/tson";
|
||||
|
||||
import {
|
||||
WorkflowBlockType,
|
||||
WorkflowBlockTypes,
|
||||
@@ -2188,10 +2191,12 @@ function getWorkflowErrors(nodes: Array<AppNode>): Array<string> {
|
||||
}
|
||||
// Validate Task data schema JSON when enabled (value different from "null")
|
||||
if (node.data.dataSchema && node.data.dataSchema !== "null") {
|
||||
try {
|
||||
JSON.parse(node.data.dataSchema);
|
||||
} catch {
|
||||
errors.push(`${node.data.label}: Data schema is not valid JSON.`);
|
||||
const result = TSON.parse(node.data.dataSchema);
|
||||
|
||||
if (!result.success) {
|
||||
errors.push(
|
||||
`${node.data.label}: Data schema has invalid templated JSON: ${result.error ?? "-"}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -2227,10 +2232,12 @@ function getWorkflowErrors(nodes: Array<AppNode>): Array<string> {
|
||||
}
|
||||
// Validate Extraction data schema JSON when enabled (value different from "null")
|
||||
if (node.data.dataSchema && node.data.dataSchema !== "null") {
|
||||
try {
|
||||
JSON.parse(node.data.dataSchema);
|
||||
} catch {
|
||||
errors.push(`${node.data.label}: Data schema is not valid JSON.`);
|
||||
const result = TSON.parse(node.data.dataSchema);
|
||||
|
||||
if (!result.success) {
|
||||
errors.push(
|
||||
`${node.data.label}: Data schema has invalid templated JSON: ${result.error ?? "-"}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
91
skyvern-frontend/src/util/tson.test.ts
Normal file
91
skyvern-frontend/src/util/tson.test.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
// TSON.parse.test.ts
|
||||
import { TSON } from "./tson";
|
||||
import { describe, test, expect } from "vitest";
|
||||
|
||||
describe("TSON.parse", () => {
|
||||
test("single top-level template works", () => {
|
||||
const input = "{{ hello }}";
|
||||
const result = TSON.parse(input);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data).toEqual("<STUB>");
|
||||
});
|
||||
|
||||
test("preserves double braces inside quoted strings", () => {
|
||||
const input = '{"a": "{{ hello }}"}';
|
||||
const result = TSON.parse(input);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data).toEqual({ a: "{{ hello }}" });
|
||||
});
|
||||
|
||||
test("replaces double braces outside strings with stub", () => {
|
||||
const input = '{"a": {{ hello }} }';
|
||||
const result = TSON.parse(input);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data).toEqual({ a: "<STUB>" });
|
||||
});
|
||||
|
||||
test("handles double braces in keys and values", () => {
|
||||
const input = `
|
||||
{
|
||||
"hello": "world",
|
||||
{{foo}}: "bar",
|
||||
"baz": {{quux}}
|
||||
}`;
|
||||
const result = TSON.parse(input);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data).toEqual({
|
||||
hello: "world",
|
||||
"<STUB>": "bar",
|
||||
baz: "<STUB>",
|
||||
});
|
||||
});
|
||||
|
||||
test("does not allow trailing commas", () => {
|
||||
const input = `
|
||||
{
|
||||
"hello": "world",
|
||||
{{foo}}: "bar",
|
||||
"baz": {{quux}},
|
||||
}`;
|
||||
const result = TSON.parse(input);
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toContain("Expected double-quoted property name");
|
||||
});
|
||||
|
||||
test("detects unclosed double braces", () => {
|
||||
const input = "{{ unclosed";
|
||||
const result = TSON.parse(input);
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toContain("Unclosed");
|
||||
});
|
||||
|
||||
test("detects unmatched closing double braces", () => {
|
||||
const input = "closed }}";
|
||||
const result = TSON.parse(input);
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.error).toContain("Unmatched");
|
||||
});
|
||||
|
||||
test("handles nested double braces", () => {
|
||||
const input = "{{ {{ nested }} }}";
|
||||
const result = TSON.parse(input);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data).toEqual("<STUB>");
|
||||
});
|
||||
|
||||
test("handles double braces in arrays", () => {
|
||||
const input = '[{{ }}, {{ }}, "normal"]';
|
||||
const result = TSON.parse(input);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data).toEqual(["<STUB>", "<STUB>", "normal"]);
|
||||
});
|
||||
});
|
||||
223
skyvern-frontend/src/util/tson.ts
Normal file
223
skyvern-frontend/src/util/tson.ts
Normal file
@@ -0,0 +1,223 @@
|
||||
type JSONValue =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null
|
||||
| JSONValue[]
|
||||
| { [key: string]: JSONValue };
|
||||
|
||||
interface ParseResult {
|
||||
success: boolean;
|
||||
data?: JSONValue;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
const placeholder = () => "<STUB>";
|
||||
|
||||
/**
|
||||
* TSON ("templated JSON") is a superset of JSON, where double curly braces {{...}} can:
|
||||
* - exist anywhere outside of string literals, and
|
||||
* - are treated as placeholders
|
||||
*/
|
||||
const TSON = {
|
||||
parse(input: string): ParseResult {
|
||||
try {
|
||||
const balanceCheck = checkDoubleBraceBalance(input);
|
||||
|
||||
if (!balanceCheck.balanced) {
|
||||
return {
|
||||
success: false,
|
||||
error: balanceCheck.error,
|
||||
};
|
||||
}
|
||||
|
||||
const pipeline = [
|
||||
replaceBracesOutsideQuotes,
|
||||
// removeTrailingCommas,
|
||||
JSON.parse,
|
||||
];
|
||||
|
||||
const parsed = pipeline.reduce((acc, fn) => fn(acc), input) as JSONValue;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: parsed,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function checkDoubleBraceBalance(input: string): {
|
||||
balanced: boolean;
|
||||
error?: string;
|
||||
} {
|
||||
let inString = false;
|
||||
let escapeNext = false;
|
||||
let depth = 0;
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
const char = input[i];
|
||||
const nextChar = input[i + 1];
|
||||
|
||||
// handle escape sequences
|
||||
if (escapeNext) {
|
||||
escapeNext = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (char === "\\") {
|
||||
escapeNext = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// inside-string tracking
|
||||
if (char === '"') {
|
||||
inString = !inString;
|
||||
continue;
|
||||
}
|
||||
|
||||
// double braces counts (only outside strings)
|
||||
if (!inString) {
|
||||
if (char === "{" && nextChar === "{") {
|
||||
depth++;
|
||||
i++; // skip next char
|
||||
} else if (char === "}" && nextChar === "}") {
|
||||
depth--;
|
||||
if (depth < 0) {
|
||||
return {
|
||||
balanced: false,
|
||||
error: `Unmatched closing }} at position ${i}`,
|
||||
};
|
||||
}
|
||||
i++; // skip next char
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (depth > 0) {
|
||||
return {
|
||||
balanced: false,
|
||||
error: `Unclosed {{ - missing ${depth} closing }}`,
|
||||
};
|
||||
}
|
||||
|
||||
return { balanced: true };
|
||||
}
|
||||
|
||||
function replaceBracesOutsideQuotes(input: string): string {
|
||||
let result = "";
|
||||
let inString = false;
|
||||
let escapeNext = false;
|
||||
let inDoubleBrace = 0; // track nesting depth of {{...}}
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
const char = input[i];
|
||||
const nextChar = input[i + 1];
|
||||
|
||||
// escape sequences
|
||||
if (escapeNext) {
|
||||
if (inDoubleBrace === 0) {
|
||||
result += char;
|
||||
}
|
||||
escapeNext = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (char === "\\") {
|
||||
if (inDoubleBrace === 0) {
|
||||
result += char;
|
||||
}
|
||||
escapeNext = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// inside-string tracking
|
||||
if (char === '"') {
|
||||
inString = !inString;
|
||||
if (inDoubleBrace === 0) {
|
||||
result += char;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// double braces (only outside strings)
|
||||
if (!inString) {
|
||||
if (char === "{" && nextChar === "{") {
|
||||
if (inDoubleBrace === 0) {
|
||||
result += `"${placeholder()}"`;
|
||||
}
|
||||
inDoubleBrace++;
|
||||
i++; // skip next char
|
||||
continue;
|
||||
} else if (char === "}" && nextChar === "}") {
|
||||
inDoubleBrace--;
|
||||
i++; // skip next char
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// add characters when we're not inside double braces
|
||||
if (inDoubleBrace === 0) {
|
||||
result += char;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function removeTrailingCommas(input: string): string {
|
||||
let result = "";
|
||||
let inString = false;
|
||||
let escapeNext = false;
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
const char = input[i];
|
||||
|
||||
// escape sequences
|
||||
if (escapeNext) {
|
||||
result += char;
|
||||
escapeNext = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (char === "\\") {
|
||||
result += char;
|
||||
escapeNext = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// inside-string tracking
|
||||
if (char === '"') {
|
||||
inString = !inString;
|
||||
result += char;
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for trailing commas (outside strings)
|
||||
if (!inString && char === ",") {
|
||||
// look-ahead for the next non-whitespace character
|
||||
let j = i + 1;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
while (j < input.length && /\s/.test(input[j])) {
|
||||
j++;
|
||||
}
|
||||
|
||||
// if next non-whitespace is } or ], skip the comma
|
||||
if (j < input.length && (input[j] === "}" || input[j] === "]")) {
|
||||
continue; // Skip this comma
|
||||
}
|
||||
}
|
||||
|
||||
result += char;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export { TSON };
|
||||
Reference in New Issue
Block a user