diff --git a/packages/ast/src/types/transform.ts b/packages/ast/src/types/transform.ts index f4c30171..bec98321 100644 --- a/packages/ast/src/types/transform.ts +++ b/packages/ast/src/types/transform.ts @@ -47,8 +47,8 @@ export interface FsContext extends TransformContext { } export interface AstCliContext extends FsContext { - warn(node: NodePath | null, message: string): void; - fail(node: NodePath | null, message: string): void; + warn(node: NodePath | Error | null, message: string): void; + fail(node: NodePath | Error | null, message: string): void; } export type AstTransformResult = { diff --git a/packages/cli/src/codemods/plugins/jscodeshift/jscodeshift.adapter.ts b/packages/cli/src/codemods/plugins/jscodeshift/jscodeshift.adapter.ts index a7991bd0..9230fb74 100644 --- a/packages/cli/src/codemods/plugins/jscodeshift/jscodeshift.adapter.ts +++ b/packages/cli/src/codemods/plugins/jscodeshift/jscodeshift.adapter.ts @@ -1,7 +1,12 @@ import j, { Collection } from 'jscodeshift'; -import { AstCliContext, AstTransform, NodePath } from '@ag-grid-devtools/ast'; +import { AstCliContext, AstTransform, NodePath, Node } from '@ag-grid-devtools/ast'; -export type JSCodeShiftTransformer = (root: Collection) => void | any; +export type ErrorSpec = { path: j.ASTPath; message: string }; + +export type JSCodeShiftTransformer = (root: Collection) => void | { + errors: ErrorSpec[]; + warnings: ErrorSpec[]; +}; // Use https://astexplorer.net/ to iterate on your transformer // Parser: Typescript @@ -15,11 +20,16 @@ export type JSCodeShiftTransformer = (root: Collection) => void | any; export const jsCodeShiftTransform = ( ...transforms: JSCodeShiftTransformer[] ): AstTransform => { + const errors: Error[] = []; + const warnings: Error[] = []; + let source: any; + return (_babel) => ({ visitor: { Program: { exit(path: NodePath) { - const root: Collection = j((path.hub as any).file.ast); + source = (path.hub as any).file.ast; + const root: Collection = j(source); const getFirstNode = () => root.find(j.Program).get('body', 0).node; // save initial comment if any @@ -28,7 +38,21 @@ export const jsCodeShiftTransform = ( // transform for (const transform of transforms) { - transform(root); + const result = transform(root); + if (result?.errors) { + errors.push( + ...result.errors.map((error) => + path.hub.buildError(error.path.node as Node, error.message), + ), + ); + } + if (result?.warnings) { + warnings.push( + ...result.warnings.map((warning) => + path.hub.buildError(warning.path.node as Node, warning.message), + ), + ); + } } // restore initial comment if any @@ -43,5 +67,14 @@ export const jsCodeShiftTransform = ( }, }, }, + post(_file) { + for (const warning of warnings) { + this.opts.warn(warning, warning.message); + } + + for (const error of errors) { + this.opts.fail(error, error.message); + } + }, }); }; diff --git a/packages/cli/src/codemods/transforms/transform-modules-to-packages-v33/transformers/package-transforms.ts b/packages/cli/src/codemods/transforms/transform-modules-to-packages-v33/transformers/package-transforms.ts index 76351e5e..caf0c1d9 100644 --- a/packages/cli/src/codemods/transforms/transform-modules-to-packages-v33/transformers/package-transforms.ts +++ b/packages/cli/src/codemods/transforms/transform-modules-to-packages-v33/transformers/package-transforms.ts @@ -47,7 +47,7 @@ export const packageLicenseManager: JSCodeShiftTransformer = (root) => { if (alreadyExists) { // This package file already has a ModuleRegistry import so looks like it has already been transformed - return root.toSource(); + return; } const usingCharts: UsingCharts = process.env.AG_USING_CHARTS as any; diff --git a/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-chart-type-subobject.ts b/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-chart-type-subobject.ts index 7e620383..f37e52e4 100644 --- a/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-chart-type-subobject.ts +++ b/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-chart-type-subobject.ts @@ -4,7 +4,7 @@ import { JSCodeShiftTransformer } from '../../../plugins/jscodeshift'; const chartTypeKeys = ['area', 'bar', 'column', 'line']; // find [chart-type] keys, and merge their contents into the parent object -export const chartTypeSubobject: JSCodeShiftTransformer = (root) => +export const chartTypeSubobject: JSCodeShiftTransformer = (root) => { root .find(j.ObjectProperty, { key: { name: 'cellRendererParams' } }) .find(j.ObjectProperty, { key: { name: 'sparklineOptions' } }) @@ -17,3 +17,4 @@ export const chartTypeSubobject: JSCodeShiftTransformer = (root) => }); path.replace(); }); +}; diff --git a/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-column.ts b/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-column.ts index b2caa43c..3eeae66b 100644 --- a/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-column.ts +++ b/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-column.ts @@ -2,7 +2,7 @@ import j from 'jscodeshift'; import { JSCodeShiftTransformer } from '../../../plugins/jscodeshift'; // update bar/column types to bar with matching direction -export const columnToVerticalBarTransform: JSCodeShiftTransformer = (root) => +export const columnToVerticalBarTransform: JSCodeShiftTransformer = (root) => { root .find(j.ObjectProperty, { key: { name: 'cellRendererParams' } }) .find(j.ObjectProperty, { key: { name: 'sparklineOptions' } }) @@ -14,3 +14,4 @@ export const columnToVerticalBarTransform: JSCodeShiftTransformer = (root) => path.replace(j.objectProperty(j.identifier('type'), j.stringLiteral('bar'))); path.insertAfter(j.objectProperty(j.identifier('direction'), j.stringLiteral(direction))); }); +}; diff --git a/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-crosshairs.ts b/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-crosshairs.ts index 2fb96b54..7f6f0fc6 100644 --- a/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-crosshairs.ts +++ b/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-crosshairs.ts @@ -1,9 +1,10 @@ import j from 'jscodeshift'; import { JSCodeShiftTransformer } from '../../../plugins/jscodeshift'; -export const removeCrosshairs: JSCodeShiftTransformer = (root) => +export const removeCrosshairs: JSCodeShiftTransformer = (root) => { root .find(j.ObjectProperty, { key: { name: 'cellRendererParams' } }) .find(j.ObjectProperty, { key: { name: 'sparklineOptions' } }) .find(j.ObjectProperty, { key: { name: 'crosshairs' } }) .forEach((path) => path.replace()); +}; diff --git a/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-types.ts b/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-types.ts index 72a0642e..4e9fc27f 100644 --- a/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-types.ts +++ b/packages/cli/src/codemods/transforms/transform-sparklines-options-v33-0/transformers/sparkline-types.ts @@ -2,8 +2,9 @@ import j from 'jscodeshift'; import { JSCodeShiftTransformer } from '../../../plugins/jscodeshift'; import { newType, oldTypes } from './constants'; -export const replaceTypes: JSCodeShiftTransformer = (root) => +export const replaceTypes: JSCodeShiftTransformer = (root) => { root .find(j.TSTypeReference) .filter((path) => oldTypes.includes((path.value.typeName as any).name)) .forEach((path) => path.replace(j.tsTypeReference(j.identifier(newType)))); +}; diff --git a/packages/codemod-utils/src/transform/js.ts b/packages/codemod-utils/src/transform/js.ts index 9eb33e63..1459868c 100644 --- a/packages/codemod-utils/src/transform/js.ts +++ b/packages/codemod-utils/src/transform/js.ts @@ -65,11 +65,11 @@ function transformJsFile( const transformContext: AstTransformContext = { filename, opts: { - warn(node: NodePath | null, message: string) { + warn(node, message) { const error = createSourceCodeError(node, message); uniqueErrors.set(error.message, { error, fatal: false }); }, - fail(node: NodePath | null, message: string) { + fail(node, message) { const error = createSourceCodeError(node, message); uniqueErrors.set(error.message, { error, fatal: true }); }, @@ -99,6 +99,14 @@ function transformJsFile( }; } -function createSourceCodeError(node: NodePath | null, message: string): Error { - return node ? node.buildCodeFrameError(message) : new SyntaxError(message); +function createSourceCodeError(node: NodePath | Error | null, message: string): Error { + if (!node) { + return new SyntaxError(message); + } + + if ('hub' in node) { + return node.buildCodeFrameError(message); + } + + return node; } diff --git a/packages/codemods-tasks/templates/plugin-jscodeshift/<%= filename %>.test.ts b/packages/codemods-tasks/templates/plugin-jscodeshift/<%= filename %>.test.ts new file mode 100644 index 00000000..84038b5a --- /dev/null +++ b/packages/codemods-tasks/templates/plugin-jscodeshift/<%= filename %>.test.ts @@ -0,0 +1,16 @@ +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { describe, expect, onTestFinished, test } from 'vitest'; +import { loadTransformScenarios } from '../../test/runners/transform'; + +import <%= identifier %> from '.'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +describe(<%= identifier %>, () => { + const scenariosPath = join(__dirname, './__fixtures__/scenarios'); + loadTransformScenarios(scenariosPath, { + transforms: [<%= identifier %>], + vitest: { describe, expect, test, onTestFinished }, + }); +}); diff --git a/packages/codemods-tasks/templates/plugin-jscodeshift/README.md b/packages/codemods-tasks/templates/plugin-jscodeshift/README.md new file mode 100644 index 00000000..840bfa78 --- /dev/null +++ b/packages/codemods-tasks/templates/plugin-jscodeshift/README.md @@ -0,0 +1,3 @@ +# jscodeshift Plugin + +The `jscodeshift` plugin is a tool used for running codemods over JavaScript and TypeScript codebases. It leverages the `jscodeshift` library, which provides a simple API for transforming code using the power of abstract syntax trees (ASTs). diff --git a/packages/codemods-tasks/templates/plugin-jscodeshift/__fixtures__/scenarios/hello-world/input.js b/packages/codemods-tasks/templates/plugin-jscodeshift/__fixtures__/scenarios/hello-world/input.js new file mode 100644 index 00000000..ddf7f593 --- /dev/null +++ b/packages/codemods-tasks/templates/plugin-jscodeshift/__fixtures__/scenarios/hello-world/input.js @@ -0,0 +1,9 @@ +import { createGrid } from '@ag-grid-community/core'; + +const gridApi = createGrid(document.body, { + columnDefs: [], + rowData: [], +}); + +gridApi.helloWorld(); +gridApi?.goodbyeWorld(); diff --git a/packages/codemods-tasks/templates/plugin-jscodeshift/__fixtures__/scenarios/hello-world/output.errors.cjs b/packages/codemods-tasks/templates/plugin-jscodeshift/__fixtures__/scenarios/hello-world/output.errors.cjs new file mode 100644 index 00000000..b9595cdc --- /dev/null +++ b/packages/codemods-tasks/templates/plugin-jscodeshift/__fixtures__/scenarios/hello-world/output.errors.cjs @@ -0,0 +1,6 @@ +module.exports = [ + new SyntaxError(`This method has been deprecated + +> | gridApi.goodbyeWorld(); + | ^^^^^^^^^^^^^^^^^^^^^^`), +]; diff --git a/packages/codemods-tasks/templates/plugin-jscodeshift/__fixtures__/scenarios/hello-world/output.js b/packages/codemods-tasks/templates/plugin-jscodeshift/__fixtures__/scenarios/hello-world/output.js new file mode 100644 index 00000000..fcc27e36 --- /dev/null +++ b/packages/codemods-tasks/templates/plugin-jscodeshift/__fixtures__/scenarios/hello-world/output.js @@ -0,0 +1,9 @@ +import { createGrid } from '@ag-grid-community/core'; + +const gridApi = createGrid(document.body, { + columnDefs: [], + rowData: [], +}); + +gridApi.sayHello("world"); +gridApi?.goodbyeWorld(); diff --git a/packages/codemods-tasks/templates/plugin-jscodeshift/__fixtures__/scenarios/hello-world/output.warnings.cjs b/packages/codemods-tasks/templates/plugin-jscodeshift/__fixtures__/scenarios/hello-world/output.warnings.cjs new file mode 100644 index 00000000..e0a30c5d --- /dev/null +++ b/packages/codemods-tasks/templates/plugin-jscodeshift/__fixtures__/scenarios/hello-world/output.warnings.cjs @@ -0,0 +1 @@ +module.exports = []; diff --git a/packages/codemods-tasks/templates/plugin-jscodeshift/__fixtures__/scenarios/hello-world/scenario.json b/packages/codemods-tasks/templates/plugin-jscodeshift/__fixtures__/scenarios/hello-world/scenario.json new file mode 100644 index 00000000..346c1107 --- /dev/null +++ b/packages/codemods-tasks/templates/plugin-jscodeshift/__fixtures__/scenarios/hello-world/scenario.json @@ -0,0 +1,8 @@ +{ + "scenario": { + "input": "input.js", + "output": "output.js", + "errors": "output.errors.cjs", + "warnings": "output.warnings.cjs" + } +} diff --git a/packages/codemods-tasks/templates/plugin-jscodeshift/index.ts b/packages/codemods-tasks/templates/plugin-jscodeshift/index.ts new file mode 100644 index 00000000..f596ad1e --- /dev/null +++ b/packages/codemods-tasks/templates/plugin-jscodeshift/index.ts @@ -0,0 +1 @@ +export * from './transforms'; diff --git a/packages/codemods-tasks/templates/plugin-jscodeshift/manifest.ts b/packages/codemods-tasks/templates/plugin-jscodeshift/manifest.ts new file mode 100644 index 00000000..24b766eb --- /dev/null +++ b/packages/codemods-tasks/templates/plugin-jscodeshift/manifest.ts @@ -0,0 +1,8 @@ +import { type TransformManifest } from '@ag-grid-devtools/types'; + +const manifest: TransformManifest = { + name: '<%= name %>', + description: '<%= description %>', +}; + +export default manifest; diff --git a/packages/codemods-tasks/templates/plugin-jscodeshift/plugin.json b/packages/codemods-tasks/templates/plugin-jscodeshift/plugin.json new file mode 100644 index 00000000..63a25fc3 --- /dev/null +++ b/packages/codemods-tasks/templates/plugin-jscodeshift/plugin.json @@ -0,0 +1,4 @@ +{ + "name": "JSCodeshift", + "description": "Transform using JSCodeshift" +} diff --git a/packages/codemods-tasks/templates/plugin-jscodeshift/transforms/index.ts b/packages/codemods-tasks/templates/plugin-jscodeshift/transforms/index.ts new file mode 100644 index 00000000..944724f7 --- /dev/null +++ b/packages/codemods-tasks/templates/plugin-jscodeshift/transforms/index.ts @@ -0,0 +1,6 @@ +import { JSCodeShiftTransformer } from '../../../plugins/jscodeshift'; + +// Transforms go here +export const myTransform: JSCodeShiftTransformer = (root) => { + // ... +};