From 7a28ba23885dbb2bda98b5c6d7659134ea6d7777 Mon Sep 17 00:00:00 2001 From: Ivan Rubinson Date: Mon, 18 Mar 2024 21:11:25 +0200 Subject: [PATCH] [Refactor] `ExportMap`: separate ExportMap instance from its builder logic --- .eslintrc | 2 +- CHANGELOG.md | 2 + src/exportMap.js | 178 ++++++++++++++++++++ src/{ExportMap.js => exportMapBuilder.js} | 188 +--------------------- src/rules/default.js | 4 +- src/rules/export.js | 4 +- src/rules/named.js | 6 +- src/rules/namespace.js | 11 +- src/rules/no-cycle.js | 4 +- src/rules/no-deprecated.js | 7 +- src/rules/no-named-as-default-member.js | 4 +- src/rules/no-named-as-default.js | 4 +- src/rules/no-unused-modules.js | 4 +- tests/src/core/getExports.js | 60 +++---- 14 files changed, 242 insertions(+), 236 deletions(-) create mode 100644 src/exportMap.js rename src/{ExportMap.js => exportMapBuilder.js} (78%) diff --git a/.eslintrc b/.eslintrc index 224ffcb0e..1bbbba014 100644 --- a/.eslintrc +++ b/.eslintrc @@ -229,7 +229,7 @@ { "files": [ "utils/**", // TODO - "src/ExportMap.js", // TODO + "src/exportMapBuilder.js", // TODO ], "rules": { "no-use-before-define": "off", diff --git a/CHANGELOG.md b/CHANGELOG.md index 9552774dc..7ad93fbd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange - [Docs] `no-extraneous-dependencies`: Make glob pattern description more explicit ([#2944], thanks [@mulztob]) - [`no-unused-modules`]: add console message to help debug [#2866] - [Refactor] `ExportMap`: make procedures static instead of monkeypatching exportmap ([#2982], thanks [@soryy708]) +- [Refactor] `ExportMap`: separate ExportMap instance from its builder logic ([#2985], thanks [@soryy708]) ## [2.29.1] - 2023-12-14 @@ -1109,6 +1110,7 @@ for info on changes for earlier releases. [`memo-parser`]: ./memo-parser/README.md +[#2985]: https://github.com/import-js/eslint-plugin-import/pull/2985 [#2982]: https://github.com/import-js/eslint-plugin-import/pull/2982 [#2944]: https://github.com/import-js/eslint-plugin-import/pull/2944 [#2942]: https://github.com/import-js/eslint-plugin-import/pull/2942 diff --git a/src/exportMap.js b/src/exportMap.js new file mode 100644 index 000000000..e4d61638c --- /dev/null +++ b/src/exportMap.js @@ -0,0 +1,178 @@ +export default class ExportMap { + constructor(path) { + this.path = path; + this.namespace = new Map(); + // todo: restructure to key on path, value is resolver + map of names + this.reexports = new Map(); + /** + * star-exports + * @type {Set<() => ExportMap>} + */ + this.dependencies = new Set(); + /** + * dependencies of this module that are not explicitly re-exported + * @type {Map ExportMap>} + */ + this.imports = new Map(); + this.errors = []; + /** + * type {'ambiguous' | 'Module' | 'Script'} + */ + this.parseGoal = 'ambiguous'; + } + + get hasDefault() { return this.get('default') != null; } // stronger than this.has + + get size() { + let size = this.namespace.size + this.reexports.size; + this.dependencies.forEach((dep) => { + const d = dep(); + // CJS / ignored dependencies won't exist (#717) + if (d == null) { return; } + size += d.size; + }); + return size; + } + + /** + * Note that this does not check explicitly re-exported names for existence + * in the base namespace, but it will expand all `export * from '...'` exports + * if not found in the explicit namespace. + * @param {string} name + * @return {boolean} true if `name` is exported by this module. + */ + has(name) { + if (this.namespace.has(name)) { return true; } + if (this.reexports.has(name)) { return true; } + + // default exports must be explicitly re-exported (#328) + if (name !== 'default') { + for (const dep of this.dependencies) { + const innerMap = dep(); + + // todo: report as unresolved? + if (!innerMap) { continue; } + + if (innerMap.has(name)) { return true; } + } + } + + return false; + } + + /** + * ensure that imported name fully resolves. + * @param {string} name + * @return {{ found: boolean, path: ExportMap[] }} + */ + hasDeep(name) { + if (this.namespace.has(name)) { return { found: true, path: [this] }; } + + if (this.reexports.has(name)) { + const reexports = this.reexports.get(name); + const imported = reexports.getImport(); + + // if import is ignored, return explicit 'null' + if (imported == null) { return { found: true, path: [this] }; } + + // safeguard against cycles, only if name matches + if (imported.path === this.path && reexports.local === name) { + return { found: false, path: [this] }; + } + + const deep = imported.hasDeep(reexports.local); + deep.path.unshift(this); + + return deep; + } + + // default exports must be explicitly re-exported (#328) + if (name !== 'default') { + for (const dep of this.dependencies) { + const innerMap = dep(); + if (innerMap == null) { return { found: true, path: [this] }; } + // todo: report as unresolved? + if (!innerMap) { continue; } + + // safeguard against cycles + if (innerMap.path === this.path) { continue; } + + const innerValue = innerMap.hasDeep(name); + if (innerValue.found) { + innerValue.path.unshift(this); + return innerValue; + } + } + } + + return { found: false, path: [this] }; + } + + get(name) { + if (this.namespace.has(name)) { return this.namespace.get(name); } + + if (this.reexports.has(name)) { + const reexports = this.reexports.get(name); + const imported = reexports.getImport(); + + // if import is ignored, return explicit 'null' + if (imported == null) { return null; } + + // safeguard against cycles, only if name matches + if (imported.path === this.path && reexports.local === name) { return undefined; } + + return imported.get(reexports.local); + } + + // default exports must be explicitly re-exported (#328) + if (name !== 'default') { + for (const dep of this.dependencies) { + const innerMap = dep(); + // todo: report as unresolved? + if (!innerMap) { continue; } + + // safeguard against cycles + if (innerMap.path === this.path) { continue; } + + const innerValue = innerMap.get(name); + if (innerValue !== undefined) { return innerValue; } + } + } + + return undefined; + } + + forEach(callback, thisArg) { + this.namespace.forEach((v, n) => { callback.call(thisArg, v, n, this); }); + + this.reexports.forEach((reexports, name) => { + const reexported = reexports.getImport(); + // can't look up meta for ignored re-exports (#348) + callback.call(thisArg, reexported && reexported.get(reexports.local), name, this); + }); + + this.dependencies.forEach((dep) => { + const d = dep(); + // CJS / ignored dependencies won't exist (#717) + if (d == null) { return; } + + d.forEach((v, n) => { + if (n !== 'default') { + callback.call(thisArg, v, n, this); + } + }); + }); + } + + // todo: keys, values, entries? + + reportErrors(context, declaration) { + const msg = this.errors + .map((e) => `${e.message} (${e.lineNumber}:${e.column})`) + .join(', '); + context.report({ + node: declaration.source, + message: `Parse errors in imported module '${declaration.source.value}': ${msg}`, + }); + } +} diff --git a/src/ExportMap.js b/src/exportMapBuilder.js similarity index 78% rename from src/ExportMap.js rename to src/exportMapBuilder.js index 9ee65a504..f2b40e7b4 100644 --- a/src/ExportMap.js +++ b/src/exportMapBuilder.js @@ -18,6 +18,7 @@ import * as unambiguous from 'eslint-module-utils/unambiguous'; import { tsConfigLoader } from 'tsconfig-paths/lib/tsconfig-loader'; import includes from 'array-includes'; +import ExportMap from './exportMap'; let ts; @@ -117,189 +118,12 @@ const availableDocStyleParsers = { const supportedImportTypes = new Set(['ImportDefaultSpecifier', 'ImportNamespaceSpecifier']); -export default class ExportMap { - constructor(path) { - this.path = path; - this.namespace = new Map(); - // todo: restructure to key on path, value is resolver + map of names - this.reexports = new Map(); - /** - * star-exports - * @type {Set} of () => ExportMap - */ - this.dependencies = new Set(); - /** - * dependencies of this module that are not explicitly re-exported - * @type {Map} from path = () => ExportMap - */ - this.imports = new Map(); - this.errors = []; - /** - * type {'ambiguous' | 'Module' | 'Script'} - */ - this.parseGoal = 'ambiguous'; - } - - get hasDefault() { return this.get('default') != null; } // stronger than this.has - - get size() { - let size = this.namespace.size + this.reexports.size; - this.dependencies.forEach((dep) => { - const d = dep(); - // CJS / ignored dependencies won't exist (#717) - if (d == null) { return; } - size += d.size; - }); - return size; - } - - /** - * Note that this does not check explicitly re-exported names for existence - * in the base namespace, but it will expand all `export * from '...'` exports - * if not found in the explicit namespace. - * @param {string} name - * @return {Boolean} true if `name` is exported by this module. - */ - has(name) { - if (this.namespace.has(name)) { return true; } - if (this.reexports.has(name)) { return true; } - - // default exports must be explicitly re-exported (#328) - if (name !== 'default') { - for (const dep of this.dependencies) { - const innerMap = dep(); - - // todo: report as unresolved? - if (!innerMap) { continue; } - - if (innerMap.has(name)) { return true; } - } - } - - return false; - } - - /** - * ensure that imported name fully resolves. - * @param {string} name - * @return {{ found: boolean, path: ExportMap[] }} - */ - hasDeep(name) { - if (this.namespace.has(name)) { return { found: true, path: [this] }; } - - if (this.reexports.has(name)) { - const reexports = this.reexports.get(name); - const imported = reexports.getImport(); - - // if import is ignored, return explicit 'null' - if (imported == null) { return { found: true, path: [this] }; } - - // safeguard against cycles, only if name matches - if (imported.path === this.path && reexports.local === name) { - return { found: false, path: [this] }; - } - - const deep = imported.hasDeep(reexports.local); - deep.path.unshift(this); - - return deep; - } - - // default exports must be explicitly re-exported (#328) - if (name !== 'default') { - for (const dep of this.dependencies) { - const innerMap = dep(); - if (innerMap == null) { return { found: true, path: [this] }; } - // todo: report as unresolved? - if (!innerMap) { continue; } - - // safeguard against cycles - if (innerMap.path === this.path) { continue; } - - const innerValue = innerMap.hasDeep(name); - if (innerValue.found) { - innerValue.path.unshift(this); - return innerValue; - } - } - } - - return { found: false, path: [this] }; - } - - get(name) { - if (this.namespace.has(name)) { return this.namespace.get(name); } - - if (this.reexports.has(name)) { - const reexports = this.reexports.get(name); - const imported = reexports.getImport(); - - // if import is ignored, return explicit 'null' - if (imported == null) { return null; } - - // safeguard against cycles, only if name matches - if (imported.path === this.path && reexports.local === name) { return undefined; } - - return imported.get(reexports.local); - } - - // default exports must be explicitly re-exported (#328) - if (name !== 'default') { - for (const dep of this.dependencies) { - const innerMap = dep(); - // todo: report as unresolved? - if (!innerMap) { continue; } - - // safeguard against cycles - if (innerMap.path === this.path) { continue; } - - const innerValue = innerMap.get(name); - if (innerValue !== undefined) { return innerValue; } - } - } - - return undefined; - } - - forEach(callback, thisArg) { - this.namespace.forEach((v, n) => { callback.call(thisArg, v, n, this); }); - - this.reexports.forEach((reexports, name) => { - const reexported = reexports.getImport(); - // can't look up meta for ignored re-exports (#348) - callback.call(thisArg, reexported && reexported.get(reexports.local), name, this); - }); - - this.dependencies.forEach((dep) => { - const d = dep(); - // CJS / ignored dependencies won't exist (#717) - if (d == null) { return; } - - d.forEach((v, n) => { - if (n !== 'default') { - callback.call(thisArg, v, n, this); - } - }); - }); - } - - // todo: keys, values, entries? - - reportErrors(context, declaration) { - const msg = this.errors - .map((e) => `${e.message} (${e.lineNumber}:${e.column})`) - .join(', '); - context.report({ - node: declaration.source, - message: `Parse errors in imported module '${declaration.source.value}': ${msg}`, - }); - } - +export default class ExportMapBuilder { static get(source, context) { const path = resolve(source, context); if (path == null) { return null; } - return ExportMap.for(childContext(path, context)); + return ExportMapBuilder.for(childContext(path, context)); } static for(context) { @@ -343,7 +167,7 @@ export default class ExportMap { } log('cache miss', cacheKey, 'for path', path); - exportMap = ExportMap.parse(path, content, context); + exportMap = ExportMapBuilder.parse(path, content, context); // ambiguous modules return null if (exportMap == null) { @@ -447,7 +271,7 @@ export default class ExportMap { function resolveImport(value) { const rp = remotePath(value); if (rp == null) { return null; } - return ExportMap.for(childContext(rp, context)); + return ExportMapBuilder.for(childContext(rp, context)); } function getNamespace(identifier) { @@ -738,7 +562,7 @@ export default class ExportMap { * caused memory leaks. See #1266. */ function thunkFor(p, context) { - return () => ExportMap.for(childContext(p, context)); + return () => ExportMapBuilder.for(childContext(p, context)); } /** diff --git a/src/rules/default.js b/src/rules/default.js index 297a80c46..cbaa49f1f 100644 --- a/src/rules/default.js +++ b/src/rules/default.js @@ -1,4 +1,4 @@ -import Exports from '../ExportMap'; +import ExportMapBuilder from '../exportMapBuilder'; import docsUrl from '../docsUrl'; module.exports = { @@ -19,7 +19,7 @@ module.exports = { ); if (!defaultSpecifier) { return; } - const imports = Exports.get(node.source.value, context); + const imports = ExportMapBuilder.get(node.source.value, context); if (imports == null) { return; } if (imports.errors.length) { diff --git a/src/rules/export.js b/src/rules/export.js index c540f1e3c..b1dc5ca9e 100644 --- a/src/rules/export.js +++ b/src/rules/export.js @@ -1,4 +1,4 @@ -import ExportMap, { recursivePatternCapture } from '../ExportMap'; +import ExportMapBuilder, { recursivePatternCapture } from '../exportMapBuilder'; import docsUrl from '../docsUrl'; import includes from 'array-includes'; import flatMap from 'array.prototype.flatmap'; @@ -197,7 +197,7 @@ module.exports = { // `export * as X from 'path'` does not conflict if (node.exported && node.exported.name) { return; } - const remoteExports = ExportMap.get(node.source.value, context); + const remoteExports = ExportMapBuilder.get(node.source.value, context); if (remoteExports == null) { return; } if (remoteExports.errors.length) { diff --git a/src/rules/named.js b/src/rules/named.js index e7fe4e4dc..043d72eab 100644 --- a/src/rules/named.js +++ b/src/rules/named.js @@ -1,5 +1,5 @@ import * as path from 'path'; -import Exports from '../ExportMap'; +import ExportMapBuilder from '../exportMapBuilder'; import docsUrl from '../docsUrl'; module.exports = { @@ -41,7 +41,7 @@ module.exports = { return; // no named imports/exports } - const imports = Exports.get(node.source.value, context); + const imports = ExportMapBuilder.get(node.source.value, context); if (imports == null || imports.parseGoal === 'ambiguous') { return; } @@ -93,7 +93,7 @@ module.exports = { const call = node.init; const [source] = call.arguments; const variableImports = node.id.properties; - const variableExports = Exports.get(source.value, context); + const variableExports = ExportMapBuilder.get(source.value, context); if ( // return if it's not a commonjs require statement diff --git a/src/rules/namespace.js b/src/rules/namespace.js index 77a3ea907..e1ca2870b 100644 --- a/src/rules/namespace.js +++ b/src/rules/namespace.js @@ -1,5 +1,6 @@ import declaredScope from 'eslint-module-utils/declaredScope'; -import Exports from '../ExportMap'; +import ExportMapBuilder from '../exportMapBuilder'; +import ExportMap from '../exportMap'; import importDeclaration from '../importDeclaration'; import docsUrl from '../docsUrl'; @@ -8,7 +9,7 @@ function processBodyStatement(context, namespaces, declaration) { if (declaration.specifiers.length === 0) { return; } - const imports = Exports.get(declaration.source.value, context); + const imports = ExportMapBuilder.get(declaration.source.value, context); if (imports == null) { return null; } if (imports.errors.length > 0) { @@ -88,7 +89,7 @@ module.exports = { ExportNamespaceSpecifier(namespace) { const declaration = importDeclaration(context); - const imports = Exports.get(declaration.source.value, context); + const imports = ExportMapBuilder.get(declaration.source.value, context); if (imports == null) { return null; } if (imports.errors.length) { @@ -122,7 +123,7 @@ module.exports = { let namespace = namespaces.get(dereference.object.name); const namepath = [dereference.object.name]; // while property is namespace and parent is member expression, keep validating - while (namespace instanceof Exports && dereference.type === 'MemberExpression') { + while (namespace instanceof ExportMap && dereference.type === 'MemberExpression') { if (dereference.computed) { if (!allowComputed) { context.report( @@ -161,7 +162,7 @@ module.exports = { // DFS traverse child namespaces function testKey(pattern, namespace, path = [init.name]) { - if (!(namespace instanceof Exports)) { return; } + if (!(namespace instanceof ExportMap)) { return; } if (pattern.type !== 'ObjectPattern') { return; } diff --git a/src/rules/no-cycle.js b/src/rules/no-cycle.js index 11c2f44fc..b7b907b06 100644 --- a/src/rules/no-cycle.js +++ b/src/rules/no-cycle.js @@ -4,7 +4,7 @@ */ import resolve from 'eslint-module-utils/resolve'; -import Exports from '../ExportMap'; +import ExportMapBuilder from '../exportMapBuilder'; import { isExternalModule } from '../core/importType'; import moduleVisitor, { makeOptionsSchema } from 'eslint-module-utils/moduleVisitor'; import docsUrl from '../docsUrl'; @@ -88,7 +88,7 @@ module.exports = { return; // ignore type imports } - const imported = Exports.get(sourceNode.value, context); + const imported = ExportMapBuilder.get(sourceNode.value, context); if (imported == null) { return; // no-unresolved territory diff --git a/src/rules/no-deprecated.js b/src/rules/no-deprecated.js index 06eeff8ea..50072f3f8 100644 --- a/src/rules/no-deprecated.js +++ b/src/rules/no-deprecated.js @@ -1,5 +1,6 @@ import declaredScope from 'eslint-module-utils/declaredScope'; -import Exports from '../ExportMap'; +import ExportMapBuilder from '../exportMapBuilder'; +import ExportMap from '../exportMap'; import docsUrl from '../docsUrl'; function message(deprecation) { @@ -31,7 +32,7 @@ module.exports = { if (node.type !== 'ImportDeclaration') { return; } if (node.source == null) { return; } // local export, ignore - const imports = Exports.get(node.source.value, context); + const imports = ExportMapBuilder.get(node.source.value, context); if (imports == null) { return; } const moduleDeprecation = imports.doc && imports.doc.tags.find((t) => t.title === 'deprecated'); @@ -114,7 +115,7 @@ module.exports = { let namespace = namespaces.get(dereference.object.name); const namepath = [dereference.object.name]; // while property is namespace and parent is member expression, keep validating - while (namespace instanceof Exports && dereference.type === 'MemberExpression') { + while (namespace instanceof ExportMap && dereference.type === 'MemberExpression') { // ignore computed parts for now if (dereference.computed) { return; } diff --git a/src/rules/no-named-as-default-member.js b/src/rules/no-named-as-default-member.js index e00a4cbc8..d594c5843 100644 --- a/src/rules/no-named-as-default-member.js +++ b/src/rules/no-named-as-default-member.js @@ -4,7 +4,7 @@ * @copyright 2016 Desmond Brand. All rights reserved. * See LICENSE in root directory for full license. */ -import Exports from '../ExportMap'; +import ExportMapBuilder from '../exportMapBuilder'; import importDeclaration from '../importDeclaration'; import docsUrl from '../docsUrl'; @@ -36,7 +36,7 @@ module.exports = { return { ImportDefaultSpecifier(node) { const declaration = importDeclaration(context); - const exportMap = Exports.get(declaration.source.value, context); + const exportMap = ExportMapBuilder.get(declaration.source.value, context); if (exportMap == null) { return; } if (exportMap.errors.length) { diff --git a/src/rules/no-named-as-default.js b/src/rules/no-named-as-default.js index 40b1e175b..3e73ff2f4 100644 --- a/src/rules/no-named-as-default.js +++ b/src/rules/no-named-as-default.js @@ -1,4 +1,4 @@ -import Exports from '../ExportMap'; +import ExportMapBuilder from '../exportMapBuilder'; import importDeclaration from '../importDeclaration'; import docsUrl from '../docsUrl'; @@ -20,7 +20,7 @@ module.exports = { const declaration = importDeclaration(context); - const imports = Exports.get(declaration.source.value, context); + const imports = ExportMapBuilder.get(declaration.source.value, context); if (imports == null) { return; } if (imports.errors.length) { diff --git a/src/rules/no-unused-modules.js b/src/rules/no-unused-modules.js index ec3425dac..812efffbc 100644 --- a/src/rules/no-unused-modules.js +++ b/src/rules/no-unused-modules.js @@ -13,7 +13,7 @@ import values from 'object.values'; import includes from 'array-includes'; import flatMap from 'array.prototype.flatmap'; -import Exports, { recursivePatternCapture } from '../ExportMap'; +import ExportMapBuilder, { recursivePatternCapture } from '../exportMapBuilder'; import docsUrl from '../docsUrl'; let FileEnumerator; @@ -194,7 +194,7 @@ const prepareImportsAndExports = (srcFiles, context) => { srcFiles.forEach((file) => { const exports = new Map(); const imports = new Map(); - const currentExports = Exports.get(file, context); + const currentExports = ExportMapBuilder.get(file, context); if (currentExports) { const { dependencies, diff --git a/tests/src/core/getExports.js b/tests/src/core/getExports.js index 1dd6e8801..611a13055 100644 --- a/tests/src/core/getExports.js +++ b/tests/src/core/getExports.js @@ -4,7 +4,7 @@ import sinon from 'sinon'; import eslintPkg from 'eslint/package.json'; import typescriptPkg from 'typescript/package.json'; import * as tsConfigLoader from 'tsconfig-paths/lib/tsconfig-loader'; -import ExportMap from '../../../src/ExportMap'; +import ExportMapBuilder from '../../../src/exportMapBuilder'; import * as fs from 'fs'; @@ -28,7 +28,7 @@ describe('ExportMap', function () { it('handles ExportAllDeclaration', function () { let imports; expect(function () { - imports = ExportMap.get('./export-all', fakeContext); + imports = ExportMapBuilder.get('./export-all', fakeContext); }).not.to.throw(Error); expect(imports).to.exist; @@ -37,25 +37,25 @@ describe('ExportMap', function () { }); it('returns a cached copy on subsequent requests', function () { - expect(ExportMap.get('./named-exports', fakeContext)) - .to.exist.and.equal(ExportMap.get('./named-exports', fakeContext)); + expect(ExportMapBuilder.get('./named-exports', fakeContext)) + .to.exist.and.equal(ExportMapBuilder.get('./named-exports', fakeContext)); }); it('does not return a cached copy after modification', (done) => { - const firstAccess = ExportMap.get('./mutator', fakeContext); + const firstAccess = ExportMapBuilder.get('./mutator', fakeContext); expect(firstAccess).to.exist; // mutate (update modified time) const newDate = new Date(); fs.utimes(getFilename('mutator.js'), newDate, newDate, (error) => { expect(error).not.to.exist; - expect(ExportMap.get('./mutator', fakeContext)).not.to.equal(firstAccess); + expect(ExportMapBuilder.get('./mutator', fakeContext)).not.to.equal(firstAccess); done(); }); }); it('does not return a cached copy with different settings', () => { - const firstAccess = ExportMap.get('./named-exports', fakeContext); + const firstAccess = ExportMapBuilder.get('./named-exports', fakeContext); expect(firstAccess).to.exist; const differentSettings = { @@ -63,7 +63,7 @@ describe('ExportMap', function () { parserPath: 'espree', }; - expect(ExportMap.get('./named-exports', differentSettings)) + expect(ExportMapBuilder.get('./named-exports', differentSettings)) .to.exist.and .not.to.equal(firstAccess); }); @@ -71,7 +71,7 @@ describe('ExportMap', function () { it('does not throw for a missing file', function () { let imports; expect(function () { - imports = ExportMap.get('./does-not-exist', fakeContext); + imports = ExportMapBuilder.get('./does-not-exist', fakeContext); }).not.to.throw(Error); expect(imports).not.to.exist; @@ -81,7 +81,7 @@ describe('ExportMap', function () { it('exports explicit names for a missing file in exports', function () { let imports; expect(function () { - imports = ExportMap.get('./exports-missing', fakeContext); + imports = ExportMapBuilder.get('./exports-missing', fakeContext); }).not.to.throw(Error); expect(imports).to.exist; @@ -92,7 +92,7 @@ describe('ExportMap', function () { it('finds exports for an ES7 module with babel-eslint', function () { const path = getFilename('jsx/FooES7.js'); const contents = fs.readFileSync(path, { encoding: 'utf8' }); - const imports = ExportMap.parse( + const imports = ExportMapBuilder.parse( path, contents, { parserPath: 'babel-eslint', settings: {} }, @@ -112,7 +112,7 @@ describe('ExportMap', function () { before('parse file', function () { const path = getFilename('deprecated.js'); const contents = fs.readFileSync(path, { encoding: 'utf8' }).replace(/[\r]\n/g, lineEnding); - imports = ExportMap.parse(path, contents, parseContext); + imports = ExportMapBuilder.parse(path, contents, parseContext); // sanity checks expect(imports.errors).to.be.empty; @@ -181,7 +181,7 @@ describe('ExportMap', function () { before('parse file', function () { const path = getFilename('deprecated-file.js'); const contents = fs.readFileSync(path, { encoding: 'utf8' }); - imports = ExportMap.parse(path, contents, parseContext); + imports = ExportMapBuilder.parse(path, contents, parseContext); // sanity checks expect(imports.errors).to.be.empty; @@ -243,7 +243,7 @@ describe('ExportMap', function () { it('works with espree & traditional namespace exports', function () { const path = getFilename('deep/a.js'); const contents = fs.readFileSync(path, { encoding: 'utf8' }); - const a = ExportMap.parse(path, contents, espreeContext); + const a = ExportMapBuilder.parse(path, contents, espreeContext); expect(a.errors).to.be.empty; expect(a.get('b').namespace).to.exist; expect(a.get('b').namespace.has('c')).to.be.true; @@ -252,7 +252,7 @@ describe('ExportMap', function () { it('captures namespace exported as default', function () { const path = getFilename('deep/default.js'); const contents = fs.readFileSync(path, { encoding: 'utf8' }); - const def = ExportMap.parse(path, contents, espreeContext); + const def = ExportMapBuilder.parse(path, contents, espreeContext); expect(def.errors).to.be.empty; expect(def.get('default').namespace).to.exist; expect(def.get('default').namespace.has('c')).to.be.true; @@ -261,7 +261,7 @@ describe('ExportMap', function () { it('works with babel-eslint & ES7 namespace exports', function () { const path = getFilename('deep-es7/a.js'); const contents = fs.readFileSync(path, { encoding: 'utf8' }); - const a = ExportMap.parse(path, contents, babelContext); + const a = ExportMapBuilder.parse(path, contents, babelContext); expect(a.errors).to.be.empty; expect(a.get('b').namespace).to.exist; expect(a.get('b').namespace.has('c')).to.be.true; @@ -278,7 +278,7 @@ describe('ExportMap', function () { const path = getFilename('deep/cache-1.js'); const contents = fs.readFileSync(path, { encoding: 'utf8' }); - a = ExportMap.parse(path, contents, espreeContext); + a = ExportMapBuilder.parse(path, contents, espreeContext); expect(a.errors).to.be.empty; expect(a.get('b').namespace).to.exist; @@ -304,10 +304,10 @@ describe('ExportMap', function () { context('Map API', function () { context('#size', function () { - it('counts the names', () => expect(ExportMap.get('./named-exports', fakeContext)) + it('counts the names', () => expect(ExportMapBuilder.get('./named-exports', fakeContext)) .to.have.property('size', 12)); - it('includes exported namespace size', () => expect(ExportMap.get('./export-all', fakeContext)) + it('includes exported namespace size', () => expect(ExportMapBuilder.get('./export-all', fakeContext)) .to.have.property('size', 1)); }); @@ -315,14 +315,14 @@ describe('ExportMap', function () { context('issue #210: self-reference', function () { it(`doesn't crash`, function () { - expect(() => ExportMap.get('./narcissist', fakeContext)).not.to.throw(Error); + expect(() => ExportMapBuilder.get('./narcissist', fakeContext)).not.to.throw(Error); }); it(`'has' circular reference`, function () { - expect(ExportMap.get('./narcissist', fakeContext)) + expect(ExportMapBuilder.get('./narcissist', fakeContext)) .to.exist.and.satisfy((m) => m.has('soGreat')); }); it(`can 'get' circular reference`, function () { - expect(ExportMap.get('./narcissist', fakeContext)) + expect(ExportMapBuilder.get('./narcissist', fakeContext)) .to.exist.and.satisfy((m) => m.get('soGreat') != null); }); }); @@ -335,7 +335,7 @@ describe('ExportMap', function () { let imports; before('load imports', function () { - imports = ExportMap.get('./typescript.ts', context); + imports = ExportMapBuilder.get('./typescript.ts', context); }); it('returns nothing for a TypeScript file', function () { @@ -372,7 +372,7 @@ describe('ExportMap', function () { before('load imports', function () { this.timeout(20e3); // takes a long time :shrug: sinon.spy(tsConfigLoader, 'tsConfigLoader'); - imports = ExportMap.get('./typescript.ts', context); + imports = ExportMapBuilder.get('./typescript.ts', context); }); after('clear spies', function () { tsConfigLoader.tsConfigLoader.restore(); @@ -414,9 +414,9 @@ describe('ExportMap', function () { }, }; expect(tsConfigLoader.tsConfigLoader.callCount).to.equal(0); - ExportMap.parse('./baz.ts', 'export const baz = 5', customContext); + ExportMapBuilder.parse('./baz.ts', 'export const baz = 5', customContext); expect(tsConfigLoader.tsConfigLoader.callCount).to.equal(1); - ExportMap.parse('./baz.ts', 'export const baz = 5', customContext); + ExportMapBuilder.parse('./baz.ts', 'export const baz = 5', customContext); expect(tsConfigLoader.tsConfigLoader.callCount).to.equal(1); const differentContext = { @@ -426,17 +426,17 @@ describe('ExportMap', function () { }, }; - ExportMap.parse('./baz.ts', 'export const baz = 5', differentContext); + ExportMapBuilder.parse('./baz.ts', 'export const baz = 5', differentContext); expect(tsConfigLoader.tsConfigLoader.callCount).to.equal(2); }); it('should cache after parsing for an ambiguous module', function () { const source = './typescript-declare-module.ts'; - const parseSpy = sinon.spy(ExportMap, 'parse'); + const parseSpy = sinon.spy(ExportMapBuilder, 'parse'); - expect(ExportMap.get(source, context)).to.be.null; + expect(ExportMapBuilder.get(source, context)).to.be.null; - ExportMap.get(source, context); + ExportMapBuilder.get(source, context); expect(parseSpy.callCount).to.equal(1);