diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index d600cdd550..9d848348e2 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -33,6 +33,7 @@ jobs: - uses: actions/checkout@v4 - name: Install dependencies uses: ./.github/actions/setup + - run: pnpm codemod - run: pnpm check - run: pnpm dtslint @@ -61,6 +62,7 @@ jobs: - uses: actions/checkout@v4 - name: Install dependencies uses: ./.github/actions/setup + - run: pnpm codemod - uses: oven-sh/setup-bun@v1 if: matrix.runtime == 'Bun' with: diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index c9b56d14ce..290ecf4727 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -16,8 +16,10 @@ jobs: - uses: actions/checkout@v4 - name: Install dependencies uses: ./.github/actions/setup + - name: Run codemods + run: pnpm codemod - name: Build package run: pnpm build - name: Create snapshot id: snapshot - run: pnpx pkg-pr-new@0.0.17 publish --pnpm --comment=off ./packages/* + run: pnpx pkg-pr-new@0.0.28 publish --pnpm --comment=off ./packages/* diff --git a/package.json b/package.json index afca4365b2..78a4539f6b 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "scripts": { "clean": "node scripts/clean.mjs", "codegen": "pnpm --recursive --parallel run codegen", + "codemod": "node scripts/codemod.mjs", "build": "tsc -b tsconfig.build.json && pnpm --recursive --parallel run build", "circular": "node scripts/circular.mjs", "test": "vitest", @@ -20,7 +21,7 @@ "dtslint": "pnpm --recursive --parallel run dtslint", "dtslint-clean": "dtslint --installAll", "changeset-version": "changeset version && node scripts/version.mjs", - "changeset-publish": "pnpm build && TEST_DIST= pnpm vitest && changeset publish" + "changeset-publish": "pnpm codemod && pnpm lint-fix && pnpm build && TEST_DIST= pnpm vitest && changeset publish" }, "resolutions": { "dependency-tree": "^10.0.9", @@ -51,6 +52,7 @@ "@eslint/compat": "1.1.1", "@eslint/eslintrc": "3.1.0", "@eslint/js": "9.9.1", + "@types/jscodeshift": "^0.11.11", "@types/node": "^22.5.4", "@typescript-eslint/eslint-plugin": "^7.16.0", "@typescript-eslint/parser": "^7.16.0", @@ -58,6 +60,7 @@ "@vitest/coverage-v8": "^2.0.5", "@vitest/expect": "^2.0.5", "@vitest/web-worker": "^2.0.5", + "ast-types": "^0.14.2", "babel-plugin-annotate-pure-calls": "^0.4.0", "eslint": "^9.9.1", "eslint-import-resolver-typescript": "^3.6.3", @@ -68,6 +71,7 @@ "eslint-plugin-sort-destructure-keys": "^2.0.0", "fast-check": "^3.21.0", "glob": "^11.0.0", + "jscodeshift": "^0.16.1", "madge": "^8.0.0", "playwright": "^1.46.0", "prettier": "^3.3.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8f12c73dfe..0f15e3c347 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -78,6 +78,9 @@ importers: '@eslint/js': specifier: 9.9.1 version: 9.9.1 + '@types/jscodeshift': + specifier: ^0.11.11 + version: 0.11.11 '@types/node': specifier: ^22.5.4 version: 22.5.4 @@ -99,6 +102,9 @@ importers: '@vitest/web-worker': specifier: ^2.0.5 version: 2.0.5(vitest@2.0.5(@edge-runtime/vm@4.0.1)(@types/node@22.5.4)(@vitest/browser@2.0.5)(happy-dom@14.12.3)(terser@5.32.0)) + ast-types: + specifier: ^0.14.2 + version: 0.14.2 babel-plugin-annotate-pure-calls: specifier: ^0.4.0 version: 0.4.0(patch_hash=lz2aochwly4t7pzapzh4fqay4m)(@babel/core@7.25.2) @@ -129,6 +135,9 @@ importers: glob: specifier: ^11.0.0 version: 11.0.0 + jscodeshift: + specifier: ^0.16.1 + version: 0.16.1(@babel/preset-env@7.25.4(@babel/core@7.25.2)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.6.2) @@ -5190,6 +5199,7 @@ packages: libsql@0.4.5: resolution: {integrity: sha512-sorTJV6PNt94Wap27Sai5gtVLIea4Otb2LUiAUyr3p6BPOScGMKGt5F1b5X/XgkNtcsDKeX5qfeBDj+PdShclQ==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lighthouse-logger@1.4.2: diff --git a/scripts/codemod.mjs b/scripts/codemod.mjs new file mode 100644 index 0000000000..bdcb0eb22c --- /dev/null +++ b/scripts/codemod.mjs @@ -0,0 +1,22 @@ +// @ts-check +import * as Glob from "glob" +import jscodeshift from "jscodeshift/src/Runner.js" +import * as Fs from "node:fs" +import * as Path from "node:path" + +const packageJsonPath = Path.resolve("package.json") +const packageJson = JSON.parse(Fs.readFileSync(packageJsonPath, "utf-8")) +const workspaces = Glob.globSync(packageJson["workspaces"]) +const packages = workspaces.map((workspace) => workspace.replace("packages/", "")) +const pattern = `packages/{${packages.join(",")}}/src/**/*.ts` + +const paths = Glob.globSync(pattern, { + ignore: ["**/internal/**"] +}).map((path) => Path.resolve(path)) + +const transformer = Path.resolve("scripts/codemods/jsdoc.ts") + +jscodeshift.run(Path.resolve(transformer), paths, { + babel: true, + parser: "ts" +}) diff --git a/scripts/codemods/jsdoc.ts b/scripts/codemods/jsdoc.ts new file mode 100644 index 0000000000..196f04f48a --- /dev/null +++ b/scripts/codemods/jsdoc.ts @@ -0,0 +1,72 @@ +import type cs from "jscodeshift" + +// +// this is needed to resolve a bug in jscodeshift that +// forgets to traverse type parameters in call expressions +// +declare module "ast-types/gen/namedTypes.js" { + namespace namedTypes { + interface CallExpression extends TSHasOptionalTypeParameterInstantiation {} + } +} + +export default function transformer(file: cs.FileInfo, api: cs.API) { + const j = api.jscodeshift + + const root = j(file.source) + + root.find(j.ExportNamedDeclaration, { + declaration: { + type: "VariableDeclaration", + declarations: [{ + type: "VariableDeclarator", + id: { + type: "Identifier", + typeAnnotation: { + type: "TSTypeAnnotation", + typeAnnotation: { + type: "TSTypeLiteral", + members: [{ type: "TSCallSignatureDeclaration" }] + } + } + } + }] + } + }).forEach((path) => { + const comments = path.node.comments ?? [] + j(path).find(j.TSCallSignatureDeclaration).forEach((path) => { + // Don't override comments if they already exist + if (!Array.isArray(path.node.comments)) { + path.node.comments = comments + } + }) + }) + + root.find(j.ExportNamedDeclaration, { + declaration: { + type: "VariableDeclaration", + declarations: [{ + type: "VariableDeclarator", + init: { + type: "CallExpression", + callee: { + type: "Identifier", + name: "dual" + } + } + }] + } + }).forEach((path) => { + const comments = path.node.comments ?? [] + j(path).find(j.CallExpression).forEach((path) => { + path.node.typeParameters?.params.forEach((param) => { + // Don't override comments if they already exist + if (!Array.isArray(param.comments)) { + param.comments = comments + } + }) + }) + }) + + return root.toSource() +}