fix(ivy): ngcc - do not analyze files outside the current package (#30591)
Our module resolution prefers `.js` files over `.d.ts` files because occasionally libraries publish their typings in the same directory structure as the compiled JS files, i.e. adjacent to each other. The standard TS module resolution would pick up the typings file and add that to the `ts.Program` and so they would be ignored by our analyzers. But we need those JS files, if they are part of the current package. But this meant that we also bring in JS files from external imports from outside the package, which is not desired. This was happening for the `@fire/storage` enty-point that was importing the `firebase/storage` path. In this commit we solve this problem, for the case of imports coming from a completely different package, by saying that any file that is outside the package root directory must be an external import and so we do not analyze those files. This does not solve the potential problem of imports between secondary entry-points within a package but so far that does not appear to be a problem. PR Close #30591
This commit is contained in:
parent
42036f4b79
commit
f690a4e0af
|
@ -10,7 +10,7 @@ import * as ts from 'typescript';
|
||||||
|
|
||||||
import {BaseDefDecoratorHandler, ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ReferencesRegistry, ResourceLoader} from '../../../src/ngtsc/annotations';
|
import {BaseDefDecoratorHandler, ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ReferencesRegistry, ResourceLoader} from '../../../src/ngtsc/annotations';
|
||||||
import {CycleAnalyzer, ImportGraph} from '../../../src/ngtsc/cycles';
|
import {CycleAnalyzer, ImportGraph} from '../../../src/ngtsc/cycles';
|
||||||
import {AbsoluteFsPath, FileSystem, LogicalFileSystem, absoluteFrom, dirname, resolve} from '../../../src/ngtsc/file_system';
|
import {FileSystem, LogicalFileSystem, absoluteFrom, dirname, resolve} from '../../../src/ngtsc/file_system';
|
||||||
import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../../src/ngtsc/imports';
|
import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../../src/ngtsc/imports';
|
||||||
import {CompoundMetadataReader, CompoundMetadataRegistry, DtsMetadataReader, LocalMetadataRegistry} from '../../../src/ngtsc/metadata';
|
import {CompoundMetadataReader, CompoundMetadataRegistry, DtsMetadataReader, LocalMetadataRegistry} from '../../../src/ngtsc/metadata';
|
||||||
import {PartialEvaluator} from '../../../src/ngtsc/partial_evaluator';
|
import {PartialEvaluator} from '../../../src/ngtsc/partial_evaluator';
|
||||||
|
@ -20,6 +20,7 @@ import {CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '
|
||||||
import {NgccReflectionHost} from '../host/ngcc_host';
|
import {NgccReflectionHost} from '../host/ngcc_host';
|
||||||
import {EntryPointBundle} from '../packages/entry_point_bundle';
|
import {EntryPointBundle} from '../packages/entry_point_bundle';
|
||||||
import {isDefined} from '../utils';
|
import {isDefined} from '../utils';
|
||||||
|
import {isWithinPackage} from './util';
|
||||||
|
|
||||||
export interface AnalyzedFile {
|
export interface AnalyzedFile {
|
||||||
sourceFile: ts.SourceFile;
|
sourceFile: ts.SourceFile;
|
||||||
|
@ -72,6 +73,7 @@ export class DecorationAnalyzer {
|
||||||
private host = this.bundle.src.host;
|
private host = this.bundle.src.host;
|
||||||
private typeChecker = this.bundle.src.program.getTypeChecker();
|
private typeChecker = this.bundle.src.program.getTypeChecker();
|
||||||
private rootDirs = this.bundle.rootDirs;
|
private rootDirs = this.bundle.rootDirs;
|
||||||
|
private packagePath = this.bundle.entryPoint.package;
|
||||||
private isCore = this.bundle.isCore;
|
private isCore = this.bundle.isCore;
|
||||||
resourceManager = new NgccResourceLoader(this.fs);
|
resourceManager = new NgccResourceLoader(this.fs);
|
||||||
metaRegistry = new LocalMetadataRegistry();
|
metaRegistry = new LocalMetadataRegistry();
|
||||||
|
@ -130,6 +132,7 @@ export class DecorationAnalyzer {
|
||||||
analyzeProgram(): DecorationAnalyses {
|
analyzeProgram(): DecorationAnalyses {
|
||||||
const decorationAnalyses = new DecorationAnalyses();
|
const decorationAnalyses = new DecorationAnalyses();
|
||||||
const analysedFiles = this.program.getSourceFiles()
|
const analysedFiles = this.program.getSourceFiles()
|
||||||
|
.filter(sourceFile => isWithinPackage(this.packagePath, sourceFile))
|
||||||
.map(sourceFile => this.analyzeFile(sourceFile))
|
.map(sourceFile => this.analyzeFile(sourceFile))
|
||||||
.filter(isDefined);
|
.filter(isDefined);
|
||||||
analysedFiles.forEach(analysedFile => this.resolveFile(analysedFile));
|
analysedFiles.forEach(analysedFile => this.resolveFile(analysedFile));
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
import {AbsoluteFsPath} from '../../../src/ngtsc/file_system';
|
||||||
import {NgccReflectionHost, SwitchableVariableDeclaration} from '../host/ngcc_host';
|
import {NgccReflectionHost, SwitchableVariableDeclaration} from '../host/ngcc_host';
|
||||||
|
import {isWithinPackage} from './util';
|
||||||
|
|
||||||
export interface SwitchMarkerAnalysis {
|
export interface SwitchMarkerAnalysis {
|
||||||
sourceFile: ts.SourceFile;
|
sourceFile: ts.SourceFile;
|
||||||
|
@ -21,7 +23,7 @@ export const SwitchMarkerAnalyses = Map;
|
||||||
* that will be replaced.
|
* that will be replaced.
|
||||||
*/
|
*/
|
||||||
export class SwitchMarkerAnalyzer {
|
export class SwitchMarkerAnalyzer {
|
||||||
constructor(private host: NgccReflectionHost) {}
|
constructor(private host: NgccReflectionHost, private packagePath: AbsoluteFsPath) {}
|
||||||
/**
|
/**
|
||||||
* Analyze the files in the program to identify declarations that contain R3
|
* Analyze the files in the program to identify declarations that contain R3
|
||||||
* switch markers.
|
* switch markers.
|
||||||
|
@ -32,7 +34,9 @@ export class SwitchMarkerAnalyzer {
|
||||||
*/
|
*/
|
||||||
analyzeProgram(program: ts.Program): SwitchMarkerAnalyses {
|
analyzeProgram(program: ts.Program): SwitchMarkerAnalyses {
|
||||||
const analyzedFiles = new SwitchMarkerAnalyses();
|
const analyzedFiles = new SwitchMarkerAnalyses();
|
||||||
program.getSourceFiles().forEach(sourceFile => {
|
program.getSourceFiles()
|
||||||
|
.filter(sourceFile => isWithinPackage(this.packagePath, sourceFile))
|
||||||
|
.forEach(sourceFile => {
|
||||||
const declarations = this.host.getSwitchableDeclarations(sourceFile);
|
const declarations = this.host.getSwitchableDeclarations(sourceFile);
|
||||||
if (declarations.length) {
|
if (declarations.length) {
|
||||||
analyzedFiles.set(sourceFile, {sourceFile, declarations});
|
analyzedFiles.set(sourceFile, {sourceFile, declarations});
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
import * as ts from 'typescript';
|
||||||
|
import {AbsoluteFsPath, absoluteFromSourceFile, relative} from '../../../src/ngtsc/file_system';
|
||||||
|
|
||||||
|
export function isWithinPackage(packagePath: AbsoluteFsPath, sourceFile: ts.SourceFile): boolean {
|
||||||
|
return !relative(packagePath, absoluteFromSourceFile(sourceFile)).startsWith('..');
|
||||||
|
}
|
|
@ -122,7 +122,8 @@ export class Transformer {
|
||||||
analyzeProgram(reflectionHost: NgccReflectionHost, bundle: EntryPointBundle): ProgramAnalyses {
|
analyzeProgram(reflectionHost: NgccReflectionHost, bundle: EntryPointBundle): ProgramAnalyses {
|
||||||
const referencesRegistry = new NgccReferencesRegistry(reflectionHost);
|
const referencesRegistry = new NgccReferencesRegistry(reflectionHost);
|
||||||
|
|
||||||
const switchMarkerAnalyzer = new SwitchMarkerAnalyzer(reflectionHost);
|
const switchMarkerAnalyzer =
|
||||||
|
new SwitchMarkerAnalyzer(reflectionHost, bundle.entryPoint.package);
|
||||||
const switchMarkerAnalyses = switchMarkerAnalyzer.analyzeProgram(bundle.src.program);
|
const switchMarkerAnalyses = switchMarkerAnalyzer.analyzeProgram(bundle.src.program);
|
||||||
|
|
||||||
const decorationAnalyzer =
|
const decorationAnalyzer =
|
||||||
|
|
|
@ -109,17 +109,19 @@ runInEachFileSystem(() => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const TEST_PROGRAM = [
|
const TEST_PROGRAM = [
|
||||||
{
|
{
|
||||||
name: _('/index.js'),
|
name: _('/node_modules/test-package/index.js'),
|
||||||
contents: `
|
contents: `
|
||||||
import * as test from './test';
|
import * as test from './test';
|
||||||
import * as other from './other';
|
import * as other from './other';
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/test.js'),
|
name: _('/node_modules/test-package/test.js'),
|
||||||
contents: `
|
contents: `
|
||||||
import {Component, Directive, Injectable} from '@angular/core';
|
import {Component, Directive, Injectable} from '@angular/core';
|
||||||
|
|
||||||
|
export class NoDecorators {}
|
||||||
|
|
||||||
export class MyComponent {}
|
export class MyComponent {}
|
||||||
MyComponent.decorators = [{type: Component}];
|
MyComponent.decorators = [{type: Component}];
|
||||||
|
|
||||||
|
@ -128,10 +130,11 @@ runInEachFileSystem(() => {
|
||||||
|
|
||||||
export class MyService {}
|
export class MyService {}
|
||||||
MyService.decorators = [{type: Injectable}];
|
MyService.decorators = [{type: Injectable}];
|
||||||
|
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/other.js'),
|
name: _('/node_modules/test-package/other.js'),
|
||||||
contents: `
|
contents: `
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
|
|
||||||
|
@ -144,22 +147,16 @@ runInEachFileSystem(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return an object containing a reference to the original source file', () => {
|
it('should return an object containing a reference to the original source file', () => {
|
||||||
const testFile = getSourceFileOrError(program, _('/test.js'));
|
const testFile = getSourceFileOrError(program, _('/node_modules/test-package/test.js'));
|
||||||
expect(result.get(testFile) !.sourceFile).toBe(testFile);
|
expect(result.get(testFile) !.sourceFile).toBe(testFile);
|
||||||
const otherFile = getSourceFileOrError(program, _('/other.js'));
|
const otherFile = getSourceFileOrError(program, _('/node_modules/test-package/other.js'));
|
||||||
expect(result.get(otherFile) !.sourceFile).toBe(otherFile);
|
expect(result.get(otherFile) !.sourceFile).toBe(otherFile);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call detect on the decorator handlers with each class from the parsed file',
|
it('should call detect on the decorator handlers with each class from the parsed file',
|
||||||
() => {
|
() => {
|
||||||
expect(testHandler.detect).toHaveBeenCalledTimes(11);
|
expect(testHandler.detect).toHaveBeenCalledTimes(5);
|
||||||
expect(testHandler.detect.calls.allArgs().map(args => args[1])).toEqual([
|
expect(testHandler.detect.calls.allArgs().map(args => args[1])).toEqual([
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
null,
|
||||||
jasmine.arrayContaining([jasmine.objectContaining({name: 'Component'})]),
|
jasmine.arrayContaining([jasmine.objectContaining({name: 'Component'})]),
|
||||||
jasmine.arrayContaining([jasmine.objectContaining({name: 'Directive'})]),
|
jasmine.arrayContaining([jasmine.objectContaining({name: 'Directive'})]),
|
||||||
|
@ -169,7 +166,7 @@ runInEachFileSystem(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return an object containing the classes that were analyzed', () => {
|
it('should return an object containing the classes that were analyzed', () => {
|
||||||
const file1 = getSourceFileOrError(program, _('/test.js'));
|
const file1 = getSourceFileOrError(program, _('/node_modules/test-package/test.js'));
|
||||||
const compiledFile1 = result.get(file1) !;
|
const compiledFile1 = result.get(file1) !;
|
||||||
expect(compiledFile1.compiledClasses.length).toEqual(2);
|
expect(compiledFile1.compiledClasses.length).toEqual(2);
|
||||||
expect(compiledFile1.compiledClasses[0]).toEqual(jasmine.objectContaining({
|
expect(compiledFile1.compiledClasses[0]).toEqual(jasmine.objectContaining({
|
||||||
|
@ -179,7 +176,7 @@ runInEachFileSystem(() => {
|
||||||
name: 'MyDirective', compilation: ['@Directive (compiled)'],
|
name: 'MyDirective', compilation: ['@Directive (compiled)'],
|
||||||
} as unknown as CompiledClass));
|
} as unknown as CompiledClass));
|
||||||
|
|
||||||
const file2 = getSourceFileOrError(program, _('/other.js'));
|
const file2 = getSourceFileOrError(program, _('/node_modules/test-package/other.js'));
|
||||||
const compiledFile2 = result.get(file2) !;
|
const compiledFile2 = result.get(file2) !;
|
||||||
expect(compiledFile2.compiledClasses.length).toEqual(1);
|
expect(compiledFile2.compiledClasses.length).toEqual(1);
|
||||||
expect(compiledFile2.compiledClasses[0]).toEqual(jasmine.objectContaining({
|
expect(compiledFile2.compiledClasses[0]).toEqual(jasmine.objectContaining({
|
||||||
|
@ -190,13 +187,7 @@ runInEachFileSystem(() => {
|
||||||
it('should analyze, resolve and compile the classes that are detected', () => {
|
it('should analyze, resolve and compile the classes that are detected', () => {
|
||||||
expect(logs).toEqual([
|
expect(logs).toEqual([
|
||||||
// Classes without decorators should also be detected.
|
// Classes without decorators should also be detected.
|
||||||
'detect: ChangeDetectorRef (no decorators)',
|
'detect: NoDecorators (no decorators)',
|
||||||
'detect: ElementRef (no decorators)',
|
|
||||||
'detect: Injector (no decorators)',
|
|
||||||
'detect: TemplateRef (no decorators)',
|
|
||||||
'detect: ViewContainerRef (no decorators)',
|
|
||||||
'detect: Renderer2 (no decorators)',
|
|
||||||
'detect: ɵNgModuleFactory (no decorators)',
|
|
||||||
// First detect and (potentially) analyze.
|
// First detect and (potentially) analyze.
|
||||||
'detect: MyComponent@Component',
|
'detect: MyComponent@Component',
|
||||||
'analyze: MyComponent@Component',
|
'analyze: MyComponent@Component',
|
||||||
|
@ -221,7 +212,7 @@ runInEachFileSystem(() => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const INTERNAL_COMPONENT_PROGRAM = [
|
const INTERNAL_COMPONENT_PROGRAM = [
|
||||||
{
|
{
|
||||||
name: _('/entrypoint.js'),
|
name: _('/node_modules/test-package/entrypoint.js'),
|
||||||
contents: `
|
contents: `
|
||||||
import {Component, NgModule} from '@angular/core';
|
import {Component, NgModule} from '@angular/core';
|
||||||
import {ImportedComponent} from './component';
|
import {ImportedComponent} from './component';
|
||||||
|
@ -237,7 +228,7 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/component.js'),
|
name: _('/node_modules/test-package/component.js'),
|
||||||
contents: `
|
contents: `
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
export class ImportedComponent {}
|
export class ImportedComponent {}
|
||||||
|
@ -253,7 +244,8 @@ runInEachFileSystem(() => {
|
||||||
// files is not yet solved.
|
// files is not yet solved.
|
||||||
it('should analyze an internally imported component, which is not publicly exported from the entry-point',
|
it('should analyze an internally imported component, which is not publicly exported from the entry-point',
|
||||||
() => {
|
() => {
|
||||||
const file = getSourceFileOrError(program, _('/component.js'));
|
const file =
|
||||||
|
getSourceFileOrError(program, _('/node_modules/test-package/component.js'));
|
||||||
const analysis = result.get(file) !;
|
const analysis = result.get(file) !;
|
||||||
expect(analysis).toBeDefined();
|
expect(analysis).toBeDefined();
|
||||||
const ImportedComponent =
|
const ImportedComponent =
|
||||||
|
@ -262,13 +254,58 @@ runInEachFileSystem(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should analyze an internally defined component, which is not exported at all', () => {
|
it('should analyze an internally defined component, which is not exported at all', () => {
|
||||||
const file = getSourceFileOrError(program, _('/entrypoint.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/entrypoint.js'));
|
||||||
const analysis = result.get(file) !;
|
const analysis = result.get(file) !;
|
||||||
expect(analysis).toBeDefined();
|
expect(analysis).toBeDefined();
|
||||||
const LocalComponent = analysis.compiledClasses.find(f => f.name === 'LocalComponent') !;
|
const LocalComponent = analysis.compiledClasses.find(f => f.name === 'LocalComponent') !;
|
||||||
expect(LocalComponent).toBeDefined();
|
expect(LocalComponent).toBeDefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('external components', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
const EXTERNAL_COMPONENT_PROGRAM: TestFile[] = [
|
||||||
|
{
|
||||||
|
name: _('/node_modules/test-package/entrypoint.js'),
|
||||||
|
contents: `
|
||||||
|
import {Component, NgModule} from '@angular/core';
|
||||||
|
import {ImportedComponent} from 'other/component';
|
||||||
|
|
||||||
|
export class LocalComponent {}
|
||||||
|
LocalComponent.decorators = [{type: Component}];
|
||||||
|
|
||||||
|
export class MyModule {}
|
||||||
|
MyModule.decorators = [{type: NgModule, args: [{
|
||||||
|
declarations: [ImportedComponent, LocalComponent],
|
||||||
|
exports: [ImportedComponent, LocalComponent],
|
||||||
|
},] }];
|
||||||
|
`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: _('/node_modules/other/component.js'),
|
||||||
|
contents: `
|
||||||
|
import {Component} from '@angular/core';
|
||||||
|
export class ImportedComponent {}
|
||||||
|
ImportedComponent.decorators = [{type: Component}];
|
||||||
|
`,
|
||||||
|
isRoot: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: _('/node_modules/other/component.d.ts'),
|
||||||
|
contents: `
|
||||||
|
import {Component} from '@angular/core';
|
||||||
|
export class ImportedComponent {}`
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
setUpAndAnalyzeProgram(EXTERNAL_COMPONENT_PROGRAM);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should ignore classes from an externally imported file', () => {
|
||||||
|
const file = program.getSourceFile(_('/node_modules/other/component.js')) !;
|
||||||
|
expect(result.has(file)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -32,7 +32,7 @@ runInEachFileSystem(() => {
|
||||||
|
|
||||||
const TEST_PROGRAM: TestFile[] = [
|
const TEST_PROGRAM: TestFile[] = [
|
||||||
{
|
{
|
||||||
name: _('/src/entry-point.js'),
|
name: _('/node_modules/test-package/src/entry-point.js'),
|
||||||
contents: `
|
contents: `
|
||||||
export * from './explicit';
|
export * from './explicit';
|
||||||
export * from './any';
|
export * from './any';
|
||||||
|
@ -42,7 +42,7 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/src/explicit.js'),
|
name: _('/node_modules/test-package/src/explicit.js'),
|
||||||
contents: `
|
contents: `
|
||||||
import {ExternalModule} from './module';
|
import {ExternalModule} from './module';
|
||||||
import {LibraryModule} from 'some-library';
|
import {LibraryModule} from 'some-library';
|
||||||
|
@ -88,7 +88,7 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/src/any.js'),
|
name: _('/node_modules/test-package/src/any.js'),
|
||||||
contents: `
|
contents: `
|
||||||
import {ExternalModule} from './module';
|
import {ExternalModule} from './module';
|
||||||
import {LibraryModule} from 'some-library';
|
import {LibraryModule} from 'some-library';
|
||||||
|
@ -134,7 +134,7 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/src/implicit.js'),
|
name: _('/node_modules/test-package/src/implicit.js'),
|
||||||
contents: `
|
contents: `
|
||||||
import {ExternalModule} from './module';
|
import {ExternalModule} from './module';
|
||||||
import {LibraryModule} from 'some-library';
|
import {LibraryModule} from 'some-library';
|
||||||
|
@ -180,7 +180,7 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/src/no-providers.js'),
|
name: _('/node_modules/test-package/src/no-providers.js'),
|
||||||
contents: `
|
contents: `
|
||||||
import {ExternalModule} from './module';
|
import {ExternalModule} from './module';
|
||||||
import {LibraryModule} from 'some-library';
|
import {LibraryModule} from 'some-library';
|
||||||
|
@ -215,7 +215,7 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/src/module.js'),
|
name: _('/node_modules/test-package/src/module.js'),
|
||||||
contents: `
|
contents: `
|
||||||
export class ExternalModule {}
|
export class ExternalModule {}
|
||||||
`
|
`
|
||||||
|
@ -227,7 +227,7 @@ runInEachFileSystem(() => {
|
||||||
];
|
];
|
||||||
const TEST_DTS_PROGRAM: TestFile[] = [
|
const TEST_DTS_PROGRAM: TestFile[] = [
|
||||||
{
|
{
|
||||||
name: _('/typings/entry-point.d.ts'),
|
name: _('/node_modules/test-package/typings/entry-point.d.ts'),
|
||||||
contents: `
|
contents: `
|
||||||
export * from './explicit';
|
export * from './explicit';
|
||||||
export * from './any';
|
export * from './any';
|
||||||
|
@ -237,7 +237,7 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/typings/explicit.d.ts'),
|
name: _('/node_modules/test-package/typings/explicit.d.ts'),
|
||||||
contents: `
|
contents: `
|
||||||
import {ModuleWithProviders} from './core';
|
import {ModuleWithProviders} from './core';
|
||||||
import {ExternalModule} from './module';
|
import {ExternalModule} from './module';
|
||||||
|
@ -254,7 +254,7 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/typings/any.d.ts'),
|
name: _('/node_modules/test-package/typings/any.d.ts'),
|
||||||
contents: `
|
contents: `
|
||||||
import {ModuleWithProviders} from './core';
|
import {ModuleWithProviders} from './core';
|
||||||
export declare class AnyInternalModule {}
|
export declare class AnyInternalModule {}
|
||||||
|
@ -269,7 +269,7 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/typings/implicit.d.ts'),
|
name: _('/node_modules/test-package/typings/implicit.d.ts'),
|
||||||
contents: `
|
contents: `
|
||||||
import {ExternalModule} from './module';
|
import {ExternalModule} from './module';
|
||||||
import {LibraryModule} from 'some-library';
|
import {LibraryModule} from 'some-library';
|
||||||
|
@ -285,7 +285,7 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/typings/no-providers.d.ts'),
|
name: _('/node_modules/test-package/typings/no-providers.d.ts'),
|
||||||
contents: `
|
contents: `
|
||||||
import {ModuleWithProviders} from './core';
|
import {ModuleWithProviders} from './core';
|
||||||
import {ExternalModule} from './module';
|
import {ExternalModule} from './module';
|
||||||
|
@ -303,13 +303,13 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/typings/module.d.ts'),
|
name: _('/node_modules/test-package/typings/module.d.ts'),
|
||||||
contents: `
|
contents: `
|
||||||
export declare class ExternalModule {}
|
export declare class ExternalModule {}
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/typings/core.d.ts'),
|
name: _('/node_modules/test-package/typings/core.d.ts'),
|
||||||
contents: `
|
contents: `
|
||||||
|
|
||||||
export declare interface Type<T> {
|
export declare interface Type<T> {
|
||||||
|
@ -343,11 +343,14 @@ runInEachFileSystem(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should ignore declarations that already have explicit NgModule type params', () => {
|
it('should ignore declarations that already have explicit NgModule type params', () => {
|
||||||
expect(getAnalysisDescription(analyses, _('/typings/explicit.d.ts'))).toEqual([]);
|
expect(
|
||||||
|
getAnalysisDescription(analyses, _('/node_modules/test-package/typings/explicit.d.ts')))
|
||||||
|
.toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should find declarations that use `any` for the NgModule type param', () => {
|
it('should find declarations that use `any` for the NgModule type param', () => {
|
||||||
const anyAnalysis = getAnalysisDescription(analyses, _('/typings/any.d.ts'));
|
const anyAnalysis =
|
||||||
|
getAnalysisDescription(analyses, _('/node_modules/test-package/typings/any.d.ts'));
|
||||||
expect(anyAnalysis).toContain(['anyInternalFunction', 'AnyInternalModule', null]);
|
expect(anyAnalysis).toContain(['anyInternalFunction', 'AnyInternalModule', null]);
|
||||||
expect(anyAnalysis).toContain(['anyExternalFunction', 'ExternalModule', null]);
|
expect(anyAnalysis).toContain(['anyExternalFunction', 'ExternalModule', null]);
|
||||||
expect(anyAnalysis).toContain(['anyLibraryFunction', 'LibraryModule', 'some-library']);
|
expect(anyAnalysis).toContain(['anyLibraryFunction', 'LibraryModule', 'some-library']);
|
||||||
|
@ -359,7 +362,8 @@ runInEachFileSystem(() => {
|
||||||
it('should track internal module references in the references registry', () => {
|
it('should track internal module references in the references registry', () => {
|
||||||
const declarations = referencesRegistry.getDeclarationMap();
|
const declarations = referencesRegistry.getDeclarationMap();
|
||||||
const externalModuleDeclaration = getDeclaration(
|
const externalModuleDeclaration = getDeclaration(
|
||||||
program, absoluteFrom('/src/module.js'), 'ExternalModule', ts.isClassDeclaration);
|
program, absoluteFrom('/node_modules/test-package/src/module.js'), 'ExternalModule',
|
||||||
|
ts.isClassDeclaration);
|
||||||
const libraryModuleDeclaration = getDeclaration(
|
const libraryModuleDeclaration = getDeclaration(
|
||||||
program, absoluteFrom('/node_modules/some-library/index.d.ts'), 'LibraryModule',
|
program, absoluteFrom('/node_modules/some-library/index.d.ts'), 'LibraryModule',
|
||||||
ts.isClassDeclaration);
|
ts.isClassDeclaration);
|
||||||
|
@ -368,7 +372,8 @@ runInEachFileSystem(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should find declarations that have implicit return types', () => {
|
it('should find declarations that have implicit return types', () => {
|
||||||
const anyAnalysis = getAnalysisDescription(analyses, _('/typings/implicit.d.ts'));
|
const anyAnalysis =
|
||||||
|
getAnalysisDescription(analyses, _('/node_modules/test-package/typings/implicit.d.ts'));
|
||||||
expect(anyAnalysis).toContain(['implicitInternalFunction', 'ImplicitInternalModule', null]);
|
expect(anyAnalysis).toContain(['implicitInternalFunction', 'ImplicitInternalModule', null]);
|
||||||
expect(anyAnalysis).toContain(['implicitExternalFunction', 'ExternalModule', null]);
|
expect(anyAnalysis).toContain(['implicitExternalFunction', 'ExternalModule', null]);
|
||||||
expect(anyAnalysis).toContain(['implicitLibraryFunction', 'LibraryModule', 'some-library']);
|
expect(anyAnalysis).toContain(['implicitLibraryFunction', 'LibraryModule', 'some-library']);
|
||||||
|
@ -379,7 +384,8 @@ runInEachFileSystem(() => {
|
||||||
|
|
||||||
it('should find declarations that do not specify a `providers` property in the return type',
|
it('should find declarations that do not specify a `providers` property in the return type',
|
||||||
() => {
|
() => {
|
||||||
const anyAnalysis = getAnalysisDescription(analyses, _('/typings/no-providers.d.ts'));
|
const anyAnalysis = getAnalysisDescription(
|
||||||
|
analyses, _('/node_modules/test-package/typings/no-providers.d.ts'));
|
||||||
expect(anyAnalysis).not.toContain([
|
expect(anyAnalysis).not.toContain([
|
||||||
'noProvExplicitInternalFunction', 'NoProvidersInternalModule'
|
'noProvExplicitInternalFunction', 'NoProvidersInternalModule'
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -27,7 +27,7 @@ runInEachFileSystem(() => {
|
||||||
|
|
||||||
const TEST_PROGRAM: TestFile[] = [
|
const TEST_PROGRAM: TestFile[] = [
|
||||||
{
|
{
|
||||||
name: _('/src/entry_point.js'),
|
name: _('/node_modules/test-package/src/entry_point.js'),
|
||||||
isRoot: true,
|
isRoot: true,
|
||||||
contents: `
|
contents: `
|
||||||
export {PublicComponent} from './a';
|
export {PublicComponent} from './a';
|
||||||
|
@ -36,7 +36,7 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/src/a.js'),
|
name: _('/node_modules/test-package/src/a.js'),
|
||||||
isRoot: false,
|
isRoot: false,
|
||||||
contents: `
|
contents: `
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
|
@ -47,7 +47,7 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/src/b.js'),
|
name: _('/node_modules/test-package/src/b.js'),
|
||||||
isRoot: false,
|
isRoot: false,
|
||||||
contents: `
|
contents: `
|
||||||
import {Component, NgModule} from '@angular/core';
|
import {Component, NgModule} from '@angular/core';
|
||||||
|
@ -66,7 +66,7 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/src/c.js'),
|
name: _('/node_modules/test-package/src/c.js'),
|
||||||
isRoot: false,
|
isRoot: false,
|
||||||
contents: `
|
contents: `
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
|
@ -81,7 +81,7 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/src/mod.js'),
|
name: _('/node_modules/test-package/src/mod.js'),
|
||||||
isRoot: false,
|
isRoot: false,
|
||||||
contents: `
|
contents: `
|
||||||
import {Component, NgModule} from '@angular/core';
|
import {Component, NgModule} from '@angular/core';
|
||||||
|
@ -100,7 +100,7 @@ runInEachFileSystem(() => {
|
||||||
];
|
];
|
||||||
const TEST_DTS_PROGRAM = [
|
const TEST_DTS_PROGRAM = [
|
||||||
{
|
{
|
||||||
name: _('/typings/entry_point.d.ts'),
|
name: _('/node_modules/test-package/typings/entry_point.d.ts'),
|
||||||
isRoot: true,
|
isRoot: true,
|
||||||
contents: `
|
contents: `
|
||||||
export {PublicComponent} from './a';
|
export {PublicComponent} from './a';
|
||||||
|
@ -109,28 +109,28 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/typings/a.d.ts'),
|
name: _('/node_modules/test-package/typings/a.d.ts'),
|
||||||
isRoot: false,
|
isRoot: false,
|
||||||
contents: `
|
contents: `
|
||||||
export declare class PublicComponent {}
|
export declare class PublicComponent {}
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/typings/b.d.ts'),
|
name: _('/node_modules/test-package/typings/b.d.ts'),
|
||||||
isRoot: false,
|
isRoot: false,
|
||||||
contents: `
|
contents: `
|
||||||
export declare class ModuleB {}
|
export declare class ModuleB {}
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/typings/c.d.ts'),
|
name: _('/node_modules/test-package/typings/c.d.ts'),
|
||||||
isRoot: false,
|
isRoot: false,
|
||||||
contents: `
|
contents: `
|
||||||
export declare class InternalComponent1 {}
|
export declare class InternalComponent1 {}
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/typings/mod.d.ts'),
|
name: _('/node_modules/test-package/typings/mod.d.ts'),
|
||||||
isRoot: false,
|
isRoot: false,
|
||||||
contents: `
|
contents: `
|
||||||
import {PublicComponent} from './a';
|
import {PublicComponent} from './a';
|
||||||
|
@ -142,22 +142,31 @@ runInEachFileSystem(() => {
|
||||||
];
|
];
|
||||||
const {program, referencesRegistry, analyzer} = setup(TEST_PROGRAM, TEST_DTS_PROGRAM);
|
const {program, referencesRegistry, analyzer} = setup(TEST_PROGRAM, TEST_DTS_PROGRAM);
|
||||||
|
|
||||||
addToReferencesRegistry(program, referencesRegistry, _('/src/a.js'), 'PublicComponent');
|
|
||||||
addToReferencesRegistry(
|
addToReferencesRegistry(
|
||||||
program, referencesRegistry, _('/src/b.js'), 'PrivateComponent1');
|
program, referencesRegistry, _('/node_modules/test-package/src/a.js'),
|
||||||
|
'PublicComponent');
|
||||||
addToReferencesRegistry(
|
addToReferencesRegistry(
|
||||||
program, referencesRegistry, _('/src/c.js'), 'InternalComponent1');
|
program, referencesRegistry, _('/node_modules/test-package/src/b.js'),
|
||||||
|
'PrivateComponent1');
|
||||||
|
addToReferencesRegistry(
|
||||||
|
program, referencesRegistry, _('/node_modules/test-package/src/c.js'),
|
||||||
|
'InternalComponent1');
|
||||||
|
|
||||||
const analyses = analyzer.analyzeProgram(program);
|
const analyses = analyzer.analyzeProgram(program);
|
||||||
// Note that `PrivateComponent2` and `InternalComponent2` are not found because they are
|
// Note that `PrivateComponent2` and `InternalComponent2` are not found because they are
|
||||||
// not added to the ReferencesRegistry (i.e. they were not declared in an NgModule).
|
// not added to the ReferencesRegistry (i.e. they were not declared in an NgModule).
|
||||||
expect(analyses.length).toEqual(2);
|
expect(analyses.length).toEqual(2);
|
||||||
expect(analyses).toEqual([
|
expect(analyses).toEqual([
|
||||||
{identifier: 'PrivateComponent1', from: _('/src/b.js'), dtsFrom: null, alias: null},
|
{
|
||||||
|
identifier: 'PrivateComponent1',
|
||||||
|
from: _('/node_modules/test-package/src/b.js'),
|
||||||
|
dtsFrom: null,
|
||||||
|
alias: null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
identifier: 'InternalComponent1',
|
identifier: 'InternalComponent1',
|
||||||
from: _('/src/c.js'),
|
from: _('/node_modules/test-package/src/c.js'),
|
||||||
dtsFrom: _('/typings/c.d.ts'),
|
dtsFrom: _('/node_modules/test-package/typings/c.d.ts'),
|
||||||
alias: null
|
alias: null
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
@ -167,7 +176,7 @@ runInEachFileSystem(() => {
|
||||||
const _ = absoluteFrom;
|
const _ = absoluteFrom;
|
||||||
const ALIASED_EXPORTS_PROGRAM = [
|
const ALIASED_EXPORTS_PROGRAM = [
|
||||||
{
|
{
|
||||||
name: _('/src/entry_point.js'),
|
name: _('/node_modules/test-package/src/entry_point.js'),
|
||||||
isRoot: true,
|
isRoot: true,
|
||||||
contents: `
|
contents: `
|
||||||
// This component is only exported as an alias.
|
// This component is only exported as an alias.
|
||||||
|
@ -177,7 +186,7 @@ runInEachFileSystem(() => {
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/src/a.js'),
|
name: _('/node_modules/test-package/src/a.js'),
|
||||||
isRoot: false,
|
isRoot: false,
|
||||||
contents: `
|
contents: `
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
|
@ -195,7 +204,7 @@ runInEachFileSystem(() => {
|
||||||
];
|
];
|
||||||
const ALIASED_EXPORTS_DTS_PROGRAM = [
|
const ALIASED_EXPORTS_DTS_PROGRAM = [
|
||||||
{
|
{
|
||||||
name: _('/typings/entry_point.d.ts'),
|
name: _('/node_modules/test-package/typings/entry_point.d.ts'),
|
||||||
isRoot: true,
|
isRoot: true,
|
||||||
contents: `
|
contents: `
|
||||||
export declare class aliasedComponentOne {}
|
export declare class aliasedComponentOne {}
|
||||||
|
@ -207,13 +216,15 @@ runInEachFileSystem(() => {
|
||||||
const {program, referencesRegistry, analyzer} =
|
const {program, referencesRegistry, analyzer} =
|
||||||
setup(ALIASED_EXPORTS_PROGRAM, ALIASED_EXPORTS_DTS_PROGRAM);
|
setup(ALIASED_EXPORTS_PROGRAM, ALIASED_EXPORTS_DTS_PROGRAM);
|
||||||
|
|
||||||
addToReferencesRegistry(program, referencesRegistry, _('/src/a.js'), 'ComponentOne');
|
addToReferencesRegistry(
|
||||||
addToReferencesRegistry(program, referencesRegistry, _('/src/a.js'), 'ComponentTwo');
|
program, referencesRegistry, _('/node_modules/test-package/src/a.js'), 'ComponentOne');
|
||||||
|
addToReferencesRegistry(
|
||||||
|
program, referencesRegistry, _('/node_modules/test-package/src/a.js'), 'ComponentTwo');
|
||||||
|
|
||||||
const analyses = analyzer.analyzeProgram(program);
|
const analyses = analyzer.analyzeProgram(program);
|
||||||
expect(analyses).toEqual([{
|
expect(analyses).toEqual([{
|
||||||
identifier: 'ComponentOne',
|
identifier: 'ComponentOne',
|
||||||
from: _('/src/a.js'),
|
from: _('/node_modules/test-package/src/a.js'),
|
||||||
dtsFrom: null,
|
dtsFrom: null,
|
||||||
alias: 'aliasedComponentOne',
|
alias: 'aliasedComponentOne',
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -11,54 +11,77 @@ import {loadTestFiles} from '../../../test/helpers';
|
||||||
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
|
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
|
||||||
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 {getRootFiles, makeTestBundleProgram} from '../helpers/utils';
|
import {makeTestEntryPointBundle} from '../helpers/utils';
|
||||||
|
|
||||||
runInEachFileSystem(() => {
|
runInEachFileSystem(() => {
|
||||||
describe('SwitchMarkerAnalyzer', () => {
|
describe('SwitchMarkerAnalyzer', () => {
|
||||||
describe('analyzeProgram()', () => {
|
|
||||||
it('should check for switchable markers in all the files of the program', () => {
|
let _: typeof absoluteFrom;
|
||||||
const _ = absoluteFrom;
|
let TEST_PROGRAM: TestFile[];
|
||||||
const TEST_PROGRAM: TestFile[] = [
|
|
||||||
|
beforeEach(() => {
|
||||||
|
_ = absoluteFrom;
|
||||||
|
TEST_PROGRAM = [
|
||||||
{
|
{
|
||||||
name: _('/entrypoint.js'),
|
name: _('/node_modules/test/entrypoint.js'),
|
||||||
contents: `
|
contents: `
|
||||||
import {a} from './a';
|
import {a} from './a';
|
||||||
import {b} from './b';
|
import {b} from './b';
|
||||||
|
import {x} from '../other/x';
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/a.js'),
|
name: _('/node_modules/test/a.js'),
|
||||||
contents: `
|
contents: `
|
||||||
import {c} from './c';
|
import {c} from './c';
|
||||||
export const a = 1;
|
export const a = 1;
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/b.js'),
|
name: _('/node_modules/test/b.js'),
|
||||||
contents: `
|
contents: `
|
||||||
export const b = 42;
|
export const b = 42;
|
||||||
var factoryB = factory__PRE_R3__;
|
var factoryB = factory__PRE_R3__;
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: _('/c.js'),
|
name: _('/node_modules/test/c.js'),
|
||||||
contents: `
|
contents: `
|
||||||
export const c = 'So long, and thanks for all the fish!';
|
export const c = 'So long, and thanks for all the fish!';
|
||||||
var factoryC = factory__PRE_R3__;
|
var factoryC = factory__PRE_R3__;
|
||||||
var factoryD = factory__PRE_R3__;
|
var factoryD = factory__PRE_R3__;
|
||||||
`
|
`
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: _('/node_modules/other/x.js'),
|
||||||
|
contents: `
|
||||||
|
export const x = 3.142;
|
||||||
|
var factoryX = factory__PRE_R3__;
|
||||||
|
`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: _('/node_modules/other/x.d.ts'),
|
||||||
|
contents: `
|
||||||
|
export const x: number;
|
||||||
|
`
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('analyzeProgram()', () => {
|
||||||
|
it('should check for switchable markers in all the files of the program', () => {
|
||||||
loadTestFiles(TEST_PROGRAM);
|
loadTestFiles(TEST_PROGRAM);
|
||||||
const {program} = makeTestBundleProgram(getRootFiles(TEST_PROGRAM)[0]);
|
const bundle = makeTestEntryPointBundle(
|
||||||
|
'test', 'esm2015', 'esm2015', false, [_('/node_modules/test/entrypoint.js')]);
|
||||||
|
const program = bundle.src.program;
|
||||||
const host = new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker());
|
const host = new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker());
|
||||||
const analyzer = new SwitchMarkerAnalyzer(host);
|
const analyzer = new SwitchMarkerAnalyzer(host, bundle.entryPoint.package);
|
||||||
const analysis = analyzer.analyzeProgram(program);
|
const analysis = analyzer.analyzeProgram(program);
|
||||||
|
|
||||||
const entrypoint = getSourceFileOrError(program, _('/entrypoint.js'));
|
const entrypoint = getSourceFileOrError(program, _('/node_modules/test/entrypoint.js'));
|
||||||
const a = getSourceFileOrError(program, _('/a.js'));
|
const a = getSourceFileOrError(program, _('/node_modules/test/a.js'));
|
||||||
const b = getSourceFileOrError(program, _('/b.js'));
|
const b = getSourceFileOrError(program, _('/node_modules/test/b.js'));
|
||||||
const c = getSourceFileOrError(program, _('/c.js'));
|
const c = getSourceFileOrError(program, _('/node_modules/test/c.js'));
|
||||||
|
|
||||||
expect(analysis.size).toEqual(2);
|
expect(analysis.size).toEqual(2);
|
||||||
expect(analysis.has(entrypoint)).toBe(false);
|
expect(analysis.has(entrypoint)).toBe(false);
|
||||||
|
@ -76,6 +99,19 @@ runInEachFileSystem(() => {
|
||||||
'factoryD = factory__PRE_R3__',
|
'factoryD = factory__PRE_R3__',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should ignore files that are outside the package', () => {
|
||||||
|
loadTestFiles(TEST_PROGRAM);
|
||||||
|
const bundle = makeTestEntryPointBundle(
|
||||||
|
'test', 'esm2015', 'esm2015', false, [_('/node_modules/test/entrypoint.js')]);
|
||||||
|
const program = bundle.src.program;
|
||||||
|
const host = new Esm2015ReflectionHost(new MockLogger(), false, program.getTypeChecker());
|
||||||
|
const analyzer = new SwitchMarkerAnalyzer(host, bundle.entryPoint.package);
|
||||||
|
const analysis = analyzer.analyzeProgram(program);
|
||||||
|
|
||||||
|
const x = getSourceFileOrError(program, _('/node_modules/other/x.js'));
|
||||||
|
expect(analysis.has(x)).toBe(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -0,0 +1,31 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
import * as ts from 'typescript';
|
||||||
|
import {absoluteFrom} from '../../../src/ngtsc/file_system';
|
||||||
|
import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
|
||||||
|
import {isWithinPackage} from '../../src/analysis/util';
|
||||||
|
|
||||||
|
runInEachFileSystem(() => {
|
||||||
|
describe('isWithinPackage', () => {
|
||||||
|
it('should return true if the source-file is contained in the package', () => {
|
||||||
|
const _ = absoluteFrom;
|
||||||
|
const file =
|
||||||
|
ts.createSourceFile(_('/node_modules/test/src/index.js'), '', ts.ScriptTarget.ES2015);
|
||||||
|
const packagePath = _('/node_modules/test');
|
||||||
|
expect(isWithinPackage(packagePath, file)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if the source-file is not contained in the package', () => {
|
||||||
|
const _ = absoluteFrom;
|
||||||
|
const file =
|
||||||
|
ts.createSourceFile(_('/node_modules/other/src/index.js'), '', ts.ScriptTarget.ES2015);
|
||||||
|
const packagePath = _('/node_modules/test');
|
||||||
|
expect(isWithinPackage(packagePath, file)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -5,6 +5,7 @@
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
import * as ts from 'typescript';
|
||||||
import {AbsoluteFsPath, NgtscCompilerHost, absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system';
|
import {AbsoluteFsPath, NgtscCompilerHost, absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system';
|
||||||
import {TestFile} from '../../../src/ngtsc/file_system/testing';
|
import {TestFile} from '../../../src/ngtsc/file_system/testing';
|
||||||
import {BundleProgram, makeBundleProgram} from '../../src/packages/bundle_program';
|
import {BundleProgram, makeBundleProgram} from '../../src/packages/bundle_program';
|
||||||
|
@ -49,8 +50,10 @@ export function makeTestEntryPointBundle(
|
||||||
export function makeTestBundleProgram(
|
export function makeTestBundleProgram(
|
||||||
path: AbsoluteFsPath, isCore: boolean = false): BundleProgram {
|
path: AbsoluteFsPath, isCore: boolean = false): BundleProgram {
|
||||||
const fs = getFileSystem();
|
const fs = getFileSystem();
|
||||||
const options = {allowJs: true, checkJs: false};
|
|
||||||
const entryPointPath = fs.dirname(path);
|
const entryPointPath = fs.dirname(path);
|
||||||
|
const rootDir = fs.dirname(entryPointPath);
|
||||||
|
const options: ts.CompilerOptions =
|
||||||
|
{allowJs: true, maxNodeModuleJsDepth: Infinity, checkJs: false, rootDir, rootDirs: [rootDir]};
|
||||||
const host = new NgccSourcesCompilerHost(fs, options, entryPointPath);
|
const host = new NgccSourcesCompilerHost(fs, options, entryPointPath);
|
||||||
return makeBundleProgram(fs, isCore, path, 'r3_symbols.js', options, host);
|
return makeBundleProgram(fs, isCore, path, 'r3_symbols.js', options, host);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ runInEachFileSystem(() => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
_ = absoluteFrom;
|
_ = absoluteFrom;
|
||||||
PROGRAM = {
|
PROGRAM = {
|
||||||
name: _('/some/file.js'),
|
name: _('/node_modules/test-package/some/file.js'),
|
||||||
contents: `
|
contents: `
|
||||||
/* A copyright notice */
|
/* A copyright notice */
|
||||||
require('some-side-effect');
|
require('some-side-effect');
|
||||||
|
@ -94,7 +94,7 @@ exports.BadIife = BadIife;`
|
||||||
};
|
};
|
||||||
|
|
||||||
PROGRAM_DECORATE_HELPER = {
|
PROGRAM_DECORATE_HELPER = {
|
||||||
name: _('/some/file.js'),
|
name: _('/node_modules/test-package/some/file.js'),
|
||||||
contents: `
|
contents: `
|
||||||
var tslib_1 = require("tslib");
|
var tslib_1 = require("tslib");
|
||||||
/* A copyright notice */
|
/* A copyright notice */
|
||||||
|
@ -156,8 +156,8 @@ exports.D = D;
|
||||||
const referencesRegistry = new NgccReferencesRegistry(host);
|
const referencesRegistry = new NgccReferencesRegistry(host);
|
||||||
const decorationAnalyses =
|
const decorationAnalyses =
|
||||||
new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram();
|
new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram();
|
||||||
const switchMarkerAnalyses =
|
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host, bundle.entryPoint.package)
|
||||||
new SwitchMarkerAnalyzer(host).analyzeProgram(bundle.src.program);
|
.analyzeProgram(bundle.src.program);
|
||||||
const renderer = new CommonJsRenderingFormatter(host, false);
|
const renderer = new CommonJsRenderingFormatter(host, false);
|
||||||
const importManager = new ImportManager(new NoopImportRewriter(), 'i');
|
const importManager = new ImportManager(new NoopImportRewriter(), 'i');
|
||||||
return {
|
return {
|
||||||
|
@ -197,9 +197,21 @@ var i1 = require('@angular/common');`);
|
||||||
renderer.addExports(
|
renderer.addExports(
|
||||||
output, _(PROGRAM.name.replace(/\.js$/, '')),
|
output, _(PROGRAM.name.replace(/\.js$/, '')),
|
||||||
[
|
[
|
||||||
{from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA1'},
|
{
|
||||||
{from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA2'},
|
from: _('/node_modules/test-package/some/a.js'),
|
||||||
{from: _('/some/foo/b.js'), dtsFrom: _('/some/foo/b.d.ts'), identifier: 'ComponentB'},
|
dtsFrom: _('/node_modules/test-package/some/a.d.ts'),
|
||||||
|
identifier: 'ComponentA1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: _('/node_modules/test-package/some/a.js'),
|
||||||
|
dtsFrom: _('/node_modules/test-package/some/a.d.ts'),
|
||||||
|
identifier: 'ComponentA2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: _('/node_modules/test-package/some/foo/b.js'),
|
||||||
|
dtsFrom: _('/node_modules/test-package/some/foo/b.d.ts'),
|
||||||
|
identifier: 'ComponentB'
|
||||||
|
},
|
||||||
{from: PROGRAM.name, dtsFrom: PROGRAM.name, identifier: 'TopLevelComponent'},
|
{from: PROGRAM.name, dtsFrom: PROGRAM.name, identifier: 'TopLevelComponent'},
|
||||||
],
|
],
|
||||||
importManager, sourceFile);
|
importManager, sourceFile);
|
||||||
|
@ -222,9 +234,21 @@ exports.TopLevelComponent = TopLevelComponent;`);
|
||||||
renderer.addExports(
|
renderer.addExports(
|
||||||
output, _(PROGRAM.name.replace(/\.js$/, '')),
|
output, _(PROGRAM.name.replace(/\.js$/, '')),
|
||||||
[
|
[
|
||||||
{from: _('/some/a.js'), alias: 'eComponentA1', identifier: 'ComponentA1'},
|
{
|
||||||
{from: _('/some/a.js'), alias: 'eComponentA2', identifier: 'ComponentA2'},
|
from: _('/node_modules/test-package/some/a.js'),
|
||||||
{from: _('/some/foo/b.js'), alias: 'eComponentB', identifier: 'ComponentB'},
|
alias: 'eComponentA1',
|
||||||
|
identifier: 'ComponentA1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: _('/node_modules/test-package/some/a.js'),
|
||||||
|
alias: 'eComponentA2',
|
||||||
|
identifier: 'ComponentA2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: _('/node_modules/test-package/some/foo/b.js'),
|
||||||
|
alias: 'eComponentB',
|
||||||
|
identifier: 'ComponentB'
|
||||||
|
},
|
||||||
{from: PROGRAM.name, alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'},
|
{from: PROGRAM.name, alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'},
|
||||||
],
|
],
|
||||||
importManager, sourceFile);
|
importManager, sourceFile);
|
||||||
|
@ -238,7 +262,7 @@ exports.TopLevelComponent = TopLevelComponent;`);
|
||||||
describe('addConstants', () => {
|
describe('addConstants', () => {
|
||||||
it('should insert the given constants after imports in the source file', () => {
|
it('should insert the given constants after imports in the source file', () => {
|
||||||
const {renderer, program} = setup(PROGRAM);
|
const {renderer, program} = setup(PROGRAM);
|
||||||
const file = getSourceFileOrError(program, _('/some/file.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js'));
|
||||||
const output = new MagicString(PROGRAM.contents);
|
const output = new MagicString(PROGRAM.contents);
|
||||||
renderer.addConstants(output, 'var x = 3;', file);
|
renderer.addConstants(output, 'var x = 3;', file);
|
||||||
expect(output.toString()).toContain(`
|
expect(output.toString()).toContain(`
|
||||||
|
@ -250,7 +274,7 @@ var A = (function() {`);
|
||||||
|
|
||||||
it('should insert constants after inserted imports', () => {
|
it('should insert constants after inserted imports', () => {
|
||||||
const {renderer, program} = setup(PROGRAM);
|
const {renderer, program} = setup(PROGRAM);
|
||||||
const file = getSourceFileOrError(program, _('/some/file.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js'));
|
||||||
const output = new MagicString(PROGRAM.contents);
|
const output = new MagicString(PROGRAM.contents);
|
||||||
renderer.addConstants(output, 'var x = 3;', file);
|
renderer.addConstants(output, 'var x = 3;', file);
|
||||||
renderer.addImports(output, [{specifier: '@angular/core', qualifier: 'i0'}], file);
|
renderer.addImports(output, [{specifier: '@angular/core', qualifier: 'i0'}], file);
|
||||||
|
@ -266,7 +290,7 @@ var A = (function() {`);
|
||||||
describe('rewriteSwitchableDeclarations', () => {
|
describe('rewriteSwitchableDeclarations', () => {
|
||||||
it('should switch marked declaration initializers', () => {
|
it('should switch marked declaration initializers', () => {
|
||||||
const {renderer, program, sourceFile, switchMarkerAnalyses} = setup(PROGRAM);
|
const {renderer, program, sourceFile, switchMarkerAnalyses} = setup(PROGRAM);
|
||||||
const file = getSourceFileOrError(program, _('/some/file.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js'));
|
||||||
const output = new MagicString(PROGRAM.contents);
|
const output = new MagicString(PROGRAM.contents);
|
||||||
renderer.rewriteSwitchableDeclarations(
|
renderer.rewriteSwitchableDeclarations(
|
||||||
output, file, switchMarkerAnalyses.get(sourceFile) !.declarations);
|
output, file, switchMarkerAnalyses.get(sourceFile) !.declarations);
|
||||||
|
@ -311,14 +335,14 @@ SOME DEFINITION TEXT
|
||||||
const mockNoIifeClass: any = {declaration: noIifeDeclaration, name: 'NoIife'};
|
const mockNoIifeClass: any = {declaration: noIifeDeclaration, name: 'NoIife'};
|
||||||
expect(() => renderer.addDefinitions(output, mockNoIifeClass, 'SOME DEFINITION TEXT'))
|
expect(() => renderer.addDefinitions(output, mockNoIifeClass, 'SOME DEFINITION TEXT'))
|
||||||
.toThrowError(
|
.toThrowError(
|
||||||
`Compiled class declaration is not inside an IIFE: NoIife in ${_('/some/file.js')}`);
|
`Compiled class declaration is not inside an IIFE: NoIife in ${_('/node_modules/test-package/some/file.js')}`);
|
||||||
|
|
||||||
const badIifeDeclaration = getDeclaration(
|
const badIifeDeclaration = getDeclaration(
|
||||||
program, absoluteFromSourceFile(sourceFile), 'BadIife', ts.isVariableDeclaration);
|
program, absoluteFromSourceFile(sourceFile), 'BadIife', ts.isVariableDeclaration);
|
||||||
const mockBadIifeClass: any = {declaration: badIifeDeclaration, name: 'BadIife'};
|
const mockBadIifeClass: any = {declaration: badIifeDeclaration, name: 'BadIife'};
|
||||||
expect(() => renderer.addDefinitions(output, mockBadIifeClass, 'SOME DEFINITION TEXT'))
|
expect(() => renderer.addDefinitions(output, mockBadIifeClass, 'SOME DEFINITION TEXT'))
|
||||||
.toThrowError(
|
.toThrowError(
|
||||||
`Compiled class wrapper IIFE does not have a return statement: BadIife in ${_('/some/file.js')}`);
|
`Compiled class wrapper IIFE does not have a return statement: BadIife in ${_('/node_modules/test-package/some/file.js')}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,7 @@ runInEachFileSystem(() => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
_ = absoluteFrom;
|
_ = absoluteFrom;
|
||||||
INPUT_PROGRAM = {
|
INPUT_PROGRAM = {
|
||||||
name: _('/src/file.js'),
|
name: _('/node_modules/test-package/src/file.js'),
|
||||||
contents:
|
contents:
|
||||||
`import { Directive } from '@angular/core';\nexport class A {\n foo(x) {\n return x;\n }\n}\nA.decorators = [\n { type: Directive, args: [{ selector: '[a]' }] }\n];\n`
|
`import { Directive } from '@angular/core';\nexport class A {\n foo(x) {\n return x;\n }\n}\nA.decorators = [\n { type: Directive, args: [{ selector: '[a]' }] }\n];\n`
|
||||||
};
|
};
|
||||||
|
@ -139,8 +139,11 @@ runInEachFileSystem(() => {
|
||||||
createTestRenderer('test-package', [INPUT_PROGRAM], [INPUT_DTS_PROGRAM]);
|
createTestRenderer('test-package', [INPUT_PROGRAM], [INPUT_DTS_PROGRAM]);
|
||||||
|
|
||||||
// Add a mock export to trigger export rendering
|
// Add a mock export to trigger export rendering
|
||||||
privateDeclarationsAnalyses.push(
|
privateDeclarationsAnalyses.push({
|
||||||
{identifier: 'ComponentB', from: _('/src/file.js'), dtsFrom: _('/typings/b.d.ts')});
|
identifier: 'ComponentB',
|
||||||
|
from: _('/node_modules/test-package/src/file.js'),
|
||||||
|
dtsFrom: _('/typings/b.d.ts')
|
||||||
|
});
|
||||||
|
|
||||||
const result = renderer.renderProgram(
|
const result = renderer.renderProgram(
|
||||||
decorationAnalyses, privateDeclarationsAnalyses, moduleWithProvidersAnalyses);
|
decorationAnalyses, privateDeclarationsAnalyses, moduleWithProvidersAnalyses);
|
||||||
|
|
|
@ -32,7 +32,8 @@ function setup(file: {name: AbsoluteFsPath, contents: string}) {
|
||||||
const referencesRegistry = new NgccReferencesRegistry(host);
|
const referencesRegistry = new NgccReferencesRegistry(host);
|
||||||
const decorationAnalyses =
|
const decorationAnalyses =
|
||||||
new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram();
|
new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram();
|
||||||
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(bundle.src.program);
|
const switchMarkerAnalyses =
|
||||||
|
new SwitchMarkerAnalyzer(host, bundle.entryPoint.package).analyzeProgram(bundle.src.program);
|
||||||
const renderer = new Esm5RenderingFormatter(host, false);
|
const renderer = new Esm5RenderingFormatter(host, false);
|
||||||
const importManager = new ImportManager(new NoopImportRewriter(), IMPORT_PREFIX);
|
const importManager = new ImportManager(new NoopImportRewriter(), IMPORT_PREFIX);
|
||||||
return {
|
return {
|
||||||
|
@ -52,7 +53,7 @@ runInEachFileSystem(() => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
_ = absoluteFrom;
|
_ = absoluteFrom;
|
||||||
PROGRAM = {
|
PROGRAM = {
|
||||||
name: _('/some/file.js'),
|
name: _('/node_modules/test-package/some/file.js'),
|
||||||
contents: `
|
contents: `
|
||||||
/* A copyright notice */
|
/* A copyright notice */
|
||||||
import 'some-side-effect';
|
import 'some-side-effect';
|
||||||
|
@ -112,7 +113,7 @@ export {A, B, C, NoIife, BadIife};`
|
||||||
};
|
};
|
||||||
|
|
||||||
PROGRAM_DECORATE_HELPER = {
|
PROGRAM_DECORATE_HELPER = {
|
||||||
name: _('/some/file.js'),
|
name: _('/node_modules/test-package/some/file.js'),
|
||||||
contents: `
|
contents: `
|
||||||
import * as tslib_1 from "tslib";
|
import * as tslib_1 from "tslib";
|
||||||
/* A copyright notice */
|
/* A copyright notice */
|
||||||
|
@ -189,9 +190,21 @@ import * as i1 from '@angular/common';`);
|
||||||
renderer.addExports(
|
renderer.addExports(
|
||||||
output, _(PROGRAM.name.replace(/\.js$/, '')),
|
output, _(PROGRAM.name.replace(/\.js$/, '')),
|
||||||
[
|
[
|
||||||
{from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA1'},
|
{
|
||||||
{from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA2'},
|
from: _('/node_modules/test-package/some/a.js'),
|
||||||
{from: _('/some/foo/b.js'), dtsFrom: _('/some/foo/b.d.ts'), identifier: 'ComponentB'},
|
dtsFrom: _('/node_modules/test-package/some/a.d.ts'),
|
||||||
|
identifier: 'ComponentA1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: _('/node_modules/test-package/some/a.js'),
|
||||||
|
dtsFrom: _('/node_modules/test-package/some/a.d.ts'),
|
||||||
|
identifier: 'ComponentA2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: _('/node_modules/test-package/some/foo/b.js'),
|
||||||
|
dtsFrom: _('/node_modules/test-package/some/foo/b.d.ts'),
|
||||||
|
identifier: 'ComponentB'
|
||||||
|
},
|
||||||
{from: PROGRAM.name, dtsFrom: PROGRAM.name, identifier: 'TopLevelComponent'},
|
{from: PROGRAM.name, dtsFrom: PROGRAM.name, identifier: 'TopLevelComponent'},
|
||||||
],
|
],
|
||||||
importManager, sourceFile);
|
importManager, sourceFile);
|
||||||
|
@ -209,9 +222,21 @@ export {TopLevelComponent};`);
|
||||||
renderer.addExports(
|
renderer.addExports(
|
||||||
output, _(PROGRAM.name.replace(/\.js$/, '')),
|
output, _(PROGRAM.name.replace(/\.js$/, '')),
|
||||||
[
|
[
|
||||||
{from: _('/some/a.js'), alias: 'eComponentA1', identifier: 'ComponentA1'},
|
{
|
||||||
{from: _('/some/a.js'), alias: 'eComponentA2', identifier: 'ComponentA2'},
|
from: _('/node_modules/test-package/some/a.js'),
|
||||||
{from: _('/some/foo/b.js'), alias: 'eComponentB', identifier: 'ComponentB'},
|
alias: 'eComponentA1',
|
||||||
|
identifier: 'ComponentA1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: _('/node_modules/test-package/some/a.js'),
|
||||||
|
alias: 'eComponentA2',
|
||||||
|
identifier: 'ComponentA2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: _('/node_modules/test-package/some/foo/b.js'),
|
||||||
|
alias: 'eComponentB',
|
||||||
|
identifier: 'ComponentB'
|
||||||
|
},
|
||||||
{from: PROGRAM.name, alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'},
|
{from: PROGRAM.name, alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'},
|
||||||
],
|
],
|
||||||
importManager, sourceFile);
|
importManager, sourceFile);
|
||||||
|
@ -225,7 +250,7 @@ export {TopLevelComponent};`);
|
||||||
describe('addConstants', () => {
|
describe('addConstants', () => {
|
||||||
it('should insert the given constants after imports in the source file', () => {
|
it('should insert the given constants after imports in the source file', () => {
|
||||||
const {renderer, program} = setup(PROGRAM);
|
const {renderer, program} = setup(PROGRAM);
|
||||||
const file = getSourceFileOrError(program, _('/some/file.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js'));
|
||||||
const output = new MagicString(PROGRAM.contents);
|
const output = new MagicString(PROGRAM.contents);
|
||||||
renderer.addConstants(output, 'var x = 3;', file);
|
renderer.addConstants(output, 'var x = 3;', file);
|
||||||
expect(output.toString()).toContain(`
|
expect(output.toString()).toContain(`
|
||||||
|
@ -237,7 +262,7 @@ var A = (function() {`);
|
||||||
|
|
||||||
it('should insert constants after inserted imports', () => {
|
it('should insert constants after inserted imports', () => {
|
||||||
const {renderer, program} = setup(PROGRAM);
|
const {renderer, program} = setup(PROGRAM);
|
||||||
const file = getSourceFileOrError(program, _('/some/file.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js'));
|
||||||
const output = new MagicString(PROGRAM.contents);
|
const output = new MagicString(PROGRAM.contents);
|
||||||
renderer.addConstants(output, 'var x = 3;', file);
|
renderer.addConstants(output, 'var x = 3;', file);
|
||||||
renderer.addImports(output, [{specifier: '@angular/core', qualifier: 'i0'}], file);
|
renderer.addImports(output, [{specifier: '@angular/core', qualifier: 'i0'}], file);
|
||||||
|
@ -253,7 +278,7 @@ var A = (function() {`);
|
||||||
describe('rewriteSwitchableDeclarations', () => {
|
describe('rewriteSwitchableDeclarations', () => {
|
||||||
it('should switch marked declaration initializers', () => {
|
it('should switch marked declaration initializers', () => {
|
||||||
const {renderer, program, sourceFile, switchMarkerAnalyses} = setup(PROGRAM);
|
const {renderer, program, sourceFile, switchMarkerAnalyses} = setup(PROGRAM);
|
||||||
const file = getSourceFileOrError(program, _('/some/file.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js'));
|
||||||
const output = new MagicString(PROGRAM.contents);
|
const output = new MagicString(PROGRAM.contents);
|
||||||
renderer.rewriteSwitchableDeclarations(
|
renderer.rewriteSwitchableDeclarations(
|
||||||
output, file, switchMarkerAnalyses.get(sourceFile) !.declarations);
|
output, file, switchMarkerAnalyses.get(sourceFile) !.declarations);
|
||||||
|
@ -298,14 +323,14 @@ SOME DEFINITION TEXT
|
||||||
const mockNoIifeClass: any = {declaration: noIifeDeclaration, name: 'NoIife'};
|
const mockNoIifeClass: any = {declaration: noIifeDeclaration, name: 'NoIife'};
|
||||||
expect(() => renderer.addDefinitions(output, mockNoIifeClass, 'SOME DEFINITION TEXT'))
|
expect(() => renderer.addDefinitions(output, mockNoIifeClass, 'SOME DEFINITION TEXT'))
|
||||||
.toThrowError(
|
.toThrowError(
|
||||||
`Compiled class declaration is not inside an IIFE: NoIife in ${_('/some/file.js')}`);
|
`Compiled class declaration is not inside an IIFE: NoIife in ${_('/node_modules/test-package/some/file.js')}`);
|
||||||
|
|
||||||
const badIifeDeclaration = getDeclaration(
|
const badIifeDeclaration = getDeclaration(
|
||||||
program, absoluteFromSourceFile(sourceFile), 'BadIife', ts.isVariableDeclaration);
|
program, absoluteFromSourceFile(sourceFile), 'BadIife', ts.isVariableDeclaration);
|
||||||
const mockBadIifeClass: any = {declaration: badIifeDeclaration, name: 'BadIife'};
|
const mockBadIifeClass: any = {declaration: badIifeDeclaration, name: 'BadIife'};
|
||||||
expect(() => renderer.addDefinitions(output, mockBadIifeClass, 'SOME DEFINITION TEXT'))
|
expect(() => renderer.addDefinitions(output, mockBadIifeClass, 'SOME DEFINITION TEXT'))
|
||||||
.toThrowError(
|
.toThrowError(
|
||||||
`Compiled class wrapper IIFE does not have a return statement: BadIife in ${_('/some/file.js')}`);
|
`Compiled class wrapper IIFE does not have a return statement: BadIife in ${_('/node_modules/test-package/some/file.js')}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import MagicString from 'magic-string';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {NoopImportRewriter} from '../../../src/ngtsc/imports';
|
import {NoopImportRewriter} from '../../../src/ngtsc/imports';
|
||||||
import {absoluteFrom, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system';
|
import {absoluteFrom, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system';
|
||||||
import {loadTestFiles} from '../../../test/helpers';
|
import {loadTestFiles, loadFakeCore} from '../../../test/helpers';
|
||||||
import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
|
import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
|
||||||
import {ImportManager} from '../../../src/ngtsc/translator';
|
import {ImportManager} from '../../../src/ngtsc/translator';
|
||||||
import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
|
import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
|
||||||
|
@ -23,11 +23,12 @@ import {MockLogger} from '../helpers/mock_logger';
|
||||||
import {ModuleWithProvidersAnalyzer} from '../../src/analysis/module_with_providers_analyzer';
|
import {ModuleWithProvidersAnalyzer} from '../../src/analysis/module_with_providers_analyzer';
|
||||||
|
|
||||||
function setup(files: TestFile[], dtsFiles?: TestFile[]) {
|
function setup(files: TestFile[], dtsFiles?: TestFile[]) {
|
||||||
|
const fs = getFileSystem();
|
||||||
|
loadFakeCore(fs);
|
||||||
loadTestFiles(files);
|
loadTestFiles(files);
|
||||||
if (dtsFiles) {
|
if (dtsFiles) {
|
||||||
loadTestFiles(dtsFiles);
|
loadTestFiles(dtsFiles);
|
||||||
}
|
}
|
||||||
const fs = getFileSystem();
|
|
||||||
const logger = new MockLogger();
|
const logger = new MockLogger();
|
||||||
const bundle = makeTestEntryPointBundle(
|
const bundle = makeTestEntryPointBundle(
|
||||||
'test-package', 'es2015', 'esm2015', false, getRootFiles(files),
|
'test-package', 'es2015', 'esm2015', false, getRootFiles(files),
|
||||||
|
@ -37,7 +38,8 @@ function setup(files: TestFile[], dtsFiles?: TestFile[]) {
|
||||||
const referencesRegistry = new NgccReferencesRegistry(host);
|
const referencesRegistry = new NgccReferencesRegistry(host);
|
||||||
const decorationAnalyses =
|
const decorationAnalyses =
|
||||||
new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram();
|
new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram();
|
||||||
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(bundle.src.program);
|
const switchMarkerAnalyses =
|
||||||
|
new SwitchMarkerAnalyzer(host, bundle.entryPoint.package).analyzeProgram(bundle.src.program);
|
||||||
const renderer = new EsmRenderingFormatter(host, false);
|
const renderer = new EsmRenderingFormatter(host, false);
|
||||||
const importManager = new ImportManager(new NoopImportRewriter(), IMPORT_PREFIX);
|
const importManager = new ImportManager(new NoopImportRewriter(), IMPORT_PREFIX);
|
||||||
return {
|
return {
|
||||||
|
@ -58,7 +60,7 @@ runInEachFileSystem(() => {
|
||||||
_ = absoluteFrom;
|
_ = absoluteFrom;
|
||||||
|
|
||||||
PROGRAM = {
|
PROGRAM = {
|
||||||
name: _('/some/file.js'),
|
name: _('/node_modules/test-package/some/file.js'),
|
||||||
contents: `
|
contents: `
|
||||||
/* A copyright notice */
|
/* A copyright notice */
|
||||||
import 'some-side-effect';
|
import 'some-side-effect';
|
||||||
|
@ -120,9 +122,21 @@ import * as i1 from '@angular/common';`);
|
||||||
renderer.addExports(
|
renderer.addExports(
|
||||||
output, _(PROGRAM.name.replace(/\.js$/, '')),
|
output, _(PROGRAM.name.replace(/\.js$/, '')),
|
||||||
[
|
[
|
||||||
{from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA1'},
|
{
|
||||||
{from: _('/some/a.js'), dtsFrom: _('/some/a.d.ts'), identifier: 'ComponentA2'},
|
from: _('/node_modules/test-package/some/a.js'),
|
||||||
{from: _('/some/foo/b.js'), dtsFrom: _('/some/foo/b.d.ts'), identifier: 'ComponentB'},
|
dtsFrom: _('/node_modules/test-package/some/a.d.ts'),
|
||||||
|
identifier: 'ComponentA1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: _('/node_modules/test-package/some/a.js'),
|
||||||
|
dtsFrom: _('/node_modules/test-package/some/a.d.ts'),
|
||||||
|
identifier: 'ComponentA2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: _('/node_modules/test-package/some/foo/b.js'),
|
||||||
|
dtsFrom: _('/node_modules/test-package/some/foo/b.d.ts'),
|
||||||
|
identifier: 'ComponentB'
|
||||||
|
},
|
||||||
{from: PROGRAM.name, dtsFrom: PROGRAM.name, identifier: 'TopLevelComponent'},
|
{from: PROGRAM.name, dtsFrom: PROGRAM.name, identifier: 'TopLevelComponent'},
|
||||||
],
|
],
|
||||||
importManager, sourceFile);
|
importManager, sourceFile);
|
||||||
|
@ -140,9 +154,21 @@ export {TopLevelComponent};`);
|
||||||
renderer.addExports(
|
renderer.addExports(
|
||||||
output, _(PROGRAM.name.replace(/\.js$/, '')),
|
output, _(PROGRAM.name.replace(/\.js$/, '')),
|
||||||
[
|
[
|
||||||
{from: _('/some/a.js'), alias: 'eComponentA1', identifier: 'ComponentA1'},
|
{
|
||||||
{from: _('/some/a.js'), alias: 'eComponentA2', identifier: 'ComponentA2'},
|
from: _('/node_modules/test-package/some/a.js'),
|
||||||
{from: _('/some/foo/b.js'), alias: 'eComponentB', identifier: 'ComponentB'},
|
alias: 'eComponentA1',
|
||||||
|
identifier: 'ComponentA1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: _('/node_modules/test-package/some/a.js'),
|
||||||
|
alias: 'eComponentA2',
|
||||||
|
identifier: 'ComponentA2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: _('/node_modules/test-package/some/foo/b.js'),
|
||||||
|
alias: 'eComponentB',
|
||||||
|
identifier: 'ComponentB'
|
||||||
|
},
|
||||||
{from: PROGRAM.name, alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'},
|
{from: PROGRAM.name, alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'},
|
||||||
],
|
],
|
||||||
importManager, sourceFile);
|
importManager, sourceFile);
|
||||||
|
@ -156,7 +182,7 @@ export {TopLevelComponent};`);
|
||||||
describe('addConstants', () => {
|
describe('addConstants', () => {
|
||||||
it('should insert the given constants after imports in the source file', () => {
|
it('should insert the given constants after imports in the source file', () => {
|
||||||
const {renderer, program} = setup([PROGRAM]);
|
const {renderer, program} = setup([PROGRAM]);
|
||||||
const file = getSourceFileOrError(program, _('/some/file.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js'));
|
||||||
const output = new MagicString(PROGRAM.contents);
|
const output = new MagicString(PROGRAM.contents);
|
||||||
renderer.addConstants(output, 'const x = 3;', file);
|
renderer.addConstants(output, 'const x = 3;', file);
|
||||||
expect(output.toString()).toContain(`
|
expect(output.toString()).toContain(`
|
||||||
|
@ -168,7 +194,7 @@ export class A {}`);
|
||||||
|
|
||||||
it('should insert constants after inserted imports', () => {
|
it('should insert constants after inserted imports', () => {
|
||||||
const {renderer, program} = setup([PROGRAM]);
|
const {renderer, program} = setup([PROGRAM]);
|
||||||
const file = getSourceFileOrError(program, _('/some/file.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js'));
|
||||||
const output = new MagicString(PROGRAM.contents);
|
const output = new MagicString(PROGRAM.contents);
|
||||||
renderer.addConstants(output, 'const x = 3;', file);
|
renderer.addConstants(output, 'const x = 3;', file);
|
||||||
renderer.addImports(output, [{specifier: '@angular/core', qualifier: 'i0'}], file);
|
renderer.addImports(output, [{specifier: '@angular/core', qualifier: 'i0'}], file);
|
||||||
|
@ -184,7 +210,7 @@ export class A {`);
|
||||||
describe('rewriteSwitchableDeclarations', () => {
|
describe('rewriteSwitchableDeclarations', () => {
|
||||||
it('should switch marked declaration initializers', () => {
|
it('should switch marked declaration initializers', () => {
|
||||||
const {renderer, program, switchMarkerAnalyses, sourceFile} = setup([PROGRAM]);
|
const {renderer, program, switchMarkerAnalyses, sourceFile} = setup([PROGRAM]);
|
||||||
const file = getSourceFileOrError(program, _('/some/file.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js'));
|
||||||
const output = new MagicString(PROGRAM.contents);
|
const output = new MagicString(PROGRAM.contents);
|
||||||
renderer.rewriteSwitchableDeclarations(
|
renderer.rewriteSwitchableDeclarations(
|
||||||
output, file, switchMarkerAnalyses.get(sourceFile) !.declarations);
|
output, file, switchMarkerAnalyses.get(sourceFile) !.declarations);
|
||||||
|
@ -292,7 +318,7 @@ A.decorators = [
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
PROGRAM_DECORATE_HELPER = {
|
PROGRAM_DECORATE_HELPER = {
|
||||||
name: _('/some/file.js'),
|
name: _('/node_modules/test-package/some/file.js'),
|
||||||
contents: `
|
contents: `
|
||||||
import * as tslib_1 from "tslib";
|
import * as tslib_1 from "tslib";
|
||||||
var D_1;
|
var D_1;
|
||||||
|
|
|
@ -69,7 +69,8 @@ function createTestRenderer(
|
||||||
const referencesRegistry = new NgccReferencesRegistry(host);
|
const referencesRegistry = new NgccReferencesRegistry(host);
|
||||||
const decorationAnalyses =
|
const decorationAnalyses =
|
||||||
new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram();
|
new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram();
|
||||||
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(bundle.src.program);
|
const switchMarkerAnalyses =
|
||||||
|
new SwitchMarkerAnalyzer(host, bundle.entryPoint.package).analyzeProgram(bundle.src.program);
|
||||||
const privateDeclarationsAnalyses =
|
const privateDeclarationsAnalyses =
|
||||||
new PrivateDeclarationsAnalyzer(host, referencesRegistry).analyzeProgram(bundle.src.program);
|
new PrivateDeclarationsAnalyzer(host, referencesRegistry).analyzeProgram(bundle.src.program);
|
||||||
const testFormatter = new TestRenderingFormatter();
|
const testFormatter = new TestRenderingFormatter();
|
||||||
|
@ -105,22 +106,22 @@ runInEachFileSystem(() => {
|
||||||
_ = absoluteFrom;
|
_ = absoluteFrom;
|
||||||
|
|
||||||
INPUT_PROGRAM = {
|
INPUT_PROGRAM = {
|
||||||
name: _('/src/file.js'),
|
name: _('/node_modules/test-package/src/file.js'),
|
||||||
contents:
|
contents:
|
||||||
`import { Directive } from '@angular/core';\nexport class A {\n foo(x) {\n return x;\n }\n}\nA.decorators = [\n { type: Directive, args: [{ selector: '[a]' }] }\n];\n`
|
`import { Directive } from '@angular/core';\nexport class A {\n foo(x) {\n return x;\n }\n}\nA.decorators = [\n { type: Directive, args: [{ selector: '[a]' }] }\n];\n`
|
||||||
};
|
};
|
||||||
|
|
||||||
COMPONENT_PROGRAM = {
|
COMPONENT_PROGRAM = {
|
||||||
name: _('/src/component.js'),
|
name: _('/node_modules/test-package/src/component.js'),
|
||||||
contents:
|
contents:
|
||||||
`import { Component } from '@angular/core';\nexport class A {}\nA.decorators = [\n { type: Component, args: [{ selector: 'a', template: '{{ person!.name }}' }] }\n];\n`
|
`import { Component } from '@angular/core';\nexport class A {}\nA.decorators = [\n { type: Component, args: [{ selector: 'a', template: '{{ person!.name }}' }] }\n];\n`
|
||||||
};
|
};
|
||||||
|
|
||||||
INPUT_PROGRAM_MAP = fromObject({
|
INPUT_PROGRAM_MAP = fromObject({
|
||||||
'version': 3,
|
'version': 3,
|
||||||
'file': _('/src/file.js'),
|
'file': _('/node_modules/test-package/src/file.js'),
|
||||||
'sourceRoot': '',
|
'sourceRoot': '',
|
||||||
'sources': [_('/src/file.ts')],
|
'sources': [_('/node_modules/test-package/src/file.ts')],
|
||||||
'names': [],
|
'names': [],
|
||||||
'mappings':
|
'mappings':
|
||||||
'AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,MAAM;IACF,GAAG,CAAC,CAAS;QACT,OAAO,CAAC,CAAC;IACb,CAAC;;AACM,YAAU,GAAG;IAChB,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE;CACnD,CAAC',
|
'AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,MAAM;IACF,GAAG,CAAC,CAAS;QACT,OAAO,CAAC,CAAC;IACb,CAAC;;AACM,YAAU,GAAG;IAChB,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE;CACnD,CAAC',
|
||||||
|
@ -142,7 +143,7 @@ runInEachFileSystem(() => {
|
||||||
OUTPUT_PROGRAM_MAP = fromObject({
|
OUTPUT_PROGRAM_MAP = fromObject({
|
||||||
'version': 3,
|
'version': 3,
|
||||||
'file': 'file.js',
|
'file': 'file.js',
|
||||||
'sources': [_('/src/file.js')],
|
'sources': [_('/node_modules/test-package/src/file.js')],
|
||||||
'sourcesContent': [INPUT_PROGRAM.contents],
|
'sourcesContent': [INPUT_PROGRAM.contents],
|
||||||
'names': [],
|
'names': [],
|
||||||
'mappings': ';;;;;;;;;;AAAA;;;;;;;;;'
|
'mappings': ';;;;;;;;;;AAAA;;;;;;;;;'
|
||||||
|
@ -150,7 +151,7 @@ runInEachFileSystem(() => {
|
||||||
|
|
||||||
MERGED_OUTPUT_PROGRAM_MAP = fromObject({
|
MERGED_OUTPUT_PROGRAM_MAP = fromObject({
|
||||||
'version': 3,
|
'version': 3,
|
||||||
'sources': [_('/src/file.ts')],
|
'sources': [_('/node_modules/test-package/src/file.ts')],
|
||||||
'names': [],
|
'names': [],
|
||||||
'mappings': ';;;;;;;;;;AAAA',
|
'mappings': ';;;;;;;;;;AAAA',
|
||||||
'file': 'file.js',
|
'file': 'file.js',
|
||||||
|
@ -165,10 +166,10 @@ runInEachFileSystem(() => {
|
||||||
createTestRenderer('test-package', [INPUT_PROGRAM]);
|
createTestRenderer('test-package', [INPUT_PROGRAM]);
|
||||||
const result = renderer.renderProgram(
|
const result = renderer.renderProgram(
|
||||||
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
|
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
|
||||||
expect(result[0].path).toEqual(_('/src/file.js'));
|
expect(result[0].path).toEqual(_('/node_modules/test-package/src/file.js'));
|
||||||
expect(result[0].contents)
|
expect(result[0].contents)
|
||||||
.toEqual(RENDERED_CONTENTS + '\n' + generateMapFileComment('file.js.map'));
|
.toEqual(RENDERED_CONTENTS + '\n' + generateMapFileComment('file.js.map'));
|
||||||
expect(result[1].path).toEqual(_('/src/file.js.map'));
|
expect(result[1].path).toEqual(_('/node_modules/test-package/src/file.js.map'));
|
||||||
expect(result[1].contents).toEqual(OUTPUT_PROGRAM_MAP.toJSON());
|
expect(result[1].contents).toEqual(OUTPUT_PROGRAM_MAP.toJSON());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -254,8 +255,9 @@ runInEachFileSystem(() => {
|
||||||
|
|
||||||
it('should render classes without decorators if handler matches', () => {
|
it('should render classes without decorators if handler matches', () => {
|
||||||
const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses,
|
const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses,
|
||||||
testFormatter} = createTestRenderer('test-package', [{
|
testFormatter} =
|
||||||
name: _('/src/file.js'),
|
createTestRenderer('test-package', [{
|
||||||
|
name: _('/node_modules/test-package/src/file.js'),
|
||||||
contents: `
|
contents: `
|
||||||
import { Directive, ViewChild } from '@angular/core';
|
import { Directive, ViewChild } from '@angular/core';
|
||||||
|
|
||||||
|
@ -312,7 +314,7 @@ runInEachFileSystem(() => {
|
||||||
}]);
|
}]);
|
||||||
const result = renderer.renderProgram(
|
const result = renderer.renderProgram(
|
||||||
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
|
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
|
||||||
expect(result[0].path).toEqual(_('/src/file.js'));
|
expect(result[0].path).toEqual(_('/node_modules/test-package/src/file.js'));
|
||||||
expect(result[0].contents)
|
expect(result[0].contents)
|
||||||
.toEqual(RENDERED_CONTENTS + '\n' + MERGED_OUTPUT_PROGRAM_MAP.toComment());
|
.toEqual(RENDERED_CONTENTS + '\n' + MERGED_OUTPUT_PROGRAM_MAP.toComment());
|
||||||
expect(result[1]).toBeUndefined();
|
expect(result[1]).toBeUndefined();
|
||||||
|
@ -331,10 +333,10 @@ runInEachFileSystem(() => {
|
||||||
createTestRenderer('test-package', sourceFiles, undefined, mappingFiles);
|
createTestRenderer('test-package', sourceFiles, undefined, mappingFiles);
|
||||||
const result = renderer.renderProgram(
|
const result = renderer.renderProgram(
|
||||||
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
|
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
|
||||||
expect(result[0].path).toEqual(_('/src/file.js'));
|
expect(result[0].path).toEqual(_('/node_modules/test-package/src/file.js'));
|
||||||
expect(result[0].contents)
|
expect(result[0].contents)
|
||||||
.toEqual(RENDERED_CONTENTS + '\n' + generateMapFileComment('file.js.map'));
|
.toEqual(RENDERED_CONTENTS + '\n' + generateMapFileComment('file.js.map'));
|
||||||
expect(result[1].path).toEqual(_('/src/file.js.map'));
|
expect(result[1].path).toEqual(_('/node_modules/test-package/src/file.js.map'));
|
||||||
expect(JSON.parse(result[1].contents)).toEqual(MERGED_OUTPUT_PROGRAM_MAP.toObject());
|
expect(JSON.parse(result[1].contents)).toEqual(MERGED_OUTPUT_PROGRAM_MAP.toObject());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -342,14 +344,14 @@ runInEachFileSystem(() => {
|
||||||
describe('@angular/core support', () => {
|
describe('@angular/core support', () => {
|
||||||
it('should render relative imports in ESM bundles', () => {
|
it('should render relative imports in ESM bundles', () => {
|
||||||
const CORE_FILE: TestFile = {
|
const CORE_FILE: TestFile = {
|
||||||
name: _('/src/core.js'),
|
name: _('/node_modules/test-package/src/core.js'),
|
||||||
contents:
|
contents:
|
||||||
`import { NgModule } from './ng_module';\nexport class MyModule {}\nMyModule.decorators = [\n { type: NgModule, args: [] }\n];\n`
|
`import { NgModule } from './ng_module';\nexport class MyModule {}\nMyModule.decorators = [\n { type: NgModule, args: [] }\n];\n`
|
||||||
};
|
};
|
||||||
const R3_SYMBOLS_FILE: TestFile = {
|
const R3_SYMBOLS_FILE: TestFile = {
|
||||||
// r3_symbols in the file name indicates that this is the path to rewrite core imports
|
// r3_symbols in the file name indicates that this is the path to rewrite core imports
|
||||||
// to
|
// to
|
||||||
name: _('/src/r3_symbols.js'),
|
name: _('/node_modules/test-package/src/r3_symbols.js'),
|
||||||
contents: `export const NgModule = () => null;`
|
contents: `export const NgModule = () => null;`
|
||||||
};
|
};
|
||||||
// The package name of `@angular/core` indicates that we are compiling the core library.
|
// The package name of `@angular/core` indicates that we are compiling the core library.
|
||||||
|
@ -368,7 +370,7 @@ runInEachFileSystem(() => {
|
||||||
|
|
||||||
it('should render no imports in FESM bundles', () => {
|
it('should render no imports in FESM bundles', () => {
|
||||||
const CORE_FILE: TestFile = {
|
const CORE_FILE: TestFile = {
|
||||||
name: _('/src/core.js'),
|
name: _('/node_modules/test-package/src/core.js'),
|
||||||
contents: `export const NgModule = () => null;
|
contents: `export const NgModule = () => null;
|
||||||
export class MyModule {}\nMyModule.decorators = [\n { type: NgModule, args: [] }\n];\n`
|
export class MyModule {}\nMyModule.decorators = [\n { type: NgModule, args: [] }\n];\n`
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,7 +31,8 @@ function setup(file: TestFile) {
|
||||||
const referencesRegistry = new NgccReferencesRegistry(host);
|
const referencesRegistry = new NgccReferencesRegistry(host);
|
||||||
const decorationAnalyses =
|
const decorationAnalyses =
|
||||||
new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram();
|
new DecorationAnalyzer(fs, bundle, host, referencesRegistry).analyzeProgram();
|
||||||
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(src.program);
|
const switchMarkerAnalyses =
|
||||||
|
new SwitchMarkerAnalyzer(host, bundle.entryPoint.package).analyzeProgram(src.program);
|
||||||
const renderer = new UmdRenderingFormatter(host, false);
|
const renderer = new UmdRenderingFormatter(host, false);
|
||||||
const importManager = new ImportManager(new NoopImportRewriter(), 'i');
|
const importManager = new ImportManager(new NoopImportRewriter(), 'i');
|
||||||
return {
|
return {
|
||||||
|
@ -54,7 +55,7 @@ runInEachFileSystem(() => {
|
||||||
_ = absoluteFrom;
|
_ = absoluteFrom;
|
||||||
|
|
||||||
PROGRAM = {
|
PROGRAM = {
|
||||||
name: _('/some/file.js'),
|
name: _('/node_modules/test-package/some/file.js'),
|
||||||
contents: `
|
contents: `
|
||||||
/* A copyright notice */
|
/* A copyright notice */
|
||||||
(function (global, factory) {
|
(function (global, factory) {
|
||||||
|
@ -123,7 +124,7 @@ exports.BadIife = BadIife;
|
||||||
|
|
||||||
|
|
||||||
PROGRAM_DECORATE_HELPER = {
|
PROGRAM_DECORATE_HELPER = {
|
||||||
name: _('/some/file.js'),
|
name: _('/node_modules/test-package/some/file.js'),
|
||||||
contents: `
|
contents: `
|
||||||
/* A copyright notice */
|
/* A copyright notice */
|
||||||
(function (global, factory) {
|
(function (global, factory) {
|
||||||
|
@ -181,7 +182,7 @@ typeof define === 'function' && define.amd ? define('file', ['exports','/tslib',
|
||||||
describe('addImports', () => {
|
describe('addImports', () => {
|
||||||
it('should append the given imports into the CommonJS factory call', () => {
|
it('should append the given imports into the CommonJS factory call', () => {
|
||||||
const {renderer, program} = setup(PROGRAM);
|
const {renderer, program} = setup(PROGRAM);
|
||||||
const file = getSourceFileOrError(program, _('/some/file.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js'));
|
||||||
const output = new MagicString(PROGRAM.contents);
|
const output = new MagicString(PROGRAM.contents);
|
||||||
renderer.addImports(
|
renderer.addImports(
|
||||||
output,
|
output,
|
||||||
|
@ -197,7 +198,7 @@ typeof define === 'function' && define.amd ? define('file', ['exports','/tslib',
|
||||||
|
|
||||||
it('should append the given imports into the AMD initialization', () => {
|
it('should append the given imports into the AMD initialization', () => {
|
||||||
const {renderer, program} = setup(PROGRAM);
|
const {renderer, program} = setup(PROGRAM);
|
||||||
const file = getSourceFileOrError(program, _('/some/file.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js'));
|
||||||
const output = new MagicString(PROGRAM.contents);
|
const output = new MagicString(PROGRAM.contents);
|
||||||
renderer.addImports(
|
renderer.addImports(
|
||||||
output,
|
output,
|
||||||
|
@ -213,7 +214,7 @@ typeof define === 'function' && define.amd ? define('file', ['exports','/tslib',
|
||||||
|
|
||||||
it('should append the given imports into the global initialization', () => {
|
it('should append the given imports into the global initialization', () => {
|
||||||
const {renderer, program} = setup(PROGRAM);
|
const {renderer, program} = setup(PROGRAM);
|
||||||
const file = getSourceFileOrError(program, _('/some/file.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js'));
|
||||||
const output = new MagicString(PROGRAM.contents);
|
const output = new MagicString(PROGRAM.contents);
|
||||||
renderer.addImports(
|
renderer.addImports(
|
||||||
output,
|
output,
|
||||||
|
@ -230,7 +231,7 @@ typeof define === 'function' && define.amd ? define('file', ['exports','/tslib',
|
||||||
it('should append the given imports as parameters into the factory function definition',
|
it('should append the given imports as parameters into the factory function definition',
|
||||||
() => {
|
() => {
|
||||||
const {renderer, program} = setup(PROGRAM);
|
const {renderer, program} = setup(PROGRAM);
|
||||||
const file = getSourceFileOrError(program, _('/some/file.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js'));
|
||||||
const output = new MagicString(PROGRAM.contents);
|
const output = new MagicString(PROGRAM.contents);
|
||||||
renderer.addImports(
|
renderer.addImports(
|
||||||
output,
|
output,
|
||||||
|
@ -253,9 +254,9 @@ typeof define === 'function' && define.amd ? define('file', ['exports','/tslib',
|
||||||
renderer.addExports(
|
renderer.addExports(
|
||||||
output, PROGRAM.name.replace(/\.js$/, ''),
|
output, PROGRAM.name.replace(/\.js$/, ''),
|
||||||
[
|
[
|
||||||
{from: _('/some/a.js'), identifier: 'ComponentA1'},
|
{from: _('/node_modules/test-package/some/a.js'), identifier: 'ComponentA1'},
|
||||||
{from: _('/some/a.js'), identifier: 'ComponentA2'},
|
{from: _('/node_modules/test-package/some/a.js'), identifier: 'ComponentA2'},
|
||||||
{from: _('/some/foo/b.js'), identifier: 'ComponentB'},
|
{from: _('/node_modules/test-package/some/foo/b.js'), identifier: 'ComponentB'},
|
||||||
{from: PROGRAM.name, identifier: 'TopLevelComponent'},
|
{from: PROGRAM.name, identifier: 'TopLevelComponent'},
|
||||||
],
|
],
|
||||||
importManager, sourceFile);
|
importManager, sourceFile);
|
||||||
|
@ -283,9 +284,21 @@ exports.TopLevelComponent = TopLevelComponent;
|
||||||
renderer.addExports(
|
renderer.addExports(
|
||||||
output, PROGRAM.name.replace(/\.js$/, ''),
|
output, PROGRAM.name.replace(/\.js$/, ''),
|
||||||
[
|
[
|
||||||
{from: _('/some/a.js'), alias: 'eComponentA1', identifier: 'ComponentA1'},
|
{
|
||||||
{from: _('/some/a.js'), alias: 'eComponentA2', identifier: 'ComponentA2'},
|
from: _('/node_modules/test-package/some/a.js'),
|
||||||
{from: _('/some/foo/b.js'), alias: 'eComponentB', identifier: 'ComponentB'},
|
alias: 'eComponentA1',
|
||||||
|
identifier: 'ComponentA1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: _('/node_modules/test-package/some/a.js'),
|
||||||
|
alias: 'eComponentA2',
|
||||||
|
identifier: 'ComponentA2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: _('/node_modules/test-package/some/foo/b.js'),
|
||||||
|
alias: 'eComponentB',
|
||||||
|
identifier: 'ComponentB'
|
||||||
|
},
|
||||||
{from: PROGRAM.name, alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'},
|
{from: PROGRAM.name, alias: 'eTopLevelComponent', identifier: 'TopLevelComponent'},
|
||||||
],
|
],
|
||||||
importManager, sourceFile);
|
importManager, sourceFile);
|
||||||
|
@ -299,7 +312,7 @@ exports.TopLevelComponent = TopLevelComponent;
|
||||||
describe('addConstants', () => {
|
describe('addConstants', () => {
|
||||||
it('should insert the given constants after imports in the source file', () => {
|
it('should insert the given constants after imports in the source file', () => {
|
||||||
const {renderer, program} = setup(PROGRAM);
|
const {renderer, program} = setup(PROGRAM);
|
||||||
const file = getSourceFileOrError(program, _('/some/file.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js'));
|
||||||
const output = new MagicString(PROGRAM.contents);
|
const output = new MagicString(PROGRAM.contents);
|
||||||
renderer.addConstants(output, 'var x = 3;', file);
|
renderer.addConstants(output, 'var x = 3;', file);
|
||||||
expect(output.toString()).toContain(`
|
expect(output.toString()).toContain(`
|
||||||
|
@ -319,7 +332,7 @@ var A = (function() {`);
|
||||||
describe('rewriteSwitchableDeclarations', () => {
|
describe('rewriteSwitchableDeclarations', () => {
|
||||||
it('should switch marked declaration initializers', () => {
|
it('should switch marked declaration initializers', () => {
|
||||||
const {renderer, program, sourceFile, switchMarkerAnalyses} = setup(PROGRAM);
|
const {renderer, program, sourceFile, switchMarkerAnalyses} = setup(PROGRAM);
|
||||||
const file = getSourceFileOrError(program, _('/some/file.js'));
|
const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js'));
|
||||||
const output = new MagicString(PROGRAM.contents);
|
const output = new MagicString(PROGRAM.contents);
|
||||||
renderer.rewriteSwitchableDeclarations(
|
renderer.rewriteSwitchableDeclarations(
|
||||||
output, file, switchMarkerAnalyses.get(sourceFile) !.declarations);
|
output, file, switchMarkerAnalyses.get(sourceFile) !.declarations);
|
||||||
|
@ -364,14 +377,14 @@ SOME DEFINITION TEXT
|
||||||
const mockNoIifeClass: any = {declaration: noIifeDeclaration, name: 'NoIife'};
|
const mockNoIifeClass: any = {declaration: noIifeDeclaration, name: 'NoIife'};
|
||||||
expect(() => renderer.addDefinitions(output, mockNoIifeClass, 'SOME DEFINITION TEXT'))
|
expect(() => renderer.addDefinitions(output, mockNoIifeClass, 'SOME DEFINITION TEXT'))
|
||||||
.toThrowError(
|
.toThrowError(
|
||||||
`Compiled class declaration is not inside an IIFE: NoIife in ${_('/some/file.js')}`);
|
`Compiled class declaration is not inside an IIFE: NoIife in ${_('/node_modules/test-package/some/file.js')}`);
|
||||||
|
|
||||||
const badIifeDeclaration = getDeclaration(
|
const badIifeDeclaration = getDeclaration(
|
||||||
program, absoluteFromSourceFile(sourceFile), 'BadIife', ts.isVariableDeclaration);
|
program, absoluteFromSourceFile(sourceFile), 'BadIife', ts.isVariableDeclaration);
|
||||||
const mockBadIifeClass: any = {declaration: badIifeDeclaration, name: 'BadIife'};
|
const mockBadIifeClass: any = {declaration: badIifeDeclaration, name: 'BadIife'};
|
||||||
expect(() => renderer.addDefinitions(output, mockBadIifeClass, 'SOME DEFINITION TEXT'))
|
expect(() => renderer.addDefinitions(output, mockBadIifeClass, 'SOME DEFINITION TEXT'))
|
||||||
.toThrowError(
|
.toThrowError(
|
||||||
`Compiled class wrapper IIFE does not have a return statement: BadIife in ${_('/some/file.js')}`);
|
`Compiled class wrapper IIFE does not have a return statement: BadIife in ${_('/node_modules/test-package/some/file.js')}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue