Merge pull request #1558 from ing-bank/fix/dedupeMatchImportsResults

Fix/dedupe match imports results
This commit is contained in:
Thijs Louisse 2021-11-23 10:32:35 +01:00 committed by GitHub
commit f282091750
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 105 additions and 49 deletions

View file

@ -0,0 +1,7 @@
---
'providence-analytics': patch
---
- correctly dedupe match-imports exportSpecifiers
- windows compatibility
- example conf file esm compatible

View file

@ -0,0 +1,5 @@
---
'rocket-preset-extend-lion-docs': patch
---
windows compatibility

View file

@ -21,7 +21,7 @@
"scripts": { "scripts": {
"dashboard": "node ./dashboard/src/server.js --serve-from-package-root", "dashboard": "node ./dashboard/src/server.js --serve-from-package-root",
"match-lion-imports": "npm run providence analyze match-imports --search-target-collection @lion-targets --reference-collection @lion-references", "match-lion-imports": "npm run providence analyze match-imports --search-target-collection @lion-targets --reference-collection @lion-references",
"providence": "node --max-old-space-size=8192 ./src/cli/index.js", "providence": "node --max-old-space-size=8192 ./src/cli/index.mjs",
"publish-docs": "node ../../packages-node/publish-docs/src/cli.js --github-url https://github.com/ing-bank/lion/ --git-root-dir ../../", "publish-docs": "node ../../packages-node/publish-docs/src/cli.js --github-url https://github.com/ing-bank/lion/ --git-root-dir ../../",
"prepublishOnly": "npm run publish-docs", "prepublishOnly": "npm run publish-docs",
"test:node": "mocha './test-node/**/*.test.js'", "test:node": "mocha './test-node/**/*.test.js'",

View file

@ -1,5 +1,8 @@
import pathLib from 'path'; import pathLib, { dirname } from 'path';
import fs from 'fs'; import fs from 'fs';
import { fileURLToPath } from 'url';
const __dirname = dirname(fileURLToPath(import.meta.url));
// This file is read by dashboard and cli and needs to be present under process.cwd() // This file is read by dashboard and cli and needs to be present under process.cwd()
// It mainly serves as an example and it allows to run the dashboard locally // It mainly serves as an example and it allows to run the dashboard locally

View file

@ -115,7 +115,12 @@ async function appendProjectDependencyPaths(rootPaths, matchPattern, modes = ['n
let matchFn; let matchFn;
if (matchPattern) { if (matchPattern) {
if (matchPattern.startsWith('/') && matchPattern.endsWith('/')) { if (matchPattern.startsWith('/') && matchPattern.endsWith('/')) {
matchFn = (_, d) => new RegExp(matchPattern.slice(1, -1)).test(d); matchFn = (_, d) => {
const reString = matchPattern.slice(1, -1);
const result = new RegExp(reString).test(d);
LogService.debug(`[appendProjectDependencyPaths]: /${reString}/.test(${d} => ${result})`);
return result;
};
} else { } else {
LogService.error( LogService.error(
`[appendProjectDependencyPaths] Please provide a matchPattern enclosed by '/'. Found: ${matchPattern}`, `[appendProjectDependencyPaths] Please provide a matchPattern enclosed by '/'. Found: ${matchPattern}`,

View file

@ -8,10 +8,10 @@ const { LogService } = require('../program/services/LogService.js');
const JsdocCommentParser = require('../program/utils/jsdoc-comment-parser.js'); const JsdocCommentParser = require('../program/utils/jsdoc-comment-parser.js');
/** /**
* @desc extracts name, defaultValue, optional, type, desc from JsdocCommentParser.parse method * Extracts name, defaultValue, optional, type, desc from JsdocCommentParser.parse method
* result * result
* @param {array} jsdoc * @param {string[]} jsdoc
* @returns {object} * @returns {{ name:string, defaultValue:string, optional:boolean, type:string, desc:string }}
*/ */
function getPropsFromParsedJsDoc(jsdoc) { function getPropsFromParsedJsDoc(jsdoc) {
const jsdocProps = jsdoc.filter(p => p.tagName === '@property'); const jsdocProps = jsdoc.filter(p => p.tagName === '@property');

View file

@ -237,7 +237,9 @@ async function matchImportsPostprocess(exportsAnalyzerResult, importsAnalyzerRes
* Add it to the results array * Add it to the results array
*/ */
const id = `${exportEntry.specifier}::${exportEntry.file}::${exportsAnalyzerResult.analyzerMeta.targetProject.name}`; const id = `${exportEntry.specifier}::${exportEntry.file}::${exportsAnalyzerResult.analyzerMeta.targetProject.name}`;
const resultForCurrentExport = conciseResultsArray.find(entry => entry.id === id); const resultForCurrentExport = conciseResultsArray.find(
entry => entry.exportSpecifier && entry.exportSpecifier.id === id,
);
if (resultForCurrentExport) { if (resultForCurrentExport) {
resultForCurrentExport.importProjectFiles.push(importEntry.file); resultForCurrentExport.importProjectFiles.push(importEntry.file);
} else { } else {

View file

@ -12,6 +12,8 @@
const pathLib = require('path'); const pathLib = require('path');
const { nodeResolve } = require('@rollup/plugin-node-resolve'); const { nodeResolve } = require('@rollup/plugin-node-resolve');
const { LogService } = require('../services/LogService.js'); const { LogService } = require('../services/LogService.js');
const { memoizeAsync } = require('./memoize.js');
const { toPosixPath } = require('./to-posix-path.js');
const fakePluginContext = { const fakePluginContext = {
meta: { meta: {
@ -27,15 +29,6 @@ const fakePluginContext = {
}, },
}; };
/**
* Based on importee (in a statement "import {x} from '@lion/core'", "@lion/core" is an
* importee), which can be a bare module specifier, a filename without extension, or a folder
* name without an extension.
* @param {SpecifierSource} importee source like '@lion/core' or '../helpers/index.js'
* @param {PathFromSystemRoot} importer importing file, like '/my/project/importing-file.js'
* @param {{customResolveOptions?: {preserveSymlinks:boolean}}} [opts] nodeResolve options
* @returns {Promise<PathFromSystemRoot|null>} the resolved file system path, like '/my/project/node_modules/@lion/core/index.js'
*/
async function resolveImportPath(importee, importer, opts = {}) { async function resolveImportPath(importee, importer, opts = {}) {
const rollupResolve = nodeResolve({ const rollupResolve = nodeResolve({
rootDir: pathLib.dirname(importer), rootDir: pathLib.dirname(importer),
@ -59,7 +52,18 @@ async function resolveImportPath(importee, importer, opts = {}) {
return null; return null;
} }
// @ts-ignore // @ts-ignore
return result.id; return toPosixPath(result.id);
} }
module.exports = { resolveImportPath }; /**
* Based on importee (in a statement "import {x} from '@lion/core'", "@lion/core" is an
* importee), which can be a bare module specifier, a filename without extension, or a folder
* name without an extension.
* @param {SpecifierSource} importee source like '@lion/core' or '../helpers/index.js'
* @param {PathFromSystemRoot} importer importing file, like '/my/project/importing-file.js'
* @param {{customResolveOptions?: {preserveSymlinks:boolean}}} [opts] nodeResolve options
* @returns {Promise<PathFromSystemRoot|null>} the resolved file system path, like '/my/project/node_modules/@lion/core/index.js'
*/
const resolveImportPathMemoized = memoizeAsync(resolveImportPath);
module.exports = { resolveImportPath: resolveImportPathMemoized };

View file

@ -92,57 +92,41 @@
{ {
"name": "getterSetter", "name": "getterSetter",
"accessType": "public", "accessType": "public",
"kind": [ "kind": ["get", "set"]
"get",
"set"
]
}, },
{ {
"name": "staticGetterSetter", "name": "staticGetterSetter",
"accessType": "public", "accessType": "public",
"static": true, "static": true,
"kind": [ "kind": ["get", "set"]
"get",
"set"
]
}, },
{ {
"name": "attributes", "name": "attributes",
"accessType": "public", "accessType": "public",
"static": true, "static": true,
"kind": [ "kind": ["get"]
"get"
]
}, },
{ {
"name": "styles", "name": "styles",
"accessType": "public", "accessType": "public",
"static": true, "static": true,
"kind": [ "kind": ["get"]
"get"
]
}, },
{ {
"name": "updateComplete", "name": "updateComplete",
"accessType": "public", "accessType": "public",
"kind": [ "kind": ["get"]
"get"
]
}, },
{ {
"name": "localizeNamespaces", "name": "localizeNamespaces",
"accessType": "public", "accessType": "public",
"static": true, "static": true,
"kind": [ "kind": ["get"]
"get"
]
}, },
{ {
"name": "slots", "name": "slots",
"accessType": "public", "accessType": "public",
"kind": [ "kind": ["get"]
"get"
]
} }
], ],
"methods": [ "methods": [
@ -180,7 +164,7 @@
}, },
{ {
"name": "requestUpdate", "name": "requestUpdate",
"accessType": "protected" "accessType": "public"
}, },
{ {
"name": "createRenderRoot", "name": "createRenderRoot",

View file

@ -484,8 +484,18 @@ describe('CLI helpers', () => {
}); });
it('allows a regex filter', async () => { it('allows a regex filter', async () => {
const result = await appendProjectDependencyPaths(['/mocked/path/example-project'], '/b$/'); const result = await appendProjectDependencyPaths(
['/mocked/path/example-project'],
'/^dependency-/',
);
expect(result).to.eql([ expect(result).to.eql([
'/mocked/path/example-project/node_modules/dependency-a',
'/mocked/path/example-project/bower_components/dependency-b',
'/mocked/path/example-project',
]);
const result2 = await appendProjectDependencyPaths(['/mocked/path/example-project'], '/b$/');
expect(result2).to.eql([
'/mocked/path/example-project/bower_components/dependency-b', '/mocked/path/example-project/bower_components/dependency-b',
'/mocked/path/example-project', '/mocked/path/example-project',
]); ]);

View file

@ -441,6 +441,32 @@ describe('Analyzer "match-imports"', () => {
]); ]);
}); });
it(`correctly merges/dedupes double found exports`, async () => {
const refProject = {
path: '/target/node_modules/ref',
name: 'ref',
files: [{ file: './index.js', code: `export default function x() {};` }],
};
const targetProject = {
path: '/target',
name: 'target',
files: [
{ file: './importDefault1.js', code: `import myFn1 from 'ref/index.js';` },
{ file: './importDefault2.js', code: `import myFn2 from 'ref/index.js';` },
],
};
mockTargetAndReferenceProject(targetProject, refProject);
await providence(matchImportsQueryConfig, {
targetProjectPaths: [targetProject.path],
referenceProjectPaths: [refProject.path],
});
const queryResult = queryResults[0];
expect(queryResult.queryOutput[0].exportSpecifier.name).to.equal('[default]');
expect(queryResult.queryOutput[0].matchesPerProject).to.eql([
{ files: ['./importDefault1.js', './importDefault2.js'], project: 'target' },
]);
});
describe('Inside small example project', () => { describe('Inside small example project', () => {
it(`produces a list of all matches, sorted by project`, async () => { it(`produces a list of all matches, sorted by project`, async () => {
mockTargetAndReferenceProject(searchTargetProject, referenceProject); mockTargetAndReferenceProject(searchTargetProject, referenceProject);

View file

@ -12,15 +12,26 @@ import visit from 'unist-util-visit';
/** @typedef {Node & UrlProperty} UrlNode */ /** @typedef {Node & UrlProperty} UrlNode */
/**
* @param {string} pathStr C:\Example\path/like/this
* @returns {string} /Example/path/like/this
*/
function toPosixPath(pathStr) {
if (process.platform === 'win32') {
return pathStr.replace(/^.:/, '').replace(/\\/g, '/');
}
return pathStr;
}
/** /**
* @param {object} opts * @param {object} opts
* @param {string} opts.gitHubUrl * @param {string} opts.gitHubUrl
* @param {object} opts.page * @param {{inputPath:string}} opts.page
* @param {string} opts.page.inputPath
* @param {string} opts.rootDir * @param {string} opts.rootDir
* @returns
*/ */
export function remarkUrlToLocal({ gitHubUrl, page, rootDir }) { export function remarkUrlToLocal({ gitHubUrl, page, rootDir }) {
const inputPath = toPosixPath(page.inputPath);
/** /**
* @param {UrlNode} node * @param {UrlNode} node
*/ */
@ -34,10 +45,9 @@ export function remarkUrlToLocal({ gitHubUrl, page, rootDir }) {
urlParts.shift(); urlParts.shift();
urlParts.shift(); urlParts.shift();
const fullUrlPath = path.join(rootDir, urlParts.join('/')); const fullUrlPath = path.join(rootDir, urlParts.join('/'));
const fullInputPath = const fullInputPath = inputPath[0] === '/' ? inputPath : path.join(rootDir, inputPath);
page.inputPath[0] === '/' ? page.inputPath : path.join(rootDir, page.inputPath);
const newPath = path.relative(path.dirname(fullInputPath), fullUrlPath); const newPath = path.relative(path.dirname(fullInputPath), fullUrlPath);
node.url = newPath; node.url = toPosixPath(newPath);
} }
} }
} }