-
Notifications
You must be signed in to change notification settings - Fork 30
Description
This proposal is based on the discussion in #90.
There are 2 problems right now:
- There is no way to know, if the codemod replaced package imports or similar.
- Sourcemaps also cant be generated
Atm, every codemod is defined as
interface Codemod {
name: string;
transform: (options: { file: File }) => string | Promise<string>
}
So, you could probably just add a new field replacements
that holds a list with the packages the codemod uses.
interface Codemod {
name: string;
replacements: ['picoquery']
transform: (options: { file: File }) => string | Promise<string>
}
However, this is static and has the obious flaw, that the consumer of the codemod always assumes that the packages in replacements
are now in use and should be installed.
It doesnt matter if the codemod didnt do any replacements in the end (because maybe it didnt find an import to replace).
Therefore, it is more useful to return a list of replaced packages from the transform function.
This has the added benefit of solving the second problem: sourcemaps.
Solution
I propose the following interface:
interface CodemodReturn {
code: string;
map?: SourceMapV3 | null;
meta?: {
replacements?: Record<string, string>;
warnings?: MaybeLineNumbersAndMessage;
[key: string]: any;
}
}
interface Codemod {
name: string;
transform: (options: { file: File }) => string | CodemodReturn | Promise<string | CodemodReturn>
}
code
contains the modded codemap
contains a sourcemap (of which type is to be discussed)meta
can contain any data the codemod wants to return. This should be documented by the codemod. However, some special keys should be reserved:replacements
is a list of packages that were replaced by the codemod. This is an object with the form{ [oldPackage]: newPackage }
. This way, we can track what was replaced by what in case the codemap replaces multiple things. Maybe you want to run another codemod if the first couldnt replace some packages.warnings
is an array of warnings. At best, we should have aCodeframe
here so we can exactly tell what is a problem where. At least, we should have line numbers and file names.
We might also want to consider adding errors
for the case, that the codemod encountered a critical error.
Imho, codemods shouldnt throw and break the pipeline. Instead, they should return the untransformed code with an error message.
An alternative idea would be to use logs
that can hold logs of different severity levels. That way we could have all logs, warnings and errors in one property
Compatibility
The former interface must still be supported. So for newer consumers of all codemods, we should declare the rule, that a codemod that returns a string, is to be treated as { code: string }
.
Requirements for Codemos
- If all your codemod is doing, is changing some syntax, and you dont want to support sourcemaps, you probably can use the old api.
This is, to be able to accept new codemods easier which can be refined later. Its always good to have something. - Codemods that replace imports must be required to list them in
replacements
. If no replacement happened, it shouldnt be inreplacements
- Codemods thar replace imports must support import AND require. PRs that only include one of them should be guided to also implement the other