refactor(ivy): ngcc - remove flat-format and use AbsoluteFsPath (#29092)
Now that we are using package.json properties to indicate which entry-point format to compile, it turns out that we don't really need to distinguish between flat and non-flat formats, unless we are compiling `@angular/core`. PR Close #29092
This commit is contained in:

committed by
Matias Niemelä

parent
cd449021c1
commit
7b55ba58b9
@ -6,6 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AbsoluteFsPath} from '../../src/ngtsc/path';
|
||||
import {checkMarker, writeMarker} from './packages/build_marker';
|
||||
import {DependencyHost} from './packages/dependency_host';
|
||||
import {DependencyResolver} from './packages/dependency_resolver';
|
||||
@ -19,14 +20,12 @@ import {Transformer} from './packages/transformer';
|
||||
*/
|
||||
export interface NgccOptions {
|
||||
/** The path to the node_modules folder that contains the packages to compile. */
|
||||
baseSourcePath: string;
|
||||
/** The path to the node_modules folder where modified files should be written. */
|
||||
baseTargetPath?: string;
|
||||
baseSourcePath: AbsoluteFsPath;
|
||||
/**
|
||||
* The path, relative to `baseSourcePath` of the primary package to be compiled.
|
||||
* All its dependencies will need to be compiled too.
|
||||
*/
|
||||
targetEntryPointPath?: string;
|
||||
targetEntryPointPath?: AbsoluteFsPath;
|
||||
/**
|
||||
* Which entry-point properties in the package.json to consider when compiling.
|
||||
* Each of properties contain a path to particular bundle format for a given entry-point.
|
||||
@ -34,7 +33,7 @@ export interface NgccOptions {
|
||||
propertiesToConsider?: EntryPointJsonProperty[];
|
||||
}
|
||||
|
||||
const SUPPORTED_FORMATS: EntryPointFormat[] = ['esm5', 'esm2015', 'fesm5', 'fesm2015'];
|
||||
const SUPPORTED_FORMATS: EntryPointFormat[] = ['esm5', 'esm2015'];
|
||||
|
||||
/**
|
||||
* This is the main entry-point into ngcc (aNGular Compatibility Compiler).
|
||||
@ -44,9 +43,9 @@ const SUPPORTED_FORMATS: EntryPointFormat[] = ['esm5', 'esm2015', 'fesm5', 'fesm
|
||||
*
|
||||
* @param options The options telling ngcc what to compile and how.
|
||||
*/
|
||||
export function mainNgcc({baseSourcePath, baseTargetPath = baseSourcePath, targetEntryPointPath,
|
||||
propertiesToConsider}: NgccOptions): void {
|
||||
const transformer = new Transformer(baseSourcePath, baseTargetPath);
|
||||
export function mainNgcc({baseSourcePath, targetEntryPointPath, propertiesToConsider}: NgccOptions):
|
||||
void {
|
||||
const transformer = new Transformer(baseSourcePath, baseSourcePath);
|
||||
const host = new DependencyHost();
|
||||
const resolver = new DependencyResolver(host);
|
||||
const finder = new EntryPointFinder(resolver);
|
||||
@ -57,51 +56,50 @@ export function mainNgcc({baseSourcePath, baseTargetPath = baseSourcePath, targe
|
||||
// Are we compiling the Angular core?
|
||||
const isCore = entryPoint.name === '@angular/core';
|
||||
|
||||
let dtsTransformFormat: EntryPointFormat|undefined;
|
||||
|
||||
const propertiesToCompile =
|
||||
propertiesToConsider || Object.keys(entryPoint.packageJson) as EntryPointJsonProperty[];
|
||||
const compiledFormats = new Set<EntryPointFormat>();
|
||||
const compiledFormats = new Set<string>();
|
||||
|
||||
for (let i = 0; i < propertiesToCompile.length; i++) {
|
||||
const property = propertiesToCompile[i];
|
||||
const format = getEntryPointFormat(entryPoint.packageJson, property);
|
||||
const formatPath = entryPoint.packageJson[property];
|
||||
const format = getEntryPointFormat(property);
|
||||
|
||||
// No format then this property is not supposed to be compiled.
|
||||
if (!format || SUPPORTED_FORMATS.indexOf(format) === -1) continue;
|
||||
if (!formatPath || !format || SUPPORTED_FORMATS.indexOf(format) === -1) continue;
|
||||
|
||||
// We don't want to compile a format more than once.
|
||||
// This could happen if there are multiple properties that map to the same format...
|
||||
// E.g. `fesm5` and `module` both can point to the flat ESM5 format.
|
||||
if (!compiledFormats.has(format)) {
|
||||
compiledFormats.add(format);
|
||||
|
||||
// Use the first format found for typings transformation.
|
||||
dtsTransformFormat = dtsTransformFormat || format;
|
||||
|
||||
|
||||
if (checkMarker(entryPoint, property)) {
|
||||
const bundle =
|
||||
makeEntryPointBundle(entryPoint, isCore, format, format === dtsTransformFormat);
|
||||
if (bundle) {
|
||||
transformer.transform(entryPoint, isCore, bundle);
|
||||
} else {
|
||||
console.warn(
|
||||
`Skipping ${entryPoint.name} : ${format} (no entry point file for this format).`);
|
||||
}
|
||||
} else {
|
||||
console.warn(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
|
||||
}
|
||||
if (checkMarker(entryPoint, property)) {
|
||||
compiledFormats.add(formatPath);
|
||||
console.warn(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!compiledFormats.has(formatPath)) {
|
||||
const bundle = makeEntryPointBundle(
|
||||
entryPoint.path, formatPath, entryPoint.typings, isCore, format,
|
||||
compiledFormats.size === 0);
|
||||
if (bundle) {
|
||||
console.warn(`Compiling ${entryPoint.name} : ${property} as ${format}`);
|
||||
transformer.transform(entryPoint, isCore, bundle);
|
||||
compiledFormats.add(formatPath);
|
||||
} else {
|
||||
console.warn(
|
||||
`Skipping ${entryPoint.name} : ${format} (no valid entry point file for this format).`);
|
||||
}
|
||||
} else {
|
||||
console.warn(`Skipping ${entryPoint.name} : ${property} (already compiled).`);
|
||||
}
|
||||
|
||||
// Either this format was just compiled or its underlying format was compiled because of a
|
||||
// previous property.
|
||||
if (compiledFormats.has(formatPath)) {
|
||||
writeMarker(entryPoint, property);
|
||||
}
|
||||
// Write the built-with-ngcc marker.
|
||||
writeMarker(entryPoint, property);
|
||||
}
|
||||
|
||||
if (!dtsTransformFormat) {
|
||||
if (compiledFormats.size === 0) {
|
||||
throw new Error(
|
||||
`Failed to compile any formats for entry-point at (${entryPoint.path}). Tried ${propertiesToCompile}.`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export {NGCC_VERSION} from './packages/build_marker';
|
@ -10,6 +10,8 @@ import * as path from 'canonical-path';
|
||||
import * as fs from 'fs';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {AbsoluteFsPath, PathSegment} from '../../../src/ngtsc/path';
|
||||
|
||||
/**
|
||||
* Helper functions for computing dependencies.
|
||||
*/
|
||||
@ -17,7 +19,8 @@ export class DependencyHost {
|
||||
/**
|
||||
* Get a list of the resolved paths to all the dependencies of this entry point.
|
||||
* @param from An absolute path to the file whose dependencies we want to get.
|
||||
* @param resolved A set that will have the absolute paths of resolved entry points added to it.
|
||||
* @param dependencies A set that will have the absolute paths of resolved entry points added to
|
||||
* it.
|
||||
* @param missing A set that will have the dependencies that could not be found added to it.
|
||||
* @param deepImports A set that will have the import paths that exist but cannot be mapped to
|
||||
* entry-points, i.e. deep-imports.
|
||||
@ -25,11 +28,16 @@ export class DependencyHost {
|
||||
* circular dependency loop.
|
||||
*/
|
||||
computeDependencies(
|
||||
from: string, resolved: Set<string>, missing: Set<string>, deepImports: Set<string>,
|
||||
internal: Set<string> = new Set()): void {
|
||||
from: AbsoluteFsPath, dependencies: Set<AbsoluteFsPath> = new Set(),
|
||||
missing: Set<PathSegment> = new Set(), deepImports: Set<PathSegment> = new Set(),
|
||||
internal: Set<AbsoluteFsPath> = new Set()): {
|
||||
dependencies: Set<AbsoluteFsPath>,
|
||||
missing: Set<PathSegment>,
|
||||
deepImports: Set<PathSegment>
|
||||
} {
|
||||
const fromContents = fs.readFileSync(from, 'utf8');
|
||||
if (!this.hasImportOrReexportStatements(fromContents)) {
|
||||
return;
|
||||
return {dependencies, missing, deepImports};
|
||||
}
|
||||
|
||||
// Parse the source into a TypeScript AST and then walk it looking for imports and re-exports.
|
||||
@ -41,7 +49,7 @@ export class DependencyHost {
|
||||
// Grab the id of the module that is being imported
|
||||
.map(stmt => stmt.moduleSpecifier.text)
|
||||
// Resolve this module id into an absolute path
|
||||
.forEach(importPath => {
|
||||
.forEach((importPath: PathSegment) => {
|
||||
if (importPath.startsWith('.')) {
|
||||
// This is an internal import so follow it
|
||||
const internalDependency = this.resolveInternal(from, importPath);
|
||||
@ -49,12 +57,12 @@ export class DependencyHost {
|
||||
if (!internal.has(internalDependency)) {
|
||||
internal.add(internalDependency);
|
||||
this.computeDependencies(
|
||||
internalDependency, resolved, missing, deepImports, internal);
|
||||
internalDependency, dependencies, missing, deepImports, internal);
|
||||
}
|
||||
} else {
|
||||
const resolvedEntryPoint = this.tryResolveEntryPoint(from, importPath);
|
||||
if (resolvedEntryPoint !== null) {
|
||||
resolved.add(resolvedEntryPoint);
|
||||
dependencies.add(resolvedEntryPoint);
|
||||
} else {
|
||||
// If the import could not be resolved as entry point, it either does not exist
|
||||
// at all or is a deep import.
|
||||
@ -67,6 +75,7 @@ export class DependencyHost {
|
||||
}
|
||||
}
|
||||
});
|
||||
return {dependencies, missing, deepImports};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,11 +84,11 @@ export class DependencyHost {
|
||||
* @param to the module specifier of the internal dependency to resolve
|
||||
* @returns the resolved path to the import.
|
||||
*/
|
||||
resolveInternal(from: string, to: string): string {
|
||||
resolveInternal(from: AbsoluteFsPath, to: PathSegment): AbsoluteFsPath {
|
||||
const fromDirectory = path.dirname(from);
|
||||
// `fromDirectory` is absolute so we don't need to worry about telling `require.resolve`
|
||||
// about it - unlike `tryResolve` below.
|
||||
return require.resolve(path.resolve(fromDirectory, to));
|
||||
// about it by adding it to a `paths` parameter - unlike `tryResolve` below.
|
||||
return AbsoluteFsPath.from(require.resolve(path.resolve(fromDirectory, to)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,9 +108,9 @@ export class DependencyHost {
|
||||
* @returns the resolved path to the entry point directory of the import or null
|
||||
* if it cannot be resolved.
|
||||
*/
|
||||
tryResolveEntryPoint(from: string, to: string): string|null {
|
||||
const entryPoint = this.tryResolve(from, `${to}/package.json`);
|
||||
return entryPoint && path.dirname(entryPoint);
|
||||
tryResolveEntryPoint(from: AbsoluteFsPath, to: PathSegment): AbsoluteFsPath|null {
|
||||
const entryPoint = this.tryResolve(from, `${to}/package.json` as PathSegment);
|
||||
return entryPoint && AbsoluteFsPath.from(path.dirname(entryPoint));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -112,9 +121,9 @@ export class DependencyHost {
|
||||
* @returns an absolute path to the entry-point of the dependency or null if it could not be
|
||||
* resolved.
|
||||
*/
|
||||
tryResolve(from: string, to: string): string|null {
|
||||
tryResolve(from: AbsoluteFsPath, to: PathSegment): AbsoluteFsPath|null {
|
||||
try {
|
||||
return require.resolve(to, {paths: [from]});
|
||||
return AbsoluteFsPath.from(require.resolve(to, {paths: [from]}));
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
|
@ -6,9 +6,12 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {resolve} from 'canonical-path';
|
||||
import {DepGraph} from 'dependency-graph';
|
||||
|
||||
import {AbsoluteFsPath} from '../../../src/ngtsc/path';
|
||||
import {DependencyHost} from './dependency_host';
|
||||
import {EntryPoint} from './entry_point';
|
||||
import {EntryPoint, EntryPointJsonProperty, getEntryPointFormat} from './entry_point';
|
||||
|
||||
|
||||
/**
|
||||
@ -105,11 +108,8 @@ export class DependencyResolver {
|
||||
|
||||
// Now add the dependencies between them
|
||||
entryPoints.forEach(entryPoint => {
|
||||
const dependencies = new Set<string>();
|
||||
const missing = new Set<string>();
|
||||
const deepImports = new Set<string>();
|
||||
const entryPointPath = getEntryPointPath(entryPoint);
|
||||
this.host.computeDependencies(entryPointPath, dependencies, missing, deepImports);
|
||||
const {dependencies, missing, deepImports} = this.host.computeDependencies(entryPointPath);
|
||||
|
||||
if (missing.size > 0) {
|
||||
// This entry point has dependencies that are missing
|
||||
@ -152,12 +152,16 @@ export class DependencyResolver {
|
||||
}
|
||||
}
|
||||
|
||||
function getEntryPointPath(entryPoint: EntryPoint): string {
|
||||
const entryPointPath =
|
||||
entryPoint.fesm2015 || entryPoint.fesm5 || entryPoint.esm2015 || entryPoint.esm5;
|
||||
if (!entryPointPath) {
|
||||
throw new Error(
|
||||
`There is no format with import statements in '${entryPoint.path}' entry-point.`);
|
||||
function getEntryPointPath(entryPoint: EntryPoint): AbsoluteFsPath {
|
||||
const properties = Object.keys(entryPoint.packageJson);
|
||||
for (let i = 0; i < properties.length; i++) {
|
||||
const property = properties[i] as EntryPointJsonProperty;
|
||||
const format = getEntryPointFormat(property);
|
||||
|
||||
if (format === 'esm2015' || format === 'esm5') {
|
||||
const formatPath = entryPoint.packageJson[property] !;
|
||||
return AbsoluteFsPath.from(resolve(entryPoint.path, formatPath));
|
||||
}
|
||||
}
|
||||
return entryPointPath;
|
||||
throw new Error(`There is no format with import statements in '${entryPoint.path}' entry-point.`);
|
||||
}
|
||||
|
@ -8,40 +8,30 @@
|
||||
|
||||
import * as path from 'canonical-path';
|
||||
import * as fs from 'fs';
|
||||
import {isDefined} from '../utils';
|
||||
|
||||
import {AbsoluteFsPath} from '../../../src/ngtsc/path';
|
||||
|
||||
/**
|
||||
* An object containing paths to the entry-points for each format.
|
||||
*/
|
||||
export interface EntryPointPaths {
|
||||
esm5?: string;
|
||||
fesm5?: string;
|
||||
esm2015?: string;
|
||||
fesm2015?: string;
|
||||
umd?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The possible values for the format of an entry-point.
|
||||
*/
|
||||
export type EntryPointFormat = keyof(EntryPointPaths);
|
||||
export type EntryPointFormat = 'esm5' | 'esm2015' | 'umd';
|
||||
|
||||
/**
|
||||
* An object containing information about an entry-point, including paths
|
||||
* to each of the possible entry-point formats.
|
||||
*/
|
||||
export interface EntryPoint extends EntryPointPaths {
|
||||
export interface EntryPoint {
|
||||
/** The name of the package (e.g. `@angular/core`). */
|
||||
name: string;
|
||||
/** The parsed package.json file for this entry-point. */
|
||||
packageJson: EntryPointPackageJson;
|
||||
/** The path to the package that contains this entry-point. */
|
||||
package: string;
|
||||
package: AbsoluteFsPath;
|
||||
/** The path to this entry point. */
|
||||
path: string;
|
||||
path: AbsoluteFsPath;
|
||||
/** The path to a typings (.d.ts) file for this entry-point. */
|
||||
typings: string;
|
||||
typings: AbsoluteFsPath;
|
||||
}
|
||||
|
||||
interface PackageJsonFormatProperties {
|
||||
@ -73,7 +63,8 @@ export type EntryPointJsonProperty = keyof(PackageJsonFormatProperties);
|
||||
* @param entryPointPath the absolute path to the potential entry-point.
|
||||
* @returns An entry-point if it is valid, `null` otherwise.
|
||||
*/
|
||||
export function getEntryPointInfo(packagePath: string, entryPointPath: string): EntryPoint|null {
|
||||
export function getEntryPointInfo(
|
||||
packagePath: AbsoluteFsPath, entryPointPath: AbsoluteFsPath): EntryPoint|null {
|
||||
const packageJsonPath = path.resolve(entryPointPath, 'package.json');
|
||||
if (!fs.existsSync(packageJsonPath)) {
|
||||
return null;
|
||||
@ -98,48 +89,31 @@ export function getEntryPointInfo(packagePath: string, entryPointPath: string):
|
||||
return null;
|
||||
}
|
||||
|
||||
const formats = Object.keys(entryPointPackageJson)
|
||||
.map((property: EntryPointJsonProperty) => {
|
||||
const format = getEntryPointFormat(entryPointPackageJson, property);
|
||||
return format ? {property, format} : undefined;
|
||||
})
|
||||
.filter(isDefined);
|
||||
|
||||
const entryPointInfo: EntryPoint = {
|
||||
name: entryPointPackageJson.name,
|
||||
packageJson: entryPointPackageJson,
|
||||
package: packagePath,
|
||||
path: entryPointPath,
|
||||
typings: path.resolve(entryPointPath, typings)
|
||||
typings: AbsoluteFsPath.from(path.resolve(entryPointPath, typings)),
|
||||
};
|
||||
|
||||
// Add the formats to the entry-point info object.
|
||||
formats.forEach(
|
||||
item => entryPointInfo[item.format] =
|
||||
path.resolve(entryPointPath, entryPointPackageJson[item.property] !));
|
||||
|
||||
return entryPointInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a package.json property into an entry-point format.
|
||||
*
|
||||
* The actual format is dependent not only on the property itself but also
|
||||
* on what other properties exist in the package.json.
|
||||
*
|
||||
* @param entryPointProperties The package.json that contains the properties.
|
||||
* @param property The property to convert to a format.
|
||||
* @returns An entry-point format or `undefined` if none match the given property.
|
||||
*/
|
||||
export function getEntryPointFormat(
|
||||
entryPointProperties: EntryPointPackageJson, property: string): EntryPointFormat|undefined {
|
||||
export function getEntryPointFormat(property: string): EntryPointFormat|undefined {
|
||||
switch (property) {
|
||||
case 'fesm2015':
|
||||
return 'fesm2015';
|
||||
return 'esm2015';
|
||||
case 'fesm5':
|
||||
return 'fesm5';
|
||||
return 'esm5';
|
||||
case 'es2015':
|
||||
return !entryPointProperties.fesm2015 ? 'fesm2015' : 'esm2015';
|
||||
return 'esm2015';
|
||||
case 'esm2015':
|
||||
return 'esm2015';
|
||||
case 'esm5':
|
||||
@ -147,7 +121,7 @@ export function getEntryPointFormat(
|
||||
case 'main':
|
||||
return 'umd';
|
||||
case 'module':
|
||||
return !entryPointProperties.fesm5 ? 'fesm5' : 'esm5';
|
||||
return 'esm5';
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
@ -5,12 +5,12 @@
|
||||
* 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 {resolve} from 'canonical-path';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {AbsoluteFsPath} from '../../../src/ngtsc/path';
|
||||
|
||||
import {BundleProgram, makeBundleProgram} from './bundle_program';
|
||||
import {EntryPoint, EntryPointFormat} from './entry_point';
|
||||
import {EntryPointFormat} from './entry_point';
|
||||
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ import {EntryPoint, EntryPointFormat} from './entry_point';
|
||||
*/
|
||||
export interface EntryPointBundle {
|
||||
format: EntryPointFormat;
|
||||
isFlat: boolean;
|
||||
isFlatCore: boolean;
|
||||
rootDirs: AbsoluteFsPath[];
|
||||
src: BundleProgram;
|
||||
dts: BundleProgram|null;
|
||||
@ -28,34 +28,33 @@ export interface EntryPointBundle {
|
||||
|
||||
/**
|
||||
* Get an object that describes a formatted bundle for an entry-point.
|
||||
* @param entryPoint The entry-point that contains the bundle.
|
||||
* @param format The format of the bundle.
|
||||
* @param transformDts True if processing this bundle should also process its `.d.ts` files.
|
||||
* @param entryPointPath The path to the entry-point that contains the bundle.
|
||||
* @param formatPath The path to the source files for this bundle.
|
||||
* @param typingsPath The path to the typings files if we should transform them with this bundle.
|
||||
* @param isCore This entry point is the Angular core package.
|
||||
* @param format The underlying format of the bundle.
|
||||
* @param transformDts Whether to transform the typings along with this bundle.
|
||||
*/
|
||||
export function makeEntryPointBundle(
|
||||
entryPoint: EntryPoint, isCore: boolean, format: EntryPointFormat,
|
||||
transformDts: boolean): EntryPointBundle|null {
|
||||
// Bail out if the entry-point does not have this format.
|
||||
const path = entryPoint[format];
|
||||
if (!path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
entryPointPath: string, formatPath: string, typingsPath: string, isCore: boolean,
|
||||
format: EntryPointFormat, transformDts: boolean): EntryPointBundle|null {
|
||||
// Create the TS program and necessary helpers.
|
||||
const options: ts.CompilerOptions = {
|
||||
allowJs: true,
|
||||
maxNodeModuleJsDepth: Infinity,
|
||||
rootDir: entryPoint.path,
|
||||
rootDir: entryPointPath,
|
||||
};
|
||||
const host = ts.createCompilerHost(options);
|
||||
const rootDirs = [AbsoluteFsPath.from(entryPoint.path)];
|
||||
const rootDirs = [AbsoluteFsPath.from(entryPointPath)];
|
||||
|
||||
// Create the bundle programs, as necessary.
|
||||
const src = makeBundleProgram(isCore, path, 'r3_symbols.js', options, host);
|
||||
const src = makeBundleProgram(
|
||||
isCore, resolve(entryPointPath, formatPath), 'r3_symbols.js', options, host);
|
||||
const dts = transformDts ?
|
||||
makeBundleProgram(isCore, entryPoint.typings, 'r3_symbols.d.ts', options, host) :
|
||||
makeBundleProgram(
|
||||
isCore, resolve(entryPointPath, typingsPath), 'r3_symbols.d.ts', options, host) :
|
||||
null;
|
||||
const isFlat = src.r3SymbolsFile === null;
|
||||
const isFlatCore = isCore && src.r3SymbolsFile === null;
|
||||
|
||||
return {format, rootDirs, isFlat, src, dts};
|
||||
return {format, rootDirs, isFlatCore, src, dts};
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
import * as path from 'canonical-path';
|
||||
import * as fs from 'fs';
|
||||
|
||||
import {AbsoluteFsPath} from '../../../src/ngtsc/path';
|
||||
import {DependencyResolver, SortedEntryPointsInfo} from './dependency_resolver';
|
||||
import {EntryPoint, getEntryPointInfo} from './entry_point';
|
||||
|
||||
@ -18,10 +19,9 @@ export class EntryPointFinder {
|
||||
* Search the given directory, and sub-directories, for Angular package entry points.
|
||||
* @param sourceDirectory An absolute path to the directory to search for entry points.
|
||||
*/
|
||||
findEntryPoints(sourceDirectory: string, targetEntryPointPath?: string): SortedEntryPointsInfo {
|
||||
findEntryPoints(sourceDirectory: AbsoluteFsPath, targetEntryPointPath?: AbsoluteFsPath):
|
||||
SortedEntryPointsInfo {
|
||||
const unsortedEntryPoints = walkDirectoryForEntryPoints(sourceDirectory);
|
||||
targetEntryPointPath =
|
||||
targetEntryPointPath && path.resolve(sourceDirectory, targetEntryPointPath);
|
||||
const targetEntryPoint = targetEntryPointPath ?
|
||||
unsortedEntryPoints.find(entryPoint => entryPoint.path === targetEntryPointPath) :
|
||||
undefined;
|
||||
@ -34,7 +34,7 @@ export class EntryPointFinder {
|
||||
* The function will recurse into directories that start with `@...`, e.g. `@angular/...`.
|
||||
* @param sourceDirectory An absolute path to the root directory where searching begins.
|
||||
*/
|
||||
function walkDirectoryForEntryPoints(sourceDirectory: string): EntryPoint[] {
|
||||
function walkDirectoryForEntryPoints(sourceDirectory: AbsoluteFsPath): EntryPoint[] {
|
||||
const entryPoints: EntryPoint[] = [];
|
||||
fs.readdirSync(sourceDirectory)
|
||||
// Not interested in hidden files
|
||||
@ -49,14 +49,15 @@ function walkDirectoryForEntryPoints(sourceDirectory: string): EntryPoint[] {
|
||||
.forEach(p => {
|
||||
// Either the directory is a potential package or a namespace containing packages (e.g
|
||||
// `@angular`).
|
||||
const packagePath = path.join(sourceDirectory, p);
|
||||
const packagePath = AbsoluteFsPath.from(path.join(sourceDirectory, p));
|
||||
if (p.startsWith('@')) {
|
||||
entryPoints.push(...walkDirectoryForEntryPoints(packagePath));
|
||||
} else {
|
||||
entryPoints.push(...getEntryPointsForPackage(packagePath));
|
||||
|
||||
// Also check for any nested node_modules in this package
|
||||
const nestedNodeModulesPath = path.resolve(packagePath, 'node_modules');
|
||||
const nestedNodeModulesPath =
|
||||
AbsoluteFsPath.from(path.resolve(packagePath, 'node_modules'));
|
||||
if (fs.existsSync(nestedNodeModulesPath)) {
|
||||
entryPoints.push(...walkDirectoryForEntryPoints(nestedNodeModulesPath));
|
||||
}
|
||||
@ -70,7 +71,7 @@ function walkDirectoryForEntryPoints(sourceDirectory: string): EntryPoint[] {
|
||||
* @param packagePath The absolute path to an npm package that may contain entry points
|
||||
* @returns An array of entry points that were discovered.
|
||||
*/
|
||||
function getEntryPointsForPackage(packagePath: string): EntryPoint[] {
|
||||
function getEntryPointsForPackage(packagePath: AbsoluteFsPath): EntryPoint[] {
|
||||
const entryPoints: EntryPoint[] = [];
|
||||
|
||||
// Try to get an entry point from the top level package directory
|
||||
@ -96,7 +97,7 @@ function getEntryPointsForPackage(packagePath: string): EntryPoint[] {
|
||||
* @param dir the directory to recursively walk.
|
||||
* @param fn the function to apply to each directory.
|
||||
*/
|
||||
function walkDirectory(dir: string, fn: (dir: string) => void) {
|
||||
function walkDirectory(dir: AbsoluteFsPath, fn: (dir: AbsoluteFsPath) => void) {
|
||||
return fs
|
||||
.readdirSync(dir)
|
||||
// Not interested in hidden files
|
||||
@ -108,9 +109,9 @@ function walkDirectory(dir: string, fn: (dir: string) => void) {
|
||||
const stat = fs.lstatSync(path.resolve(dir, p));
|
||||
return stat.isDirectory() && !stat.isSymbolicLink();
|
||||
})
|
||||
.forEach(subdir => {
|
||||
subdir = path.resolve(dir, subdir);
|
||||
fn(subdir);
|
||||
walkDirectory(subdir, fn);
|
||||
.forEach(subDir => {
|
||||
const resolvedSubDir = AbsoluteFsPath.from(path.resolve(dir, subDir));
|
||||
fn(resolvedSubDir);
|
||||
walkDirectory(resolvedSubDir, fn);
|
||||
});
|
||||
}
|
||||
|
@ -56,8 +56,6 @@ export class Transformer {
|
||||
* @param bundle the bundle to transform.
|
||||
*/
|
||||
transform(entryPoint: EntryPoint, isCore: boolean, bundle: EntryPointBundle): void {
|
||||
console.warn(`Compiling ${entryPoint.name} - ${bundle.format}`);
|
||||
|
||||
const reflectionHost = this.getHost(isCore, bundle);
|
||||
|
||||
// Parse and analyze the files.
|
||||
@ -78,10 +76,8 @@ export class Transformer {
|
||||
const typeChecker = bundle.src.program.getTypeChecker();
|
||||
switch (bundle.format) {
|
||||
case 'esm2015':
|
||||
case 'fesm2015':
|
||||
return new Esm2015ReflectionHost(isCore, typeChecker, bundle.dts);
|
||||
case 'esm5':
|
||||
case 'fesm5':
|
||||
return new Esm5ReflectionHost(isCore, typeChecker, bundle.dts);
|
||||
default:
|
||||
throw new Error(`Reflection host for "${bundle.format}" not yet implemented.`);
|
||||
@ -91,10 +87,8 @@ export class Transformer {
|
||||
getRenderer(host: NgccReflectionHost, isCore: boolean, bundle: EntryPointBundle): Renderer {
|
||||
switch (bundle.format) {
|
||||
case 'esm2015':
|
||||
case 'fesm2015':
|
||||
return new EsmRenderer(host, isCore, bundle, this.sourcePath, this.targetPath);
|
||||
case 'esm5':
|
||||
case 'fesm5':
|
||||
return new Esm5Renderer(host, isCore, bundle, this.sourcePath, this.targetPath);
|
||||
default:
|
||||
throw new Error(`Renderer for "${bundle.format}" not yet implemented.`);
|
||||
|
@ -137,7 +137,8 @@ export abstract class Renderer {
|
||||
|
||||
if (compiledFile) {
|
||||
const importManager = new ImportManager(
|
||||
this.getImportRewriter(this.bundle.src.r3SymbolsFile, this.bundle.isFlat), IMPORT_PREFIX);
|
||||
this.getImportRewriter(this.bundle.src.r3SymbolsFile, this.bundle.isFlatCore),
|
||||
IMPORT_PREFIX);
|
||||
|
||||
// TODO: remove constructor param metadata and property decorators (we need info from the
|
||||
// handlers to do this)
|
||||
|
Reference in New Issue
Block a user