From d4073431a1b5275657c73f4ce89421e122a2ccdb Mon Sep 17 00:00:00 2001 From: Xiaoji Chen Date: Mon, 29 Jan 2024 15:04:11 -0800 Subject: [PATCH] Address comments --- modules/dev-tools/package.json | 7 +- .../src/configuration/get-esbuild-config.js | 1 + modules/dev-tools/src/helpers/get-config.js | 6 ++ modules/dev-tools/ts-plugins/.gitignore | 1 + .../ts-transform-append-extension/index.ts | 91 +++++++++++++++++++ .../ts-transform-version-inline/index.ts | 73 +++++++++++++++ .../ts-transform-append-extension/index.cjs | 51 ----------- .../ts-transform-version-inline/index.cjs | 48 ---------- modules/dev-tools/tsconfig.json | 8 +- 9 files changed, 180 insertions(+), 106 deletions(-) create mode 100644 modules/dev-tools/ts-plugins/.gitignore create mode 100644 modules/dev-tools/ts-plugins/ts-transform-append-extension/index.ts create mode 100644 modules/dev-tools/ts-plugins/ts-transform-version-inline/index.ts delete mode 100644 modules/dev-tools/ts-transform-append-extension/index.cjs delete mode 100644 modules/dev-tools/ts-transform-version-inline/index.cjs diff --git a/modules/dev-tools/package.json b/modules/dev-tools/package.json index 5eefb0a1..0424f10e 100644 --- a/modules/dev-tools/package.json +++ b/modules/dev-tools/package.json @@ -15,13 +15,14 @@ "src", "scripts", "templates", + "ts-plugins", "CHANGELOG.md" ], "exports": { ".": "./src/index.js", "./configuration": "./src/configuration/index.cjs", - "./ts-transform-version-inline": "./ts-transform-version-inline/index.cjs", - "./ts-transform-append-extension": "./ts-transform-append-extension/index.cjs" + "./ts-transform-version-inline": "./ts-plugins/ts-transform-version-inline/index.cjs", + "./ts-transform-append-extension": "./ts-plugins/ts-transform-append-extension/index.cjs" }, "types": "./src/index.d.ts", "main": "./src/index.js", @@ -41,7 +42,7 @@ "bootstrap": "yarn install-fast && ocular-bootstrap", "install-fast": "PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true yarn", "clean": "echo No build needed", - "build": "echo No build needed", + "build": "tsc && find ./ts-plugins -depth -name \"*.js\" -exec sh -c 'f=\"{}\"; mv -- \"$f\" \"${f%.js}.cjs\"' \\;", "lint": "npm run lint-yarn", "lint-yarn": "!(grep -q unpm.u yarn.lock) || (echo 'Please rebuild yarn file using public npmrc' && false)", "publish-prod": "npm run build && npm run test && npm run test dist && npm publish", diff --git a/modules/dev-tools/src/configuration/get-esbuild-config.js b/modules/dev-tools/src/configuration/get-esbuild-config.js index 4e769cee..25b11d64 100644 --- a/modules/dev-tools/src/configuration/get-esbuild-config.js +++ b/modules/dev-tools/src/configuration/get-esbuild-config.js @@ -77,6 +77,7 @@ export async function getCJSExportConfig(opts) { outfile: opts.output, bundle: true, format: 'cjs', + // Node 16 is out of support, kept for compatibility. Move to 18? target: 'node16', packages: 'external', sourcemap: true, diff --git a/modules/dev-tools/src/helpers/get-config.js b/modules/dev-tools/src/helpers/get-config.js index 5524a4b8..576ee81b 100644 --- a/modules/dev-tools/src/helpers/get-config.js +++ b/modules/dev-tools/src/helpers/get-config.js @@ -1,3 +1,9 @@ +/** + * Used by command line scripts to print a field from the local ocular config. + Path is period separated. + Example: + $ node get-config.js ".babel.configPath" + */ import {getOcularConfig} from '../helpers/get-ocular-config.js'; let ocularConfig; diff --git a/modules/dev-tools/ts-plugins/.gitignore b/modules/dev-tools/ts-plugins/.gitignore new file mode 100644 index 00000000..cf16a28b --- /dev/null +++ b/modules/dev-tools/ts-plugins/.gitignore @@ -0,0 +1 @@ +*.cjs \ No newline at end of file diff --git a/modules/dev-tools/ts-plugins/ts-transform-append-extension/index.ts b/modules/dev-tools/ts-plugins/ts-transform-append-extension/index.ts new file mode 100644 index 00000000..21c93a8b --- /dev/null +++ b/modules/dev-tools/ts-plugins/ts-transform-append-extension/index.ts @@ -0,0 +1,91 @@ +/** + * TypeScript transform to append file extension to import statements in the compiled JS files + * Usage with ts-patch: + { + "plugins": [ + { + "transform": "ocular-dev-tools/ts-transform-append-extension", + "extensions": [".js"], + "after": true + } + ] + } + * Adapted from https://github.com/murolem/ts-transformer-append-js-extension to support custom extensions + */ +import * as path from 'path'; +import type {Program, TransformationContext, SourceFile, Node} from 'typescript'; +import type {TransformerExtras, PluginConfig} from 'ts-patch'; + +type AppendExtensionPluginConfig = PluginConfig & { + /** List of file extensions, for example: + * '.js': applies to paths without an extension, e.g. `import {add} from './math'` => `import {add} from './math.js'` + * '.lib.cjs': applies to paths ending with .lib, e.g. `import fft from './fft.lib` => `import fft from './fft.lib.cjs'` + * @default [".js"] + */ + extensions?: string[]; +}; + +export default function ( + program: Program, + pluginConfig: AppendExtensionPluginConfig, + {ts}: TransformerExtras +) { + // only append .js when module specifier has no extension or user-provided extensions + const {extensions = ['.js']} = pluginConfig; + const extMappings = new Map(); + for (const ext of extensions) { + const addition = path.extname(ext) || ext; + const base = path.basename(ext, addition); + extMappings.set(base, addition); + } + + function shouldMutateModuleSpecifier(node: Node): string | false { + if (!ts.isImportDeclaration(node) && !ts.isExportDeclaration(node)) return false; + if (node.moduleSpecifier === undefined) return false; + // only when module specifier is valid + if (!ts.isStringLiteral(node.moduleSpecifier)) return false; + // only when path is relative + if (!node.moduleSpecifier.text.startsWith('./') && !node.moduleSpecifier.text.startsWith('../')) + return false; + // only when module specifier has accepted extension + const ext = path.extname(node.moduleSpecifier.text); + if (!extMappings.has(ext)) return false; + return node.moduleSpecifier.text + extMappings.get(ext); + } + + return (ctx: TransformationContext) => { + const {factory} = ctx; + + return (sourceFile: SourceFile) => { + function visit(node: Node): Node { + const newImportSource = shouldMutateModuleSpecifier(node); + if (newImportSource) { + if (ts.isImportDeclaration(node)) { + const newModuleSpecifier = factory.createStringLiteral(newImportSource); + node = factory.updateImportDeclaration( + node, + node.modifiers, + node.importClause, + newModuleSpecifier, + node.assertClause + ); + } else if (ts.isExportDeclaration(node)) { + const newModuleSpecifier = factory.createStringLiteral(newImportSource); + node = factory.updateExportDeclaration( + node, + node.modifiers, + node.isTypeOnly, + node.exportClause, + newModuleSpecifier, + node.assertClause + ); + } + } + + return ts.visitEachChild(node, visit, ctx); + } + + return ts.visitNode(sourceFile, visit); + }; + }; +} diff --git a/modules/dev-tools/ts-plugins/ts-transform-version-inline/index.ts b/modules/dev-tools/ts-plugins/ts-transform-version-inline/index.ts new file mode 100644 index 00000000..76afa0a0 --- /dev/null +++ b/modules/dev-tools/ts-plugins/ts-transform-version-inline/index.ts @@ -0,0 +1,73 @@ +/** + * TypeScript transform to inject the current version of the package as string. + * Usage with ts-patch: + { + "plugins": [ + { + "transform": "ocular-dev-tools/ts-transform-version-inline", + "identifier": "PACKAGE_VERSION" + } + ] + } + */ +import * as fs from 'fs'; +import * as path from 'path'; +import type {Program, TransformationContext, SourceFile, Node} from 'typescript'; +import type {TransformerExtras, PluginConfig} from 'ts-patch'; + +type VersionInlinePluginConfig = PluginConfig & { + /** Identifier name to replace in code. + * @default "__VERSION__" + */ + identifier?: string; +}; + +export default function ( + program: Program, + pluginConfig: VersionInlinePluginConfig, + {ts}: TransformerExtras +) { + const {identifier = '__VERSION__'} = pluginConfig; + + return (ctx: TransformationContext) => { + const {factory} = ctx; + + return (sourceFile: SourceFile) => { + let packageVersion: string | null; + + function visit(node: Node): Node { + if (ts.isIdentifier(node) && node.getText() === identifier) { + if (packageVersion === undefined) { + packageVersion = getPackageVersion(sourceFile.fileName); + } + if (packageVersion) { + return factory.createStringLiteral(packageVersion); + } + } + return ts.visitEachChild(node, visit, ctx); + } + return ts.visitNode(sourceFile, visit); + }; + }; +} + +/** + * Retrieve the version string from the closest package.json + */ +function getPackageVersion(fileName: string): string | null { + let currentDir = fileName; + while (currentDir !== '/') { + try { + currentDir = path.dirname(currentDir); + const packageJson = path.join(currentDir, 'package.json'); + const stat = fs.statSync(packageJson); + if (stat.isFile()) { + const content = fs.readFileSync(packageJson, 'utf8'); + return JSON.parse(content).version as string; + } + } catch { + // file does not exist, try going up + } + } + return null; +} diff --git a/modules/dev-tools/ts-transform-append-extension/index.cjs b/modules/dev-tools/ts-transform-append-extension/index.cjs deleted file mode 100644 index 46aca01b..00000000 --- a/modules/dev-tools/ts-transform-append-extension/index.cjs +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Adapted from https://github.com/murolem/ts-transformer-append-js-extension - */ -const path = require('path'); - -module.exports = function (program, pluginConfig, { ts }) { - // only append .js when module specifier has no extension or user-provided extensions - const {extensions = ['.js']} = pluginConfig; - const extMappings = new Map(); - for (const ext of extensions) { - const addition = path.extname(ext) || ext; - const base = path.basename(ext, addition); - extMappings.set(base, addition); - } - - function shouldMutateModuleSpecifier(node) { - if (!ts.isImportDeclaration(node) && !ts.isExportDeclaration(node)) return false; - if (node.moduleSpecifier === undefined) return false; - // only when module specifier is valid - if (!ts.isStringLiteral(node.moduleSpecifier)) return false; - // only when path is relative - if (!node.moduleSpecifier.text.startsWith('./') && !node.moduleSpecifier.text.startsWith('../')) return false; - // only when module specifier has accepted extension - const ext = path.extname(node.moduleSpecifier.text); - if (!extMappings.has(ext)) return false; - return node.moduleSpecifier.text + extMappings.get(ext); - } - - return (ctx) => { - const { factory } = ctx; - - return (sourceFile) => { - function visit(node) { - const newImportSource = shouldMutateModuleSpecifier(node); - if (newImportSource) { - if (ts.isImportDeclaration(node)) { - const newModuleSpecifier = factory.createStringLiteral(newImportSource); - node = factory.updateImportDeclaration(node, node.modifiers, node.importClause, newModuleSpecifier, node.assertClause); - } else if (ts.isExportDeclaration(node)) { - const newModuleSpecifier = factory.createStringLiteral(newImportSource); - node = factory.updateExportDeclaration(node, node.modifiers, node.isTypeOnly, node.exportClause, newModuleSpecifier, node.assertClause); - } - } - - return ts.visitEachChild(node, visit, ctx); - } - - return ts.visitNode(sourceFile, visit); - }; - }; -} diff --git a/modules/dev-tools/ts-transform-version-inline/index.cjs b/modules/dev-tools/ts-transform-version-inline/index.cjs deleted file mode 100644 index 19fccbc6..00000000 --- a/modules/dev-tools/ts-transform-version-inline/index.cjs +++ /dev/null @@ -1,48 +0,0 @@ -const fs = require('fs'); -const path = require('path'); - -module.exports = function (program, pluginConfig, { ts }) { - const {identifier = '__VERSION__'} = pluginConfig; - - return (ctx) => { - const { factory } = ctx; - - return (sourceFile) => { - let packageVersion = undefined; - - function visit(node) { - if (ts.isIdentifier(node) && node.getText() === identifier) { - if (packageVersion === undefined) { - packageVersion = getPackageVersion(sourceFile.fileName); - } - if (packageVersion) { - return factory.createStringLiteral(packageVersion); - } - } - return ts.visitEachChild(node, visit, ctx); - } - return ts.visitNode(sourceFile, visit); - }; - }; -} - -/** - * Retrieve the version string from the closest package.json - */ -function getPackageVersion(fileName) { - let currentDir = fileName; - while (currentDir !== '/') { - try { - currentDir = path.dirname(currentDir); - const packageJson = path.join(currentDir, 'package.json'); - const stat = fs.statSync(packageJson); - if (stat.isFile()) { - const content = fs.readFileSync(packageJson, 'utf8'); - return JSON.parse(content).version; - } - } catch { - // file does not exist, try going up - } - } - return null; -} diff --git a/modules/dev-tools/tsconfig.json b/modules/dev-tools/tsconfig.json index 0ba7297d..698470f0 100644 --- a/modules/dev-tools/tsconfig.json +++ b/modules/dev-tools/tsconfig.json @@ -1,18 +1,18 @@ { "compilerOptions": { "target": "esnext", - "module": "esnext", - "allowJs": true, + "module": "commonjs", + "allowJs": false, "checkJs": false, "moduleResolution": "node", "esModuleInterop": true, "allowSyntheticDefaultImports": true, - "noEmit": true, "baseUrl": ".", "skipLibCheck": true, "strict": true }, "include":[ - "src/**/*" + "src/**/*", + "ts-plugins/**/*" ] }