332 lines
20 KiB
JavaScript
332 lines
20 KiB
JavaScript
// Vikunja #779: the organization-imports helper (business-imports before rename r2 stage B) on
|
|
// synthetic trees. Every tree is built under a private temp directory with the repository one level
|
|
// down, so a test can put a file outside the repository. Each tree has both package roots:
|
|
// packages/organization/src holds the file under test and packages/business/src, the shim root, is
|
|
// empty unless a test fills it.
|
|
import test, {after} from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {mkdirSync,mkdtempSync,rmSync,symlinkSync,writeFileSync} from 'node:fs';
|
|
import {tmpdir} from 'node:os';
|
|
import {dirname,join} from 'node:path';
|
|
import {fileURLToPath} from 'node:url';
|
|
import {organizationImportedFiles} from './organization-imports.mjs';
|
|
import * as oldName from './business-imports.mjs';
|
|
|
|
const ROOT=fileURLToPath(new URL('../../..',import.meta.url)).replace(/\/$/,'');
|
|
const base=mkdtempSync(join(tmpdir(),'bi-'));
|
|
after(()=>rmSync(base,{recursive:true,force:true}));
|
|
const ORG='repo/packages/organization/src/',SHIM='repo/packages/business/src/',EXT='repo/packages/other/src/',EMPTY='export {};\n';
|
|
let count=0;
|
|
// files: path under the tree's top directory -> text. links: path -> target path, both under it.
|
|
function tree(files,links={},{roots=[ORG,SHIM]}={}){
|
|
const top=join(base,`t${++count}`);
|
|
for(const r of roots)mkdirSync(join(top,r),{recursive:true});
|
|
for(const [path,text] of Object.entries(files)){mkdirSync(dirname(join(top,path)),{recursive:true});writeFileSync(join(top,path),text);}
|
|
for(const [path,target] of Object.entries(links)){mkdirSync(dirname(join(top,path)),{recursive:true});symlinkSync(join(top,target),join(top,path));}
|
|
return join(top,'repo');
|
|
}
|
|
const withOrg=(text,extra={})=>tree({[`${ORG}a.mjs`]:text,...extra});
|
|
|
|
test('the real tree gives the plug-in files the loader reads, and nothing inside either root', ()=>{
|
|
const found=organizationImportedFiles(ROOT);
|
|
assert.ok(found.includes('packages/plugins/src/kinds.mjs'),found.join(' '));
|
|
assert.deepEqual(found.filter((f)=>f.startsWith('packages/organization/src/')||f.startsWith('packages/business/src/')),[]);
|
|
assert.ok(found.includes('packages/plugins/src/model-quota.mjs'),found.join(' '));
|
|
assert.deepEqual(found,[...found].sort());
|
|
});
|
|
|
|
test('the loader exception holds only for the loader file and its exact computed import', ()=>{
|
|
const text="const module=await import(pathToFileURL(expected).href);\n";
|
|
const at=(file)=>tree({[`${ORG}a.mjs`]:"import '../../plugins/src/loader.mjs';\n",[`repo/${file}`]:text});
|
|
assert.deepEqual(organizationImportedFiles(at('packages/plugins/src/loader.mjs')),['packages/plugins/src/loader.mjs']);
|
|
assert.throws(()=>organizationImportedFiles(tree({[`${ORG}a.mjs`]:"import '../../plugins/src/other.mjs';\n",'repo/packages/plugins/src/other.mjs':text})),/not a plain string literal/);
|
|
assert.throws(()=>organizationImportedFiles(tree({[`${ORG}a.mjs`]:"import '../../plugins/src/loader.mjs';\n",'repo/packages/plugins/src/loader.mjs':"await import(x);\n"})),/not a plain string literal/);
|
|
});
|
|
|
|
test('PL1 pinned import exception holds only for the checked loader entry and exact hash cache key',()=>{
|
|
const computed="await import(pathToFileURL(entry).href + '?pin=' + checked.manifest.sha256);\n";
|
|
const at=(file,text=computed)=>tree({[`${ORG}a.mjs`]:`import '../../plugins/src/${file}';\n`,[`repo/packages/plugins/src/${file}`]:text});
|
|
assert.deepEqual(organizationImportedFiles(at('loader.mjs')),['packages/plugins/src/loader.mjs']);
|
|
assert.throws(()=>organizationImportedFiles(at('other.mjs')),/not a plain string literal/);
|
|
for(const changed of [computed.replace('entry','arbitrary'),computed.replace('?pin=','?unchecked='),computed.replace('checked.manifest.sha256','input')])assert.throws(()=>organizationImportedFiles(at('loader.mjs',changed)),/not a plain string literal/);
|
|
});
|
|
|
|
test('every static form and a literal dynamic import is found, and the imports of what it finds in turn', ()=>{
|
|
const repo=withOrg([
|
|
"import x from '../../other/src/from.mjs';",
|
|
"import {\n y,\n z,\n} from '../../other/src/multi.mjs';",
|
|
"import '../../other/src/bare.mjs';",
|
|
"export * from '../../other/src/reexport.mjs';",
|
|
"export {w} from '../../other/src/named.mjs';",
|
|
"const d=await import('../../other/src/dynamic.mjs');",
|
|
"const n=await import(\n '../../other/src/newline.mjs'\n);",
|
|
].join('\n'),{
|
|
[`${EXT}from.mjs`]:"import '../../third/src/deep.mjs';\n",
|
|
'repo/packages/third/src/deep.mjs':EMPTY,
|
|
...Object.fromEntries(['multi','bare','reexport','named','dynamic','newline'].map(n=>[`${EXT}${n}.mjs`,EMPTY])),
|
|
});
|
|
assert.deepEqual(organizationImportedFiles(repo),[
|
|
...['bare','dynamic','from','multi','named','newline','reexport'].map(n=>`packages/other/src/${n}.mjs`),
|
|
'packages/third/src/deep.mjs',
|
|
]);
|
|
});
|
|
|
|
test('#779 a dynamic import written with a space or a line break before the bracket is found', ()=>{
|
|
const repo=withOrg("const s=await import ('../../other/src/spaced.mjs');\nconst t=await import\n ('../../other/src/broken.mjs');\n",
|
|
{[`${EXT}spaced.mjs`]:EMPTY,[`${EXT}broken.mjs`]:EMPTY});
|
|
assert.deepEqual(organizationImportedFiles(repo),['packages/other/src/broken.mjs','packages/other/src/spaced.mjs']);
|
|
});
|
|
|
|
test('#779 an import in a line or block comment is not an import, and one after a comment is', ()=>{
|
|
const repo=withOrg([
|
|
"// import '../../other/src/missing1.mjs';",
|
|
"/* import x from '../../other/src/missing2.mjs'; */",
|
|
"/*\n import('../../other/src/missing3.mjs')\n*/",
|
|
"const x=1; // import '../../other/src/missing4.mjs'",
|
|
"import '../../other/src/real.mjs'; // import('../../other/src/missing5.mjs')",
|
|
"// import(name)",
|
|
"/* import(name) */ import '../../other/src/after.mjs';",
|
|
].join('\n'),{[`${EXT}real.mjs`]:EMPTY,[`${EXT}after.mjs`]:EMPTY});
|
|
assert.deepEqual(organizationImportedFiles(repo),['packages/other/src/after.mjs','packages/other/src/real.mjs']);
|
|
});
|
|
|
|
test('#779 comment markers inside strings, templates and regular expressions do not hide an import', ()=>{
|
|
const repo=withOrg([
|
|
"const url='http://example.invalid/a'; import '../../other/src/after-url.mjs';",
|
|
"const glob=\"/* open\"; import '../../other/src/after-glob.mjs';",
|
|
"const tpl=`// not a comment ${1}`; import '../../other/src/after-template.mjs';",
|
|
"const re=/['\"]\\/\\/x/; import '../../other/src/after-regex.mjs';",
|
|
"const half=a / 2;\nconst mid=(a+b) / 2;\nimport '../../other/src/after-divide.mjs';",
|
|
].join('\n'),Object.fromEntries(['url','glob','template','regex','divide'].map(n=>[`${EXT}after-${n}.mjs`,EMPTY])));
|
|
assert.deepEqual(organizationImportedFiles(repo),['url','glob','template','regex','divide'].map(n=>`packages/other/src/after-${n}.mjs`).sort());
|
|
});
|
|
|
|
test('#779 an import form inside a string or a regular expression is not an import', ()=>{
|
|
const repo=withOrg([
|
|
"const a=\"import '../../other/src/missing1.mjs'\";",
|
|
"const b='import(name)';",
|
|
"const c=/import (name)/;",
|
|
"const d=\"export {x} from '../../other/src/missing2.mjs'\";",
|
|
"import '../../other/src/real.mjs';",
|
|
].join('\n'),{[`${EXT}real.mjs`]:EMPTY});
|
|
assert.deepEqual(organizationImportedFiles(repo),['packages/other/src/real.mjs']);
|
|
});
|
|
|
|
test('#779 a hashbang line is skipped and a bare slash in it does not start a regular expression', ()=>{
|
|
const repo=withOrg("#!/usr/bin/env node\nimport '../../other/src/real.mjs';\n",{[`${EXT}real.mjs`]:EMPTY});
|
|
assert.deepEqual(organizationImportedFiles(repo),['packages/other/src/real.mjs']);
|
|
const bare=withOrg("#!/odd\nimport '../../other/src/real.mjs';\n",{[`${EXT}real.mjs`]:EMPTY});
|
|
assert.deepEqual(organizationImportedFiles(bare),['packages/other/src/real.mjs']);
|
|
});
|
|
|
|
test('#779 a dynamic import of anything but a plain string throws, and what only looks like one does not', ()=>{
|
|
for(const argument of ['name',"'../../other/src/' + name",'`../../other/src/${name}.mjs`',"'../../other/src/a.mjs', {with:{type:'json'}}","'../../other/src/a.mjs' + ''"]){
|
|
const repo=withOrg(`const m=await import(${argument});\n`,{[`${EXT}a.mjs`]:EMPTY});
|
|
assert.throws(()=>organizationImportedFiles(repo),/organization\/src\/a\.mjs has a dynamic import that is not a plain string literal/,argument);
|
|
}
|
|
const repo=withOrg([
|
|
'const u=import.meta.url;','loader.import(thing);','reimport(thing);','$import(thing);',
|
|
"const fs=await import('node:fs');","const s='import(name)';",
|
|
].join('\n'));
|
|
assert.deepEqual(organizationImportedFiles(repo),[]);
|
|
});
|
|
|
|
test('#779 a file the scanner cannot read to its end throws and names the file, in a root or external', ()=>{
|
|
for(const [what,text] of [['string',"const a='open;\n"],['string','const a="open'],['comment',"/* open\nimport '../../other/src/a.mjs';\n"],['template','const a=`open'],['regular expression','const a=/open\n']]){
|
|
const repo=withOrg(text,{[`${EXT}a.mjs`]:EMPTY});
|
|
assert.throws(()=>organizationImportedFiles(repo),new RegExp(`packages/organization/src/a\\.mjs cannot be read for imports: unterminated ${what}`),text);
|
|
}
|
|
const repo=withOrg("import '../../other/src/a.mjs';\n",{[`${EXT}a.mjs`]:"/* never closed\n"});
|
|
assert.throws(()=>organizationImportedFiles(repo),/packages\/other\/src\/a\.mjs cannot be read for imports: unterminated comment/);
|
|
});
|
|
|
|
test('#779 an import of a file that is missing throws, inside a package root or out of it', ()=>{
|
|
const inside=withOrg("import './missing.mjs';\n");
|
|
assert.throws(()=>organizationImportedFiles(inside),/packages\/organization\/src\/a\.mjs imports \.\/missing\.mjs, which does not exist/);
|
|
const outside=withOrg("import '../../other/src/missing.mjs';\n");
|
|
assert.throws(()=>organizationImportedFiles(outside),/imports \.\.\/\.\.\/other\/src\/missing\.mjs, which does not exist/);
|
|
const broken=tree({[`${ORG}a.mjs`]:"import '../../other/src/link.mjs';\n"},{[`${EXT}link.mjs`]:'gone.mjs'});
|
|
assert.throws(()=>organizationImportedFiles(broken),/which does not exist/);
|
|
const beyond=withOrg("import '../../other/src/a.mjs/b.mjs';\n",{[`${EXT}a.mjs`]:EMPTY});
|
|
assert.throws(()=>organizationImportedFiles(beyond),/which does not exist/);
|
|
});
|
|
|
|
test('#779 an import of a directory throws', ()=>{
|
|
const repo=withOrg("import '../../other/src/dir';\n",{[`${EXT}dir/index.mjs`]:EMPTY});
|
|
assert.throws(()=>organizationImportedFiles(repo),/imports \.\.\/\.\.\/other\/src\/dir, which is not a regular file/);
|
|
});
|
|
|
|
test('#779 a target outside the repository throws, by a path that climbs out or by a symlink', ()=>{
|
|
const climbs=tree({[`${ORG}a.mjs`]:"import '../../../../outside.mjs';\n",'outside.mjs':EMPTY});
|
|
assert.throws(()=>organizationImportedFiles(climbs),/imports \.\.\/\.\.\/\.\.\/\.\.\/outside\.mjs, which is outside the repository/);
|
|
const sibling=tree({[`${ORG}a.mjs`]:"import '../../../../repo2/x.mjs';\n",'repo2/x.mjs':EMPTY});
|
|
assert.throws(()=>organizationImportedFiles(sibling),/which is outside the repository/);
|
|
const linked=tree({[`${ORG}a.mjs`]:"import '../../other/src/link.mjs';\n",'outside.mjs':EMPTY},{[`${EXT}link.mjs`]:'outside.mjs'});
|
|
assert.throws(()=>organizationImportedFiles(linked),/imports \.\.\/\.\.\/other\/src\/link\.mjs, which is outside the repository/);
|
|
const folder=tree({[`${ORG}a.mjs`]:"import '../../other/src/out/x.mjs';\n",'outside/x.mjs':EMPTY},{[`${EXT}out`]:'outside'});
|
|
assert.throws(()=>organizationImportedFiles(folder),/which is outside the repository/);
|
|
});
|
|
|
|
test('#779 a symlink that stays inside the repository, and a repository reached by a symlink, are fine', ()=>{
|
|
const repo=tree({[`${ORG}a.mjs`]:"import '../../other/src/link.mjs';\n",'repo/packages/third/real.mjs':EMPTY},{[`${EXT}link.mjs`]:'repo/packages/third/real.mjs'});
|
|
assert.deepEqual(organizationImportedFiles(repo),['packages/other/src/link.mjs']);
|
|
const via=join(base,`via${++count}`);
|
|
symlinkSync(repo,via);
|
|
assert.deepEqual(organizationImportedFiles(via),['packages/other/src/link.mjs']);
|
|
});
|
|
|
|
const SUBSTITUTION=/packages\/organization\/src\/a\.mjs cannot be read for imports: unsupported import inside a template substitution/;
|
|
|
|
test('#779 R2 a dynamic import inside a template substitution throws, whether the target exists, is missing or is outside', ()=>{
|
|
const exists=withOrg("const v=`${await import('../../other/src/real.mjs')}`;\n",{[`${EXT}real.mjs`]:EMPTY});
|
|
assert.throws(()=>organizationImportedFiles(exists),SUBSTITUTION);
|
|
const missing=withOrg("const v=`${await import('../../other/src/real.mjs')}`;\n");
|
|
assert.throws(()=>organizationImportedFiles(missing),SUBSTITUTION);
|
|
const outside=tree({[`${ORG}a.mjs`]:"const v=`${await import('../../../../outside.mjs')}`;\n",'outside.mjs':EMPTY});
|
|
assert.throws(()=>organizationImportedFiles(outside),SUBSTITUTION);
|
|
});
|
|
|
|
test('#779 R2 a dynamic import inside a substitution throws however the substitution is written', ()=>{
|
|
for(const source of [
|
|
"const v=`a ${b} ${await import ('../../other/src/real.mjs')} c`;",
|
|
"const v=`${await import(name)}`;",
|
|
"const v=`${/* c */ import('../../other/src/real.mjs') /* d */}`;",
|
|
"const v=`x ${`y ${await import('../../other/src/real.mjs')}`}`;",
|
|
"const v=`${ {a:1}.a + '}' + (await import('../../other/src/real.mjs')) }`;",
|
|
"const v=`${\n await import(\n '../../other/src/real.mjs'\n )\n}`;",
|
|
]){
|
|
const repo=withOrg(`${source}\n`,{[`${EXT}real.mjs`]:EMPTY});
|
|
assert.throws(()=>organizationImportedFiles(repo),SUBSTITUTION,source);
|
|
}
|
|
const external=withOrg("import '../../other/src/a.mjs';\n",{[`${EXT}a.mjs`]:"const v=`${await import('./b.mjs')}`;\n",[`${EXT}b.mjs`]:EMPTY});
|
|
assert.throws(()=>organizationImportedFiles(external),/packages\/other\/src\/a\.mjs cannot be read for imports: unsupported import inside a template substitution/);
|
|
});
|
|
|
|
test('#779 R2 a substitution without a dynamic import is allowed, and the import around it is found', ()=>{
|
|
const repo=withOrg([
|
|
"const a=`plain ${b} text ${c.d({e:1})} end`;",
|
|
"const u=`${import.meta.url}/${x.import}/${loader.import('y')}`;",
|
|
"const s=`${'}'}${\"import('../../other/src/missing1.mjs')\"}${/import('..\\/x')/.source}`;",
|
|
"const t=`text import('../../other/src/missing2.mjs') ${a} import '../../other/src/missing3.mjs'`;",
|
|
"const e=`\\${await import('../../other/src/missing4.mjs')}`;",
|
|
"const n=`outer ${`inner ${a}`} tail`;",
|
|
"import '../../other/src/real.mjs';",
|
|
].join('\n'),{[`${EXT}real.mjs`]:EMPTY});
|
|
assert.deepEqual(organizationImportedFiles(repo),['packages/other/src/real.mjs']);
|
|
});
|
|
|
|
test('#779 R2 a substitution or the template text after it that never ends throws', ()=>{
|
|
for(const text of ['const a=`${b','const a=`${b} open','const a=`${`${b}']){
|
|
const repo=withOrg(text);
|
|
assert.throws(()=>organizationImportedFiles(repo),/packages\/organization\/src\/a\.mjs cannot be read for imports: unterminated template/,text);
|
|
}
|
|
});
|
|
|
|
// Each case is its own test, so one failing case does not hide the next.
|
|
for(const [what,make] of [
|
|
['an existing target',()=>withOrg("const v=`${({...import('../../other/src/real.mjs')})}`;\n",{[`${EXT}real.mjs`]:EMPTY})],
|
|
['a missing target',()=>withOrg("const v=`${({...import('../../other/src/real.mjs')})}`;\n")],
|
|
['a target outside the repository',()=>tree({[`${ORG}a.mjs`]:"const v=`${({...import('../../../../outside.mjs')})}`;\n",'outside.mjs':EMPTY})],
|
|
['an array spread of an existing target',()=>withOrg("const v=`${[...import('../../other/src/real.mjs')]}`;\n",{[`${EXT}real.mjs`]:EMPTY})],
|
|
]){
|
|
test(`#779 R3 a spread before import inside a template substitution throws: ${what}`,()=>{
|
|
assert.throws(()=>organizationImportedFiles(make()),SUBSTITUTION);
|
|
});
|
|
}
|
|
|
|
for(const [what,source,files] of [
|
|
['object spread',"const o={...import('../../other/src/real.mjs')};",{[`${EXT}real.mjs`]:EMPTY}],
|
|
['array spread',"const l=[...import('../../other/src/real.mjs')];",{[`${EXT}real.mjs`]:EMPTY}],
|
|
]){
|
|
test(`#779 R3 a spread before import in plain code is a dynamic import and is found when its argument is a plain string: ${what}`,()=>{
|
|
assert.deepEqual(organizationImportedFiles(withOrg(`${source}\n`,files)),['packages/other/src/real.mjs']);
|
|
});
|
|
}
|
|
|
|
test('#779 R3 a spread before import in plain code reaches the target checks: a missing target throws', ()=>{
|
|
const missing=withOrg("const o={...import('./missing.mjs')};\n");
|
|
assert.throws(()=>organizationImportedFiles(missing),/packages\/organization\/src\/a\.mjs imports \.\/missing\.mjs, which does not exist/);
|
|
});
|
|
|
|
for(const source of ['const o={...import(name)};','const l=[...import(name)];']){
|
|
test(`#779 R3 a spread before import in plain code is refused when its argument is not a plain string: ${source}`,()=>{
|
|
const repo=withOrg(`${source}\n`);
|
|
assert.throws(()=>organizationImportedFiles(repo),/organization\/src\/a\.mjs has a dynamic import that is not a plain string literal/);
|
|
});
|
|
}
|
|
|
|
test('#779 R3 a property call of import, x.import or x?.import, in plain code is not an import', ()=>{
|
|
const repo=withOrg([
|
|
"loader.import('../../other/src/missing1.mjs');",
|
|
"loader?.import('../../other/src/missing2.mjs');",
|
|
'loader.import(name);',
|
|
'loader?.import(name);',
|
|
"import '../../other/src/real.mjs';",
|
|
].join('\n'),{[`${EXT}real.mjs`]:EMPTY});
|
|
assert.deepEqual(organizationImportedFiles(repo),['packages/other/src/real.mjs']);
|
|
});
|
|
|
|
test('#779 R3 a property call of import, x.import or x?.import, in a substitution is not an import and is not refused', ()=>{
|
|
const repo=withOrg([
|
|
"const u=`${loader.import('../../other/src/missing3.mjs')}${loader?.import('../../other/src/missing4.mjs')}`;",
|
|
'const w=`${loader.import(name)}${loader?.import(name)}`;',
|
|
"import '../../other/src/real.mjs';",
|
|
].join('\n'),{[`${EXT}real.mjs`]:EMPTY});
|
|
assert.deepEqual(organizationImportedFiles(repo),['packages/other/src/real.mjs']);
|
|
});
|
|
|
|
test('#779 R2 a slash after a postfix ++ or -- is division, not a regular expression', ()=>{
|
|
for(const op of ['++','--']){
|
|
const repo=withOrg([
|
|
'let n=2;',
|
|
`const half=n${op} / 2;`,
|
|
`const spaced=n ${op}/2;`,
|
|
`const member=arr[0]${op} / 2;`,
|
|
`const grouped=(n)${op} / 2 / 3;`,
|
|
"import '../../other/src/real.mjs';",
|
|
].join('\n'),{[`${EXT}real.mjs`]:EMPTY});
|
|
assert.deepEqual(organizationImportedFiles(repo),['packages/other/src/real.mjs'],op);
|
|
}
|
|
});
|
|
|
|
test('#779 R2 a regular expression after an operator, a bracket or a prefix ++ or -- is still a regular expression', ()=>{
|
|
// Each body holds a quote, which would start an unterminated string if the slash were read as division.
|
|
const repo=withOrg([
|
|
"const a = /it's/;",
|
|
"if (/it's/.test(s)) {}",
|
|
"const b = f(1, /it's \\/ x/);",
|
|
"const c = a + /it's/.source;",
|
|
"const d = a++ + /it's/.source;",
|
|
"const e = ++/it's/.lastIndex;",
|
|
"const f = 1 + --/it's/.lastIndex;",
|
|
"import '../../other/src/real.mjs';",
|
|
].join('\n'),{[`${EXT}real.mjs`]:EMPTY});
|
|
assert.deepEqual(organizationImportedFiles(repo),['packages/other/src/real.mjs']);
|
|
});
|
|
|
|
// Rename r2 stage B: the walker reads both roots, the implementation and its old-path shims.
|
|
test('rename r2 B: a shim that re-exports the implementation adds nothing, and an outside import from a shim is found', ()=>{
|
|
const repo=tree({
|
|
[`${ORG}a.mjs`]:"import '../../other/src/from-org.mjs';\n",
|
|
[`${SHIM}a.mjs`]:"export * from '../../organization/src/a.mjs';\n",
|
|
[`${SHIM}b.mjs`]:"import '../../other/src/from-shim.mjs';\n",
|
|
[`${EXT}from-org.mjs`]:EMPTY,[`${EXT}from-shim.mjs`]:EMPTY,
|
|
});
|
|
assert.deepEqual(organizationImportedFiles(repo),['packages/other/src/from-org.mjs','packages/other/src/from-shim.mjs']);
|
|
});
|
|
|
|
test('rename r2 B: a shim that imports a missing implementation file throws and names the shim', ()=>{
|
|
const repo=tree({[`${SHIM}a.mjs`]:"export * from '../../organization/src/gone.mjs';\n"});
|
|
assert.throws(()=>organizationImportedFiles(repo),/packages\/business\/src\/a\.mjs imports \.\.\/\.\.\/organization\/src\/gone\.mjs, which does not exist/);
|
|
});
|
|
|
|
test('rename r2 B: a tree without either root throws, so half a package is never walked as a whole one', ()=>{
|
|
assert.throws(()=>organizationImportedFiles(tree({[`${ORG}a.mjs`]:EMPTY},{},{roots:[ORG]})),/ENOENT.*packages\/business\/src/);
|
|
assert.throws(()=>organizationImportedFiles(tree({[`${SHIM}a.mjs`]:EMPTY},{},{roots:[SHIM]})),/ENOENT.*packages\/organization\/src/);
|
|
});
|
|
|
|
test('rename r2 B: business-imports.mjs is the old name of the same walker', ()=>{
|
|
assert.equal(oldName.businessImportedFiles,organizationImportedFiles);
|
|
assert.equal(oldName.organizationImportedFiles,organizationImportedFiles);
|
|
});
|