347 lines
14 KiB
JavaScript
347 lines
14 KiB
JavaScript
const { expect } = require('chai');
|
|
const { providence } = require('../../../src/program/providence.js');
|
|
const { QueryService } = require('../../../src/program/services/QueryService.js');
|
|
const {
|
|
mockProject,
|
|
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 findImportsQueryConfig = QueryService.getQueryConfigFromAnalyzer('find-imports');
|
|
const _providenceCfg = {
|
|
targetProjectPaths: ['/fictional/project'], // defined in mockProject
|
|
};
|
|
|
|
describe('Analyzer "find-imports"', () => {
|
|
const queryResults = [];
|
|
|
|
const cacheDisabledInitialValue = QueryService.cacheDisabled;
|
|
|
|
before(() => {
|
|
QueryService.cacheDisabled = true;
|
|
});
|
|
|
|
after(() => {
|
|
QueryService.cacheDisabled = cacheDisabledInitialValue;
|
|
});
|
|
|
|
beforeEach(() => {
|
|
suppressNonCriticalLogs();
|
|
mockWriteToJson(queryResults);
|
|
});
|
|
|
|
afterEach(() => {
|
|
restoreSuppressNonCriticalLogs();
|
|
restoreMockedProjects();
|
|
restoreWriteToJson(queryResults);
|
|
});
|
|
|
|
describe('Import notations', () => {
|
|
it(`supports [import 'imported/source'] (no specifiers)`, async () => {
|
|
mockProject([`import 'imported/source'`]);
|
|
await providence(findImportsQueryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers).to.eql(['[file]']);
|
|
expect(firstEntry.result[0].source).to.equal('imported/source');
|
|
});
|
|
|
|
it(`supports [import x from 'imported/source'] (default specifier)`, async () => {
|
|
mockProject([`import x from 'imported/source'`]);
|
|
await providence(findImportsQueryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('[default]');
|
|
expect(firstEntry.result[0].source).to.equal('imported/source');
|
|
});
|
|
|
|
it(`supports [import { x } from 'imported/source'] (named specifier)`, async () => {
|
|
mockProject([`import { x } from 'imported/source'`]);
|
|
await providence(findImportsQueryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('x');
|
|
expect(firstEntry.result[0].importSpecifiers[1]).to.equal(undefined);
|
|
expect(firstEntry.result[0].source).to.equal('imported/source');
|
|
});
|
|
|
|
it(`supports [import { x, y } from 'imported/source'] (multiple named specifiers)`, async () => {
|
|
mockProject([`import { x, y } from 'imported/source'`]);
|
|
await providence(findImportsQueryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('x');
|
|
expect(firstEntry.result[0].importSpecifiers[1]).to.equal('y');
|
|
expect(firstEntry.result[0].importSpecifiers[2]).to.equal(undefined);
|
|
expect(firstEntry.result[0].source).to.equal('imported/source');
|
|
});
|
|
|
|
it(`supports [import x, { y, z } from 'imported/source'] (default and named specifiers)`, async () => {
|
|
mockProject([`import x, { y, z } from 'imported/source'`]);
|
|
await providence(findImportsQueryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('[default]');
|
|
expect(firstEntry.result[0].importSpecifiers[1]).to.equal('y');
|
|
expect(firstEntry.result[0].importSpecifiers[2]).to.equal('z');
|
|
expect(firstEntry.result[0].source).to.equal('imported/source');
|
|
});
|
|
|
|
it(`supports [import { x as y } from 'imported/source'] (renamed specifiers)`, async () => {
|
|
mockProject([`import { x as y } from 'imported/source'`]);
|
|
await providence(findImportsQueryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('x');
|
|
});
|
|
|
|
it(`supports [import * as all from 'imported/source'] (namespace specifiers)`, async () => {
|
|
mockProject([`import * as all from 'imported/source'`]);
|
|
await providence(findImportsQueryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('[*]');
|
|
});
|
|
|
|
describe('Reexports', () => {
|
|
it(`supports [export { x } from 'imported/source'] (reexported named specifiers)`, async () => {
|
|
mockProject([`export { x } from 'imported/source'`]);
|
|
await providence(findImportsQueryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('x');
|
|
});
|
|
|
|
it(`supports [export { x as y } from 'imported/source'] (reexported renamed specifiers)`, async () => {
|
|
mockProject([`export { x as y } from 'imported/source'`]);
|
|
await providence(findImportsQueryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('x');
|
|
});
|
|
|
|
// maybe in the future... needs experimental babel flag "exportDefaultFrom"
|
|
it.skip(`supports [export x from 'imported/source'] (reexported default specifiers)`, async () => {
|
|
mockProject([`export x from 'imported/source'`]);
|
|
await providence(findImportsQueryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('x');
|
|
});
|
|
|
|
it(`supports [export * as x from 'imported/source'] (reexported namespace specifiers)`, async () => {
|
|
mockProject([`export * as x from 'imported/source'`]);
|
|
await providence(findImportsQueryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('[*]');
|
|
});
|
|
});
|
|
|
|
// Currently only supported for find-exports. For now not needed...
|
|
it.skip(`stores meta info(local name) of renamed specifiers`, async () => {
|
|
mockProject([`import { x as y } from 'imported/source'`]);
|
|
await providence(findImportsQueryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
// This info will be relevant later to identify transitive relations
|
|
expect(firstEntry.result[0].localMap[0]).to.eql({
|
|
local: 'y',
|
|
imported: 'x',
|
|
});
|
|
});
|
|
|
|
it(`supports [import('my/source')] (dynamic imports)`, async () => {
|
|
mockProject([`import('my/source')`]);
|
|
await providence(findImportsQueryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('[default]');
|
|
// TODO: somehow mark as dynamic??
|
|
expect(firstEntry.result[0].source).to.equal('my/source');
|
|
});
|
|
|
|
it(`supports [import(pathReference)] (dynamic imports with variable source)`, async () => {
|
|
mockProject([
|
|
`
|
|
const pathReference = 'my/source';
|
|
import(pathReference);
|
|
`,
|
|
]);
|
|
await providence(findImportsQueryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers[0]).to.equal('[default]');
|
|
// TODO: somehow mark as dynamic??
|
|
expect(firstEntry.result[0].source).to.equal('[variable]');
|
|
});
|
|
|
|
describe('Filter out false positives', () => {
|
|
it(`doesn't support [object.import('my/source')] (import method members)`, async () => {
|
|
mockProject([`object.import('my/source')`]);
|
|
await providence(findImportsQueryConfig, {
|
|
targetProjectPaths: ['/fictional/project'], // defined in mockProject
|
|
});
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry).to.equal(undefined);
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Not in scope:
|
|
* - dynamic imports containing variables
|
|
* - tracking of specifier usage for default (dynamic or not) imports
|
|
*/
|
|
});
|
|
|
|
describe('Default post processing', () => {
|
|
it('only stores external sources', async () => {
|
|
mockProject([
|
|
`
|
|
import '@external/source';
|
|
import 'external/source';
|
|
import './internal/source';
|
|
import '../internal/source';
|
|
import '../../internal/source';
|
|
`,
|
|
]);
|
|
await providence(findImportsQueryConfig, { ..._providenceCfg });
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers.length).to.equal(1);
|
|
expect(firstEntry.result[0].source).to.equal('@external/source');
|
|
expect(firstEntry.result[1].source).to.equal('external/source');
|
|
expect(firstEntry.result[2]).to.equal(undefined);
|
|
});
|
|
|
|
it('normalizes source paths', async () => {
|
|
const queryConfig = QueryService.getQueryConfigFromAnalyzer('find-imports', {
|
|
keepInternalSources: true,
|
|
});
|
|
mockProject({
|
|
'./internal/file-imports.js': `
|
|
import '@external/source';
|
|
import 'external/source';
|
|
import './source/x'; // auto resolve filename
|
|
import '../'; // auto resolve root
|
|
`,
|
|
'./internal/source/x.js': '',
|
|
'./index.js': '',
|
|
});
|
|
await providence(queryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers.length).to.equal(1);
|
|
expect(firstEntry.result[0].normalizedSource).to.equal('@external/source');
|
|
// expect(firstEntry.result[0].fullSource).to.equal('@external/source');
|
|
expect(firstEntry.result[1].normalizedSource).to.equal('external/source');
|
|
// expect(firstEntry.result[1].fullSource).to.equal('external/source');
|
|
expect(firstEntry.result[2].normalizedSource).to.equal('./source/x.js');
|
|
// expect(firstEntry.result[2].fullSource).to.equal('./internal/source/x.js');
|
|
expect(firstEntry.result[3].normalizedSource).to.equal('../index.js');
|
|
// expect(firstEntry.result[3].fullSource).to.equal('./index.js');
|
|
expect(firstEntry.result[4]).to.equal(undefined);
|
|
});
|
|
});
|
|
|
|
describe('Options', () => {
|
|
it('"keepInternalSources"', async () => {
|
|
const queryConfig = QueryService.getQueryConfigFromAnalyzer('find-imports', {
|
|
keepInternalSources: true,
|
|
});
|
|
mockProject([
|
|
`
|
|
import '@external/source';
|
|
import 'external/source';
|
|
import './internal/source';
|
|
import '../internal/source';
|
|
import '../../internal/source';
|
|
`,
|
|
]);
|
|
await providence(queryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
|
|
const firstEntry = getEntry(queryResult);
|
|
expect(firstEntry.result[0].importSpecifiers.length).to.equal(1);
|
|
expect(firstEntry.result[0].source).to.equal('@external/source');
|
|
expect(firstEntry.result[1].source).to.equal('external/source');
|
|
expect(firstEntry.result[2].source).to.equal('./internal/source');
|
|
expect(firstEntry.result[3].source).to.equal('../internal/source');
|
|
expect(firstEntry.result[4].source).to.equal('../../internal/source');
|
|
expect(firstEntry.result[5]).to.equal(undefined);
|
|
});
|
|
|
|
// Post processors for whole result
|
|
it('"keepOriginalSourceExtensions"', async () => {
|
|
const queryConfig = QueryService.getQueryConfigFromAnalyzer('find-imports', {
|
|
keepOriginalSourceExtensions: true,
|
|
});
|
|
mockProject([`import '@external/source.js'`, `import '@external/source';`]);
|
|
await providence(queryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
|
|
const firstEntry = getEntry(queryResult);
|
|
const secondEntry = getEntry(queryResult, 1);
|
|
|
|
expect(firstEntry.result[0].normalizedSource).to.equal('@external/source.js');
|
|
expect(secondEntry.result[0].normalizedSource).to.equal('@external/source');
|
|
});
|
|
|
|
// TODO: currently disabled. Might become default later (increased readability of json reports)
|
|
// but only without loss of information and once depending analyzers (match-imports and
|
|
// match-subclasses) are made compatible.
|
|
it.skip('"sortBySpecifier"', async () => {
|
|
const queryConfig = QueryService.getQueryConfigFromAnalyzer('find-imports', {
|
|
sortBySpecifier: true,
|
|
});
|
|
mockProject(
|
|
[
|
|
`import { x, y } from '@external/source.js'`,
|
|
`import { x, y, z } from '@external/source.js'`,
|
|
],
|
|
{ filePaths: ['./file1.js', './file2.js'] },
|
|
);
|
|
await providence(queryConfig, _providenceCfg);
|
|
const queryResult = queryResults[0];
|
|
|
|
/**
|
|
* Output will be in the format of:
|
|
*
|
|
* "queryOutput": [
|
|
* {
|
|
* "specifier": "LitElement",
|
|
* "source": "lion-based-ui/core",
|
|
* "id": "LitElement::lion-based-ui/core",
|
|
* "dependents": [
|
|
* "my-app-using-lion-based-ui/src/x.js",
|
|
* "my-app-using-lion-based-ui/src/y/z.js", *
|
|
* ...
|
|
*/
|
|
|
|
expect(queryResult.queryOutput[0].specifier).to.equal('x');
|
|
// Should be normalized source...?
|
|
expect(queryResult.queryOutput[0].source).to.equal('@external/source.js');
|
|
expect(queryResult.queryOutput[0].id).to.equal('x::@external/source.js');
|
|
expect(queryResult.queryOutput[0].dependents).to.eql([
|
|
'fictional-project/file1.js',
|
|
'fictional-project/file2.js',
|
|
]);
|
|
});
|
|
});
|
|
|
|
// TODO: put this in the generic providence/analyzer part
|
|
describe.skip('With <script type="module"> inside .html', () => {
|
|
it('gets the source from script tags', async () => {});
|
|
|
|
it('gets the content from script tags', async () => {});
|
|
});
|
|
});
|