chore(providence-analytics): apply "custom projects" in find-exports

This commit is contained in:
Thijs Louisse 2022-09-14 17:01:18 +02:00 committed by Thijs Louisse
parent 0b95d906e3
commit 3865a2433f
5 changed files with 160 additions and 129 deletions

View file

@ -4,23 +4,24 @@ const { default: traverse } = require('@babel/traverse');
const { Analyzer } = require('./helpers/Analyzer.js'); const { Analyzer } = require('./helpers/Analyzer.js');
const { trackDownIdentifier } = require('./helpers/track-down-identifier.js'); const { trackDownIdentifier } = require('./helpers/track-down-identifier.js');
const { normalizeSourcePaths } = require('./helpers/normalize-source-paths.js'); const { normalizeSourcePaths } = require('./helpers/normalize-source-paths.js');
const { aForEach } = require('../utils/async-array-utils.js');
const { LogService } = require('../services/LogService.js'); const { LogService } = require('../services/LogService.js');
/** /**
* @typedef {import('./helpers/track-down-identifier.js').RootFile} RootFile * @typedef {import('./helpers/track-down-identifier.js').RootFile} RootFile
* @typedef {object} RootFileMapEntry * @typedef {object} RootFileMapEntry
* @property {string} currentFileSpecifier this is the local name in the file we track from * @typedef {string} currentFileSpecifier this is the local name in the file we track from
* @property {RootFile} rootFile contains file(filePath) and specifier * @typedef {RootFile} rootFile contains file(filePath) and specifier
* @typedef {RootFileMapEntry[]} RootFileMap
*
* @typedef {{ exportSpecifiers:string[]; localMap: object; source:string, __tmp: { path:string } }} FindExportsSpecifierObj
*/ */
/** /**
* @typedef {RootFileMapEntry[]} RootFileMap * @param {FindExportsSpecifierObj[]} transformedEntry
*/ */
async function trackdownRoot(transformedEntry, relativePath, projectPath) { async function trackdownRoot(transformedEntry, relativePath, projectPath) {
const fullCurrentFilePath = pathLib.resolve(projectPath, relativePath); const fullCurrentFilePath = pathLib.resolve(projectPath, relativePath);
await aForEach(transformedEntry, async specObj => { for (const specObj of transformedEntry) {
/** @type {RootFileMap} */ /** @type {RootFileMap} */
const rootFileMap = []; const rootFileMap = [];
if (specObj.exportSpecifiers[0] === '[file]') { if (specObj.exportSpecifiers[0] === '[file]') {
@ -39,7 +40,7 @@ async function trackdownRoot(transformedEntry, relativePath, projectPath) {
* } * }
* } * }
*/ */
await aForEach(specObj.exportSpecifiers, async (/** @type {string} */ specifier) => { for (const specifier of specObj.exportSpecifiers) {
let rootFile; let rootFile;
let localMapMatch; let localMapMatch;
if (specObj.localMap) { if (specObj.localMap) {
@ -48,7 +49,7 @@ async function trackdownRoot(transformedEntry, relativePath, projectPath) {
// TODO: find out if possible to use trackDownIdentifierFromScope // TODO: find out if possible to use trackDownIdentifierFromScope
if (specObj.source) { if (specObj.source) {
// TODO: see if still needed: && (localMapMatch || specifier === '[default]') // TODO: see if still needed: && (localMapMatch || specifier === '[default]')
const importedIdentifier = (localMapMatch && localMapMatch.local) || specifier; const importedIdentifier = localMapMatch?.local || specifier;
rootFile = await trackDownIdentifier( rootFile = await trackDownIdentifier(
specObj.source, specObj.source,
importedIdentifier, importedIdentifier,
@ -69,10 +70,10 @@ async function trackdownRoot(transformedEntry, relativePath, projectPath) {
}; };
rootFileMap.push(entry); rootFileMap.push(entry);
} }
}); }
} }
specObj.rootFileMap = rootFileMap; specObj.rootFileMap = rootFileMap;
}); }
return transformedEntry; return transformedEntry;
} }
@ -139,6 +140,8 @@ function findExportsPerAstEntry(ast, { skipFileImports }) {
LogService.debug(`Analyzer "find-exports": started findExportsPerAstEntry method`); LogService.debug(`Analyzer "find-exports": started findExportsPerAstEntry method`);
// Visit AST... // Visit AST...
/** @type {FindExportsSpecifierObj} */
const transformedEntry = []; const transformedEntry = [];
// Unfortunately, we cannot have async functions in babel traverse. // Unfortunately, we cannot have async functions in babel traverse.
// Therefore, we store a temp reference to path that we use later for // Therefore, we store a temp reference to path that we use later for
@ -147,7 +150,7 @@ function findExportsPerAstEntry(ast, { skipFileImports }) {
ExportNamedDeclaration(path) { ExportNamedDeclaration(path) {
const exportSpecifiers = getExportSpecifiers(path.node); const exportSpecifiers = getExportSpecifiers(path.node);
const localMap = getLocalNameSpecifiers(path.node); const localMap = getLocalNameSpecifiers(path.node);
const source = path.node.source && path.node.source.value; const source = path.node.source?.value;
transformedEntry.push({ exportSpecifiers, localMap, source, __tmp: { path } }); transformedEntry.push({ exportSpecifiers, localMap, source, __tmp: { path } });
}, },
ExportDefaultDeclaration(path) { ExportDefaultDeclaration(path) {
@ -205,7 +208,8 @@ class FindExportsAnalyzer extends Analyzer {
* Traverse * Traverse
*/ */
const projectPath = cfg.targetProjectPath; const projectPath = cfg.targetProjectPath;
const queryOutput = await this._traverse(async (ast, { relativePath }) => {
const traverseEntryFn = async (ast, { relativePath }) => {
let transformedEntry = findExportsPerAstEntry(ast, cfg); let transformedEntry = findExportsPerAstEntry(ast, cfg);
transformedEntry = await normalizeSourcePaths(transformedEntry, relativePath, projectPath); transformedEntry = await normalizeSourcePaths(transformedEntry, relativePath, projectPath);
@ -213,6 +217,12 @@ class FindExportsAnalyzer extends Analyzer {
transformedEntry = cleanup(transformedEntry); transformedEntry = cleanup(transformedEntry);
return { result: transformedEntry }; return { result: transformedEntry };
};
const queryOutput = await this._traverse({
traverseEntryFn,
filePaths: cfg.targetFilePaths,
projectPath: cfg.targetProjectPath,
}); });
/** /**

View file

@ -0,0 +1,67 @@
/**
* @typedef {import('../../types/analyzers').FindExportsAnalyzerResult} FindExportsAnalyzerResult
*/
/**
* Convert to more easily iterable object
*
* From:
* ```js
* [
* "file": "./file-1.js",
* "result": [{
* "exportSpecifiers": [ "a", "b"],
* "localMap": [{...},{...}],
* "source": null,
* "rootFileMap": [{"currentFileSpecifier": "a", "rootFile": { "file": "[current]", "specifier": "a" }}]
* }, ...],
* ```
* To:
* ```js
* [{
* "file": ""./file-1.js",
* "exportSpecifier": "a",
* "localMap": {...},
* "source": null,
* "rootFileMap": {...}
* },
* {{
* "file": ""./file-1.js",
* "exportSpecifier": "b",
* "localMap": {...},
* "source": null,
* "rootFileMap": {...}
* }}],
*
* @param {FindExportsAnalyzerResult} exportsAnalyzerResult
*/
function transformIntoIterableFindExportsOutput(exportsAnalyzerResult) {
/** @type {IterableFindExportsAnalyzerEntry[]} */
const iterableEntries = [];
for (const { file, result } of exportsAnalyzerResult.queryOutput) {
for (const { exportSpecifiers, source, rootFileMap, localMap, meta } of result) {
if (!exportSpecifiers) {
// eslint-disable-next-line no-continue
continue;
}
for (const exportSpecifier of exportSpecifiers) {
const i = exportSpecifiers.indexOf(exportSpecifier);
/** @type {IterableFindExportsAnalyzerEntry} */
const resultEntry = {
file,
specifier: exportSpecifier,
source,
rootFile: rootFileMap ? rootFileMap[i] : undefined,
localSpecifier: localMap ? localMap[i] : undefined,
meta,
};
iterableEntries.push(resultEntry);
}
}
}
return iterableEntries;
}
module.exports = {
transformIntoIterableFindExportsOutput,
};

View file

@ -0,0 +1,62 @@
/**
* @typedef {import('../../types/analyzers').FindImportsAnalyzerResult} FindImportsAnalyzerResult
*/
/**
* Convert to more easily iterable object
*
* From:
* ```js
* [
* "file": "./file-1.js",
* "result": [{
* "importSpecifiers": [ "a", "b" ],
* "source": "exporting-ref-project",
* "normalizedSource": "exporting-ref-project"
* }], ,
* ```
* To:
* ```js
* [{
* "file": ""./file-1.js",
* "importSpecifier": "a",,
* "source": "exporting-ref-project",
* "normalizedSource": "exporting-ref-project"
* },
* {{
* "file": ""./file-1.js",
* "importSpecifier": "b",,
* "source": "exporting-ref-project",
* "normalizedSource": "exporting-ref-project"
* }}],
*
* @param {FindImportsAnalyzerResult} importsAnalyzerResult
*/
function transformIntoIterableFindImportsOutput(importsAnalyzerResult) {
/** @type {IterableFindImportsAnalyzerEntry[]} */
const iterableEntries = [];
for (const { file, result } of importsAnalyzerResult.queryOutput) {
for (const { importSpecifiers, source, normalizedSource } of result) {
if (!importSpecifiers) {
// eslint-disable-next-line no-continue
continue;
}
for (const importSpecifier of importSpecifiers) {
/** @type {IterableFindImportsAnalyzerEntry} */
const resultEntry = {
file,
specifier: importSpecifier,
source,
normalizedSource,
};
iterableEntries.push(resultEntry);
}
}
}
return iterableEntries;
}
module.exports = {
transformIntoIterableFindImportsOutput,
};

View file

@ -5,6 +5,12 @@ const FindImportsAnalyzer = require('./find-imports.js');
const FindExportsAnalyzer = require('./find-exports.js'); const FindExportsAnalyzer = require('./find-exports.js');
const { Analyzer } = require('./helpers/Analyzer.js'); const { Analyzer } = require('./helpers/Analyzer.js');
const { fromImportToExportPerspective } = require('./helpers/from-import-to-export-perspective.js'); const { fromImportToExportPerspective } = require('./helpers/from-import-to-export-perspective.js');
const {
transformIntoIterableFindExportsOutput,
} = require('./helpers/transform-into-iterable-find-exports-output.js');
const {
transformIntoIterableFindImportsOutput,
} = require('./helpers/transform-into-iterable-find-imports-output.js');
/** /**
* @typedef {import('../types/analyzers').FindImportsAnalyzerResult} FindImportsAnalyzerResult * @typedef {import('../types/analyzers').FindImportsAnalyzerResult} FindImportsAnalyzerResult
@ -32,120 +38,6 @@ function compareImportAndExportPaths(exportPath, translatedImportPath) {
); );
} }
/**
* Convert to more easily iterable object
*
* From:
* ```js
* [
* "file": "./file-1.js",
* "result": [{
* "exportSpecifiers": [ "a", "b"],
* "localMap": [{...},{...}],
* "source": null,
* "rootFileMap": [{"currentFileSpecifier": "a", "rootFile": { "file": "[current]", "specifier": "a" }}]
* }, ...],
* ```
* To:
* ```js
* [{
* "file": ""./file-1.js",
* "exportSpecifier": "a",
* "localMap": {...},
* "source": null,
* "rootFileMap": {...}
* },
* {{
* "file": ""./file-1.js",
* "exportSpecifier": "b",
* "localMap": {...},
* "source": null,
* "rootFileMap": {...}
* }}],
*
* @param {FindExportsAnalyzerResult} exportsAnalyzerResult
*/
function transformIntoIterableFindExportsOutput(exportsAnalyzerResult) {
/** @type {IterableFindExportsAnalyzerEntry[]} */
const iterableEntries = [];
for (const { file, result } of exportsAnalyzerResult.queryOutput) {
for (const { exportSpecifiers, source, rootFileMap, localMap, meta } of result) {
if (!exportSpecifiers) {
continue;
}
for (const exportSpecifier of exportSpecifiers) {
const i = exportSpecifiers.indexOf(exportSpecifier);
/** @type {IterableFindExportsAnalyzerEntry} */
const resultEntry = {
file,
specifier: exportSpecifier,
source,
rootFile: rootFileMap ? rootFileMap[i] : undefined,
localSpecifier: localMap ? localMap[i] : undefined,
meta,
};
iterableEntries.push(resultEntry);
}
}
}
return iterableEntries;
}
/**
* Convert to more easily iterable object
*
* From:
* ```js
* [
* "file": "./file-1.js",
* "result": [{
* "importSpecifiers": [ "a", "b" ],
* "source": "exporting-ref-project",
* "normalizedSource": "exporting-ref-project"
* }], ,
* ```
* To:
* ```js
* [{
* "file": ""./file-1.js",
* "importSpecifier": "a",,
* "source": "exporting-ref-project",
* "normalizedSource": "exporting-ref-project"
* },
* {{
* "file": ""./file-1.js",
* "importSpecifier": "b",,
* "source": "exporting-ref-project",
* "normalizedSource": "exporting-ref-project"
* }}],
*
* @param {FindImportsAnalyzerResult} importsAnalyzerResult
*/
function transformIntoIterableFindImportsOutput(importsAnalyzerResult) {
/** @type {IterableFindImportsAnalyzerEntry[]} */
const iterableEntries = [];
for (const { file, result } of importsAnalyzerResult.queryOutput) {
for (const { importSpecifiers, source, normalizedSource } of result) {
if (!importSpecifiers) {
continue;
}
for (const importSpecifier of importSpecifiers) {
/** @type {IterableFindImportsAnalyzerEntry} */
const resultEntry = {
file,
specifier: importSpecifier,
source,
normalizedSource,
};
iterableEntries.push(resultEntry);
}
}
}
return iterableEntries;
}
/** /**
* Makes a 'compatible resultsArray' (compatible with dashboard + tests + ...?) from * Makes a 'compatible resultsArray' (compatible with dashboard + tests + ...?) from
* a conciseResultsArray. * a conciseResultsArray.

View file

@ -53,7 +53,7 @@ describe('Analyzer "find-exports"', () => {
const firstEntry = getEntry(queryResult); const firstEntry = getEntry(queryResult);
expect(firstEntry.result[0].exportSpecifiers.length).to.equal(1); expect(firstEntry.result[0].exportSpecifiers.length).to.equal(1);
expect(firstEntry.result[0].exportSpecifiers[0]).to.equal('x'); expect(firstEntry.result[0].exportSpecifiers[0]).to.equal('x');
expect(firstEntry.result[0].source).to.be.null; expect(firstEntry.result[0].source).to.be.undefined;
}); });
it(`supports [export default class X {}] (default export)`, async () => { it(`supports [export default class X {}] (default export)`, async () => {
@ -189,7 +189,7 @@ describe('Analyzer "find-exports"', () => {
const firstEntry = getEntry(queryResult); const firstEntry = getEntry(queryResult);
expect(firstEntry.result[0].exportSpecifiers.length).to.equal(1); expect(firstEntry.result[0].exportSpecifiers.length).to.equal(1);
expect(firstEntry.result[0].exportSpecifiers[0]).to.equal('X'); expect(firstEntry.result[0].exportSpecifiers[0]).to.equal('X');
expect(firstEntry.result[0].source).to.be.null; expect(firstEntry.result[0].source).to.be.undefined;
}); });
it(`functions`, async () => { it(`functions`, async () => {
@ -199,7 +199,7 @@ describe('Analyzer "find-exports"', () => {
const firstEntry = getEntry(queryResult); const firstEntry = getEntry(queryResult);
expect(firstEntry.result[0].exportSpecifiers.length).to.equal(1); expect(firstEntry.result[0].exportSpecifiers.length).to.equal(1);
expect(firstEntry.result[0].exportSpecifiers[0]).to.equal('y'); expect(firstEntry.result[0].exportSpecifiers[0]).to.equal('y');
expect(firstEntry.result[0].source).to.be.null; expect(firstEntry.result[0].source).to.be.undefined;
}); });
// ...etc? // ...etc?