807 lines
27 KiB
JavaScript
807 lines
27 KiB
JavaScript
/* eslint-disable no-unused-expressions */
|
|
/* eslint-disable import/no-extraneous-dependencies */
|
|
import sinon from 'sinon';
|
|
import pathLib from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import { expect } from 'chai';
|
|
import commander from 'commander';
|
|
import {
|
|
mockProject,
|
|
restoreMockedProjects,
|
|
mockTargetAndReferenceProject,
|
|
} from '../../test-helpers/mock-project-helpers.js';
|
|
import {
|
|
mockWriteToJson,
|
|
restoreWriteToJson,
|
|
} from '../../test-helpers/mock-report-service-helpers.js';
|
|
import {
|
|
suppressNonCriticalLogs,
|
|
restoreSuppressNonCriticalLogs,
|
|
} from '../../test-helpers/mock-log-service-helpers.js';
|
|
import { InputDataService } from '../../src/program/core/InputDataService.js';
|
|
import { QueryService } from '../../src/program/core/QueryService.js';
|
|
import providenceModule from '../../src/program/providence.js';
|
|
import cliHelpersModule from '../../src/cli/cli-helpers.js';
|
|
import { cli } from '../../src/cli/cli.mjs';
|
|
import promptAnalyzerModule from '../../src/cli/prompt-analyzer-menu.js';
|
|
import { toPosixPath } from '../../src/program/utils/to-posix-path.js';
|
|
import { memoizeConfig } from '../../src/program/utils/memoize.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 } =
|
|
cliHelpersModule;
|
|
|
|
/** @type {QueryResult[]} */
|
|
const queryResults = [];
|
|
|
|
const externalCfgMock = {
|
|
searchTargetCollections: {
|
|
'lion-collection': [
|
|
'./providence-input-data/search-targets/example-project-a',
|
|
'./providence-input-data/search-targets/example-project-b',
|
|
// ...etc
|
|
],
|
|
},
|
|
referenceCollections: {
|
|
'lion-based-ui-collection': [
|
|
'./providence-input-data/references/lion-based-ui',
|
|
'./providence-input-data/references/lion-based-ui-labs',
|
|
],
|
|
},
|
|
};
|
|
|
|
/**
|
|
* @param {string} args
|
|
* @param {string} cwd
|
|
*/
|
|
async function runCli(args, cwd) {
|
|
const argv = [
|
|
...process.argv.slice(0, 2),
|
|
...args.split(' ').map(a => a.replace(/^("|')?(.*)("|')?$/, '$2')),
|
|
];
|
|
await cli({ argv, cwd });
|
|
}
|
|
|
|
describe('Providence CLI', () => {
|
|
const rootDir = '/mocked/path/example-project';
|
|
|
|
/** @type {sinon.SinonStub} */
|
|
let providenceStub;
|
|
/** @type {sinon.SinonStub} */
|
|
let promptCfgStub;
|
|
/** @type {sinon.SinonStub} */
|
|
let iExtConfStub;
|
|
/** @type {sinon.SinonStub} */
|
|
let promptStub;
|
|
/** @type {sinon.SinonStub} */
|
|
let qConfStub;
|
|
|
|
const memoizeCacheDisabledInitial = memoizeConfig.isCacheDisabled;
|
|
memoizeConfig.isCacheDisabled = true;
|
|
|
|
before(() => {
|
|
// Prevent MaxListenersExceededWarning
|
|
commander.setMaxListeners(100);
|
|
|
|
mockWriteToJson(queryResults);
|
|
suppressNonCriticalLogs();
|
|
|
|
mockProject(
|
|
{
|
|
'./src/OriginalComp.js': `export class OriginalComp {}`,
|
|
'./src/inbetween.js': `export { OriginalComp as InBetweenComp } from './OriginalComp.js'`,
|
|
'./index.js': `export { InBetweenComp as MyComp } from './src/inbetween.js'`,
|
|
'./node_modules/dependency-a/index.js': '',
|
|
'./bower_components/dependency-b/index.js': '',
|
|
},
|
|
{
|
|
projectName: 'example-project',
|
|
projectPath: '/mocked/path/example-project',
|
|
},
|
|
);
|
|
|
|
/** @type {sinon.SinonStub} */
|
|
providenceStub = sinon.stub(providenceModule, 'providence').returns(Promise.resolve());
|
|
|
|
/** @type {sinon.SinonStub} */
|
|
promptCfgStub = sinon
|
|
.stub(promptAnalyzerModule, 'promptAnalyzerConfigMenu')
|
|
.returns(Promise.resolve({ analyzerConfig: { con: 'fig' } }));
|
|
|
|
/** @type {sinon.SinonStub} */
|
|
iExtConfStub = sinon.stub(InputDataService, 'getExternalConfig').returns(externalCfgMock);
|
|
|
|
/** @type {sinon.SinonStub} */
|
|
promptStub = sinon
|
|
.stub(promptAnalyzerModule, 'promptAnalyzerMenu')
|
|
.returns(Promise.resolve({ analyzerName: 'match-analyzer-mock' }));
|
|
|
|
/** @type {sinon.SinonStub} */
|
|
qConfStub = sinon.stub(QueryService, 'getQueryConfigFromAnalyzer').returns({
|
|
analyzer: {
|
|
name: 'match-analyzer-mock',
|
|
requiresReference: true,
|
|
},
|
|
});
|
|
});
|
|
|
|
after(() => {
|
|
commander.setMaxListeners(10);
|
|
|
|
restoreSuppressNonCriticalLogs();
|
|
restoreMockedProjects();
|
|
restoreWriteToJson();
|
|
|
|
providenceStub.restore();
|
|
promptCfgStub.restore();
|
|
iExtConfStub.restore();
|
|
promptStub.restore();
|
|
qConfStub.restore();
|
|
|
|
memoizeConfig.isCacheDisabled = memoizeCacheDisabledInitial;
|
|
});
|
|
|
|
beforeEach(() => {
|
|
memoizeConfig.isCacheDisabled = true;
|
|
});
|
|
|
|
afterEach(() => {
|
|
providenceStub.resetHistory();
|
|
promptCfgStub.resetHistory();
|
|
iExtConfStub.resetHistory();
|
|
promptStub.resetHistory();
|
|
qConfStub.resetHistory();
|
|
});
|
|
|
|
const analyzeCmd = 'analyze match-analyzer-mock';
|
|
|
|
it('calls providence', async () => {
|
|
await runCli(`${analyzeCmd} -t /mocked/path/example-project`, rootDir);
|
|
expect(providenceStub.called).to.be.true;
|
|
});
|
|
|
|
it('creates a QueryConfig', async () => {
|
|
await runCli(`${analyzeCmd} -t /mocked/path/example-project`, rootDir);
|
|
expect(qConfStub.called).to.be.true;
|
|
expect(qConfStub.args[0][0]).to.equal('match-analyzer-mock');
|
|
});
|
|
|
|
describe('Global options', () => {
|
|
/** @type {sinon.SinonStub} */
|
|
let pathsArrayFromCollectionStub;
|
|
/** @type {sinon.SinonStub} */
|
|
let pathsArrayFromCsStub;
|
|
/** @type {sinon.SinonStub} */
|
|
let appendProjectDependencyPathsStub;
|
|
|
|
before(() => {
|
|
pathsArrayFromCsStub = sinon
|
|
.stub(cliHelpersModule, 'pathsArrayFromCs')
|
|
.returns(['/mocked/path/example-project']);
|
|
pathsArrayFromCollectionStub = sinon
|
|
.stub(cliHelpersModule, 'pathsArrayFromCollectionName')
|
|
.returns(['/mocked/path/example-project']);
|
|
appendProjectDependencyPathsStub = sinon
|
|
.stub(cliHelpersModule, 'appendProjectDependencyPaths')
|
|
.returns(
|
|
Promise.resolve([
|
|
'/mocked/path/example-project',
|
|
'/mocked/path/example-project/node_modules/mock-dep-a',
|
|
'/mocked/path/example-project/bower_components/mock-dep-b',
|
|
]),
|
|
);
|
|
});
|
|
|
|
after(() => {
|
|
pathsArrayFromCsStub.restore();
|
|
pathsArrayFromCollectionStub.restore();
|
|
appendProjectDependencyPathsStub.restore();
|
|
});
|
|
|
|
afterEach(() => {
|
|
pathsArrayFromCsStub.resetHistory();
|
|
pathsArrayFromCollectionStub.resetHistory();
|
|
appendProjectDependencyPathsStub.resetHistory();
|
|
});
|
|
|
|
it('"-e --extensions"', async () => {
|
|
await runCli(`${analyzeCmd} -e bla,blu`, rootDir);
|
|
expect(providenceStub.args[0][1].gatherFilesConfig.extensions).to.eql(['.bla', '.blu']);
|
|
|
|
providenceStub.resetHistory();
|
|
|
|
await runCli(`${analyzeCmd} --extensions bla,blu`, rootDir);
|
|
expect(providenceStub.args[0][1].gatherFilesConfig.extensions).to.eql(['.bla', '.blu']);
|
|
});
|
|
|
|
it('"-t --search-target-paths"', async () => {
|
|
await runCli(`${analyzeCmd} -t /mocked/path/example-project`, rootDir);
|
|
expect(pathsArrayFromCsStub.args[0][0]).to.equal('/mocked/path/example-project');
|
|
expect(providenceStub.args[0][1].targetProjectPaths).to.eql(['/mocked/path/example-project']);
|
|
|
|
pathsArrayFromCsStub.resetHistory();
|
|
providenceStub.resetHistory();
|
|
|
|
await runCli(`${analyzeCmd} --search-target-paths /mocked/path/example-project`, rootDir);
|
|
expect(pathsArrayFromCsStub.args[0][0]).to.equal('/mocked/path/example-project');
|
|
expect(providenceStub.args[0][1].targetProjectPaths).to.eql(['/mocked/path/example-project']);
|
|
});
|
|
|
|
it('"-r --reference-paths"', async () => {
|
|
await runCli(`${analyzeCmd} -r /mocked/path/example-project`, rootDir);
|
|
expect(pathsArrayFromCsStub.args[0][0]).to.equal('/mocked/path/example-project');
|
|
expect(providenceStub.args[0][1].referenceProjectPaths).to.eql([
|
|
'/mocked/path/example-project',
|
|
]);
|
|
|
|
pathsArrayFromCsStub.resetHistory();
|
|
providenceStub.resetHistory();
|
|
|
|
await runCli(`${analyzeCmd} --reference-paths /mocked/path/example-project`, rootDir);
|
|
expect(pathsArrayFromCsStub.args[0][0]).to.equal('/mocked/path/example-project');
|
|
expect(providenceStub.args[0][1].referenceProjectPaths).to.eql([
|
|
'/mocked/path/example-project',
|
|
]);
|
|
});
|
|
|
|
it('"--search-target-collection"', async () => {
|
|
await runCli(`${analyzeCmd} --search-target-collection lion-collection`, rootDir);
|
|
expect(pathsArrayFromCollectionStub.args[0][0]).to.equal('lion-collection');
|
|
expect(providenceStub.args[0][1].targetProjectPaths).to.eql(['/mocked/path/example-project']);
|
|
});
|
|
|
|
it('"--reference-collection"', async () => {
|
|
await runCli(`${analyzeCmd} --reference-collection lion-based-ui-collection`, rootDir);
|
|
expect(pathsArrayFromCollectionStub.args[0][0]).to.equal('lion-based-ui-collection');
|
|
expect(providenceStub.args[0][1].referenceProjectPaths).to.eql([
|
|
'/mocked/path/example-project',
|
|
]);
|
|
});
|
|
|
|
it('"-a --allowlist"', async () => {
|
|
await runCli(`${analyzeCmd} -a mocked/**/*,rocked/*`, rootDir);
|
|
expect(providenceStub.args[0][1].gatherFilesConfig.allowlist).to.eql([
|
|
'mocked/**/*',
|
|
'rocked/*',
|
|
]);
|
|
|
|
providenceStub.resetHistory();
|
|
|
|
await runCli(`${analyzeCmd} --allowlist mocked/**/*,rocked/*`, rootDir);
|
|
expect(providenceStub.args[0][1].gatherFilesConfig.allowlist).to.eql([
|
|
'mocked/**/*',
|
|
'rocked/*',
|
|
]);
|
|
});
|
|
|
|
it('"--allowlist-reference"', async () => {
|
|
await runCli(`${analyzeCmd} --allowlist-reference mocked/**/*,rocked/*`, rootDir);
|
|
expect(providenceStub.args[0][1].gatherFilesConfigReference.allowlist).to.eql([
|
|
'mocked/**/*',
|
|
'rocked/*',
|
|
]);
|
|
});
|
|
|
|
it('--allowlist-mode', async () => {
|
|
await runCli(`${analyzeCmd} --allowlist-mode git`, rootDir);
|
|
expect(providenceStub.args[0][1].gatherFilesConfig.allowlistMode).to.equal('git');
|
|
});
|
|
|
|
it('--allowlist-mode-reference', async () => {
|
|
await runCli(`${analyzeCmd} --allowlist-mode-reference npm`, rootDir);
|
|
expect(providenceStub.args[0][1].gatherFilesConfigReference.allowlistMode).to.equal('npm');
|
|
});
|
|
|
|
it('"-D --debug"', async () => {
|
|
await runCli(`${analyzeCmd} -D`, rootDir);
|
|
expect(providenceStub.args[0][1].debugEnabled).to.equal(true);
|
|
|
|
providenceStub.resetHistory();
|
|
|
|
await runCli(`${analyzeCmd} --debug`, rootDir);
|
|
expect(providenceStub.args[0][1].debugEnabled).to.equal(true);
|
|
});
|
|
|
|
it('--write-log-file"', async () => {
|
|
await runCli(`${analyzeCmd} --write-log-file`, rootDir);
|
|
expect(providenceStub.args[0][1].writeLogFile).to.equal(true);
|
|
});
|
|
|
|
it('--target-dependencies"', async () => {
|
|
await runCli(`${analyzeCmd}`, rootDir);
|
|
expect(appendProjectDependencyPathsStub.called).to.be.false;
|
|
|
|
appendProjectDependencyPathsStub.resetHistory();
|
|
providenceStub.resetHistory();
|
|
|
|
await runCli(`${analyzeCmd} --target-dependencies`, rootDir);
|
|
expect(appendProjectDependencyPathsStub.called).to.be.true;
|
|
expect(providenceStub.args[0][1].targetProjectPaths).to.eql([
|
|
'/mocked/path/example-project',
|
|
'/mocked/path/example-project/node_modules/mock-dep-a',
|
|
'/mocked/path/example-project/bower_components/mock-dep-b',
|
|
]);
|
|
});
|
|
|
|
it('--target-dependencies /^with-regex/"', async () => {
|
|
await runCli(`${analyzeCmd} --target-dependencies /^mock-/`, rootDir);
|
|
expect(appendProjectDependencyPathsStub.args[0][1]).to.equal('/^mock-/');
|
|
});
|
|
|
|
it('"--skip-check-match-compatibility"', async () => {
|
|
await runCli(`${analyzeCmd} --skip-check-match-compatibility`, rootDir);
|
|
expect(providenceStub.args[0][1].skipCheckMatchCompatibility).to.equal(true);
|
|
});
|
|
});
|
|
|
|
describe('Commands', () => {
|
|
describe('Analyze', () => {
|
|
it('calls providence', async () => {
|
|
await runCli(`${analyzeCmd}`, rootDir);
|
|
expect(providenceStub.called).to.be.true;
|
|
});
|
|
|
|
describe('Options', () => {
|
|
it('"-o --prompt-optional-config"', async () => {
|
|
await runCli(`analyze -o`, rootDir);
|
|
expect(promptStub.called).to.be.true;
|
|
|
|
promptStub.resetHistory();
|
|
|
|
await runCli(`analyze --prompt-optional-config`, rootDir);
|
|
expect(promptStub.called).to.be.true;
|
|
});
|
|
|
|
it('"-c --config"', async () => {
|
|
await runCli(`analyze match-analyzer-mock -c {"a":"2"}`, rootDir);
|
|
expect(qConfStub.args[0][0]).to.equal('match-analyzer-mock');
|
|
expect(qConfStub.args[0][1]).to.eql({ a: '2', metaConfig: {} });
|
|
|
|
qConfStub.resetHistory();
|
|
|
|
await runCli(`analyze match-analyzer-mock --config {"a":"2"}`, rootDir);
|
|
expect(qConfStub.args[0][0]).to.equal('match-analyzer-mock');
|
|
expect(qConfStub.args[0][1]).to.eql({ a: '2', metaConfig: {} });
|
|
});
|
|
|
|
it('calls "promptAnalyzerConfigMenu" without config given', async () => {
|
|
await runCli(`analyze match-analyzer-mock`, rootDir);
|
|
expect(promptCfgStub.called).to.be.true;
|
|
});
|
|
});
|
|
});
|
|
|
|
describe.skip('Query', () => {});
|
|
describe.skip('Search', () => {});
|
|
|
|
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', () => {
|
|
/** @type {sinon.SinonStub} */
|
|
let extendDocsStub;
|
|
|
|
before(() => {
|
|
extendDocsStub = sinon
|
|
.stub(extendDocsModule, 'launchProvidenceWithExtendDocs')
|
|
.returns(Promise.resolve());
|
|
});
|
|
|
|
after(() => {
|
|
extendDocsStub.restore();
|
|
});
|
|
|
|
afterEach(() => {
|
|
extendDocsStub.resetHistory();
|
|
});
|
|
|
|
it('allows configuration', async () => {
|
|
await runCli(
|
|
[
|
|
'extend-docs',
|
|
'-t /xyz',
|
|
'-r /xyz/x',
|
|
'--prefix-from pfrom --prefix-to pto',
|
|
'--output-folder /outp',
|
|
'--extensions bla',
|
|
'--allowlist al --allowlist-reference alr',
|
|
].join(' '),
|
|
rootDir,
|
|
);
|
|
expect(extendDocsStub.called).to.be.true;
|
|
expect(extendDocsStub.args[0][0]).to.eql({
|
|
referenceProjectPaths: ['/xyz/x'],
|
|
prefixCfg: {
|
|
from: 'pfrom',
|
|
to: 'pto',
|
|
},
|
|
outputFolder: '/outp',
|
|
extensions: ['.bla'],
|
|
allowlist: ['al'],
|
|
allowlistReference: ['alr'],
|
|
cwd: '/mocked/path/example-project',
|
|
skipCheckMatchCompatibility: true,
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('CLI helpers', () => {
|
|
const rootDir = toPosixPath(pathLib.resolve(__dirname, '../../'));
|
|
|
|
describe('pathsArrayFromCs', () => {
|
|
it('allows absolute paths', async () => {
|
|
expect(pathsArrayFromCs('/mocked/path/example-project', rootDir)).to.eql([
|
|
'/mocked/path/example-project',
|
|
]);
|
|
});
|
|
|
|
it('allows relative paths', async () => {
|
|
expect(
|
|
pathsArrayFromCs('./test-helpers/project-mocks/importing-target-project', rootDir),
|
|
).to.eql([`${rootDir}/test-helpers/project-mocks/importing-target-project`]);
|
|
expect(
|
|
pathsArrayFromCs('test-helpers/project-mocks/importing-target-project', rootDir),
|
|
).to.eql([`${rootDir}/test-helpers/project-mocks/importing-target-project`]);
|
|
});
|
|
|
|
it('allows globs', async () => {
|
|
expect(pathsArrayFromCs('test-helpers/project-mocks*', rootDir)).to.eql([
|
|
`${rootDir}/test-helpers/project-mocks`,
|
|
`${rootDir}/test-helpers/project-mocks-analyzer-outputs`,
|
|
]);
|
|
});
|
|
|
|
it('allows multiple comma separated paths', async () => {
|
|
const paths =
|
|
'test-helpers/project-mocks*, ./test-helpers/project-mocks/importing-target-project,/mocked/path/example-project';
|
|
expect(pathsArrayFromCs(paths, rootDir)).to.eql([
|
|
`${rootDir}/test-helpers/project-mocks`,
|
|
`${rootDir}/test-helpers/project-mocks-analyzer-outputs`,
|
|
`${rootDir}/test-helpers/project-mocks/importing-target-project`,
|
|
'/mocked/path/example-project',
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('pathsArrayFromCollectionName', () => {
|
|
it('gets collections from external target config', async () => {
|
|
expect(
|
|
pathsArrayFromCollectionName('lion-collection', 'search-target', externalCfgMock, rootDir),
|
|
).to.eql(
|
|
externalCfgMock.searchTargetCollections['lion-collection'].map(p =>
|
|
toPosixPath(pathLib.join(rootDir, p)),
|
|
),
|
|
);
|
|
});
|
|
|
|
it('gets collections from external reference config', async () => {
|
|
expect(
|
|
pathsArrayFromCollectionName(
|
|
'lion-based-ui-collection',
|
|
'reference',
|
|
externalCfgMock,
|
|
rootDir,
|
|
),
|
|
).to.eql(
|
|
externalCfgMock.referenceCollections['lion-based-ui-collection'].map(p =>
|
|
toPosixPath(pathLib.join(rootDir, p)),
|
|
),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('appendProjectDependencyPaths', () => {
|
|
before(() => {
|
|
mockWriteToJson(queryResults);
|
|
suppressNonCriticalLogs();
|
|
|
|
mockProject(
|
|
{
|
|
'./src/OriginalComp.js': `export class OriginalComp {}`,
|
|
'./src/inbetween.js': `export { OriginalComp as InBetweenComp } from './OriginalComp.js'`,
|
|
'./index.js': `export { InBetweenComp as MyComp } from './src/inbetween.js'`,
|
|
'./node_modules/dependency-a/index.js': '',
|
|
'./bower_components/dependency-b/index.js': '',
|
|
'./node_modules/my-dependency/index.js': '',
|
|
},
|
|
{
|
|
projectName: 'example-project',
|
|
projectPath: '/mocked/path/example-project',
|
|
},
|
|
);
|
|
});
|
|
|
|
it('adds bower and node dependencies', async () => {
|
|
const result = await appendProjectDependencyPaths(['/mocked/path/example-project']);
|
|
expect(result).to.eql([
|
|
'/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',
|
|
]);
|
|
});
|
|
|
|
it('allows a regex filter', async () => {
|
|
const result = await appendProjectDependencyPaths(
|
|
['/mocked/path/example-project'],
|
|
'/^dependency-/',
|
|
);
|
|
expect(result).to.eql([
|
|
'/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',
|
|
]);
|
|
|
|
const result2 = await appendProjectDependencyPaths(['/mocked/path/example-project'], '/b$/');
|
|
expect(result2).to.eql([
|
|
'/mocked/path/example-project/bower_components/dependency-b',
|
|
'/mocked/path/example-project',
|
|
]);
|
|
});
|
|
|
|
it('allows to filter out only npm or bower deps', async () => {
|
|
const result = await appendProjectDependencyPaths(['/mocked/path/example-project'], null, [
|
|
'npm',
|
|
]);
|
|
expect(result).to.eql([
|
|
'/mocked/path/example-project/node_modules/dependency-a',
|
|
'/mocked/path/example-project/node_modules/my-dependency',
|
|
'/mocked/path/example-project',
|
|
]);
|
|
|
|
const result2 = await appendProjectDependencyPaths(['/mocked/path/example-project'], null, [
|
|
'bower',
|
|
]);
|
|
expect(result2).to.eql([
|
|
'/mocked/path/example-project/bower_components/dependency-b',
|
|
'/mocked/path/example-project',
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('Extend docs', () => {
|
|
afterEach(() => {
|
|
restoreMockedProjects();
|
|
});
|
|
|
|
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 = {
|
|
'./package.json': JSON.stringify({
|
|
name: 'their-components',
|
|
version: '1.0.0',
|
|
}),
|
|
'./src/TheirButton.js': `export class TheirButton extends HTMLElement {}`,
|
|
'./src/TheirTooltip.js': `export class TheirTooltip extends HTMLElement {}`,
|
|
'./their-button.js': `
|
|
import { TheirButton } from './src/TheirButton.js';
|
|
|
|
customElements.define('their-button', TheirButton);
|
|
`,
|
|
'./demo.js': `
|
|
import { TheirTooltip } from './src/TheirTooltip.js';
|
|
import './their-button.js';
|
|
`,
|
|
};
|
|
|
|
const myProjectFiles = {
|
|
'./package.json': JSON.stringify({
|
|
name: '@my/root',
|
|
workspaces: ['packages/*', 'another-folder/my-tooltip'],
|
|
dependencies: {
|
|
'their-components': '1.0.0',
|
|
},
|
|
}),
|
|
// Package 1: @my/button
|
|
'./packages/button/package.json': JSON.stringify({
|
|
name: '@my/button',
|
|
}),
|
|
'./packages/button/src/MyButton.js': `
|
|
import { TheirButton } from 'their-components/src/TheirButton.js';
|
|
|
|
export class MyButton extends TheirButton {}
|
|
`,
|
|
'./packages/button/src/my-button.js': `
|
|
import { MyButton } from './MyButton.js';
|
|
|
|
customElements.define('my-button', MyButton);
|
|
`,
|
|
|
|
// Package 2: @my/tooltip
|
|
'./packages/tooltip/package.json': JSON.stringify({
|
|
name: '@my/tooltip',
|
|
}),
|
|
'./packages/tooltip/src/MyTooltip.js': `
|
|
import { TheirTooltip } from 'their-components/src/TheirTooltip.js';
|
|
|
|
export class MyTooltip extends TheirTooltip {}
|
|
`,
|
|
};
|
|
|
|
const theirProject = {
|
|
path: '/my-components/node_modules/their-components',
|
|
name: 'their-components',
|
|
files: Object.entries(theirProjectFiles).map(([file, code]) => ({ file, code })),
|
|
};
|
|
|
|
const myProject = {
|
|
path: '/my-components',
|
|
name: 'my-components',
|
|
files: Object.entries(myProjectFiles).map(([file, code]) => ({ file, code })),
|
|
};
|
|
|
|
mockTargetAndReferenceProject(theirProject, myProject);
|
|
|
|
const result = await getExtendDocsResults({
|
|
referenceProjectPaths: [theirProject.path],
|
|
prefixCfg: { from: 'their', to: 'my' },
|
|
extensions: ['.js'],
|
|
cwd: '/my-components',
|
|
});
|
|
|
|
expect(result).to.eql([
|
|
{
|
|
name: 'TheirButton',
|
|
variable: {
|
|
from: 'TheirButton',
|
|
to: 'MyButton',
|
|
paths: [
|
|
{
|
|
from: './src/TheirButton.js',
|
|
to: '@my/button/src/MyButton.js', // rewritten from './packages/button/src/MyButton.js',
|
|
},
|
|
{
|
|
from: 'their-components/src/TheirButton.js',
|
|
to: '@my/button/src/MyButton.js', // rewritten from './packages/button/src/MyButton.js',
|
|
},
|
|
],
|
|
},
|
|
tag: {
|
|
from: 'their-button',
|
|
to: 'my-button',
|
|
paths: [
|
|
{
|
|
from: './their-button.js',
|
|
to: '@my/button/src/my-button.js', // rewritten from './packages/button/src/MyButton.js',
|
|
},
|
|
{
|
|
from: 'their-components/their-button.js',
|
|
to: '@my/button/src/my-button.js', // rewritten from './packages/button/src/MyButton.js',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
name: 'TheirTooltip',
|
|
variable: {
|
|
from: 'TheirTooltip',
|
|
to: 'MyTooltip',
|
|
paths: [
|
|
{
|
|
from: './src/TheirTooltip.js',
|
|
to: '@my/tooltip/src/MyTooltip.js', // './packages/tooltip/src/MyTooltip.js',
|
|
},
|
|
{
|
|
from: 'their-components/src/TheirTooltip.js',
|
|
to: '@my/tooltip/src/MyTooltip.js', // './packages/tooltip/src/MyTooltip.js',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('does not check for match compatibility (target and reference) in monorepo targets', async () => {
|
|
// ===== REFERENCE AND TARGET PROJECTS =====
|
|
|
|
const theirProjectFiles = {
|
|
'./package.json': JSON.stringify({
|
|
name: 'their-components',
|
|
version: '1.0.0',
|
|
}),
|
|
'./src/TheirButton.js': `export class TheirButton extends HTMLElement {}`,
|
|
};
|
|
|
|
// This will be detected as being a monorepo
|
|
const monoProjectFiles = {
|
|
'./package.json': JSON.stringify({
|
|
name: '@mono/root',
|
|
workspaces: ['packages/*'],
|
|
dependencies: {
|
|
'their-components': '1.0.0',
|
|
},
|
|
}),
|
|
// Package: @mono/button
|
|
'./packages/button/package.json': JSON.stringify({
|
|
name: '@mono/button',
|
|
}),
|
|
};
|
|
|
|
// This will be detected as NOT being a monorepo
|
|
const nonMonoProjectFiles = {
|
|
'./package.json': JSON.stringify({
|
|
name: 'non-mono',
|
|
dependencies: {
|
|
'their-components': '1.0.0',
|
|
},
|
|
}),
|
|
};
|
|
|
|
const theirProject = {
|
|
path: '/their-components',
|
|
name: 'their-components',
|
|
files: Object.entries(theirProjectFiles).map(([file, code]) => ({ file, code })),
|
|
};
|
|
|
|
const monoProject = {
|
|
path: '/mono-components',
|
|
name: 'mono-components',
|
|
files: Object.entries(monoProjectFiles).map(([file, code]) => ({ file, code })),
|
|
};
|
|
|
|
const nonMonoProject = {
|
|
path: '/non-mono-components',
|
|
name: 'non-mono-components',
|
|
files: Object.entries(nonMonoProjectFiles).map(([file, code]) => ({ file, code })),
|
|
};
|
|
|
|
// ===== TESTS =====
|
|
|
|
const providenceStub = sinon.stub(providenceModule, 'providence').returns(
|
|
new Promise(resolve => {
|
|
resolve([]);
|
|
}),
|
|
);
|
|
|
|
// ===== mono =====
|
|
|
|
mockTargetAndReferenceProject(theirProject, monoProject);
|
|
await getExtendDocsResults({
|
|
referenceProjectPaths: ['/their-components'],
|
|
prefixCfg: { from: 'their', to: 'my' },
|
|
extensions: ['.js'],
|
|
cwd: '/mono-components',
|
|
});
|
|
|
|
expect(providenceStub.args[0][1].skipCheckMatchCompatibility).to.equal(true);
|
|
providenceStub.resetHistory();
|
|
restoreMockedProjects();
|
|
|
|
// ===== non mono =====
|
|
|
|
mockTargetAndReferenceProject(theirProject, nonMonoProject);
|
|
await getExtendDocsResults({
|
|
referenceProjectPaths: ['/their-components'],
|
|
prefixCfg: { from: 'their', to: 'my' },
|
|
extensions: ['.js'],
|
|
cwd: '/non-mono-components',
|
|
});
|
|
expect(providenceStub.args[0][1].skipCheckMatchCompatibility).to.equal(false);
|
|
|
|
providenceStub.restore();
|
|
});
|
|
});
|
|
});
|