|
| 1 | +/** |
| 2 | + * This is a transformer which `ts-jest` applies during the compilation process, which switches all of the `const`s out |
| 3 | + * for `var`s. Unlike in our package builds, where we do the same substiution for bundle size reasons, here we do it |
| 4 | + * because otherwise `const global = getGlobalObject()` throws an error about redifining `global`. (This didn't used to |
| 5 | + * be a problem because our down-compilation did the `const`-`var` substitution for us, but now that we're ES6-only, we |
| 6 | + * have to do it ourselves.) |
| 7 | + * |
| 8 | + * Note: If you ever have to change this, and are testing it locally in the process, be sure to call |
| 9 | + * `yarn jest --clearCache` |
| 10 | + * before each test run, as transformation results are cached between runs. |
| 11 | + */ |
| 12 | + |
| 13 | +import { |
| 14 | + createVariableDeclarationList, |
| 15 | + getCombinedNodeFlags, |
| 16 | + isVariableDeclarationList, |
| 17 | + Node, |
| 18 | + NodeFlags, |
| 19 | + SourceFile, |
| 20 | + TransformationContext, |
| 21 | + Transformer, |
| 22 | + TransformerFactory, |
| 23 | + visitEachChild, |
| 24 | + visitNode, |
| 25 | + VisitResult, |
| 26 | +} from 'typescript'; |
| 27 | + |
| 28 | +// These can be anything - they're just used to construct a cache key for the transformer returned by the factory below. |
| 29 | +// This really only matters when you're testing the transformer itself, as changing these values gives you a quick way |
| 30 | +// to invalidate the cache and ensure that changes you've made to the code here are immediately picked up on and used. |
| 31 | +export const name = 'const-to-var'; |
| 32 | +export const version = '1.0'; |
| 33 | + |
| 34 | +/** |
| 35 | + * Check whether the given AST node represents a `const` token. |
| 36 | + * |
| 37 | + * This function comes from the TS compiler, and is copied here to get around the fact that it's not exported by the |
| 38 | + * `typescript` package. |
| 39 | + * |
| 40 | + * @param node The node to check |
| 41 | + * @returns A boolean indicating if the node is a `const` token. |
| 42 | + */ |
| 43 | +function isVarConst(node: Node): boolean { |
| 44 | + // eslint-disable-next-line no-bitwise |
| 45 | + return !!(getCombinedNodeFlags(node) & NodeFlags.Const); |
| 46 | +} |
| 47 | + |
| 48 | +/** |
| 49 | + * Return a set of nested factory functions, which ultimately creates an AST-node visitor function, which can modify |
| 50 | + * each visited node as it sees fit, and uses it to walk the AST, returning the results. |
| 51 | + * |
| 52 | + * In our case, we're modifying all `const` variable declarations to use `var` instead. |
| 53 | + */ |
| 54 | +export function factory(): TransformerFactory<SourceFile> { |
| 55 | + // Create the transformer |
| 56 | + function transformerFactory(context: TransformationContext): Transformer<SourceFile> { |
| 57 | + // Create a visitor function and use it to walk the AST |
| 58 | + function transformer(sourceFile: SourceFile): SourceFile { |
| 59 | + // This visitor function can either return a node, in which case the subtree rooted at the returned node is |
| 60 | + // substituted for the subtree rooted at the visited node, or can use the recursive `visitEachChild` function |
| 61 | + // provided by TS to continue traversing the tree. |
| 62 | + function visitor(node: Node): VisitResult<Node> { |
| 63 | + // If we've found a `const` declaration, return a `var` declaration in its place |
| 64 | + if (isVariableDeclarationList(node) && isVarConst(node)) { |
| 65 | + // A declaration list with a `None` flag defaults to using `var` |
| 66 | + return createVariableDeclarationList(node.declarations, NodeFlags.None); |
| 67 | + } |
| 68 | + |
| 69 | + // This wasn't a node we're interested in, so keep walking down the tree. |
| 70 | + return visitEachChild(node, visitor, context); |
| 71 | + } |
| 72 | + |
| 73 | + // Having defined our visitor, pass it to the TS-provided `visitNode` function, which will use it to walk the AST, |
| 74 | + // and return the results of that walk. |
| 75 | + return visitNode(sourceFile, visitor); |
| 76 | + } |
| 77 | + |
| 78 | + // Back in the transformer factory, return the transformer we just created |
| 79 | + return transformer; |
| 80 | + } |
| 81 | + |
| 82 | + // Finally, we're back in `factory`, and can return the whole nested system |
| 83 | + return transformerFactory; |
| 84 | +} |
0 commit comments