fix(providence): type fixes, windows fixes
This commit is contained in:
parent
c1d66f1e04
commit
c745761ce7
94 changed files with 3103 additions and 1233 deletions
|
|
@ -1,3 +1,3 @@
|
||||||
providence-output
|
/providence-output
|
||||||
providence-input-data
|
providence-input-data
|
||||||
/.nyc_output
|
/.nyc_output
|
||||||
|
|
|
||||||
|
|
@ -278,7 +278,7 @@ class PBoard extends DecorateMixin(LitElement) {
|
||||||
if (!this.__menuData) {
|
if (!this.__menuData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await this.__fetchResults();
|
// await this.__fetchResults();
|
||||||
|
|
||||||
const elements = Array.from(this._selectionMenuFormNode.elements);
|
const elements = Array.from(this._selectionMenuFormNode.elements);
|
||||||
const repos = elements.filter(n => n.name === 'repos');
|
const repos = elements.filter(n => n.name === 'repos');
|
||||||
|
|
@ -303,7 +303,8 @@ class PBoard extends DecorateMixin(LitElement) {
|
||||||
this.__providenceConf,
|
this.__providenceConf,
|
||||||
);
|
);
|
||||||
dataResult[i].type = specifierRes.exportSpecifier.name === '[file]' ? 'file' : 'specifier';
|
dataResult[i].type = specifierRes.exportSpecifier.name === '[file]' ? 'file' : 'specifier';
|
||||||
dataResult[i].count = specifierRes.matchesPerProject
|
// dedupe, because outputs genarted with older versions might have dedupe problems
|
||||||
|
dataResult[i].count = Array.from(new Set(specifierRes.matchesPerProject))
|
||||||
.map(mpp => mpp.files)
|
.map(mpp => mpp.files)
|
||||||
.flat(Infinity).length;
|
.flat(Infinity).length;
|
||||||
dataResult[i].matchedProjects = specifierRes.matchesPerProject;
|
dataResult[i].matchedProjects = specifierRes.matchesPerProject;
|
||||||
|
|
@ -435,7 +436,7 @@ class PBoard extends DecorateMixin(LitElement) {
|
||||||
|
|
||||||
async __fetchMenuData() {
|
async __fetchMenuData() {
|
||||||
// Derived from providence.conf.js, generated in server.mjs
|
// Derived from providence.conf.js, generated in server.mjs
|
||||||
this.__initialMenuData = await fetch('/menu-data').then(response => response.json());
|
this.__initialMenuData = await fetch('/menu-data.json').then(response => response.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
async __fetchProvidenceConf() {
|
async __fetchProvidenceConf() {
|
||||||
|
|
@ -446,7 +447,7 @@ class PBoard extends DecorateMixin(LitElement) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async __fetchResults() {
|
async __fetchResults() {
|
||||||
this.__resultFiles = await fetch('/results').then(response => response.json());
|
this.__resultFiles = await fetch('/results.json').then(response => response.json());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define('p-board', PBoard);
|
customElements.define('p-board', PBoard);
|
||||||
16
packages-node/providence-analytics/dashboard/index.html
Normal file
16
packages-node/providence-analytics/dashboard/index.html
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Providence dashboard</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 8px 32px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script type="module" src="./app/p-board.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<p-board></p-board>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import pathLib, { dirname } from 'path';
|
import pathLib, { dirname } from 'path';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import { createConfig, startServer } from 'es-dev-server';
|
import { startDevServer } from '@web/dev-server';
|
||||||
import { ReportService } from '../../src/program/services/ReportService.js';
|
import { ReportService } from '../src/program/core/ReportService.js';
|
||||||
import { getProvidenceConf } from '../../src/program/utils/get-providence-conf.mjs';
|
import { providenceConfUtil } from '../src/program/utils/providence-conf-util.mjs';
|
||||||
|
|
||||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
|
@ -66,7 +66,7 @@ function createMiddleWares({ providenceConf, providenceConfRaw, searchTargetDeps
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {object[]} collections
|
* @param {object[]} collections
|
||||||
* @returns {{[keu as string]: }}
|
* @returns {{[key as string]: }}
|
||||||
*/
|
*/
|
||||||
function transformToProjectNames(collections) {
|
function transformToProjectNames(collections) {
|
||||||
const res = {};
|
const res = {};
|
||||||
|
|
@ -74,7 +74,7 @@ function createMiddleWares({ providenceConf, providenceConfRaw, searchTargetDeps
|
||||||
Object.entries(collections).map(([key, val]) => {
|
Object.entries(collections).map(([key, val]) => {
|
||||||
res[key] = val.map(c => {
|
res[key] = val.map(c => {
|
||||||
const pkg = getPackageJson(c);
|
const pkg = getPackageJson(c);
|
||||||
return pkg && pkg.name;
|
return pkg?.name;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return res;
|
return res;
|
||||||
|
|
@ -94,9 +94,10 @@ function createMiddleWares({ providenceConf, providenceConfRaw, searchTargetDeps
|
||||||
ctx.url = `${pathFromServerRootToHere}/index.html`;
|
ctx.url = `${pathFromServerRootToHere}/index.html`;
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
if (ctx.url === '/results') {
|
if (ctx.url === '/results.json') {
|
||||||
|
ctx.type = 'application/json';
|
||||||
ctx.body = resultFiles;
|
ctx.body = resultFiles;
|
||||||
} else if (ctx.url === '/menu-data') {
|
} else if (ctx.url === '/menu-data.json') {
|
||||||
// Gathers all data that are relevant to create a configuration menu
|
// Gathers all data that are relevant to create a configuration menu
|
||||||
// at the top of the dashboard:
|
// at the top of the dashboard:
|
||||||
// - referenceCollections as defined in providence.conf.js
|
// - referenceCollections as defined in providence.conf.js
|
||||||
|
|
@ -112,16 +113,18 @@ function createMiddleWares({ providenceConf, providenceConfRaw, searchTargetDeps
|
||||||
}
|
}
|
||||||
|
|
||||||
const menuData = {
|
const menuData = {
|
||||||
// N.B. theoratically there can be a mismatch between basename and pkgJson.name,
|
// N.B. theoretically there can be a mismatch between basename and pkgJson.name,
|
||||||
// but we assume folder names and pkgJson.names to be similar
|
// but we assume folder names and pkgJson.names to be similar
|
||||||
searchTargetCollections,
|
searchTargetCollections,
|
||||||
referenceCollections: transformToProjectNames(providenceConf.referenceCollections),
|
referenceCollections: transformToProjectNames(providenceConf.referenceCollections),
|
||||||
searchTargetDeps,
|
searchTargetDeps,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ctx.type = 'application/json';
|
||||||
ctx.body = menuData;
|
ctx.body = menuData;
|
||||||
} else if (ctx.url === '/providence-conf.js') {
|
} else if (ctx.url === '/providence-conf.js') {
|
||||||
// Alloes frontend dasbboard app to find categoriesand other configs
|
// Allows frontend dasbboard app to find categories and other configs
|
||||||
ctx.type = 'text/javascript';
|
ctx.type = 'application/javascript';
|
||||||
ctx.body = providenceConfRaw;
|
ctx.body = providenceConfRaw;
|
||||||
} else {
|
} else {
|
||||||
await next();
|
await next();
|
||||||
|
|
@ -130,8 +133,8 @@ function createMiddleWares({ providenceConf, providenceConfRaw, searchTargetDeps
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
(async function main() {
|
export async function createDashboardServerConfig() {
|
||||||
const { providenceConf, providenceConfRaw } = await getProvidenceConf();
|
const { providenceConf, providenceConfRaw } = (await providenceConfUtil.getConf()) || {};
|
||||||
const { searchTargetDeps, resultFiles } = await getCachedProvidenceResults();
|
const { searchTargetDeps, resultFiles } = await getCachedProvidenceResults();
|
||||||
|
|
||||||
// Needed for dev purposes (we call it from ./packages-node/providence-analytics/ instead of ./)
|
// Needed for dev purposes (we call it from ./packages-node/providence-analytics/ instead of ./)
|
||||||
|
|
@ -139,21 +142,37 @@ function createMiddleWares({ providenceConf, providenceConfRaw, searchTargetDeps
|
||||||
const fromPackageRoot = process.argv.includes('--serve-from-package-root');
|
const fromPackageRoot = process.argv.includes('--serve-from-package-root');
|
||||||
const moduleRoot = fromPackageRoot ? pathLib.resolve(process.cwd(), '../../') : process.cwd();
|
const moduleRoot = fromPackageRoot ? pathLib.resolve(process.cwd(), '../../') : process.cwd();
|
||||||
|
|
||||||
const config = createConfig({
|
return {
|
||||||
port: 8080,
|
|
||||||
appIndex: pathLib.resolve(__dirname, 'index.html'),
|
appIndex: pathLib.resolve(__dirname, 'index.html'),
|
||||||
rootDir: moduleRoot,
|
rootDir: moduleRoot,
|
||||||
nodeResolve: true,
|
nodeResolve: true,
|
||||||
moduleDirs: pathLib.resolve(moduleRoot, 'node_modules'),
|
moduleDirs: pathLib.resolve(moduleRoot, 'node_modules'),
|
||||||
watch: false,
|
watch: false,
|
||||||
open: true,
|
open: true,
|
||||||
middlewares: createMiddleWares({
|
middleware: createMiddleWares({
|
||||||
providenceConf,
|
providenceConf,
|
||||||
providenceConfRaw,
|
providenceConfRaw,
|
||||||
searchTargetDeps,
|
searchTargetDeps,
|
||||||
resultFiles,
|
resultFiles,
|
||||||
}),
|
}),
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
|
||||||
await startServer(config);
|
let resolveLoaded;
|
||||||
|
export const serverInstanceLoaded = new Promise(resolve => {
|
||||||
|
resolveLoaded = resolve;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Export interface as object, so we can mock it easily inside tests
|
||||||
|
export const dashboardServer = {
|
||||||
|
start: async () => {
|
||||||
|
await startDevServer({ config: await createDashboardServerConfig() });
|
||||||
|
resolveLoaded();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
if (process.argv.includes('--run-server')) {
|
||||||
|
dashboardServer.start();
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<title>providence-board</title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
margin: 8px 32px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script type="module" src="./app/p-board.js"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<p-board></p-board>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
const { LogService } = require('../../src/program/services/LogService.js');
|
|
||||||
|
|
||||||
LogService.warn(
|
|
||||||
'Running via "dashboard/src/server.js" is deprecated. Please run "providence dashboard" instead.',
|
|
||||||
);
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
import('./server.mjs');
|
|
||||||
|
|
@ -26,14 +26,15 @@
|
||||||
"src"
|
"src"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dashboard": "node ./dashboard/src/server.js --serve-from-package-root",
|
"dashboard": "node ./dashboard/server.mjs --run-server --serve-from-package-root",
|
||||||
"match-lion-imports": "npm run providence analyze match-imports --search-target-collection @lion-targets --reference-collection @lion-references",
|
"postinstall": "npx patch-package",
|
||||||
|
"match-lion-imports": "npm run providence -- analyze match-subclasses --search-target-collection @lion-targets --reference-collection @lion-references --measure-perf --add-system-paths",
|
||||||
"providence": "node --max-old-space-size=8192 ./src/cli/index.mjs",
|
"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": "npm run test:node:unit && npm run test:node:e2e",
|
||||||
"test:node:e2e": "mocha './test-node/program/**/*.e2e.js' --timeout 60000",
|
"test:node:e2e": "mocha './test-node/**/*.e2e.{j,mj}s' --timeout 60000",
|
||||||
"test:node:watch": "npm run test:node --watch"
|
"test:node:unit": "mocha './test-node/**/*.test.{j,mj}s'"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.10.1",
|
"@babel/core": "^7.10.1",
|
||||||
|
|
@ -44,26 +45,25 @@
|
||||||
"@babel/register": "^7.5.5",
|
"@babel/register": "^7.5.5",
|
||||||
"@babel/traverse": "^7.23.2",
|
"@babel/traverse": "^7.23.2",
|
||||||
"@babel/types": "^7.9.0",
|
"@babel/types": "^7.9.0",
|
||||||
"@rollup/plugin-node-resolve": "^13.0.6",
|
"@rollup/plugin-node-resolve": "^15.0.0",
|
||||||
"@typescript-eslint/typescript-estree": "^3.0.0",
|
"@web/dev-server": "^0.1.28",
|
||||||
"anymatch": "^3.1.1",
|
"anymatch": "^3.1.1",
|
||||||
"chalk": "^4.1.0",
|
"chalk": "^4.1.0",
|
||||||
"commander": "^2.20.0",
|
"commander": "^2.20.0",
|
||||||
"deepmerge": "^4.0.0",
|
"deepmerge": "^4.0.0",
|
||||||
"es-dev-server": "^1.57.1",
|
|
||||||
"es-module-lexer": "^0.3.6",
|
|
||||||
"glob": "^7.1.6",
|
"glob": "^7.1.6",
|
||||||
"htm": "^3.0.3",
|
|
||||||
"inquirer": "^7.0.0",
|
"inquirer": "^7.0.0",
|
||||||
"is-negated-glob": "^1.0.0",
|
"is-negated-glob": "^1.0.0",
|
||||||
"lit-element": "~2.4.0",
|
"lit-element": "~2.4.0",
|
||||||
"mock-require": "^3.0.3",
|
|
||||||
"ora": "^3.4.0",
|
|
||||||
"parse5": "^5.1.1",
|
"parse5": "^5.1.1",
|
||||||
"read-package-tree": "5.3.1",
|
"read-package-tree": "5.3.1",
|
||||||
"semver": "^7.5.2",
|
"semver": "^7.5.2",
|
||||||
"typescript": "~4.8.4"
|
"typescript": "~4.8.4"
|
||||||
},
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@web/dev-server-core": "^0.3.19",
|
||||||
|
"mock-require": "^3.0.3"
|
||||||
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"analysis",
|
"analysis",
|
||||||
"impact",
|
"impact",
|
||||||
|
|
@ -77,5 +77,8 @@
|
||||||
],
|
],
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
},
|
||||||
|
"imports": {
|
||||||
|
"#types": "./src/program/types"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
diff --git a/node_modules/@web/dev-server-core/test-helpers.mjs b/node_modules/@web/dev-server-core/test-helpers.mjs
|
||||||
|
index 1a4d604..9c0d714 100644
|
||||||
|
--- a/node_modules/@web/dev-server-core/test-helpers.mjs
|
||||||
|
+++ b/node_modules/@web/dev-server-core/test-helpers.mjs
|
||||||
|
@@ -1,5 +1,5 @@
|
||||||
|
// this file is autogenerated with the generate-mjs-dts-entrypoints script
|
||||||
|
-import cjsEntrypoint from './dist/index.js';
|
||||||
|
+import cjsEntrypoint from './dist/test-helpers.js';
|
||||||
|
|
||||||
|
const {
|
||||||
|
virtualFilesPlugin,
|
||||||
|
|
@ -1,37 +1,4 @@
|
||||||
import pathLib, { dirname } from 'path';
|
const lionScopedPackagePaths = ['../../packages/ui'];
|
||||||
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()
|
|
||||||
// It mainly serves as an example and it allows to run the dashboard locally
|
|
||||||
// from within this repo.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {string[]}
|
|
||||||
*/
|
|
||||||
function getAllLionScopedPackagePaths() {
|
|
||||||
const rootPath = pathLib.resolve(__dirname, '../../packages');
|
|
||||||
const filesAndDirs = fs.readdirSync(rootPath);
|
|
||||||
const packages = filesAndDirs.filter(f => {
|
|
||||||
const filePath = pathLib.join(rootPath, f);
|
|
||||||
if (fs.lstatSync(filePath).isDirectory()) {
|
|
||||||
let pkgJson;
|
|
||||||
try {
|
|
||||||
pkgJson = JSON.parse(fs.readFileSync(pathLib.resolve(filePath, './package.json')));
|
|
||||||
// eslint-disable-next-line no-empty
|
|
||||||
} catch (_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return pkgJson.name && pkgJson.name.startsWith('@lion/');
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
return packages.map(p => pathLib.join(rootPath, p));
|
|
||||||
}
|
|
||||||
|
|
||||||
const lionScopedPackagePaths = getAllLionScopedPackagePaths();
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
metaConfig: {
|
metaConfig: {
|
||||||
|
|
@ -44,7 +11,9 @@ export default {
|
||||||
categories: {
|
categories: {
|
||||||
overlays: localFilePath => {
|
overlays: localFilePath => {
|
||||||
const names = ['dialog', 'tooltip'];
|
const names = ['dialog', 'tooltip'];
|
||||||
const fromPackages = names.some(p => localFilePath.startsWith(`./packages/${p}`));
|
const fromPackages = names.some(p =>
|
||||||
|
localFilePath.startsWith(`./packages/ui/components/${p}`),
|
||||||
|
);
|
||||||
const fromRoot =
|
const fromRoot =
|
||||||
names.some(p => localFilePath.startsWith(`./ui-${p}`)) ||
|
names.some(p => localFilePath.startsWith(`./ui-${p}`)) ||
|
||||||
localFilePath.startsWith('./overlays.js');
|
localFilePath.startsWith('./overlays.js');
|
||||||
|
|
@ -65,6 +34,6 @@ export default {
|
||||||
// Usually the references are different from the targets.
|
// Usually the references are different from the targets.
|
||||||
// In this demo file, we test @lion usage amongst itself
|
// In this demo file, we test @lion usage amongst itself
|
||||||
// Select via " providence analyze --reference-collection 'exampleCollection' "
|
// Select via " providence analyze --reference-collection 'exampleCollection' "
|
||||||
'@lion-references': lionScopedPackagePaths,
|
'@lion-references': ['../../packages/ui/'],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,29 @@ const pathLib = require('path');
|
||||||
const child_process = require('child_process'); // eslint-disable-line camelcase
|
const child_process = require('child_process'); // eslint-disable-line camelcase
|
||||||
const glob = require('glob');
|
const glob = require('glob');
|
||||||
const readPackageTree = require('../program/utils/read-package-tree-with-bower-support.js');
|
const readPackageTree = require('../program/utils/read-package-tree-with-bower-support.js');
|
||||||
const { InputDataService } = require('../program/services/InputDataService.js');
|
const { LogService } = require('../program/core/LogService.js');
|
||||||
const { LogService } = require('../program/services/LogService.js');
|
|
||||||
const { aForEach } = require('../program/utils/async-array-utils.js');
|
|
||||||
const { toPosixPath } = require('../program/utils/to-posix-path.js');
|
const { toPosixPath } = require('../program/utils/to-posix-path.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {any[]} arr
|
||||||
|
* @returns {any[]}
|
||||||
|
*/
|
||||||
function flatten(arr) {
|
function flatten(arr) {
|
||||||
return Array.prototype.concat.apply([], arr);
|
return Array.prototype.concat.apply([], arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} v
|
||||||
|
* @returns {string[]}
|
||||||
|
*/
|
||||||
function csToArray(v) {
|
function csToArray(v) {
|
||||||
return v.split(',').map(v => v.trim());
|
return v.split(',').map(v => v.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} v like 'js,html'
|
||||||
|
* @returns {string[]} like ['.js', '.html']
|
||||||
|
*/
|
||||||
function extensionsFromCs(v) {
|
function extensionsFromCs(v) {
|
||||||
return csToArray(v).map(v => `.${v}`);
|
return csToArray(v).map(v => `.${v}`);
|
||||||
}
|
}
|
||||||
|
|
@ -25,13 +35,13 @@ function setQueryMethod(m) {
|
||||||
if (allowedMehods.includes(m)) {
|
if (allowedMehods.includes(m)) {
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
LogService.error(`Please provide one of the following methods: ${allowedMehods.join(', ')}`);
|
LogService.error(`Please provide one of the following methods: ${allowedMehods.join(', ')}`);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {string[]}
|
* @param {string} t
|
||||||
|
* @returns {string[]|undefined}
|
||||||
*/
|
*/
|
||||||
function pathsArrayFromCs(t, cwd = process.cwd()) {
|
function pathsArrayFromCs(t, cwd = process.cwd()) {
|
||||||
if (!t) {
|
if (!t) {
|
||||||
|
|
@ -57,27 +67,40 @@ function pathsArrayFromCs(t, cwd = process.cwd()) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name collection name found in eCfg
|
* @param {string} name collection name found in eCfg
|
||||||
* @param {'search-target'|'reference'} [colType='search-targets'] collection type
|
* @param {'search-target'|'reference'} collectionType collection type
|
||||||
* @param {object} eCfg external configuration. Usually providence.conf.js
|
* @param {{searchTargetCollections: {[repo:string]:string[]}; referenceCollections:{[repo:string]:string[]}}} [eCfg] external configuration. Usually providence.conf.js
|
||||||
* @returns {string[]}
|
* @param {string} [cwd]
|
||||||
|
* @returns {string[]|undefined}
|
||||||
*/
|
*/
|
||||||
function pathsArrayFromCollectionName(name, colType = 'search-target', eCfg, cwd) {
|
function pathsArrayFromCollectionName(
|
||||||
|
name,
|
||||||
|
collectionType = 'search-target',
|
||||||
|
eCfg,
|
||||||
|
cwd = process.cwd(),
|
||||||
|
) {
|
||||||
let collection;
|
let collection;
|
||||||
if (colType === 'search-target') {
|
if (collectionType === 'search-target') {
|
||||||
collection = eCfg.searchTargetCollections;
|
collection = eCfg?.searchTargetCollections;
|
||||||
} else if (colType === 'reference') {
|
} else if (collectionType === 'reference') {
|
||||||
collection = eCfg.referenceCollections;
|
collection = eCfg?.referenceCollections;
|
||||||
}
|
}
|
||||||
if (collection && collection[name]) {
|
if (collection?.[name]) {
|
||||||
return pathsArrayFromCs(collection[name].join(','), cwd);
|
return pathsArrayFromCs(collection[name].join(','), cwd);
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} processArgStr
|
||||||
|
* @param {object} [opts]
|
||||||
|
* @returns {Promise<{ code:string; number:string }>}
|
||||||
|
* @throws {Error}
|
||||||
|
*/
|
||||||
function spawnProcess(processArgStr, opts) {
|
function spawnProcess(processArgStr, opts) {
|
||||||
const processArgs = processArgStr.split(' ');
|
const processArgs = processArgStr.split(' ');
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
const proc = child_process.spawn(processArgs[0], processArgs.slice(1), opts);
|
const proc = child_process.spawn(processArgs[0], processArgs.slice(1), opts);
|
||||||
|
/** @type {string} */
|
||||||
let output;
|
let output;
|
||||||
proc.stdout.on('data', data => {
|
proc.stdout.on('data', data => {
|
||||||
output += data;
|
output += data;
|
||||||
|
|
@ -95,28 +118,26 @@ function spawnProcess(processArgStr, opts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* When providence is called from the root of a repo and no target is provided,
|
||||||
|
* this will provide the default fallback (the project itself)
|
||||||
|
* @param {string} cwd
|
||||||
* @returns {string[]}
|
* @returns {string[]}
|
||||||
*/
|
*/
|
||||||
function targetDefault() {
|
function targetDefault(cwd) {
|
||||||
// eslint-disable-next-line import/no-dynamic-require, global-require
|
return [toPosixPath(cwd)];
|
||||||
const { name } = require(`${process.cwd()}/package.json`);
|
|
||||||
if (name === 'providence') {
|
|
||||||
return InputDataService.targetProjectPaths;
|
|
||||||
}
|
|
||||||
return [toPosixPath(process.cwd())];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Returns all sub projects matching condition supplied in matchFn
|
* Returns all sub projects matching condition supplied in matchFn
|
||||||
* @param {string[]} searchTargetPaths all search-target project paths
|
* @param {string[]} rootPaths all search-target project paths
|
||||||
* @param {string} matchPattern base for RegExp
|
* @param {string} [matchPattern] base for RegExp
|
||||||
* @param {string[]} modes
|
* @param {('npm'|'bower')[]} [modes]
|
||||||
*/
|
*/
|
||||||
async function appendProjectDependencyPaths(rootPaths, matchPattern, modes = ['npm', 'bower']) {
|
async function appendProjectDependencyPaths(rootPaths, matchPattern, modes = ['npm', 'bower']) {
|
||||||
let matchFn;
|
let matchFn;
|
||||||
if (matchPattern) {
|
if (matchPattern) {
|
||||||
if (matchPattern.startsWith('/') && matchPattern.endsWith('/')) {
|
if (matchPattern.startsWith('/') && matchPattern.endsWith('/')) {
|
||||||
matchFn = (_, d) => {
|
matchFn = (/** @type {any} */ _, /** @type {string} */ d) => {
|
||||||
const reString = matchPattern.slice(1, -1);
|
const reString = matchPattern.slice(1, -1);
|
||||||
const result = new RegExp(reString).test(d);
|
const result = new RegExp(reString).test(d);
|
||||||
LogService.debug(`[appendProjectDependencyPaths]: /${reString}/.test(${d} => ${result})`);
|
LogService.debug(`[appendProjectDependencyPaths]: /${reString}/.test(${d} => ${result})`);
|
||||||
|
|
@ -128,13 +149,14 @@ async function appendProjectDependencyPaths(rootPaths, matchPattern, modes = ['n
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/** @type {string[]} */
|
||||||
const depProjectPaths = [];
|
const depProjectPaths = [];
|
||||||
await aForEach(rootPaths, async targetPath => {
|
for (const targetPath of rootPaths) {
|
||||||
await aForEach(modes, async mode => {
|
for (const mode of modes) {
|
||||||
await readPackageTree(
|
await readPackageTree(
|
||||||
targetPath,
|
targetPath,
|
||||||
matchFn,
|
matchFn,
|
||||||
(err, tree) => {
|
(/** @type {string | undefined} */ err, /** @type {{ children: any[]; }} */ tree) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw new Error(err);
|
throw new Error(err);
|
||||||
}
|
}
|
||||||
|
|
@ -143,8 +165,8 @@ async function appendProjectDependencyPaths(rootPaths, matchPattern, modes = ['n
|
||||||
},
|
},
|
||||||
mode,
|
mode,
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
// Write all data to {outputPath}/projectDeps.json
|
// Write all data to {outputPath}/projectDeps.json
|
||||||
// const projectDeps = {};
|
// const projectDeps = {};
|
||||||
// rootPaths.forEach(rootP => {
|
// rootPaths.forEach(rootP => {
|
||||||
|
|
@ -154,25 +176,27 @@ async function appendProjectDependencyPaths(rootPaths, matchPattern, modes = ['n
|
||||||
return depProjectPaths.concat(rootPaths).map(toPosixPath);
|
return depProjectPaths.concat(rootPaths).map(toPosixPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will install all npm and bower deps, so an analysis can be performed on them as well.
|
||||||
|
* Relevant when '--target-dependencies' is supplied.
|
||||||
|
* @param {string[]} searchTargetPaths
|
||||||
|
*/
|
||||||
async function installDeps(searchTargetPaths) {
|
async function installDeps(searchTargetPaths) {
|
||||||
return aForEach(searchTargetPaths, async t => {
|
for (const targetPath of searchTargetPaths) {
|
||||||
const spawnConfig = { cwd: t };
|
LogService.info(`Installing npm dependencies for ${pathLib.basename(targetPath)}`);
|
||||||
const extraOptions = { log: true };
|
|
||||||
|
|
||||||
LogService.info(`Installing npm dependencies for ${pathLib.basename(t)}`);
|
|
||||||
try {
|
try {
|
||||||
await spawnProcess('npm i --no-progress', spawnConfig, extraOptions);
|
await spawnProcess('npm i --no-progress', { cwd: targetPath });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
LogService.error(e);
|
LogService.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogService.info(`Installing bower dependencies for ${pathLib.basename(t)}`);
|
LogService.info(`Installing bower dependencies for ${pathLib.basename(targetPath)}`);
|
||||||
try {
|
try {
|
||||||
await spawnProcess(`bower i --production --force-latest`, spawnConfig, extraOptions);
|
await spawnProcess(`bower i --production --force-latest`, { cwd: targetPath });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
LogService.error(e);
|
LogService.error(e);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,30 @@
|
||||||
const child_process = require('child_process'); // eslint-disable-line camelcase
|
import child_process from 'child_process'; // eslint-disable-line camelcase
|
||||||
const pathLib = require('path');
|
import pathLib from 'path';
|
||||||
const commander = require('commander');
|
import fs from 'fs';
|
||||||
const providenceModule = require('../program/providence.js');
|
import commander from 'commander';
|
||||||
const { LogService } = require('../program/services/LogService.js');
|
import providenceModule from '../program/providence.js';
|
||||||
const { QueryService } = require('../program/services/QueryService.js');
|
import { LogService } from '../program/core/LogService.js';
|
||||||
const { InputDataService } = require('../program/services/InputDataService.js');
|
import { QueryService } from '../program/core/QueryService.js';
|
||||||
const promptModule = require('./prompt-analyzer-menu.js');
|
import { InputDataService } from '../program/core/InputDataService.js';
|
||||||
const cliHelpers = require('./cli-helpers.js');
|
import promptModule from './prompt-analyzer-menu.js';
|
||||||
const extendDocsModule = require('./launch-providence-with-extend-docs.js');
|
import cliHelpers from './cli-helpers.js';
|
||||||
const { toPosixPath } = require('../program/utils/to-posix-path.js');
|
import extendDocsModule from './launch-providence-with-extend-docs.js';
|
||||||
|
import { toPosixPath } from '../program/utils/to-posix-path.js';
|
||||||
|
import { getCurrentDir } from '../program/utils/get-current-dir.mjs';
|
||||||
|
import { dashboardServer } from '../../dashboard/server.mjs';
|
||||||
|
|
||||||
const { extensionsFromCs, setQueryMethod, targetDefault, installDeps, spawnProcess } = cliHelpers;
|
const { version } = JSON.parse(
|
||||||
|
fs.readFileSync(pathLib.resolve(getCurrentDir(import.meta.url), '../../package.json'), 'utf8'),
|
||||||
|
);
|
||||||
|
const { extensionsFromCs, setQueryMethod, targetDefault, installDeps } = cliHelpers;
|
||||||
|
|
||||||
const { version } = require('../../package.json');
|
/**
|
||||||
|
* @param {{cwd?:string; argv: string[]; providenceConf?: object}} cfg
|
||||||
async function cli({ cwd, providenceConf } = {}) {
|
*/
|
||||||
|
export async function cli({ cwd = process.cwd(), providenceConf, argv = process.argv }) {
|
||||||
|
/** @type {(value: any) => void} */
|
||||||
let resolveCli;
|
let resolveCli;
|
||||||
|
/** @type {(reason?: any) => void} */
|
||||||
let rejectCli;
|
let rejectCli;
|
||||||
|
|
||||||
const cliPromise = new Promise((resolve, reject) => {
|
const cliPromise = new Promise((resolve, reject) => {
|
||||||
|
|
@ -35,7 +44,7 @@ async function cli({ cwd, providenceConf } = {}) {
|
||||||
// TODO: change back to "InputDataService.getExternalConfig();" once full package ESM
|
// TODO: change back to "InputDataService.getExternalConfig();" once full package ESM
|
||||||
const externalConfig = providenceConf;
|
const externalConfig = providenceConf;
|
||||||
|
|
||||||
async function getQueryInputData(
|
async function getQueryConfigAndMeta(
|
||||||
/* eslint-disable no-shadow */
|
/* eslint-disable no-shadow */
|
||||||
searchMode,
|
searchMode,
|
||||||
regexSearchOptions,
|
regexSearchOptions,
|
||||||
|
|
@ -80,7 +89,7 @@ async function cli({ cwd, providenceConf } = {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function launchProvidence() {
|
async function launchProvidence() {
|
||||||
const { queryConfig, queryMethod } = await getQueryInputData(
|
const { queryConfig, queryMethod } = await getQueryConfigAndMeta(
|
||||||
searchMode,
|
searchMode,
|
||||||
regexSearchOptions,
|
regexSearchOptions,
|
||||||
featureOptions,
|
featureOptions,
|
||||||
|
|
@ -130,6 +139,8 @@ async function cli({ cwd, providenceConf } = {}) {
|
||||||
targetProjectRootPaths: searchTargetPaths,
|
targetProjectRootPaths: searchTargetPaths,
|
||||||
writeLogFile: commander.writeLogFile,
|
writeLogFile: commander.writeLogFile,
|
||||||
skipCheckMatchCompatibility: commander.skipCheckMatchCompatibility,
|
skipCheckMatchCompatibility: commander.skipCheckMatchCompatibility,
|
||||||
|
measurePerformance: commander.measurePerf,
|
||||||
|
addSystemPathsInResult: commander.addSystemPaths,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,15 +164,6 @@ async function cli({ cwd, providenceConf } = {}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runDashboard() {
|
|
||||||
const pathFromServerRootToDashboard = `${pathLib.relative(
|
|
||||||
process.cwd(),
|
|
||||||
pathLib.resolve(__dirname, '../../dashboard'),
|
|
||||||
)}`;
|
|
||||||
|
|
||||||
spawnProcess(`node ${pathFromServerRootToDashboard}/src/server.mjs`);
|
|
||||||
}
|
|
||||||
|
|
||||||
commander
|
commander
|
||||||
.version(version, '-v, --version')
|
.version(version, '-v, --version')
|
||||||
.option('-e, --extensions [extensions]', 'extensions like "js,html"', extensionsFromCs, [
|
.option('-e, --extensions [extensions]', 'extensions like "js,html"', extensionsFromCs, [
|
||||||
|
|
@ -174,7 +176,7 @@ async function cli({ cwd, providenceConf } = {}) {
|
||||||
`path(s) to project(s) on which analysis/querying should take place. Requires
|
`path(s) to project(s) on which analysis/querying should take place. Requires
|
||||||
a list of comma seperated values relative to project root`,
|
a list of comma seperated values relative to project root`,
|
||||||
v => cliHelpers.pathsArrayFromCs(v, cwd),
|
v => cliHelpers.pathsArrayFromCs(v, cwd),
|
||||||
targetDefault(),
|
targetDefault(cwd),
|
||||||
)
|
)
|
||||||
.option(
|
.option(
|
||||||
'-r, --reference-paths [references]',
|
'-r, --reference-paths [references]',
|
||||||
|
|
@ -185,12 +187,12 @@ async function cli({ cwd, providenceConf } = {}) {
|
||||||
InputDataService.referenceProjectPaths,
|
InputDataService.referenceProjectPaths,
|
||||||
)
|
)
|
||||||
.option('-a, --allowlist [allowlist]', `allowlisted paths, like 'src/**/*, packages/**/*'`, v =>
|
.option('-a, --allowlist [allowlist]', `allowlisted paths, like 'src/**/*, packages/**/*'`, v =>
|
||||||
cliHelpers.csToArray(v, cwd),
|
cliHelpers.csToArray(v),
|
||||||
)
|
)
|
||||||
.option(
|
.option(
|
||||||
'--allowlist-reference [allowlist-reference]',
|
'--allowlist-reference [allowlist-reference]',
|
||||||
`allowed paths for reference, like 'src/**/*, packages/**/*'`,
|
`allowed paths for reference, like 'src/**/*, packages/**/*'`,
|
||||||
v => cliHelpers.csToArray(v, cwd),
|
v => cliHelpers.csToArray(v),
|
||||||
)
|
)
|
||||||
.option(
|
.option(
|
||||||
'--search-target-collection [collection-name]',
|
'--search-target-collection [collection-name]',
|
||||||
|
|
@ -232,7 +234,9 @@ async function cli({ cwd, providenceConf } = {}) {
|
||||||
.option(
|
.option(
|
||||||
'--skip-check-match-compatibility',
|
'--skip-check-match-compatibility',
|
||||||
`skips semver checks, handy for forward compatible libs or libs below v1`,
|
`skips semver checks, handy for forward compatible libs or libs below v1`,
|
||||||
);
|
)
|
||||||
|
.option('--measure-perf', 'Logs the completion time in seconds')
|
||||||
|
.option('--add-system-paths', 'Adds system paths to results');
|
||||||
|
|
||||||
commander
|
commander
|
||||||
.command('search <regex>')
|
.command('search <regex>')
|
||||||
|
|
@ -346,12 +350,10 @@ async function cli({ cwd, providenceConf } = {}) {
|
||||||
via providence.conf`,
|
via providence.conf`,
|
||||||
)
|
)
|
||||||
.action(() => {
|
.action(() => {
|
||||||
runDashboard();
|
dashboardServer.start();
|
||||||
});
|
});
|
||||||
|
|
||||||
commander.parse(process.argv);
|
commander.parse(argv);
|
||||||
|
|
||||||
await cliPromise;
|
await cliPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { cli };
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
import { cli } from './cli.js';
|
import { cli } from './cli.mjs';
|
||||||
import { getProvidenceConf } from '../program/utils/get-providence-conf.mjs';
|
import { providenceConfUtil } from '../program/utils/providence-conf-util.mjs';
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
// We need to provide config to cli, until whole package is rewritten as ESM.
|
// We need to provide config to cli, until whole package is rewritten as ESM.
|
||||||
const { providenceConf } = (await getProvidenceConf()) || {};
|
const { providenceConf } = (await providenceConfUtil.getConf()) || {};
|
||||||
cli({ providenceConf });
|
cli({ providenceConf });
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,27 @@ const fs = require('fs');
|
||||||
const pathLib = require('path');
|
const pathLib = require('path');
|
||||||
const { performance } = require('perf_hooks');
|
const { performance } = require('perf_hooks');
|
||||||
const providenceModule = require('../program/providence.js');
|
const providenceModule = require('../program/providence.js');
|
||||||
const { QueryService } = require('../program/services/QueryService.js');
|
const { QueryService } = require('../program/core/QueryService.js');
|
||||||
const { InputDataService } = require('../program/services/InputDataService.js');
|
const { InputDataService } = require('../program/core/InputDataService.js');
|
||||||
const { LogService } = require('../program/services/LogService.js');
|
const { LogService } = require('../program/core/LogService.js');
|
||||||
const { flatten } = require('./cli-helpers.js');
|
const { flatten } = require('./cli-helpers.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../program/types').PathFromSystemRoot} PathFromSystemRoot
|
||||||
|
* @typedef {import('../program/types').GatherFilesConfig} GatherFilesConfig
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{
|
||||||
|
* referenceProjectPaths: PathFromSystemRoot[];
|
||||||
|
* prefixCfg:{from:string;to:string};
|
||||||
|
* extensions:GatherFilesConfig['extensions'];
|
||||||
|
* allowlist?:string[];
|
||||||
|
* allowlistReference?:string[];
|
||||||
|
* cwd:PathFromSystemRoot
|
||||||
|
* }} opts
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
async function getExtendDocsResults({
|
async function getExtendDocsResults({
|
||||||
referenceProjectPaths,
|
referenceProjectPaths,
|
||||||
prefixCfg,
|
prefixCfg,
|
||||||
|
|
@ -22,7 +38,7 @@ async function getExtendDocsResults({
|
||||||
QueryService.getQueryConfigFromAnalyzer('match-paths', { prefix: prefixCfg }),
|
QueryService.getQueryConfigFromAnalyzer('match-paths', { prefix: prefixCfg }),
|
||||||
{
|
{
|
||||||
gatherFilesConfig: {
|
gatherFilesConfig: {
|
||||||
extensions: extensions || ['.js'],
|
extensions: extensions || /** @type {GatherFilesConfig['extensions']} */ (['.js']),
|
||||||
allowlist: allowlist || ['!coverage', '!test'],
|
allowlist: allowlist || ['!coverage', '!test'],
|
||||||
},
|
},
|
||||||
gatherFilesConfigReference: {
|
gatherFilesConfigReference: {
|
||||||
|
|
@ -31,7 +47,7 @@ async function getExtendDocsResults({
|
||||||
},
|
},
|
||||||
queryMethod: 'ast',
|
queryMethod: 'ast',
|
||||||
report: false,
|
report: false,
|
||||||
targetProjectPaths: [pathLib.resolve(cwd)],
|
targetProjectPaths: [cwd],
|
||||||
referenceProjectPaths,
|
referenceProjectPaths,
|
||||||
// For mono repos, a match between root package.json and ref project will not exist.
|
// For mono repos, a match between root package.json and ref project will not exist.
|
||||||
// Disable this check, so it won't be a blocker for extendin docs
|
// Disable this check, so it won't be a blocker for extendin docs
|
||||||
|
|
@ -45,7 +61,7 @@ async function getExtendDocsResults({
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} pathStr ./packages/lea-tabs/lea-tabs.js
|
* @param {string} pathStr ./packages/lea-tabs/lea-tabs.js
|
||||||
* @param {string[]} pkgs ['packages/lea-tabs', ...]
|
* @param {{path:string;name:string}[]} pkgs ['packages/lea-tabs', ...]
|
||||||
*/
|
*/
|
||||||
function replaceToMonoRepoPath(pathStr, pkgs) {
|
function replaceToMonoRepoPath(pathStr, pkgs) {
|
||||||
let result = pathStr;
|
let result = pathStr;
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ const fs = require('fs');
|
||||||
const pathLib = require('path');
|
const pathLib = require('path');
|
||||||
const inquirer = require('inquirer');
|
const inquirer = require('inquirer');
|
||||||
const { default: traverse } = require('@babel/traverse');
|
const { default: traverse } = require('@babel/traverse');
|
||||||
const { InputDataService } = require('../program/services/InputDataService.js');
|
const { InputDataService } = require('../program/core/InputDataService.js');
|
||||||
const { AstService } = require('../program/services/AstService.js');
|
const { AstService } = require('../program/core/AstService.js');
|
||||||
const { LogService } = require('../program/services/LogService.js');
|
const { LogService } = require('../program/core/LogService.js');
|
||||||
const JsdocCommentParser = require('../program/utils/jsdoc-comment-parser.js');
|
const JsdocCommentParser = require('../program/utils/jsdoc-comment-parser.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
const { providence } = require('./program/providence.js');
|
const { providence } = require('./program/providence.js');
|
||||||
const { QueryService } = require('./program/services/QueryService.js');
|
const { QueryService } = require('./program/core/QueryService.js');
|
||||||
const { LogService } = require('./program/services/LogService.js');
|
const { LogService } = require('./program/core/LogService.js');
|
||||||
const { InputDataService } = require('./program/services/InputDataService.js');
|
const { InputDataService } = require('./program/core/InputDataService.js');
|
||||||
const { AstService } = require('./program/services/AstService.js');
|
const { AstService } = require('./program/core/AstService.js');
|
||||||
|
|
||||||
module.exports = { providence, QueryService, LogService, InputDataService, AstService };
|
module.exports = { providence, QueryService, LogService, InputDataService, AstService };
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,21 @@
|
||||||
const pathLib = require('path');
|
const pathLib = require('path');
|
||||||
const t = require('@babel/types');
|
const t = require('@babel/types');
|
||||||
const { default: traverse } = require('@babel/traverse');
|
const { default: traverse } = require('@babel/traverse');
|
||||||
const { Analyzer } = require('./helpers/Analyzer.js');
|
const { Analyzer } = require('../core/Analyzer.js');
|
||||||
const { trackDownIdentifierFromScope } = require('./helpers/track-down-identifier.js');
|
const { trackDownIdentifierFromScope } = require('./helpers/track-down-identifier.js');
|
||||||
const { aForEach } = require('../utils/async-array-utils.js');
|
|
||||||
|
|
||||||
/** @typedef {import('../types/analyzers').FindClassesAnalyzerOutput} FindClassesAnalyzerOutput */
|
/**
|
||||||
/** @typedef {import('../types/analyzers').FindClassesAnalyzerOutputEntry} FindClassesAnalyzerOutputEntry */
|
* @typedef {import('@babel/types').File} File
|
||||||
/** @typedef {import('../types/analyzers').FindClassesConfig} FindClassesConfig */
|
* @typedef {import('@babel/types').ClassMethod} ClassMethod
|
||||||
|
* @typedef {import('../types/analyzers').FindClassesAnalyzerOutput} FindClassesAnalyzerOutput
|
||||||
|
* @typedef {import('../types/analyzers').FindClassesAnalyzerOutputEntry} FindClassesAnalyzerOutputEntry
|
||||||
|
* @typedef {import('../types/analyzers').FindClassesConfig} FindClassesConfig
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds import specifiers and sources
|
* Finds import specifiers and sources
|
||||||
* @param {BabelAst} ast
|
* @param {File} ast
|
||||||
* @param {string} relativePath the file being currently processed
|
* @param {string} fullCurrentFilePath the file being currently processed
|
||||||
*/
|
*/
|
||||||
async function findMembersPerAstEntry(ast, fullCurrentFilePath, projectPath) {
|
async function findMembersPerAstEntry(ast, fullCurrentFilePath, projectPath) {
|
||||||
// The transformed entry
|
// The transformed entry
|
||||||
|
|
@ -34,6 +37,10 @@ async function findMembersPerAstEntry(ast, fullCurrentFilePath, projectPath) {
|
||||||
return 'public';
|
return 'public';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{node:ClassMethod}} cfg
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
function isStaticProperties({ node }) {
|
function isStaticProperties({ node }) {
|
||||||
return node.static && node.kind === 'get' && node.key.name === 'properties';
|
return node.static && node.kind === 'get' && node.key.name === 'properties';
|
||||||
}
|
}
|
||||||
|
|
@ -73,7 +80,12 @@ async function findMembersPerAstEntry(ast, fullCurrentFilePath, projectPath) {
|
||||||
// return false;
|
// return false;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
async function traverseClass(path, { isMixin } = {}) {
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} path
|
||||||
|
* @param {{isMixin?:boolean}} param1
|
||||||
|
*/
|
||||||
|
async function traverseClass(path, { isMixin = false } = {}) {
|
||||||
const classRes = {};
|
const classRes = {};
|
||||||
classRes.name = path.node.id && path.node.id.name;
|
classRes.name = path.node.id && path.node.id.name;
|
||||||
classRes.isMixin = Boolean(isMixin);
|
classRes.isMixin = Boolean(isMixin);
|
||||||
|
|
@ -95,7 +107,8 @@ async function findMembersPerAstEntry(ast, fullCurrentFilePath, projectPath) {
|
||||||
// or an external path like '@lion/overlays'. In the latter case,
|
// or an external path like '@lion/overlays'. In the latter case,
|
||||||
// tracking down will halt and should be done when there is access to
|
// tracking down will halt and should be done when there is access to
|
||||||
// the external repo... (similar to how 'match-imports' analyzer works)
|
// the external repo... (similar to how 'match-imports' analyzer works)
|
||||||
await aForEach(superClasses, async classObj => {
|
|
||||||
|
for (const classObj of superClasses) {
|
||||||
// Finds the file that holds the declaration of the import
|
// Finds the file that holds the declaration of the import
|
||||||
classObj.rootFile = await trackDownIdentifierFromScope(
|
classObj.rootFile = await trackDownIdentifierFromScope(
|
||||||
path,
|
path,
|
||||||
|
|
@ -103,13 +116,17 @@ async function findMembersPerAstEntry(ast, fullCurrentFilePath, projectPath) {
|
||||||
fullCurrentFilePath,
|
fullCurrentFilePath,
|
||||||
projectPath,
|
projectPath,
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
classRes.superClasses = superClasses;
|
classRes.superClasses = superClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
classRes.members = {};
|
classRes.members = {
|
||||||
classRes.members.props = []; // meta: private, public, getter/setter, (found in static get properties)
|
// meta: private, public, getter/setter, (found in static get properties)
|
||||||
classRes.members.methods = []; // meta: private, public, getter/setter
|
props: [],
|
||||||
|
// meta: private, public, getter/setter
|
||||||
|
methods: [],
|
||||||
|
};
|
||||||
|
|
||||||
path.traverse({
|
path.traverse({
|
||||||
ClassMethod(path) {
|
ClassMethod(path) {
|
||||||
// if (isBlacklisted(path)) {
|
// if (isBlacklisted(path)) {
|
||||||
|
|
@ -174,9 +191,9 @@ async function findMembersPerAstEntry(ast, fullCurrentFilePath, projectPath) {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await aForEach(classesToTraverse, async klass => {
|
for (const klass of classesToTraverse) {
|
||||||
await traverseClass(klass.path, { isMixin: klass.isMixin });
|
await traverseClass(klass.path, { isMixin: klass.isMixin });
|
||||||
});
|
}
|
||||||
|
|
||||||
return classesFound;
|
return classesFound;
|
||||||
}
|
}
|
||||||
|
|
@ -202,9 +219,8 @@ async function findMembersPerAstEntry(ast, fullCurrentFilePath, projectPath) {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
class FindClassesAnalyzer extends Analyzer {
|
class FindClassesAnalyzer extends Analyzer {
|
||||||
constructor() {
|
static get analyzerName() {
|
||||||
super();
|
return 'find-classes';
|
||||||
this.name = 'find-classes';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
const pathLib = require('path');
|
const pathLib = require('path');
|
||||||
const t = require('@babel/types');
|
const t = require('@babel/types');
|
||||||
const { default: traverse } = require('@babel/traverse');
|
const { default: traverse } = require('@babel/traverse');
|
||||||
const { Analyzer } = require('./helpers/Analyzer.js');
|
const { Analyzer } = require('../core/Analyzer.js');
|
||||||
const { trackDownIdentifierFromScope } = require('./helpers/track-down-identifier.js');
|
const { trackDownIdentifierFromScope } = require('./helpers/track-down-identifier.js');
|
||||||
const { aForEach } = require('../utils/async-array-utils.js');
|
|
||||||
|
|
||||||
function cleanup(transformedEntry) {
|
function cleanup(transformedEntry) {
|
||||||
transformedEntry.forEach(definitionObj => {
|
transformedEntry.forEach(definitionObj => {
|
||||||
|
|
@ -18,7 +17,7 @@ function cleanup(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 definitionObj => {
|
for (const definitionObj of transformedEntry) {
|
||||||
const rootFile = await trackDownIdentifierFromScope(
|
const rootFile = await trackDownIdentifierFromScope(
|
||||||
definitionObj.__tmp.path,
|
definitionObj.__tmp.path,
|
||||||
definitionObj.constructorIdentifier,
|
definitionObj.constructorIdentifier,
|
||||||
|
|
@ -27,7 +26,7 @@ async function trackdownRoot(transformedEntry, relativePath, projectPath) {
|
||||||
);
|
);
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
definitionObj.rootFile = rootFile;
|
definitionObj.rootFile = rootFile;
|
||||||
});
|
}
|
||||||
return transformedEntry;
|
return transformedEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,13 +84,12 @@ function findCustomElementsPerAstEntry(ast) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class FindCustomelementsAnalyzer extends Analyzer {
|
class FindCustomelementsAnalyzer extends Analyzer {
|
||||||
constructor() {
|
static get analyzerName() {
|
||||||
super();
|
return 'find-customelements';
|
||||||
this.name = 'find-customelements';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Finds export specifiers and sources
|
* Finds export specifiers and sources
|
||||||
* @param {FindCustomelementsConfig} customConfig
|
* @param {FindCustomelementsConfig} customConfig
|
||||||
*/
|
*/
|
||||||
async execute(customConfig = {}) {
|
async execute(customConfig = {}) {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
/* eslint-disable no-shadow, no-param-reassign */
|
/* eslint-disable no-shadow, no-param-reassign */
|
||||||
const pathLib = require('path');
|
const pathLib = require('path');
|
||||||
const { default: traverse } = require('@babel/traverse');
|
const { default: traverse } = require('@babel/traverse');
|
||||||
const { Analyzer } = require('./helpers/Analyzer.js');
|
const { Analyzer } = require('../core/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 { getReferencedDeclaration } = require('../utils/get-source-code-fragment-of-declaration.js');
|
const { getReferencedDeclaration } = require('../utils/get-source-code-fragment-of-declaration.js');
|
||||||
|
|
||||||
const { LogService } = require('../services/LogService.js');
|
const { LogService } = require('../core/LogService.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('./helpers/track-down-identifier.js').RootFile} RootFile
|
* @typedef {import('./helpers/track-down-identifier.js').RootFile} RootFile
|
||||||
|
|
@ -141,8 +141,8 @@ const isImportingSpecifier = pathOrNode =>
|
||||||
pathOrNode.type === 'ImportDefaultSpecifier' || pathOrNode.type === 'ImportSpecifier';
|
pathOrNode.type === 'ImportDefaultSpecifier' || pathOrNode.type === 'ImportSpecifier';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Finds import specifiers and sources for a given ast result
|
* Finds import specifiers and sources for a given ast result
|
||||||
* @param {BabelAst} ast
|
* @param {File} ast
|
||||||
* @param {FindExportsConfig} config
|
* @param {FindExportsConfig} config
|
||||||
*/
|
*/
|
||||||
function findExportsPerAstEntry(ast, { skipFileImports }) {
|
function findExportsPerAstEntry(ast, { skipFileImports }) {
|
||||||
|
|
@ -207,13 +207,12 @@ function findExportsPerAstEntry(ast, { skipFileImports }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class FindExportsAnalyzer extends Analyzer {
|
class FindExportsAnalyzer extends Analyzer {
|
||||||
constructor() {
|
static get analyzerName() {
|
||||||
super();
|
return 'find-exports';
|
||||||
this.name = 'find-exports';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Finds export specifiers and sources
|
* Finds export specifiers and sources
|
||||||
* @param {FindExportsConfig} customConfig
|
* @param {FindExportsConfig} customConfig
|
||||||
*/
|
*/
|
||||||
async execute(customConfig = {}) {
|
async execute(customConfig = {}) {
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,12 @@
|
||||||
const { default: traverse } = require('@babel/traverse');
|
const { default: traverse } = require('@babel/traverse');
|
||||||
const { isRelativeSourcePath } = require('../utils/relative-source-path.js');
|
const { isRelativeSourcePath } = require('../utils/relative-source-path.js');
|
||||||
const { normalizeSourcePaths } = require('./helpers/normalize-source-paths.js');
|
const { normalizeSourcePaths } = require('./helpers/normalize-source-paths.js');
|
||||||
const { Analyzer } = require('./helpers/Analyzer.js');
|
const { Analyzer } = require('../core/Analyzer.js');
|
||||||
const { LogService } = require('../services/LogService.js');
|
const { LogService } = require('../core/LogService.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @typedef {import('@babel/types').File} File
|
||||||
|
* @typedef {import('@babel/types').Node} Node *
|
||||||
* @typedef {import('../types/core').AnalyzerName} AnalyzerName
|
* @typedef {import('../types/core').AnalyzerName} AnalyzerName
|
||||||
* @typedef {import('../types/analyzers').FindImportsAnalyzerResult} FindImportsAnalyzerResult
|
* @typedef {import('../types/analyzers').FindImportsAnalyzerResult} FindImportsAnalyzerResult
|
||||||
* @typedef {import('../types/analyzers').FindImportsAnalyzerEntry} FindImportsAnalyzerEntry
|
* @typedef {import('../types/analyzers').FindImportsAnalyzerEntry} FindImportsAnalyzerEntry
|
||||||
|
|
@ -16,12 +18,12 @@ const { LogService } = require('../services/LogService.js');
|
||||||
* Options that allow to filter 'on a file basis'.
|
* Options that allow to filter 'on a file basis'.
|
||||||
* We can also filter on the total result
|
* We can also filter on the total result
|
||||||
*/
|
*/
|
||||||
const /** @type {AnalyzerOptions} */ options = {
|
const /** @type {AnalyzerConfig} */ options = {
|
||||||
/**
|
/**
|
||||||
* Only leaves entries with external sources:
|
* Only leaves entries with external sources:
|
||||||
* - keeps: '@open-wc/testing'
|
* - keeps: '@open-wc/testing'
|
||||||
* - drops: '../testing'
|
* - drops: '../testing'
|
||||||
* @param {FindImportsAnalyzerResult} result
|
* @param {FindImportsAnalyzerQueryOutput} result
|
||||||
* @param {string} targetSpecifier for instance 'LitElement'
|
* @param {string} targetSpecifier for instance 'LitElement'
|
||||||
*/
|
*/
|
||||||
onlyExternalSources(result) {
|
onlyExternalSources(result) {
|
||||||
|
|
@ -29,6 +31,9 @@ const /** @type {AnalyzerOptions} */ options = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Node} node
|
||||||
|
*/
|
||||||
function getImportOrReexportsSpecifiers(node) {
|
function getImportOrReexportsSpecifiers(node) {
|
||||||
return node.specifiers.map(s => {
|
return node.specifiers.map(s => {
|
||||||
if (s.type === 'ImportDefaultSpecifier' || s.type === 'ExportDefaultSpecifier') {
|
if (s.type === 'ImportDefaultSpecifier' || s.type === 'ExportDefaultSpecifier') {
|
||||||
|
|
@ -49,11 +54,12 @@ function getImportOrReexportsSpecifiers(node) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds import specifiers and sources
|
* Finds import specifiers and sources
|
||||||
* @param {any} ast
|
* @param {File} ast
|
||||||
*/
|
*/
|
||||||
function findImportsPerAstEntry(ast) {
|
function findImportsPerAstEntry(ast) {
|
||||||
LogService.debug(`Analyzer "find-imports": started findImportsPerAstEntry method`);
|
LogService.debug(`Analyzer "find-imports": started findImportsPerAstEntry method`);
|
||||||
|
|
||||||
|
// https://github.com/babel/babel/blob/672a58660f0b15691c44582f1f3fdcdac0fa0d2f/packages/babel-core/src/transformation/index.ts#L110
|
||||||
// Visit AST...
|
// Visit AST...
|
||||||
/** @type {Partial<FindImportsAnalyzerEntry>[]} */
|
/** @type {Partial<FindImportsAnalyzerEntry>[]} */
|
||||||
const transformedEntry = [];
|
const transformedEntry = [];
|
||||||
|
|
@ -110,10 +116,9 @@ function findImportsPerAstEntry(ast) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class FindImportsAnalyzer extends Analyzer {
|
class FindImportsAnalyzer extends Analyzer {
|
||||||
constructor() {
|
/** @type {AnalyzerName} */
|
||||||
super();
|
static get analyzerName() {
|
||||||
/** @type {AnalyzerName} */
|
return 'find-imports';
|
||||||
this.name = 'find-imports';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,14 @@
|
||||||
const { isRelativeSourcePath } = require('../../utils/relative-source-path.js');
|
const { isRelativeSourcePath } = require('../../utils/relative-source-path.js');
|
||||||
const { LogService } = require('../../services/LogService.js');
|
const { LogService } = require('../../core/LogService.js');
|
||||||
const { resolveImportPath } = require('../../utils/resolve-import-path.js');
|
const { resolveImportPath } = require('../../utils/resolve-import-path.js');
|
||||||
|
const { toPosixPath } = require('../../utils/to-posix-path.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('../../types/core').PathRelativeFromProjectRoot} PathRelativeFromProjectRoot
|
* @typedef {import('../../types/core').PathRelativeFromProjectRoot} PathRelativeFromProjectRoot
|
||||||
|
* @typedef {import('../../types/core').PathFromSystemRoot} PathFromSystemRoot
|
||||||
|
* @typedef {import('../../types/core').SpecifierSource} SpecifierSource
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} importee like '@lion/core/myFile.js'
|
|
||||||
* @returns {string} project name ('@lion/core')
|
|
||||||
*/
|
|
||||||
function getProjectFromImportee(importee) {
|
|
||||||
const scopedProject = importee[0] === '@';
|
|
||||||
// 'external-project/src/file.js' -> ['external-project', 'src', file.js']
|
|
||||||
let splitSource = importee.split('/');
|
|
||||||
if (scopedProject) {
|
|
||||||
// '@external/project'
|
|
||||||
splitSource = [splitSource.slice(0, 2).join('/'), ...splitSource.slice(2)];
|
|
||||||
}
|
|
||||||
// ['external-project', 'src', 'file.js'] -> 'external-project'
|
|
||||||
const project = splitSource.slice(0, 1).join('/');
|
|
||||||
|
|
||||||
return project;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets local path from reference project
|
* Gets local path from reference project
|
||||||
*
|
*
|
||||||
|
|
@ -33,28 +18,25 @@ function getProjectFromImportee(importee) {
|
||||||
* - from: 'reference-project'
|
* - from: 'reference-project'
|
||||||
* - to: './index.js' (or other file specified in package.json 'main')
|
* - to: './index.js' (or other file specified in package.json 'main')
|
||||||
* @param {object} config
|
* @param {object} config
|
||||||
* @param {string} config.importee 'reference-project/foo.js'
|
* @param {SpecifierSource} config.importee 'reference-project/foo.js'
|
||||||
* @param {string} config.importer '/my/project/importing-file.js'
|
* @param {PathFromSystemRoot} config.importer '/my/project/importing-file.js'
|
||||||
|
* @param {PathFromSystemRoot} config.importeeProjectPath '/path/to/reference/project'
|
||||||
* @returns {Promise<PathRelativeFromProjectRoot|null>} './foo.js'
|
* @returns {Promise<PathRelativeFromProjectRoot|null>} './foo.js'
|
||||||
*/
|
*/
|
||||||
async function fromImportToExportPerspective({ importee, importer }) {
|
async function fromImportToExportPerspective({ importee, importer, importeeProjectPath }) {
|
||||||
if (isRelativeSourcePath(importee)) {
|
if (isRelativeSourcePath(importee)) {
|
||||||
LogService.warn('[fromImportToExportPerspective] Please only provide external import paths');
|
LogService.warn('[fromImportToExportPerspective] Please only provide external import paths');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const absolutePath = await resolveImportPath(importee, importer);
|
const absolutePath = await resolveImportPath(importee, importer);
|
||||||
const projectName = getProjectFromImportee(importee);
|
if (!absolutePath) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
return /** @type {PathRelativeFromProjectRoot} */ (
|
||||||
* - from: '/my/reference/project/packages/foo/index.js'
|
absolutePath.replace(new RegExp(`^${toPosixPath(importeeProjectPath)}/?(.*)$`), './$1')
|
||||||
* - to: './packages/foo/index.js'
|
);
|
||||||
*/
|
|
||||||
return absolutePath
|
|
||||||
? /** @type {PathRelativeFromProjectRoot} */ (
|
|
||||||
absolutePath.replace(new RegExp(`^.*/${projectName}/?(.*)$`), './$1')
|
|
||||||
)
|
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { fromImportToExportPerspective };
|
module.exports = { fromImportToExportPerspective };
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ const pathLib = require('path');
|
||||||
const { isRelativeSourcePath } = require('../../utils/relative-source-path.js');
|
const { isRelativeSourcePath } = require('../../utils/relative-source-path.js');
|
||||||
const { resolveImportPath } = require('../../utils/resolve-import-path.js');
|
const { resolveImportPath } = require('../../utils/resolve-import-path.js');
|
||||||
const { toPosixPath } = require('../../utils/to-posix-path.js');
|
const { toPosixPath } = require('../../utils/to-posix-path.js');
|
||||||
const { aMap } = require('../../utils/async-array-utils.js');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('../../types/core').PathRelative} PathRelative
|
* @typedef {import('../../types/core').PathRelative} PathRelative
|
||||||
|
|
@ -44,7 +43,9 @@ async function normalizeSourcePaths(queryOutput, relativePath, rootPath = proces
|
||||||
pathLib.resolve(rootPath, relativePath)
|
pathLib.resolve(rootPath, relativePath)
|
||||||
);
|
);
|
||||||
const currentDirPath = /** @type {PathFromSystemRoot} */ (pathLib.dirname(currentFilePath));
|
const currentDirPath = /** @type {PathFromSystemRoot} */ (pathLib.dirname(currentFilePath));
|
||||||
return aMap(queryOutput, async specifierResObj => {
|
|
||||||
|
const normalizedQueryOutput = [];
|
||||||
|
for (const specifierResObj of queryOutput) {
|
||||||
if (specifierResObj.source) {
|
if (specifierResObj.source) {
|
||||||
if (isRelativeSourcePath(specifierResObj.source) && relativePath) {
|
if (isRelativeSourcePath(specifierResObj.source) && relativePath) {
|
||||||
// This will be a source like '../my/file.js' or './file.js'
|
// This will be a source like '../my/file.js' or './file.js'
|
||||||
|
|
@ -60,8 +61,9 @@ async function normalizeSourcePaths(queryOutput, relativePath, rootPath = proces
|
||||||
// specifierResObj.fullSource = specifierResObj.source;
|
// specifierResObj.fullSource = specifierResObj.source;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return specifierResObj;
|
normalizedQueryOutput.push(specifierResObj);
|
||||||
});
|
}
|
||||||
|
return normalizedQueryOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { normalizeSourcePaths };
|
module.exports = { normalizeSourcePaths };
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ const {
|
||||||
isRelativeSourcePath,
|
isRelativeSourcePath,
|
||||||
toRelativeSourcePath,
|
toRelativeSourcePath,
|
||||||
} = require('../../utils/relative-source-path.js');
|
} = require('../../utils/relative-source-path.js');
|
||||||
const { AstService } = require('../../services/AstService.js');
|
const { InputDataService } = require('../../core/InputDataService.js');
|
||||||
const { LogService } = require('../../services/LogService.js');
|
|
||||||
const { InputDataService } = require('../../services/InputDataService.js');
|
|
||||||
const { resolveImportPath } = require('../../utils/resolve-import-path.js');
|
const { resolveImportPath } = require('../../utils/resolve-import-path.js');
|
||||||
|
const { AstService } = require('../../core/AstService.js');
|
||||||
|
const { LogService } = require('../../core/LogService.js');
|
||||||
const { memoize } = require('../../utils/memoize.js');
|
const { memoize } = require('../../utils/memoize.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -18,6 +18,14 @@ const { memoize } = require('../../utils/memoize.js');
|
||||||
* @typedef {import('../../types/core').PathFromSystemRoot} PathFromSystemRoot
|
* @typedef {import('../../types/core').PathFromSystemRoot} PathFromSystemRoot
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} source
|
||||||
|
* @param {string} projectName
|
||||||
|
*/
|
||||||
|
function isSelfReferencingProject(source, projectName) {
|
||||||
|
return source.startsWith(`${projectName}`);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} source
|
* @param {string} source
|
||||||
* @param {string} projectName
|
* @param {string} projectName
|
||||||
|
|
@ -26,7 +34,7 @@ function isExternalProject(source, projectName) {
|
||||||
return (
|
return (
|
||||||
!source.startsWith('#') &&
|
!source.startsWith('#') &&
|
||||||
!isRelativeSourcePath(source) &&
|
!isRelativeSourcePath(source) &&
|
||||||
!source.startsWith(`${projectName}/`)
|
!isSelfReferencingProject(source, projectName)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// A base class for writing Analyzers
|
// A base class for writing Analyzers
|
||||||
const { Analyzer } = require('./helpers/Analyzer.js');
|
const { Analyzer } = require('../core/Analyzer.js');
|
||||||
|
|
||||||
// Expose analyzers that are requested to be run in external contexts
|
// Expose analyzers that are requested to be run in external contexts
|
||||||
const FindExportsAnalyzer = require('./find-exports.js');
|
const FindExportsAnalyzer = require('./find-exports.js');
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ const pathLib = require('path');
|
||||||
/* eslint-disable no-shadow, no-param-reassign */
|
/* eslint-disable no-shadow, no-param-reassign */
|
||||||
const FindImportsAnalyzer = require('./find-imports.js');
|
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('../core/Analyzer.js');
|
||||||
const { fromImportToExportPerspective } = require('./helpers/from-import-to-export-perspective.js');
|
const { fromImportToExportPerspective } = require('./helpers/from-import-to-export-perspective.js');
|
||||||
const {
|
const {
|
||||||
transformIntoIterableFindExportsOutput,
|
transformIntoIterableFindExportsOutput,
|
||||||
|
|
@ -21,6 +21,7 @@ const {
|
||||||
* @typedef {import('../types/analyzers').MatchImportsConfig} MatchImportsConfig
|
* @typedef {import('../types/analyzers').MatchImportsConfig} MatchImportsConfig
|
||||||
* @typedef {import('../types/analyzers').MatchImportsAnalyzerResult} MatchImportsAnalyzerResult
|
* @typedef {import('../types/analyzers').MatchImportsAnalyzerResult} MatchImportsAnalyzerResult
|
||||||
* @typedef {import('../types/core').PathRelativeFromProjectRoot} PathRelativeFromProjectRoot
|
* @typedef {import('../types/core').PathRelativeFromProjectRoot} PathRelativeFromProjectRoot
|
||||||
|
* @typedef {import('../types/core').PathFromSystemRoot} PathFromSystemRoot
|
||||||
* @typedef {import('../types/core').AnalyzerName} AnalyzerName
|
* @typedef {import('../types/core').AnalyzerName} AnalyzerName
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
@ -117,9 +118,13 @@ async function matchImportsPostprocess(exportsAnalyzerResult, importsAnalyzerRes
|
||||||
*/
|
*/
|
||||||
const fromImportToExport = await fromImportToExportPerspective({
|
const fromImportToExport = await fromImportToExportPerspective({
|
||||||
importee: importEntry.normalizedSource,
|
importee: importEntry.normalizedSource,
|
||||||
importer: pathLib.resolve(importProjectPath, importEntry.file),
|
importer: /** @type {PathFromSystemRoot} */ (
|
||||||
|
pathLib.resolve(importProjectPath, importEntry.file)
|
||||||
|
),
|
||||||
|
importeeProjectPath: cfg.referenceProjectPath,
|
||||||
});
|
});
|
||||||
const isFromSameSource = compareImportAndExportPaths(exportEntry.file, fromImportToExport);
|
const isFromSameSource = compareImportAndExportPaths(exportEntry.file, fromImportToExport);
|
||||||
|
|
||||||
if (!isFromSameSource) {
|
if (!isFromSameSource) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -133,7 +138,10 @@ async function matchImportsPostprocess(exportsAnalyzerResult, importsAnalyzerRes
|
||||||
entry => entry.exportSpecifier && entry.exportSpecifier.id === id,
|
entry => entry.exportSpecifier && entry.exportSpecifier.id === id,
|
||||||
);
|
);
|
||||||
if (resultForCurrentExport) {
|
if (resultForCurrentExport) {
|
||||||
resultForCurrentExport.importProjectFiles.push(importEntry.file);
|
// Prevent that we count double import like "import * as all from 'x'" and "import {smth} from 'x'"
|
||||||
|
if (!resultForCurrentExport.importProjectFiles.includes(importEntry.file)) {
|
||||||
|
resultForCurrentExport.importProjectFiles.push(importEntry.file);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
conciseResultsArray.push({
|
conciseResultsArray.push({
|
||||||
exportSpecifier: { id, ...(exportEntry.meta ? { meta: exportEntry.meta } : {}) },
|
exportSpecifier: { id, ...(exportEntry.meta ? { meta: exportEntry.meta } : {}) },
|
||||||
|
|
@ -151,10 +159,8 @@ async function matchImportsPostprocess(exportsAnalyzerResult, importsAnalyzerRes
|
||||||
}
|
}
|
||||||
|
|
||||||
class MatchImportsAnalyzer extends Analyzer {
|
class MatchImportsAnalyzer extends Analyzer {
|
||||||
constructor() {
|
static get analyzerName() {
|
||||||
super();
|
return 'match-imports';
|
||||||
/** @type {AnalyzerName} */
|
|
||||||
this.name = 'match-imports';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static get requiresReference() {
|
static get requiresReference() {
|
||||||
|
|
@ -207,6 +213,7 @@ class MatchImportsAnalyzer extends Analyzer {
|
||||||
metaConfig: cfg.metaConfig,
|
metaConfig: cfg.metaConfig,
|
||||||
targetProjectPath: cfg.referenceProjectPath,
|
targetProjectPath: cfg.referenceProjectPath,
|
||||||
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
||||||
|
suppressNonCriticalLogs: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -217,6 +224,7 @@ class MatchImportsAnalyzer extends Analyzer {
|
||||||
metaConfig: cfg.metaConfig,
|
metaConfig: cfg.metaConfig,
|
||||||
targetProjectPath: cfg.targetProjectPath,
|
targetProjectPath: cfg.targetProjectPath,
|
||||||
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
||||||
|
suppressNonCriticalLogs: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@
|
||||||
const MatchSubclassesAnalyzer = require('./match-subclasses.js');
|
const MatchSubclassesAnalyzer = require('./match-subclasses.js');
|
||||||
const FindExportsAnalyzer = require('./find-exports.js');
|
const FindExportsAnalyzer = require('./find-exports.js');
|
||||||
const FindCustomelementsAnalyzer = require('./find-customelements.js');
|
const FindCustomelementsAnalyzer = require('./find-customelements.js');
|
||||||
const { Analyzer } = require('./helpers/Analyzer.js');
|
const { Analyzer } = require('../core/Analyzer.js');
|
||||||
|
|
||||||
/** @typedef {import('./types').FindExportsAnalyzerResult} FindExportsAnalyzerResult */
|
/** @typedef {import('../types/core').FindExportsAnalyzerResult} FindExportsAnalyzerResult */
|
||||||
/** @typedef {import('./types').FindCustomelementsAnalyzerResult} FindCustomelementsAnalyzerResult */
|
/** @typedef {import('../types/core').FindCustomelementsAnalyzerResult} FindCustomelementsAnalyzerResult */
|
||||||
/** @typedef {import('./types').MatchSubclassesAnalyzerResult} MatchSubclassesAnalyzerResult */
|
/** @typedef {import('../types/core').MatchSubclassesAnalyzerResult} MatchSubclassesAnalyzerResult */
|
||||||
/** @typedef {import('./types').FindImportsAnalyzerResult} FindImportsAnalyzerResult */
|
/** @typedef {import('../types/core').FindImportsAnalyzerResult} FindImportsAnalyzerResult */
|
||||||
/** @typedef {import('./types').MatchedExportSpecifier} MatchedExportSpecifier */
|
/** @typedef {import('../types/core').MatchedExportSpecifier} MatchedExportSpecifier */
|
||||||
/** @typedef {import('./types').RootFile} RootFile */
|
/** @typedef {import('../types/core').RootFile} RootFile */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For prefix `{ from: 'lion', to: 'wolf' }`
|
* For prefix `{ from: 'lion', to: 'wolf' }`
|
||||||
|
|
@ -362,9 +362,8 @@ function matchPathsPostprocess(
|
||||||
* ]
|
* ]
|
||||||
*/
|
*/
|
||||||
class MatchPathsAnalyzer extends Analyzer {
|
class MatchPathsAnalyzer extends Analyzer {
|
||||||
constructor() {
|
static get analyzerName() {
|
||||||
super();
|
return 'match-paths';
|
||||||
this.name = 'match-paths';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static get requiresReference() {
|
static get requiresReference() {
|
||||||
|
|
@ -429,6 +428,7 @@ class MatchPathsAnalyzer extends Analyzer {
|
||||||
gatherFilesConfig: cfg.gatherFilesConfig,
|
gatherFilesConfig: cfg.gatherFilesConfig,
|
||||||
gatherFilesConfigReference: cfg.gatherFilesConfigReference,
|
gatherFilesConfigReference: cfg.gatherFilesConfigReference,
|
||||||
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
||||||
|
suppressNonCriticalLogs: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// [A2]
|
// [A2]
|
||||||
|
|
@ -438,6 +438,7 @@ class MatchPathsAnalyzer extends Analyzer {
|
||||||
targetProjectPath: cfg.targetProjectPath,
|
targetProjectPath: cfg.targetProjectPath,
|
||||||
gatherFilesConfig: cfg.gatherFilesConfig,
|
gatherFilesConfig: cfg.gatherFilesConfig,
|
||||||
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
||||||
|
suppressNonCriticalLogs: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// [A3]
|
// [A3]
|
||||||
|
|
@ -447,6 +448,7 @@ class MatchPathsAnalyzer extends Analyzer {
|
||||||
targetProjectPath: cfg.referenceProjectPath,
|
targetProjectPath: cfg.referenceProjectPath,
|
||||||
gatherFilesConfig: cfg.gatherFilesConfigReference,
|
gatherFilesConfig: cfg.gatherFilesConfigReference,
|
||||||
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
||||||
|
suppressNonCriticalLogs: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -475,6 +477,7 @@ class MatchPathsAnalyzer extends Analyzer {
|
||||||
targetProjectPath: cfg.targetProjectPath,
|
targetProjectPath: cfg.targetProjectPath,
|
||||||
gatherFilesConfig: cfg.gatherFilesConfig,
|
gatherFilesConfig: cfg.gatherFilesConfig,
|
||||||
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
||||||
|
suppressNonCriticalLogs: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// [B2]
|
// [B2]
|
||||||
|
|
@ -484,6 +487,7 @@ class MatchPathsAnalyzer extends Analyzer {
|
||||||
targetProjectPath: cfg.referenceProjectPath,
|
targetProjectPath: cfg.referenceProjectPath,
|
||||||
gatherFilesConfig: cfg.gatherFilesConfigReference,
|
gatherFilesConfig: cfg.gatherFilesConfigReference,
|
||||||
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
||||||
|
suppressNonCriticalLogs: true,
|
||||||
});
|
});
|
||||||
// refFindExportsAnalyzer was already created in A3
|
// refFindExportsAnalyzer was already created in A3
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,19 @@ const pathLib = require('path');
|
||||||
/* eslint-disable no-shadow, no-param-reassign */
|
/* eslint-disable no-shadow, no-param-reassign */
|
||||||
const FindClassesAnalyzer = require('./find-classes.js');
|
const FindClassesAnalyzer = require('./find-classes.js');
|
||||||
const FindExportsAnalyzer = require('./find-exports.js');
|
const FindExportsAnalyzer = require('./find-exports.js');
|
||||||
const { Analyzer } = require('./helpers/Analyzer.js');
|
const { Analyzer } = require('../core/Analyzer.js');
|
||||||
const { fromImportToExportPerspective } = require('./helpers/from-import-to-export-perspective.js');
|
const { fromImportToExportPerspective } = require('./helpers/from-import-to-export-perspective.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('../types/analyzers/find-classes').FindClassesAnalyzerResult} FindClassesAnalyzerResult
|
* @typedef {import('../types/analyzers').FindClassesAnalyzerResult} FindClassesAnalyzerResult
|
||||||
* @typedef {import('../types/find-imports').FindImportsAnalyzerResult} FindImportsAnalyzerResult
|
* @typedef {import('../types/analyzers').FindImportsAnalyzerResult} FindImportsAnalyzerResult
|
||||||
* @typedef {import('../types/find-exports').FindExportsAnalyzerResult} FindExportsAnalyzerResult
|
* @typedef {import('../types/analyzers').FindExportsAnalyzerResult} FindExportsAnalyzerResult
|
||||||
* @typedef {import('../types/find-exports').IterableFindExportsAnalyzerEntry} IterableFindExportsAnalyzerEntry
|
* @typedef {import('../types/analyzers').IterableFindExportsAnalyzerEntry} IterableFindExportsAnalyzerEntry
|
||||||
* @typedef {import('../types/find-imports').IterableFindImportsAnalyzerEntry} IterableFindImportsAnalyzerEntry
|
* @typedef {import('../types/analyzers').IterableFindImportsAnalyzerEntry} IterableFindImportsAnalyzerEntry
|
||||||
* @typedef {import('../types/match-imports').ConciseMatchImportsAnalyzerResult} ConciseMatchImportsAnalyzerResult
|
* @typedef {import('../types/analyzers').ConciseMatchImportsAnalyzerResult} ConciseMatchImportsAnalyzerResult
|
||||||
* @typedef {import('../types/match-imports').MatchImportsConfig} MatchImportsConfig
|
* @typedef {import('../types/analyzers').MatchImportsConfig} MatchImportsConfig
|
||||||
* @typedef {import('../types/core/core').PathRelativeFromProjectRoot} PathRelativeFromProjectRoot
|
* @typedef {import('../types/core').PathRelativeFromProjectRoot} PathRelativeFromProjectRoot
|
||||||
|
* @typedef {import('../types/core').PathFromSystemRoot} PathFromSystemRoot
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function getMemberOverrides(
|
function getMemberOverrides(
|
||||||
|
|
@ -52,7 +53,7 @@ function getMemberOverrides(
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Helper method for matchImportsPostprocess. Modifies its resultsObj
|
* Helper method for matchImportsPostprocess. Modifies its resultsObj
|
||||||
* @param {object} resultsObj
|
* @param {object} resultsObj
|
||||||
* @param {string} exportId like 'myExport::./reference-project/my/export.js::my-project'
|
* @param {string} exportId like 'myExport::./reference-project/my/export.js::my-project'
|
||||||
* @param {Set<string>} filteredList
|
* @param {Set<string>} filteredList
|
||||||
|
|
@ -67,14 +68,14 @@ function storeResult(resultsObj, exportId, filteredList, meta) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {FindExportsAnalyzerResult} exportsAnalyzerResult
|
* @param {FindExportsAnalyzerResult} refExportsAnalyzerResult
|
||||||
* @param {FindClassesAnalyzerResult} targetClassesAnalyzerResult
|
* @param {FindClassesAnalyzerResult} targetClassesAnalyzerResult
|
||||||
* @param {FindClassesAnalyzerResult} refClassesAResult
|
* @param {FindClassesAnalyzerResult} refClassesAResult
|
||||||
* @param {MatchSubclassesConfig} customConfig
|
* @param {MatchSubclassesConfig} customConfig
|
||||||
* @returns {AnalyzerQueryResult}
|
* @returns {AnalyzerQueryResult}
|
||||||
*/
|
*/
|
||||||
async function matchSubclassesPostprocess(
|
async function matchSubclassesPostprocess(
|
||||||
exportsAnalyzerResult,
|
refExportsAnalyzerResult,
|
||||||
targetClassesAnalyzerResult,
|
targetClassesAnalyzerResult,
|
||||||
refClassesAResult,
|
refClassesAResult,
|
||||||
customConfig,
|
customConfig,
|
||||||
|
|
@ -102,8 +103,8 @@ async function matchSubclassesPostprocess(
|
||||||
*/
|
*/
|
||||||
const resultsObj = {};
|
const resultsObj = {};
|
||||||
|
|
||||||
for (const exportEntry of exportsAnalyzerResult.queryOutput) {
|
for (const exportEntry of refExportsAnalyzerResult.queryOutput) {
|
||||||
const exportsProjectObj = exportsAnalyzerResult.analyzerMeta.targetProject;
|
const exportsProjectObj = refExportsAnalyzerResult.analyzerMeta.targetProject;
|
||||||
const exportsProjectName = exportsProjectObj.name;
|
const exportsProjectName = exportsProjectObj.name;
|
||||||
|
|
||||||
// Look for all specifiers that are exported, like [import {specifier} 'lion-based-ui/foo.js']
|
// Look for all specifiers that are exported, like [import {specifier} 'lion-based-ui/foo.js']
|
||||||
|
|
@ -124,9 +125,10 @@ async function matchSubclassesPostprocess(
|
||||||
// TODO: What if this info is retrieved from cached importProject/target project?
|
// TODO: What if this info is retrieved from cached importProject/target project?
|
||||||
const importProjectPath = cfg.targetProjectPath;
|
const importProjectPath = cfg.targetProjectPath;
|
||||||
for (const { result, file } of targetClassesAnalyzerResult.queryOutput) {
|
for (const { result, file } of targetClassesAnalyzerResult.queryOutput) {
|
||||||
// targetClassesAnalyzerResult.queryOutput.forEach(({ result, file }) =>
|
const importerFilePath = /** @type {PathFromSystemRoot} */ (
|
||||||
|
pathLib.resolve(importProjectPath, file)
|
||||||
|
);
|
||||||
for (const classEntryResult of result) {
|
for (const classEntryResult of result) {
|
||||||
// result.forEach(classEntryResult => {
|
|
||||||
/**
|
/**
|
||||||
* @example
|
* @example
|
||||||
* Example context (read by 'find-classes'/'find-exports' analyzers)
|
* Example context (read by 'find-classes'/'find-exports' analyzers)
|
||||||
|
|
@ -165,7 +167,8 @@ async function matchSubclassesPostprocess(
|
||||||
exportEntry.file ===
|
exportEntry.file ===
|
||||||
(await fromImportToExportPerspective({
|
(await fromImportToExportPerspective({
|
||||||
importee: classMatch.rootFile.file,
|
importee: classMatch.rootFile.file,
|
||||||
importer: pathLib.resolve(importProjectPath, file),
|
importer: importerFilePath,
|
||||||
|
importeeProjectPath: cfg.referenceProjectPath,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (classMatch && isFromSameSource) {
|
if (classMatch && isFromSameSource) {
|
||||||
|
|
@ -176,8 +179,14 @@ async function matchSubclassesPostprocess(
|
||||||
exportEntryResult,
|
exportEntryResult,
|
||||||
exportSpecifier,
|
exportSpecifier,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let projectFileId = `${importProject}::${file}::${classEntryResult.name}`;
|
||||||
|
if (cfg.addSystemPathsInResult) {
|
||||||
|
projectFileId += `::${importerFilePath}`;
|
||||||
|
}
|
||||||
|
|
||||||
filteredImportsList.add({
|
filteredImportsList.add({
|
||||||
projectFileId: `${importProject}::${file}::${classEntryResult.name}`,
|
projectFileId,
|
||||||
memberOverrides,
|
memberOverrides,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -235,13 +244,18 @@ async function matchSubclassesPostprocess(
|
||||||
const matchesPerProject = [];
|
const matchesPerProject = [];
|
||||||
flatResult.files.forEach(({ projectFileId, memberOverrides }) => {
|
flatResult.files.forEach(({ projectFileId, memberOverrides }) => {
|
||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
const [project, file, identifier] = projectFileId.split('::');
|
const [project, file, identifier, filePath] = projectFileId.split('::');
|
||||||
let projectEntry = matchesPerProject.find(m => m.project === project);
|
let projectEntry = matchesPerProject.find(m => m.project === project);
|
||||||
if (!projectEntry) {
|
if (!projectEntry) {
|
||||||
matchesPerProject.push({ project, files: [] });
|
matchesPerProject.push({ project, files: [] });
|
||||||
projectEntry = matchesPerProject[matchesPerProject.length - 1];
|
projectEntry = matchesPerProject[matchesPerProject.length - 1];
|
||||||
}
|
}
|
||||||
projectEntry.files.push({ file, identifier, memberOverrides });
|
const entry = { file, identifier, memberOverrides };
|
||||||
|
if (filePath) {
|
||||||
|
// @ts-ignore
|
||||||
|
entry.filePath = filePath;
|
||||||
|
}
|
||||||
|
projectEntry.files.push(entry);
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -262,9 +276,8 @@ async function matchSubclassesPostprocess(
|
||||||
// }
|
// }
|
||||||
|
|
||||||
class MatchSubclassesAnalyzer extends Analyzer {
|
class MatchSubclassesAnalyzer extends Analyzer {
|
||||||
constructor() {
|
static get analyzerName() {
|
||||||
super();
|
return 'match-subclasses';
|
||||||
this.name = 'match-subclasses';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static get requiresReference() {
|
static get requiresReference() {
|
||||||
|
|
@ -309,16 +322,18 @@ class MatchSubclassesAnalyzer extends Analyzer {
|
||||||
*/
|
*/
|
||||||
const findExportsAnalyzer = new FindExportsAnalyzer();
|
const findExportsAnalyzer = new FindExportsAnalyzer();
|
||||||
/** @type {FindExportsAnalyzerResult} */
|
/** @type {FindExportsAnalyzerResult} */
|
||||||
const exportsAnalyzerResult = await findExportsAnalyzer.execute({
|
const refExportsAnalyzerResult = await findExportsAnalyzer.execute({
|
||||||
targetProjectPath: cfg.referenceProjectPath,
|
targetProjectPath: cfg.referenceProjectPath,
|
||||||
gatherFilesConfig: cfg.gatherFilesConfigReference,
|
gatherFilesConfig: cfg.gatherFilesConfigReference,
|
||||||
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
||||||
|
suppressNonCriticalLogs: true,
|
||||||
});
|
});
|
||||||
const findClassesAnalyzer = new FindClassesAnalyzer();
|
const findClassesAnalyzer = new FindClassesAnalyzer();
|
||||||
/** @type {FindClassesAnalyzerResult} */
|
/** @type {FindClassesAnalyzerResult} */
|
||||||
const targetClassesAnalyzerResult = await findClassesAnalyzer.execute({
|
const targetClassesAnalyzerResult = await findClassesAnalyzer.execute({
|
||||||
targetProjectPath: cfg.targetProjectPath,
|
targetProjectPath: cfg.targetProjectPath,
|
||||||
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
||||||
|
suppressNonCriticalLogs: true,
|
||||||
});
|
});
|
||||||
const findRefClassesAnalyzer = new FindClassesAnalyzer();
|
const findRefClassesAnalyzer = new FindClassesAnalyzer();
|
||||||
/** @type {FindClassesAnalyzerResult} */
|
/** @type {FindClassesAnalyzerResult} */
|
||||||
|
|
@ -326,10 +341,11 @@ class MatchSubclassesAnalyzer extends Analyzer {
|
||||||
targetProjectPath: cfg.referenceProjectPath,
|
targetProjectPath: cfg.referenceProjectPath,
|
||||||
gatherFilesConfig: cfg.gatherFilesConfigReference,
|
gatherFilesConfig: cfg.gatherFilesConfigReference,
|
||||||
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
||||||
|
suppressNonCriticalLogs: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const queryOutput = await matchSubclassesPostprocess(
|
const queryOutput = await matchSubclassesPostprocess(
|
||||||
exportsAnalyzerResult,
|
refExportsAnalyzerResult,
|
||||||
targetClassesAnalyzerResult,
|
targetClassesAnalyzerResult,
|
||||||
refClassesAnalyzerResult,
|
refClassesAnalyzerResult,
|
||||||
cfg,
|
cfg,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
const pathLib = require('path');
|
const pathLib = require('path');
|
||||||
const { LogService } = require('../../services/LogService.js');
|
const { LogService } = require('../../core/LogService.js');
|
||||||
|
|
||||||
const /** @type {AnalyzerOptions} */ options = {
|
const /** @type {AnalyzerOptions} */ options = {
|
||||||
filterSpecifier(results, targetSpecifier, specifiersKey) {
|
filterSpecifier(results, targetSpecifier, specifiersKey) {
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,22 @@
|
||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
const fs = require('fs');
|
|
||||||
const semver = require('semver');
|
const semver = require('semver');
|
||||||
const pathLib = require('path');
|
const pathLib = require('path');
|
||||||
const { LogService } = require('../../services/LogService.js');
|
const { LogService } = require('./LogService.js');
|
||||||
const { QueryService } = require('../../services/QueryService.js');
|
const { QueryService } = require('./QueryService.js');
|
||||||
const { ReportService } = require('../../services/ReportService.js');
|
const { ReportService } = require('./ReportService.js');
|
||||||
const { InputDataService } = require('../../services/InputDataService.js');
|
const { InputDataService } = require('./InputDataService.js');
|
||||||
const { toPosixPath } = require('../../utils/to-posix-path.js');
|
const { toPosixPath } = require('../utils/to-posix-path.js');
|
||||||
const { getFilePathRelativeFromRoot } = require('../../utils/get-file-path-relative-from-root.js');
|
const { memoize } = require('../utils/memoize.js');
|
||||||
|
const { getFilePathRelativeFromRoot } = require('../utils/get-file-path-relative-from-root.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('../../types/core').AnalyzerName} AnalyzerName
|
* @typedef {import('../types/core').AnalyzerName} AnalyzerName
|
||||||
* @typedef {import('../../types/core').PathFromSystemRoot} PathFromSystemRoot
|
* @typedef {import('../types/core').PathFromSystemRoot} PathFromSystemRoot
|
||||||
* @typedef {import('../../types/core').QueryOutput} QueryOutput
|
* @typedef {import('../types/core').QueryOutput} QueryOutput
|
||||||
* @typedef {import('../../types/core').QueryOutputEntry} QueryOutputEntry
|
* @typedef {import('../types/core').ProjectInputData} ProjectInputData
|
||||||
* @typedef {import('../../types/core').ProjectInputData} ProjectInputData
|
* @typedef {import('../types/core').ProjectInputDataWithMeta} ProjectInputDataWithMeta
|
||||||
* @typedef {import('../../types/core').ProjectInputDataWithMeta} ProjectInputDataWithMeta
|
* @typedef {import('../types/core').AnalyzerQueryResult} AnalyzerQueryResult
|
||||||
* @typedef {import('../../types/core').AnalyzerQueryResult} AnalyzerQueryResult
|
* @typedef {import('../types/core').MatchAnalyzerConfig} MatchAnalyzerConfig
|
||||||
* @typedef {import('../../types/core').MatchAnalyzerConfig} MatchAnalyzerConfig
|
|
||||||
*
|
|
||||||
* @typedef {(ast: object, { relativePath: PathRelative }) => {result: QueryOutputEntry}} TraversEntryFn
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -27,7 +24,7 @@ const { getFilePathRelativeFromRoot } = require('../../utils/get-file-path-relat
|
||||||
* @param {ProjectInputDataWithMeta} projectData
|
* @param {ProjectInputDataWithMeta} projectData
|
||||||
* @param {function} astAnalysis
|
* @param {function} astAnalysis
|
||||||
*/
|
*/
|
||||||
async function analyzePerAstEntry(projectData, astAnalysis) {
|
async function analyzePerAstFile(projectData, astAnalysis) {
|
||||||
const entries = [];
|
const entries = [];
|
||||||
for (const { file, ast, context: astContext } of projectData.entries) {
|
for (const { file, ast, context: astContext } of projectData.entries) {
|
||||||
const relativePath = getFilePathRelativeFromRoot(file, projectData.project.path);
|
const relativePath = getFilePathRelativeFromRoot(file, projectData.project.path);
|
||||||
|
|
@ -64,22 +61,22 @@ function posixify(data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc This method ensures that the result returned by an analyzer always has a consistent format.
|
* This method ensures that the result returned by an analyzer always has a consistent format.
|
||||||
* By returning the configuration for the queryOutput, it will be possible to run later queries
|
* By returning the configuration for the queryOutput, it will be possible to run later queries
|
||||||
* under the same circumstances
|
* under the same circumstances
|
||||||
* @param {QueryOutput} queryOutput
|
* @param {QueryOutput} queryOutput
|
||||||
* @param {object} configuration
|
* @param {object} cfg
|
||||||
* @param {Analyzer} analyzer
|
* @param {Analyzer} analyzer
|
||||||
*/
|
*/
|
||||||
function ensureAnalyzerResultFormat(queryOutput, configuration, analyzer) {
|
function ensureAnalyzerResultFormat(queryOutput, cfg, analyzer) {
|
||||||
const { targetProjectMeta, identifier, referenceProjectMeta } = analyzer;
|
const { targetProjectMeta, identifier, referenceProjectMeta } = analyzer;
|
||||||
const optional = {};
|
const optional = {};
|
||||||
if (targetProjectMeta) {
|
if (targetProjectMeta) {
|
||||||
optional.targetProject = targetProjectMeta;
|
optional.targetProject = { ...targetProjectMeta };
|
||||||
delete optional.targetProject.path; // get rid of machine specific info
|
delete optional.targetProject.path; // get rid of machine specific info
|
||||||
}
|
}
|
||||||
if (referenceProjectMeta) {
|
if (referenceProjectMeta) {
|
||||||
optional.referenceProject = referenceProjectMeta;
|
optional.referenceProject = { ...referenceProjectMeta };
|
||||||
delete optional.referenceProject.path; // get rid of machine specific info
|
delete optional.referenceProject.path; // get rid of machine specific info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,7 +88,7 @@ function ensureAnalyzerResultFormat(queryOutput, configuration, analyzer) {
|
||||||
requiredAst: analyzer.requiredAst,
|
requiredAst: analyzer.requiredAst,
|
||||||
identifier,
|
identifier,
|
||||||
...optional,
|
...optional,
|
||||||
configuration,
|
configuration: cfg,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -129,28 +126,33 @@ function ensureAnalyzerResultFormat(queryOutput, configuration, analyzer) {
|
||||||
* Before running the analyzer, we need two conditions for a 'compatible match':
|
* Before running the analyzer, we need two conditions for a 'compatible match':
|
||||||
* - 1. referenceProject is imported by targetProject at all
|
* - 1. referenceProject is imported by targetProject at all
|
||||||
* - 2. referenceProject and targetProject have compatible major versions
|
* - 2. referenceProject and targetProject have compatible major versions
|
||||||
* @param {PathFromSystemRoot} referencePath
|
* @typedef {(referencePath:PathFromSystemRoot,targetPath:PathFromSystemRoot) => {compatible:boolean}} CheckForMatchCompatibilityFn
|
||||||
* @param {PathFromSystemRoot} targetPath
|
* @type {CheckForMatchCompatibilityFn}
|
||||||
*/
|
*/
|
||||||
function checkForMatchCompatibility(referencePath, targetPath) {
|
const checkForMatchCompatibility = memoize(
|
||||||
const refFile = pathLib.resolve(referencePath, 'package.json');
|
(
|
||||||
const referencePkg = JSON.parse(fs.readFileSync(refFile, 'utf8'));
|
/** @type {PathFromSystemRoot} */ referencePath,
|
||||||
const targetFile = pathLib.resolve(targetPath, 'package.json');
|
/** @type {PathFromSystemRoot} */ targetPath,
|
||||||
const targetPkg = JSON.parse(fs.readFileSync(targetFile, 'utf8'));
|
) => {
|
||||||
|
// const refFile = pathLib.resolve(referencePath, 'package.json');
|
||||||
|
const referencePkg = InputDataService.getPackageJson(referencePath);
|
||||||
|
// const targetFile = pathLib.resolve(targetPath, 'package.json');
|
||||||
|
const targetPkg = InputDataService.getPackageJson(targetPath);
|
||||||
|
|
||||||
const allTargetDeps = [
|
const allTargetDeps = [
|
||||||
...Object.entries(targetPkg.devDependencies || {}),
|
...Object.entries(targetPkg.devDependencies || {}),
|
||||||
...Object.entries(targetPkg.dependencies || {}),
|
...Object.entries(targetPkg.dependencies || {}),
|
||||||
];
|
];
|
||||||
const importEntry = allTargetDeps.find(([name]) => referencePkg.name === name);
|
const importEntry = allTargetDeps.find(([name]) => referencePkg.name === name);
|
||||||
if (!importEntry) {
|
if (!importEntry) {
|
||||||
return { compatible: false, reason: 'no-dependency' };
|
return { compatible: false, reason: 'no-dependency' };
|
||||||
}
|
}
|
||||||
if (!semver.satisfies(referencePkg.version, importEntry[1])) {
|
if (!semver.satisfies(referencePkg.version, importEntry[1])) {
|
||||||
return { compatible: false, reason: 'no-matched-version' };
|
return { compatible: false, reason: 'no-matched-version' };
|
||||||
}
|
}
|
||||||
return { compatible: true };
|
return { compatible: true };
|
||||||
}
|
},
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If in json format, 'unwind' to be compatible for analysis...
|
* If in json format, 'unwind' to be compatible for analysis...
|
||||||
|
|
@ -163,19 +165,18 @@ function unwindJsonResult(targetOrReferenceProjectResult) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Analyzer {
|
class Analyzer {
|
||||||
constructor() {
|
static requiresReference = false;
|
||||||
this.requiredAst = 'babel';
|
|
||||||
/** @type {AnalyzerName|''} */
|
|
||||||
this.name = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
static get requiresReference() {
|
/** @type {AnalyzerName|''} */
|
||||||
return false;
|
static analyzerName = '';
|
||||||
}
|
|
||||||
|
name = /** @type {typeof Analyzer} */ (this.constructor).analyzerName;
|
||||||
|
|
||||||
|
requiredAst = 'babel';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In a MatchAnalyzer, two Analyzers (a reference and target) are run.
|
* In a MatchAnalyzer, two Analyzers (a reference and targer) are run.
|
||||||
* For instance: a FindExportsAnalyzer and FindImportsAnalyzer are run.
|
* For instance, in a MatchImportsAnalyzer, a FindExportsAnalyzer and FinImportsAnalyzer are run.
|
||||||
* Their results can be provided as config params.
|
* Their results can be provided as config params.
|
||||||
* When they were stored in json format in the filesystem, 'unwind' them to be compatible for analysis...
|
* When they were stored in json format in the filesystem, 'unwind' them to be compatible for analysis...
|
||||||
* @param {MatchAnalyzerConfig} cfg
|
* @param {MatchAnalyzerConfig} cfg
|
||||||
|
|
@ -198,13 +199,13 @@ class Analyzer {
|
||||||
this.constructor.__unwindProvidedResults(cfg);
|
this.constructor.__unwindProvidedResults(cfg);
|
||||||
|
|
||||||
if (!cfg.targetProjectResult) {
|
if (!cfg.targetProjectResult) {
|
||||||
this.targetProjectMeta = InputDataService.getProjectMeta(cfg.targetProjectPath, true);
|
this.targetProjectMeta = InputDataService.getProjectMeta(cfg.targetProjectPath);
|
||||||
} else {
|
} else {
|
||||||
this.targetProjectMeta = cfg.targetProjectResult.analyzerMeta.targetProject;
|
this.targetProjectMeta = cfg.targetProjectResult.analyzerMeta.targetProject;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cfg.referenceProjectPath && !cfg.referenceProjectResult) {
|
if (cfg.referenceProjectPath && !cfg.referenceProjectResult) {
|
||||||
this.referenceProjectMeta = InputDataService.getProjectMeta(cfg.referenceProjectPath, true);
|
this.referenceProjectMeta = InputDataService.getProjectMeta(cfg.referenceProjectPath);
|
||||||
} else if (cfg.referenceProjectResult) {
|
} else if (cfg.referenceProjectResult) {
|
||||||
this.referenceProjectMeta = cfg.referenceProjectResult.analyzerMeta.targetProject;
|
this.referenceProjectMeta = cfg.referenceProjectResult.analyzerMeta.targetProject;
|
||||||
}
|
}
|
||||||
|
|
@ -227,14 +228,16 @@ class Analyzer {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!compatible) {
|
if (!compatible) {
|
||||||
LogService.info(
|
if (!cfg.suppressNonCriticalLogs) {
|
||||||
`skipping ${LogService.pad(this.name, 16)} for ${
|
LogService.info(
|
||||||
this.identifier
|
`skipping ${LogService.pad(this.name, 16)} for ${
|
||||||
}: (${reason})\n${cfg.targetProjectPath.replace(
|
this.identifier
|
||||||
`${process.cwd()}/providence-input-data/search-targets/`,
|
}: (${reason})\n${cfg.targetProjectPath.replace(
|
||||||
'',
|
`${process.cwd()}/providence-input-data/search-targets/`,
|
||||||
)}`,
|
'',
|
||||||
);
|
)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
return ensureAnalyzerResultFormat(`[${reason}]`, cfg, this);
|
return ensureAnalyzerResultFormat(`[${reason}]`, cfg, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -245,13 +248,16 @@ class Analyzer {
|
||||||
const cachedResult = Analyzer._getCachedAnalyzerResult({
|
const cachedResult = Analyzer._getCachedAnalyzerResult({
|
||||||
analyzerName: this.name,
|
analyzerName: this.name,
|
||||||
identifier: this.identifier,
|
identifier: this.identifier,
|
||||||
|
cfg,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (cachedResult) {
|
if (cachedResult) {
|
||||||
return cachedResult;
|
return cachedResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogService.info(`starting ${LogService.pad(this.name, 16)} for ${this.identifier}`);
|
if (!cfg.suppressNonCriticalLogs) {
|
||||||
|
LogService.info(`starting ${LogService.pad(this.name, 16)} for ${this.identifier}`);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get reference and search-target data
|
* Get reference and search-target data
|
||||||
|
|
@ -282,12 +288,14 @@ class Analyzer {
|
||||||
LogService.debug(`Analyzer "${this.name}": started _finalize method`);
|
LogService.debug(`Analyzer "${this.name}": started _finalize method`);
|
||||||
|
|
||||||
const analyzerResult = ensureAnalyzerResultFormat(queryOutput, cfg, this);
|
const analyzerResult = ensureAnalyzerResultFormat(queryOutput, cfg, this);
|
||||||
LogService.success(`finished ${LogService.pad(this.name, 16)} for ${this.identifier}`);
|
if (!cfg.suppressNonCriticalLogs) {
|
||||||
|
LogService.success(`finished ${LogService.pad(this.name, 16)} for ${this.identifier}`);
|
||||||
|
}
|
||||||
return analyzerResult;
|
return analyzerResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {function|{traverseEntryFn: function: filePaths:string[]; projectPath: string}} traverseEntryOrConfig
|
* @param {function|{traverseEntryFn: function; filePaths:string[]; projectPath: string}} traverseEntryOrConfig
|
||||||
*/
|
*/
|
||||||
async _traverse(traverseEntryOrConfig) {
|
async _traverse(traverseEntryOrConfig) {
|
||||||
LogService.debug(`Analyzer "${this.name}": started _traverse method`);
|
LogService.debug(`Analyzer "${this.name}": started _traverse method`);
|
||||||
|
|
@ -323,7 +331,7 @@ class Analyzer {
|
||||||
* Create ASTs for our inputData
|
* Create ASTs for our inputData
|
||||||
*/
|
*/
|
||||||
const astDataProjects = await QueryService.addAstToProjectsData(finalTargetData, 'babel');
|
const astDataProjects = await QueryService.addAstToProjectsData(finalTargetData, 'babel');
|
||||||
return analyzePerAstEntry(astDataProjects[0], traverseEntryFn);
|
return analyzePerAstFile(astDataProjects[0], traverseEntryFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(customConfig = {}) {
|
async execute(customConfig = {}) {
|
||||||
|
|
@ -332,6 +340,7 @@ class Analyzer {
|
||||||
const cfg = {
|
const cfg = {
|
||||||
targetProjectPath: null,
|
targetProjectPath: null,
|
||||||
referenceProjectPath: null,
|
referenceProjectPath: null,
|
||||||
|
suppressNonCriticalLogs: false,
|
||||||
...customConfig,
|
...customConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -355,19 +364,19 @@ class Analyzer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Gets a cached result from ReportService. Since ReportService slightly modifies analyzer
|
* Gets a cached result from ReportService. Since ReportService slightly modifies analyzer
|
||||||
* output, we 'unwind' before we return...
|
* output, we 'unwind' before we return...
|
||||||
* @param {object} config
|
* @param {{ analyzerName:AnalyzerName, identifier:string, cfg:AnalyzerConfig}} config
|
||||||
* @param {string} config.analyzerName
|
|
||||||
* @param {string} config.identifier
|
|
||||||
* @returns {AnalyzerQueryResult|undefined}
|
* @returns {AnalyzerQueryResult|undefined}
|
||||||
*/
|
*/
|
||||||
static _getCachedAnalyzerResult({ analyzerName, identifier }) {
|
static _getCachedAnalyzerResult({ analyzerName, identifier, cfg }) {
|
||||||
const cachedResult = ReportService.getCachedResult({ analyzerName, identifier });
|
const cachedResult = ReportService.getCachedResult({ analyzerName, identifier });
|
||||||
if (!cachedResult) {
|
if (!cachedResult) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
LogService.success(`cached version found for ${identifier}`);
|
if (!cfg.suppressNonCriticalLogs) {
|
||||||
|
LogService.success(`cached version found for ${identifier}`);
|
||||||
|
}
|
||||||
|
|
||||||
/** @type {AnalyzerQueryResult} */
|
/** @type {AnalyzerQueryResult} */
|
||||||
const result = unwindJsonResult(cachedResult);
|
const result = unwindJsonResult(cachedResult);
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
const babelParser = require('@babel/parser');
|
||||||
|
const parse5 = require('parse5');
|
||||||
|
const traverseHtml = require('../utils/traverse-html.js');
|
||||||
|
const { LogService } = require('./LogService.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import("@babel/types").File} File
|
||||||
|
* @typedef {import("@babel/parser").ParserOptions} ParserOptions
|
||||||
|
* @typedef {import('../types/core').PathFromSystemRoot} PathFromSystemRoot
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AstService {
|
||||||
|
/**
|
||||||
|
* Compiles an array of file paths using Babel.
|
||||||
|
* @param {string} code
|
||||||
|
* @param {ParserOptions} parserOptions
|
||||||
|
* @returns {File}
|
||||||
|
*/
|
||||||
|
static _getBabelAst(code, parserOptions = {}) {
|
||||||
|
const ast = babelParser.parse(code, {
|
||||||
|
sourceType: 'module',
|
||||||
|
plugins: [
|
||||||
|
'importMeta',
|
||||||
|
'dynamicImport',
|
||||||
|
'classProperties',
|
||||||
|
'exportDefaultFrom',
|
||||||
|
'importAssertions',
|
||||||
|
],
|
||||||
|
...parserOptions,
|
||||||
|
});
|
||||||
|
return ast;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combines all script tags as if it were one js file.
|
||||||
|
* @param {string} htmlCode
|
||||||
|
*/
|
||||||
|
static getScriptsFromHtml(htmlCode) {
|
||||||
|
const ast = parse5.parseFragment(htmlCode);
|
||||||
|
/**
|
||||||
|
* @type {string[]}
|
||||||
|
*/
|
||||||
|
const scripts = [];
|
||||||
|
traverseHtml(ast, {
|
||||||
|
/**
|
||||||
|
* @param {{ node: { childNodes: { value: any; }[]; }; }} path
|
||||||
|
*/
|
||||||
|
script(path) {
|
||||||
|
const code = path.node.childNodes[0] ? path.node.childNodes[0].value : '';
|
||||||
|
scripts.push(code);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return scripts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Babel AST
|
||||||
|
* @param { string } code
|
||||||
|
* @param { 'babel' } astType
|
||||||
|
* @param { {filePath?: PathFromSystemRoot} } options
|
||||||
|
* @returns {File|undefined}
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line consistent-return
|
||||||
|
static getAst(code, astType, { filePath } = {}) {
|
||||||
|
// eslint-disable-next-line default-case
|
||||||
|
try {
|
||||||
|
return this._getBabelAst(code);
|
||||||
|
} catch (e) {
|
||||||
|
LogService.error(`Error when parsing "${filePath}":/n${e}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { AstService };
|
||||||
|
|
@ -10,11 +10,13 @@ const { LogService } = require('./LogService.js');
|
||||||
const { AstService } = require('./AstService.js');
|
const { AstService } = require('./AstService.js');
|
||||||
const { getFilePathRelativeFromRoot } = require('../utils/get-file-path-relative-from-root.js');
|
const { getFilePathRelativeFromRoot } = require('../utils/get-file-path-relative-from-root.js');
|
||||||
const { toPosixPath } = require('../utils/to-posix-path.js');
|
const { toPosixPath } = require('../utils/to-posix-path.js');
|
||||||
|
const { memoize } = require('../utils/memoize.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('../types/analyzers').FindImportsAnalyzerResult} FindImportsAnalyzerResult
|
* @typedef {import('../types/analyzers').FindImportsAnalyzerResult} FindImportsAnalyzerResult
|
||||||
* @typedef {import('../types/analyzers').FindImportsAnalyzerEntry} FindImportsAnalyzerEntry
|
* @typedef {import('../types/analyzers').FindImportsAnalyzerEntry} FindImportsAnalyzerEntry
|
||||||
* @typedef {import('../types/core').PathRelativeFromProjectRoot} PathRelativeFromProjectRoot
|
* @typedef {import('../types/core').PathRelativeFromProjectRoot} PathRelativeFromProjectRoot
|
||||||
|
* @typedef {import('../types/core').PathRelative} PathRelative
|
||||||
* @typedef {import('../types/core').QueryConfig} QueryConfig
|
* @typedef {import('../types/core').QueryConfig} QueryConfig
|
||||||
* @typedef {import('../types/core').QueryResult} QueryResult
|
* @typedef {import('../types/core').QueryResult} QueryResult
|
||||||
* @typedef {import('../types/core').FeatureQueryConfig} FeatureQueryConfig
|
* @typedef {import('../types/core').FeatureQueryConfig} FeatureQueryConfig
|
||||||
|
|
@ -31,20 +33,15 @@ const { toPosixPath } = require('../utils/to-posix-path.js');
|
||||||
* @typedef {import('../types/core').ProjectInputDataWithMeta} ProjectInputDataWithMeta
|
* @typedef {import('../types/core').ProjectInputDataWithMeta} ProjectInputDataWithMeta
|
||||||
* @typedef {import('../types/core').Project} Project
|
* @typedef {import('../types/core').Project} Project
|
||||||
* @typedef {import('../types/core').ProjectName} ProjectName
|
* @typedef {import('../types/core').ProjectName} ProjectName
|
||||||
*/
|
* @typedef {import('../types/core').PackageJson} PackageJson
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {{path:PathFromSystemRoot; name:ProjectName}} ProjectNameAndPath
|
* @typedef {{path:PathFromSystemRoot; name:ProjectName}} ProjectNameAndPath
|
||||||
* @typedef {{name:ProjectName;files:PathRelativeFromProjectRoot[], workspaces:string[]}} PkgJson
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: memoize
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {PathFromSystemRoot} rootPath
|
* @typedef {(rootPath:PathFromSystemRoot) => PackageJson|undefined} GetPackageJsonFn
|
||||||
* @returns {PkgJson|undefined}
|
* @type {GetPackageJsonFn}
|
||||||
*/
|
*/
|
||||||
function getPackageJson(rootPath) {
|
const getPackageJson = memoize((/** @type {PathFromSystemRoot} */ rootPath) => {
|
||||||
try {
|
try {
|
||||||
const fileContent = fs.readFileSync(`${rootPath}/package.json`, 'utf8');
|
const fileContent = fs.readFileSync(`${rootPath}/package.json`, 'utf8');
|
||||||
return JSON.parse(fileContent);
|
return JSON.parse(fileContent);
|
||||||
|
|
@ -58,71 +55,75 @@ function getPackageJson(rootPath) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {PathFromSystemRoot} rootPath
|
* @typedef {(rootPath:PathFromSystemRoot) => object|undefined} GetLernaJsonFn
|
||||||
|
* @type {GetLernaJsonFn}
|
||||||
*/
|
*/
|
||||||
function getLernaJson(rootPath) {
|
const getLernaJson = memoize((/** @type {PathFromSystemRoot} */ rootPath) => {
|
||||||
try {
|
try {
|
||||||
const fileContent = fs.readFileSync(`${rootPath}/lerna.json`, 'utf8');
|
const fileContent = fs.readFileSync(`${rootPath}/lerna.json`, 'utf8');
|
||||||
return JSON.parse(fileContent);
|
return JSON.parse(fileContent);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @typedef {(list:PathFromSystemRoot[]|string[], rootPath:PathFromSystemRoot) => ProjectNameAndPath[]} GetPathsFromGlobListFn
|
||||||
* @param {PathFromSystemRoot[]|string[]} list
|
* @type {GetPathsFromGlobListFn}
|
||||||
* @param {PathFromSystemRoot} rootPath
|
|
||||||
* @returns {ProjectNameAndPath[]}
|
|
||||||
*/
|
*/
|
||||||
function getPathsFromGlobList(list, rootPath) {
|
const getPathsFromGlobList = memoize(
|
||||||
/** @type {string[]} */
|
(
|
||||||
const results = [];
|
/** @type {PathFromSystemRoot[]|string[]} */ list,
|
||||||
list.forEach(pathOrGlob => {
|
/** @type {PathFromSystemRoot} */ rootPath,
|
||||||
if (!pathOrGlob.endsWith('/')) {
|
) => {
|
||||||
// eslint-disable-next-line no-param-reassign
|
/** @type {string[]} */
|
||||||
pathOrGlob = `${pathOrGlob}/`;
|
const results = [];
|
||||||
}
|
list.forEach(pathOrGlob => {
|
||||||
|
if (!pathOrGlob.endsWith('/')) {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
pathOrGlob = `${pathOrGlob}/`;
|
||||||
|
}
|
||||||
|
|
||||||
if (pathOrGlob.includes('*')) {
|
if (pathOrGlob.includes('*')) {
|
||||||
const globResults = glob.sync(pathOrGlob, { cwd: rootPath, absolute: false });
|
const globResults = glob.sync(pathOrGlob, { cwd: rootPath, absolute: false });
|
||||||
globResults.forEach(r => {
|
globResults.forEach(r => {
|
||||||
results.push(r);
|
results.push(r);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
results.push(pathOrGlob);
|
results.push(pathOrGlob);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return results.map(pkgPath => {
|
return results.map(pkgPath => {
|
||||||
const packageRoot = pathLib.resolve(rootPath, pkgPath);
|
const packageRoot = pathLib.resolve(rootPath, pkgPath);
|
||||||
const basename = pathLib.basename(pkgPath);
|
const basename = pathLib.basename(pkgPath);
|
||||||
const pkgJson = getPackageJson(/** @type {PathFromSystemRoot} */ (packageRoot));
|
const pkgJson = getPackageJson(/** @type {PathFromSystemRoot} */ (packageRoot));
|
||||||
const name = /** @type {ProjectName} */ ((pkgJson && pkgJson.name) || basename);
|
const name = /** @type {ProjectName} */ ((pkgJson && pkgJson.name) || basename);
|
||||||
return { name, path: /** @type {PathFromSystemRoot} */ (pkgPath) };
|
return { name, path: /** @type {PathFromSystemRoot} */ (pkgPath) };
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {PathFromSystemRoot} rootPath
|
* @typedef {(rootPath:PathFromSystemRoot) => string|undefined} GetGitignoreFileFn
|
||||||
* @returns {string|undefined}
|
* @type {GetGitignoreFileFn}
|
||||||
*/
|
*/
|
||||||
function getGitignoreFile(rootPath) {
|
const getGitignoreFile = memoize((/** @type {PathFromSystemRoot} */ rootPath) => {
|
||||||
try {
|
try {
|
||||||
return fs.readFileSync(`${rootPath}/.gitignore`, 'utf8');
|
return fs.readFileSync(`${rootPath}/.gitignore`, 'utf8');
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {PathFromSystemRoot} rootPath
|
* @typedef {(rootPath:PathFromSystemRoot) => string[]} GetGitIgnorePathsFn
|
||||||
* @returns {string[]}
|
* @type {GetGitIgnorePathsFn}
|
||||||
*/
|
*/
|
||||||
function getGitIgnorePaths(rootPath) {
|
const getGitIgnorePaths = memoize((/** @type {PathFromSystemRoot} */ rootPath) => {
|
||||||
const fileContent = getGitignoreFile(rootPath);
|
const fileContent = /** @type {string} */ (getGitignoreFile(rootPath));
|
||||||
if (!fileContent) {
|
if (!fileContent) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
@ -154,14 +155,14 @@ function getGitIgnorePaths(rootPath) {
|
||||||
return entry;
|
return entry;
|
||||||
});
|
});
|
||||||
return normalizedEntries;
|
return normalizedEntries;
|
||||||
}
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gives back all files and folders that need to be added to npm artifact
|
* Gives back all files and folders that need to be added to npm artifact
|
||||||
* @param {PathFromSystemRoot} rootPath
|
* @typedef {(rootPath:PathFromSystemRoot) => string[]} GetNpmPackagePathsFn
|
||||||
* @returns {string[]}
|
* @type {GetNpmPackagePathsFn}
|
||||||
*/
|
*/
|
||||||
function getNpmPackagePaths(rootPath) {
|
const getNpmPackagePaths = memoize((/** @type {PathFromSystemRoot} */ rootPath) => {
|
||||||
const pkgJson = getPackageJson(rootPath);
|
const pkgJson = getPackageJson(rootPath);
|
||||||
if (!pkgJson) {
|
if (!pkgJson) {
|
||||||
return [];
|
return [];
|
||||||
|
|
@ -176,7 +177,7 @@ function getNpmPackagePaths(rootPath) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
}
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {any|any[]} v
|
* @param {any|any[]} v
|
||||||
|
|
@ -189,22 +190,31 @@ function ensureArray(v) {
|
||||||
/**
|
/**
|
||||||
* @param {string|string[]} patterns
|
* @param {string|string[]} patterns
|
||||||
* @param {Partial<{keepDirs:boolean;root:string}>} [options]
|
* @param {Partial<{keepDirs:boolean;root:string}>} [options]
|
||||||
|
*
|
||||||
|
* @typedef {(patterns:string|string[], opts: {keepDirs?:boolean;root:string}) => string[]} MultiGlobSyncFn
|
||||||
|
* @type {MultiGlobSyncFn}
|
||||||
*/
|
*/
|
||||||
function multiGlobSync(patterns, { keepDirs = false, root } = {}) {
|
const multiGlobSync = memoize(
|
||||||
patterns = ensureArray(patterns);
|
(/** @type {string|string[]} */ patterns, { keepDirs = false, root } = {}) => {
|
||||||
const res = new Set();
|
patterns = ensureArray(patterns);
|
||||||
patterns.forEach(pattern => {
|
const res = new Set();
|
||||||
const files = glob.sync(pattern, { root });
|
patterns.forEach(pattern => {
|
||||||
files.forEach(filePath => {
|
const files = glob.sync(pattern, { root });
|
||||||
if (fs.lstatSync(filePath).isDirectory() && !keepDirs) {
|
files.forEach(filePath => {
|
||||||
return;
|
if (fs.lstatSync(filePath).isDirectory() && !keepDirs) {
|
||||||
}
|
return;
|
||||||
res.add(filePath);
|
}
|
||||||
|
res.add(filePath);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
return Array.from(res);
|
||||||
return Array.from(res);
|
},
|
||||||
}
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} localPathWithDotSlash
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
function stripDotSlashFromLocalPath(localPathWithDotSlash) {
|
function stripDotSlashFromLocalPath(localPathWithDotSlash) {
|
||||||
return localPathWithDotSlash.replace(/^\.\//, '');
|
return localPathWithDotSlash.replace(/^\.\//, '');
|
||||||
}
|
}
|
||||||
|
|
@ -241,9 +251,9 @@ function getStringOrObjectValOfExportMapEntry({ valObjOrStr, nodeResolveMode })
|
||||||
class InputDataService {
|
class InputDataService {
|
||||||
/**
|
/**
|
||||||
* Create an array of ProjectData
|
* Create an array of ProjectData
|
||||||
* @param {PathFromSystemRoot | ProjectInputData []} projectPaths
|
* @param {(PathFromSystemRoot|ProjectInputData)[]} projectPaths
|
||||||
* @param {Partial<GatherFilesConfig>} gatherFilesConfig
|
* @param {Partial<GatherFilesConfig>} gatherFilesConfig
|
||||||
* @returns {ProjectInputData[]}
|
* @returns {ProjectInputDataWithMeta[]}
|
||||||
*/
|
*/
|
||||||
static createDataObject(projectPaths, gatherFilesConfig = {}) {
|
static createDataObject(projectPaths, gatherFilesConfig = {}) {
|
||||||
/** @type {ProjectInputData[]} */
|
/** @type {ProjectInputData[]} */
|
||||||
|
|
@ -306,7 +316,7 @@ class InputDataService {
|
||||||
LogService.warn(/** @type {string} */ (e));
|
LogService.warn(/** @type {string} */ (e));
|
||||||
}
|
}
|
||||||
project.commitHash = this._getCommitHash(projectPath);
|
project.commitHash = this._getCommitHash(projectPath);
|
||||||
return /** @type {Project} */ (project);
|
return /** @type {Project} */ (Object.freeze(project));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -365,7 +375,7 @@ class InputDataService {
|
||||||
toPosixPath(projectObj.project.path),
|
toPosixPath(projectObj.project.path),
|
||||||
);
|
);
|
||||||
if (pathLib.extname(file) === '.html') {
|
if (pathLib.extname(file) === '.html') {
|
||||||
const extractedScripts = AstService.getScriptsFromHtml(code);
|
const extractedScripts = AstService.getScriptsFromHtml(/** @type {string} */ (code));
|
||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
extractedScripts.forEach((code, i) => {
|
extractedScripts.forEach((code, i) => {
|
||||||
newEntries.push({
|
newEntries.push({
|
||||||
|
|
@ -619,7 +629,7 @@ class InputDataService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {{[key:string]: string|object}} exports
|
* @param {{[key:string]: string|object|null}} exports
|
||||||
* @param {object} opts
|
* @param {object} opts
|
||||||
* @param {'default'|'development'|string} [opts.nodeResolveMode='default']
|
* @param {'default'|'development'|string} [opts.nodeResolveMode='default']
|
||||||
* @param {string} opts.packageRootPath
|
* @param {string} opts.packageRootPath
|
||||||
|
|
@ -688,7 +698,14 @@ class InputDataService {
|
||||||
return exportMapPaths;
|
return exportMapPaths;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputDataService.cacheDisabled = false;
|
// TODO: Remove memoizeConfig.isCacheDisabled this once whole providence uses cacheConfig instead of
|
||||||
|
// memoizeConfig.isCacheDisabled
|
||||||
|
// InputDataService.cacheDisabled = memoizeConfig.isCacheDisabled;
|
||||||
|
|
||||||
|
InputDataService.getProjectMeta = memoize(InputDataService.getProjectMeta);
|
||||||
|
InputDataService.gatherFilesFromDir = memoize(InputDataService.gatherFilesFromDir);
|
||||||
|
InputDataService.getMonoRepoPackages = memoize(InputDataService.getMonoRepoPackages);
|
||||||
|
InputDataService.createDataObject = memoize(InputDataService.createDataObject);
|
||||||
|
|
||||||
InputDataService.getPackageJson = getPackageJson;
|
InputDataService.getPackageJson = getPackageJson;
|
||||||
|
|
||||||
|
|
@ -1,12 +1,7 @@
|
||||||
const pathLib = require('path');
|
const pathLib = require('path');
|
||||||
const chalk = require('chalk');
|
const chalk = require('chalk');
|
||||||
const ora = require('ora');
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('ora').Ora} Ora
|
|
||||||
*/
|
|
||||||
|
|
||||||
const { log } = console;
|
const { log } = console;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -17,9 +12,6 @@ function printTitle(title) {
|
||||||
return `${title ? `${title}\n` : ''}`;
|
return `${title ? `${title}\n` : ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {Ora} */
|
|
||||||
let spinner;
|
|
||||||
|
|
||||||
class LogService {
|
class LogService {
|
||||||
/**
|
/**
|
||||||
* @param {string} text
|
* @param {string} text
|
||||||
|
|
@ -89,39 +81,12 @@ class LogService {
|
||||||
static info(text, title) {
|
static info(text, title) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this._logHistory.push(`- info -${printTitle(title)} ${text}`);
|
this._logHistory.push(`- info -${printTitle(title)} ${text}`);
|
||||||
|
|
||||||
if (this.allMuted) {
|
if (this.allMuted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log(chalk.bgBlue.black.bold(` info${printTitle(title)}`), text);
|
log(chalk.bgBlue.black.bold(` info${printTitle(title)}`), text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} text
|
|
||||||
*/
|
|
||||||
static spinnerStart(text) {
|
|
||||||
spinner = ora(text).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} text
|
|
||||||
*/
|
|
||||||
static spinnerText(text) {
|
|
||||||
if (!spinner) {
|
|
||||||
this.spinnerStart(text);
|
|
||||||
}
|
|
||||||
spinner.text = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
static spinnerStop() {
|
|
||||||
spinner.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
static get spinner() {
|
|
||||||
return spinner;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} text
|
* @param {string} text
|
||||||
* @param {number} minChars
|
* @param {number} minChars
|
||||||
|
|
@ -3,6 +3,7 @@ const child_process = require('child_process'); // eslint-disable-line camelcase
|
||||||
const { AstService } = require('./AstService.js');
|
const { AstService } = require('./AstService.js');
|
||||||
const { LogService } = require('./LogService.js');
|
const { LogService } = require('./LogService.js');
|
||||||
const { getFilePathRelativeFromRoot } = require('../utils/get-file-path-relative-from-root.js');
|
const { getFilePathRelativeFromRoot } = require('../utils/get-file-path-relative-from-root.js');
|
||||||
|
const { memoize } = require('../utils/memoize.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('../types/analyzers').FindImportsAnalyzerResult} FindImportsAnalyzerResult
|
* @typedef {import('../types/analyzers').FindImportsAnalyzerResult} FindImportsAnalyzerResult
|
||||||
|
|
@ -31,6 +32,9 @@ class QueryService {
|
||||||
* @returns {SearchQueryConfig}
|
* @returns {SearchQueryConfig}
|
||||||
*/
|
*/
|
||||||
static getQueryConfigFromRegexSearchString(regexString) {
|
static getQueryConfigFromRegexSearchString(regexString) {
|
||||||
|
if (typeof regexString !== 'string') {
|
||||||
|
throw new Error('[QueryService.getQueryConfigFromRegexSearchString]: provide a string');
|
||||||
|
}
|
||||||
return { type: 'search', regexString };
|
return { type: 'search', regexString };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,8 +48,13 @@ class QueryService {
|
||||||
* @returns {FeatureQueryConfig}
|
* @returns {FeatureQueryConfig}
|
||||||
*/
|
*/
|
||||||
static getQueryConfigFromFeatureString(queryString) {
|
static getQueryConfigFromFeatureString(queryString) {
|
||||||
|
if (typeof queryString !== 'string') {
|
||||||
|
throw new Error('[QueryService.getQueryConfigFromFeatureString]: provide a string');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} candidate
|
* Each candidate (tag, attrKey or attrValue) can end with asterisk.
|
||||||
|
* @param {string} candidate for my-*[attr*=x*] 'my-*', 'attr*' or 'x*'
|
||||||
* @returns {[string, boolean]}
|
* @returns {[string, boolean]}
|
||||||
*/
|
*/
|
||||||
function parseContains(candidate) {
|
function parseContains(candidate) {
|
||||||
|
|
@ -59,12 +68,12 @@ class QueryService {
|
||||||
let featString;
|
let featString;
|
||||||
|
|
||||||
// Creates tag ('tg-icon') and featString ('font-icon+size=xs')
|
// Creates tag ('tg-icon') and featString ('font-icon+size=xs')
|
||||||
const match = queryString.match(/(^.*)(\[(.+)\])+/);
|
const attrMatch = queryString.match(/(^.*)(\[(.+)\])+/);
|
||||||
if (match) {
|
if (attrMatch) {
|
||||||
// eslint-disable-next-line prefer-destructuring
|
// eslint-disable-next-line prefer-destructuring
|
||||||
tagCandidate = match[1];
|
tagCandidate = attrMatch[1];
|
||||||
// eslint-disable-next-line prefer-destructuring
|
// eslint-disable-next-line prefer-destructuring
|
||||||
featString = match[3];
|
featString = attrMatch[3];
|
||||||
} else {
|
} else {
|
||||||
tagCandidate = queryString;
|
tagCandidate = queryString;
|
||||||
}
|
}
|
||||||
|
|
@ -94,9 +103,9 @@ class QueryService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RSetrieves the default export found in ./program/analyzers/findImport.js
|
* Retrieves the default export found in ./program/analyzers/find-import.js
|
||||||
* @param {string|Analyzer} analyzerObjectOrString
|
* @param {string|typeof Analyzer} analyzerObjectOrString
|
||||||
* @param {AnalyzerConfig} analyzerConfig
|
* @param {AnalyzerConfig} [analyzerConfig]
|
||||||
* @returns {AnalyzerQueryConfig}
|
* @returns {AnalyzerQueryConfig}
|
||||||
*/
|
*/
|
||||||
static getQueryConfigFromAnalyzer(analyzerObjectOrString, analyzerConfig) {
|
static getQueryConfigFromAnalyzer(analyzerObjectOrString, analyzerConfig) {
|
||||||
|
|
@ -108,28 +117,26 @@ class QueryService {
|
||||||
// eslint-disable-next-line import/no-dynamic-require, global-require
|
// eslint-disable-next-line import/no-dynamic-require, global-require
|
||||||
analyzer = /** @type {Analyzer} */ (require(`../analyzers/${analyzerObjectOrString}`));
|
analyzer = /** @type {Analyzer} */ (require(`../analyzers/${analyzerObjectOrString}`));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
LogService.error(e);
|
LogService.error(e.toString());
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We don't need to import the analyzer, since we already have it
|
// We don't need to import the analyzer, since we already have it
|
||||||
analyzer = analyzerObjectOrString;
|
analyzer = analyzerObjectOrString;
|
||||||
}
|
}
|
||||||
return {
|
return /** @type {AnalyzerQueryConfig} */ ({
|
||||||
type: 'ast-analyzer',
|
type: 'ast-analyzer',
|
||||||
analyzerName: /** @type {AnalyzerName} */ (analyzer.name),
|
analyzerName: /** @type {AnalyzerName} */ (analyzer.analyzerName),
|
||||||
analyzerConfig,
|
analyzerConfig,
|
||||||
analyzer,
|
analyzer,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Search via unix grep
|
* Search via unix grep
|
||||||
* @param {InputData} inputData
|
* @param {InputData} inputData
|
||||||
* @param {QueryConfig} queryConfig
|
* @param {FeatureQueryConfig|SearchQueryConfig} queryConfig
|
||||||
* @param {object} [customConfig]
|
* @param {{hasVerboseReporting:boolean;gatherFilesConfig:GatherFilesConfig}} [customConfig]
|
||||||
* @param {boolean} [customConfig.hasVerboseReporting]
|
|
||||||
* @param {object} [customConfig.gatherFilesConfig]
|
|
||||||
* @returns {Promise<QueryResult>}
|
* @returns {Promise<QueryResult>}
|
||||||
*/
|
*/
|
||||||
static async grepSearch(inputData, queryConfig, customConfig) {
|
static async grepSearch(inputData, queryConfig, customConfig) {
|
||||||
|
|
@ -190,7 +197,7 @@ class QueryService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search via ast (typescript compilation)
|
* Perform ast analysis
|
||||||
* @param {AnalyzerQueryConfig} analyzerQueryConfig
|
* @param {AnalyzerQueryConfig} analyzerQueryConfig
|
||||||
* @param {AnalyzerConfig} [customConfig]
|
* @param {AnalyzerConfig} [customConfig]
|
||||||
* @returns {Promise<AnalyzerQueryResult>}
|
* @returns {Promise<AnalyzerQueryResult>}
|
||||||
|
|
@ -341,4 +348,6 @@ class QueryService {
|
||||||
}
|
}
|
||||||
QueryService.cacheDisabled = false;
|
QueryService.cacheDisabled = false;
|
||||||
|
|
||||||
|
QueryService.addAstToProjectsData = memoize(QueryService.addAstToProjectsData);
|
||||||
|
|
||||||
module.exports = { QueryService };
|
module.exports = { QueryService };
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const pathLib = require('path');
|
const pathLib = require('path');
|
||||||
const getHash = require('../utils/get-hash.js');
|
const getHash = require('../utils/get-hash.js');
|
||||||
|
const { memoize } = require('../utils/memoize.js');
|
||||||
|
// const memoize = fn => fn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('../types/core').Project} Project
|
* @typedef {import('../types/core').Project} Project
|
||||||
|
|
@ -60,6 +62,7 @@ class ReportService {
|
||||||
}
|
}
|
||||||
const { name } = queryResult.meta.analyzerMeta;
|
const { name } = queryResult.meta.analyzerMeta;
|
||||||
const filePath = this._getResultFileNameAndPath(name, identifier);
|
const filePath = this._getResultFileNameAndPath(name, identifier);
|
||||||
|
|
||||||
fs.writeFileSync(filePath, output, { flag: 'w' });
|
fs.writeFileSync(filePath, output, { flag: 'w' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,5 +128,7 @@ class ReportService {
|
||||||
fs.writeFileSync(filePath, JSON.stringify(file, null, 2), { flag: 'w' });
|
fs.writeFileSync(filePath, JSON.stringify(file, null, 2), { flag: 'w' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ReportService.createIdentifier = memoize(ReportService.createIdentifier);
|
||||||
|
ReportService.getCachedResult = memoize(ReportService.getCachedResult);
|
||||||
|
|
||||||
module.exports = { ReportService };
|
module.exports = { ReportService };
|
||||||
|
|
@ -1,12 +1,25 @@
|
||||||
|
const { performance } = require('perf_hooks');
|
||||||
const deepmerge = require('deepmerge');
|
const deepmerge = require('deepmerge');
|
||||||
const { ReportService } = require('./services/ReportService.js');
|
const { ReportService } = require('./core/ReportService.js');
|
||||||
const { InputDataService } = require('./services/InputDataService.js');
|
const { InputDataService } = require('./core/InputDataService.js');
|
||||||
const { LogService } = require('./services/LogService.js');
|
const { LogService } = require('./core/LogService.js');
|
||||||
const { QueryService } = require('./services/QueryService.js');
|
const { QueryService } = require('./core/QueryService.js');
|
||||||
const { aForEach } = require('./utils/async-array-utils.js');
|
|
||||||
|
|
||||||
// After handling a combo, we should know which project versions we have, since
|
/**
|
||||||
// the analyzer internally called createDataObject(which provides us the needed meta info).
|
* @typedef {import('./types/core').ProvidenceConfig} ProvidenceConfig
|
||||||
|
* @typedef {import('./types/core').PathFromSystemRoot} PathFromSystemRoot
|
||||||
|
* @typedef {import('./types/core').QueryResult} QueryResult
|
||||||
|
* @typedef {import('./types/core').AnalyzerQueryResult} AnalyzerQueryResult
|
||||||
|
* @typedef {import('./types/core').QueryConfig} QueryConfig
|
||||||
|
* @typedef {import('./types/core').AnalyzerQueryConfig} AnalyzerQueryConfig
|
||||||
|
* @typedef {import('./types/core').GatherFilesConfig} GatherFilesConfig
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After handling a combo, we should know which project versions we have, since
|
||||||
|
* the analyzer internally called createDataObject(which provides us the needed meta info).
|
||||||
|
* @param {{queryResult: AnalyzerQueryResult; queryConfig: AnalyzerQueryConfig; providenceConfig: ProvidenceConfig}} opts
|
||||||
|
*/
|
||||||
function addToSearchTargetDepsFile({ queryResult, queryConfig, providenceConfig }) {
|
function addToSearchTargetDepsFile({ queryResult, queryConfig, providenceConfig }) {
|
||||||
const currentSearchTarget = queryConfig.analyzerConfig.targetProjectPath;
|
const currentSearchTarget = queryConfig.analyzerConfig.targetProjectPath;
|
||||||
// eslint-disable-next-line array-callback-return, consistent-return
|
// eslint-disable-next-line array-callback-return, consistent-return
|
||||||
|
|
@ -26,6 +39,10 @@ function addToSearchTargetDepsFile({ queryResult, queryConfig, providenceConfig
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AnalyzerQueryResult} queryResult
|
||||||
|
* @param {{outputPath:PathFromSystemRoot;report:boolean}} cfg
|
||||||
|
*/
|
||||||
function report(queryResult, cfg) {
|
function report(queryResult, cfg) {
|
||||||
if (cfg.report && !queryResult.meta.analyzerMeta.__fromCache) {
|
if (cfg.report && !queryResult.meta.analyzerMeta.__fromCache) {
|
||||||
const { identifier } = queryResult.meta.analyzerMeta;
|
const { identifier } = queryResult.meta.analyzerMeta;
|
||||||
|
|
@ -35,12 +52,13 @@ function report(queryResult, cfg) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates unique QueryConfig for analyzer turn
|
* Creates unique QueryConfig for analyzer turn
|
||||||
* @param {QueryConfig} queryConfig
|
* @param {AnalyzerQueryConfig} queryConfig
|
||||||
* @param {string} targetProjectPath
|
* @param {PathFromSystemRoot} targetProjectPath
|
||||||
* @param {string} referenceProjectPath
|
* @param {PathFromSystemRoot} referenceProjectPath
|
||||||
|
* @returns {Partial<AnalyzerQueryResult>}
|
||||||
*/
|
*/
|
||||||
function getSlicedQueryConfig(queryConfig, targetProjectPath, referenceProjectPath) {
|
function getSlicedQueryConfig(queryConfig, targetProjectPath, referenceProjectPath) {
|
||||||
return {
|
return /** @type {Partial<AnalyzerQueryResult>} */ ({
|
||||||
...queryConfig,
|
...queryConfig,
|
||||||
...{
|
...{
|
||||||
analyzerConfig: {
|
analyzerConfig: {
|
||||||
|
|
@ -51,19 +69,20 @@ function getSlicedQueryConfig(queryConfig, targetProjectPath, referenceProjectPa
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc definition "projectCombo": referenceProject#version + searchTargetProject#version
|
* Definition "projectCombo": referenceProject#version + searchTargetProject#version
|
||||||
* @param {QueryConfig} slicedQConfig
|
* @param {AnalyzerQueryConfig} slicedQConfig
|
||||||
* @param {cfg} object
|
* @param {{ gatherFilesConfig:GatherFilesConfig, gatherFilesConfigReference:GatherFilesConfig, skipCheckMatchCompatibility:boolean }} cfg
|
||||||
*/
|
*/
|
||||||
async function handleAnalyzerForProjectCombo(slicedQConfig, cfg) {
|
async function handleAnalyzerForProjectCombo(slicedQConfig, cfg) {
|
||||||
const queryResult = await QueryService.astSearch(slicedQConfig, {
|
const queryResult = await QueryService.astSearch(slicedQConfig, {
|
||||||
gatherFilesConfig: cfg.gatherFilesConfig,
|
gatherFilesConfig: cfg.gatherFilesConfig,
|
||||||
gatherFilesConfigReference: cfg.gatherFilesConfigReference,
|
gatherFilesConfigReference: cfg.gatherFilesConfigReference,
|
||||||
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
skipCheckMatchCompatibility: cfg.skipCheckMatchCompatibility,
|
||||||
|
addSystemPathsInResult: cfg.addSystemPathsInResult,
|
||||||
...slicedQConfig.analyzerConfig,
|
...slicedQConfig.analyzerConfig,
|
||||||
});
|
});
|
||||||
if (queryResult) {
|
if (queryResult) {
|
||||||
|
|
@ -73,7 +92,7 @@ async function handleAnalyzerForProjectCombo(slicedQConfig, cfg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Here, we will match all our reference projects (exports) against all our search targets
|
* Here, we will match all our reference projects (exports) against all our search targets
|
||||||
* (imports).
|
* (imports).
|
||||||
*
|
*
|
||||||
* This is an expensive operation. Therefore, we allow caching.
|
* This is an expensive operation. Therefore, we allow caching.
|
||||||
|
|
@ -88,16 +107,16 @@ async function handleAnalyzerForProjectCombo(slicedQConfig, cfg) {
|
||||||
* All the json outputs can be aggregated in our dashboard and visually presented in
|
* All the json outputs can be aggregated in our dashboard and visually presented in
|
||||||
* various ways.
|
* various ways.
|
||||||
*
|
*
|
||||||
* @param {QueryConfig} queryConfig
|
* @param {AnalyzerQueryConfig} queryConfig
|
||||||
* @param {ProvidenceConfig} cfg
|
* @param {Partial<ProvidenceConfig>} cfg
|
||||||
*/
|
*/
|
||||||
async function handleAnalyzer(queryConfig, cfg) {
|
async function handleAnalyzer(queryConfig, cfg) {
|
||||||
const queryResults = [];
|
const queryResults = [];
|
||||||
const { referenceProjectPaths, targetProjectPaths } = cfg;
|
const { referenceProjectPaths, targetProjectPaths } = cfg;
|
||||||
|
|
||||||
await aForEach(targetProjectPaths, async searchTargetProject => {
|
for (const searchTargetProject of targetProjectPaths) {
|
||||||
if (referenceProjectPaths) {
|
if (referenceProjectPaths) {
|
||||||
await aForEach(referenceProjectPaths, async ref => {
|
for (const ref of referenceProjectPaths) {
|
||||||
// Create shallow cfg copy with just currrent reference folder
|
// Create shallow cfg copy with just currrent reference folder
|
||||||
const slicedQueryConfig = getSlicedQueryConfig(queryConfig, searchTargetProject, ref);
|
const slicedQueryConfig = getSlicedQueryConfig(queryConfig, searchTargetProject, ref);
|
||||||
const queryResult = await handleAnalyzerForProjectCombo(slicedQueryConfig, cfg);
|
const queryResult = await handleAnalyzerForProjectCombo(slicedQueryConfig, cfg);
|
||||||
|
|
@ -109,7 +128,7 @@ async function handleAnalyzer(queryConfig, cfg) {
|
||||||
providenceConfig: cfg,
|
providenceConfig: cfg,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
} else {
|
} else {
|
||||||
const slicedQueryConfig = getSlicedQueryConfig(queryConfig, searchTargetProject);
|
const slicedQueryConfig = getSlicedQueryConfig(queryConfig, searchTargetProject);
|
||||||
const queryResult = await handleAnalyzerForProjectCombo(slicedQueryConfig, cfg);
|
const queryResult = await handleAnalyzerForProjectCombo(slicedQueryConfig, cfg);
|
||||||
|
|
@ -122,7 +141,7 @@ async function handleAnalyzer(queryConfig, cfg) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return queryResults;
|
return queryResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -149,40 +168,37 @@ async function handleRegexSearch(queryConfig, cfg, inputData) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Creates a report with usage metrics, based on a queryConfig.
|
* Creates a report with usage metrics, based on a queryConfig.
|
||||||
*
|
*
|
||||||
* @param {QueryConfig} queryConfig a query configuration object containing analyzerOptions.
|
* @param {QueryConfig} queryConfig a query configuration object containing analyzerOptions.
|
||||||
* @param {object} customConfig
|
* @param {Partial<ProvidenceConfig>} customConfig
|
||||||
* @param {'ast'|'grep'} customConfig.queryMethod whether analyzer should be run or a grep should
|
|
||||||
* be performed
|
|
||||||
* @param {string[]} customConfig.targetProjectPaths search target projects. For instance
|
|
||||||
* ['/path/to/app-a', '/path/to/app-b', ... '/path/to/app-z']
|
|
||||||
* @param {string[]} [customConfig.referenceProjectPaths] reference projects. Needed for 'match
|
|
||||||
* analyzers', having `requiresReference: true`. For instance
|
|
||||||
* ['/path/to/lib1', '/path/to/lib2']
|
|
||||||
* @param {GatherFilesConfig} [customConfig.gatherFilesConfig]
|
|
||||||
* @param {boolean} [customConfig.report]
|
|
||||||
* @param {boolean} [customConfig.debugEnabled]
|
|
||||||
*/
|
*/
|
||||||
async function providenceMain(queryConfig, customConfig) {
|
async function providenceMain(queryConfig, customConfig) {
|
||||||
const cfg = deepmerge(
|
const tStart = performance.now();
|
||||||
{
|
|
||||||
queryMethod: 'grep',
|
const cfg = /** @type {ProvidenceConfig} */ (
|
||||||
// This is a merge of all 'main entry projects'
|
deepmerge(
|
||||||
// found in search-targets, including their children
|
{
|
||||||
targetProjectPaths: null,
|
queryMethod: 'grep',
|
||||||
referenceProjectPaths: null,
|
// This is a merge of all 'main entry projects'
|
||||||
// This will be needed to identify the parent/child relationship to write to
|
// found in search-targets, including their children
|
||||||
// {outputFolder}/entryProjectDependencies.json, which will map
|
targetProjectPaths: null,
|
||||||
// a project#version to [ depA#version, depB#version ]
|
referenceProjectPaths: null,
|
||||||
targetProjectRootPaths: null,
|
// This will be needed to identify the parent/child relationship to write to
|
||||||
gatherFilesConfig: {},
|
// {outputFolder}/entryProjectDependencies.json, which will map
|
||||||
report: true,
|
// a project#version to [ depA#version, depB#version ]
|
||||||
debugEnabled: false,
|
targetProjectRootPaths: null,
|
||||||
writeLogFile: false,
|
gatherFilesConfig: {},
|
||||||
skipCheckMatchCompatibility: false,
|
report: true,
|
||||||
},
|
debugEnabled: false,
|
||||||
customConfig,
|
writeLogFile: false,
|
||||||
|
skipCheckMatchCompatibility: false,
|
||||||
|
measurePerformance: false,
|
||||||
|
/** Allows to navigate to source file in code editor */
|
||||||
|
addSystemPathsInResult: false,
|
||||||
|
},
|
||||||
|
customConfig,
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (cfg.debugEnabled) {
|
if (cfg.debugEnabled) {
|
||||||
|
|
@ -215,6 +231,12 @@ async function providenceMain(queryConfig, customConfig) {
|
||||||
LogService.writeLogFile();
|
LogService.writeLogFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tEnd = performance.now();
|
||||||
|
|
||||||
|
if (cfg.measurePerformance) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`completed in ${((tEnd - tStart) / 1000).toFixed(2)} seconds`);
|
||||||
|
}
|
||||||
return queryResults;
|
return queryResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
// @ts-nocheck
|
|
||||||
const {
|
|
||||||
createProgram,
|
|
||||||
getPreEmitDiagnostics,
|
|
||||||
ModuleKind,
|
|
||||||
ModuleResolutionKind,
|
|
||||||
ScriptTarget,
|
|
||||||
} = require('typescript');
|
|
||||||
const babelParser = require('@babel/parser');
|
|
||||||
// @ts-expect-error
|
|
||||||
const esModuleLexer = require('es-module-lexer');
|
|
||||||
const parse5 = require('parse5');
|
|
||||||
const traverseHtml = require('../utils/traverse-html.js');
|
|
||||||
const { LogService } = require('./LogService.js');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('../types/core').PathFromSystemRoot} PathFromSystemRoot
|
|
||||||
*/
|
|
||||||
|
|
||||||
class AstService {
|
|
||||||
/**
|
|
||||||
* @deprecated for simplicity/maintainability, only allow Babel for js
|
|
||||||
* Compiles an array of file paths using Typescript.
|
|
||||||
* @param {string[]} filePaths
|
|
||||||
* @param {CompilerOptions} options
|
|
||||||
*/
|
|
||||||
static _getTypescriptAst(filePaths, options) {
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
|
||||||
filePaths = Array.isArray(filePaths) ? filePaths : [filePaths];
|
|
||||||
|
|
||||||
const defaultOptions = {
|
|
||||||
noEmitOnError: false,
|
|
||||||
allowJs: true,
|
|
||||||
experimentalDecorators: true,
|
|
||||||
target: ScriptTarget.Latest,
|
|
||||||
downlevelIteration: true,
|
|
||||||
module: ModuleKind.ESNext,
|
|
||||||
// module: ModuleKind.CommonJS,
|
|
||||||
// lib: ["esnext", "dom"],
|
|
||||||
strictNullChecks: true,
|
|
||||||
moduleResolution: ModuleResolutionKind.NodeJs,
|
|
||||||
esModuleInterop: true,
|
|
||||||
noEmit: true,
|
|
||||||
allowSyntheticDefaultImports: true,
|
|
||||||
allowUnreachableCode: true,
|
|
||||||
allowUnusedLabels: true,
|
|
||||||
skipLibCheck: true,
|
|
||||||
isolatedModules: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
const program = createProgram(filePaths, options || defaultOptions);
|
|
||||||
const diagnostics = getPreEmitDiagnostics(program);
|
|
||||||
const files = program.getSourceFiles().filter(sf => filePaths.includes(sf.fileName));
|
|
||||||
return { diagnostics, program, files };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compiles an array of file paths using Babel.
|
|
||||||
* @param {string} code
|
|
||||||
*/
|
|
||||||
static _getBabelAst(code) {
|
|
||||||
const ast = babelParser.parse(code, {
|
|
||||||
sourceType: 'module',
|
|
||||||
plugins: [
|
|
||||||
'importMeta',
|
|
||||||
'dynamicImport',
|
|
||||||
'classProperties',
|
|
||||||
'exportDefaultFrom',
|
|
||||||
'importAssertions',
|
|
||||||
],
|
|
||||||
});
|
|
||||||
return ast;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Combines all script tags as if it were one js file.
|
|
||||||
* @param {string} htmlCode
|
|
||||||
*/
|
|
||||||
static getScriptsFromHtml(htmlCode) {
|
|
||||||
const ast = parse5.parseFragment(htmlCode);
|
|
||||||
const scripts = [];
|
|
||||||
traverseHtml(ast, {
|
|
||||||
script(path) {
|
|
||||||
const code = path.node.childNodes[0] ? path.node.childNodes[0].value : '';
|
|
||||||
scripts.push(code);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return scripts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated for simplicity/maintainability, only allow Babel for js
|
|
||||||
* @param {string} code
|
|
||||||
*/
|
|
||||||
static async _getEsModuleLexerOutput(code) {
|
|
||||||
return esModuleLexer.parse(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the desired AST
|
|
||||||
* Why would we support multiple ASTs/parsers?
|
|
||||||
* - 'babel' is our default tool for analysis. It's the most versatile and popular tool, it's
|
|
||||||
* close to the EStree standard (other than Typescript) and a lot of plugins and resources can
|
|
||||||
* be found online. It also allows to parse Typescript and spec proposals.
|
|
||||||
* - 'typescript' (deprecated) is needed for some valuable third party tooling, like web-component-analyzer
|
|
||||||
* - 'es-module-lexer' (deprecated) is needed for the dedicated task of finding module imports; it is way
|
|
||||||
* quicker than a full fledged AST parser
|
|
||||||
* @param { 'babel' } astType
|
|
||||||
* @param { {filePath: PathFromSystemRoot} } [options]
|
|
||||||
*/
|
|
||||||
// eslint-disable-next-line consistent-return
|
|
||||||
static getAst(code, astType, { filePath } = {}) {
|
|
||||||
// eslint-disable-next-line default-case
|
|
||||||
try {
|
|
||||||
// eslint-disable-next-line default-case
|
|
||||||
switch (astType) {
|
|
||||||
case 'babel':
|
|
||||||
return this._getBabelAst(code);
|
|
||||||
case 'typescript':
|
|
||||||
LogService.warn(`
|
|
||||||
Please notice "typescript" support is deprecated.
|
|
||||||
For parsing javascript, "babel" is recommended.`);
|
|
||||||
return this._getTypescriptAst(code);
|
|
||||||
case 'es-module-lexer':
|
|
||||||
LogService.warn(`
|
|
||||||
Please notice "es-module-lexer" support is deprecated.
|
|
||||||
For parsing javascript, "babel" is recommended.`);
|
|
||||||
return this._getEsModuleLexerOutput(code);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
LogService.error(`Error when parsing "${filePath}":/n${e}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { AstService };
|
|
||||||
|
|
@ -8,6 +8,7 @@ import {
|
||||||
Project,
|
Project,
|
||||||
GatherFilesConfig,
|
GatherFilesConfig,
|
||||||
SpecifierName,
|
SpecifierName,
|
||||||
|
QueryOutput,
|
||||||
} from './index';
|
} from './index';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -27,21 +28,23 @@ export interface Meta {
|
||||||
export interface AnalyzerMeta {
|
export interface AnalyzerMeta {
|
||||||
name: AnalyzerName;
|
name: AnalyzerName;
|
||||||
requiredAst: RequiredAst;
|
requiredAst: RequiredAst;
|
||||||
/** a unique hash based on target, reference and configuration */
|
/* a unique hash based on target, reference and configuration */
|
||||||
identifier: ImportOrExportId;
|
identifier: ImportOrExportId;
|
||||||
/** target project meta object */
|
/* target project meta object */
|
||||||
targetProject: Project;
|
targetProject: Project;
|
||||||
/** reference project meta object */
|
/* reference project meta object */
|
||||||
referenceProject?: Project;
|
referenceProject?: Project;
|
||||||
/** the configuration used for this particular analyzer run */
|
/* the configuration used for this particular analyzer run */
|
||||||
configuration: object;
|
configuration: object;
|
||||||
|
/* whether it was cached in file system or not */
|
||||||
|
__fromCache?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AnalyzerQueryResult extends QueryResult {
|
export interface AnalyzerQueryResult extends QueryResult {
|
||||||
/** meta info object */
|
/** meta info object */
|
||||||
meta: Meta;
|
meta: Meta;
|
||||||
/** array of AST traversal output, per project file */
|
/** array of AST traversal output, per project file */
|
||||||
queryOutput: any[];
|
queryOutput: QueryOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FindAnalyzerQueryResult extends AnalyzerQueryResult {
|
export interface FindAnalyzerQueryResult extends AnalyzerQueryResult {
|
||||||
|
|
@ -58,7 +61,9 @@ export interface FindAnalyzerOutputFile {
|
||||||
export interface AnalyzerConfig {
|
export interface AnalyzerConfig {
|
||||||
/** search target project path */
|
/** search target project path */
|
||||||
targetProjectPath: PathFromSystemRoot;
|
targetProjectPath: PathFromSystemRoot;
|
||||||
gatherFilesConfig: GatherFilesConfig;
|
gatherFilesConfig?: GatherFilesConfig;
|
||||||
|
gatherFilesConfigReference?: GatherFilesConfig;
|
||||||
|
skipCheckMatchCompatibility?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MatchAnalyzerConfig extends AnalyzerConfig {
|
export interface MatchAnalyzerConfig extends AnalyzerConfig {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { AnalyzerName, Feature, AnalyzerConfig, PathRelativeFromProjectRoot } from './index';
|
import { AnalyzerName, Feature, AnalyzerConfig, PathRelativeFromProjectRoot } from './index';
|
||||||
import { Analyzer } from '../../analyzers/helpers/Analyzer';
|
import { Analyzer } from '../../core/Analyzer';
|
||||||
export { Analyzer } from '../../analyzers/helpers/Analyzer';
|
export { Analyzer } from '../../core/Analyzer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type of the query. Currently only "ast-analyzer" supported
|
* Type of the query. Currently only "ast-analyzer" supported
|
||||||
|
|
@ -38,7 +38,7 @@ export interface QueryOutputEntry {
|
||||||
file: PathRelativeFromProjectRoot;
|
file: PathRelativeFromProjectRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type QueryOutput = QueryOutputEntry[];
|
export type QueryOutput = QueryOutputEntry[] | '[no-dependency]' | '[no-matched-version]';
|
||||||
|
|
||||||
export interface QueryResult {
|
export interface QueryResult {
|
||||||
queryOutput: QueryOutput;
|
queryOutput: QueryOutput;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { File } from '@babel/types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of a variable in a local context. Examples:
|
* The name of a variable in a local context. Examples:
|
||||||
* - 'b': (`import {a as b } from 'c';`)
|
* - 'b': (`import {a as b } from 'c';`)
|
||||||
|
|
@ -140,6 +142,11 @@ export interface ProjectInputDataWithMeta {
|
||||||
project: Project;
|
project: Project;
|
||||||
entries: { file: PathRelativeFromProjectRoot; context: { code: string } }[];
|
entries: { file: PathRelativeFromProjectRoot; context: { code: string } }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ProjectInputDataWithAstMeta extends ProjectInputDataWithMeta {
|
||||||
|
entries: { file: PathRelativeFromProjectRoot; ast: File; context: { code: string } }[];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See: https://www.npmjs.com/package/anymatch
|
* See: https://www.npmjs.com/package/anymatch
|
||||||
* Allows negations as well. See: https://www.npmjs.com/package/is-negated-glob
|
* Allows negations as well. See: https://www.npmjs.com/package/is-negated-glob
|
||||||
|
|
@ -149,3 +156,33 @@ export interface ProjectInputDataWithMeta {
|
||||||
* - 'scripts/vendor/react.js'
|
* - 'scripts/vendor/react.js'
|
||||||
*/
|
*/
|
||||||
export type AnyMatchString = string;
|
export type AnyMatchString = string;
|
||||||
|
|
||||||
|
export type ProvidenceConfig = {
|
||||||
|
/* Whether analyzer should be run or a grep should be performed */
|
||||||
|
queryMethod: 'ast' | 'grep';
|
||||||
|
/* Search target projects. For instance ['/path/to/app-a', '/path/to/app-b', ... '/path/to/app-z'] */
|
||||||
|
targetProjectPaths: PathFromSystemRoot[];
|
||||||
|
/* Reference projects. Needed for 'match analyzers', having `requiresReference: true`. For instance ['/path/to/lib1', '/path/to/lib2'] */
|
||||||
|
referenceProjectPaths: PathFromSystemRoot[];
|
||||||
|
/* When targetProjectPaths are dependencies of other projects (their 'roots') */
|
||||||
|
targetProjectRootPaths: PathFromSystemRoot[];
|
||||||
|
gatherFilesConfig: GatherFilesConfig;
|
||||||
|
gatherFilesConfigReference: GatherFilesConfig;
|
||||||
|
report: boolean;
|
||||||
|
debugEnabled: boolean;
|
||||||
|
measurePerformance: boolean;
|
||||||
|
writeLogFile: boolean;
|
||||||
|
skipCheckMatchCompatibility: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of package.json with only those keys relevant for Providence
|
||||||
|
*/
|
||||||
|
export type PackageJson = {
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
files?: PathRelativeFromProjectRoot[];
|
||||||
|
dependencies?: { [dependency: string]: string };
|
||||||
|
devDependencies?: { [dependency: string]: string };
|
||||||
|
workspaces?: string[];
|
||||||
|
};
|
||||||
|
|
|
||||||
3
packages-node/providence-analytics/src/program/types/index.d.ts
vendored
Normal file
3
packages-node/providence-analytics/src/program/types/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
export * from './core';
|
||||||
|
export * from './analyzers';
|
||||||
|
export * from './utils';
|
||||||
1
packages-node/providence-analytics/src/program/types/utils/memoize.d.ts
vendored
Normal file
1
packages-node/providence-analytics/src/program/types/utils/memoize.d.ts
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export type MemoizeFunction<T> = (fn: T, storage?: object) => T;
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
/**
|
|
||||||
* Readable way to do an async forEach
|
|
||||||
* Since predictability matters, all array items will be handled in a queue,
|
|
||||||
* one after another
|
|
||||||
* @param {any[]} array
|
|
||||||
* @param {function} callback
|
|
||||||
*/
|
|
||||||
async function aForEach(array, callback) {
|
|
||||||
for (let i = 0; i < array.length; i += 1) {
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
|
||||||
await callback(array[i], i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Readable way to do an async forEach
|
|
||||||
* If predictability does not matter, this method will traverse array items concurrently,
|
|
||||||
* leading to a better performance
|
|
||||||
* @param {any[]} array
|
|
||||||
* @param {(value:any, index:number) => {}} callback
|
|
||||||
*/
|
|
||||||
async function aForEachNonSequential(array, callback) {
|
|
||||||
return Promise.all(array.map(callback));
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Readable way to do an async map
|
|
||||||
* Since predictability is crucial for a map, all array items will be handled in a queue,
|
|
||||||
* one after anotoher
|
|
||||||
* @param {Array<any>} array
|
|
||||||
* @param {(param:any, i:number) => any} callback
|
|
||||||
*/
|
|
||||||
async function aMap(array, callback) {
|
|
||||||
const mappedResults = [];
|
|
||||||
for (let i = 0; i < array.length; i += 1) {
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
|
||||||
const resolvedCb = await callback(array[i], i);
|
|
||||||
mappedResults.push(resolvedCb);
|
|
||||||
}
|
|
||||||
return mappedResults;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { aForEach, aMap, aForEachNonSequential };
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { dirname } from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} importMetaUrl should be import.meta.url
|
||||||
|
*/
|
||||||
|
export function getCurrentDir(importMetaUrl) {
|
||||||
|
return dirname(fileURLToPath(importMetaUrl));
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const babelTraversePkg = require('@babel/traverse');
|
const babelTraversePkg = require('@babel/traverse');
|
||||||
const { AstService } = require('../services/AstService.js');
|
const { AstService } = require('../core/AstService.js');
|
||||||
const { trackDownIdentifier } = require('../analyzers/helpers/track-down-identifier.js');
|
const { trackDownIdentifier } = require('../analyzers/helpers/track-down-identifier.js');
|
||||||
const { toPosixPath } = require('./to-posix-path.js');
|
const { toPosixPath } = require('./to-posix-path.js');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
// import htm from 'htm';
|
|
||||||
const htm = require('htm');
|
|
||||||
|
|
||||||
function convertToObj(type, props, ...children) {
|
|
||||||
return { type, props, children };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @desc
|
|
||||||
* Used for parsing lit-html templates inside ASTs
|
|
||||||
* @returns {type, props, children}
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* litToObj`<h1 .id=${'hello'}>Hello world!</h1>`;
|
|
||||||
* // {
|
|
||||||
* // type: 'h1',
|
|
||||||
* // props: { .id: 'hello' },
|
|
||||||
* // children: ['Hello world!']
|
|
||||||
* // }
|
|
||||||
*/
|
|
||||||
const litToObj = htm.bind(convertToObj);
|
|
||||||
|
|
||||||
module.exports = litToObj;
|
|
||||||
|
|
@ -1,9 +1,17 @@
|
||||||
const { InputDataService } = require('../services/InputDataService.js');
|
const memoizeConfig = {
|
||||||
|
isCacheDisabled: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object|any[]|string} arg
|
||||||
|
*/
|
||||||
function isObject(arg) {
|
function isObject(arg) {
|
||||||
return !Array.isArray(arg) && typeof arg === 'object';
|
return !Array.isArray(arg) && typeof arg === 'object';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object|any[]|string} arg
|
||||||
|
*/
|
||||||
function createCachableArg(arg) {
|
function createCachableArg(arg) {
|
||||||
if (isObject(arg)) {
|
if (isObject(arg)) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -17,7 +25,7 @@ function createCachableArg(arg) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {function} functionToMemoize
|
* @param {function} functionToMemoize
|
||||||
* @param {{ storage:object; serializeObjects: boolean }} [opts]
|
* @param {{ storage?:object; serializeObjects?: boolean }} opts
|
||||||
*/
|
*/
|
||||||
function memoize(functionToMemoize, { storage = {}, serializeObjects = false } = {}) {
|
function memoize(functionToMemoize, { storage = {}, serializeObjects = false } = {}) {
|
||||||
// eslint-disable-next-line func-names
|
// eslint-disable-next-line func-names
|
||||||
|
|
@ -27,7 +35,7 @@ function memoize(functionToMemoize, { storage = {}, serializeObjects = false } =
|
||||||
const cachableArgs = !serializeObjects ? args : args.map(createCachableArg);
|
const cachableArgs = !serializeObjects ? args : args.map(createCachableArg);
|
||||||
// Allow disabling of cache for testing purposes
|
// Allow disabling of cache for testing purposes
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (!InputDataService.cacheDisabled && cachableArgs in storage) {
|
if (!memoizeConfig.isCacheDisabled && cachableArgs in storage) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return storage[cachableArgs];
|
return storage[cachableArgs];
|
||||||
}
|
}
|
||||||
|
|
@ -42,4 +50,5 @@ function memoize(functionToMemoize, { storage = {}, serializeObjects = false } =
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
memoize,
|
memoize,
|
||||||
|
memoizeConfig,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { pathToFileURL } from 'url';
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<object|null>}
|
* @returns {Promise<object|null>}
|
||||||
*/
|
*/
|
||||||
export async function getProvidenceConf() {
|
async function getConf() {
|
||||||
const confPathWithoutExtension = `${pathLib.join(process.cwd(), 'providence.conf')}`;
|
const confPathWithoutExtension = `${pathLib.join(process.cwd(), 'providence.conf')}`;
|
||||||
let confPathFound;
|
let confPathFound;
|
||||||
try {
|
try {
|
||||||
|
|
@ -33,6 +33,8 @@ export async function getProvidenceConf() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const providenceConfRaw = fs.readFileSync(confPathFound, 'utf8');
|
const providenceConfRaw = fs.readFileSync(confPathFound, 'utf8');
|
||||||
|
|
||||||
return { providenceConf, providenceConfRaw };
|
return { providenceConf, providenceConfRaw };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wrapped in object for stubbing
|
||||||
|
export const providenceConfUtil = { getConf };
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
const { toPosixPath } = require('./to-posix-path.js');
|
const { toPosixPath } = require('./to-posix-path.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc determines for a source path of an import- or export specifier, whether
|
* Determines for a source path of an import- or export specifier, whether
|
||||||
* it is relative (an internal import/export) or absolute (external)
|
* it is relative (an internal import/export) or absolute (external)
|
||||||
* - relative: './helpers', './helpers.js', '../helpers.js'
|
* - relative: './helpers', './helpers.js', '../helpers.js'
|
||||||
* - not relative: '@open-wc/helpers', 'project-x/helpers'
|
* - not relative: '@open-wc/helpers', 'project-x/helpers'
|
||||||
|
|
@ -13,7 +13,7 @@ function isRelativeSourcePath(source) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @desc Simple helper te make code a bit more readable.
|
* Simple helper te make code a bit more readable.
|
||||||
* - from '/path/to/repo/my/file.js';
|
* - from '/path/to/repo/my/file.js';
|
||||||
* - to './my/file.js'
|
* - to './my/file.js'
|
||||||
* @param {string} fullPath like '/path/to/repo/my/file.js'
|
* @param {string} fullPath like '/path/to/repo/my/file.js'
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
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('../core/LogService.js');
|
||||||
const { memoize } = require('./memoize.js');
|
const { memoize } = require('./memoize.js');
|
||||||
const { toPosixPath } = require('./to-posix-path.js');
|
const { toPosixPath } = require('./to-posix-path.js');
|
||||||
|
|
||||||
|
|
@ -29,13 +29,13 @@ const fakePluginContext = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
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),
|
||||||
// allow resolving polyfills for nodejs libs
|
// allow resolving polyfills for nodejs libs
|
||||||
preferBuiltins: false,
|
preferBuiltins: false,
|
||||||
// extensions: ['.mjs', '.js', '.json', '.node'],
|
// extensions: ['.mjs', '.js', '.json', '.node'],
|
||||||
...opts,
|
...(opts || {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const preserveSymlinks =
|
const preserveSymlinks =
|
||||||
|
|
@ -44,10 +44,14 @@ async function resolveImportPath(importee, importer, opts = {}) {
|
||||||
rollupResolve.buildStart.call(fakePluginContext, { preserveSymlinks });
|
rollupResolve.buildStart.call(fakePluginContext, { preserveSymlinks });
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const result = await rollupResolve.resolveId.call(fakePluginContext, importee, importer, {});
|
const result = await rollupResolve.resolveId.handler.call(
|
||||||
|
fakePluginContext,
|
||||||
|
importee,
|
||||||
|
importer,
|
||||||
|
{},
|
||||||
|
);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (!result || !result.id) {
|
if (!result?.id) {
|
||||||
// throw new Error(`importee ${importee} not found in filesystem.`);
|
|
||||||
LogService.warn(`importee ${importee} not found in filesystem for importer '${importer}'.`);
|
LogService.warn(`importee ${importee} not found in filesystem for importer '${importer}'.`);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
|
// @ts-ignore
|
||||||
|
const mockFs = require('mock-fs');
|
||||||
|
// @ts-ignore
|
||||||
|
const mockRequire = require('mock-require');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object} obj
|
||||||
|
*/
|
||||||
|
function mockFsAndRequire(obj) {
|
||||||
|
mockFs(obj);
|
||||||
|
|
||||||
|
// Object.entries(obj).forEach(([key, value]) => {
|
||||||
|
// if (key.endsWith('.json')) {
|
||||||
|
// mockRequire(key, JSON.parse(value));
|
||||||
|
// } else {
|
||||||
|
// mockRequire(key, value);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
mockFsAndRequire.restore = () => {
|
||||||
|
mockFs.restore();
|
||||||
|
mockRequire.stopAll();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mockFsAndRequire,
|
||||||
|
};
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
const { LogService } = require('../src/program/services/LogService.js');
|
const { LogService } = require('../src/program/core/LogService.js');
|
||||||
|
|
||||||
const originalWarn = LogService.warn;
|
const originalWarn = LogService.warn;
|
||||||
function suppressWarningLogs() {
|
function suppressWarningLogs() {
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,8 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
const mockFs = require('mock-fs');
|
const { mockFsAndRequire: mock } = require('./mock-fs-and-require.js');
|
||||||
const mockRequire = require('mock-require');
|
|
||||||
|
|
||||||
function mock(obj) {
|
|
||||||
mockFs(obj);
|
|
||||||
|
|
||||||
Object.entries(obj).forEach(([key, value]) => {
|
|
||||||
if (key.endsWith('.json')) {
|
|
||||||
mockRequire(key, JSON.parse(value));
|
|
||||||
} else {
|
|
||||||
mockRequire(key, value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
mock.restore = () => {
|
|
||||||
mockFs.restore();
|
|
||||||
mockRequire.stopAll();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes sure that, whenever the main program (providence) calls
|
* Makes sure that, whenever the main program (providence) calls
|
||||||
|
|
@ -88,7 +72,7 @@ function getMockObjectForProject(files, cfg = {}, existingMock = {}) {
|
||||||
*/
|
*/
|
||||||
function mockProject(files, cfg = {}, existingMock = {}) {
|
function mockProject(files, cfg = {}, existingMock = {}) {
|
||||||
const obj = getMockObjectForProject(files, cfg, existingMock);
|
const obj = getMockObjectForProject(files, cfg, existingMock);
|
||||||
mockFs(obj);
|
mock(obj);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,26 @@
|
||||||
const { ReportService } = require('../src/program/services/ReportService.js');
|
const { ReportService } = require('../src/program/core/ReportService.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../src/program/types/core').QueryResult} QueryResult
|
||||||
|
*/
|
||||||
|
|
||||||
const originalWriteToJson = ReportService.writeToJson;
|
const originalWriteToJson = ReportService.writeToJson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {QueryResult[]} queryResults
|
||||||
|
*/
|
||||||
function mockWriteToJson(queryResults) {
|
function mockWriteToJson(queryResults) {
|
||||||
ReportService.writeToJson = queryResult => {
|
ReportService.writeToJson = queryResult => {
|
||||||
queryResults.push(queryResult);
|
queryResults.push(queryResult);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {QueryResult[]} [queryResults]
|
||||||
|
*/
|
||||||
function restoreWriteToJson(queryResults) {
|
function restoreWriteToJson(queryResults) {
|
||||||
ReportService.writeToJson = originalWriteToJson;
|
ReportService.writeToJson = originalWriteToJson;
|
||||||
while (queryResults && queryResults.length) {
|
while (queryResults?.length) {
|
||||||
queryResults.pop();
|
queryResults.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
"analyzerMeta": {
|
"analyzerMeta": {
|
||||||
"name": "find-exports",
|
"name": "find-exports",
|
||||||
"requiredAst": "babel",
|
"requiredAst": "babel",
|
||||||
"identifier": "exporting-ref-project_1.0.0__309114983",
|
"identifier": "exporting-ref-project_1.0.0__-42206859",
|
||||||
"targetProject": {
|
"targetProject": {
|
||||||
"mainEntry": "./index.js",
|
"mainEntry": "./index.js",
|
||||||
"name": "exporting-ref-project",
|
"name": "exporting-ref-project",
|
||||||
|
|
@ -13,7 +13,9 @@
|
||||||
},
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"skipFileImports": false,
|
"skipFileImports": false,
|
||||||
"gatherFilesConfig": {}
|
"gatherFilesConfig": {},
|
||||||
|
"skipCheckMatchCompatibility": false,
|
||||||
|
"addSystemPathsInResult": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -25,13 +27,13 @@
|
||||||
"exportSpecifiers": [
|
"exportSpecifiers": [
|
||||||
"[default]"
|
"[default]"
|
||||||
],
|
],
|
||||||
"source": "refConstImported",
|
"source": "./ref-src/core.js",
|
||||||
"normalizedSource": "refConstImported",
|
"normalizedSource": "./ref-src/core.js",
|
||||||
"rootFileMap": [
|
"rootFileMap": [
|
||||||
{
|
{
|
||||||
"currentFileSpecifier": "[default]",
|
"currentFileSpecifier": "[default]",
|
||||||
"rootFile": {
|
"rootFile": {
|
||||||
"file": "refConstImported",
|
"file": "./ref-src/core.js",
|
||||||
"specifier": "[default]"
|
"specifier": "[default]"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +87,6 @@
|
||||||
"notImported"
|
"notImported"
|
||||||
],
|
],
|
||||||
"localMap": [],
|
"localMap": [],
|
||||||
"source": null,
|
|
||||||
"rootFileMap": [
|
"rootFileMap": [
|
||||||
{
|
{
|
||||||
"currentFileSpecifier": "notImported",
|
"currentFileSpecifier": "notImported",
|
||||||
|
|
@ -127,7 +128,6 @@
|
||||||
"RefClass"
|
"RefClass"
|
||||||
],
|
],
|
||||||
"localMap": [],
|
"localMap": [],
|
||||||
"source": null,
|
|
||||||
"rootFileMap": [
|
"rootFileMap": [
|
||||||
{
|
{
|
||||||
"currentFileSpecifier": "RefClass",
|
"currentFileSpecifier": "RefClass",
|
||||||
|
|
@ -170,7 +170,6 @@
|
||||||
"resolvePathCorrect"
|
"resolvePathCorrect"
|
||||||
],
|
],
|
||||||
"localMap": [],
|
"localMap": [],
|
||||||
"source": null,
|
|
||||||
"rootFileMap": [
|
"rootFileMap": [
|
||||||
{
|
{
|
||||||
"currentFileSpecifier": "resolvePathCorrect",
|
"currentFileSpecifier": "resolvePathCorrect",
|
||||||
|
|
@ -192,4 +191,4 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
6
packages-node/providence-analytics/test-helpers/project-mocks/importing-target-project/node_modules/dep-a/README.md
generated
vendored
Normal file
6
packages-node/providence-analytics/test-helpers/project-mocks/importing-target-project/node_modules/dep-a/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
Has a deprecated (from Node 16) export maps format:
|
||||||
|
```
|
||||||
|
"exports": {
|
||||||
|
"./src/": "./src/"
|
||||||
|
})
|
||||||
|
```
|
||||||
7
packages-node/providence-analytics/test-helpers/project-mocks/importing-target-project/node_modules/dep-a/package.json
generated
vendored
Normal file
7
packages-node/providence-analytics/test-helpers/project-mocks/importing-target-project/node_modules/dep-a/package.json
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"name": "dep-a",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"exports": {
|
||||||
|
"./src/": "./src/"
|
||||||
|
}
|
||||||
|
}
|
||||||
0
packages-node/providence-analytics/test-helpers/project-mocks/importing-target-project/node_modules/dep-a/src/src.js
generated
vendored
Normal file
0
packages-node/providence-analytics/test-helpers/project-mocks/importing-target-project/node_modules/dep-a/src/src.js
generated
vendored
Normal file
7
packages-node/providence-analytics/test-helpers/project-mocks/importing-target-project/node_modules/my-dep-b/package.json
generated
vendored
Normal file
7
packages-node/providence-analytics/test-helpers/project-mocks/importing-target-project/node_modules/my-dep-b/package.json
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"name": "my-dep-b",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"exports": {
|
||||||
|
"./src/*": "./src/*"
|
||||||
|
}
|
||||||
|
}
|
||||||
0
packages-node/providence-analytics/test-helpers/project-mocks/importing-target-project/node_modules/my-dep-b/src/src.js
generated
vendored
Normal file
0
packages-node/providence-analytics/test-helpers/project-mocks/importing-target-project/node_modules/my-dep-b/src/src.js
generated
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
const { InputDataService } = require('../src/program/core/InputDataService.js');
|
||||||
|
const { QueryService } = require('../src/program/core/QueryService.js');
|
||||||
|
const { restoreMockedProjects } = require('./mock-project-helpers.js');
|
||||||
|
const { mockWriteToJson, restoreWriteToJson } = require('./mock-report-service-helpers.js');
|
||||||
|
const {
|
||||||
|
suppressNonCriticalLogs,
|
||||||
|
restoreSuppressNonCriticalLogs,
|
||||||
|
} = require('./mock-log-service-helpers.js');
|
||||||
|
const { memoizeConfig } = require('../src/program/utils/memoize.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../src/program/types/core').QueryResult} QueryResult
|
||||||
|
* @returns {QueryResult[]}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function setupAnalyzerTest() {
|
||||||
|
/** @type {QueryResult[]} */
|
||||||
|
const queryResults = [];
|
||||||
|
|
||||||
|
const originalReferenceProjectPaths = InputDataService.referenceProjectPaths;
|
||||||
|
const cacheDisabledQInitialValue = QueryService.cacheDisabled;
|
||||||
|
const cacheDisabledIInitialValue = memoizeConfig.isCacheDisabled;
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
QueryService.cacheDisabled = true;
|
||||||
|
memoizeConfig.isCacheDisabled = true;
|
||||||
|
suppressNonCriticalLogs();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
QueryService.cacheDisabled = cacheDisabledQInitialValue;
|
||||||
|
memoizeConfig.isCacheDisabled = cacheDisabledIInitialValue;
|
||||||
|
restoreSuppressNonCriticalLogs();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
InputDataService.referenceProjectPaths = [];
|
||||||
|
mockWriteToJson(queryResults);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
InputDataService.referenceProjectPaths = originalReferenceProjectPaths;
|
||||||
|
restoreWriteToJson(queryResults);
|
||||||
|
restoreMockedProjects();
|
||||||
|
});
|
||||||
|
|
||||||
|
return queryResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { setupAnalyzerTest };
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
const { Analyzer } = require('../../src/program/analyzers/helpers/Analyzer.js');
|
const { Analyzer } = require('../../src/program/core/Analyzer.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('@babel/types').File} File
|
||||||
|
* @typedef {import('../../src/program/types/core').QueryOutputEntry} QueryOutputEntry
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file outlines the minimum required functionality for an analyzer.
|
* This file outlines the minimum required functionality for an analyzer.
|
||||||
|
|
@ -23,8 +28,7 @@ const options = {
|
||||||
* corresponds to one file.
|
* corresponds to one file.
|
||||||
* The contents of this function should be designed in such a way that they
|
* The contents of this function should be designed in such a way that they
|
||||||
* can be directly pasted and edited in https://astexplorer.net/
|
* can be directly pasted and edited in https://astexplorer.net/
|
||||||
* @param {BabelAST} ast
|
* @param {File} ast
|
||||||
* @returns {TransformedEntry}
|
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function myAnalyzerPerAstEntry(ast) {
|
function myAnalyzerPerAstEntry(ast) {
|
||||||
|
|
@ -36,22 +40,9 @@ function myAnalyzerPerAstEntry(ast) {
|
||||||
return transformedEntryResult;
|
return transformedEntryResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyAnalyzer extends Analyzer {
|
class DummyAnalyzer extends Analyzer {
|
||||||
constructor() {
|
static get analyzerName() {
|
||||||
super();
|
return 'dummy-analyzer';
|
||||||
/**
|
|
||||||
* This must match with the name in file-system (will be used for reporting)
|
|
||||||
*/
|
|
||||||
this.name = 'my-analyzer';
|
|
||||||
/**
|
|
||||||
* The ast format that the execute function expects
|
|
||||||
* Compatible with formats supported by AstService.getAst()
|
|
||||||
*/
|
|
||||||
this.requiredAst = 'babel';
|
|
||||||
/**
|
|
||||||
* Not all analyzers require a references. Those that do, (usually 'match analyzers'),
|
|
||||||
* must explicitly state so with `requiresReference: true`
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -91,7 +82,6 @@ class MyAnalyzer extends Analyzer {
|
||||||
|
|
||||||
return { result: transformedEntryResult, meta };
|
return { result: transformedEntryResult, meta };
|
||||||
});
|
});
|
||||||
|
|
||||||
// (optional): Post processors on TransformedQueryResult
|
// (optional): Post processors on TransformedQueryResult
|
||||||
if (cfg.optionB) {
|
if (cfg.optionB) {
|
||||||
// Run your QueryResult transformation based on option B
|
// Run your QueryResult transformation based on option B
|
||||||
|
|
@ -104,4 +94,4 @@ class MyAnalyzer extends Analyzer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = MyAnalyzer;
|
module.exports = { DummyAnalyzer };
|
||||||
30
packages-node/providence-analytics/test-node/cli/cli.e2e.mjs
Normal file
30
packages-node/providence-analytics/test-node/cli/cli.e2e.mjs
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
|
import pathLib from 'path';
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { appendProjectDependencyPaths } from '../../src/cli/cli-helpers.js';
|
||||||
|
import { toPosixPath } from '../../src/program/utils/to-posix-path.js';
|
||||||
|
import { getCurrentDir } from '../../src/program/utils/get-current-dir.mjs';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These tests are added on top of unit tests. See:
|
||||||
|
* - https://github.com/ing-bank/lion/issues/1565
|
||||||
|
* - https://github.com/ing-bank/lion/issues/1564
|
||||||
|
*/
|
||||||
|
describe('CLI helpers against filesystem', () => {
|
||||||
|
describe('appendProjectDependencyPaths', () => {
|
||||||
|
it('allows a regex filter', async () => {
|
||||||
|
const targetFilePath = toPosixPath(
|
||||||
|
pathLib.resolve(
|
||||||
|
getCurrentDir(import.meta.url),
|
||||||
|
'../../test-helpers/project-mocks/importing-target-project',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const result = await appendProjectDependencyPaths([targetFilePath], '/^dep-/');
|
||||||
|
expect(result).to.eql([
|
||||||
|
`${targetFilePath}/node_modules/dep-a`,
|
||||||
|
// in windows, it should not add `${targetFilePath}/node_modules/my-dep-b`,
|
||||||
|
targetFilePath,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,37 +1,48 @@
|
||||||
const sinon = require('sinon');
|
/* eslint-disable no-unused-expressions */
|
||||||
const pathLib = require('path');
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
const { expect } = require('chai');
|
import sinon from 'sinon';
|
||||||
const commander = require('commander');
|
import pathLib from 'path';
|
||||||
const {
|
import { fileURLToPath } from 'url';
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import commander from 'commander';
|
||||||
|
import {
|
||||||
mockProject,
|
mockProject,
|
||||||
restoreMockedProjects,
|
restoreMockedProjects,
|
||||||
mockTargetAndReferenceProject,
|
mockTargetAndReferenceProject,
|
||||||
} = require('../../test-helpers/mock-project-helpers.js');
|
} from '../../test-helpers/mock-project-helpers.js';
|
||||||
const {
|
import {
|
||||||
mockWriteToJson,
|
mockWriteToJson,
|
||||||
restoreWriteToJson,
|
restoreWriteToJson,
|
||||||
} = require('../../test-helpers/mock-report-service-helpers.js');
|
} from '../../test-helpers/mock-report-service-helpers.js';
|
||||||
const {
|
import {
|
||||||
suppressNonCriticalLogs,
|
suppressNonCriticalLogs,
|
||||||
restoreSuppressNonCriticalLogs,
|
restoreSuppressNonCriticalLogs,
|
||||||
} = require('../../test-helpers/mock-log-service-helpers.js');
|
} from '../../test-helpers/mock-log-service-helpers.js';
|
||||||
const { InputDataService } = require('../../src/program/services/InputDataService.js');
|
import { InputDataService } from '../../src/program/core/InputDataService.js';
|
||||||
const { QueryService } = require('../../src/program/services/QueryService.js');
|
import { QueryService } from '../../src/program/core/QueryService.js';
|
||||||
const providenceModule = require('../../src/program/providence.js');
|
import providenceModule from '../../src/program/providence.js';
|
||||||
const extendDocsModule = require('../../src/cli/launch-providence-with-extend-docs.js');
|
import cliHelpersModule from '../../src/cli/cli-helpers.js';
|
||||||
const cliHelpersModule = require('../../src/cli/cli-helpers.js');
|
import { cli } from '../../src/cli/cli.mjs';
|
||||||
const { cli } = require('../../src/cli/cli.js');
|
import promptAnalyzerModule from '../../src/cli/prompt-analyzer-menu.js';
|
||||||
const promptAnalyzerModule = require('../../src/cli/prompt-analyzer-menu.js');
|
import { toPosixPath } from '../../src/program/utils/to-posix-path.js';
|
||||||
const { toPosixPath } = require('../../src/program/utils/to-posix-path.js');
|
import { memoizeConfig } from '../../src/program/utils/memoize.js';
|
||||||
const { getExtendDocsResults } = require('../../src/cli/launch-providence-with-extend-docs.js');
|
import extendDocsModule, {
|
||||||
|
getExtendDocsResults,
|
||||||
|
} from '../../src/cli/launch-providence-with-extend-docs.js';
|
||||||
|
import { dashboardServer } from '../../dashboard/server.mjs';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../../src/program/types/core').QueryResult} QueryResult
|
||||||
|
*/
|
||||||
|
|
||||||
|
const __dirname = pathLib.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
const { pathsArrayFromCs, pathsArrayFromCollectionName, appendProjectDependencyPaths } =
|
const { pathsArrayFromCs, pathsArrayFromCollectionName, appendProjectDependencyPaths } =
|
||||||
cliHelpersModule;
|
cliHelpersModule;
|
||||||
|
|
||||||
|
/** @type {QueryResult[]} */
|
||||||
const queryResults = [];
|
const queryResults = [];
|
||||||
|
|
||||||
const rootDir = toPosixPath(pathLib.resolve(__dirname, '../../'));
|
|
||||||
|
|
||||||
const externalCfgMock = {
|
const externalCfgMock = {
|
||||||
searchTargetCollections: {
|
searchTargetCollections: {
|
||||||
'lion-collection': [
|
'lion-collection': [
|
||||||
|
|
@ -48,21 +59,35 @@ const externalCfgMock = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} args
|
||||||
|
* @param {string} cwd
|
||||||
|
*/
|
||||||
async function runCli(args, cwd) {
|
async function runCli(args, cwd) {
|
||||||
process.argv = [
|
const argv = [
|
||||||
...process.argv.slice(0, 2),
|
...process.argv.slice(0, 2),
|
||||||
...args.split(' ').map(a => a.replace(/^("|')?(.*)("|')?$/, '$2')),
|
...args.split(' ').map(a => a.replace(/^("|')?(.*)("|')?$/, '$2')),
|
||||||
];
|
];
|
||||||
await cli({ cwd });
|
await cli({ argv, cwd });
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Providence CLI', () => {
|
describe('Providence CLI', () => {
|
||||||
|
const rootDir = '/mocked/path/example-project';
|
||||||
|
|
||||||
|
/** @type {sinon.SinonStub} */
|
||||||
let providenceStub;
|
let providenceStub;
|
||||||
|
/** @type {sinon.SinonStub} */
|
||||||
let promptCfgStub;
|
let promptCfgStub;
|
||||||
|
/** @type {sinon.SinonStub} */
|
||||||
let iExtConfStub;
|
let iExtConfStub;
|
||||||
|
/** @type {sinon.SinonStub} */
|
||||||
let promptStub;
|
let promptStub;
|
||||||
|
/** @type {sinon.SinonStub} */
|
||||||
let qConfStub;
|
let qConfStub;
|
||||||
|
|
||||||
|
const memoizeCacheDisabledInitial = memoizeConfig.isCacheDisabled;
|
||||||
|
memoizeConfig.isCacheDisabled = true;
|
||||||
|
|
||||||
before(() => {
|
before(() => {
|
||||||
// Prevent MaxListenersExceededWarning
|
// Prevent MaxListenersExceededWarning
|
||||||
commander.setMaxListeners(100);
|
commander.setMaxListeners(100);
|
||||||
|
|
@ -84,25 +109,26 @@ describe('Providence CLI', () => {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
providenceStub = sinon.stub(providenceModule, 'providence').returns(
|
/** @type {sinon.SinonStub} */
|
||||||
new Promise(resolve => {
|
providenceStub = sinon.stub(providenceModule, 'providence').returns(Promise.resolve());
|
||||||
resolve();
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
|
/** @type {sinon.SinonStub} */
|
||||||
promptCfgStub = sinon
|
promptCfgStub = sinon
|
||||||
.stub(promptAnalyzerModule, 'promptAnalyzerConfigMenu')
|
.stub(promptAnalyzerModule, 'promptAnalyzerConfigMenu')
|
||||||
.returns({ analyzerConfig: { con: 'fig' } });
|
.returns(Promise.resolve({ analyzerConfig: { con: 'fig' } }));
|
||||||
|
|
||||||
|
/** @type {sinon.SinonStub} */
|
||||||
iExtConfStub = sinon.stub(InputDataService, 'getExternalConfig').returns(externalCfgMock);
|
iExtConfStub = sinon.stub(InputDataService, 'getExternalConfig').returns(externalCfgMock);
|
||||||
|
|
||||||
|
/** @type {sinon.SinonStub} */
|
||||||
promptStub = sinon
|
promptStub = sinon
|
||||||
.stub(promptAnalyzerModule, 'promptAnalyzerMenu')
|
.stub(promptAnalyzerModule, 'promptAnalyzerMenu')
|
||||||
.returns({ analyzerName: 'mock-analyzer' });
|
.returns(Promise.resolve({ analyzerName: 'match-analyzer-mock' }));
|
||||||
|
|
||||||
|
/** @type {sinon.SinonStub} */
|
||||||
qConfStub = sinon.stub(QueryService, 'getQueryConfigFromAnalyzer').returns({
|
qConfStub = sinon.stub(QueryService, 'getQueryConfigFromAnalyzer').returns({
|
||||||
analyzer: {
|
analyzer: {
|
||||||
name: 'mock-analyzer',
|
name: 'match-analyzer-mock',
|
||||||
requiresReference: true,
|
requiresReference: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -120,6 +146,12 @@ describe('Providence CLI', () => {
|
||||||
iExtConfStub.restore();
|
iExtConfStub.restore();
|
||||||
promptStub.restore();
|
promptStub.restore();
|
||||||
qConfStub.restore();
|
qConfStub.restore();
|
||||||
|
|
||||||
|
memoizeConfig.isCacheDisabled = memoizeCacheDisabledInitial;
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
memoizeConfig.isCacheDisabled = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
|
@ -130,22 +162,25 @@ describe('Providence CLI', () => {
|
||||||
qConfStub.resetHistory();
|
qConfStub.resetHistory();
|
||||||
});
|
});
|
||||||
|
|
||||||
const analyzeCmd = 'analyze mock-analyzer';
|
const analyzeCmd = 'analyze match-analyzer-mock';
|
||||||
|
|
||||||
it('calls providence', async () => {
|
it('calls providence', async () => {
|
||||||
await runCli(`${analyzeCmd} -t /mocked/path/example-project`);
|
await runCli(`${analyzeCmd} -t /mocked/path/example-project`, rootDir);
|
||||||
expect(providenceStub.called).to.be.true;
|
expect(providenceStub.called).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates a QueryConfig', async () => {
|
it('creates a QueryConfig', async () => {
|
||||||
await runCli(`${analyzeCmd} -t /mocked/path/example-project`);
|
await runCli(`${analyzeCmd} -t /mocked/path/example-project`, rootDir);
|
||||||
expect(qConfStub.called).to.be.true;
|
expect(qConfStub.called).to.be.true;
|
||||||
expect(qConfStub.args[0][0]).to.equal('mock-analyzer');
|
expect(qConfStub.args[0][0]).to.equal('match-analyzer-mock');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Global options', () => {
|
describe('Global options', () => {
|
||||||
|
/** @type {sinon.SinonStub} */
|
||||||
let pathsArrayFromCollectionStub;
|
let pathsArrayFromCollectionStub;
|
||||||
|
/** @type {sinon.SinonStub} */
|
||||||
let pathsArrayFromCsStub;
|
let pathsArrayFromCsStub;
|
||||||
|
/** @type {sinon.SinonStub} */
|
||||||
let appendProjectDependencyPathsStub;
|
let appendProjectDependencyPathsStub;
|
||||||
|
|
||||||
before(() => {
|
before(() => {
|
||||||
|
|
@ -157,11 +192,13 @@ describe('Providence CLI', () => {
|
||||||
.returns(['/mocked/path/example-project']);
|
.returns(['/mocked/path/example-project']);
|
||||||
appendProjectDependencyPathsStub = sinon
|
appendProjectDependencyPathsStub = sinon
|
||||||
.stub(cliHelpersModule, 'appendProjectDependencyPaths')
|
.stub(cliHelpersModule, 'appendProjectDependencyPaths')
|
||||||
.returns([
|
.returns(
|
||||||
'/mocked/path/example-project',
|
Promise.resolve([
|
||||||
'/mocked/path/example-project/node_modules/mock-dep-a',
|
'/mocked/path/example-project',
|
||||||
'/mocked/path/example-project/bower_components/mock-dep-b',
|
'/mocked/path/example-project/node_modules/mock-dep-a',
|
||||||
]);
|
'/mocked/path/example-project/bower_components/mock-dep-b',
|
||||||
|
]),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
after(() => {
|
after(() => {
|
||||||
|
|
@ -177,12 +214,12 @@ describe('Providence CLI', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('"-e --extensions"', async () => {
|
it('"-e --extensions"', async () => {
|
||||||
await runCli(`${analyzeCmd} -e bla,blu`);
|
await runCli(`${analyzeCmd} -e bla,blu`, rootDir);
|
||||||
expect(providenceStub.args[0][1].gatherFilesConfig.extensions).to.eql(['.bla', '.blu']);
|
expect(providenceStub.args[0][1].gatherFilesConfig.extensions).to.eql(['.bla', '.blu']);
|
||||||
|
|
||||||
providenceStub.resetHistory();
|
providenceStub.resetHistory();
|
||||||
|
|
||||||
await runCli(`${analyzeCmd} --extensions bla,blu`);
|
await runCli(`${analyzeCmd} --extensions bla,blu`, rootDir);
|
||||||
expect(providenceStub.args[0][1].gatherFilesConfig.extensions).to.eql(['.bla', '.blu']);
|
expect(providenceStub.args[0][1].gatherFilesConfig.extensions).to.eql(['.bla', '.blu']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -325,19 +362,19 @@ describe('Providence CLI', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('"-c --config"', async () => {
|
it('"-c --config"', async () => {
|
||||||
await runCli(`analyze mock-analyzer -c {"a":"2"}`, rootDir);
|
await runCli(`analyze match-analyzer-mock -c {"a":"2"}`, rootDir);
|
||||||
expect(qConfStub.args[0][0]).to.equal('mock-analyzer');
|
expect(qConfStub.args[0][0]).to.equal('match-analyzer-mock');
|
||||||
expect(qConfStub.args[0][1]).to.eql({ a: '2', metaConfig: {} });
|
expect(qConfStub.args[0][1]).to.eql({ a: '2', metaConfig: {} });
|
||||||
|
|
||||||
qConfStub.resetHistory();
|
qConfStub.resetHistory();
|
||||||
|
|
||||||
await runCli(`analyze mock-analyzer --config {"a":"2"}`, rootDir);
|
await runCli(`analyze match-analyzer-mock --config {"a":"2"}`, rootDir);
|
||||||
expect(qConfStub.args[0][0]).to.equal('mock-analyzer');
|
expect(qConfStub.args[0][0]).to.equal('match-analyzer-mock');
|
||||||
expect(qConfStub.args[0][1]).to.eql({ a: '2', metaConfig: {} });
|
expect(qConfStub.args[0][1]).to.eql({ a: '2', metaConfig: {} });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calls "promptAnalyzerConfigMenu" without config given', async () => {
|
it('calls "promptAnalyzerConfigMenu" without config given', async () => {
|
||||||
await runCli(`analyze mock-analyzer`, rootDir);
|
await runCli(`analyze match-analyzer-mock`, rootDir);
|
||||||
expect(promptCfgStub.called).to.be.true;
|
expect(promptCfgStub.called).to.be.true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -348,7 +385,17 @@ describe('Providence CLI', () => {
|
||||||
|
|
||||||
describe('Manage', () => {});
|
describe('Manage', () => {});
|
||||||
|
|
||||||
|
describe('Dashboard', () => {
|
||||||
|
/** @type {sinon.SinonStub} */
|
||||||
|
const startStub = sinon.stub(dashboardServer, 'start');
|
||||||
|
it('spawns a dashboard', async () => {
|
||||||
|
runCli(`dashboard`, rootDir);
|
||||||
|
expect(startStub.called).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('Extend docs', () => {
|
describe('Extend docs', () => {
|
||||||
|
/** @type {sinon.SinonStub} */
|
||||||
let extendDocsStub;
|
let extendDocsStub;
|
||||||
|
|
||||||
before(() => {
|
before(() => {
|
||||||
|
|
@ -389,7 +436,7 @@ describe('Providence CLI', () => {
|
||||||
extensions: ['.bla'],
|
extensions: ['.bla'],
|
||||||
allowlist: ['al'],
|
allowlist: ['al'],
|
||||||
allowlistReference: ['alr'],
|
allowlistReference: ['alr'],
|
||||||
cwd: undefined,
|
cwd: '/mocked/path/example-project',
|
||||||
skipCheckMatchCompatibility: true,
|
skipCheckMatchCompatibility: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -398,6 +445,8 @@ describe('Providence CLI', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('CLI helpers', () => {
|
describe('CLI helpers', () => {
|
||||||
|
const rootDir = toPosixPath(pathLib.resolve(__dirname, '../../'));
|
||||||
|
|
||||||
describe('pathsArrayFromCs', () => {
|
describe('pathsArrayFromCs', () => {
|
||||||
it('allows absolute paths', async () => {
|
it('allows absolute paths', async () => {
|
||||||
expect(pathsArrayFromCs('/mocked/path/example-project', rootDir)).to.eql([
|
expect(pathsArrayFromCs('/mocked/path/example-project', rootDir)).to.eql([
|
||||||
|
|
@ -472,6 +521,7 @@ describe('CLI helpers', () => {
|
||||||
'./index.js': `export { InBetweenComp as MyComp } from './src/inbetween.js'`,
|
'./index.js': `export { InBetweenComp as MyComp } from './src/inbetween.js'`,
|
||||||
'./node_modules/dependency-a/index.js': '',
|
'./node_modules/dependency-a/index.js': '',
|
||||||
'./bower_components/dependency-b/index.js': '',
|
'./bower_components/dependency-b/index.js': '',
|
||||||
|
'./node_modules/my-dependency/index.js': '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
projectName: 'example-project',
|
projectName: 'example-project',
|
||||||
|
|
@ -484,6 +534,7 @@ describe('CLI helpers', () => {
|
||||||
const result = await appendProjectDependencyPaths(['/mocked/path/example-project']);
|
const result = await appendProjectDependencyPaths(['/mocked/path/example-project']);
|
||||||
expect(result).to.eql([
|
expect(result).to.eql([
|
||||||
'/mocked/path/example-project/node_modules/dependency-a',
|
'/mocked/path/example-project/node_modules/dependency-a',
|
||||||
|
'/mocked/path/example-project/node_modules/my-dependency',
|
||||||
'/mocked/path/example-project/bower_components/dependency-b',
|
'/mocked/path/example-project/bower_components/dependency-b',
|
||||||
'/mocked/path/example-project',
|
'/mocked/path/example-project',
|
||||||
]);
|
]);
|
||||||
|
|
@ -496,6 +547,7 @@ describe('CLI helpers', () => {
|
||||||
);
|
);
|
||||||
expect(result).to.eql([
|
expect(result).to.eql([
|
||||||
'/mocked/path/example-project/node_modules/dependency-a',
|
'/mocked/path/example-project/node_modules/dependency-a',
|
||||||
|
// in windows, it should not add '/mocked/path/example-project/node_modules/my-dependency',
|
||||||
'/mocked/path/example-project/bower_components/dependency-b',
|
'/mocked/path/example-project/bower_components/dependency-b',
|
||||||
'/mocked/path/example-project',
|
'/mocked/path/example-project',
|
||||||
]);
|
]);
|
||||||
|
|
@ -513,6 +565,7 @@ describe('CLI helpers', () => {
|
||||||
]);
|
]);
|
||||||
expect(result).to.eql([
|
expect(result).to.eql([
|
||||||
'/mocked/path/example-project/node_modules/dependency-a',
|
'/mocked/path/example-project/node_modules/dependency-a',
|
||||||
|
'/mocked/path/example-project/node_modules/my-dependency',
|
||||||
'/mocked/path/example-project',
|
'/mocked/path/example-project',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -530,7 +583,12 @@ describe('CLI helpers', () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
restoreMockedProjects();
|
restoreMockedProjects();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rewrites monorepo package paths when analysis is run from monorepo root', async () => {
|
it('rewrites monorepo package paths when analysis is run from monorepo root', async () => {
|
||||||
|
// This fails after InputDataService.addAstToProjectsData is memoized
|
||||||
|
// (it does pass when run in isolation however, as a quick fix we disable memoization cache here...)
|
||||||
|
memoizeConfig.isCacheDisabled = true;
|
||||||
|
|
||||||
const theirProjectFiles = {
|
const theirProjectFiles = {
|
||||||
'./package.json': JSON.stringify({
|
'./package.json': JSON.stringify({
|
||||||
name: 'their-components',
|
name: 'their-components',
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
|
import fs from 'fs';
|
||||||
|
import pathLib from 'path';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import fetch from 'node-fetch';
|
||||||
|
import { createTestServer } from '@web/dev-server-core/test-helpers';
|
||||||
|
import { createDashboardServerConfig } from '../../dashboard/server.mjs';
|
||||||
|
import { ReportService } from '../../src/program/core/ReportService.js';
|
||||||
|
import { providenceConfUtil } from '../../src/program/utils/providence-conf-util.mjs';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('@web/dev-server-core').DevServer} DevServer
|
||||||
|
*/
|
||||||
|
|
||||||
|
const __dirname = pathLib.dirname(fileURLToPath(import.meta.url));
|
||||||
|
const { outputPath: reportServiceOutputPathOriginal } = ReportService;
|
||||||
|
const fixturesPath = pathLib.join(__dirname, 'fixtures');
|
||||||
|
const mockedResponsesPath = pathLib.join(__dirname, 'fixtures/dashboard-responses');
|
||||||
|
const mockedOutputPath = pathLib.join(__dirname, 'fixtures/providence-output');
|
||||||
|
|
||||||
|
async function getConf(url) {
|
||||||
|
const { default: providenceConf } = await import(url);
|
||||||
|
const providenceConfRaw = fs.readFileSync(url, 'utf8');
|
||||||
|
return { providenceConf, providenceConfRaw };
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Dashboard Server', () => {
|
||||||
|
/** @type {string} */
|
||||||
|
let host;
|
||||||
|
/** @type {DevServer} */
|
||||||
|
let server;
|
||||||
|
/** @type {sinon.SinonStub} */
|
||||||
|
let providenceConfStub;
|
||||||
|
|
||||||
|
before(() => {
|
||||||
|
// N.B. don't use mock-fs, since it doesn't correctly handle dynamic imports and fs.promises
|
||||||
|
ReportService.outputPath = mockedOutputPath;
|
||||||
|
});
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
ReportService.outputPath = reportServiceOutputPathOriginal;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Happy flow', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
const conf = await getConf(`${fixturesPath}/providence.conf.mjs`);
|
||||||
|
providenceConfStub = sinon.stub(providenceConfUtil, 'getConf').resolves(conf);
|
||||||
|
({ host, server } = await createTestServer(await createDashboardServerConfig()));
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
providenceConfStub.restore();
|
||||||
|
server.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Index', () => {
|
||||||
|
it(`returns an index on '/'`, async () => {
|
||||||
|
const response = await fetch(`${host}/dashboard`);
|
||||||
|
const responseText = await response.text();
|
||||||
|
expect(response.status).to.equal(200);
|
||||||
|
expect(responseText).to.include('<title>Providence dashboard</title>');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('App assets', () => {
|
||||||
|
it(`returns (static) js assets via app/*`, async () => {
|
||||||
|
const response = await fetch(`${host}/dashboard/app/p-board.js`);
|
||||||
|
expect(response.status).to.equal(200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Menu data', () => {
|
||||||
|
it(`returns json object based on output`, async () => {
|
||||||
|
const response = await fetch(`${host}/menu-data.json`);
|
||||||
|
expect(response.status).to.equal(200);
|
||||||
|
const responseJSON = await response.json();
|
||||||
|
const expectedResult = fs.readFileSync(`${mockedResponsesPath}/menu-data.json`, 'utf8');
|
||||||
|
expect(responseJSON).to.eql(JSON.parse(expectedResult));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Results', () => {
|
||||||
|
it(`returns json object based on output`, async () => {
|
||||||
|
const response = await fetch(`${host}/results.json`);
|
||||||
|
expect(response.status).to.equal(200);
|
||||||
|
const responseJson = await response.json();
|
||||||
|
const expectedResult = fs.readFileSync(`${mockedResponsesPath}/results.json`, 'utf8');
|
||||||
|
expect(responseJson).to.eql(JSON.parse(expectedResult));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Config file "providence.conf.(m)js"', () => {
|
||||||
|
it(`returns providence.conf.mjs found in cwd`, async () => {
|
||||||
|
const response = await fetch(`${host}/providence-conf.js`);
|
||||||
|
expect(response.status).to.equal(200);
|
||||||
|
const responseText = await response.text();
|
||||||
|
const { providenceConfRaw } = await getConf(`${fixturesPath}/providence.conf.mjs`);
|
||||||
|
expect(responseText).to.equal(providenceConfRaw);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Since we cannot mock dynamic imports: skip for now...
|
||||||
|
it.skip(`returns providence.conf.js found in cwd`, async () => {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Unhappy flow', () => {
|
||||||
|
// Since we cannot mock dynamic imports: skip for now...
|
||||||
|
describe.skip('Config file "providence.conf.(m)js"', () => {
|
||||||
|
it(`throws when no providence.conf.(m)js found`, async () => {});
|
||||||
|
|
||||||
|
it(`throws when providence.conf.(m)js is not an esm module`, async () => {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"searchTargetCollections": {
|
||||||
|
"@lion-targets": ["@lion/ui"]
|
||||||
|
},
|
||||||
|
"referenceCollections": {
|
||||||
|
"@lion-references": ["@lion/ui"]
|
||||||
|
},
|
||||||
|
"searchTargetDeps": {
|
||||||
|
"@lion/input#0.15.7": ["@lion/input#0.15.7"],
|
||||||
|
"@lion/listbox#0.10.7": ["@lion/listbox#0.10.7"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,634 @@
|
||||||
|
{
|
||||||
|
"match-imports": [
|
||||||
|
{
|
||||||
|
"fileName": "match-imports_-_%40lion%2Finput_0.15.7_+_%40lion%2Fform-core_0.15.4__1410239906.json",
|
||||||
|
"content": {
|
||||||
|
"meta": {
|
||||||
|
"searchType": "ast-analyzer",
|
||||||
|
"analyzerMeta": {
|
||||||
|
"name": "match-imports",
|
||||||
|
"requiredAst": "babel",
|
||||||
|
"identifier": "%40lion%2Finput_0.15.7_+_%40lion%2Fform-core_0.15.4__1410239906",
|
||||||
|
"targetProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/input",
|
||||||
|
"version": "0.15.7",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"referenceProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/form-core",
|
||||||
|
"version": "0.15.4",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"configuration": {
|
||||||
|
"gatherFilesConfig": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"targetProjectResult": null,
|
||||||
|
"referenceProjectResult": null,
|
||||||
|
"gatherFilesConfigReference": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"skipCheckMatchCompatibility": false,
|
||||||
|
"metaConfig": {
|
||||||
|
"categoryConfig": [
|
||||||
|
{
|
||||||
|
"project": "@lion/overlays",
|
||||||
|
"majorVersion": 1,
|
||||||
|
"categories": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"queryOutput": [
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "LionField::./index.js::@lion/form-core",
|
||||||
|
"name": "LionField",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/input",
|
||||||
|
"files": [
|
||||||
|
"./src/LionInput.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "NativeTextFieldMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "NativeTextFieldMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/input",
|
||||||
|
"files": [
|
||||||
|
"./src/LionInput.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "Validator::./index.js::@lion/form-core",
|
||||||
|
"name": "Validator",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/input",
|
||||||
|
"files": [
|
||||||
|
"./test/lion-input.test.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fileName": "match-imports_-_%40lion%2Flistbox_0.10.7_+_%40lion%2Fform-core_0.15.4__-1773728033.json",
|
||||||
|
"content": {
|
||||||
|
"meta": {
|
||||||
|
"searchType": "ast-analyzer",
|
||||||
|
"analyzerMeta": {
|
||||||
|
"name": "match-imports",
|
||||||
|
"requiredAst": "babel",
|
||||||
|
"identifier": "%40lion%2Flistbox_0.10.7_+_%40lion%2Fform-core_0.15.4__-1773728033",
|
||||||
|
"targetProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/listbox",
|
||||||
|
"version": "0.10.7",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"referenceProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/form-core",
|
||||||
|
"version": "0.15.4",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"configuration": {
|
||||||
|
"gatherFilesConfig": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"targetProjectResult": null,
|
||||||
|
"referenceProjectResult": null,
|
||||||
|
"gatherFilesConfigReference": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"skipCheckMatchCompatibility": false,
|
||||||
|
"metaConfig": {
|
||||||
|
"categoryConfig": [
|
||||||
|
{
|
||||||
|
"project": "@lion/overlays",
|
||||||
|
"majorVersion": 1,
|
||||||
|
"categories": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"queryOutput": [
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "FocusMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "FocusMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/LionListbox.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "FormControlMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "FormControlMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/ListboxMixin.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "InteractionStateMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "InteractionStateMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/LionListbox.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "FormRegisteringMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "FormRegisteringMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/LionOption.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "FormRegistrarMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "FormRegistrarMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/ListboxMixin.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "FormRegistrarPortalMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "FormRegistrarPortalMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/LionOptions.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "ValidateMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "ValidateMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/LionListbox.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "ChoiceGroupMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "ChoiceGroupMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/ListboxMixin.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "ChoiceInputMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "ChoiceInputMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/LionOption.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"match-subclasses": [
|
||||||
|
{
|
||||||
|
"fileName": "match-subclasses_-_%40lion%2Finput_0.15.7_+_%40lion%2Fform-core_0.15.4__-1212823364.json",
|
||||||
|
"content": {
|
||||||
|
"meta": {
|
||||||
|
"searchType": "ast-analyzer",
|
||||||
|
"analyzerMeta": {
|
||||||
|
"name": "match-subclasses",
|
||||||
|
"requiredAst": "babel",
|
||||||
|
"identifier": "%40lion%2Finput_0.15.7_+_%40lion%2Fform-core_0.15.4__-1212823364",
|
||||||
|
"targetProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/input",
|
||||||
|
"version": "0.15.7",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"referenceProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/form-core",
|
||||||
|
"version": "0.15.4",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"configuration": {
|
||||||
|
"gatherFilesConfig": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gatherFilesConfigReference": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"skipCheckMatchCompatibility": false,
|
||||||
|
"metaConfig": {
|
||||||
|
"categoryConfig": [
|
||||||
|
{
|
||||||
|
"project": "@lion/overlays",
|
||||||
|
"majorVersion": 1,
|
||||||
|
"categories": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"queryOutput": [
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "LionField",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "LionField::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/input",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionInput.js",
|
||||||
|
"identifier": "LionInput"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "NativeTextFieldMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "NativeTextFieldMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/input",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionInput.js",
|
||||||
|
"identifier": "LionInput"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "Validator",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "Validator::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/input",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./test/lion-input.test.js",
|
||||||
|
"identifier": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fileName": "match-subclasses_-_%40lion%2Flistbox_0.10.7_+_%40lion%2Fform-core_0.15.4__-222436449.json",
|
||||||
|
"content": {
|
||||||
|
"meta": {
|
||||||
|
"searchType": "ast-analyzer",
|
||||||
|
"analyzerMeta": {
|
||||||
|
"name": "match-subclasses",
|
||||||
|
"requiredAst": "babel",
|
||||||
|
"identifier": "%40lion%2Flistbox_0.10.7_+_%40lion%2Fform-core_0.15.4__-222436449",
|
||||||
|
"targetProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/listbox",
|
||||||
|
"version": "0.10.7",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"referenceProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/form-core",
|
||||||
|
"version": "0.15.4",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"configuration": {
|
||||||
|
"gatherFilesConfig": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gatherFilesConfigReference": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"skipCheckMatchCompatibility": false,
|
||||||
|
"metaConfig": {
|
||||||
|
"categoryConfig": [
|
||||||
|
{
|
||||||
|
"project": "@lion/overlays",
|
||||||
|
"majorVersion": 1,
|
||||||
|
"categories": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"queryOutput": [
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "FocusMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "FocusMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionListbox.js",
|
||||||
|
"identifier": "LionListbox"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "FormControlMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "FormControlMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/ListboxMixin.js",
|
||||||
|
"identifier": "ListboxMixin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "InteractionStateMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "InteractionStateMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionListbox.js",
|
||||||
|
"identifier": "LionListbox"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "FormRegisteringMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "FormRegisteringMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionOption.js",
|
||||||
|
"identifier": "LionOption"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "FormRegistrarMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "FormRegistrarMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/ListboxMixin.js",
|
||||||
|
"identifier": "ListboxMixin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "FormRegistrarPortalMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "FormRegistrarPortalMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionOptions.js",
|
||||||
|
"identifier": "LionOptions"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "ValidateMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "ValidateMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionListbox.js",
|
||||||
|
"identifier": "LionListbox"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "ChoiceGroupMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "ChoiceGroupMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/ListboxMixin.js",
|
||||||
|
"identifier": "ListboxMixin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "ChoiceInputMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "ChoiceInputMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionOption.js",
|
||||||
|
"identifier": "LionOption"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"searchType": "ast-analyzer",
|
||||||
|
"analyzerMeta": {
|
||||||
|
"name": "match-imports",
|
||||||
|
"requiredAst": "babel",
|
||||||
|
"identifier": "%40lion%2Finput_0.15.7_+_%40lion%2Fform-core_0.15.4__1410239906",
|
||||||
|
"targetProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/input",
|
||||||
|
"version": "0.15.7",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"referenceProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/form-core",
|
||||||
|
"version": "0.15.4",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"configuration": {
|
||||||
|
"gatherFilesConfig": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"targetProjectResult": null,
|
||||||
|
"referenceProjectResult": null,
|
||||||
|
"gatherFilesConfigReference": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"skipCheckMatchCompatibility": false,
|
||||||
|
"metaConfig": {
|
||||||
|
"categoryConfig": [
|
||||||
|
{
|
||||||
|
"project": "@lion/overlays",
|
||||||
|
"majorVersion": 1,
|
||||||
|
"categories": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"queryOutput": [
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "LionField::./index.js::@lion/form-core",
|
||||||
|
"name": "LionField",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/input",
|
||||||
|
"files": [
|
||||||
|
"./src/LionInput.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "NativeTextFieldMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "NativeTextFieldMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/input",
|
||||||
|
"files": [
|
||||||
|
"./src/LionInput.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "Validator::./index.js::@lion/form-core",
|
||||||
|
"name": "Validator",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/input",
|
||||||
|
"files": [
|
||||||
|
"./test/lion-input.test.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,194 @@
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"searchType": "ast-analyzer",
|
||||||
|
"analyzerMeta": {
|
||||||
|
"name": "match-imports",
|
||||||
|
"requiredAst": "babel",
|
||||||
|
"identifier": "%40lion%2Flistbox_0.10.7_+_%40lion%2Fform-core_0.15.4__-1773728033",
|
||||||
|
"targetProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/listbox",
|
||||||
|
"version": "0.10.7",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"referenceProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/form-core",
|
||||||
|
"version": "0.15.4",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"configuration": {
|
||||||
|
"gatherFilesConfig": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"targetProjectResult": null,
|
||||||
|
"referenceProjectResult": null,
|
||||||
|
"gatherFilesConfigReference": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"skipCheckMatchCompatibility": false,
|
||||||
|
"metaConfig": {
|
||||||
|
"categoryConfig": [
|
||||||
|
{
|
||||||
|
"project": "@lion/overlays",
|
||||||
|
"majorVersion": 1,
|
||||||
|
"categories": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"queryOutput": [
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "FocusMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "FocusMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/LionListbox.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "FormControlMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "FormControlMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/ListboxMixin.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "InteractionStateMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "InteractionStateMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/LionListbox.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "FormRegisteringMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "FormRegisteringMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/LionOption.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "FormRegistrarMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "FormRegistrarMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/ListboxMixin.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "FormRegistrarPortalMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "FormRegistrarPortalMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/LionOptions.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "ValidateMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "ValidateMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/LionListbox.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "ChoiceGroupMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "ChoiceGroupMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/ListboxMixin.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"id": "ChoiceInputMixin::./index.js::@lion/form-core",
|
||||||
|
"name": "ChoiceInputMixin",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"project": "@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
"./src/LionOption.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"searchType": "ast-analyzer",
|
||||||
|
"analyzerMeta": {
|
||||||
|
"name": "match-subclasses",
|
||||||
|
"requiredAst": "babel",
|
||||||
|
"identifier": "%40lion%2Finput_0.15.7_+_%40lion%2Fform-core_0.15.4__-1212823364",
|
||||||
|
"targetProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/input",
|
||||||
|
"version": "0.15.7",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"referenceProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/form-core",
|
||||||
|
"version": "0.15.4",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"configuration": {
|
||||||
|
"gatherFilesConfig": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gatherFilesConfigReference": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"skipCheckMatchCompatibility": false,
|
||||||
|
"metaConfig": {
|
||||||
|
"categoryConfig": [
|
||||||
|
{
|
||||||
|
"project": "@lion/overlays",
|
||||||
|
"majorVersion": 1,
|
||||||
|
"categories": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"queryOutput": [
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "LionField",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "LionField::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/input",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionInput.js",
|
||||||
|
"identifier": "LionInput"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "NativeTextFieldMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "NativeTextFieldMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/input",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionInput.js",
|
||||||
|
"identifier": "LionInput"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "Validator",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "Validator::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/input",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./test/lion-input.test.js",
|
||||||
|
"identifier": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,219 @@
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"searchType": "ast-analyzer",
|
||||||
|
"analyzerMeta": {
|
||||||
|
"name": "match-subclasses",
|
||||||
|
"requiredAst": "babel",
|
||||||
|
"identifier": "%40lion%2Flistbox_0.10.7_+_%40lion%2Fform-core_0.15.4__-222436449",
|
||||||
|
"targetProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/listbox",
|
||||||
|
"version": "0.10.7",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"referenceProject": {
|
||||||
|
"mainEntry": "./index.js",
|
||||||
|
"name": "@lion/form-core",
|
||||||
|
"version": "0.15.4",
|
||||||
|
"commitHash": "[not-a-git-root]"
|
||||||
|
},
|
||||||
|
"configuration": {
|
||||||
|
"gatherFilesConfig": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gatherFilesConfigReference": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".html"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"skipCheckMatchCompatibility": false,
|
||||||
|
"metaConfig": {
|
||||||
|
"categoryConfig": [
|
||||||
|
{
|
||||||
|
"project": "@lion/overlays",
|
||||||
|
"majorVersion": 1,
|
||||||
|
"categories": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"queryOutput": [
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "FocusMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "FocusMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionListbox.js",
|
||||||
|
"identifier": "LionListbox"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "FormControlMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "FormControlMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/ListboxMixin.js",
|
||||||
|
"identifier": "ListboxMixin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "InteractionStateMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "InteractionStateMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionListbox.js",
|
||||||
|
"identifier": "LionListbox"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "FormRegisteringMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "FormRegisteringMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionOption.js",
|
||||||
|
"identifier": "LionOption"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "FormRegistrarMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "FormRegistrarMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/ListboxMixin.js",
|
||||||
|
"identifier": "ListboxMixin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "FormRegistrarPortalMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "FormRegistrarPortalMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionOptions.js",
|
||||||
|
"identifier": "LionOptions"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "ValidateMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "ValidateMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionListbox.js",
|
||||||
|
"identifier": "LionListbox"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "ChoiceGroupMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "ChoiceGroupMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/ListboxMixin.js",
|
||||||
|
"identifier": "ListboxMixin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"exportSpecifier": {
|
||||||
|
"name": "ChoiceInputMixin",
|
||||||
|
"project": "@lion/form-core",
|
||||||
|
"filePath": "./index.js",
|
||||||
|
"id": "ChoiceInputMixin::./index.js::@lion/form-core"
|
||||||
|
},
|
||||||
|
"matchesPerProject": [
|
||||||
|
{
|
||||||
|
"project": "@lion/listbox",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"file": "./src/LionOption.js",
|
||||||
|
"identifier": "LionOption"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"@lion/input#0.15.7": [
|
||||||
|
"@lion/input#0.15.7"
|
||||||
|
],
|
||||||
|
"@lion/listbox#0.10.7": [
|
||||||
|
"@lion/listbox#0.10.7"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
export default {
|
||||||
|
metaConfig: {
|
||||||
|
categoryConfig: [
|
||||||
|
{
|
||||||
|
// This is the name found in package.json
|
||||||
|
project: '@lion/overlays',
|
||||||
|
majorVersion: 1,
|
||||||
|
// These conditions will be run on overy filePath
|
||||||
|
categories: {
|
||||||
|
overlays: localFilePath => {
|
||||||
|
const names = ['dialog', 'tooltip'];
|
||||||
|
const fromPackages = names.some(p =>
|
||||||
|
localFilePath.startsWith(`./packages/ui/components/${p}`),
|
||||||
|
);
|
||||||
|
const fromRoot =
|
||||||
|
names.some(p => localFilePath.startsWith(`./ui-${p}`)) ||
|
||||||
|
localFilePath.startsWith('./overlays.js');
|
||||||
|
return fromPackages || fromRoot;
|
||||||
|
},
|
||||||
|
// etc...
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// By predefening groups, we can do a query for programs/collections...
|
||||||
|
// Select via " providence analyze --search-target-collection 'exampleCollection' "
|
||||||
|
searchTargetCollections: {
|
||||||
|
'@lion-targets': ['../../packages/ui'],
|
||||||
|
// ...
|
||||||
|
},
|
||||||
|
referenceCollections: {
|
||||||
|
// Usually the references are different from the targets.
|
||||||
|
// In this demo file, we test @lion usage amongst itself
|
||||||
|
// Select via " providence analyze --reference-collection 'exampleCollection' "
|
||||||
|
'@lion-references': ['../../packages/ui'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -1,15 +1,26 @@
|
||||||
const pathLib = require('path');
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
const { expect } = require('chai');
|
import pathLib, { dirname } from 'path';
|
||||||
const { providence } = require('../../../../src/program/providence.js');
|
import { fileURLToPath } from 'url';
|
||||||
const { QueryService } = require('../../../../src/program/services/QueryService.js');
|
import fs from 'fs';
|
||||||
const { ReportService } = require('../../../../src/program/services/ReportService.js');
|
import { expect } from 'chai';
|
||||||
|
import { providence } from '../../../../src/program/providence.js';
|
||||||
|
import { QueryService } from '../../../../src/program/core/QueryService.js';
|
||||||
|
import { ReportService } from '../../../../src/program/core/ReportService.js';
|
||||||
|
import { memoizeConfig } from '../../../../src/program/utils/memoize.js';
|
||||||
|
|
||||||
const {
|
import {
|
||||||
mockWriteToJson,
|
mockWriteToJson,
|
||||||
restoreWriteToJson,
|
restoreWriteToJson,
|
||||||
} = require('../../../../test-helpers/mock-report-service-helpers.js');
|
} from '../../../../test-helpers/mock-report-service-helpers.js';
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
describe('Analyzers file-system integration', () => {
|
describe('Analyzers file-system integration', () => {
|
||||||
|
/**
|
||||||
|
* Flag to enable mode that generates e2e mocks.
|
||||||
|
* We 'abuse' this test file for that purpose for ease of maintenance
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
const generateE2eMode = process.argv.includes('--generate-e2e-mode');
|
const generateE2eMode = process.argv.includes('--generate-e2e-mode');
|
||||||
|
|
||||||
const queryResults = [];
|
const queryResults = [];
|
||||||
|
|
@ -25,9 +36,13 @@ describe('Analyzers file-system integration', () => {
|
||||||
const originalGetResultFileNameAndPath = ReportService._getResultFileNameAndPath;
|
const originalGetResultFileNameAndPath = ReportService._getResultFileNameAndPath;
|
||||||
const originalOutputPath = ReportService.outputPath;
|
const originalOutputPath = ReportService.outputPath;
|
||||||
|
|
||||||
|
const memoizeCacheDisabledInitial = memoizeConfig.isCacheDisabled;
|
||||||
|
memoizeConfig.isCacheDisabled = true;
|
||||||
|
|
||||||
after(() => {
|
after(() => {
|
||||||
ReportService._getResultFileNameAndPath = originalGetResultFileNameAndPath;
|
ReportService._getResultFileNameAndPath = originalGetResultFileNameAndPath;
|
||||||
ReportService.outputPath = originalOutputPath;
|
ReportService.outputPath = originalOutputPath;
|
||||||
|
memoizeConfig.isCacheDisabled = memoizeCacheDisabledInitial;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (generateE2eMode) {
|
if (generateE2eMode) {
|
||||||
|
|
@ -108,8 +123,15 @@ describe('Analyzers file-system integration', () => {
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line import/no-dynamic-require, global-require
|
const expectedOutput = JSON.parse(
|
||||||
const expectedOutput = require(`../../../../test-helpers/project-mocks-analyzer-outputs/${analyzerName}.json`);
|
fs.readFileSync(
|
||||||
|
pathLib.resolve(
|
||||||
|
__dirname,
|
||||||
|
`../../../../test-helpers/project-mocks-analyzer-outputs/${analyzerName}.json`,
|
||||||
|
),
|
||||||
|
'utf8',
|
||||||
|
),
|
||||||
|
);
|
||||||
const { queryOutput } = JSON.parse(JSON.stringify(queryResults[0]));
|
const { queryOutput } = JSON.parse(JSON.stringify(queryResults[0]));
|
||||||
expect(queryOutput).not.to.eql([]);
|
expect(queryOutput).not.to.eql([]);
|
||||||
expect(queryOutput).to.eql(expectedOutput.queryOutput);
|
expect(queryOutput).to.eql(expectedOutput.queryOutput);
|
||||||
|
|
@ -1,49 +1,17 @@
|
||||||
const { expect } = require('chai');
|
const { expect } = require('chai');
|
||||||
const { providence } = require('../../../src/program/providence.js');
|
const { providence } = require('../../../src/program/providence.js');
|
||||||
const { QueryService } = require('../../../src/program/services/QueryService.js');
|
const { QueryService } = require('../../../src/program/core/QueryService.js');
|
||||||
const {
|
const { setupAnalyzerTest } = require('../../../test-helpers/setup-analyzer-test.js');
|
||||||
mockProject,
|
const { mockProject, getEntry } = require('../../../test-helpers/mock-project-helpers.js');
|
||||||
restoreMockedProjects,
|
|
||||||
getEntry,
|
|
||||||
} = require('../../../test-helpers/mock-project-helpers.js');
|
|
||||||
const {
|
|
||||||
mockWriteToJson,
|
|
||||||
restoreWriteToJson,
|
|
||||||
} = require('../../../test-helpers/mock-report-service-helpers.js');
|
|
||||||
const {
|
|
||||||
suppressNonCriticalLogs,
|
|
||||||
restoreSuppressNonCriticalLogs,
|
|
||||||
} = require('../../../test-helpers/mock-log-service-helpers.js');
|
|
||||||
|
|
||||||
const findClassesQueryConfig = QueryService.getQueryConfigFromAnalyzer('find-classes');
|
const findClassesQueryConfig = QueryService.getQueryConfigFromAnalyzer('find-classes');
|
||||||
|
|
||||||
describe('Analyzer "find-classes"', () => {
|
describe('Analyzer "find-classes"', () => {
|
||||||
const queryResults = [];
|
const queryResults = setupAnalyzerTest();
|
||||||
const _providenceCfg = {
|
const _providenceCfg = {
|
||||||
targetProjectPaths: ['/fictional/project'], // defined in mockProject
|
targetProjectPaths: ['/fictional/project'], // defined in mockProject
|
||||||
};
|
};
|
||||||
|
|
||||||
const cacheDisabledInitialValue = QueryService.cacheDisabled;
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
QueryService.cacheDisabled = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
QueryService.cacheDisabled = cacheDisabledInitialValue;
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
suppressNonCriticalLogs();
|
|
||||||
mockWriteToJson(queryResults);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
restoreSuppressNonCriticalLogs();
|
|
||||||
restoreWriteToJson(queryResults);
|
|
||||||
restoreMockedProjects();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`finds class definitions`, async () => {
|
it(`finds class definitions`, async () => {
|
||||||
mockProject([`class EmptyClass {}`]);
|
mockProject([`class EmptyClass {}`]);
|
||||||
await providence(findClassesQueryConfig, _providenceCfg);
|
await providence(findClassesQueryConfig, _providenceCfg);
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,9 @@
|
||||||
const { expect } = require('chai');
|
const { expect } = require('chai');
|
||||||
const { providence } = require('../../../src/program/providence.js');
|
const { providence } = require('../../../src/program/providence.js');
|
||||||
const { QueryService } = require('../../../src/program/services/QueryService.js');
|
const { QueryService } = require('../../../src/program/core/QueryService.js');
|
||||||
const {
|
const { setupAnalyzerTest } = require('../../../test-helpers/setup-analyzer-test.js');
|
||||||
mockProject,
|
|
||||||
restoreMockedProjects,
|
const { mockProject, getEntry } = require('../../../test-helpers/mock-project-helpers.js');
|
||||||
getEntry,
|
|
||||||
} = require('../../../test-helpers/mock-project-helpers.js');
|
|
||||||
const {
|
|
||||||
mockWriteToJson,
|
|
||||||
restoreWriteToJson,
|
|
||||||
} = require('../../../test-helpers/mock-report-service-helpers.js');
|
|
||||||
const {
|
|
||||||
suppressNonCriticalLogs,
|
|
||||||
restoreSuppressNonCriticalLogs,
|
|
||||||
} = require('../../../test-helpers/mock-log-service-helpers.js');
|
|
||||||
|
|
||||||
const findCustomelementsQueryConfig =
|
const findCustomelementsQueryConfig =
|
||||||
QueryService.getQueryConfigFromAnalyzer('find-customelements');
|
QueryService.getQueryConfigFromAnalyzer('find-customelements');
|
||||||
|
|
@ -22,28 +12,7 @@ const _providenceCfg = {
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Analyzer "find-customelements"', () => {
|
describe('Analyzer "find-customelements"', () => {
|
||||||
const queryResults = [];
|
const queryResults = setupAnalyzerTest();
|
||||||
|
|
||||||
const cacheDisabledInitialValue = QueryService.cacheDisabled;
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
QueryService.cacheDisabled = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
QueryService.cacheDisabled = cacheDisabledInitialValue;
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
suppressNonCriticalLogs();
|
|
||||||
mockWriteToJson(queryResults);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
restoreSuppressNonCriticalLogs();
|
|
||||||
restoreMockedProjects();
|
|
||||||
restoreWriteToJson(queryResults);
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`stores the tagName of a custom element`, async () => {
|
it(`stores the tagName of a custom element`, async () => {
|
||||||
mockProject([`customElements.define('custom-el', class extends HTMLElement {});`]);
|
mockProject([`customElements.define('custom-el', class extends HTMLElement {});`]);
|
||||||
|
|
|
||||||
|
|
@ -1,50 +1,22 @@
|
||||||
const { expect } = require('chai');
|
const { expect } = require('chai');
|
||||||
const { providence } = require('../../../src/program/providence.js');
|
const { providence } = require('../../../src/program/providence.js');
|
||||||
const { QueryService } = require('../../../src/program/services/QueryService.js');
|
const { QueryService } = require('../../../src/program/core/QueryService.js');
|
||||||
|
const { setupAnalyzerTest } = require('../../../test-helpers/setup-analyzer-test.js');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mockProject,
|
mockProject,
|
||||||
restoreMockedProjects,
|
|
||||||
getEntry,
|
getEntry,
|
||||||
getEntries,
|
getEntries,
|
||||||
} = require('../../../test-helpers/mock-project-helpers.js');
|
} = require('../../../test-helpers/mock-project-helpers.js');
|
||||||
const {
|
|
||||||
mockWriteToJson,
|
|
||||||
restoreWriteToJson,
|
|
||||||
} = require('../../../test-helpers/mock-report-service-helpers.js');
|
|
||||||
const {
|
|
||||||
suppressNonCriticalLogs,
|
|
||||||
restoreSuppressNonCriticalLogs,
|
|
||||||
} = require('../../../test-helpers/mock-log-service-helpers.js');
|
|
||||||
|
|
||||||
const findExportsQueryConfig = QueryService.getQueryConfigFromAnalyzer('find-exports');
|
const findExportsQueryConfig = QueryService.getQueryConfigFromAnalyzer('find-exports');
|
||||||
|
|
||||||
describe('Analyzer "find-exports"', () => {
|
describe('Analyzer "find-exports"', () => {
|
||||||
const queryResults = [];
|
const queryResults = setupAnalyzerTest();
|
||||||
const _providenceCfg = {
|
const _providenceCfg = {
|
||||||
targetProjectPaths: ['/fictional/project'], // defined in mockProject
|
targetProjectPaths: ['/fictional/project'], // defined in mockProject
|
||||||
};
|
};
|
||||||
|
|
||||||
const cacheDisabledInitialValue = QueryService.cacheDisabled;
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
QueryService.cacheDisabled = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
QueryService.cacheDisabled = cacheDisabledInitialValue;
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
suppressNonCriticalLogs();
|
|
||||||
mockWriteToJson(queryResults);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
restoreSuppressNonCriticalLogs();
|
|
||||||
restoreWriteToJson(queryResults);
|
|
||||||
restoreMockedProjects();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Export notations', () => {
|
describe('Export notations', () => {
|
||||||
it(`supports [export const x = 0] (named specifier)`, async () => {
|
it(`supports [export const x = 0] (named specifier)`, async () => {
|
||||||
mockProject([`export const x = 0`]);
|
mockProject([`export const x = 0`]);
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,21 @@
|
||||||
const { expect } = require('chai');
|
const { expect } = require('chai');
|
||||||
const { providence } = require('../../../src/program/providence.js');
|
const { providence } = require('../../../src/program/providence.js');
|
||||||
const { QueryService } = require('../../../src/program/services/QueryService.js');
|
const { QueryService } = require('../../../src/program/core/QueryService.js');
|
||||||
const {
|
const { setupAnalyzerTest } = require('../../../test-helpers/setup-analyzer-test.js');
|
||||||
mockProject,
|
const { mockProject, getEntry } = require('../../../test-helpers/mock-project-helpers.js');
|
||||||
restoreMockedProjects,
|
|
||||||
getEntry,
|
/**
|
||||||
} = require('../../../test-helpers/mock-project-helpers.js');
|
* @typedef {import('../../../src/program/types/core').ProvidenceConfig} ProvidenceConfig
|
||||||
const {
|
*/
|
||||||
mockWriteToJson,
|
|
||||||
restoreWriteToJson,
|
|
||||||
} = require('../../../test-helpers/mock-report-service-helpers.js');
|
|
||||||
const {
|
|
||||||
suppressNonCriticalLogs,
|
|
||||||
restoreSuppressNonCriticalLogs,
|
|
||||||
} = require('../../../test-helpers/mock-log-service-helpers.js');
|
|
||||||
|
|
||||||
const findImportsQueryConfig = QueryService.getQueryConfigFromAnalyzer('find-imports');
|
const findImportsQueryConfig = QueryService.getQueryConfigFromAnalyzer('find-imports');
|
||||||
|
/** @type {Partial<ProvidenceConfig>} */
|
||||||
const _providenceCfg = {
|
const _providenceCfg = {
|
||||||
targetProjectPaths: ['/fictional/project'], // defined in mockProject
|
targetProjectPaths: ['/fictional/project'], // defined in mockProject
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Analyzer "find-imports"', () => {
|
describe('Analyzer "find-imports"', () => {
|
||||||
const queryResults = [];
|
const queryResults = setupAnalyzerTest();
|
||||||
const cacheDisabledInitialValue = QueryService.cacheDisabled;
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
QueryService.cacheDisabled = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
QueryService.cacheDisabled = cacheDisabledInitialValue;
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
suppressNonCriticalLogs();
|
|
||||||
mockWriteToJson(queryResults);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
restoreSuppressNonCriticalLogs();
|
|
||||||
restoreMockedProjects();
|
|
||||||
restoreWriteToJson(queryResults);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Import notations', () => {
|
describe('Import notations', () => {
|
||||||
it(`supports [import 'imported/source'] (no specifiers)`, async () => {
|
it(`supports [import 'imported/source'] (no specifiers)`, async () => {
|
||||||
|
|
@ -190,7 +164,6 @@ describe('Analyzer "find-imports"', () => {
|
||||||
await providence(findImportsQueryConfig, _providenceCfg);
|
await providence(findImportsQueryConfig, _providenceCfg);
|
||||||
const queryResult = queryResults[0];
|
const queryResult = queryResults[0];
|
||||||
const firstEntry = getEntry(queryResult);
|
const firstEntry = getEntry(queryResult);
|
||||||
console.log({ firstEntry });
|
|
||||||
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('[default]');
|
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('[default]');
|
||||||
expect(firstEntry.result[0].source).to.equal('@css/lib/styles.css');
|
expect(firstEntry.result[0].source).to.equal('@css/lib/styles.css');
|
||||||
expect(firstEntry.result[0].assertionType).to.equal('css');
|
expect(firstEntry.result[0].assertionType).to.equal('css');
|
||||||
|
|
@ -201,7 +174,6 @@ describe('Analyzer "find-imports"', () => {
|
||||||
await providence(findImportsQueryConfig, _providenceCfg);
|
await providence(findImportsQueryConfig, _providenceCfg);
|
||||||
const queryResult = queryResults[0];
|
const queryResult = queryResults[0];
|
||||||
const firstEntry = getEntry(queryResult);
|
const firstEntry = getEntry(queryResult);
|
||||||
console.log({ firstEntry });
|
|
||||||
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('[default]');
|
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('[default]');
|
||||||
expect(firstEntry.result[0].source).to.equal('@css/lib/styles.css');
|
expect(firstEntry.result[0].source).to.equal('@css/lib/styles.css');
|
||||||
expect(firstEntry.result[0].assertionType).to.equal('css');
|
expect(firstEntry.result[0].assertionType).to.equal('css');
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,19 @@ const {
|
||||||
trackDownIdentifier,
|
trackDownIdentifier,
|
||||||
trackDownIdentifierFromScope,
|
trackDownIdentifierFromScope,
|
||||||
} = require('../../../../src/program/analyzers/helpers/track-down-identifier.js');
|
} = require('../../../../src/program/analyzers/helpers/track-down-identifier.js');
|
||||||
const { AstService } = require('../../../../src/program/services/AstService.js');
|
const { AstService } = require('../../../../src/program/core/AstService.js');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mockProject,
|
mockProject,
|
||||||
restoreMockedProjects,
|
restoreMockedProjects,
|
||||||
} = require('../../../../test-helpers/mock-project-helpers.js');
|
} = require('../../../../test-helpers/mock-project-helpers.js');
|
||||||
|
const { memoizeConfig } = require('../../../../src/program/utils/memoize.js');
|
||||||
|
|
||||||
describe('trackdownIdentifier', () => {
|
describe('trackdownIdentifier', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
memoizeConfig.isCacheDisabled = true;
|
||||||
|
});
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
memoizeConfig.isCacheDisabled = false;
|
||||||
restoreMockedProjects();
|
restoreMockedProjects();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -168,13 +172,18 @@ describe('trackdownIdentifier', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`identifies the current project as internal source`, async () => {
|
it(`self-referencing projects are recognized as internal source`, async () => {
|
||||||
|
// https://nodejs.org/api/packages.html#self-referencing-a-package-using-its-name
|
||||||
mockProject(
|
mockProject(
|
||||||
{
|
{
|
||||||
'./MyClass.js': `export default class {}`,
|
'./MyClass.js': `export default class {}`,
|
||||||
'./currentFile.js': `
|
'./currentFile.js': `
|
||||||
import MyClass from 'my-project/MyClass.js';
|
import MyClass from 'my-project/MyClass.js';
|
||||||
`,
|
`,
|
||||||
|
'./package.json': JSON.stringify({
|
||||||
|
name: 'my-project',
|
||||||
|
exports: { './MyClass.js': './MyClass.js' },
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
projectName: 'my-project',
|
projectName: 'my-project',
|
||||||
|
|
@ -183,7 +192,7 @@ describe('trackdownIdentifier', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Let's say we want to track down 'MyClass' in the code above
|
// Let's say we want to track down 'MyClass' in the code above
|
||||||
const source = '#internal/source';
|
const source = 'my-project/MyClass.js';
|
||||||
const identifierName = '[default]';
|
const identifierName = '[default]';
|
||||||
const currentFilePath = '/my/project/currentFile.js';
|
const currentFilePath = '/my/project/currentFile.js';
|
||||||
const rootPath = '/my/project';
|
const rootPath = '/my/project';
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,10 @@
|
||||||
const { expect } = require('chai');
|
const { expect } = require('chai');
|
||||||
const { providence } = require('../../../src/program/providence.js');
|
const { providence } = require('../../../src/program/providence.js');
|
||||||
const { QueryService } = require('../../../src/program/services/QueryService.js');
|
const { QueryService } = require('../../../src/program/core/QueryService.js');
|
||||||
const { InputDataService } = require('../../../src/program/services/InputDataService.js');
|
|
||||||
const FindExportsAnalyzer = require('../../../src/program/analyzers/find-exports.js');
|
const FindExportsAnalyzer = require('../../../src/program/analyzers/find-exports.js');
|
||||||
const FindImportsAnalyzer = require('../../../src/program/analyzers/find-imports.js');
|
const FindImportsAnalyzer = require('../../../src/program/analyzers/find-imports.js');
|
||||||
|
const { setupAnalyzerTest } = require('../../../test-helpers/setup-analyzer-test.js');
|
||||||
const {
|
const { mockTargetAndReferenceProject } = require('../../../test-helpers/mock-project-helpers.js');
|
||||||
mockTargetAndReferenceProject,
|
|
||||||
restoreMockedProjects,
|
|
||||||
} = require('../../../test-helpers/mock-project-helpers.js');
|
|
||||||
const {
|
|
||||||
mockWriteToJson,
|
|
||||||
restoreWriteToJson,
|
|
||||||
} = require('../../../test-helpers/mock-report-service-helpers.js');
|
|
||||||
const {
|
|
||||||
suppressNonCriticalLogs,
|
|
||||||
restoreSuppressNonCriticalLogs,
|
|
||||||
} = require('../../../test-helpers/mock-log-service-helpers.js');
|
|
||||||
|
|
||||||
const matchImportsQueryConfig = QueryService.getQueryConfigFromAnalyzer('match-imports');
|
const matchImportsQueryConfig = QueryService.getQueryConfigFromAnalyzer('match-imports');
|
||||||
const _providenceCfg = {
|
const _providenceCfg = {
|
||||||
|
|
@ -210,31 +198,7 @@ const expectedMatchesOutput = [
|
||||||
];
|
];
|
||||||
|
|
||||||
describe('Analyzer "match-imports"', () => {
|
describe('Analyzer "match-imports"', () => {
|
||||||
const originalReferenceProjectPaths = InputDataService.referenceProjectPaths;
|
const queryResults = setupAnalyzerTest();
|
||||||
const queryResults = [];
|
|
||||||
|
|
||||||
const cacheDisabledInitialValue = QueryService.cacheDisabled;
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
QueryService.cacheDisabled = true;
|
|
||||||
suppressNonCriticalLogs();
|
|
||||||
});
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
QueryService.cacheDisabled = cacheDisabledInitialValue;
|
|
||||||
restoreSuppressNonCriticalLogs();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mockWriteToJson(queryResults);
|
|
||||||
InputDataService.referenceProjectPaths = [];
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
InputDataService.referenceProjectPaths = originalReferenceProjectPaths;
|
|
||||||
restoreWriteToJson(queryResults);
|
|
||||||
restoreMockedProjects();
|
|
||||||
});
|
|
||||||
|
|
||||||
function testMatchedEntry(targetExportedId, queryResult, importedByFiles = []) {
|
function testMatchedEntry(targetExportedId, queryResult, importedByFiles = []) {
|
||||||
const matchedEntry = queryResult.queryOutput.find(
|
const matchedEntry = queryResult.queryOutput.find(
|
||||||
|
|
@ -466,6 +430,51 @@ describe('Analyzer "match-imports"', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it(`correctly merges/dedupes double found file matches when imported in different ways`, async () => {
|
||||||
|
const refProject = {
|
||||||
|
path: '/target/node_modules/ref',
|
||||||
|
name: 'ref',
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
file: './src/core.js',
|
||||||
|
code: `
|
||||||
|
export default function x() {};
|
||||||
|
export class RefClass extends HTMLElement {}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const targetProject = {
|
||||||
|
path: '/target',
|
||||||
|
name: 'target',
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
file: './deep-imports.js',
|
||||||
|
code: `
|
||||||
|
import myFn1 from 'ref/src/core.js';
|
||||||
|
import { RefClass } from 'ref/src/core.js';
|
||||||
|
|
||||||
|
import * as all from 'ref/src/core.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: ['./deep-imports.js'], project: 'target' },
|
||||||
|
]);
|
||||||
|
expect(queryResult.queryOutput[1].exportSpecifier.name).to.equal('RefClass');
|
||||||
|
expect(queryResult.queryOutput[1].matchesPerProject).to.eql([
|
||||||
|
{ files: ['./deep-imports.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);
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,11 @@
|
||||||
const { expect } = require('chai');
|
const { expect } = require('chai');
|
||||||
const { providence } = require('../../../src/program/providence.js');
|
const { providence } = require('../../../src/program/providence.js');
|
||||||
const { QueryService } = require('../../../src/program/services/QueryService.js');
|
const { QueryService } = require('../../../src/program/core/QueryService.js');
|
||||||
const { InputDataService } = require('../../../src/program/services/InputDataService.js');
|
const { setupAnalyzerTest } = require('../../../test-helpers/setup-analyzer-test.js');
|
||||||
const {
|
const { mockTargetAndReferenceProject } = require('../../../test-helpers/mock-project-helpers.js');
|
||||||
mockTargetAndReferenceProject,
|
|
||||||
restoreMockedProjects,
|
|
||||||
} = require('../../../test-helpers/mock-project-helpers.js');
|
|
||||||
const {
|
|
||||||
mockWriteToJson,
|
|
||||||
restoreWriteToJson,
|
|
||||||
} = require('../../../test-helpers/mock-report-service-helpers.js');
|
|
||||||
const {
|
|
||||||
suppressNonCriticalLogs,
|
|
||||||
restoreSuppressNonCriticalLogs,
|
|
||||||
} = require('../../../test-helpers/mock-log-service-helpers.js');
|
|
||||||
|
|
||||||
describe('Analyzer "match-paths"', () => {
|
describe('Analyzer "match-paths"', () => {
|
||||||
const originalReferenceProjectPaths = InputDataService.referenceProjectPaths;
|
const queryResults = setupAnalyzerTest();
|
||||||
const queryResults = [];
|
|
||||||
const cacheDisabledInitialValue = QueryService.cacheDisabled;
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
QueryService.cacheDisabled = true;
|
|
||||||
suppressNonCriticalLogs();
|
|
||||||
});
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
QueryService.cacheDisabled = cacheDisabledInitialValue;
|
|
||||||
restoreSuppressNonCriticalLogs();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
InputDataService.referenceProjectPaths = [];
|
|
||||||
mockWriteToJson(queryResults);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
InputDataService.referenceProjectPaths = originalReferenceProjectPaths;
|
|
||||||
restoreWriteToJson(queryResults);
|
|
||||||
restoreMockedProjects();
|
|
||||||
});
|
|
||||||
|
|
||||||
const referenceProject = {
|
const referenceProject = {
|
||||||
path: '/importing/target/project/node_modules/reference-project',
|
path: '/importing/target/project/node_modules/reference-project',
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,8 @@
|
||||||
const { expect } = require('chai');
|
const { expect } = require('chai');
|
||||||
const { providence } = require('../../../src/program/providence.js');
|
const { providence } = require('../../../src/program/providence.js');
|
||||||
const { QueryService } = require('../../../src/program/services/QueryService.js');
|
const { QueryService } = require('../../../src/program/core/QueryService.js');
|
||||||
const { InputDataService } = require('../../../src/program/services/InputDataService.js');
|
const { mockTargetAndReferenceProject } = require('../../../test-helpers/mock-project-helpers.js');
|
||||||
const {
|
const { setupAnalyzerTest } = require('../../../test-helpers/setup-analyzer-test.js');
|
||||||
mockTargetAndReferenceProject,
|
|
||||||
restoreMockedProjects,
|
|
||||||
} = require('../../../test-helpers/mock-project-helpers.js');
|
|
||||||
const {
|
|
||||||
mockWriteToJson,
|
|
||||||
restoreWriteToJson,
|
|
||||||
} = require('../../../test-helpers/mock-report-service-helpers.js');
|
|
||||||
const {
|
|
||||||
suppressNonCriticalLogs,
|
|
||||||
restoreSuppressNonCriticalLogs,
|
|
||||||
} = require('../../../test-helpers/mock-log-service-helpers.js');
|
|
||||||
|
|
||||||
// 1. Reference input data
|
// 1. Reference input data
|
||||||
const referenceProject = {
|
const referenceProject = {
|
||||||
|
|
@ -136,59 +125,192 @@ const expectedMatchesOutput = [
|
||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
|
|
||||||
describe('Analyzer "match-subclasses"', () => {
|
describe('Analyzer "match-subclasses"', () => {
|
||||||
const originalReferenceProjectPaths = InputDataService.referenceProjectPaths;
|
const queryResults = setupAnalyzerTest();
|
||||||
const queryResults = [];
|
|
||||||
const cacheDisabledQInitialValue = QueryService.cacheDisabled;
|
|
||||||
const cacheDisabledIInitialValue = InputDataService.cacheDisabled;
|
|
||||||
|
|
||||||
before(() => {
|
describe('Match Features', () => {
|
||||||
QueryService.cacheDisabled = true;
|
it(`identifies all directly imported class extensions`, async () => {
|
||||||
InputDataService.cacheDisabled = true;
|
const refProject = {
|
||||||
suppressNonCriticalLogs();
|
path: '/target/node_modules/ref',
|
||||||
});
|
name: 'ref',
|
||||||
|
files: [{ file: './LionComp.js', code: `export class LionComp extends HTMLElement {};` }],
|
||||||
|
};
|
||||||
|
const targetProject = {
|
||||||
|
path: '/target',
|
||||||
|
name: 'target',
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
file: './WolfComp.js',
|
||||||
|
code: `
|
||||||
|
import { LionComp } from 'ref/LionComp.js';
|
||||||
|
|
||||||
after(() => {
|
export class WolfComp extends LionComp {}
|
||||||
QueryService.cacheDisabled = cacheDisabledQInitialValue;
|
`,
|
||||||
InputDataService.cacheDisabled = cacheDisabledIInitialValue;
|
},
|
||||||
restoreSuppressNonCriticalLogs();
|
],
|
||||||
});
|
};
|
||||||
|
mockTargetAndReferenceProject(targetProject, refProject);
|
||||||
|
await providence(matchSubclassesQueryConfig, {
|
||||||
|
targetProjectPaths: [targetProject.path],
|
||||||
|
referenceProjectPaths: [refProject.path],
|
||||||
|
});
|
||||||
|
const queryResult = queryResults[0];
|
||||||
|
expect(queryResult.queryOutput).eql([
|
||||||
|
{
|
||||||
|
exportSpecifier: {
|
||||||
|
filePath: './LionComp.js',
|
||||||
|
id: 'LionComp::./LionComp.js::ref',
|
||||||
|
name: 'LionComp',
|
||||||
|
project: 'ref',
|
||||||
|
},
|
||||||
|
matchesPerProject: [
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
{ file: './WolfComp.js', identifier: 'WolfComp', memberOverrides: undefined },
|
||||||
|
],
|
||||||
|
project: 'target',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
it(`identifies all indirectly imported (transitive) class extensions`, async () => {
|
||||||
InputDataService.cacheDisabled = true;
|
const refProject = {
|
||||||
InputDataService.referenceProjectPaths = [];
|
path: '/target/node_modules/ref',
|
||||||
mockWriteToJson(queryResults);
|
name: 'ref',
|
||||||
});
|
files: [
|
||||||
|
{ file: './LionComp.js', code: `export class LionComp extends HTMLElement {};` },
|
||||||
|
{
|
||||||
|
file: './RenamedLionComp.js',
|
||||||
|
code: `export { LionComp as RenamedLionComp } from './LionComp.js';`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const targetProject = {
|
||||||
|
path: '/target',
|
||||||
|
name: 'target',
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
file: './WolfComp2.js',
|
||||||
|
code: `
|
||||||
|
import { RenamedLionComp } from 'ref/RenamedLionComp.js';
|
||||||
|
|
||||||
afterEach(() => {
|
export class WolfComp2 extends RenamedLionComp {}
|
||||||
InputDataService.referenceProjectPaths = originalReferenceProjectPaths;
|
`,
|
||||||
restoreWriteToJson(queryResults);
|
},
|
||||||
restoreMockedProjects();
|
],
|
||||||
|
};
|
||||||
|
mockTargetAndReferenceProject(targetProject, refProject);
|
||||||
|
await providence(matchSubclassesQueryConfig, {
|
||||||
|
targetProjectPaths: [targetProject.path],
|
||||||
|
referenceProjectPaths: [refProject.path],
|
||||||
|
});
|
||||||
|
const queryResult = queryResults[0];
|
||||||
|
expect(queryResult.queryOutput).eql([
|
||||||
|
{
|
||||||
|
exportSpecifier: {
|
||||||
|
filePath: './RenamedLionComp.js',
|
||||||
|
id: 'RenamedLionComp::./RenamedLionComp.js::ref',
|
||||||
|
name: 'RenamedLionComp',
|
||||||
|
project: 'ref',
|
||||||
|
},
|
||||||
|
matchesPerProject: [
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
{ file: './WolfComp2.js', identifier: 'WolfComp2', memberOverrides: undefined },
|
||||||
|
],
|
||||||
|
project: 'target',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`identifies Mixins`, async () => {
|
||||||
|
const refProject = {
|
||||||
|
path: '/target/node_modules/ref',
|
||||||
|
name: 'ref',
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
file: './LionMixin.js',
|
||||||
|
code: `
|
||||||
|
export function LionMixin(superclass) {
|
||||||
|
return class extends superclass {};
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const targetProject = {
|
||||||
|
path: '/target',
|
||||||
|
name: 'target',
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
file: './WolfCompUsingMixin.js',
|
||||||
|
code: `
|
||||||
|
import { LionMixin } from 'ref/LionMixin.js';
|
||||||
|
|
||||||
|
export class WolfCompUsingMixin extends LionMixin(HTMLElement) {}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
mockTargetAndReferenceProject(targetProject, refProject);
|
||||||
|
await providence(matchSubclassesQueryConfig, {
|
||||||
|
targetProjectPaths: [targetProject.path],
|
||||||
|
referenceProjectPaths: [refProject.path],
|
||||||
|
});
|
||||||
|
const queryResult = queryResults[0];
|
||||||
|
expect(queryResult.queryOutput).eql([
|
||||||
|
{
|
||||||
|
exportSpecifier: {
|
||||||
|
filePath: './LionMixin.js',
|
||||||
|
id: 'LionMixin::./LionMixin.js::ref',
|
||||||
|
name: 'LionMixin',
|
||||||
|
project: 'ref',
|
||||||
|
},
|
||||||
|
matchesPerProject: [
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
file: './WolfCompUsingMixin.js',
|
||||||
|
identifier: 'WolfCompUsingMixin',
|
||||||
|
memberOverrides: undefined,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
project: 'target',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Extracting exports', () => {
|
describe('Extracting exports', () => {
|
||||||
it(`identifies all indirect export specifiers consumed by "importing-target-project"`, async () => {
|
describe('Inside small example project', () => {
|
||||||
mockTargetAndReferenceProject(searchTargetProject, referenceProject);
|
it(`identifies all indirect export specifiers consumed by "importing-target-project"`, async () => {
|
||||||
await providence(matchSubclassesQueryConfig, _providenceCfg);
|
mockTargetAndReferenceProject(searchTargetProject, referenceProject);
|
||||||
const queryResult = queryResults[0];
|
await providence(matchSubclassesQueryConfig, _providenceCfg);
|
||||||
expectedExportIdsIndirect.forEach(indirectId => {
|
const queryResult = queryResults[0];
|
||||||
expect(
|
expectedExportIdsIndirect.forEach(indirectId => {
|
||||||
queryResult.queryOutput.find(
|
expect(
|
||||||
exportMatchResult => exportMatchResult.exportSpecifier.id === indirectId,
|
queryResult.queryOutput.find(
|
||||||
),
|
exportMatchResult => exportMatchResult.exportSpecifier.id === indirectId,
|
||||||
).not.to.equal(undefined, `id '${indirectId}' not found`);
|
),
|
||||||
|
).not.to.equal(undefined, `id '${indirectId}' not found`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
it(`identifies all direct export specifiers consumed by "importing-target-project"`, async () => {
|
it(`identifies all direct export specifiers consumed by "importing-target-project"`, async () => {
|
||||||
mockTargetAndReferenceProject(searchTargetProject, referenceProject);
|
mockTargetAndReferenceProject(searchTargetProject, referenceProject);
|
||||||
await providence(matchSubclassesQueryConfig, _providenceCfg);
|
await providence(matchSubclassesQueryConfig, _providenceCfg);
|
||||||
const queryResult = queryResults[0];
|
const queryResult = queryResults[0];
|
||||||
expectedExportIdsDirect.forEach(directId => {
|
expectedExportIdsDirect.forEach(directId => {
|
||||||
expect(
|
expect(
|
||||||
queryResult.queryOutput.find(
|
queryResult.queryOutput.find(
|
||||||
exportMatchResult => exportMatchResult.exportSpecifier.id === directId,
|
exportMatchResult => exportMatchResult.exportSpecifier.id === directId,
|
||||||
),
|
),
|
||||||
).not.to.equal(undefined, `id '${directId}' not found`);
|
).not.to.equal(undefined, `id '${directId}' not found`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,20 @@
|
||||||
const { expect } = require('chai');
|
const { expect } = require('chai');
|
||||||
const {
|
const {
|
||||||
// mockTargetAndReferenceProject,
|
|
||||||
mockProject,
|
mockProject,
|
||||||
restoreMockedProjects,
|
restoreMockedProjects,
|
||||||
} = require('../../test-helpers/mock-project-helpers.js');
|
} = require('../../../test-helpers/mock-project-helpers.js');
|
||||||
const {
|
const { setupAnalyzerTest } = require('../../../test-helpers/setup-analyzer-test.js');
|
||||||
mockWriteToJson,
|
const { QueryService } = require('../../../src/program/core/QueryService.js');
|
||||||
restoreWriteToJson,
|
const { providence } = require('../../../src/program/providence.js');
|
||||||
} = require('../../test-helpers/mock-report-service-helpers.js');
|
const { DummyAnalyzer } = require('../../../test-helpers/templates/DummyAnalyzer.js');
|
||||||
const {
|
|
||||||
suppressNonCriticalLogs,
|
|
||||||
restoreSuppressNonCriticalLogs,
|
|
||||||
} = require('../../test-helpers/mock-log-service-helpers.js');
|
|
||||||
|
|
||||||
const { QueryService } = require('../../src/program/services/QueryService.js');
|
/**
|
||||||
const { providence } = require('../../src/program/providence.js');
|
* @typedef {import('../../../src/program/types/core').ProvidenceConfig} ProvidenceConfig
|
||||||
const dummyAnalyzer = require('../../test-helpers/templates/analyzer-template.js');
|
*/
|
||||||
|
|
||||||
const queryResults = [];
|
|
||||||
|
|
||||||
describe('Analyzer', () => {
|
describe('Analyzer', () => {
|
||||||
before(() => {
|
const dummyAnalyzer = new DummyAnalyzer();
|
||||||
suppressNonCriticalLogs();
|
const queryResults = setupAnalyzerTest();
|
||||||
mockWriteToJson(queryResults);
|
|
||||||
});
|
|
||||||
|
|
||||||
after(() => {
|
|
||||||
restoreSuppressNonCriticalLogs();
|
|
||||||
restoreWriteToJson(queryResults);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Public api', () => {
|
describe('Public api', () => {
|
||||||
it('has a "name" string', async () => {
|
it('has a "name" string', async () => {
|
||||||
|
|
@ -41,34 +27,32 @@ describe('Analyzer', () => {
|
||||||
|
|
||||||
it('has a "requiredAst" string', async () => {
|
it('has a "requiredAst" string', async () => {
|
||||||
expect(typeof dummyAnalyzer.requiredAst).to.equal('string');
|
expect(typeof dummyAnalyzer.requiredAst).to.equal('string');
|
||||||
const allowedAsts = ['babel', 'typescript', 'es-module-lexer'];
|
const allowedAsts = ['babel'];
|
||||||
expect(allowedAsts).to.include(dummyAnalyzer.requiredAst);
|
expect(allowedAsts).to.include(dummyAnalyzer.requiredAst);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has a "requiresReference" boolean', async () => {
|
it('has a "requiresReference" boolean', async () => {
|
||||||
expect(typeof dummyAnalyzer.requiresReference).to.equal('boolean');
|
expect(typeof DummyAnalyzer.requiresReference).to.equal('boolean');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Find Analyzers', async () => {
|
describe.skip('Find Analyzers', async () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
restoreMockedProjects();
|
restoreMockedProjects();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Our configuration object
|
const myQueryConfigObject = QueryService.getQueryConfigFromAnalyzer(DummyAnalyzer);
|
||||||
const myQueryConfigObject = QueryService.getQueryConfigFromAnalyzer(dummyAnalyzer);
|
/** @type {Partial<ProvidenceConfig>} */
|
||||||
mockProject([`const validJs = true;`, `let invalidJs = false;`], {
|
const _providenceCfg = {
|
||||||
projectName: 'my-project',
|
targetProjectPaths: ['/fictional/project'],
|
||||||
projectPath: '/path/to/my-project',
|
};
|
||||||
filePaths: ['./test-file1.js', './test-file2.js'],
|
|
||||||
});
|
|
||||||
|
|
||||||
await providence(myQueryConfigObject, {
|
|
||||||
targetProjectPaths: ['/path/to/my-project'],
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Prepare phase', () => {
|
describe('Prepare phase', () => {
|
||||||
it('looks for a cached result', async () => {});
|
it('looks for a cached result', async () => {
|
||||||
|
// Our configuration object
|
||||||
|
mockProject([`const validJs = true;`, `let invalidJs = false;`]);
|
||||||
|
await providence(myQueryConfigObject, _providenceCfg);
|
||||||
|
});
|
||||||
|
|
||||||
it('exposes a ".targetMeta" object', async () => {});
|
it('exposes a ".targetMeta" object', async () => {});
|
||||||
|
|
||||||
|
|
@ -77,15 +61,29 @@ describe('Analyzer', () => {
|
||||||
it('exposes a ".identifier" string', async () => {});
|
it('exposes a ".identifier" string', async () => {});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Traverse phase', () => {});
|
describe('Traverse phase', () => {
|
||||||
|
it('schedules a Babel visitor', async () => {});
|
||||||
|
it('merges multiple Babel visitors for performance', async () => {});
|
||||||
|
it('traverses Babel visitor and stores traversal result', async () => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Postprocess phase', () => {
|
||||||
|
it('optionally post processes traversal result', async () => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Performance', () => {
|
||||||
|
it('memoizes execute functions', async () => {});
|
||||||
|
});
|
||||||
|
|
||||||
describe('Finalize phase', () => {
|
describe('Finalize phase', () => {
|
||||||
it('returns an AnalyzerQueryResult', async () => {
|
it('returns an AnalyzerQueryResult', async () => {
|
||||||
|
await providence(myQueryConfigObject, _providenceCfg);
|
||||||
|
|
||||||
const queryResult = queryResults[0];
|
const queryResult = queryResults[0];
|
||||||
const { queryOutput, meta } = queryResult;
|
const { queryOutput, meta } = queryResult;
|
||||||
|
|
||||||
expect(queryOutput[0]).to.eql({
|
expect(queryOutput[0]).to.eql({
|
||||||
file: './test-file1.js',
|
file: './test-file-0.js',
|
||||||
meta: {},
|
meta: {},
|
||||||
result: [{ matched: 'entry' }],
|
result: [{ matched: 'entry' }],
|
||||||
});
|
});
|
||||||
|
|
@ -226,3 +224,7 @@ describe('Analyzer', () => {
|
||||||
// });
|
// });
|
||||||
// });
|
// });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('FindAnalyzer', () => {});
|
||||||
|
|
||||||
|
describe('MatchAnalyzer', () => {});
|
||||||
|
|
@ -1,31 +1,46 @@
|
||||||
const { expect } = require('chai');
|
const { expect } = require('chai');
|
||||||
const pathLib = require('path');
|
const pathLib = require('path');
|
||||||
const { InputDataService } = require('../../../src/index.js');
|
const { InputDataService } = require('../../../src/program/core/InputDataService.js');
|
||||||
|
const { memoizeConfig } = require('../../../src/program/utils/memoize.js');
|
||||||
const {
|
const {
|
||||||
restoreMockedProjects,
|
restoreMockedProjects,
|
||||||
mockProject,
|
mockProject,
|
||||||
mock,
|
mock,
|
||||||
} = require('../../../test-helpers/mock-project-helpers.js');
|
} = require('../../../test-helpers/mock-project-helpers.js');
|
||||||
|
|
||||||
function restoreOriginalInputDataPaths() {
|
/**
|
||||||
InputDataService.referenceProjectPaths = undefined;
|
* @typedef {import('../../../src/program/types/core').PathFromSystemRoot} PathFromSystemRoot
|
||||||
InputDataService.targetProjectPaths = undefined;
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
describe('InputDataService', () => {
|
describe('InputDataService', () => {
|
||||||
|
const initialReferenceProjectPaths = InputDataService.referenceProjectPaths;
|
||||||
|
const initialTargetProjectPaths = InputDataService.referenceProjectPaths;
|
||||||
|
|
||||||
|
function restoreOriginalInputDataPaths() {
|
||||||
|
InputDataService.referenceProjectPaths = initialReferenceProjectPaths;
|
||||||
|
InputDataService.targetProjectPaths = initialTargetProjectPaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
memoizeConfig.isCacheDisabled = true;
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
restoreOriginalInputDataPaths();
|
restoreOriginalInputDataPaths();
|
||||||
restoreMockedProjects();
|
restoreMockedProjects();
|
||||||
|
memoizeConfig.isCacheDisabled = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Configuration', () => {
|
describe('Configuration', () => {
|
||||||
it('allows to set referenceProjectPaths', async () => {
|
it('allows to set referenceProjectPaths', async () => {
|
||||||
|
/** @type {PathFromSystemRoot[]} */
|
||||||
const newPaths = ['/my/path', '/my/other/path'];
|
const newPaths = ['/my/path', '/my/other/path'];
|
||||||
InputDataService.referenceProjectPaths = newPaths;
|
InputDataService.referenceProjectPaths = newPaths;
|
||||||
expect(InputDataService.referenceProjectPaths).to.equal(newPaths);
|
expect(InputDataService.referenceProjectPaths).to.equal(newPaths);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows to set targetProjectPaths', async () => {
|
it('allows to set targetProjectPaths', async () => {
|
||||||
|
/** @type {PathFromSystemRoot[]} */
|
||||||
const newPaths = ['/my/path', '/my/other/path'];
|
const newPaths = ['/my/path', '/my/other/path'];
|
||||||
InputDataService.targetProjectPaths = newPaths;
|
InputDataService.targetProjectPaths = newPaths;
|
||||||
expect(InputDataService.targetProjectPaths).to.equal(newPaths);
|
expect(InputDataService.targetProjectPaths).to.equal(newPaths);
|
||||||
|
|
@ -35,10 +50,13 @@ describe('InputDataService', () => {
|
||||||
describe('Methods', () => {
|
describe('Methods', () => {
|
||||||
// TODO: mock file system...
|
// TODO: mock file system...
|
||||||
it('"createDataObject"', async () => {
|
it('"createDataObject"', async () => {
|
||||||
const projectPaths = [
|
/** @type {* & PathFromSystemRoot} */
|
||||||
pathLib.resolve(__dirname, '../../../test-helpers/project-mocks/importing-target-project'),
|
const projectPath = pathLib.resolve(
|
||||||
];
|
__dirname,
|
||||||
const inputDataPerProject = InputDataService.createDataObject(projectPaths);
|
'../../../test-helpers/project-mocks/importing-target-project',
|
||||||
|
);
|
||||||
|
|
||||||
|
const inputDataPerProject = InputDataService.createDataObject([projectPath]);
|
||||||
expect(Object.keys(inputDataPerProject[0].project)).to.eql([
|
expect(Object.keys(inputDataPerProject[0].project)).to.eql([
|
||||||
'path',
|
'path',
|
||||||
'mainEntry',
|
'mainEntry',
|
||||||
|
|
@ -0,0 +1,200 @@
|
||||||
|
const { expect } = require('chai');
|
||||||
|
const { QueryService } = require('../../../src/program/core/QueryService.js');
|
||||||
|
const { DummyAnalyzer } = require('../../../test-helpers/templates/DummyAnalyzer.js');
|
||||||
|
const FindImportsAnalyzer = require('../../../src/program/analyzers/find-imports.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('../../../src/program/types/core').Analyzer} Analyzer
|
||||||
|
* @typedef {import('../../../src/program/types/core').PathFromSystemRoot} PathFromSystemRoot
|
||||||
|
*/
|
||||||
|
|
||||||
|
describe('QueryService', () => {
|
||||||
|
describe('Methods', () => {
|
||||||
|
describe('Retrieving QueryConfig', () => {
|
||||||
|
it('"getQueryConfigFromRegexSearchString"', async () => {
|
||||||
|
const result = QueryService.getQueryConfigFromRegexSearchString('x');
|
||||||
|
expect(result).to.eql({ type: 'search', regexString: 'x' });
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
// @ts-expect-error
|
||||||
|
QueryService.getQueryConfigFromRegexSearchString();
|
||||||
|
}).to.throw('[QueryService.getQueryConfigFromRegexSearchString]: provide a string');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('"getQueryConfigFromFeatureString"', () => {
|
||||||
|
it('with tag, attr-key and attr-value', async () => {
|
||||||
|
const result = QueryService.getQueryConfigFromFeatureString('tg-icon[size=xs]');
|
||||||
|
expect(result).to.eql({
|
||||||
|
type: 'feature',
|
||||||
|
feature: {
|
||||||
|
name: 'size',
|
||||||
|
value: 'xs',
|
||||||
|
tag: 'tg-icon',
|
||||||
|
isAttribute: true,
|
||||||
|
usesValueContains: false,
|
||||||
|
usesValuePartialMatch: false,
|
||||||
|
usesTagPartialMatch: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with only tag', async () => {
|
||||||
|
const result = QueryService.getQueryConfigFromFeatureString('tg-icon');
|
||||||
|
expect(result).to.eql({
|
||||||
|
type: 'feature',
|
||||||
|
feature: {
|
||||||
|
tag: 'tg-icon',
|
||||||
|
usesTagPartialMatch: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with only attr-key', async () => {
|
||||||
|
const result = QueryService.getQueryConfigFromFeatureString('[attr]');
|
||||||
|
expect(result).to.eql({
|
||||||
|
type: 'feature',
|
||||||
|
feature: {
|
||||||
|
name: 'attr',
|
||||||
|
value: undefined,
|
||||||
|
tag: '',
|
||||||
|
isAttribute: true,
|
||||||
|
usesValueContains: false,
|
||||||
|
usesValuePartialMatch: false,
|
||||||
|
usesTagPartialMatch: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with only attr-key and attr-value', async () => {
|
||||||
|
const result = QueryService.getQueryConfigFromFeatureString('[attr=x]');
|
||||||
|
expect(result).to.eql({
|
||||||
|
type: 'feature',
|
||||||
|
feature: {
|
||||||
|
name: 'attr',
|
||||||
|
value: 'x',
|
||||||
|
tag: '',
|
||||||
|
isAttribute: true,
|
||||||
|
usesValueContains: false,
|
||||||
|
usesValuePartialMatch: false,
|
||||||
|
usesTagPartialMatch: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('With partial value', async () => {
|
||||||
|
it('with tag, attr-key and attr-value', async () => {
|
||||||
|
const result = QueryService.getQueryConfigFromFeatureString('tg-icon*[size*=xs*]');
|
||||||
|
expect(result).to.eql({
|
||||||
|
type: 'feature',
|
||||||
|
feature: {
|
||||||
|
name: 'size',
|
||||||
|
value: 'xs',
|
||||||
|
tag: 'tg-icon',
|
||||||
|
isAttribute: true,
|
||||||
|
usesValueContains: true,
|
||||||
|
usesValuePartialMatch: true,
|
||||||
|
usesTagPartialMatch: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with only tag', async () => {
|
||||||
|
const result = QueryService.getQueryConfigFromFeatureString('tg-icon*');
|
||||||
|
expect(result).to.eql({
|
||||||
|
type: 'feature',
|
||||||
|
feature: {
|
||||||
|
tag: 'tg-icon',
|
||||||
|
usesTagPartialMatch: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with only attr-key', async () => {
|
||||||
|
const result = QueryService.getQueryConfigFromFeatureString('[attr*]');
|
||||||
|
expect(result).to.eql({
|
||||||
|
type: 'feature',
|
||||||
|
feature: {
|
||||||
|
name: 'attr',
|
||||||
|
value: undefined,
|
||||||
|
tag: '',
|
||||||
|
isAttribute: true,
|
||||||
|
usesValueContains: true,
|
||||||
|
usesValuePartialMatch: false,
|
||||||
|
usesTagPartialMatch: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('with only attr-key and attr-value', async () => {
|
||||||
|
const result = QueryService.getQueryConfigFromFeatureString('[attr*=x*]');
|
||||||
|
expect(result).to.eql({
|
||||||
|
type: 'feature',
|
||||||
|
feature: {
|
||||||
|
name: 'attr',
|
||||||
|
value: 'x',
|
||||||
|
tag: '',
|
||||||
|
isAttribute: true,
|
||||||
|
usesValueContains: true,
|
||||||
|
usesValuePartialMatch: true,
|
||||||
|
usesTagPartialMatch: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws when no string provided', async () => {
|
||||||
|
expect(() => {
|
||||||
|
QueryService.getQueryConfigFromFeatureString();
|
||||||
|
}).to.throw('[QueryService.getQueryConfigFromFeatureString]: provide a string');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('"getQueryConfigFromAnalyzer"', () => {
|
||||||
|
const myAnalyzerCfg = { targetProjectPath: /** @type {PathFromSystemRoot} */ ('/my/path') };
|
||||||
|
it('accepts a constructor as first argument', async () => {
|
||||||
|
const result = QueryService.getQueryConfigFromAnalyzer('find-imports', myAnalyzerCfg);
|
||||||
|
expect(result).to.eql({
|
||||||
|
type: 'ast-analyzer',
|
||||||
|
analyzerName: 'find-imports',
|
||||||
|
analyzerConfig: myAnalyzerCfg,
|
||||||
|
analyzer: FindImportsAnalyzer,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts a string as first argument', async () => {
|
||||||
|
const result = QueryService.getQueryConfigFromAnalyzer(
|
||||||
|
/** @type {* & Analyzer} */ (DummyAnalyzer),
|
||||||
|
myAnalyzerCfg,
|
||||||
|
);
|
||||||
|
expect(result).to.eql({
|
||||||
|
type: 'ast-analyzer',
|
||||||
|
analyzerName: 'dummy-analyzer',
|
||||||
|
analyzerConfig: myAnalyzerCfg,
|
||||||
|
analyzer: DummyAnalyzer,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('QueryResults', () => {
|
||||||
|
describe.skip('"grepSearch"', () => {
|
||||||
|
it('with FeatureConfig', async () => {
|
||||||
|
const featureCfg = QueryService.getQueryConfigFromFeatureString('tg-icon[size=xs]');
|
||||||
|
const result = QueryService.grepSearch(featureCfg);
|
||||||
|
expect(result).to.eql({
|
||||||
|
type: 'ast-analyzer',
|
||||||
|
analyzerName: 'find-imports',
|
||||||
|
analyzerConfig: { x: 'y' },
|
||||||
|
analyzer: FindImportsAnalyzer,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('"astSearch"', async () => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Ast retrieval', () => {
|
||||||
|
it('"addAstToProjectsData"', async () => {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
const { expect } = require('chai');
|
const { expect } = require('chai');
|
||||||
const { memoize } = require('../../../src/program/utils/memoize.js');
|
const { memoize, memoizeConfig } = require('../../../src/program/utils/memoize.js');
|
||||||
const { InputDataService } = require('../../../src/program/services/InputDataService.js');
|
|
||||||
|
|
||||||
const cacheDisabledInitialValue = InputDataService.cacheDisabled;
|
const cacheDisabledInitialValue = memoizeConfig.isCacheDisabled;
|
||||||
|
|
||||||
describe('Memoize', () => {
|
describe('Memoize', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// This is important, since memoization only works
|
// This is important, since memoization only works
|
||||||
InputDataService.cacheDisabled = false;
|
memoizeConfig.isCacheDisabled = false;
|
||||||
});
|
});
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
InputDataService.cacheDisabled = cacheDisabledInitialValue;
|
memoizeConfig.isCacheDisabled = cacheDisabledInitialValue;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('With primitives', () => {
|
describe('With primitives', () => {
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,14 @@ const {
|
||||||
mockTargetAndReferenceProject,
|
mockTargetAndReferenceProject,
|
||||||
} = require('../../../test-helpers/mock-project-helpers.js');
|
} = require('../../../test-helpers/mock-project-helpers.js');
|
||||||
const { resolveImportPath } = require('../../../src/program/utils/resolve-import-path.js');
|
const { resolveImportPath } = require('../../../src/program/utils/resolve-import-path.js');
|
||||||
|
const { memoizeConfig } = require('../../../src/program/utils/memoize.js');
|
||||||
|
|
||||||
describe('resolveImportPath', () => {
|
describe('resolveImportPath', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
memoizeConfig.isCacheDisabled = true;
|
||||||
|
});
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
memoizeConfig.isCacheDisabled = false;
|
||||||
restoreMockedProjects();
|
restoreMockedProjects();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue