217 lines
8.2 KiB
JavaScript
Executable file
217 lines
8.2 KiB
JavaScript
Executable file
import path from 'path';
|
|
|
|
import commander from 'commander';
|
|
|
|
import { InputDataService } from '../program/core/InputDataService.js';
|
|
import { getCurrentDir } from '../program/utils/get-current-dir.js';
|
|
import { QueryService } from '../program/core/QueryService.js';
|
|
import { _providenceModule } from '../program/providence.js';
|
|
import { fsAdapter } from '../program/utils/fs-adapter.js';
|
|
import { _cliHelpersModule } from './cli-helpers.js';
|
|
|
|
/**
|
|
* @typedef {import('../../types/index.js').ProvidenceCliConf} ProvidenceCliConf
|
|
* @typedef {import('../../types/index.js').AnalyzerName} AnalyzerName
|
|
*/
|
|
|
|
const { version } = JSON.parse(
|
|
fsAdapter.fs.readFileSync(
|
|
path.resolve(getCurrentDir(import.meta.url), '../../package.json'),
|
|
'utf8',
|
|
),
|
|
);
|
|
const { extensionsFromCs, targetDefault } = _cliHelpersModule;
|
|
|
|
/**
|
|
* @param {{cwd?:string; argv?: string[]; providenceConf?: Partial<ProvidenceCliConf>}} cfg
|
|
*/
|
|
export async function cli({ cwd = process.cwd(), providenceConf, argv = process.argv }) {
|
|
/** @type {(value: any) => void} */
|
|
let resolveCli;
|
|
/** @type {(reason?: any) => void} */
|
|
let rejectCli;
|
|
|
|
const cliPromise = new Promise((resolve, reject) => {
|
|
resolveCli = resolve;
|
|
rejectCli = reject;
|
|
});
|
|
|
|
/** @type {object} */
|
|
let analyzerOptions;
|
|
|
|
// TODO: change back to "InputDataService.getExternalConfig();" once full package ESM
|
|
const externalConfig = providenceConf;
|
|
|
|
/**
|
|
* @param {{analyzerOptions:{name:AnalyzerName; config:object;promptOptionalConfig:object}}} opts
|
|
*/
|
|
async function getQueryConfigAndMeta(opts) {
|
|
let queryConfig = null;
|
|
let queryMethod = null;
|
|
|
|
// eslint-disable-next-line prefer-const
|
|
let { name, config } = opts.analyzerOptions;
|
|
if (!name) {
|
|
throw new Error('Please provide an analyzer name');
|
|
}
|
|
// Will get metaConfig from ./providence.conf.js
|
|
const metaConfig = externalConfig ? externalConfig.metaConfig : {};
|
|
config = { ...config, metaConfig };
|
|
queryConfig = await QueryService.getQueryConfigFromAnalyzer(name, config);
|
|
queryMethod = 'ast';
|
|
return { queryConfig, queryMethod };
|
|
}
|
|
|
|
async function launchProvidence() {
|
|
const { queryConfig, queryMethod } = await getQueryConfigAndMeta({ analyzerOptions });
|
|
|
|
const searchTargetPaths = commander.searchTargetCollection || commander.searchTargetPaths;
|
|
let referencePaths;
|
|
if (queryConfig.analyzer.requiresReference) {
|
|
referencePaths = commander.referenceCollection || commander.referencePaths;
|
|
}
|
|
|
|
/**
|
|
* May or may not include dependencies of search target
|
|
* @type {string[]}
|
|
*/
|
|
let totalSearchTargets;
|
|
if (commander.targetDependencies !== undefined) {
|
|
totalSearchTargets = await _cliHelpersModule.appendProjectDependencyPaths(
|
|
searchTargetPaths,
|
|
commander.targetDependencies,
|
|
);
|
|
} else {
|
|
totalSearchTargets = searchTargetPaths;
|
|
}
|
|
|
|
// TODO: filter out:
|
|
// - dependencies listed in reference (?) Or at least, inside match-imports, make sure that
|
|
// we do not test against ourselves...
|
|
// -
|
|
|
|
_providenceModule.providence(queryConfig, {
|
|
gatherFilesConfig: {
|
|
extensions: commander.extensions,
|
|
allowlistMode: commander.allowlistMode,
|
|
allowlist: commander.allowlist,
|
|
},
|
|
gatherFilesConfigReference: {
|
|
extensions: commander.extensions,
|
|
allowlistMode: commander.allowlistModeReference,
|
|
allowlist: commander.allowlistReference,
|
|
},
|
|
debugEnabled: commander.debug,
|
|
queryMethod,
|
|
targetProjectPaths: totalSearchTargets,
|
|
referenceProjectPaths: referencePaths,
|
|
targetProjectRootPaths: searchTargetPaths,
|
|
writeLogFile: commander.writeLogFile,
|
|
skipCheckMatchCompatibility: commander.skipCheckMatchCompatibility,
|
|
measurePerformance: commander.measurePerf,
|
|
addSystemPathsInResult: commander.addSystemPaths,
|
|
fallbackToBabel: commander.fallbackToBabel,
|
|
});
|
|
}
|
|
|
|
commander
|
|
.version(version, '-v, --version')
|
|
.option('-e, --extensions [extensions]', 'extensions like "js,html"', extensionsFromCs, [
|
|
'.js',
|
|
'.html',
|
|
])
|
|
.option('-D, --debug', 'shows extensive logging')
|
|
.option(
|
|
'-t, --search-target-paths [targets]',
|
|
`path(s) to project(s) on which analysis/querying should take place. Requires
|
|
a list of comma seperated values relative to project root`,
|
|
v => _cliHelpersModule.pathsArrayFromCs(v, cwd),
|
|
targetDefault(cwd),
|
|
)
|
|
.option(
|
|
'-r, --reference-paths [references]',
|
|
`path(s) to project(s) which serve as a reference (applicable for certain analyzers like
|
|
'match-imports'). Requires a list of comma seperated values relative to
|
|
project root (like 'node_modules/lion-based-ui, node_modules/lion-based-ui-labs').`,
|
|
v => _cliHelpersModule.pathsArrayFromCs(v, cwd),
|
|
InputDataService.referenceProjectPaths,
|
|
)
|
|
.option('-a, --allowlist [allowlist]', `allowlisted paths, like 'src/**/*, packages/**/*'`, v =>
|
|
_cliHelpersModule.csToArray(v),
|
|
)
|
|
.option(
|
|
'--allowlist-reference [allowlist-reference]',
|
|
`allowed paths for reference, like 'src/**/*, packages/**/*'`,
|
|
v => _cliHelpersModule.csToArray(v),
|
|
)
|
|
.option(
|
|
'--search-target-collection [collection-name]',
|
|
`path(s) to project(s) which serve as a reference (applicable for certain analyzers like
|
|
'match-imports'). Should be a collection defined in providence.conf.js as paths relative to
|
|
project root.`,
|
|
v => _cliHelpersModule.pathsArrayFromCollectionName(v, 'search-target', externalConfig),
|
|
)
|
|
.option(
|
|
'--reference-collection [collection-name]',
|
|
`path(s) to project(s) on which analysis/querying should take place. Should be a collection
|
|
defined in providence.conf.js as paths relative to project root.`,
|
|
v => _cliHelpersModule.pathsArrayFromCollectionName(v, 'reference', externalConfig),
|
|
)
|
|
.option('--write-log-file', `Writes all logs to 'providence.log' file`)
|
|
.option(
|
|
'--target-dependencies [target-dependencies]',
|
|
`For all search targets, will include all its dependencies
|
|
(node_modules and bower_components). When --target-dependencies is applied
|
|
without argument, it will act as boolean and include all dependencies.
|
|
When a regex is supplied like --target-dependencies /^my-brand-/, it will filter
|
|
all packages that comply with the regex`,
|
|
)
|
|
.option(
|
|
'--allowlist-mode [allowlist-mode]',
|
|
`Depending on whether we are dealing with a published artifact
|
|
(a dependency installed via npm) or a git repository, different paths will be
|
|
automatically put in the appropiate mode.
|
|
A mode of 'npm' will look at the package.json "files" entry and a mode of
|
|
'git' will look at '.gitignore' entry. A mode of 'export-map' will look for all paths
|
|
exposed via an export map.
|
|
The mode will be auto detected, but can be overridden
|
|
via this option.`,
|
|
)
|
|
.option(
|
|
'--allowlist-mode-reference [allowlist-mode-reference]',
|
|
`allowlist mode applied to refernce project`,
|
|
)
|
|
.option(
|
|
'--skip-check-match-compatibility',
|
|
`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')
|
|
.option(
|
|
'--fallback-to-babel',
|
|
'Uses babel instead of swc. This will be slower, but guaranteed to be 100% compatible with @babel/generate and @babel/traverse',
|
|
);
|
|
|
|
commander
|
|
.command('analyze [analyzer-name]')
|
|
.alias('a')
|
|
.description(
|
|
`predefined "query" for ast analysis. Can be a script found in program/analyzers,
|
|
like "find-imports"`,
|
|
)
|
|
.option(
|
|
'-o, --prompt-optional-config',
|
|
`by default, only required configuration options are
|
|
asked for. When this flag is provided, optional configuration options are shown as well`,
|
|
)
|
|
.option('-c, --config [config]', 'configuration object for analyzer', c => JSON.parse(c))
|
|
.action((analyzerName, options) => {
|
|
analyzerOptions = options;
|
|
analyzerOptions.name = analyzerName;
|
|
launchProvidence().then(resolveCli).catch(rejectCli);
|
|
});
|
|
|
|
commander.parse(argv);
|
|
|
|
await cliPromise;
|
|
}
|