From 2f092d84412ec586bfdbaa36763484e7a2dc2dfc Mon Sep 17 00:00:00 2001 From: Christoph Thiede Date: Tue, 8 Jun 2021 21:11:58 +0000 Subject: [PATCH] Refactor module import workarounds Reuse dynamicImport workaround by @TomerAberbach due to https://github.com/microsoft/TypeScript/issues/43329 for escape-string-regexp as well --- src/references.ts | 17 +++++++++-------- src/utils/dynamic-import.ts | 7 +++++++ src/utils/escape-string-regexp.ts | 13 ------------- 3 files changed, 16 insertions(+), 21 deletions(-) create mode 100644 src/utils/dynamic-import.ts delete mode 100644 src/utils/escape-string-regexp.ts diff --git a/src/references.ts b/src/references.ts index e23a7b3b..58b6c67f 100644 --- a/src/references.ts +++ b/src/references.ts @@ -1,5 +1,4 @@ import { Dirent, promises as fsPromises } from "fs" -import escapeRegexp from './utils/escape-string-regexp' // WORKAROUND! Importing escape-string-regexp leads to ERR_REQUIRE_ESM import fs from 'fs' import glob from 'glob-promise' import asyncIteratorToArray from 'it-all' @@ -8,6 +7,7 @@ import tqdm from 'ntqdm' import path from 'path' import { getCacheDirectory } from './npm-deps' +import dynamicImport from "./utils/dynamic-import" import rex from './utils/rex' @@ -79,6 +79,7 @@ export class ReferenceSearcher { const dependencyName = path.basename(rootDirectory) const packageSearcher = new PackageReferenceSearcher(this.packageName, dependencyName) + await packageSearcher.initialize() let files: Iterable = await glob('**{/!(dist)/,}!(*.min|dist).{js,ts}', { cwd: rootDirectory, nodir: true }) if (!(depth > ReferenceSearcher.maximumReportableDepth)) { files = tqdm(files, { desc: `Scanning dependents (${dependencyName})...` }) @@ -102,11 +103,13 @@ class PackageReferenceSearcher { constructor(packageName: string, dependencyName: string) { this.packageName = packageName this.dependencyName = dependencyName + } - this.initializeCommonJsPatterns() + async initialize() { + await this.initializeCommonJsPatterns() } - private initializeCommonJsPatterns() { + private async initializeCommonJsPatterns() { // Let's build a regex family! // `foo = require('bar')` // `foo = require('bar/baz')` @@ -114,6 +117,7 @@ class PackageReferenceSearcher { const identifierPattern = /[\p{L}\p{Nl}$_][\p{L}\p{Nl}$\p{Mn}\p{Mc}\p{Nd}\p{Pc}]*/u + const escapeRegexp = (await dynamicImport('escape-string-regexp')).default const requirePattern = rex` (? ${identifierPattern} ) \s* = \s* @@ -182,14 +186,11 @@ class PackageReferenceSearcher { // Truly awful hack! There are a few things going on here: // - Jest (or something) can't find parse-imports by just importing its package name // no matter what. Just give it the path to the src/index.js file - // - TypeScript will always try to replace dynamic imports with requires - // which doesn't work for importing ESM from CJS (https://github.com/microsoft/TypeScript/issues/43329). - // We work around by "hiding" our dynamic import in a Function constructor (terrible...) + // - See the comment in dynamicImport // - All of this required jest@next, ts-jest@next, AND `NODE_OPTIONS=--experimental-vm-modules` const parseImportsIndexPath = path.join(path.dirname(__dirname), 'node_modules/parse-imports/src/index.js') - const dynamicImport = new Function('moduleName', 'return import(moduleName)') const parseImports = (await dynamicImport(parseImportsIndexPath)).default - + return await parseImports(source) } catch (parseError) { console.warn("Error from parse-imports", { parseError, source: source.slice(0, 100) }) diff --git a/src/utils/dynamic-import.ts b/src/utils/dynamic-import.ts new file mode 100644 index 00000000..6fb041ef --- /dev/null +++ b/src/utils/dynamic-import.ts @@ -0,0 +1,7 @@ +/** + * Workaround for https://github.com/microsoft/TypeScript/issues/43329. + * + * TypeScript will always try to replace dynamic imports with requires` which doesn't work for importing ESM from CJS. + * We work around by "hiding" our dynamic import in a Function constructor (terrible...) + */ +export default new Function('moduleName', 'return import(moduleName)') diff --git a/src/utils/escape-string-regexp.ts b/src/utils/escape-string-regexp.ts deleted file mode 100644 index 3ed6eef2..00000000 --- a/src/utils/escape-string-regexp.ts +++ /dev/null @@ -1,13 +0,0 @@ -// WORKAROUND! Importing escape-string-regexp leads to ERR_REQUIRE_ESM - -export default function escapeStringRegexp(string: string) { - if (typeof string !== 'string') { - throw new TypeError('Expected a string'); - } - - // Escape characters with special meaning either inside or outside character sets. - // Use a simple backslash escape when it’s always valid, and a `\xnn` escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar. - return string - .replace(/[|\\{}()[\]^$+*?.]/g, '\\$&') - .replace(/-/g, '\\x2d'); -}