2018-07-16 08:54:16 +01:00
|
|
|
/**
|
|
|
|
* @license
|
2020-05-19 12:08:49 -07:00
|
|
|
* Copyright Google LLC All Rights Reserved.
|
2018-07-16 08:54:16 +01:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
2019-05-25 21:34:40 +01:00
|
|
|
import * as ts from 'typescript';
|
2019-10-14 13:04:42 -07:00
|
|
|
|
2020-04-06 08:30:08 +01:00
|
|
|
import {absoluteFrom, AbsoluteFsPath, getFileSystem, NgtscCompilerHost} from '../../../src/ngtsc/file_system';
|
2019-06-06 20:22:32 +01:00
|
|
|
import {TestFile} from '../../../src/ngtsc/file_system/testing';
|
refactor(ngcc): support processing only the typings files of packages (#40976)
Some tools (such as Language Server and ng-packagr) only care about
the processed typings generated by ngcc. Forcing these tools to process
the JavaScript files as well has two disadvantages:
First, unnecessary work is being done, which is time consuming.
But more importantly, it is not always possible to know how the final bundling
tools will want the processed JavaScript to be configured. For example,
the CLI would prefer the `--create-ivy-entry-points` option but this would
break non-CLI build tooling.
This commit adds a new option (`--typings-only` on the command line, and
`typingsOnly` via programmatic API) that instructs ngcc to only render changes
to the typings files for the entry-points that it finds, and not to write any
JavaScript files.
In order to process the typings, a JavaScript format will need to be analysed, but
it will not be rendered to disk. When using this option, it is best to offer ngcc a
wide range of possible JavaScript formats to choose from, and it will use the
first format that it finds. Ideally you would configure it to try the `ES2015` FESM
format first, since this will be the most performant.
Fixes #40969
PR Close #40976
2021-02-24 10:36:16 +00:00
|
|
|
import {DtsProcessing} from '../../src/execution/tasks/api';
|
2019-06-06 20:22:32 +01:00
|
|
|
import {BundleProgram, makeBundleProgram} from '../../src/packages/bundle_program';
|
2019-10-14 13:04:42 -07:00
|
|
|
import {NgccEntryPointConfig} from '../../src/packages/configuration';
|
2019-08-08 02:19:52 +03:00
|
|
|
import {EntryPoint, EntryPointFormat} from '../../src/packages/entry_point';
|
2018-11-25 21:40:25 +00:00
|
|
|
import {EntryPointBundle} from '../../src/packages/entry_point_bundle';
|
2019-06-06 20:22:32 +01:00
|
|
|
import {NgccSourcesCompilerHost} from '../../src/packages/ngcc_compiler_host';
|
2020-09-14 14:08:29 +02:00
|
|
|
import {createModuleResolutionCache, EntryPointFileCache, SharedFileCache} from '../../src/packages/source_file_cache';
|
2018-07-16 08:54:16 +01:00
|
|
|
|
2019-10-14 13:04:42 -07:00
|
|
|
export type TestConfig = Pick<NgccEntryPointConfig, 'generateDeepReexports'>;
|
|
|
|
|
2019-05-25 17:46:07 +01:00
|
|
|
export function makeTestEntryPoint(
|
2019-10-14 13:04:42 -07:00
|
|
|
entryPointName: string, packageName: string = entryPointName, config?: TestConfig): EntryPoint {
|
2019-05-25 17:46:07 +01:00
|
|
|
return {
|
|
|
|
name: entryPointName,
|
|
|
|
path: absoluteFrom(`/node_modules/${entryPointName}`),
|
2020-06-08 22:04:35 +03:00
|
|
|
packageName,
|
2020-06-08 22:04:28 +03:00
|
|
|
packagePath: absoluteFrom(`/node_modules/${packageName}`),
|
|
|
|
packageJson: {name: entryPointName},
|
2019-05-25 17:46:07 +01:00
|
|
|
typings: absoluteFrom(`/node_modules/${entryPointName}/index.d.ts`),
|
|
|
|
compiledByAngular: true,
|
2019-10-02 10:32:57 +03:00
|
|
|
ignoreMissingDependencies: false,
|
2019-10-14 13:04:42 -07:00
|
|
|
generateDeepReexports: config !== undefined ? !!config.generateDeepReexports : false,
|
2019-05-25 17:46:07 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-11-25 21:40:25 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param format The format of the bundle.
|
|
|
|
* @param files The source files to include in the bundle.
|
|
|
|
* @param dtsFiles The typings files to include the bundle.
|
|
|
|
*/
|
|
|
|
export function makeTestEntryPointBundle(
|
2019-08-08 02:19:52 +03:00
|
|
|
packageName: string, format: EntryPointFormat, isCore: boolean, srcRootNames: AbsoluteFsPath[],
|
2019-12-03 08:36:38 +00:00
|
|
|
dtsRootNames?: AbsoluteFsPath[], config?: TestConfig,
|
|
|
|
enableI18nLegacyMessageIdFormat = false): EntryPointBundle {
|
2019-10-14 13:04:42 -07:00
|
|
|
const entryPoint = makeTestEntryPoint(packageName, packageName, config);
|
2019-06-06 20:22:32 +01:00
|
|
|
const src = makeTestBundleProgram(srcRootNames[0], isCore);
|
2020-06-08 22:04:28 +03:00
|
|
|
const dts = dtsRootNames ?
|
|
|
|
makeTestDtsBundleProgram(dtsRootNames[0], entryPoint.packagePath, isCore) :
|
|
|
|
null;
|
2019-03-20 13:47:58 +00:00
|
|
|
const isFlatCore = isCore && src.r3SymbolsFile === null;
|
2019-12-03 08:36:38 +00:00
|
|
|
return {
|
|
|
|
entryPoint,
|
|
|
|
format,
|
2020-04-06 08:30:08 +01:00
|
|
|
rootDirs: [absoluteFrom('/')],
|
|
|
|
src,
|
|
|
|
dts,
|
refactor(ngcc): support processing only the typings files of packages (#40976)
Some tools (such as Language Server and ng-packagr) only care about
the processed typings generated by ngcc. Forcing these tools to process
the JavaScript files as well has two disadvantages:
First, unnecessary work is being done, which is time consuming.
But more importantly, it is not always possible to know how the final bundling
tools will want the processed JavaScript to be configured. For example,
the CLI would prefer the `--create-ivy-entry-points` option but this would
break non-CLI build tooling.
This commit adds a new option (`--typings-only` on the command line, and
`typingsOnly` via programmatic API) that instructs ngcc to only render changes
to the typings files for the entry-points that it finds, and not to write any
JavaScript files.
In order to process the typings, a JavaScript format will need to be analysed, but
it will not be rendered to disk. When using this option, it is best to offer ngcc a
wide range of possible JavaScript formats to choose from, and it will use the
first format that it finds. Ideally you would configure it to try the `ES2015` FESM
format first, since this will be the most performant.
Fixes #40969
PR Close #40976
2021-02-24 10:36:16 +00:00
|
|
|
dtsProcessing: dtsRootNames ? DtsProcessing.Yes : DtsProcessing.No,
|
2020-04-06 08:30:08 +01:00
|
|
|
isCore,
|
|
|
|
isFlatCore,
|
|
|
|
enableI18nLegacyMessageIdFormat
|
2019-12-03 08:36:38 +00:00
|
|
|
};
|
2018-12-17 16:17:38 -08:00
|
|
|
}
|
2018-11-25 21:40:25 +00:00
|
|
|
|
2019-06-06 20:22:32 +01:00
|
|
|
export function makeTestBundleProgram(
|
2019-08-13 17:02:44 -07:00
|
|
|
path: AbsoluteFsPath, isCore: boolean = false,
|
|
|
|
additionalFiles?: AbsoluteFsPath[]): BundleProgram {
|
2019-06-06 20:22:32 +01:00
|
|
|
const fs = getFileSystem();
|
|
|
|
const entryPointPath = fs.dirname(path);
|
2019-05-25 21:34:40 +01:00
|
|
|
const rootDir = fs.dirname(entryPointPath);
|
|
|
|
const options: ts.CompilerOptions =
|
|
|
|
{allowJs: true, maxNodeModuleJsDepth: Infinity, checkJs: false, rootDir, rootDirs: [rootDir]};
|
2020-09-14 14:08:29 +02:00
|
|
|
const moduleResolutionCache = createModuleResolutionCache(fs);
|
|
|
|
const entryPointFileCache = new EntryPointFileCache(fs, new SharedFileCache(fs));
|
|
|
|
const host =
|
|
|
|
new NgccSourcesCompilerHost(fs, options, entryPointFileCache, moduleResolutionCache, rootDir);
|
2019-08-13 17:02:44 -07:00
|
|
|
return makeBundleProgram(
|
|
|
|
fs, isCore, rootDir, path, 'r3_symbols.js', options, host, additionalFiles);
|
2018-07-16 08:54:16 +01:00
|
|
|
}
|
2018-10-01 11:10:55 +01:00
|
|
|
|
2019-06-06 20:22:32 +01:00
|
|
|
export function makeTestDtsBundleProgram(
|
2019-08-13 17:02:44 -07:00
|
|
|
path: AbsoluteFsPath, packagePath: AbsoluteFsPath, isCore: boolean = false): BundleProgram {
|
2019-06-06 20:22:32 +01:00
|
|
|
const fs = getFileSystem();
|
|
|
|
const options = {};
|
|
|
|
const host = new NgtscCompilerHost(fs, options);
|
2019-08-13 17:02:44 -07:00
|
|
|
return makeBundleProgram(fs, isCore, packagePath, path, 'r3_symbols.d.ts', options, host);
|
2018-09-30 20:53:25 +01:00
|
|
|
}
|
|
|
|
|
2019-06-06 20:22:32 +01:00
|
|
|
export function convertToDirectTsLibImport(filesystem: TestFile[]) {
|
2018-10-01 11:10:55 +01:00
|
|
|
return filesystem.map(file => {
|
|
|
|
const contents =
|
|
|
|
file.contents
|
|
|
|
.replace(
|
|
|
|
`import * as tslib_1 from 'tslib';`,
|
|
|
|
`import { __decorate, __metadata, __read, __values, __param, __extends, __assign } from 'tslib';`)
|
2018-09-30 20:53:25 +01:00
|
|
|
.replace(/tslib_1\./g, '');
|
2018-10-01 11:10:55 +01:00
|
|
|
return {...file, contents};
|
|
|
|
});
|
|
|
|
}
|
2019-04-28 20:47:57 +01:00
|
|
|
|
2019-07-19 23:22:52 +02:00
|
|
|
export function convertToInlineTsLib(filesystem: TestFile[], suffix: string = '') {
|
refactor(ivy): ngcc - categorize the various decorate calls upfront (#31614)
Any decorator information present in TypeScript is emitted into the
generated JavaScript sources by means of `__decorate` call. This call
contains both the decorators as they existed in the original source
code, together with calls to `tslib` helpers that convey additional
information on e.g. type information and parameter decorators. These
different kinds of decorator calls were not previously distinguished on
their own, but instead all treated as `Decorator` by themselves. The
"decorators" that were actually `tslib` helper calls were conveniently
filtered out because they were not imported from `@angular/core`, a
characteristic that ngcc uses to drop certain decorators.
Note that this posed an inconsistency in ngcc when it processes
`@angular/core`'s UMD bundle, as the `tslib` helper functions have been
inlined in said bundle. Because of the inlining, the `tslib` helpers
appear to be from `@angular/core`, so ngcc would fail to drop those
apparent "decorators". This inconsistency does not currently cause any
issues, as ngtsc is specifically looking for decorators based on their
name and any remaining decorators are simply ignored.
This commit rewrites the decorator analysis of a class to occur all in a
single phase, instead of all throughout the `ReflectionHost`. This
allows to categorize the various decorate calls in a single sweep,
instead of constantly needing to filter out undesired decorate calls on
the go. As an added benefit, the computed decorator information is now
cached per class, such that subsequent reflection queries that need
decorator information can reuse the cached info.
PR Close #31614
2019-07-19 23:17:22 +02:00
|
|
|
return filesystem.map(file => {
|
|
|
|
const contents = file.contents
|
|
|
|
.replace(`import * as tslib_1 from 'tslib';`, `
|
2019-07-19 23:22:52 +02:00
|
|
|
var __decorate${suffix} = null;
|
|
|
|
var __metadata${suffix} = null;
|
|
|
|
var __read${suffix} = null;
|
|
|
|
var __values${suffix} = null;
|
|
|
|
var __param${suffix} = null;
|
|
|
|
var __extends${suffix} = null;
|
|
|
|
var __assign${suffix} = null;
|
|
|
|
`).replace(/tslib_1\.([_a-z]+)/gi, '$1' + suffix.replace('$', '$$'));
|
refactor(ivy): ngcc - categorize the various decorate calls upfront (#31614)
Any decorator information present in TypeScript is emitted into the
generated JavaScript sources by means of `__decorate` call. This call
contains both the decorators as they existed in the original source
code, together with calls to `tslib` helpers that convey additional
information on e.g. type information and parameter decorators. These
different kinds of decorator calls were not previously distinguished on
their own, but instead all treated as `Decorator` by themselves. The
"decorators" that were actually `tslib` helper calls were conveniently
filtered out because they were not imported from `@angular/core`, a
characteristic that ngcc uses to drop certain decorators.
Note that this posed an inconsistency in ngcc when it processes
`@angular/core`'s UMD bundle, as the `tslib` helper functions have been
inlined in said bundle. Because of the inlining, the `tslib` helpers
appear to be from `@angular/core`, so ngcc would fail to drop those
apparent "decorators". This inconsistency does not currently cause any
issues, as ngtsc is specifically looking for decorators based on their
name and any remaining decorators are simply ignored.
This commit rewrites the decorator analysis of a class to occur all in a
single phase, instead of all throughout the `ReflectionHost`. This
allows to categorize the various decorate calls in a single sweep,
instead of constantly needing to filter out undesired decorate calls on
the go. As an added benefit, the computed decorator information is now
cached per class, such that subsequent reflection queries that need
decorator information can reuse the cached info.
PR Close #31614
2019-07-19 23:17:22 +02:00
|
|
|
return {...file, contents};
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-06-06 20:22:32 +01:00
|
|
|
export function getRootFiles(testFiles: TestFile[]): AbsoluteFsPath[] {
|
|
|
|
return testFiles.filter(f => f.isRoot !== false).map(f => absoluteFrom(f.name));
|
2019-04-28 20:47:57 +01:00
|
|
|
}
|