diff --git a/.github/assets/.gitkeep b/.github/assets/.gitkeep deleted file mode 100644 index 139597f..0000000 --- a/.github/assets/.gitkeep +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml new file mode 100644 index 0000000..5b689e1 --- /dev/null +++ b/.github/workflows/code-quality.yml @@ -0,0 +1,134 @@ +name: Code Quality + +on: + push: + paths: + - "codemods/**/*.js" + - "codemods/**/*.ts" + - "codemods/**/*.tsx" + - "codemods/**/*.jsx" + - "codemods/**/codemod.yaml" + - "codemods/**/workflow.yaml" + - "codemods/**/package.json" + - "codemods/**/package-lock.json" + - "codemods/**/tests/**" + - "package.json" + - "package-lock.json" + - "tsconfig.json" + - "biome.jsonc" + - ".github/workflows/code-quality.yml" + pull_request: + paths: + - "codemods/**/*.js" + - "codemods/**/*.ts" + - "codemods/**/*.tsx" + - "codemods/**/*.jsx" + - "codemods/**/codemod.yaml" + - "codemods/**/workflow.yaml" + - "codemods/**/package.json" + - "codemods/**/package-lock.json" + - "codemods/**/tests/**" + - "package.json" + - "package-lock.json" + - "tsconfig.json" + - "biome.jsonc" + - ".github/workflows/code-quality.yml" + types: + - opened + - ready_for_review + - reopened + - synchronize + +permissions: + contents: read + +jobs: + lint-and-types: + name: Lint & types + runs-on: ubuntu-slim + + if: ${{ github.event_name != 'pull_request' || !github.event.pull_request.draft }} + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + show-progress: false + + - name: Set up Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + cache: "npm" + node-version: "lts/*" + + - run: npm ci + - run: node --run check + - run: node --run typecheck + + test: + name: Before/After tests + runs-on: ${{ matrix.os }} + + if: ${{ github.event_name != 'pull_request' || !github.event.pull_request.draft }} + + strategy: + fail-fast: false + matrix: + os: + - macos-latest + - ubuntu-latest + - windows-latest + + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 + with: + egress-policy: audit + + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + persist-credentials: false + show-progress: false + + - name: Set up Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + cache: "npm" + node-version: "lts/*" + + - run: npm ci + + - name: Run tests related to changes + shell: bash + run: | + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + base_sha="${{ github.event.pull_request.base.sha }}" + elif [[ "${{ github.event.before }}" =~ ^0+$ ]]; then + base_sha="$(git merge-base origin/${{ github.event.repository.default_branch }} HEAD)" + else + base_sha="${{ github.event.before }}" + fi + + changed_paths="$(git diff --name-only "$base_sha" "${{ github.sha }}")" + + # Run everything when shared configuration or workflow behavior changes. + if echo "$changed_paths" | grep -qE '^(package(-lock)?\.json|tsconfig\.json|biome\.jsonc|\.github/workflows/code-quality\.yml)$'; then + npm run test --workspaces --if-present + exit 0 + fi + + codemod_paths="$(echo "$changed_paths" | grep '^codemods/' || true)" + workspaces="$( + echo "$codemod_paths" \ + | cut -d/ -f1,2 \ + | sort -u \ + | sed 's/^/--workspace=/' + )" + + if [[ -z "$workspaces" ]]; then + echo "No codemod workspaces changed; skipping before/after tests." + exit 0 + fi + + npm run test --if-present $workspaces diff --git a/.github/workflows/codemod-publish.yaml b/.github/workflows/codemod-publish.yaml index 6c48d85..b1546a5 100644 --- a/.github/workflows/codemod-publish.yaml +++ b/.github/workflows/codemod-publish.yaml @@ -166,12 +166,11 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: 22 + node-version: 'lts/*' - name: Install project dependencies run: | - npm install --no-frozen-lockfile - npm install -g codemod@latest + npm ci # Run test before login to not waste time if it fails - name: Validate workflow @@ -191,12 +190,12 @@ jobs: - name: Install codemod dependencies if: steps.check-package-json.outputs.has-package-json == 'true' working-directory: ${{ steps.find-codemod.outputs.codemod-path }} - run: npm install --no-frozen-lockfile + run: npm ci - name: Run javascript ast-grep codemod Tests if: steps.check-package-json.outputs.has-package-json == 'true' working-directory: ${{ steps.find-codemod.outputs.codemod-path }} - run: npm test + run: node --run test - name: Publish codemod uses: codemod/publish-action@v1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d5b9c4a..f91277d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,6 +21,7 @@ Thanks for helping users adopt the latest features with your codemods! cd /path/to/sample/project npx codemod workflow run -w /path/to/my-codemod/workflow.yaml ``` + ### Project Layout - Place all codemods in the `codemods/` directory. diff --git a/_typecheck.ts b/_typecheck.ts deleted file mode 100644 index 329f573..0000000 --- a/_typecheck.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Root typecheck placeholder. No local utils folder — codemods should use - * @jssg/utils for shared utilities (import helpers, etc.). - * @see https://www.npmjs.com/package/@jssg/utils - */ -export {}; diff --git a/biome.jsonc b/biome.jsonc index 8d540dc..e73efab 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -1 +1,7 @@ -{"$schema":"https://biomejs.dev/schemas/2.4.4/schema.json","files":{"includes":["."]},"formatter":{"enabled":true,"lineWidth":100},"linter":{"enabled":true},"javascript":{"formatter":{"quoteStyle":"double"}}} +{ + "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", + "files": { "includes": ["**", "!**/package-lock.json", "!codemods/**/tests"] }, + "formatter": { "enabled": true, "lineWidth": 100 }, + "linter": { "enabled": true }, + "javascript": { "formatter": { "quoteStyle": "double" } } +} diff --git a/codemods/.gitkeep b/codemods/.gitkeep deleted file mode 100644 index 139597f..0000000 --- a/codemods/.gitkeep +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/codemods/sample-codemod/SKILL.md b/codemods/sample-codemod/SKILL.md index 1868fa3..4d931bb 100644 --- a/codemods/sample-codemod/SKILL.md +++ b/codemods/sample-codemod/SKILL.md @@ -7,6 +7,7 @@ author: "Codemod Authors" license: "MIT" workflow: "workflow.yaml" category: "migration" +repository: "https://github.com/codemod/migrations-template/tree/main/codemods/sample-codemod" targets: languages: ["typescript"] keywords: ["react", "upgrade", "standardization", "performance"] diff --git a/codemods/sample-codemod/codemod.yaml b/codemods/sample-codemod/codemod.yaml index 538ad54..cdb01e9 100644 --- a/codemods/sample-codemod/codemod.yaml +++ b/codemods/sample-codemod/codemod.yaml @@ -7,7 +7,7 @@ author: "Codemod Authors" license: "MIT" workflow: "workflow.yaml" category: "migration" - +repository: "https://github.com/codemod/migrations-template/tree/main/codemods/sample-codemod" targets: languages: ["typescript"] diff --git a/codemods/sample-codemod/package-lock.json b/codemods/sample-codemod/package-lock.json deleted file mode 100644 index a56aeb8..0000000 --- a/codemods/sample-codemod/package-lock.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "name": "react-hoist-nested-components", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "react-hoist-nested-components", - "version": "0.1.0", - "devDependencies": { - "@codemod.com/jssg-types": "latest", - "@jssg/utils": "latest", - "typescript": "latest" - } - }, - "node_modules/@codemod.com/jssg-types": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@codemod.com/jssg-types/-/jssg-types-1.5.0.tgz", - "integrity": "sha512-zChRbxI3hBSGrAHnWlEzOw1FztLWMMiarwcr0Wbk0On4hmv7dVgoUqpIHfxb64mEMKJ5syTIKY3ZNd8DcFQa5w==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/@jssg/utils": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@jssg/utils/-/utils-0.0.2.tgz", - "integrity": "sha512-eCQv5Xs9yfI6OKq2PQ8SyKsxPhdiaJY/XAFJmsZiVbsK5DIBBmGBA95CsyD4JFWXDKkNv6Q7ER/Kbp6/uWzB2w==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - } - } -} diff --git a/codemods/sample-codemod/package.json b/codemods/sample-codemod/package.json index cc1eaa2..f808e3a 100644 --- a/codemods/sample-codemod/package.json +++ b/codemods/sample-codemod/package.json @@ -1,15 +1,12 @@ { - "name": "sample-codemod", - "version": "0.1.0", - "description": "Move React components defined inside other components to module scope", - "type": "module", - "scripts": { - "test": "npx codemod@latest jssg test -l tsx ./scripts/codemod.ts", - "check-types": "tsc --noEmit" - }, - "devDependencies": { - "@codemod.com/jssg-types": "latest", - "@jssg/utils": "latest", - "typescript": "latest" - } + "name": "sample-codemod", + "version": "0.1.0", + "description": "Move React components defined inside other components to module scope", + "type": "module", + "scripts": { + "test": "npx codemod@latest jssg test -l tsx ./scripts/codemod.ts" + }, + "devDependencies": { + "@jssg/utils": "latest" + } } diff --git a/codemods/sample-codemod/scripts/codemod.ts b/codemods/sample-codemod/scripts/codemod.ts index c6ba7a8..06de57b 100644 --- a/codemods/sample-codemod/scripts/codemod.ts +++ b/codemods/sample-codemod/scripts/codemod.ts @@ -1,6 +1,7 @@ import type { Edit, SgNode, SgRoot } from "codemod:ast-grep"; import type TSX from "codemod:ast-grep/langs/tsx"; import { useMetricAtom } from "codemod:metrics"; +import path from "node:path"; // Cardinalities: // change-type: "hoisted" | "skipped-closure" @@ -8,32 +9,154 @@ import { useMetricAtom } from "codemod:metrics"; const hoistedMetric = useMetricAtom("react-hoist-nested-components"); +function getMetricFilePath(filename: string): string { + const relativePath = path.isAbsolute(filename) + ? path.relative(process.cwd(), filename) + : filename; + return relativePath.split(path.sep).join("/"); +} + /** Intrinsic HTML/SVG elements - not variable references */ const INTRINSIC_ELEMENTS = new Set([ - "a", "abbr", "address", "area", "article", "aside", "audio", "b", "base", - "bdi", "bdo", "blockquote", "body", "br", "button", "canvas", "caption", - "cite", "code", "col", "colgroup", "data", "datalist", "dd", "del", "details", - "dfn", "dialog", "div", "dl", "dt", "em", "embed", "fieldset", "figcaption", - "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "head", - "header", "hgroup", "hr", "html", "i", "iframe", "img", "input", "ins", "kbd", - "label", "legend", "li", "link", "main", "map", "mark", "menu", "meta", "meter", - "nav", "noscript", "object", "ol", "optgroup", "option", "output", "p", "param", - "picture", "pre", "progress", "q", "rp", "rt", "ruby", "s", "samp", "section", - "select", "slot", "small", "source", "span", "strong", "style", "sub", "summary", - "sup", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", - "time", "title", "tr", "track", "u", "ul", "var", "video", "wbr", - "svg", "path", "circle", "rect", "line", "ellipse", "polyline", "polygon", - "g", "defs", "use", "stop", "linearGradient", "radialGradient", + "a", + "abbr", + "address", + "area", + "article", + "aside", + "audio", + "b", + "base", + "bdi", + "bdo", + "blockquote", + "body", + "br", + "button", + "canvas", + "caption", + "cite", + "code", + "col", + "colgroup", + "data", + "datalist", + "dd", + "del", + "details", + "dfn", + "dialog", + "div", + "dl", + "dt", + "em", + "embed", + "fieldset", + "figcaption", + "figure", + "footer", + "form", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "head", + "header", + "hgroup", + "hr", + "html", + "i", + "iframe", + "img", + "input", + "ins", + "kbd", + "label", + "legend", + "li", + "link", + "main", + "map", + "mark", + "menu", + "meta", + "meter", + "nav", + "noscript", + "object", + "ol", + "optgroup", + "option", + "output", + "p", + "param", + "picture", + "pre", + "progress", + "q", + "rp", + "rt", + "ruby", + "s", + "samp", + "section", + "select", + "slot", + "small", + "source", + "span", + "strong", + "style", + "sub", + "summary", + "sup", + "table", + "tbody", + "td", + "template", + "textarea", + "tfoot", + "th", + "thead", + "time", + "title", + "tr", + "track", + "u", + "ul", + "var", + "video", + "wbr", + "svg", + "path", + "circle", + "rect", + "line", + "ellipse", + "polyline", + "polygon", + "g", + "defs", + "use", + "stop", + "linearGradient", + "radialGradient", ]); function isReactComponent(node: SgNode): boolean { if (node.is("function_declaration")) { - return node.has({ rule: { kind: "jsx_element" } }) || - node.has({ rule: { kind: "jsx_self_closing_element" } }); + return ( + node.has({ rule: { kind: "jsx_element" } }) || + node.has({ rule: { kind: "jsx_self_closing_element" } }) + ); } if (node.is("arrow_function") || node.is("function")) { - return node.has({ rule: { kind: "jsx_element" } }) || - node.has({ rule: { kind: "jsx_self_closing_element" } }); + return ( + node.has({ rule: { kind: "jsx_element" } }) || + node.has({ rule: { kind: "jsx_self_closing_element" } }) + ); } return false; } @@ -84,7 +207,11 @@ function getEnclosingStatement(innerComponent: SgNode): SgNode { let node: SgNode | null = innerComponent; while (node) { if (node.is("statement_block") || node.is("program")) break; - if (node.is("function_declaration") || node.is("lexical_declaration") || node.is("variable_declaration")) { + if ( + node.is("function_declaration") || + node.is("lexical_declaration") || + node.is("variable_declaration") + ) { return node; } node = node.parent(); @@ -107,10 +234,7 @@ function getOuterScopeBindings(outerComponent: SgNode): Set { if (body) { for (const decl of body.findAll({ rule: { - any: [ - { kind: "variable_declarator" }, - { kind: "function_declaration" }, - ], + any: [{ kind: "variable_declarator" }, { kind: "function_declaration" }], }, })) { if (decl.is("variable_declarator")) { @@ -207,6 +331,7 @@ async function transform(root: SgRoot): Promise { const rootNode = root.root(); const program = rootNode; const edits: Edit[] = []; + const metricFile = getMetricFilePath(root.filename()); // Find nested components: function decl or const/let = arrow/function inside another component const functionDecls = program.findAll({ @@ -246,7 +371,9 @@ async function transform(root: SgRoot): Promise { }); for (const { node: declOrStmt, outer } of candidates) { - const component = declOrStmt.is("function_declaration") ? declOrStmt : getComponentNode(declOrStmt); + const component = declOrStmt.is("function_declaration") + ? declOrStmt + : getComponentNode(declOrStmt); if (!component) continue; const name = getComponentName(declOrStmt); @@ -255,7 +382,7 @@ async function transform(root: SgRoot): Promise { const closureDependent = hasClosureDependency(component, outer, name); if (closureDependent) { - hoistedMetric.increment({ "change-type": "skipped-closure", "file": root.filename() }); + hoistedMetric.increment({ "change-type": "skipped-closure", file: metricFile }); // Add a flag comment above the nested component (preserve indentation) const stmt = getEnclosingStatement(component); const start = stmt.range().start.index; @@ -284,7 +411,9 @@ async function transform(root: SgRoot): Promise { // function_declaration needs no trailing semicolon; const/let already has one const textToInsert = stmt.is("function_declaration") ? `${componentText}\n\n` - : (componentText.endsWith(";") ? `${componentText}\n\n` : `${componentText};\n\n`); + : componentText.endsWith(";") + ? `${componentText}\n\n` + : `${componentText};\n\n`; edits.push({ startPos: outerStart, @@ -294,9 +423,7 @@ async function transform(root: SgRoot): Promise { // Remove statement and the newline after it (up to but not including next statement's indent) const stmtRange = stmt.range(); const nextStmt = stmt.next(); - const removalEnd = nextStmt - ? nextStmt.range().start.index - : stmtRange.end.index; + const removalEnd = nextStmt ? nextStmt.range().start.index : stmtRange.end.index; edits.push({ startPos: stmtRange.start.index, endPos: removalEnd, @@ -304,10 +431,11 @@ async function transform(root: SgRoot): Promise { }); const form = declOrStmt.is("function_declaration") ? "function-decl" : "arrow"; - hoistedMetric.increment({ "change-type": "hoisted", "component-form": form, "file": root.filename() }); + hoistedMetric.increment({ "change-type": "hoisted", "component-form": form, file: metricFile }); } if (edits.length === 0) return null; + return rootNode.commitEdits(edits); } diff --git a/codemods/sample-codemod/tsconfig.json b/codemods/sample-codemod/tsconfig.json deleted file mode 100644 index 469fc5a..0000000 --- a/codemods/sample-codemod/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "module": "NodeNext", - "moduleResolution": "NodeNext", - "types": ["@codemod.com/jssg-types"], - "allowImportingTsExtensions": true, - "noEmit": true, - "verbatimModuleSyntax": true, - "erasableSyntaxOnly": true, - "strict": true, - "strictNullChecks": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedIndexedAccess": true - }, - "exclude": ["tests"] -} diff --git a/docs/CODEMOD-TEMPLATE.md b/docs/CODEMOD-TEMPLATE.md index 86e3c11..34e6633 100644 --- a/docs/CODEMOD-TEMPLATE.md +++ b/docs/CODEMOD-TEMPLATE.md @@ -44,6 +44,7 @@ author: "Your Name " license: "MIT" workflow: "workflow.yaml" category: "migration" +repository: "" targets: languages: ["typescript"] diff --git a/package-lock.json b/package-lock.json index af09459..bbecb30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,11 +7,192 @@ "": { "name": "-codemods", "version": "0.1.0", + "workspaces": [ + "codemods/*" + ], "devDependencies": { - "@jssg/utils": "^0.0.2", - "typescript": "^5.9.3" + "@biomejs/biome": "^2.4.15", + "@codemod.com/jssg-types": "^1.6.0", + "@types/node": "^25.8.0", + "typescript": "^6.0.3" } }, + "codemods/sample-codemod": { + "version": "0.1.0", + "devDependencies": { + "@jssg/utils": "latest" + } + }, + "node_modules/@biomejs/biome": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.15.tgz", + "integrity": "sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw==", + "dev": true, + "license": "MIT OR Apache-2.0", + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "2.4.15", + "@biomejs/cli-darwin-x64": "2.4.15", + "@biomejs/cli-linux-arm64": "2.4.15", + "@biomejs/cli-linux-arm64-musl": "2.4.15", + "@biomejs/cli-linux-x64": "2.4.15", + "@biomejs/cli-linux-x64-musl": "2.4.15", + "@biomejs/cli-win32-arm64": "2.4.15", + "@biomejs/cli-win32-x64": "2.4.15" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.15.tgz", + "integrity": "sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.15.tgz", + "integrity": "sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.15.tgz", + "integrity": "sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.15.tgz", + "integrity": "sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.15.tgz", + "integrity": "sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.15.tgz", + "integrity": "sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.15.tgz", + "integrity": "sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.15.tgz", + "integrity": "sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@codemod.com/jssg-types": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@codemod.com/jssg-types/-/jssg-types-1.6.0.tgz", + "integrity": "sha512-9b6rsL3RZJvOPJ+gUj1W0041mHF6eYwLt+wsa4zqxJWNsxLha0JvFyaQdcw5XfQ5Ldd+H/kV/yZ4dpN+hC9OXw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/@jssg/utils": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/@jssg/utils/-/utils-0.0.2.tgz", @@ -19,10 +200,24 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/@types/node": { + "version": "25.8.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.8.0.tgz", + "integrity": "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/sample-codemod": { + "resolved": "codemods/sample-codemod", + "link": true + }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -32,6 +227,13 @@ "engines": { "node": ">=14.17" } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "dev": true, + "license": "MIT" } } } diff --git a/package.json b/package.json index 55f1cac..fdf9409 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,23 @@ { - "name": "-codemods", - "private": true, - "version": "0.1.0", - "description": "Codemods for ", - "type": "module", - "scripts": { - "check": "npm run lint && npm run format", - "lint": "npx -y @biomejs/biome lint .", - "format": "npx -y @biomejs/biome format --write .", - "typecheck": "tsc --noEmit" - }, - "devDependencies": { - "@jssg/utils": "^0.0.2", - "typescript": "^5.9.3" - } + "name": "-codemods", + "private": true, + "version": "0.1.0", + "description": "Codemods for ", + "type": "module", + "scripts": { + "check": "biome check .", + "lint": "biome lint .", + "format": "biome format --write .", + "typecheck": "tsc --noEmit && echo 'TypeScript type check passed!'", + "test": "npm run test --workspaces --if-present" + }, + "workspaces": [ + "codemods/*" + ], + "devDependencies": { + "@biomejs/biome": "^2.4.15", + "@codemod.com/jssg-types": "^1.6.0", + "@types/node": "^25.8.0", + "typescript": "^6.0.3" + } } - diff --git a/tsconfig.json b/tsconfig.json index 416ebbe..cc7d6ff 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,19 +1,6 @@ { - "include": [ - "_typecheck.ts" - ], - "exclude": [ - "**/tests/**/*", - "**/rules/**/*.yml", - "**/scripts/**/*.ts", - "**/node_modules/**/*", - "**/*.test.ts", - "**/*.test.js", - "**/*.spec.ts", - "**/*.spec.js", - "**/dist/**/*", - "**/build/**/*" - ], + "include": ["codemods/**/*.ts", "codemods/**/*.tsx", "codemods/**/*.js", "codemods/**/*.jsx"], + "exclude": ["**/tests/**/*"], "compilerOptions": { "target": "ES2020", "module": "ESNext", @@ -24,7 +11,6 @@ "resolveJsonModule": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "types": [] + "types": ["@codemod.com/jssg-types", "node"] } } -