From 7421b61f0c6423d4acf86bf07a85270607510369 Mon Sep 17 00:00:00 2001 From: Katsuyuki Omuro Date: Sun, 7 Dec 2025 01:42:03 +0900 Subject: [PATCH 1/6] Update ESLint for TypeScript --- .eslintrc.cjs | 15 -- eslint.config.mjs | 37 ++++ package-lock.json | 539 ++++++++++++++++++++++++++++++++++++++-------- package.json | 6 +- 4 files changed, 486 insertions(+), 111 deletions(-) delete mode 100644 .eslintrc.cjs create mode 100644 eslint.config.mjs diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index 4b89e49e65..0000000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - "env": { - "es2021": true, - "node": true - }, - "extends": "eslint:recommended", - "overrides": [ - ], - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module" - }, - "rules": { - } -} diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000000..4eae7c8886 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,37 @@ +// @ts-check + +import eslint from '@eslint/js'; +import { defineConfig } from 'eslint/config'; +import tseslint from 'typescript-eslint'; + +export default defineConfig([ + { + files: ['src/**/*.{ts,tsx,js}'], + languageOptions: { + parserOptions: { + projectService: true, + }, + }, + extends: [ + eslint.configs.recommended, + ...tseslint.configs.recommendedTypeChecked, + ...tseslint.configs.stylisticTypeChecked, + ], + rules: { + 'no-fallthrough': 'off', + '@typescript-eslint/require-await': 'off', + '@typescript-eslint/consistent-type-definitions': 'off', + }, + }, + { + ignores: [ + 'ci/*', + 'dist/*', + 'documentation/*', + 'integration-tests/*', + 'runtime/*', + 'tests/*', + 'test-d/*', + ] + }, +]); diff --git a/package-lock.json b/package-lock.json index 2ee256a087..265b6e50be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,15 +26,17 @@ "js-compute-runtime": "js-compute-runtime-cli.js" }, "devDependencies": { + "@eslint/js": "^9.39.1", "@jakechampion/cli-testing-library": "^1.0.0", "brittle": "^3.5.2", - "eslint": "^9.6.0", + "eslint": "^9.39.1", "get-bin-path": "^11.0.0", "prettier": "^3.3.3", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "tsd": "^0.33.0", - "typescript": "^5.9.0", + "typescript": "^5.9.3", + "typescript-eslint": "^8.48.1", "unified": "^11.0.5" }, "peerDependencies": { @@ -752,17 +754,20 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", "dev": true, "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } @@ -781,9 +786,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", - "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, "license": "MIT", "engines": { @@ -791,13 +796,13 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.4", + "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -805,20 +810,36 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/core": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz", - "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "dev": true, "license": "MIT", "dependencies": { @@ -828,7 +849,7 @@ "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, @@ -840,19 +861,22 @@ } }, "node_modules/@eslint/js": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz", - "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==", + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", "dev": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -860,12 +884,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", - "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, "license": "Apache-2.0", "dependencies": { + "@eslint/core": "^0.17.0", "levn": "^0.4.1" }, "engines": { @@ -873,9 +898,9 @@ } }, "node_modules/@humanfs/core": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz", - "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==", + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -883,14 +908,14 @@ } }, "node_modules/@humanfs/node": { - "version": "0.16.5", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz", - "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==", + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanfs/core": "^0.19.0", - "@humanwhocodes/retry": "^0.3.0" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { "node": ">=18.18.0" @@ -911,9 +936,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1486,12 +1511,268 @@ "dev": true, "license": "MIT" }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.1.tgz", + "integrity": "sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.48.1", + "@typescript-eslint/type-utils": "8.48.1", + "@typescript-eslint/utils": "8.48.1", + "@typescript-eslint/visitor-keys": "8.48.1", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.48.1", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.1.tgz", + "integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.48.1", + "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/typescript-estree": "8.48.1", + "@typescript-eslint/visitor-keys": "8.48.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.1.tgz", + "integrity": "sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.48.1", + "@typescript-eslint/types": "^8.48.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.1.tgz", + "integrity": "sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/visitor-keys": "8.48.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.1.tgz", + "integrity": "sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.1.tgz", + "integrity": "sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/typescript-estree": "8.48.1", + "@typescript-eslint/utils": "8.48.1", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.1.tgz", + "integrity": "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.1.tgz", + "integrity": "sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.48.1", + "@typescript-eslint/tsconfig-utils": "8.48.1", + "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/visitor-keys": "8.48.1", + "debug": "^4.3.4", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.1.tgz", + "integrity": "sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.48.1", + "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/typescript-estree": "8.48.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.1.tgz", + "integrity": "sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.48.1", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/acorn": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz", - "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1694,9 +1975,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -1947,9 +2228,9 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { @@ -2285,33 +2566,32 @@ } }, "node_modules/eslint": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz", - "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==", + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", + "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.6.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.12.0", - "@eslint/plugin-kit": "^0.2.0", - "@humanfs/node": "^0.16.5", + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.1", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.1", + "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.1.0", - "eslint-visitor-keys": "^4.1.0", - "espree": "^10.2.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -2325,8 +2605,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" @@ -2505,9 +2784,9 @@ "license": "MIT" }, "node_modules/eslint-scope": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", - "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -2522,9 +2801,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", - "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -2588,15 +2867,15 @@ "license": "MIT" }, "node_modules/espree": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", - "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.12.0", + "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.1.0" + "eslint-visitor-keys": "^4.2.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2728,6 +3007,24 @@ "pend": "~1.2.0" } }, + "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/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -2919,6 +3216,13 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, "node_modules/hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -3003,9 +3307,9 @@ } }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3325,9 +3629,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -5296,19 +5600,29 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "license": "MIT" }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "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/tmatch": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/tmatch/-/tmatch-5.0.0.tgz", @@ -5359,6 +5673,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/tsd": { "version": "0.33.0", "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.33.0.tgz", @@ -5428,6 +5755,30 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.1.tgz", + "integrity": "sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.48.1", + "@typescript-eslint/parser": "8.48.1", + "@typescript-eslint/typescript-estree": "8.48.1", + "@typescript-eslint/utils": "8.48.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, "node_modules/unbzip2-stream": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", diff --git a/package.json b/package.json index 78ef9070b8..a7fdcc30d3 100644 --- a/package.json +++ b/package.json @@ -44,15 +44,17 @@ "format:check": "prettier --check *.js src/*.js integration-tests" }, "devDependencies": { + "@eslint/js": "^9.39.1", "@jakechampion/cli-testing-library": "^1.0.0", "brittle": "^3.5.2", - "eslint": "^9.6.0", + "eslint": "^9.39.1", "get-bin-path": "^11.0.0", "prettier": "^3.3.3", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "tsd": "^0.33.0", - "typescript": "^5.9.0", + "typescript": "^5.9.3", + "typescript-eslint": "^8.48.1", "unified": "^11.0.5" }, "dependencies": { From ba725d3f72dde838bdc198ea8894803d59dccc62 Mon Sep 17 00:00:00 2001 From: Katsuyuki Omuro Date: Sun, 7 Dec 2025 01:44:09 +0900 Subject: [PATCH 2/6] Update CLI to TypeScript --- .github/workflows/main.yml | 32 ++++++- .github/workflows/release-please.yml | 7 ++ .gitignore | 3 + DEVELOPMENT.md | 12 +-- integration-tests/cli/env.test.js | 2 +- .../js-compute/fixtures/app/fastly.toml.in | 2 +- .../fixtures/module-mode/fastly.toml.in | 2 +- package-lock.json | 70 +++++++++----- package.json | 49 ++++++---- {src/rsrc => rsrc}/trace-mapping.inject.js | 2 +- src/addSdkMetadataField.js | 24 ----- src/addSdkMetadataField.ts | 26 +++++ src/{bundle.js => bundle.ts} | 10 +- .../cli/js-compute-runtime-cli.ts | 48 +++++----- ...nToWasm.js => compileApplicationToWasm.ts} | 95 ++++++++++++------- src/composeSourcemaps.js | 48 ---------- src/composeSourcemaps.ts | 68 +++++++++++++ src/{env.js => env.ts} | 12 ++- src/{isFile.js => isFile.ts} | 2 +- src/isFileOrDoesNotExist.js | 13 --- src/isFileOrDoesNotExist.ts | 13 +++ src/{parseInputs.js => parseInputs.ts} | 40 +++++++- src/{postbundle.js => postbundle.ts} | 6 +- src/{printHelp.js => printHelp.ts} | 0 src/{printVersion.js => printVersion.ts} | 2 +- ...gin.js => swallowTopLevelExportsPlugin.ts} | 11 ++- src/{tooManyEngines.js => tooManyEngines.ts} | 0 src/types/modules.d.ts | 9 ++ ...{unknownArgument.js => unknownArgument.ts} | 2 +- tests/wpt-harness/build-wpt-runtime.sh | 2 +- tsconfig.json | 16 ++-- 31 files changed, 395 insertions(+), 233 deletions(-) rename {src/rsrc => rsrc}/trace-mapping.inject.js (98%) delete mode 100644 src/addSdkMetadataField.js create mode 100644 src/addSdkMetadataField.ts rename src/{bundle.js => bundle.ts} (97%) rename js-compute-runtime-cli.js => src/cli/js-compute-runtime-cli.ts (58%) rename src/{compileApplicationToWasm.js => compileApplicationToWasm.ts} (79%) delete mode 100644 src/composeSourcemaps.js create mode 100644 src/composeSourcemaps.ts rename src/{env.js => env.ts} (89%) rename src/{isFile.js => isFile.ts} (69%) delete mode 100644 src/isFileOrDoesNotExist.js create mode 100644 src/isFileOrDoesNotExist.ts rename src/{parseInputs.js => parseInputs.ts} (85%) rename src/{postbundle.js => postbundle.ts} (98%) rename src/{printHelp.js => printHelp.ts} (100%) rename src/{printVersion.js => printVersion.ts} (85%) rename src/{swallowTopLevelExportsPlugin.js => swallowTopLevelExportsPlugin.ts} (81%) rename src/{tooManyEngines.js => tooManyEngines.ts} (100%) create mode 100644 src/types/modules.d.ts rename src/{unknownArgument.js => unknownArgument.ts} (80%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 398f008451..5fd60ef079 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -154,6 +154,8 @@ jobs: with: name: fastly-weval-ic-cache - run: npm install + - name: Build CLI + run: npm run build:cli - run: npm test build-debug: @@ -164,6 +166,11 @@ jobs: - uses: actions/checkout@v4 with: submodules: true + - name: Set up Node LTS + uses: actions/setup-node@v3 + with: + node-version: 'lts/*' + - run: npm ci - name: Install Rust 1.81.0 run: | rustup toolchain install 1.81.0 @@ -174,6 +181,8 @@ jobs: with: path: "/home/runner/.cargo/bin/wasm-tools" key: crate-cache-wasm-tools-${{ env.wasm-tools_version }} + - name: Build CLI + run: npm run build:cli - name: Build with full debug info run: npm run build:debug:info - uses: actions/upload-artifact@v4 @@ -193,6 +202,11 @@ jobs: - uses: actions/checkout@v4 with: submodules: true + - name: Set up Node LTS + uses: actions/setup-node@v3 + with: + node-version: 'lts/*' + - run: npm ci - name: Install Rust 1.81.0 run: | rustup toolchain install 1.81.0 @@ -203,6 +217,8 @@ jobs: with: path: "/home/runner/.cargo/bin/wasm-tools" key: crate-cache-wasm-tools-${{ env.wasm-tools_version }} + - name: Build CLI + run: npm run build:cli - name: Build if: matrix.profile == 'release' run: npm run build:release @@ -229,9 +245,11 @@ jobs: - uses: actions/checkout@v4 with: submodules: true - - uses: actions/setup-node@v3 + - name: Set up Node LTS + uses: actions/setup-node@v3 with: node-version: 'lts/*' + - run: npm ci - name: Download Engine uses: actions/download-artifact@v4 @@ -250,8 +268,9 @@ jobs: with: path: "/home/runner/.cargo/bin/wasm-tools" key: crate-cache-wasm-tools-${{ env.wasm-tools_version }} - - - run: npm install + + - name: Build CLI + run: npm run build:cli - name: Build WPT runtime run: tests/wpt-harness/build-wpt-runtime.sh --debug-build @@ -277,9 +296,11 @@ jobs: - uses: actions/checkout@v4 with: submodules: true - - uses: actions/setup-node@v3 + - name: Set up Node LTS + uses: actions/setup-node@v3 with: node-version: 'lts/*' + - run: npm ci - name: Download Engine uses: actions/download-artifact@v4 @@ -305,7 +326,8 @@ jobs: path: "/home/runner/.cargo/bin/wasm-tools" key: crate-cache-wasm-tools-${{ env.wasm-tools_version }} - - run: npm install + - name: Build CLI + run: npm run build:cli - name: Build WPT runtime run: tests/wpt-harness/build-wpt-runtime.sh ${{matrix.profile == 'weval' && '--enable-experimental-aot' || matrix.profile == 'debug' && '--debug-build' || ''}} diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index ba2d0efb7a..18af38d17a 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -89,6 +89,11 @@ jobs: - uses: actions/checkout@v3 with: submodules: true + - name: Set up Node LTS + uses: actions/setup-node@v3 + with: + node-version: 'lts/*' + - run: npm ci - name: Install Rust 1.81.0 run: | rustup toolchain install 1.81.0 @@ -99,6 +104,8 @@ jobs: with: path: "/home/runner/.cargo/bin/wasm-tools" key: crate-cache-wasm-tools-${{ env.wasm-tools_version }} + - name: Build CLI + run: npm run build:cli - name: Build if: ${{ matrix.profile == 'release' }} run: npm run build:release diff --git a/.gitignore b/.gitignore index 85ed93951d..7039731060 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# TypeScript build output +dist/ + # Integration Tests build output /integration-tests/**/fixtures/**/*.tar.gz /integration-tests/**/fixtures/**/fastly.toml diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 567a2ca5f6..d51121607a 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -33,9 +33,9 @@ To build from source, you need to have the following tools installed to successf ```sh sudo apt install binaryen ``` -- rust target wasm32-wasi +- rust target wasm32-wasip1 ```sh - rustup target add wasm32-wasi + rustup target add wasm32-wasip1 ``` - [cbindgen](https://github.com/eqrion/cbindgen#quick-start) ```sh @@ -87,9 +87,9 @@ npm run build # then, restart shell or run: source $HOME/.cargo/env ``` -- rust target wasm32-wasi +- rust target wasm32-wasip1 ```sh - rustup target add wasm32-wasi + rustup target add wasm32-wasip1 ``` - [cbindgen](https://github.com/eqrion/cbindgen#quick-start) ```sh @@ -180,10 +180,10 @@ In addition the following flags can be added after the command (passed via `npm A typical development test command is therefore something like: ``` -npm run build:debug && npm run test:integration -- --debug-build --debug-log --local --bail /crypto +npm run build:cli && npm run build:debug && npm run test:integration -- --debug-build --debug-log --local --bail /crypto ``` -Which would run a debug build, enable debugging logging, and then that build against all the crypto tests locally on Viceroy, throwing an error as soon as one is found. +Which would build the CLI TypeScript to JavaScript, run a debug build, enable debugging logging, and then that build against all the crypto tests locally on Viceroy, throwing an error as soon as one is found. Some tests can only be run on Compute and not Viceroy and will be automatically skipped. A green tick is always shown for a test that ran successfully - if it is missing that means it did not run. diff --git a/integration-tests/cli/env.test.js b/integration-tests/cli/env.test.js index 50ee75fd5b..ee93f2afab 100644 --- a/integration-tests/cli/env.test.js +++ b/integration-tests/cli/env.test.js @@ -1,5 +1,5 @@ import test from 'brittle'; -import { EnvParser } from '../../src/env.js'; +import { EnvParser } from '../../dist/env.js'; test('EnvParser should parse single key-value pair', function (t) { const parser = new EnvParser(); diff --git a/integration-tests/js-compute/fixtures/app/fastly.toml.in b/integration-tests/js-compute/fixtures/app/fastly.toml.in index dcc121fbed..3a4bb6a3dd 100644 --- a/integration-tests/js-compute/fixtures/app/fastly.toml.in +++ b/integration-tests/js-compute/fixtures/app/fastly.toml.in @@ -9,7 +9,7 @@ name = "js-test-app" service_id = "" [scripts] - build = "node ../../../../js-compute-runtime-cli.js --env FASTLY_DEBUG_LOGGING,ACL_NAME,CONFIG_STORE_NAME,DICTIONARY_NAME,KV_STORE_NAME,SECRET_STORE_NAME,LOCAL_TEST,TEST=\"foo\" --enable-experimental-high-resolution-time-methods src/index.js" + build = "node ../../../../dist/cli/js-compute-runtime-cli.js --env FASTLY_DEBUG_LOGGING,ACL_NAME,CONFIG_STORE_NAME,DICTIONARY_NAME,KV_STORE_NAME,SECRET_STORE_NAME,LOCAL_TEST,TEST=\"foo\" --enable-experimental-high-resolution-time-methods src/index.js" [local_server] diff --git a/integration-tests/js-compute/fixtures/module-mode/fastly.toml.in b/integration-tests/js-compute/fixtures/module-mode/fastly.toml.in index 0e6e6ef55b..65a8d68f51 100644 --- a/integration-tests/js-compute/fixtures/module-mode/fastly.toml.in +++ b/integration-tests/js-compute/fixtures/module-mode/fastly.toml.in @@ -9,7 +9,7 @@ name = "js-test-app" service_id = "" [scripts] - build = "node ../../../../js-compute-runtime-cli.js --env FASTLY_DEBUG_LOGGING,ACL_NAME,CONFIG_STORE_NAME,DICTIONARY_NAME,KV_STORE_NAME,SECRET_STORE_NAME,LOCAL_TEST,TEST=\"foo\" --enable-experimental-high-resolution-time-methods --module-mode src/index.js" + build = "node ../../../../dist/cli/js-compute-runtime-cli.js --env FASTLY_DEBUG_LOGGING,ACL_NAME,CONFIG_STORE_NAME,DICTIONARY_NAME,KV_STORE_NAME,SECRET_STORE_NAME,LOCAL_TEST,TEST=\"foo\" --enable-experimental-high-resolution-time-methods --module-mode src/index.js" [local_server] diff --git a/package-lock.json b/package-lock.json index 265b6e50be..5e31224bec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,15 +19,17 @@ "esbuild": "^0.25.0", "magic-string": "^0.30.12", "picomatch": "^4.0.3", - "regexpu-core": "^6.1.1" + "regexpu-core": "^6.4.0" }, "bin": { - "js-compute": "js-compute-runtime-cli.js", - "js-compute-runtime": "js-compute-runtime-cli.js" + "js-compute": "dist/cli/js-compute-runtime-cli.js", + "js-compute-runtime": "dist/cli/js-compute-runtime-cli.js" }, "devDependencies": { "@eslint/js": "^9.39.1", "@jakechampion/cli-testing-library": "^1.0.0", + "@types/node": "^24.10.1", + "@types/picomatch": "^4.0.2", "brittle": "^3.5.2", "eslint": "^9.39.1", "get-bin-path": "^11.0.0", @@ -1497,6 +1499,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/node": { + "version": "24.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", @@ -1504,6 +1516,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-qHHxQ+P9PysNEGbALT8f8YOSHW0KJu6l2xU8DYY0fu/EmGxXdVnuTLvFUvBgPJMSqXq29SYHveejeAha+4AYgA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -3642,9 +3661,9 @@ } }, "node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -5100,9 +5119,9 @@ "license": "MIT" }, "node_modules/regenerate-unicode-properties": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", - "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", "license": "MIT", "dependencies": { "regenerate": "^1.4.2" @@ -5112,17 +5131,17 @@ } }, "node_modules/regexpu-core": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.1.1.tgz", - "integrity": "sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", "license": "MIT", "dependencies": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.0", + "regenerate-unicode-properties": "^10.2.2", "regjsgen": "^0.8.0", - "regjsparser": "^0.11.0", + "regjsparser": "^0.13.0", "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" + "unicode-match-property-value-ecmascript": "^2.2.1" }, "engines": { "node": ">=4" @@ -5135,12 +5154,12 @@ "license": "MIT" }, "node_modules/regjsparser": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.11.1.tgz", - "integrity": "sha512-1DHODs4B8p/mQHU9kr+jv8+wIC9mtG4eBHxWxIq5mhjE3D5oORhCc6deRKzTjs9DcfRFmj9BHSDguZklqCGFWQ==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", + "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", "license": "BSD-2-Clause", "dependencies": { - "jsesc": "~3.0.2" + "jsesc": "~3.1.0" }, "bin": { "regjsparser": "bin/parser" @@ -5789,6 +5808,13 @@ "through": "^2.3.8" } }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", @@ -5812,9 +5838,9 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", - "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", "license": "MIT", "engines": { "node": ">=4" diff --git a/package.json b/package.json index a7fdcc30d3..1773cbd2cf 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@fastly/js-compute", "version": "3.36.0", "license": "Apache-2.0", - "main": "js-compute-runtime-cli.js", + "main": "dist/cli/js-compute-runtime-cli.js", "types": "types/index.d.ts", "type": "module", "repository": { @@ -10,18 +10,17 @@ "url": "https://github.com/fastly/js-compute-runtime" }, "bin": { - "js-compute": "js-compute-runtime-cli.js", - "js-compute-runtime": "js-compute-runtime-cli.js" + "js-compute": "dist/cli/js-compute-runtime-cli.js", + "js-compute-runtime": "dist/cli/js-compute-runtime-cli.js" }, "files": [ "types", - "js-compute-runtime-cli.js", "fastly.wasm", "fastly.debug.wasm", "fastly-weval.wasm", "fastly-ics.wevalcache", - "src", - "index.d.ts", + "dist", + "rsrc", "package.json", "README.md", "CHANGELOG.md" @@ -34,7 +33,8 @@ "test:wpt:debug": "tests/wpt-harness/build-wpt-runtime.sh --debug-build && node ./tests/wpt-harness/run-wpt.mjs -vv", "test:types": "tsd", "clean": "rm -f starling.wasm fastly.wasm fastly.debug.wasm fastly-weval.wasm fastly-ics.wevalcache fastly-js-compute-*.tgz", - "build": "npm run clean && npm run build:debug && npm run build:release && npm run build:weval", + "build": "npm run clean && npm run build:cli && npm run build:debug && npm run build:release && npm run build:weval", + "build:cli": "tsc", "build:release": "./runtime/fastly/build-release.sh", "build:debug": "./runtime/fastly/build-debug.sh", "build:weval": "./runtime/fastly/build-release-weval.sh", @@ -43,9 +43,24 @@ "format": "prettier --write *.js src/*.js integration-tests types test-d", "format:check": "prettier --check *.js src/*.js integration-tests" }, + "dependencies": { + "@bytecodealliance/jco": "^1.7.0", + "@bytecodealliance/weval": "^0.3.2", + "@bytecodealliance/wizer": "^7.0.5", + "@jridgewell/remapping": "^2.3.5", + "@jridgewell/trace-mapping": "^0.3.31", + "acorn": "^8.13.0", + "acorn-walk": "^8.3.4", + "esbuild": "^0.25.0", + "magic-string": "^0.30.12", + "picomatch": "^4.0.3", + "regexpu-core": "^6.4.0" + }, "devDependencies": { "@eslint/js": "^9.39.1", "@jakechampion/cli-testing-library": "^1.0.0", + "@types/node": "^24.10.1", + "@types/picomatch": "^4.0.2", "brittle": "^3.5.2", "eslint": "^9.39.1", "get-bin-path": "^11.0.0", @@ -57,19 +72,6 @@ "typescript-eslint": "^8.48.1", "unified": "^11.0.5" }, - "dependencies": { - "@bytecodealliance/jco": "^1.7.0", - "@bytecodealliance/weval": "^0.3.2", - "@bytecodealliance/wizer": "^7.0.5", - "@jridgewell/remapping": "^2.3.5", - "@jridgewell/trace-mapping": "^0.3.31", - "acorn": "^8.13.0", - "acorn-walk": "^8.3.4", - "esbuild": "^0.25.0", - "magic-string": "^0.30.12", - "picomatch": "^4.0.3", - "regexpu-core": "^6.1.1" - }, "peerDependencies": { "typescript": "^5.9.0" }, @@ -77,5 +79,10 @@ "typescript": { "optional": true } + }, + "tsd": { + "compilerOptions": { + "types": [] + } } -} \ No newline at end of file +} diff --git a/src/rsrc/trace-mapping.inject.js b/rsrc/trace-mapping.inject.js similarity index 98% rename from src/rsrc/trace-mapping.inject.js rename to rsrc/trace-mapping.inject.js index a11e9d6ddc..fafc7e8ada 100644 --- a/src/rsrc/trace-mapping.inject.js +++ b/rsrc/trace-mapping.inject.js @@ -72,7 +72,7 @@ function mapStack(raw) { const lines = String(raw).split(/\r?\n/); for (const line of lines) { - if (line.startsWith('node_modules/@fastly/js-compute/src/rsrc/trace-mapping.inject.js')) { + if (line.startsWith('node_modules/@fastly/js-compute/rsrc/trace-mapping.inject.js')) { // If the line comes from this file, skip it continue; } diff --git a/src/addSdkMetadataField.js b/src/addSdkMetadataField.js deleted file mode 100644 index f16ef00757..0000000000 --- a/src/addSdkMetadataField.js +++ /dev/null @@ -1,24 +0,0 @@ -import { metadataAdd } from '@bytecodealliance/jco'; -import { readFile, writeFile } from 'node:fs/promises'; -import { dirname, join } from 'node:path'; -import { fileURLToPath } from 'node:url'; -const __dirname = dirname(fileURLToPath(import.meta.url)); - -export async function addSdkMetadataField(wasmPath, usingAOT) { - const packageJson = await readFile(join(__dirname, '../package.json'), { - encoding: 'utf-8', - }); - - let { name, version } = JSON.parse(packageJson); - - if (usingAOT) { - name += ' (StarlingMonkey with Weval)'; - } else { - name += ' (StarlingMonkey)'; - } - - const metadata = [['sdk', [[`${name}`, version]]]]; - const wasm = await readFile(wasmPath); - const newWasm = await metadataAdd(wasm, metadata); - await writeFile(wasmPath, newWasm); -} diff --git a/src/addSdkMetadataField.ts b/src/addSdkMetadataField.ts new file mode 100644 index 0000000000..d70a97f93e --- /dev/null +++ b/src/addSdkMetadataField.ts @@ -0,0 +1,26 @@ +import { metadataAdd } from '@bytecodealliance/jco'; +import { readFile, writeFile } from 'node:fs/promises'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +const __dirname = dirname(fileURLToPath(import.meta.url)); + +export async function addSdkMetadataField(wasmPath: string, usingAOT: boolean) { + const packageJson = await readFile(join(__dirname, '../package.json'), { + encoding: 'utf-8', + }); + + const { name, version } = JSON.parse(packageJson) as { name: string, version: string, }; + + let sdkName: string; + if (usingAOT) { + sdkName = name + ' (StarlingMonkey with Weval)'; + } else { + sdkName = name + ' (StarlingMonkey)'; + } + + const metadata = [['sdk', [[sdkName, version]]]]; + const wasm = await readFile(wasmPath); + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const newWasm: Uint8Array = await metadataAdd(wasm, metadata); + await writeFile(wasmPath, newWasm); +} diff --git a/src/bundle.js b/src/bundle.ts similarity index 97% rename from src/bundle.js rename to src/bundle.ts index a28d9bdbec..5e7db0ec94 100644 --- a/src/bundle.js +++ b/src/bundle.ts @@ -1,14 +1,14 @@ import { rename } from 'node:fs/promises'; import { dirname, basename, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -import { build } from 'esbuild'; +import { build, type Plugin } from 'esbuild'; import { swallowTopLevelExportsPlugin } from './swallowTopLevelExportsPlugin.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); -const fastlyPlugin = { +const fastlyPlugin: Plugin = { name: 'fastly', setup(build) { build.onResolve({ filter: /^fastly:.*/ }, (args) => { @@ -154,8 +154,8 @@ export const TransactionCacheEntry = globalThis.TransactionCacheEntry; }; export async function bundle( - input, - outfile, + input: string, + outfile: string, { moduleMode = false, enableStackTraces = false }, ) { // Build output file in cwd first to build sourcemap with correct paths @@ -168,7 +168,7 @@ export async function bundle( const inject = []; if (enableStackTraces) { - inject.push(resolve(__dirname, './rsrc/trace-mapping.inject.js')); + inject.push(resolve(__dirname, '../rsrc/trace-mapping.inject.js')); } await build({ diff --git a/js-compute-runtime-cli.js b/src/cli/js-compute-runtime-cli.ts similarity index 58% rename from js-compute-runtime-cli.js rename to src/cli/js-compute-runtime-cli.ts index c05f48b040..e6091cf9c5 100755 --- a/js-compute-runtime-cli.js +++ b/src/cli/js-compute-runtime-cli.ts @@ -1,33 +1,33 @@ #!/usr/bin/env node -import { parseInputs } from './src/parseInputs.js'; -import { printVersion } from './src/printVersion.js'; -import { printHelp } from './src/printHelp.js'; -import { addSdkMetadataField } from './src/addSdkMetadataField.js'; +import { parseInputs } from '../parseInputs.js'; +import { printVersion } from '../printVersion.js'; +import { printHelp } from '../printHelp.js'; +import { addSdkMetadataField } from '../addSdkMetadataField.js'; -const { - enableAOT, - aotCache, - enableHttpCache, - enableExperimentalHighResolutionTimeMethods, - moduleMode, - bundle, - enableStackTraces, - excludeSources, - debugIntermediateFilesDir, - wasmEngine, - input, - output, - version, - help, - env, -} = await parseInputs(process.argv.slice(2)); +const parsedInputs = await parseInputs(process.argv.slice(2)); -if (version) { +if (parsedInputs === 'version') { await printVersion(); -} else if (help) { +} else if (parsedInputs === 'help') { await printHelp(); } else { + const { + enableAOT, + aotCache, + enableHttpCache, + enableExperimentalHighResolutionTimeMethods, + moduleMode, + bundle, + enableStackTraces, + excludeSources, + debugIntermediateFilesDir, + wasmEngine, + input, + output, + env, + } = parsedInputs; + // This is a dynamic import because this import will throw an error // if it does not have a pre-compiled version of Wizer available in the platform // running the CLI. In that situation, we would still like the @@ -35,7 +35,7 @@ if (version) { // it could be that the user is using an older version of js-compute-runtime // and a newer version does not support the platform they are using. const { compileApplicationToWasm } = await import( - './src/compileApplicationToWasm.js' + '../compileApplicationToWasm.js' ); await compileApplicationToWasm({ input, diff --git a/src/compileApplicationToWasm.js b/src/compileApplicationToWasm.ts similarity index 79% rename from src/compileApplicationToWasm.js rename to src/compileApplicationToWasm.ts index ea7e77a45d..e0b5e28aa9 100644 --- a/src/compileApplicationToWasm.js +++ b/src/compileApplicationToWasm.ts @@ -1,6 +1,6 @@ import { dirname, resolve, sep, normalize } from 'node:path'; import { tmpdir, freemem } from 'node:os'; -import { spawnSync } from 'node:child_process'; +import { spawnSync, type SpawnSyncOptionsWithStringEncoding } from 'node:child_process'; import { mkdir, readFile, @@ -9,41 +9,61 @@ import { copyFile, } from 'node:fs/promises'; import { rmSync } from 'node:fs'; -import wizer from '@bytecodealliance/wizer'; import weval from '@bytecodealliance/weval'; +import wizer from '@bytecodealliance/wizer'; import { isFile } from './isFile.js'; import { isFileOrDoesNotExist } from './isFileOrDoesNotExist.js'; import { postbundle } from './postbundle.js'; import { bundle } from './bundle.js'; -import { composeSourcemaps } from './composeSourcemaps.js'; +import { composeSourcemaps, ExcludePattern } from './composeSourcemaps.js'; const maybeWindowsPath = process.platform === 'win32' - ? (path) => { + ? (path: string) => { return '//?/' + path.replace(/\\/g, '/'); } - : (path) => path; + : (path: string) => path; async function getTmpDir() { return await mkdtemp(normalize(tmpdir() + sep)); } -export async function compileApplicationToWasm({ - input, - output, - wasmEngine, - enableHttpCache = false, - enableExperimentalHighResolutionTimeMethods = false, - enableAOT = false, - aotCache = '', - enableStackTraces, - excludeSources, - debugIntermediateFilesDir, - moduleMode = false, - doBundle = false, - env, -}) { +export type CompileApplicationToWasmParams = { + input: string, + output: string, + wasmEngine: string, + enableHttpCache: boolean, + enableExperimentalHighResolutionTimeMethods: boolean, + enableAOT: boolean, + aotCache: string, + enableStackTraces: boolean, + excludeSources: boolean, + debugIntermediateFilesDir: string | undefined, + moduleMode: boolean, + doBundle: boolean, + env: Record, +}; + +export async function compileApplicationToWasm(params: CompileApplicationToWasmParams) { + + const { + output, + wasmEngine, + enableHttpCache = false, + enableExperimentalHighResolutionTimeMethods = false, + enableAOT = false, + aotCache = '', + enableStackTraces, + excludeSources, + debugIntermediateFilesDir, + moduleMode = false, + doBundle = false, + env, + } = params; + + let input = params.input; + try { if (!(await isFile(input))) { console.error( @@ -60,7 +80,8 @@ export async function compileApplicationToWasm({ try { await readFile(input, { encoding: 'utf-8' }); - } catch (error) { + } catch (maybeError: unknown) { + const error = maybeError instanceof Error ? maybeError : new Error(String(maybeError)); console.error( `Error: Failed to open the \`input\` (${input})`, error.message, @@ -85,7 +106,8 @@ export async function compileApplicationToWasm({ await mkdir(dirname(output), { recursive: true, }); - } catch (error) { + } catch (maybeError: unknown) { + const error = maybeError instanceof Error ? maybeError : new Error(String(maybeError)); console.error( `Error: Failed to create the \`output\` (${output}) directory`, error.message, @@ -100,7 +122,8 @@ export async function compileApplicationToWasm({ ); process.exit(1); } - } catch (error) { + } catch (maybeError: unknown) { + const error = maybeError instanceof Error ? maybeError : new Error(String(maybeError)); console.error( `Error: Failed to check whether the \`output\` (${output}) is a file path`, error.message, @@ -116,7 +139,8 @@ export async function compileApplicationToWasm({ await mkdir(debugIntermediateFilesDir, { recursive: true, }); - } catch (error) { + } catch (maybeError: unknown) { + const error = maybeError instanceof Error ? maybeError : new Error(String(maybeError)); console.error( `Error: Failed to create the \`debug-intermediate-files\` (${debugIntermediateFilesDir}) directory`, error.message, @@ -141,7 +165,8 @@ export async function compileApplicationToWasm({ moduleMode, enableStackTraces, }); - } catch (error) { + } catch (maybeError: unknown) { + const error = maybeError instanceof Error ? maybeError : new Error(String(maybeError)); console.error(`Error:`, error.message); process.exit(1); } @@ -192,7 +217,7 @@ export async function compileApplicationToWasm({ if (enableStackTraces) { // Compose source maps const replaceSourceMapToken = '__FINAL_SOURCE_MAP__'; - let excludePatterns = ['forbid-entry:/**', 'node_modules/**']; + let excludePatterns: ExcludePattern[] = ['forbid-entry:/**', 'node_modules/**']; if (excludeSources) { excludePatterns = [() => true]; } @@ -251,17 +276,16 @@ export async function compileApplicationToWasm({ ENABLE_EXPERIMENTAL_HIGH_RESOLUTION_TIME_METHODS: enableExperimentalHighResolutionTimeMethods ? '1' : '0', ENABLE_EXPERIMENTAL_HTTP_CACHE: enableHttpCache ? '1' : '0', - RUST_MIN_STACK: Math.max(8 * 1024 * 1024, Math.floor(freemem() * 0.1)), + RUST_MIN_STACK: String(Math.max(8 * 1024 * 1024, Math.floor(freemem() * 0.1))), }, - }; + } satisfies SpawnSyncOptionsWithStringEncoding; try { if (!doBundle) { - // assert(moduleMode); if (enableAOT) { const wevalBin = await weval(); - let wevalProcess = spawnSync( + const wevalProcess = spawnSync( `"${wevalBin}"`, [ 'weval', @@ -279,7 +303,7 @@ export async function compileApplicationToWasm({ } process.exitCode = wevalProcess.status; } else { - let wizerProcess = spawnSync( + const wizerProcess = spawnSync( `"${wizer}"`, [ '--allow-wasi', @@ -302,7 +326,7 @@ export async function compileApplicationToWasm({ if (enableAOT) { const wevalBin = await weval(); - let wevalProcess = spawnSync( + const wevalProcess = spawnSync( `"${wevalBin}"`, [ 'weval', @@ -321,7 +345,7 @@ export async function compileApplicationToWasm({ } process.exitCode = wevalProcess.status; } else { - let wizerProcess = spawnSync( + const wizerProcess = spawnSync( `"${wizer}"`, [ '--inherit-env=true', @@ -341,12 +365,13 @@ export async function compileApplicationToWasm({ process.exitCode = wizerProcess.status; } } - } catch (error) { + } catch (maybeError: unknown) { + const error = maybeError instanceof Error ? maybeError : new Error(String(maybeError)); throw new Error( `Error: Failed to compile JavaScript to Wasm:\n${error.message}`, ); } finally { - if (doBundle) { + if (doBundle && tmpDir != null) { rmSync(tmpDir, { recursive: true }); } } diff --git a/src/composeSourcemaps.js b/src/composeSourcemaps.js deleted file mode 100644 index ee3f7895df..0000000000 --- a/src/composeSourcemaps.js +++ /dev/null @@ -1,48 +0,0 @@ -import { readFile } from 'node:fs/promises'; -import remapping from '@jridgewell/remapping'; -import { TraceMap } from '@jridgewell/trace-mapping'; -import picomatch from 'picomatch'; - -async function readSourcemap(e) { - const sourceMapJson = await readFile(e.s, { encoding: 'utf-8' }); - return JSON.parse(sourceMapJson); -} - -export async function composeSourcemaps(sourceMaps, excludePatterns = []) { - const top = new TraceMap(await readSourcemap(sourceMaps.pop())); - - const priors = {}; - for (const sourceMap of sourceMaps) { - priors[sourceMap.f] = await readSourcemap(sourceMap); - } - - // Loader: given a source name from mapXZ, return a TraceMap for that source (if any). - const loader = (source) => { - const m = priors[source]; - if (!m) return null; // no earlier map for this source - return new TraceMap(m); - }; - - const raw = JSON.parse(remapping(top, loader, false).toString()); - - return JSON.stringify(stripSourcesContent(raw, excludePatterns)); -} - -function stripSourcesContent(map, excludes) { - const matchers = excludes.map((p) => - typeof p === 'string' ? picomatch(p) : p, - ); - - for (let i = 0; i < map.sources.length; i++) { - const src = map.sources[i]; - - // [Windows] normalize slashes - const normalized = src.replace(/\\/g, '/'); - - if (matchers.some((fn) => fn(normalized))) { - map.sourcesContent[i] = null; - } - } - - return map; -} diff --git a/src/composeSourcemaps.ts b/src/composeSourcemaps.ts new file mode 100644 index 0000000000..31dfa0c308 --- /dev/null +++ b/src/composeSourcemaps.ts @@ -0,0 +1,68 @@ +import { readFile } from 'node:fs/promises'; +import remapping, { + SourceMap, + type SourceMapInput, + type SourceMapLoader, +} from '@jridgewell/remapping'; +import { TraceMap } from '@jridgewell/trace-mapping'; +import picomatch from 'picomatch'; + +export type ExcludePattern = string | ((file: string) => boolean); + +export type SourceMapInfo = { + f: string, // Filename + s: string, // Sourcemap filename +}; + +async function readSourcemap(e: SourceMapInfo) { + const sourceMapJson = await readFile(e.s, { encoding: 'utf-8' }); + return JSON.parse(sourceMapJson) as SourceMapInput; +} + +export async function composeSourcemaps(sourceMaps: SourceMapInfo[], excludePatterns: ExcludePattern[] = []) { + const topSourceMap = sourceMaps.pop(); + if (topSourceMap == null) { + throw new Error('Unexpected: composeSourcemaps received empty sourceMaps array.'); + } + + const top = new TraceMap(await readSourcemap(topSourceMap)); + + const priors: Record = {}; + for (const sourceMap of sourceMaps) { + priors[sourceMap.f] = await readSourcemap(sourceMap); + } + + // Loader: given a source name from mapXZ, return a TraceMap for that source (if any). + const loader: SourceMapLoader = (source) => { + const m = priors[source]; + if (!m) return null; // no earlier map for this source + return new TraceMap(m); + }; + + const raw = JSON.parse(remapping(top, loader, false).toString()) as SourceMap; + + return JSON.stringify(stripSourcesContent(raw, excludePatterns)); +} + +function stripSourcesContent(map: SourceMap, excludes: ExcludePattern[]) { + if (map.sourcesContent == null) { + return map; + } + + const matchers = excludes.map((p) => + typeof p === 'string' ? picomatch(p) : p, + ); + + for (let i = 0; i < map.sources.length; i++) { + const src = map.sources[i]; + + // [Windows] normalize slashes + const normalized = src?.replace(/\\/g, '/'); + + if (normalized == null || matchers.some((fn) => fn(normalized))) { + map.sourcesContent[i] = null; + } + } + + return map; +} diff --git a/src/env.js b/src/env.ts similarity index 89% rename from src/env.js rename to src/env.ts index 3e4fe6f232..ec66e8d1c0 100644 --- a/src/env.js +++ b/src/env.ts @@ -1,5 +1,5 @@ // env.js -function parseEnvPair(pair) { +function parseEnvPair(pair: string) { const trimmedPair = pair.trim(); // If no '=', treat as a variable to inherit @@ -14,7 +14,7 @@ function parseEnvPair(pair) { return [trimmedPair, value]; } - const matches = trimmedPair.match(/^([^=]+)=(.*)$/); + const matches = /^([^=]+)=(.*)$/.exec(trimmedPair); if (!matches) { throw new Error( `Invalid environment variable format: ${trimmedPair}\nMust be in format KEY=VALUE or an existing environment variable name`, @@ -33,8 +33,8 @@ function parseEnvPair(pair) { return [key, value]; } -function parseEnvString(envString) { - const result = {}; +function parseEnvString(envString: string) { + const result: Record = {}; // Split on unescaped commas and filter out empty strings const pairs = envString @@ -56,6 +56,8 @@ function parseEnvString(envString) { } export class EnvParser { + env: Record; + constructor() { this.env = {}; } @@ -65,7 +67,7 @@ export class EnvParser { * or names of environment variables to inherit * @param {string} value - The environment variable string to parse */ - parse(value) { + parse(value: string) { if (!value) { throw new Error( 'Invalid environment variable format: \nMust be in format KEY=VALUE or an existing environment variable name', diff --git a/src/isFile.js b/src/isFile.ts similarity index 69% rename from src/isFile.js rename to src/isFile.ts index ffbe2dc655..e08ad36f6c 100644 --- a/src/isFile.js +++ b/src/isFile.ts @@ -1,6 +1,6 @@ import { stat } from 'node:fs/promises'; -export async function isFile(path) { +export async function isFile(path: string) { const stats = await stat(path); return stats.isFile(); } diff --git a/src/isFileOrDoesNotExist.js b/src/isFileOrDoesNotExist.js deleted file mode 100644 index f26afef137..0000000000 --- a/src/isFileOrDoesNotExist.js +++ /dev/null @@ -1,13 +0,0 @@ -import { stat } from 'node:fs/promises'; - -export async function isFileOrDoesNotExist(path) { - try { - const stats = await stat(path); - return stats.isFile(); - } catch (error) { - if (error instanceof Error && error.code === 'ENOENT') { - return true; - } - throw error; - } -} diff --git a/src/isFileOrDoesNotExist.ts b/src/isFileOrDoesNotExist.ts new file mode 100644 index 0000000000..43d253d931 --- /dev/null +++ b/src/isFileOrDoesNotExist.ts @@ -0,0 +1,13 @@ +import { stat } from 'node:fs/promises'; + +export async function isFileOrDoesNotExist(path: string) { + try { + const stats = await stat(path); + return stats.isFile(); + } catch (error: unknown) { + if (error instanceof Error && 'code' in error && error.code === 'ENOENT') { + return true; + } + throw error; + } +} diff --git a/src/parseInputs.js b/src/parseInputs.ts similarity index 85% rename from src/parseInputs.js rename to src/parseInputs.ts index 1f85670c90..a10a0036d6 100644 --- a/src/parseInputs.js +++ b/src/parseInputs.ts @@ -4,7 +4,26 @@ import { unknownArgument } from './unknownArgument.js'; import { tooManyEngines } from './tooManyEngines.js'; import { EnvParser } from './env.js'; -export async function parseInputs(cliInputs) { +export type ParsedInputs = +| 'help' +| 'version' +| { + enableAOT: boolean, + aotCache: string, + enableHttpCache: boolean, + enableExperimentalHighResolutionTimeMethods: boolean, + moduleMode: boolean, + bundle: boolean, + enableStackTraces: boolean, + excludeSources: boolean, + debugIntermediateFilesDir: string | undefined, + wasmEngine: string, + input: string, + output: string, + env: Record, +}; + +export async function parseInputs(cliInputs: string[]): Promise { const __dirname = dirname(fileURLToPath(import.meta.url)); let enableHttpCache = false; @@ -26,14 +45,13 @@ export async function parseInputs(cliInputs) { const envParser = new EnvParser(); - // eslint-disable-next-line no-cond-assign loop: while ((cliInput = cliInputs.shift())) { switch (cliInput) { case '--': { break loop; } case '--env': { - const value = cliInputs.shift(); + let value = cliInputs.shift(); if (!value) { console.error('Error: --env requires a KEY=VALUE pair'); process.exit(1); @@ -81,11 +99,11 @@ export async function parseInputs(cliInputs) { } case '-V': case '--version': { - return { version: true }; + return 'version'; } case '-h': case '--help': { - return { help: true }; + return 'help'; } case '--starlingmonkey': { break; @@ -106,6 +124,10 @@ export async function parseInputs(cliInputs) { tooManyEngines(); } const value = cliInputs.shift(); + if (value == null) { + console.error('Error: --engine-wasm requires a value'); + process.exit(1); + } customEngineSet = true; if (isAbsolute(value)) { wasmEngine = value; @@ -116,6 +138,10 @@ export async function parseInputs(cliInputs) { } case '--aot-cache': { const value = cliInputs.shift(); + if (value == null) { + console.error('Error: --aot-cache requires a value'); + process.exit(1); + } if (isAbsolute(value)) { aotCache = value; } else { @@ -133,6 +159,10 @@ export async function parseInputs(cliInputs) { } case '--debug-intermediate-files': { const value = cliInputs.shift(); + if (value == null) { + console.error('Error: --aot-cache requires a value'); + process.exit(1); + } if (isAbsolute(value)) { debugIntermediateFilesDir = value; } else { diff --git a/src/postbundle.js b/src/postbundle.ts similarity index 98% rename from src/postbundle.js rename to src/postbundle.ts index 86521129e7..790ddd95fd 100644 --- a/src/postbundle.js +++ b/src/postbundle.ts @@ -6,8 +6,8 @@ import MagicString from 'magic-string'; import { simple as simpleWalk } from 'acorn-walk'; export async function postbundle( - input, - outfile, + input: string, + outfile: string, { moduleMode = false, enableStackTraces = false }, ) { const source = await readFile(input, { encoding: 'utf8' }); @@ -28,7 +28,7 @@ export async function postbundle( sourceType: moduleMode ? 'module' : 'script', }); - const precompileCalls = []; + const precompileCalls: string[] = []; simpleWalk(ast, { Literal(node) { if (!node.regex) return; diff --git a/src/printHelp.js b/src/printHelp.ts similarity index 100% rename from src/printHelp.js rename to src/printHelp.ts diff --git a/src/printVersion.js b/src/printVersion.ts similarity index 85% rename from src/printVersion.js rename to src/printVersion.ts index de9e72fb46..d10f7075da 100644 --- a/src/printVersion.js +++ b/src/printVersion.ts @@ -8,6 +8,6 @@ export async function printVersion() { const packageJson = await readFile(join(__dirname, '../package.json'), { encoding: 'utf-8', }); - const version = JSON.parse(packageJson).version; + const version = (JSON.parse(packageJson) as { version: string }).version; console.log(`${basename(argv[1])} ${version}`); } diff --git a/src/swallowTopLevelExportsPlugin.js b/src/swallowTopLevelExportsPlugin.ts similarity index 81% rename from src/swallowTopLevelExportsPlugin.js rename to src/swallowTopLevelExportsPlugin.ts index fbe7a1f541..4035f954ae 100644 --- a/src/swallowTopLevelExportsPlugin.js +++ b/src/swallowTopLevelExportsPlugin.ts @@ -1,7 +1,12 @@ import { dirname, isAbsolute, resolve } from 'node:path'; +import { type Plugin } from 'esbuild'; -export function swallowTopLevelExportsPlugin(opts) { - const { entry } = opts; +export type SwallowTopLevelExportsPluginParams = { + entry?: string; +}; + +export function swallowTopLevelExportsPlugin(opts?: SwallowTopLevelExportsPluginParams) { + const { entry } = opts ?? {}; const name = 'swallow-top-level-exports'; const namespace = 'swallow-top-level'; @@ -33,5 +38,5 @@ export function swallowTopLevelExportsPlugin(opts) { }; }); }, - }; + } satisfies Plugin; } diff --git a/src/tooManyEngines.js b/src/tooManyEngines.ts similarity index 100% rename from src/tooManyEngines.js rename to src/tooManyEngines.ts diff --git a/src/types/modules.d.ts b/src/types/modules.d.ts new file mode 100644 index 0000000000..e9b6174a11 --- /dev/null +++ b/src/types/modules.d.ts @@ -0,0 +1,9 @@ +declare module '@bytecodealliance/wizer' { + const wizer: string; + export default wizer; +} + +declare module '@bytecodealliance/weval' { + function getWeval(): Promise; + export default getWeval; +} diff --git a/src/unknownArgument.js b/src/unknownArgument.ts similarity index 80% rename from src/unknownArgument.js rename to src/unknownArgument.ts index 68d5071a2e..5a92411aad 100644 --- a/src/unknownArgument.js +++ b/src/unknownArgument.ts @@ -1,4 +1,4 @@ -export function unknownArgument(cliInput) { +export function unknownArgument(cliInput: string) { console.error(`error: Found argument '${cliInput}' which wasn't expected, or isn't valid in this context USAGE: diff --git a/tests/wpt-harness/build-wpt-runtime.sh b/tests/wpt-harness/build-wpt-runtime.sh index 28fe128010..0f268a7768 100755 --- a/tests/wpt-harness/build-wpt-runtime.sh +++ b/tests/wpt-harness/build-wpt-runtime.sh @@ -10,4 +10,4 @@ inputs=( ) cat "${inputs[@]}" > "${script_dir}/wpt-test-runner.js" -node "${script_dir}/../../js-compute-runtime-cli.js" "${script_dir}/wpt-test-runner.js" "$@" wpt-runtime.wasm +node "${script_dir}/../../dist/cli/js-compute-runtime-cli.js" "${script_dir}/wpt-test-runner.js" "$@" wpt-runtime.wasm diff --git a/tsconfig.json b/tsconfig.json index 8056264786..6cfce1b4cc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,16 +1,20 @@ { "compilerOptions": { "target": "es2022", - "module": "es2022", + "module": "nodenext", "lib": ["es2022"], - "outDir": "./build", + "outDir": "./dist", + "rootDir": "./src", "strict": true, - "moduleResolution": "node", - "skipLibCheck": false, + "moduleResolution": "nodenext", + "skipLibCheck": true, "forceConsistentCasingInFileNames": true, - "types": [] + "allowJs": true }, "include": [ - "types/index.d.ts" + "src/**/*.ts", + ], + "exclude": [ + "node_modules" ] } From c46844e8299af9922c5d3c4ff5b7beda2c03907a Mon Sep 17 00:00:00 2001 From: Katsuyuki Omuro Date: Sun, 7 Dec 2025 02:32:34 +0900 Subject: [PATCH 3/6] Clean up files (combine help, file checks) --- .../cli/output-path-is-not-a-file.test.js | 2 +- src/cli/js-compute-runtime-cli.ts | 3 +- src/compileApplicationToWasm.ts | 34 +++++++++---------- src/isFile.ts | 5 +++ src/isFileOrDoesNotExist.ts | 13 ------- src/parseInputs.ts | 3 +- src/printHelp.ts | 34 +++++++++++++++++-- src/printVersion.ts | 13 ------- src/tooManyEngines.ts | 9 ----- src/unknownArgument.ts | 9 ----- 10 files changed, 56 insertions(+), 69 deletions(-) delete mode 100644 src/isFileOrDoesNotExist.ts delete mode 100644 src/printVersion.ts delete mode 100644 src/tooManyEngines.ts delete mode 100644 src/unknownArgument.ts diff --git a/integration-tests/cli/output-path-is-not-a-file.test.js b/integration-tests/cli/output-path-is-not-a-file.test.js index d1cae1129c..fae5a54387 100644 --- a/integration-tests/cli/output-path-is-not-a-file.test.js +++ b/integration-tests/cli/output-path-is-not-a-file.test.js @@ -18,7 +18,7 @@ test('should return non-zero exit code', async function (t) { ok( stderr .toString() - .startsWith('Error: The `output` path does not point to a file:'), + .startsWith('Error: The `output` path points to a directory:'), ); ok(stderr.toString().endsWith('main.wasm')); t.is(code, 1); diff --git a/src/cli/js-compute-runtime-cli.ts b/src/cli/js-compute-runtime-cli.ts index e6091cf9c5..5f9d65287f 100755 --- a/src/cli/js-compute-runtime-cli.ts +++ b/src/cli/js-compute-runtime-cli.ts @@ -1,8 +1,7 @@ #!/usr/bin/env node import { parseInputs } from '../parseInputs.js'; -import { printVersion } from '../printVersion.js'; -import { printHelp } from '../printHelp.js'; +import { printHelp, printVersion } from '../printHelp.js'; import { addSdkMetadataField } from '../addSdkMetadataField.js'; const parsedInputs = await parseInputs(process.argv.slice(2)); diff --git a/src/compileApplicationToWasm.ts b/src/compileApplicationToWasm.ts index e0b5e28aa9..7a9983d89a 100644 --- a/src/compileApplicationToWasm.ts +++ b/src/compileApplicationToWasm.ts @@ -12,8 +12,7 @@ import { rmSync } from 'node:fs'; import weval from '@bytecodealliance/weval'; import wizer from '@bytecodealliance/wizer'; -import { isFile } from './isFile.js'; -import { isFileOrDoesNotExist } from './isFileOrDoesNotExist.js'; +import { isDirectory, isFile } from './isFile.js'; import { postbundle } from './postbundle.js'; import { bundle } from './bundle.js'; import { composeSourcemaps, ExcludePattern } from './composeSourcemaps.js'; @@ -102,30 +101,29 @@ export async function compileApplicationToWasm(params: CompileApplicationToWasmP ); process.exit(1); } - try { - await mkdir(dirname(output), { - recursive: true, - }); - } catch (maybeError: unknown) { - const error = maybeError instanceof Error ? maybeError : new Error(String(maybeError)); - console.error( - `Error: Failed to create the \`output\` (${output}) directory`, - error.message, - ); - process.exit(1); - } + // If output exists already, make sure it's not a directory + // (we'll try to overwrite it if it's a file) try { - if (!(await isFileOrDoesNotExist(output))) { + if (await isDirectory(output)) { console.error( - `Error: The \`output\` path does not point to a file: ${output}`, + `Error: The \`output\` path points to a directory: ${output}`, ); process.exit(1); } + } catch { + // Output doesn't exist + } + + try { + await mkdir(dirname(output), { + recursive: true, + }); } catch (maybeError: unknown) { - const error = maybeError instanceof Error ? maybeError : new Error(String(maybeError)); + const error = + maybeError instanceof Error ? maybeError : new Error(String(maybeError)); console.error( - `Error: Failed to check whether the \`output\` (${output}) is a file path`, + `Error: Failed to create the \`output\` (${dirname(output)}) directory: ${output}`, error.message, ); process.exit(1); diff --git a/src/isFile.ts b/src/isFile.ts index e08ad36f6c..207be7dac7 100644 --- a/src/isFile.ts +++ b/src/isFile.ts @@ -4,3 +4,8 @@ export async function isFile(path: string) { const stats = await stat(path); return stats.isFile(); } + +export async function isDirectory(path: string) { + const stats = await stat(path); + return stats.isDirectory(); +} diff --git a/src/isFileOrDoesNotExist.ts b/src/isFileOrDoesNotExist.ts deleted file mode 100644 index 43d253d931..0000000000 --- a/src/isFileOrDoesNotExist.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { stat } from 'node:fs/promises'; - -export async function isFileOrDoesNotExist(path: string) { - try { - const stats = await stat(path); - return stats.isFile(); - } catch (error: unknown) { - if (error instanceof Error && 'code' in error && error.code === 'ENOENT') { - return true; - } - throw error; - } -} diff --git a/src/parseInputs.ts b/src/parseInputs.ts index a10a0036d6..0258fd8603 100644 --- a/src/parseInputs.ts +++ b/src/parseInputs.ts @@ -1,7 +1,6 @@ import { fileURLToPath } from 'node:url'; import { dirname, join, isAbsolute } from 'node:path'; -import { unknownArgument } from './unknownArgument.js'; -import { tooManyEngines } from './tooManyEngines.js'; +import { tooManyEngines, unknownArgument } from './printHelp.js'; import { EnvParser } from './env.js'; export type ParsedInputs = diff --git a/src/printHelp.ts b/src/printHelp.ts index 52bfdf492d..c1c85d0592 100644 --- a/src/printHelp.ts +++ b/src/printHelp.ts @@ -1,6 +1,8 @@ -import { basename } from 'node:path'; +import { readFile } from 'node:fs/promises'; +import { basename, dirname, join } from 'node:path'; import { argv } from 'node:process'; -import { printVersion } from './printVersion.js'; +import { fileURLToPath } from 'node:url'; +const __dirname = dirname(fileURLToPath(import.meta.url)); export async function printHelp() { await printVersion(); @@ -34,3 +36,31 @@ ARGS: The file path to write the output Wasm module to [default: bin/main.wasm] `); } + +export async function printVersion() { + const packageJson = await readFile(join(__dirname, '../package.json'), { + encoding: 'utf-8', + }); + const version = (JSON.parse(packageJson) as { version: string }).version; + console.log(`${basename(argv[1])} ${version}`); +} + +export function tooManyEngines() { + console.error(`error: The argument '--engine-wasm ' was provided more than once, but cannot be used multiple times + +USAGE: + js-compute-runtime --engine-wasm + +For more information try --help`); + process.exit(1); +} + +export function unknownArgument(cliInput: string) { + console.error(`error: Found argument '${cliInput}' which wasn't expected, or isn't valid in this context + +USAGE: + js-compute-runtime [FLAGS] [OPTIONS] [ARGS] + +For more information try --help`); + process.exit(1); +} diff --git a/src/printVersion.ts b/src/printVersion.ts deleted file mode 100644 index d10f7075da..0000000000 --- a/src/printVersion.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { readFile } from 'node:fs/promises'; -import { basename, dirname, join } from 'node:path'; -import { argv } from 'node:process'; -import { fileURLToPath } from 'node:url'; -const __dirname = dirname(fileURLToPath(import.meta.url)); - -export async function printVersion() { - const packageJson = await readFile(join(__dirname, '../package.json'), { - encoding: 'utf-8', - }); - const version = (JSON.parse(packageJson) as { version: string }).version; - console.log(`${basename(argv[1])} ${version}`); -} diff --git a/src/tooManyEngines.ts b/src/tooManyEngines.ts deleted file mode 100644 index 34e1d0324e..0000000000 --- a/src/tooManyEngines.ts +++ /dev/null @@ -1,9 +0,0 @@ -export function tooManyEngines() { - console.error(`error: The argument '--engine-wasm ' was provided more than once, but cannot be used multiple times - -USAGE: - js-compute-runtime --engine-wasm - -For more information try --help`); - process.exit(1); -} diff --git a/src/unknownArgument.ts b/src/unknownArgument.ts deleted file mode 100644 index 5a92411aad..0000000000 --- a/src/unknownArgument.ts +++ /dev/null @@ -1,9 +0,0 @@ -export function unknownArgument(cliInput: string) { - console.error(`error: Found argument '${cliInput}' which wasn't expected, or isn't valid in this context - -USAGE: - js-compute-runtime [FLAGS] [OPTIONS] [ARGS] - -For more information try --help`); - process.exit(1); -} From 4500240dff7352c410fa4fdac64ca1d29e7a7a46 Mon Sep 17 00:00:00 2001 From: Katsuyuki Omuro Date: Sun, 7 Dec 2025 02:34:14 +0900 Subject: [PATCH 4/6] Prettier --- package.json | 4 +- src/addSdkMetadataField.ts | 5 ++- src/compileApplicationToWasm.ts | 61 ++++++++++++++++++----------- src/composeSourcemaps.ts | 13 ++++-- src/parseInputs.ts | 34 ++++++++-------- src/swallowTopLevelExportsPlugin.ts | 4 +- 6 files changed, 74 insertions(+), 47 deletions(-) diff --git a/package.json b/package.json index 1773cbd2cf..d29db6043c 100644 --- a/package.json +++ b/package.json @@ -40,8 +40,8 @@ "build:weval": "./runtime/fastly/build-release-weval.sh", "build:debug:info": "./runtime/fastly/build-debug.sh --keep-debug-info", "format-changelog": "node ci/format-changelog.js CHANGELOG.md", - "format": "prettier --write *.js src/*.js integration-tests types test-d", - "format:check": "prettier --check *.js src/*.js integration-tests" + "format": "prettier --write 'src/**/*.ts' integration-tests types test-d", + "format:check": "prettier --check 'src/**/*.ts' integration-tests" }, "dependencies": { "@bytecodealliance/jco": "^1.7.0", diff --git a/src/addSdkMetadataField.ts b/src/addSdkMetadataField.ts index d70a97f93e..91ac5f4afa 100644 --- a/src/addSdkMetadataField.ts +++ b/src/addSdkMetadataField.ts @@ -9,7 +9,10 @@ export async function addSdkMetadataField(wasmPath: string, usingAOT: boolean) { encoding: 'utf-8', }); - const { name, version } = JSON.parse(packageJson) as { name: string, version: string, }; + const { name, version } = JSON.parse(packageJson) as { + name: string; + version: string; + }; let sdkName: string; if (usingAOT) { diff --git a/src/compileApplicationToWasm.ts b/src/compileApplicationToWasm.ts index 7a9983d89a..04622018f5 100644 --- a/src/compileApplicationToWasm.ts +++ b/src/compileApplicationToWasm.ts @@ -1,6 +1,9 @@ import { dirname, resolve, sep, normalize } from 'node:path'; import { tmpdir, freemem } from 'node:os'; -import { spawnSync, type SpawnSyncOptionsWithStringEncoding } from 'node:child_process'; +import { + spawnSync, + type SpawnSyncOptionsWithStringEncoding, +} from 'node:child_process'; import { mkdir, readFile, @@ -29,23 +32,24 @@ async function getTmpDir() { } export type CompileApplicationToWasmParams = { - input: string, - output: string, - wasmEngine: string, - enableHttpCache: boolean, - enableExperimentalHighResolutionTimeMethods: boolean, - enableAOT: boolean, - aotCache: string, - enableStackTraces: boolean, - excludeSources: boolean, - debugIntermediateFilesDir: string | undefined, - moduleMode: boolean, - doBundle: boolean, - env: Record, + input: string; + output: string; + wasmEngine: string; + enableHttpCache: boolean; + enableExperimentalHighResolutionTimeMethods: boolean; + enableAOT: boolean; + aotCache: string; + enableStackTraces: boolean; + excludeSources: boolean; + debugIntermediateFilesDir: string | undefined; + moduleMode: boolean; + doBundle: boolean; + env: Record; }; -export async function compileApplicationToWasm(params: CompileApplicationToWasmParams) { - +export async function compileApplicationToWasm( + params: CompileApplicationToWasmParams, +) { const { output, wasmEngine, @@ -80,7 +84,8 @@ export async function compileApplicationToWasm(params: CompileApplicationToWasmP try { await readFile(input, { encoding: 'utf-8' }); } catch (maybeError: unknown) { - const error = maybeError instanceof Error ? maybeError : new Error(String(maybeError)); + const error = + maybeError instanceof Error ? maybeError : new Error(String(maybeError)); console.error( `Error: Failed to open the \`input\` (${input})`, error.message, @@ -138,7 +143,10 @@ export async function compileApplicationToWasm(params: CompileApplicationToWasmP recursive: true, }); } catch (maybeError: unknown) { - const error = maybeError instanceof Error ? maybeError : new Error(String(maybeError)); + const error = + maybeError instanceof Error + ? maybeError + : new Error(String(maybeError)); console.error( `Error: Failed to create the \`debug-intermediate-files\` (${debugIntermediateFilesDir}) directory`, error.message, @@ -164,7 +172,10 @@ export async function compileApplicationToWasm(params: CompileApplicationToWasmP enableStackTraces, }); } catch (maybeError: unknown) { - const error = maybeError instanceof Error ? maybeError : new Error(String(maybeError)); + const error = + maybeError instanceof Error + ? maybeError + : new Error(String(maybeError)); console.error(`Error:`, error.message); process.exit(1); } @@ -215,7 +226,10 @@ export async function compileApplicationToWasm(params: CompileApplicationToWasmP if (enableStackTraces) { // Compose source maps const replaceSourceMapToken = '__FINAL_SOURCE_MAP__'; - let excludePatterns: ExcludePattern[] = ['forbid-entry:/**', 'node_modules/**']; + let excludePatterns: ExcludePattern[] = [ + 'forbid-entry:/**', + 'node_modules/**', + ]; if (excludeSources) { excludePatterns = [() => true]; } @@ -274,7 +288,9 @@ export async function compileApplicationToWasm(params: CompileApplicationToWasmP ENABLE_EXPERIMENTAL_HIGH_RESOLUTION_TIME_METHODS: enableExperimentalHighResolutionTimeMethods ? '1' : '0', ENABLE_EXPERIMENTAL_HTTP_CACHE: enableHttpCache ? '1' : '0', - RUST_MIN_STACK: String(Math.max(8 * 1024 * 1024, Math.floor(freemem() * 0.1))), + RUST_MIN_STACK: String( + Math.max(8 * 1024 * 1024, Math.floor(freemem() * 0.1)), + ), }, } satisfies SpawnSyncOptionsWithStringEncoding; @@ -364,7 +380,8 @@ export async function compileApplicationToWasm(params: CompileApplicationToWasmP } } } catch (maybeError: unknown) { - const error = maybeError instanceof Error ? maybeError : new Error(String(maybeError)); + const error = + maybeError instanceof Error ? maybeError : new Error(String(maybeError)); throw new Error( `Error: Failed to compile JavaScript to Wasm:\n${error.message}`, ); diff --git a/src/composeSourcemaps.ts b/src/composeSourcemaps.ts index 31dfa0c308..8910d4f1e8 100644 --- a/src/composeSourcemaps.ts +++ b/src/composeSourcemaps.ts @@ -10,8 +10,8 @@ import picomatch from 'picomatch'; export type ExcludePattern = string | ((file: string) => boolean); export type SourceMapInfo = { - f: string, // Filename - s: string, // Sourcemap filename + f: string; // Filename + s: string; // Sourcemap filename }; async function readSourcemap(e: SourceMapInfo) { @@ -19,10 +19,15 @@ async function readSourcemap(e: SourceMapInfo) { return JSON.parse(sourceMapJson) as SourceMapInput; } -export async function composeSourcemaps(sourceMaps: SourceMapInfo[], excludePatterns: ExcludePattern[] = []) { +export async function composeSourcemaps( + sourceMaps: SourceMapInfo[], + excludePatterns: ExcludePattern[] = [], +) { const topSourceMap = sourceMaps.pop(); if (topSourceMap == null) { - throw new Error('Unexpected: composeSourcemaps received empty sourceMaps array.'); + throw new Error( + 'Unexpected: composeSourcemaps received empty sourceMaps array.', + ); } const top = new TraceMap(await readSourcemap(topSourceMap)); diff --git a/src/parseInputs.ts b/src/parseInputs.ts index 0258fd8603..61e80286b9 100644 --- a/src/parseInputs.ts +++ b/src/parseInputs.ts @@ -4,23 +4,23 @@ import { tooManyEngines, unknownArgument } from './printHelp.js'; import { EnvParser } from './env.js'; export type ParsedInputs = -| 'help' -| 'version' -| { - enableAOT: boolean, - aotCache: string, - enableHttpCache: boolean, - enableExperimentalHighResolutionTimeMethods: boolean, - moduleMode: boolean, - bundle: boolean, - enableStackTraces: boolean, - excludeSources: boolean, - debugIntermediateFilesDir: string | undefined, - wasmEngine: string, - input: string, - output: string, - env: Record, -}; + | 'help' + | 'version' + | { + enableAOT: boolean; + aotCache: string; + enableHttpCache: boolean; + enableExperimentalHighResolutionTimeMethods: boolean; + moduleMode: boolean; + bundle: boolean; + enableStackTraces: boolean; + excludeSources: boolean; + debugIntermediateFilesDir: string | undefined; + wasmEngine: string; + input: string; + output: string; + env: Record; + }; export async function parseInputs(cliInputs: string[]): Promise { const __dirname = dirname(fileURLToPath(import.meta.url)); diff --git a/src/swallowTopLevelExportsPlugin.ts b/src/swallowTopLevelExportsPlugin.ts index 4035f954ae..20157bc532 100644 --- a/src/swallowTopLevelExportsPlugin.ts +++ b/src/swallowTopLevelExportsPlugin.ts @@ -5,7 +5,9 @@ export type SwallowTopLevelExportsPluginParams = { entry?: string; }; -export function swallowTopLevelExportsPlugin(opts?: SwallowTopLevelExportsPluginParams) { +export function swallowTopLevelExportsPlugin( + opts?: SwallowTopLevelExportsPluginParams, +) { const { entry } = opts ?? {}; const name = 'swallow-top-level-exports'; From 563bff826237a02d92f694a66d8f3ac559914e73 Mon Sep 17 00:00:00 2001 From: Katsuyuki Omuro Date: Tue, 9 Dec 2025 13:46:43 +0900 Subject: [PATCH 5/6] allow license combo (LicenseRef-scancode-unicode AND MIT) --- .github/workflows/dependencies.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index ebcafb81c7..05ce8664f8 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -11,5 +11,5 @@ jobs: steps: - uses: actions/dependency-review-action@v2.2.0 with: - allow-licenses: Apache-2.0, MIT, BSD-3-Clause, ISC, BSD-2-Clause, MIT OR (CC0-1.0 AND MIT), CC0-1.0 OR MIT OR (CC0-1.0 AND MIT), CC-BY-3.0, CC0-1.0, MIT OR Apache-2.0, MIT AND Apache-2.0, MIT OR WTFPL, BSD-2-Clause OR (MIT OR Apache-2.0), Python-2.0, ISC AND MIT, Apache-2.0 AND MIT, MIT/Apache-2.0, Apache-2.0 OR MIT, (Apache-2.0 OR MIT) AND BSD-3-Clause, Zlib OR Apache-2.0 OR MIT, MIT OR Apache-2.0 OR Zlib, MIT OR (Apache-2.0 OR Zlib), (Apache-2.0 WITH LLVM-exception), 0BSD, CC-BY-4.0, Unlicense, MPL-1.1 + allow-licenses: Apache-2.0, MIT, BSD-3-Clause, ISC, BSD-2-Clause, MIT OR (CC0-1.0 AND MIT), CC0-1.0 OR MIT OR (CC0-1.0 AND MIT), CC-BY-3.0, CC0-1.0, MIT OR Apache-2.0, MIT AND Apache-2.0, MIT OR WTFPL, BSD-2-Clause OR (MIT OR Apache-2.0), Python-2.0, ISC AND MIT, Apache-2.0 AND MIT, MIT/Apache-2.0, Apache-2.0 OR MIT, (Apache-2.0 OR MIT) AND BSD-3-Clause, Zlib OR Apache-2.0 OR MIT, MIT OR Apache-2.0 OR Zlib, MIT OR (Apache-2.0 OR Zlib), (Apache-2.0 WITH LLVM-exception), 0BSD, CC-BY-4.0, Unlicense, MPL-1.1, LicenseRef-scancode-unicode AND MIT fail-on-scopes: runtime From 37962b034738ce055c58776a7d60aa2efecf371e Mon Sep 17 00:00:00 2001 From: Katsuyuki Omuro Date: Wed, 10 Dec 2025 23:40:38 +0900 Subject: [PATCH 6/6] Build CLI when setting up sdktest and sdk-test --- .github/workflows/main.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5fd60ef079..e457d1b0d5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -400,6 +400,9 @@ jobs: - name: Npm install run: npm install && cd ./integration-tests/js-compute && npm install + - name: Build CLI + run: npm run build:cli + - name: Run Tests run: SUFFIX_STRING=${{matrix.profile}} node integration-tests/js-compute/test.js --ci --skip-teardown${{ matrix.platform == 'viceroy' && ' --local' || '' }}${{ matrix.profile == 'weval' && ' --aot' || '' }}${{ matrix.features == 'http-cache' && ' --http-cache' || '' }} env: @@ -467,6 +470,9 @@ jobs: - name: Npm install run: npm install && cd ./integration-tests/js-compute && npm install + - name: Build CLI + run: npm run build:cli + - name: Run Tests run: SUFFIX_STRING=debug node integration-tests/js-compute/test.js --ci --skip-teardown --debug-build${{ matrix.platform == 'viceroy' && ' --local' || '' }}${{ matrix.features == 'http-cache' && ' --http-cache' || '' }} env: