fix(ivy): handle namespaced imports correctly (#31367)
The ngcc tool adds namespaced imports to files when compiling. The ngtsc tooling was not processing types correctly when they were imported via such namespaces. For example: ``` export declare class SomeModule { static withOptions(...): ModuleWithProviders<ɵngcc1.BaseModule>; ``` In this case the `BaseModule` was being incorrectly attributed to coming from the current module rather than the imported module, represented by `ɵngcc1`. Fixes #31342 PR Close #31367
This commit is contained in:
parent
36d3062a42
commit
98a68ad3e7
@ -12,7 +12,7 @@ import {absoluteFrom, getFileSystem, getSourceFileOrError} from '../../../src/ng
|
|||||||
import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
|
import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
|
||||||
import {ClassMemberKind, Import, isNamedVariableDeclaration} from '../../../src/ngtsc/reflection';
|
import {ClassMemberKind, Import, isNamedVariableDeclaration} from '../../../src/ngtsc/reflection';
|
||||||
import {getDeclaration} from '../../../src/ngtsc/testing';
|
import {getDeclaration} from '../../../src/ngtsc/testing';
|
||||||
import {loadFakeCore, loadTestFiles} from '../../../test/helpers';
|
import {loadFakeCore, loadTestFiles, loadTsLib} from '../../../test/helpers';
|
||||||
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
|
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
|
||||||
import {MockLogger} from '../helpers/mock_logger';
|
import {MockLogger} from '../helpers/mock_logger';
|
||||||
import {convertToDirectTsLibImport, makeTestBundleProgram} from '../helpers/utils';
|
import {convertToDirectTsLibImport, makeTestBundleProgram} from '../helpers/utils';
|
||||||
@ -122,6 +122,7 @@ runInEachFileSystem(() => {
|
|||||||
describe(`[${label}]`, () => {
|
describe(`[${label}]`, () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const fs = getFileSystem();
|
const fs = getFileSystem();
|
||||||
|
loadTsLib(fs);
|
||||||
loadFakeCore(fs);
|
loadFakeCore(fs);
|
||||||
loadTestFiles(FILES[label]);
|
loadTestFiles(FILES[label]);
|
||||||
});
|
});
|
||||||
|
@ -11,7 +11,7 @@ import {absoluteFrom, getFileSystem, getSourceFileOrError} from '../../../src/ng
|
|||||||
import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
|
import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
|
||||||
import {ClassMemberKind, Import, isNamedVariableDeclaration} from '../../../src/ngtsc/reflection';
|
import {ClassMemberKind, Import, isNamedVariableDeclaration} from '../../../src/ngtsc/reflection';
|
||||||
import {getDeclaration} from '../../../src/ngtsc/testing';
|
import {getDeclaration} from '../../../src/ngtsc/testing';
|
||||||
import {loadFakeCore, loadTestFiles} from '../../../test/helpers';
|
import {loadFakeCore, loadTestFiles, loadTsLib} from '../../../test/helpers';
|
||||||
import {Esm5ReflectionHost} from '../../src/host/esm5_host';
|
import {Esm5ReflectionHost} from '../../src/host/esm5_host';
|
||||||
import {MockLogger} from '../helpers/mock_logger';
|
import {MockLogger} from '../helpers/mock_logger';
|
||||||
import {convertToDirectTsLibImport, makeTestBundleProgram} from '../helpers/utils';
|
import {convertToDirectTsLibImport, makeTestBundleProgram} from '../helpers/utils';
|
||||||
@ -143,6 +143,7 @@ export { SomeDirective };
|
|||||||
describe(`[${label}]`, () => {
|
describe(`[${label}]`, () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const fs = getFileSystem();
|
const fs = getFileSystem();
|
||||||
|
loadTsLib(fs);
|
||||||
loadFakeCore(fs);
|
loadFakeCore(fs);
|
||||||
loadTestFiles(FILES[label]);
|
loadTestFiles(FILES[label]);
|
||||||
});
|
});
|
||||||
|
@ -97,7 +97,7 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
|||||||
}
|
}
|
||||||
this.checker.getExportsOfModule(symbol).forEach(exportSymbol => {
|
this.checker.getExportsOfModule(symbol).forEach(exportSymbol => {
|
||||||
// Map each exported Symbol to a Declaration and add it to the map.
|
// Map each exported Symbol to a Declaration and add it to the map.
|
||||||
const decl = this.getDeclarationOfSymbol(exportSymbol);
|
const decl = this.getDeclarationOfSymbol(exportSymbol, null);
|
||||||
if (decl !== null) {
|
if (decl !== null) {
|
||||||
map.set(exportSymbol.name, decl);
|
map.set(exportSymbol.name, decl);
|
||||||
}
|
}
|
||||||
@ -122,7 +122,7 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
|||||||
if (symbol === undefined) {
|
if (symbol === undefined) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return this.getDeclarationOfSymbol(symbol);
|
return this.getDeclarationOfSymbol(symbol, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDefinitionOfFunction(node: ts.Node): FunctionDefinition|null {
|
getDefinitionOfFunction(node: ts.Node): FunctionDefinition|null {
|
||||||
@ -244,7 +244,8 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
|||||||
*
|
*
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
protected getDeclarationOfSymbol(symbol: ts.Symbol): Declaration|null {
|
private getDeclarationOfSymbol(symbol: ts.Symbol, originalId: ts.Identifier|null): Declaration
|
||||||
|
|null {
|
||||||
// If the symbol points to a ShorthandPropertyAssignment, resolve it.
|
// If the symbol points to a ShorthandPropertyAssignment, resolve it.
|
||||||
if (symbol.valueDeclaration !== undefined &&
|
if (symbol.valueDeclaration !== undefined &&
|
||||||
ts.isShorthandPropertyAssignment(symbol.valueDeclaration)) {
|
ts.isShorthandPropertyAssignment(symbol.valueDeclaration)) {
|
||||||
@ -253,32 +254,15 @@ export class TypeScriptReflectionHost implements ReflectionHost {
|
|||||||
if (shorthandSymbol === undefined) {
|
if (shorthandSymbol === undefined) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return this.getDeclarationOfSymbol(shorthandSymbol);
|
return this.getDeclarationOfSymbol(shorthandSymbol, originalId);
|
||||||
}
|
|
||||||
let viaModule: string|null = null;
|
|
||||||
// Look through the Symbol's immediate declarations, and see if any of them are import-type
|
|
||||||
// statements.
|
|
||||||
if (symbol.declarations !== undefined && symbol.declarations.length > 0) {
|
|
||||||
for (let i = 0; i < symbol.declarations.length; i++) {
|
|
||||||
const decl = symbol.declarations[i];
|
|
||||||
if (ts.isImportSpecifier(decl) && decl.parent !== undefined &&
|
|
||||||
decl.parent.parent !== undefined && decl.parent.parent.parent !== undefined) {
|
|
||||||
// Find the ImportDeclaration that imported this Symbol.
|
|
||||||
const importDecl = decl.parent.parent.parent;
|
|
||||||
// The moduleSpecifier should always be a string.
|
|
||||||
if (ts.isStringLiteral(importDecl.moduleSpecifier)) {
|
|
||||||
// Check if the moduleSpecifier is absolute. If it is, this symbol comes from an
|
|
||||||
// external module, and the import path becomes the viaModule.
|
|
||||||
const moduleSpecifier = importDecl.moduleSpecifier.text;
|
|
||||||
if (!moduleSpecifier.startsWith('.')) {
|
|
||||||
viaModule = moduleSpecifier;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const importInfo = originalId && this.getImportOfIdentifier(originalId);
|
||||||
|
const viaModule =
|
||||||
|
importInfo !== null && importInfo.from !== null && !importInfo.from.startsWith('.') ?
|
||||||
|
importInfo.from :
|
||||||
|
null;
|
||||||
|
|
||||||
// Now, resolve the Symbol to its declaration by following any and all aliases.
|
// Now, resolve the Symbol to its declaration by following any and all aliases.
|
||||||
while (symbol.flags & ts.SymbolFlags.Alias) {
|
while (symbol.flags & ts.SymbolFlags.Alias) {
|
||||||
symbol = this.checker.getAliasedSymbol(symbol);
|
symbol = this.checker.getAliasedSymbol(symbol);
|
||||||
|
@ -19,7 +19,7 @@ runInEachFileSystem(() => {
|
|||||||
|
|
||||||
beforeEach(() => _ = absoluteFrom);
|
beforeEach(() => _ = absoluteFrom);
|
||||||
|
|
||||||
describe('ctor params', () => {
|
describe('getConstructorParameters()', () => {
|
||||||
it('should reflect a single argument', () => {
|
it('should reflect a single argument', () => {
|
||||||
const {program} = makeProgram([{
|
const {program} = makeProgram([{
|
||||||
name: _('/entry.ts'),
|
name: _('/entry.ts'),
|
||||||
@ -213,46 +213,215 @@ runInEachFileSystem(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reflect a re-export', () => {
|
|
||||||
const {program} = makeProgram([
|
|
||||||
{name: _('/node_modules/absolute/index.ts'), contents: 'export class Target {}'},
|
|
||||||
{name: _('/local1.ts'), contents: `export {Target as AliasTarget} from 'absolute';`},
|
|
||||||
{name: _('/local2.ts'), contents: `export {AliasTarget as Target} from './local1';`}, {
|
|
||||||
name: _('/entry.ts'),
|
|
||||||
contents: `
|
|
||||||
import {Target} from './local2';
|
|
||||||
import {Target as DirectTarget} from 'absolute';
|
|
||||||
|
|
||||||
const target = Target;
|
describe('getImportOfIdentifier()', () => {
|
||||||
const directTarget = DirectTarget;
|
it('should resolve a direct import', () => {
|
||||||
`
|
const {program} = makeProgram([
|
||||||
|
{name: _('/node_modules/absolute/index.ts'), contents: 'export class Target {}'},
|
||||||
|
{
|
||||||
|
name: _('/entry.ts'),
|
||||||
|
contents: `
|
||||||
|
import {Target} from 'absolute';
|
||||||
|
let foo: Target;
|
||||||
|
`
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const checker = program.getTypeChecker();
|
||||||
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
|
|
||||||
|
const foo = getDeclaration(program, _('/entry.ts'), 'foo', ts.isVariableDeclaration);
|
||||||
|
if (foo.type === undefined || !ts.isTypeReferenceNode(foo.type) ||
|
||||||
|
!ts.isIdentifier(foo.type.typeName)) {
|
||||||
|
return fail('Unexpected type for foo');
|
||||||
}
|
}
|
||||||
]);
|
const Target = foo.type.typeName;
|
||||||
const target = getDeclaration(program, _('/entry.ts'), 'target', ts.isVariableDeclaration);
|
const directImport = host.getImportOfIdentifier(Target);
|
||||||
if (target.initializer === undefined || !ts.isIdentifier(target.initializer)) {
|
expect(directImport).toEqual({
|
||||||
return fail('Unexpected initializer for target');
|
name: 'Target',
|
||||||
}
|
from: 'absolute',
|
||||||
const directTarget =
|
});
|
||||||
getDeclaration(program, _('/entry.ts'), 'directTarget', ts.isVariableDeclaration);
|
});
|
||||||
if (directTarget.initializer === undefined || !ts.isIdentifier(directTarget.initializer)) {
|
|
||||||
return fail('Unexpected initializer for directTarget');
|
|
||||||
}
|
|
||||||
const Target = target.initializer;
|
|
||||||
const DirectTarget = directTarget.initializer;
|
|
||||||
|
|
||||||
const checker = program.getTypeChecker();
|
it('should resolve a namespaced import', () => {
|
||||||
const host = new TypeScriptReflectionHost(checker);
|
const {program} = makeProgram([
|
||||||
const targetDecl = host.getDeclarationOfIdentifier(Target);
|
{name: _('/node_modules/absolute/index.ts'), contents: 'export class Target {}'},
|
||||||
const directTargetDecl = host.getDeclarationOfIdentifier(DirectTarget);
|
{
|
||||||
if (targetDecl === null) {
|
name: _('/entry.ts'),
|
||||||
return fail('No declaration found for Target');
|
contents: `
|
||||||
} else if (directTargetDecl === null) {
|
import * as abs from 'absolute';
|
||||||
return fail('No declaration found for DirectTarget');
|
let foo: abs.Target;
|
||||||
}
|
`
|
||||||
expect(targetDecl.node.getSourceFile().fileName).toBe(_('/node_modules/absolute/index.ts'));
|
},
|
||||||
expect(ts.isClassDeclaration(targetDecl.node)).toBe(true);
|
]);
|
||||||
expect(directTargetDecl.viaModule).toBe('absolute');
|
const checker = program.getTypeChecker();
|
||||||
expect(directTargetDecl.node).toBe(targetDecl.node);
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
|
|
||||||
|
const foo = getDeclaration(program, _('/entry.ts'), 'foo', ts.isVariableDeclaration);
|
||||||
|
if (foo.type === undefined || !ts.isTypeReferenceNode(foo.type) ||
|
||||||
|
!ts.isQualifiedName(foo.type.typeName)) {
|
||||||
|
return fail('Unexpected type for foo');
|
||||||
|
}
|
||||||
|
const Target = foo.type.typeName.right;
|
||||||
|
const namespacedImport = host.getImportOfIdentifier(Target);
|
||||||
|
expect(namespacedImport).toEqual({
|
||||||
|
name: 'Target',
|
||||||
|
from: 'absolute',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getDeclarationOfIdentifier()', () => {
|
||||||
|
it('should reflect a re-export', () => {
|
||||||
|
const {program} = makeProgram([
|
||||||
|
{name: _('/node_modules/absolute/index.ts'), contents: 'export class Target {}'},
|
||||||
|
{name: _('/local1.ts'), contents: `export {Target as AliasTarget} from 'absolute';`},
|
||||||
|
{name: _('/local2.ts'), contents: `export {AliasTarget as Target} from './local1';`}, {
|
||||||
|
name: _('/entry.ts'),
|
||||||
|
contents: `
|
||||||
|
import {Target} from './local2';
|
||||||
|
import {Target as DirectTarget} from 'absolute';
|
||||||
|
|
||||||
|
const target = Target;
|
||||||
|
const directTarget = DirectTarget;
|
||||||
|
`
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
const target = getDeclaration(program, _('/entry.ts'), 'target', ts.isVariableDeclaration);
|
||||||
|
if (target.initializer === undefined || !ts.isIdentifier(target.initializer)) {
|
||||||
|
return fail('Unexpected initializer for target');
|
||||||
|
}
|
||||||
|
const directTarget =
|
||||||
|
getDeclaration(program, _('/entry.ts'), 'directTarget', ts.isVariableDeclaration);
|
||||||
|
if (directTarget.initializer === undefined || !ts.isIdentifier(directTarget.initializer)) {
|
||||||
|
return fail('Unexpected initializer for directTarget');
|
||||||
|
}
|
||||||
|
const Target = target.initializer;
|
||||||
|
const DirectTarget = directTarget.initializer;
|
||||||
|
|
||||||
|
const checker = program.getTypeChecker();
|
||||||
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
|
const targetDecl = host.getDeclarationOfIdentifier(Target);
|
||||||
|
const directTargetDecl = host.getDeclarationOfIdentifier(DirectTarget);
|
||||||
|
if (targetDecl === null) {
|
||||||
|
return fail('No declaration found for Target');
|
||||||
|
} else if (directTargetDecl === null) {
|
||||||
|
return fail('No declaration found for DirectTarget');
|
||||||
|
}
|
||||||
|
expect(targetDecl.node.getSourceFile().fileName).toBe(_('/node_modules/absolute/index.ts'));
|
||||||
|
expect(ts.isClassDeclaration(targetDecl.node)).toBe(true);
|
||||||
|
expect(directTargetDecl.viaModule).toBe('absolute');
|
||||||
|
expect(directTargetDecl.node).toBe(targetDecl.node);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should resolve a direct import', () => {
|
||||||
|
const {program} = makeProgram([
|
||||||
|
{name: _('/node_modules/absolute/index.ts'), contents: 'export class Target {}'},
|
||||||
|
{
|
||||||
|
name: _('/entry.ts'),
|
||||||
|
contents: `
|
||||||
|
import {Target} from 'absolute';
|
||||||
|
let foo: Target;
|
||||||
|
`
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const checker = program.getTypeChecker();
|
||||||
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
|
|
||||||
|
const targetDecl = getDeclaration(
|
||||||
|
program, _('/node_modules/absolute/index.ts'), 'Target', ts.isClassDeclaration);
|
||||||
|
const foo = getDeclaration(program, _('/entry.ts'), 'foo', ts.isVariableDeclaration);
|
||||||
|
if (foo.type === undefined || !ts.isTypeReferenceNode(foo.type) ||
|
||||||
|
!ts.isIdentifier(foo.type.typeName)) {
|
||||||
|
return fail('Unexpected type for foo');
|
||||||
|
}
|
||||||
|
const Target = foo.type.typeName;
|
||||||
|
const decl = host.getDeclarationOfIdentifier(Target);
|
||||||
|
expect(decl).toEqual({
|
||||||
|
node: targetDecl,
|
||||||
|
viaModule: 'absolute',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should resolve a namespaced import', () => {
|
||||||
|
const {program} = makeProgram([
|
||||||
|
{name: _('/node_modules/absolute/index.ts'), contents: 'export class Target {}'},
|
||||||
|
{
|
||||||
|
name: _('/entry.ts'),
|
||||||
|
contents: `
|
||||||
|
import * as abs from 'absolute';
|
||||||
|
let foo: abs.Target;
|
||||||
|
`
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const checker = program.getTypeChecker();
|
||||||
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
|
|
||||||
|
const targetDecl = getDeclaration(
|
||||||
|
program, _('/node_modules/absolute/index.ts'), 'Target', ts.isClassDeclaration);
|
||||||
|
const foo = getDeclaration(program, _('/entry.ts'), 'foo', ts.isVariableDeclaration);
|
||||||
|
if (foo.type === undefined || !ts.isTypeReferenceNode(foo.type) ||
|
||||||
|
!ts.isQualifiedName(foo.type.typeName)) {
|
||||||
|
return fail('Unexpected type for foo');
|
||||||
|
}
|
||||||
|
const Target = foo.type.typeName.right;
|
||||||
|
const decl = host.getDeclarationOfIdentifier(Target);
|
||||||
|
expect(decl).toEqual({
|
||||||
|
node: targetDecl,
|
||||||
|
viaModule: 'absolute',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getExportsOfModule()', () => {
|
||||||
|
it('should handle simple exports', () => {
|
||||||
|
const {program} = makeProgram([
|
||||||
|
{
|
||||||
|
name: _('/entry.ts'),
|
||||||
|
contents: `
|
||||||
|
export const x = 10;
|
||||||
|
export function foo() {}
|
||||||
|
export type T = string;
|
||||||
|
export interface I {}
|
||||||
|
export enum E {}
|
||||||
|
`
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const checker = program.getTypeChecker();
|
||||||
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
|
const exportedDeclarations =
|
||||||
|
host.getExportsOfModule(program.getSourceFile(_('/entry.ts')) !);
|
||||||
|
expect(Array.from(exportedDeclarations !.keys())).toEqual(['foo', 'x', 'T', 'I', 'E']);
|
||||||
|
expect(Array.from(exportedDeclarations !.values()).map(v => v.viaModule)).toEqual([
|
||||||
|
null, null, null, null, null
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle re-exports', () => {
|
||||||
|
const {program} = makeProgram([
|
||||||
|
{name: _('/node_modules/absolute/index.ts'), contents: 'export class Target {}'},
|
||||||
|
{name: _('/local1.ts'), contents: `export {Target as AliasTarget} from 'absolute';`},
|
||||||
|
{name: _('/local2.ts'), contents: `export {AliasTarget as Target} from './local1';`},
|
||||||
|
{
|
||||||
|
name: _('/entry.ts'),
|
||||||
|
contents: `
|
||||||
|
export {Target as Target1} from 'absolute';
|
||||||
|
export {AliasTarget} from './local1';
|
||||||
|
export {Target as AliasTarget2} from './local2';
|
||||||
|
export * from 'absolute';
|
||||||
|
`
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const checker = program.getTypeChecker();
|
||||||
|
const host = new TypeScriptReflectionHost(checker);
|
||||||
|
const exportedDeclarations =
|
||||||
|
host.getExportsOfModule(program.getSourceFile(_('/entry.ts')) !);
|
||||||
|
expect(Array.from(exportedDeclarations !.keys())).toEqual([
|
||||||
|
'Target1', 'AliasTarget', 'AliasTarget2', 'Target'
|
||||||
|
]);
|
||||||
|
expect(Array.from(exportedDeclarations !.values()).map(v => v.viaModule)).toEqual([
|
||||||
|
null, null, null, null
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -31,9 +31,7 @@ export function loadStandardTestFiles(
|
|||||||
tmpFs, resolveNpmTreeArtifact('typescript'),
|
tmpFs, resolveNpmTreeArtifact('typescript'),
|
||||||
tmpFs.resolve(basePath, 'node_modules/typescript'));
|
tmpFs.resolve(basePath, 'node_modules/typescript'));
|
||||||
|
|
||||||
loadTestDirectory(
|
loadTsLib(tmpFs, basePath);
|
||||||
tmpFs, resolveNpmTreeArtifact('tslib'), tmpFs.resolve(basePath, 'node_modules/tslib'));
|
|
||||||
|
|
||||||
|
|
||||||
if (fakeCore) {
|
if (fakeCore) {
|
||||||
loadFakeCore(tmpFs, basePath);
|
loadFakeCore(tmpFs, basePath);
|
||||||
@ -51,6 +49,11 @@ export function loadStandardTestFiles(
|
|||||||
return tmpFs.dump();
|
return tmpFs.dump();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function loadTsLib(fs: FileSystem, basePath: string = '/') {
|
||||||
|
loadTestDirectory(
|
||||||
|
fs, resolveNpmTreeArtifact('tslib'), fs.resolve(basePath, 'node_modules/tslib'));
|
||||||
|
}
|
||||||
|
|
||||||
export function loadFakeCore(fs: FileSystem, basePath: string = '/') {
|
export function loadFakeCore(fs: FileSystem, basePath: string = '/') {
|
||||||
loadTestDirectory(
|
loadTestDirectory(
|
||||||
fs, resolveNpmTreeArtifact('angular/packages/compiler-cli/test/ngtsc/fake_core/npm_package'),
|
fs, resolveNpmTreeArtifact('angular/packages/compiler-cli/test/ngtsc/fake_core/npm_package'),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user