@kv-systems/ng-packagr
Version:
Compile and package Angular libraries in Angular Package Format (APF)
124 lines (106 loc) • 4.02 kB
text/typescript
import type { CompilerOptions, ParsedConfiguration } from '@angular/compiler-cli';
import * as path from 'path';
import ts from 'typescript';
import { EntryPointNode } from '../ng-package/nodes';
import { ngCompilerCli } from '../utils/load-esm';
import * as log from '../utils/log';
export const defaultTsConfigPath = path.join(__dirname, 'conf', 'tsconfig.ngc.json');
/**
* Reads the default TypeScript configuration.
*/
async function readDefaultTsConfig(fileName = defaultTsConfigPath): Promise<ParsedConfiguration> {
// these options are mandatory
const extraOptions: CompilerOptions = {
target: ts.ScriptTarget.ES2022,
// sourcemaps
sourceMap: false,
inlineSources: true,
inlineSourceMap: true,
outDir: '',
declaration: true,
// ng compiler
enableResourceInlining: true,
// these are required to set the appropriate EmitFlags
flatModuleId: 'AUTOGENERATED',
flatModuleOutFile: 'AUTOGENERATED',
};
const { readConfiguration } = await ngCompilerCli();
return readConfiguration(fileName, extraOptions);
}
/**
* Creates a parsed TypeScript configuration object.
*
* @param values File path or parsed configuration.
*/
async function createDefaultTsConfig(values?: ParsedConfiguration | string): Promise<ParsedConfiguration> {
if (!values) {
return readDefaultTsConfig();
} else if (typeof values === 'string') {
return readDefaultTsConfig(values);
} else {
return values;
}
}
/**
* Initializes TypeScript Compiler options and Angular Compiler options by overriding the
* default config with entry point-specific values.
*/
export async function initializeTsConfig(
defaultTsConfig: ParsedConfiguration | string | undefined,
entryPoints: EntryPointNode[],
): Promise<void> {
const defaultTsConfigParsed = await createDefaultTsConfig(defaultTsConfig);
if (defaultTsConfigParsed.errors.length > 0) {
const { formatDiagnostics } = await ngCompilerCli();
throw new Error(formatDiagnostics(defaultTsConfigParsed.errors));
}
for (const currentEntryPoint of entryPoints) {
const { entryPoint } = currentEntryPoint.data;
log.debug(`Initializing tsconfig for ${entryPoint.moduleId}`);
const basePath = path.dirname(entryPoint.entryFilePath);
// Resolve defaults from DI token and create a deep copy of the defaults
const tsConfig: ParsedConfiguration = JSON.parse(JSON.stringify(defaultTsConfigParsed));
const overrideOptions: CompilerOptions = {
flatModuleId: entryPoint.moduleId,
flatModuleOutFile: `${entryPoint.flatModuleFile}.js`,
basePath,
rootDir: basePath,
sourceRoot: '',
};
tsConfig.rootNames = [entryPoint.entryFilePath];
tsConfig.options = { ...tsConfig.options, ...overrideOptions };
currentEntryPoint.data.tsConfig = tsConfig;
}
}
/**
* Set the paths for entrypoint dependencies.
*
* This doesn't mutate the object.
*
* @param parsedTsConfig - A parsed tsconfig
* @param entryPoints - A list of entryPoints
* @param pointToSource Point the path mapping to either the source code or emitted declarations.
* Typically for analysis one should point to the source files while for a compilation once should use the emitted declarations
*/
export function setDependenciesTsConfigPaths(
parsedTsConfig: ParsedConfiguration,
entryPoints: EntryPointNode[],
pointToSource = false,
): ParsedConfiguration {
const tsConfig = JSON.parse(JSON.stringify(parsedTsConfig));
// Add paths mappings for dependencies
if (!tsConfig.options.paths) {
tsConfig.options.paths = {};
}
for (const dep of entryPoints) {
const { entryPoint } = dep.data;
const { moduleId, destinationFiles, entryFilePath } = entryPoint;
const mappedPath = [pointToSource ? entryFilePath : destinationFiles.declarations];
if (!tsConfig.options.paths[moduleId]) {
tsConfig.options.paths[moduleId] = mappedPath;
} else {
tsConfig.options.paths[moduleId].unshift(...mappedPath);
}
}
return tsConfig;
}