diff --git a/.eslintrc.js b/.eslintrc.cjs similarity index 75% rename from .eslintrc.js rename to .eslintrc.cjs index 7e81661f..069d1654 100644 --- a/.eslintrc.js +++ b/.eslintrc.cjs @@ -1,8 +1,8 @@ module.exports = { root: true, parserOptions: { - ecmaVersion: 2017, - sourceType: 'script', + ecmaVersion: 2019, + sourceType: 'module', }, plugins: ['prettier', 'node'], extends: ['eslint:recommended', 'plugin:node/recommended', 'prettier'], @@ -10,6 +10,12 @@ module.exports = { node: true, }, rules: { + // these are disabled because the import statements have to use `.js` extension, + // but eslint-plugin-node can only see `.ts` files (so it flags them as missing) + 'node/no-missing-import': 'off', + 'node/no-unpublished-import': 'off', + + 'node/no-unsupported-features/es-syntax': ['error', { ignores: ['dynamicImport', 'modules'] }], 'prettier/prettier': 'error', }, @@ -18,10 +24,6 @@ module.exports = { files: ['**/*.ts'], parser: '@typescript-eslint/parser', - parserOptions: { - ecmaVersion: 2017, - sourceType: 'module', - }, plugins: ['@typescript-eslint'], extends: ['plugin:@typescript-eslint/recommended'], @@ -39,8 +41,6 @@ module.exports = { }, rules: { - 'node/no-unsupported-features/es-syntax': ['error', { ignores: ['modules'] }], - // we should work to remove these overrides '@typescript-eslint/no-var-requires': 'off', '@typescript-eslint/no-use-before-define': 'off', diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..d4401713 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "trailingComma": "es5", + "printWidth": 100 +} diff --git a/.prettierrc.js b/.prettierrc.js deleted file mode 100644 index 978b4d51..00000000 --- a/.prettierrc.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -module.exports = { - singleQuote: true, - trailingComma: 'es5', - printWidth: 100, -}; diff --git a/jest.config.js b/jest.config.js index f2e101aa..8e9e18f6 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,5 +1,5 @@ -module.exports = { - preset: 'ts-jest', +export default { + transform: {}, testEnvironment: 'node', - roots: ['/src/'], + roots: ['/lib/'], }; diff --git a/package.json b/package.json index bcf36922..5d3f6d2a 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "lib/", "!lib/**/*.test.*" ], + "type": "module", "scripts": { "build": "tsc", "lint": "npm-run-all lint:*", @@ -28,8 +29,8 @@ "lint:tsc": "tsc --noEmit", "prepare": "tsc", "release": "release-it", - "test": "npm-run-all lint test:*", - "test:jest": "jest" + "test": "npm-run-all lint build test:*", + "test:jest": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js" }, "dependencies": { "@glimmer/reference": "^0.82.0", @@ -62,7 +63,6 @@ "prettier": "^2.4.1", "release-it": "^14.11.6", "release-it-lerna-changelog": "^4.0.1", - "ts-jest": "^26.5.6", "typescript": "~4.4.4" }, "engines": { diff --git a/src/bin.test.ts b/src/bin.test.ts index 94957f5b..f7320a61 100644 --- a/src/bin.test.ts +++ b/src/bin.test.ts @@ -1,13 +1,18 @@ -import * as path from 'path'; import { existsSync } from 'fs'; +import { fileURLToPath } from 'url'; import execa from 'execa'; import { join } from 'path'; import { createTempDir, TempDir } from 'broccoli-test-helper'; import slash from 'slash'; -const COMPILED_BIN_PATH = path.join(__dirname, '../lib/bin.js'); +const COMPILED_BIN_PATH = fileURLToPath(new URL('./bin.js', import.meta.url)); + if (!existsSync(COMPILED_BIN_PATH)) { - throw new Error('Missing compiled output, run `yarn build`!'); + throw new Error( + `Missing compiled output, run \`yarn build\`! Looked at ${COMPILED_BIN_PATH} (based on ${ + import.meta.url + })` + ); } function run(args: string[], cwd: string) { diff --git a/src/bin.ts b/src/bin.ts index c239312c..04ad666a 100755 --- a/src/bin.ts +++ b/src/bin.ts @@ -1,11 +1,16 @@ #!/usr/bin/env node import * as os from 'os'; +import { readFileSync } from 'fs'; import { program } from 'commander'; -import run from './runner'; +import run from './runner.js'; +import { pathToFileURL } from 'url'; +const version = JSON.parse( + readFileSync(new URL('../package.json', import.meta.url), { encoding: 'utf-8' }) +); program - .version(require('../package').version) + .version(version) .usage(' -t transform-plugin.js') .option( '-t, --transform ', @@ -32,5 +37,6 @@ if (program.args.length < 1 || !programOptions.transform) { silent: programOptions.silent, }; - run(programOptions.transform, program.args, options); + const transformPath = pathToFileURL(programOptions.transform); + run(transformPath, program.args, options); } diff --git a/src/index.ts b/src/index.ts index 81972190..5dc6c53d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ import { traverse, builders, Walker, print as glimmerPrint } from '@glimmer/syntax'; import type { ASTv1 as AST, NodeVisitor } from '@glimmer/syntax'; -import ParseResult, { NodeInfo } from './parse-result'; +import ParseResult, { NodeInfo } from './parse-result.js'; const PARSE_RESULT_FOR = new WeakMap(); const NODE_INFO = new WeakMap(); @@ -143,4 +143,4 @@ export function transform( export type { AST, NodeVisitor } from '@glimmer/syntax'; export { builders, traverse } from '@glimmer/syntax'; -export { sourceForLoc } from './utils'; +export { sourceForLoc } from './utils.js'; diff --git a/src/parse-result.ts b/src/parse-result.ts index 3ecca592..e3d985f8 100644 --- a/src/parse-result.ts +++ b/src/parse-result.ts @@ -1,5 +1,5 @@ import { preprocess, builders, print as _print, traverse, ASTv1 as AST } from '@glimmer/syntax'; -import { getLines, sortByLoc, sourceForLoc } from './utils'; +import { getLines, sortByLoc, sourceForLoc } from './utils.js'; const leadingWhitespace = /(^\s+)/; const attrNodeParts = /(^[^=]+)(\s+)?(=)?(\s+)?(['"])?(\S+)?/; diff --git a/src/runner.ts b/src/runner.ts index ef30db28..4c4dde61 100644 --- a/src/runner.ts +++ b/src/runner.ts @@ -2,7 +2,7 @@ import * as http from 'http'; import * as https from 'https'; import { writeFileSync } from 'fs'; import { resolve } from 'path'; -import colors from 'colors/safe'; +import colors from 'colors/safe.js'; import slash from 'slash'; import globby from 'globby'; import ora from 'ora'; @@ -12,6 +12,9 @@ import workerpool from 'workerpool'; tmp.setGracefulCleanup(); +import { fileURLToPath } from 'url'; +const WORKER_PATH = fileURLToPath(new URL('./worker.js', import.meta.url)); + class NoFilesError extends Error {} class SilentLogger { @@ -119,7 +122,7 @@ class StatsCollector { } export default async function run( - transformFile: string, + transformFile: URL, filePaths: string[], options: { silent?: boolean; cpus: number } ): Promise { @@ -149,11 +152,11 @@ export default async function run( /** * Returns the location of the transform module on disk. */ -async function loadTransform(transformFile: string): Promise { - const isRemote = transformFile.startsWith('http'); +async function loadTransform(transformFile: URL): Promise { + const isLocal = transformFile.protocol === 'file:'; - if (!isRemote) { - return resolve(process.cwd(), transformFile); + if (isLocal) { + return fileURLToPath(transformFile); } const contents = await downloadFile(transformFile); @@ -164,9 +167,9 @@ async function loadTransform(transformFile: string): Promise { return filePath.name; } -function downloadFile(url: string): Promise { +function downloadFile(url: URL): Promise { return new Promise((resolve, reject) => { - const transport = url.startsWith('https') ? https : http; + const transport = url.protocol === 'https:' ? https : http; let contents = ''; transport @@ -219,7 +222,7 @@ async function spawnWorkers( logger.spin('Processed 0 files'); - const pool = workerpool.pool(require.resolve('./worker'), { maxWorkers: cpus }); + const pool = workerpool.pool(WORKER_PATH, { maxWorkers: cpus }); let i = 0; const worker = (queue as any).async.asyncify(async (file: string) => { @@ -238,13 +241,14 @@ async function spawnWorkers( function handleError(err: any, logger: Logger): void { if (err.code === 'MODULE_NOT_FOUND') { - logger.error('Transform plugin not found'); + logger.error(`Transform plugin not found`); } else if (err instanceof NoFilesError) { logger.error('No files matched'); } else { logger.error(err); - if (err.stack) { - logger.error(err.stack); - } + } + + if (err.stack) { + logger.error(err.stack); } } diff --git a/src/worker.ts b/src/worker.ts index 54c4781b..32298425 100644 --- a/src/worker.ts +++ b/src/worker.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import workerpool from 'workerpool'; -import { transform } from './index'; +import { transform } from './index.js'; import type { TransformPluginBuilder } from './index'; interface TransformResult { @@ -14,7 +14,7 @@ interface TransformOptions { } async function run(transformPath: string, filePath: string, options: TransformOptions) { - const module = require(transformPath); + const module = await import(transformPath); const plugin: TransformPluginBuilder = typeof module.default === 'function' ? module.default : module; diff --git a/tsconfig.json b/tsconfig.json index e29963ee..72c2e587 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,8 @@ "declarationMap": true, "sourceMap": true, "target": "es2018", - "module": "commonjs", + "module": "es2020", + "moduleResolution": "Node", "strict": true, "esModuleInterop": true, "outDir": "./lib", diff --git a/yarn.lock b/yarn.lock index c2a4d960..f0a9d19c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1521,13 +1521,6 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== -bs-logger@0.x: - version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" - integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== - dependencies: - fast-json-stable-stringify "2.x" - bser@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" @@ -1535,7 +1528,7 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -buffer-from@1.x, buffer-from@^1.0.0: +buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== @@ -2649,7 +2642,7 @@ fast-glob@^3.1.1: micromatch "^4.0.2" picomatch "^2.2.1" -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -4062,7 +4055,7 @@ jest-snapshot@^26.6.2: pretty-format "^26.6.2" semver "^7.3.2" -jest-util@^26.1.0, jest-util@^26.6.2: +jest-util@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== @@ -4219,7 +4212,7 @@ json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= -json5@2.x, json5@^2.1.2: +json5@^2.1.2: version "2.1.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== @@ -4372,7 +4365,7 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= -lodash@4.17.21, lodash@4.x, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21: +lodash@4.17.21, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -4414,11 +4407,6 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" -make-error@1.x: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - make-fetch-happen@^9.0.0: version "9.1.0" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" @@ -4835,11 +4823,6 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - mkdirp@^0.5.1: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" @@ -4847,6 +4830,11 @@ mkdirp@^0.5.1: dependencies: minimist "^1.2.5" +mkdirp@^1.0.3, mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + mktemp@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" @@ -5936,7 +5924,7 @@ semver-diff@^3.1.1: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@7.3.5, semver@7.x, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: +semver@7.3.5, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== @@ -6511,22 +6499,6 @@ tree-sync@^1.2.2: quick-temp "^0.1.5" walk-sync "^0.3.3" -ts-jest@^26.5.6: - version "26.5.6" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35" - integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA== - dependencies: - bs-logger "0.x" - buffer-from "1.x" - fast-json-stable-stringify "2.x" - jest-util "^26.1.0" - json5 "2.x" - lodash "4.x" - make-error "1.x" - mkdirp "1.x" - semver "7.x" - yargs-parser "20.x" - tslib@^1.8.1: version "1.13.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" @@ -6999,7 +6971,7 @@ yaml@1.10.2, yaml@^1.10.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yargs-parser@20.2.9, yargs-parser@20.x, yargs-parser@^20.2.2: +yargs-parser@20.2.9, yargs-parser@^20.2.2: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==