@angular/compiler-cli
Version:
Angular - the compiler CLI for Node.js
1,308 lines (1,280 loc) • 223 kB
JavaScript
import {createRequire as __cjsCompatRequire} from 'module';
const require = __cjsCompatRequire(import.meta.url);
import {
angularJitApplicationTransform
} from "./chunk-6SNDDF7J.js";
import {
AbsoluteModuleStrategy,
ActivePerfRecorder,
AliasStrategy,
COMPILER_ERRORS_WITH_GUIDES,
CompilationMode,
ComponentDecoratorHandler,
ComponentScopeKind,
CompoundComponentScopeReader,
CompoundMetadataReader,
CompoundMetadataRegistry,
DefaultImportTracker,
DeferredSymbolTracker,
DelegatingPerfRecorder,
DirectiveDecoratorHandler,
DtsMetadataReader,
DtsTransformRegistry,
ERROR_DETAILS_PAGE_BASE_URL,
ErrorCode,
ExportedProviderStatusResolver,
ExtendedTemplateDiagnosticName,
HostDirectivesResolver,
INPUT_INITIALIZER_FN,
ImportedSymbolsTracker,
InjectableClassRegistry,
InjectableDecoratorHandler,
JitDeclarationRegistry,
LocalCompilationExtraImportsTracker,
LocalIdentifierStrategy,
LocalMetadataRegistry,
LocalModuleScopeRegistry,
LogicalProjectStrategy,
MODEL_INITIALIZER_FN,
MetaKind,
MetadataDtsModuleScopeResolver,
ModuleResolver,
NgModuleDecoratorHandler,
NgOriginalFile,
NoopImportRewriter,
NoopReferencesRegistry,
OUTPUT_INITIALIZER_FNS,
OptimizeFor,
PartialEvaluator,
PerfCheckpoint,
PerfEvent,
PerfPhase,
PipeDecoratorHandler,
PrivateExportAliasingHost,
QUERY_INITIALIZER_FNS,
R3SymbolsImportRewriter,
Reference,
ReferenceEmitter,
RelativePathStrategy,
ResourceRegistry,
SelectorlessComponentScopeReader,
SemanticDepGraphUpdater,
ShimAdapter,
ShimReferenceTagger,
SymbolKind,
TemplateTypeCheckerImpl,
TraitCompiler,
TsCreateProgramDriver,
TypeCheckScopeRegistry,
TypeCheckShimGenerator,
TypeScriptReflectionHost,
UnifiedModulesAliasingHost,
UnifiedModulesStrategy,
aliasTransformFactory,
declarationTransformFactory,
getRootDirs,
getSourceFileOrNull,
isDtsPath,
isFatalDiagnosticError,
isNamedClassDeclaration,
isNonDeclarationTsPath,
isShim,
ivyTransformFactory,
makeDiagnostic,
ngErrorCode,
normalizeSeparators,
relativePathBetween,
replaceTsWithNgInErrors,
retagAllTsFiles,
signalMetadataTransform,
toUnredirectedSourceFile,
tryParseInitializerApi,
untagAllTsFiles
} from "./chunk-RO5VAPEI.js";
import {
LogicalFileSystem,
absoluteFrom,
absoluteFromSourceFile,
createFileSystemTsReadDirectoryFn,
dirname,
getFileSystem,
join,
resolve
} from "./chunk-GWZQLAGK.js";
// packages/compiler-cli/src/transformers/api.js
var DEFAULT_ERROR_CODE = 100;
var UNKNOWN_ERROR_CODE = 500;
var SOURCE = "angular";
function isTsDiagnostic(diagnostic) {
return diagnostic != null && diagnostic.source !== "angular";
}
var EmitFlags;
(function(EmitFlags2) {
EmitFlags2[EmitFlags2["DTS"] = 1] = "DTS";
EmitFlags2[EmitFlags2["JS"] = 2] = "JS";
EmitFlags2[EmitFlags2["Metadata"] = 4] = "Metadata";
EmitFlags2[EmitFlags2["I18nBundle"] = 8] = "I18nBundle";
EmitFlags2[EmitFlags2["Codegen"] = 16] = "Codegen";
EmitFlags2[EmitFlags2["Default"] = 19] = "Default";
EmitFlags2[EmitFlags2["All"] = 31] = "All";
})(EmitFlags || (EmitFlags = {}));
// packages/compiler-cli/src/transformers/compiler_host.js
import ts from "typescript";
var wrapHostForTest = null;
function createCompilerHost({ options, tsHost = ts.createCompilerHost(options, true) }) {
if (wrapHostForTest !== null) {
tsHost = wrapHostForTest(tsHost);
}
return tsHost;
}
// packages/compiler-cli/src/ngtsc/docs/src/entities.js
var EntryType;
(function(EntryType2) {
EntryType2["Block"] = "block";
EntryType2["Component"] = "component";
EntryType2["Constant"] = "constant";
EntryType2["Decorator"] = "decorator";
EntryType2["Directive"] = "directive";
EntryType2["Element"] = "element";
EntryType2["Enum"] = "enum";
EntryType2["Function"] = "function";
EntryType2["Interface"] = "interface";
EntryType2["NgModule"] = "ng_module";
EntryType2["Pipe"] = "pipe";
EntryType2["TypeAlias"] = "type_alias";
EntryType2["UndecoratedClass"] = "undecorated_class";
EntryType2["InitializerApiFunction"] = "initializer_api_function";
})(EntryType || (EntryType = {}));
var MemberType;
(function(MemberType2) {
MemberType2["Property"] = "property";
MemberType2["Method"] = "method";
MemberType2["Getter"] = "getter";
MemberType2["Setter"] = "setter";
MemberType2["EnumItem"] = "enum_item";
})(MemberType || (MemberType = {}));
var DecoratorType;
(function(DecoratorType2) {
DecoratorType2["Class"] = "class";
DecoratorType2["Member"] = "member";
DecoratorType2["Parameter"] = "parameter";
})(DecoratorType || (DecoratorType = {}));
var MemberTags;
(function(MemberTags2) {
MemberTags2["Abstract"] = "abstract";
MemberTags2["Static"] = "static";
MemberTags2["Readonly"] = "readonly";
MemberTags2["Protected"] = "protected";
MemberTags2["Optional"] = "optional";
MemberTags2["Input"] = "input";
MemberTags2["Output"] = "output";
MemberTags2["Inherited"] = "override";
})(MemberTags || (MemberTags = {}));
function isDocEntryWithSourceInfo(entry) {
return "source" in entry;
}
// packages/compiler-cli/src/ngtsc/docs/src/extractor.js
import ts12 from "typescript";
// packages/compiler-cli/src/ngtsc/docs/src/class_extractor.js
import ts6 from "typescript";
// packages/compiler-cli/src/ngtsc/docs/src/filters.js
function isAngularPrivateName(name) {
const firstChar = name[0] ?? "";
return firstChar === "\u0275" || firstChar === "_";
}
// packages/compiler-cli/src/ngtsc/docs/src/function_extractor.js
import ts4 from "typescript";
// packages/compiler-cli/src/ngtsc/docs/src/generics_extractor.js
function extractGenerics(declaration) {
return declaration.typeParameters?.map((typeParam) => ({
name: typeParam.name.getText(),
constraint: typeParam.constraint?.getText(),
default: typeParam.default?.getText()
})) ?? [];
}
// packages/compiler-cli/src/ngtsc/docs/src/jsdoc_extractor.js
import ts2 from "typescript";
var decoratorExpression = /@(?=(Injectable|Component|Directive|Pipe|NgModule|Input|Output|HostBinding|HostListener|Inject|Optional|Self|Host|SkipSelf|ViewChild|ViewChildren|ContentChild|ContentChildren))/g;
function extractJsDocTags(node) {
const escapedNode = getEscapedNode(node);
return ts2.getJSDocTags(escapedNode).map((t) => {
return {
name: t.tagName.getText(),
comment: unescapeAngularDecorators(ts2.getTextOfJSDocComment(t.comment) ?? "")
};
});
}
function extractJsDocDescription(node) {
const escapedNode = getEscapedNode(node);
const commentOrTag = ts2.getJSDocCommentsAndTags(escapedNode).find((d) => {
return ts2.isJSDoc(d) || ts2.isJSDocParameterTag(d);
});
const comment = commentOrTag?.comment ?? "";
const description = typeof comment === "string" ? comment : ts2.getTextOfJSDocComment(comment) ?? "";
return unescapeAngularDecorators(description);
}
function extractRawJsDoc(node) {
const comment = ts2.getJSDocCommentsAndTags(node).find(ts2.isJSDoc)?.getFullText() ?? "";
return unescapeAngularDecorators(comment);
}
function getEscapedNode(node) {
if (ts2.isParameter(node)) {
return node;
}
const rawComment = extractRawJsDoc(node);
const escaped = escapeAngularDecorators(rawComment);
const file = ts2.createSourceFile("x.ts", `${escaped}class X {}`, ts2.ScriptTarget.ES2020, true);
return file.statements.find((s) => ts2.isClassDeclaration(s));
}
function escapeAngularDecorators(comment) {
return comment.replace(decoratorExpression, "_NG_AT_");
}
function unescapeAngularDecorators(comment) {
return comment.replace(/_NG_AT_/g, "@");
}
// packages/compiler-cli/src/ngtsc/docs/src/type_extractor.js
import ts3 from "typescript";
function extractResolvedTypeString(node, checker) {
return checker.typeToString(checker.getTypeAtLocation(node), void 0, ts3.TypeFormatFlags.NoTruncation);
}
// packages/compiler-cli/src/ngtsc/docs/src/function_extractor.js
var FunctionExtractor = class {
name;
exportDeclaration;
typeChecker;
constructor(name, exportDeclaration, typeChecker) {
this.name = name;
this.exportDeclaration = exportDeclaration;
this.typeChecker = typeChecker;
}
extract() {
const signature = this.typeChecker.getSignatureFromDeclaration(this.exportDeclaration);
const returnType = signature ? extractReturnType(signature, this.typeChecker) : "unknown";
const implementation = findImplementationOfFunction(this.exportDeclaration, this.typeChecker) ?? this.exportDeclaration;
const type = this.typeChecker.getTypeAtLocation(this.exportDeclaration);
const overloads = ts4.isConstructorDeclaration(this.exportDeclaration) ? constructorOverloads(this.exportDeclaration, this.typeChecker) : extractCallSignatures(this.name, this.typeChecker, type);
const jsdocsTags = extractJsDocTags(implementation);
const description = extractJsDocDescription(implementation);
return {
name: this.name,
signatures: overloads,
implementation: {
params: extractAllParams(implementation.parameters, this.typeChecker),
isNewType: ts4.isConstructSignatureDeclaration(implementation),
returnType,
returnDescription: jsdocsTags.find((tag) => tag.name === "returns")?.comment,
generics: extractGenerics(implementation),
name: this.name,
description,
entryType: EntryType.Function,
jsdocTags: jsdocsTags,
rawComment: extractRawJsDoc(implementation)
},
entryType: EntryType.Function,
description,
jsdocTags: jsdocsTags,
rawComment: extractRawJsDoc(implementation)
};
}
};
function constructorOverloads(constructorDeclaration, typeChecker) {
const classDeclaration = constructorDeclaration.parent;
const constructorNode = classDeclaration.members.filter((member) => {
return ts4.isConstructorDeclaration(member) && !member.body;
});
return constructorNode.map((n) => {
return {
name: "constructor",
params: extractAllParams(n.parameters, typeChecker),
returnType: typeChecker.getTypeAtLocation(classDeclaration)?.symbol.name,
description: extractJsDocDescription(n),
entryType: EntryType.Function,
jsdocTags: extractJsDocTags(n),
rawComment: extractRawJsDoc(n),
generics: extractGenerics(n),
isNewType: false
};
});
}
function extractAllParams(params, typeChecker) {
return params.map((param) => ({
name: param.name.getText(),
description: extractJsDocDescription(param),
type: extractResolvedTypeString(param, typeChecker),
isOptional: !!(param.questionToken || param.initializer),
isRestParam: !!param.dotDotDotToken
}));
}
function filterSignatureDeclarations(signatures) {
const result = [];
for (const signature of signatures) {
const decl = signature.getDeclaration();
if (ts4.isFunctionDeclaration(decl) || ts4.isCallSignatureDeclaration(decl) || ts4.isMethodDeclaration(decl) || ts4.isConstructSignatureDeclaration(decl)) {
result.push({ signature, decl });
}
}
return result;
}
function extractCallSignatures(name, typeChecker, type) {
return filterSignatureDeclarations(type.getCallSignatures()).map(({ decl, signature }) => ({
name,
entryType: EntryType.Function,
description: extractJsDocDescription(decl),
generics: extractGenerics(decl),
isNewType: false,
jsdocTags: extractJsDocTags(decl),
params: extractAllParams(decl.parameters, typeChecker),
rawComment: extractRawJsDoc(decl),
returnType: extractReturnType(signature, typeChecker)
}));
}
function extractReturnType(signature, typeChecker) {
if (signature?.declaration?.type && ts4.isTypePredicateNode(signature.declaration.type)) {
return signature.declaration.type.getText();
}
return typeChecker.typeToString(
typeChecker.getReturnTypeOfSignature(signature),
void 0,
// This ensures that e.g. `T | undefined` is not reduced to `T`.
ts4.TypeFormatFlags.NoTypeReduction | ts4.TypeFormatFlags.NoTruncation
);
}
function findImplementationOfFunction(node, typeChecker) {
if (node.body !== void 0 || node.name === void 0) {
return node;
}
const symbol = typeChecker.getSymbolAtLocation(node.name);
const implementation = symbol?.declarations?.find((s) => ts4.isFunctionDeclaration(s) && s.body !== void 0);
return implementation;
}
// packages/compiler-cli/src/ngtsc/docs/src/internal.js
import ts5 from "typescript";
function isInternal(member) {
return extractJsDocTags(member).some((tag) => tag.name === "internal") || hasLeadingInternalComment(member);
}
function hasLeadingInternalComment(member) {
const memberText = member.getSourceFile().text;
return ts5.reduceEachLeadingCommentRange(
memberText,
member.getFullStart(),
(pos, end, kind, hasTrailingNewLine, containsInternal) => {
return containsInternal || memberText.slice(pos, end).includes("@internal");
},
/* state */
false,
/* initial */
false
) ?? false;
}
// packages/compiler-cli/src/ngtsc/docs/src/class_extractor.js
var ClassExtractor = class {
declaration;
typeChecker;
constructor(declaration, typeChecker) {
this.declaration = declaration;
this.typeChecker = typeChecker;
}
/** Extract docs info specific to classes. */
extract() {
return {
name: this.declaration.name.text,
isAbstract: this.isAbstract(),
entryType: ts6.isInterfaceDeclaration(this.declaration) ? EntryType.Interface : EntryType.UndecoratedClass,
members: this.extractSignatures().concat(this.extractAllClassMembers()),
generics: extractGenerics(this.declaration),
description: extractJsDocDescription(this.declaration),
jsdocTags: extractJsDocTags(this.declaration),
rawComment: extractRawJsDoc(this.declaration),
extends: this.extractInheritance(this.declaration),
implements: this.extractInterfaceConformance(this.declaration)
};
}
/** Extracts doc info for a class's members. */
extractAllClassMembers() {
const members = [];
for (const member of this.getMemberDeclarations()) {
if (this.isMemberExcluded(member))
continue;
const memberEntry = this.extractClassMember(member);
if (memberEntry) {
members.push(memberEntry);
}
}
return members;
}
/** Extract docs for a class's members (methods and properties). */
extractClassMember(memberDeclaration) {
if (this.isMethod(memberDeclaration)) {
return this.extractMethod(memberDeclaration);
} else if (this.isProperty(memberDeclaration) && !this.hasPrivateComputedProperty(memberDeclaration)) {
return this.extractClassProperty(memberDeclaration);
} else if (ts6.isAccessor(memberDeclaration)) {
return this.extractGetterSetter(memberDeclaration);
} else if (ts6.isConstructorDeclaration(memberDeclaration) && memberDeclaration.parameters.length > 0) {
return this.extractConstructor(memberDeclaration);
}
return void 0;
}
/** Extract docs for all call signatures in the current class/interface. */
extractSignatures() {
return this.computeAllSignatureDeclarations().map((s) => this.extractSignature(s));
}
/** Extracts docs for a class method. */
extractMethod(methodDeclaration) {
const functionExtractor = new FunctionExtractor(methodDeclaration.name.getText(), methodDeclaration, this.typeChecker);
return {
...functionExtractor.extract(),
memberType: MemberType.Method,
memberTags: this.getMemberTags(methodDeclaration)
};
}
/** Extracts docs for a signature element (usually inside an interface). */
extractSignature(signature) {
const functionExtractor = new FunctionExtractor(ts6.isConstructSignatureDeclaration(signature) ? "new" : "", signature, this.typeChecker);
return {
...functionExtractor.extract(),
memberType: MemberType.Method,
memberTags: []
};
}
/** Extracts doc info for a property declaration. */
extractClassProperty(propertyDeclaration) {
return {
name: propertyDeclaration.name.getText(),
type: extractResolvedTypeString(propertyDeclaration, this.typeChecker),
memberType: MemberType.Property,
memberTags: this.getMemberTags(propertyDeclaration),
description: extractJsDocDescription(propertyDeclaration),
jsdocTags: extractJsDocTags(propertyDeclaration)
};
}
/** Extracts doc info for an accessor member (getter/setter). */
extractGetterSetter(accessor) {
return {
...this.extractClassProperty(accessor),
memberType: ts6.isGetAccessor(accessor) ? MemberType.Getter : MemberType.Setter
};
}
extractConstructor(constructorDeclaration) {
const functionExtractor = new FunctionExtractor("constructor", constructorDeclaration, this.typeChecker);
return {
...functionExtractor.extract(),
memberType: MemberType.Method,
memberTags: this.getMemberTags(constructorDeclaration)
};
}
extractInheritance(declaration) {
if (!declaration.heritageClauses) {
return void 0;
}
for (const clause of declaration.heritageClauses) {
if (clause.token === ts6.SyntaxKind.ExtendsKeyword) {
const types = clause.types;
if (types.length > 0) {
const baseClass = types[0];
return baseClass.getText();
}
}
}
return void 0;
}
extractInterfaceConformance(declaration) {
const implementClause = declaration.heritageClauses?.find((clause) => clause.token === ts6.SyntaxKind.ImplementsKeyword);
return implementClause?.types.map((m) => m.getText()) ?? [];
}
/** Gets the tags for a member (protected, readonly, static, etc.) */
getMemberTags(member) {
const tags = this.getMemberTagsFromModifiers(member.modifiers ?? []);
if (member.questionToken) {
tags.push(MemberTags.Optional);
}
if (member.parent !== this.declaration) {
tags.push(MemberTags.Inherited);
}
return tags;
}
/** Computes all signature declarations of the class/interface. */
computeAllSignatureDeclarations() {
const type = this.typeChecker.getTypeAtLocation(this.declaration);
const signatures = [...type.getCallSignatures(), ...type.getConstructSignatures()];
const result = [];
for (const signature of signatures) {
const decl = signature.getDeclaration();
if (this.isDocumentableSignature(decl) && this.isDocumentableMember(decl)) {
result.push(decl);
}
}
return result;
}
/** Gets all member declarations, including inherited members. */
getMemberDeclarations() {
const type = this.typeChecker.getTypeAtLocation(this.declaration);
const members = type.getProperties();
const constructor = type.getSymbol()?.members?.get(ts6.InternalSymbolName.Constructor);
const typeOfConstructor = this.typeChecker.getTypeOfSymbol(type.symbol);
const staticMembers = typeOfConstructor.getProperties();
const result = [];
for (const member of [...constructor ? [constructor] : [], ...members, ...staticMembers]) {
const memberDeclarations = this.filterMethodOverloads(member.getDeclarations() ?? []);
for (const memberDeclaration of memberDeclarations) {
if (this.isDocumentableMember(memberDeclaration)) {
result.push(memberDeclaration);
}
}
}
return result;
}
/** The result only contains properties, method implementations and abstracts */
filterMethodOverloads(declarations) {
return declarations.filter((declaration, index) => {
if (ts6.isFunctionDeclaration(declaration) || ts6.isMethodDeclaration(declaration) || ts6.isConstructorDeclaration(declaration)) {
const nextDeclaration = declarations[index + 1];
const isNextMethodWithSameName = nextDeclaration && (ts6.isMethodDeclaration(nextDeclaration) && nextDeclaration.name.getText() === declaration.name?.getText() || ts6.isConstructorDeclaration(nextDeclaration) && ts6.isConstructorDeclaration(declaration));
return !isNextMethodWithSameName;
}
return true;
});
}
/** Get the tags for a member that come from the declaration modifiers. */
getMemberTagsFromModifiers(mods) {
const tags = [];
for (const mod of mods) {
const tag = this.getTagForMemberModifier(mod);
if (tag)
tags.push(tag);
}
return tags;
}
/** Gets the doc tag corresponding to a class member modifier (readonly, protected, etc.). */
getTagForMemberModifier(mod) {
switch (mod.kind) {
case ts6.SyntaxKind.StaticKeyword:
return MemberTags.Static;
case ts6.SyntaxKind.ReadonlyKeyword:
return MemberTags.Readonly;
case ts6.SyntaxKind.ProtectedKeyword:
return MemberTags.Protected;
case ts6.SyntaxKind.AbstractKeyword:
return MemberTags.Abstract;
default:
return void 0;
}
}
/**
* Gets whether a given class member should be excluded from public API docs.
* This is the case if:
* - The member does not have a name
* - The member is neither a method nor property
* - The member is private
* - The member has a name that marks it as Angular-internal.
* - The member is marked as internal via JSDoc.
*/
isMemberExcluded(member) {
if (ts6.isConstructorDeclaration(member)) {
return false;
}
return !member.name || !this.isDocumentableMember(member) || !ts6.isCallSignatureDeclaration(member) && member.modifiers?.some((mod) => mod.kind === ts6.SyntaxKind.PrivateKeyword) || member.name.getText() === "prototype" || isAngularPrivateName(member.name.getText()) || isInternal(member);
}
/** Gets whether a class member is a method, property, or accessor. */
isDocumentableMember(member) {
return this.isMethod(member) || this.isProperty(member) || ts6.isAccessor(member) || ts6.isConstructorDeclaration(member) || // Signatures are documentable if they are part of an interface.
ts6.isCallSignatureDeclaration(member);
}
/** Check if the parameter is a constructor parameter with a public modifier */
isPublicConstructorParameterProperty(node) {
if (ts6.isParameterPropertyDeclaration(node, node.parent) && node.modifiers) {
return node.modifiers.some((modifier) => modifier.kind === ts6.SyntaxKind.PublicKeyword);
}
return false;
}
/** Gets whether a member is a property. */
isProperty(member) {
return ts6.isPropertyDeclaration(member) || ts6.isPropertySignature(member) || this.isPublicConstructorParameterProperty(member);
}
/** Gets whether a member is a method. */
isMethod(member) {
return ts6.isMethodDeclaration(member) || ts6.isMethodSignature(member);
}
/** Gets whether the given signature declaration is documentable. */
isDocumentableSignature(signature) {
return ts6.isConstructSignatureDeclaration(signature) || ts6.isCallSignatureDeclaration(signature);
}
/** Gets whether the declaration for this extractor is abstract. */
isAbstract() {
const modifiers = this.declaration.modifiers ?? [];
return modifiers.some((mod) => mod.kind === ts6.SyntaxKind.AbstractKeyword);
}
/**
* Check wether a member has a private computed property name like [ɵWRITABLE_SIGNAL]
*
* This will prevent exposing private computed properties in the docs.
*/
hasPrivateComputedProperty(property) {
return ts6.isComputedPropertyName(property.name) && property.name.expression.getText().startsWith("\u0275");
}
};
var DirectiveExtractor = class extends ClassExtractor {
reference;
metadata;
constructor(declaration, reference, metadata, checker) {
super(declaration, checker);
this.reference = reference;
this.metadata = metadata;
}
/** Extract docs info for directives and components (including underlying class info). */
extract() {
return {
...super.extract(),
isStandalone: this.metadata.isStandalone,
selector: this.metadata.selector ?? "",
exportAs: this.metadata.exportAs ?? [],
entryType: this.metadata.isComponent ? EntryType.Component : EntryType.Directive
};
}
/** Extracts docs info for a directive property, including input/output metadata. */
extractClassProperty(propertyDeclaration) {
const entry = super.extractClassProperty(propertyDeclaration);
const inputMetadata = this.getInputMetadata(propertyDeclaration);
if (inputMetadata) {
entry.memberTags.push(MemberTags.Input);
entry.inputAlias = inputMetadata.bindingPropertyName;
entry.isRequiredInput = inputMetadata.required;
}
const outputMetadata = this.getOutputMetadata(propertyDeclaration);
if (outputMetadata) {
entry.memberTags.push(MemberTags.Output);
entry.outputAlias = outputMetadata.bindingPropertyName;
}
return entry;
}
/** Gets the input metadata for a directive property. */
getInputMetadata(prop) {
const propName = prop.name.getText();
return this.metadata.inputs?.getByClassPropertyName(propName) ?? void 0;
}
/** Gets the output metadata for a directive property. */
getOutputMetadata(prop) {
const propName = prop.name.getText();
return this.metadata?.outputs?.getByClassPropertyName(propName) ?? void 0;
}
};
var PipeExtractor = class extends ClassExtractor {
reference;
metadata;
constructor(declaration, reference, metadata, typeChecker) {
super(declaration, typeChecker);
this.reference = reference;
this.metadata = metadata;
}
extract() {
return {
...super.extract(),
pipeName: this.metadata.name,
entryType: EntryType.Pipe,
isStandalone: this.metadata.isStandalone,
usage: extractPipeSyntax(this.metadata, this.declaration),
isPure: this.metadata.isPure
};
}
};
var NgModuleExtractor = class extends ClassExtractor {
reference;
metadata;
constructor(declaration, reference, metadata, typeChecker) {
super(declaration, typeChecker);
this.reference = reference;
this.metadata = metadata;
}
extract() {
return {
...super.extract(),
entryType: EntryType.NgModule
};
}
};
function extractClass(classDeclaration, metadataReader, typeChecker) {
const ref = new Reference(classDeclaration);
let extractor;
let directiveMetadata = metadataReader.getDirectiveMetadata(ref);
let pipeMetadata = metadataReader.getPipeMetadata(ref);
let ngModuleMetadata = metadataReader.getNgModuleMetadata(ref);
if (directiveMetadata) {
extractor = new DirectiveExtractor(classDeclaration, ref, directiveMetadata, typeChecker);
} else if (pipeMetadata) {
extractor = new PipeExtractor(classDeclaration, ref, pipeMetadata, typeChecker);
} else if (ngModuleMetadata) {
extractor = new NgModuleExtractor(classDeclaration, ref, ngModuleMetadata, typeChecker);
} else {
extractor = new ClassExtractor(classDeclaration, typeChecker);
}
return extractor.extract();
}
function extractInterface(declaration, typeChecker) {
const extractor = new ClassExtractor(declaration, typeChecker);
return extractor.extract();
}
function extractPipeSyntax(metadata, classDeclaration) {
const transformParams = classDeclaration.members.find((member) => {
return ts6.isMethodDeclaration(member) && member.name && ts6.isIdentifier(member.name) && member.name.getText() === "transform";
});
let paramNames = transformParams.parameters.slice(1).map((param) => {
return param.name.getText();
});
return `{{ value_expression | ${metadata.name}${paramNames.length ? ":" + paramNames.join(":") : ""} }}`;
}
// packages/compiler-cli/src/ngtsc/docs/src/constant_extractor.js
import ts7 from "typescript";
var LITERAL_AS_ENUM_TAG = "object-literal-as-enum";
function extractConstant(declaration, typeChecker) {
const resolvedType = typeChecker.getBaseTypeOfLiteralType(typeChecker.getTypeAtLocation(declaration));
const rawComment = extractRawJsDoc(declaration.parent.parent);
const jsdocTags = extractJsDocTags(declaration);
const description = extractJsDocDescription(declaration);
const name = declaration.name.getText();
if (jsdocTags.some((tag) => tag.name === LITERAL_AS_ENUM_TAG)) {
return {
name,
entryType: EntryType.Enum,
members: extractLiteralPropertiesAsEnumMembers(declaration),
rawComment,
description,
jsdocTags: jsdocTags.filter((tag) => tag.name !== LITERAL_AS_ENUM_TAG)
};
}
return {
name,
type: typeChecker.typeToString(resolvedType),
entryType: EntryType.Constant,
rawComment,
description,
jsdocTags
};
}
function isSyntheticAngularConstant(declaration) {
return declaration.name.getText() === "USED_FOR_NG_TYPE_CHECKING";
}
function extractLiteralPropertiesAsEnumMembers(declaration) {
let initializer = declaration.initializer;
while (initializer && (ts7.isAsExpression(initializer) || ts7.isParenthesizedExpression(initializer))) {
initializer = initializer.expression;
}
if (initializer === void 0 || !ts7.isObjectLiteralExpression(initializer)) {
throw new Error(`Declaration tagged with "${LITERAL_AS_ENUM_TAG}" must be initialized to an object literal, but received ${initializer ? ts7.SyntaxKind[initializer.kind] : "undefined"}`);
}
return initializer.properties.map((prop) => {
if (!ts7.isPropertyAssignment(prop) || !ts7.isIdentifier(prop.name)) {
throw new Error(`Property in declaration tagged with "${LITERAL_AS_ENUM_TAG}" must be a property assignment with a static name`);
}
if (!ts7.isNumericLiteral(prop.initializer) && !ts7.isStringLiteralLike(prop.initializer)) {
throw new Error(`Property in declaration tagged with "${LITERAL_AS_ENUM_TAG}" must be initialized to a number or string literal`);
}
return {
name: prop.name.text,
type: `${declaration.name.getText()}.${prop.name.text}`,
value: prop.initializer.getText(),
memberType: MemberType.EnumItem,
jsdocTags: extractJsDocTags(prop),
description: extractJsDocDescription(prop),
memberTags: []
};
});
}
// packages/compiler-cli/src/ngtsc/docs/src/decorator_extractor.js
import ts8 from "typescript";
function extractorDecorator(declaration, typeChecker) {
const documentedNode = getDecoratorJsDocNode(declaration, typeChecker);
const decoratorType = getDecoratorType(declaration);
if (!decoratorType) {
throw new Error(`"${declaration.name.getText()} is not a decorator."`);
}
const members = getDecoratorProperties(declaration, typeChecker);
let signatures = [];
if (!members) {
const decoratorInterface = getDecoratorDeclaration(declaration, typeChecker);
const callSignatures = decoratorInterface.members.filter(ts8.isCallSignatureDeclaration);
signatures = getDecoratorSignatures(callSignatures, typeChecker);
}
return {
name: declaration.name.getText(),
decoratorType,
entryType: EntryType.Decorator,
rawComment: extractRawJsDoc(documentedNode),
description: extractJsDocDescription(documentedNode),
jsdocTags: extractJsDocTags(documentedNode),
members,
signatures
};
}
function isDecoratorDeclaration(declaration) {
return !!getDecoratorType(declaration);
}
function isDecoratorOptionsInterface(declaration) {
return declaration.getSourceFile().statements.some((s) => ts8.isVariableStatement(s) && s.declarationList.declarations.some((d) => isDecoratorDeclaration(d) && d.name.getText() === declaration.name.getText()));
}
function getDecoratorType(declaration) {
const initializer = declaration.initializer?.getFullText() ?? "";
if (initializer.includes("makeDecorator"))
return DecoratorType.Class;
if (initializer.includes("makePropDecorator"))
return DecoratorType.Member;
if (initializer.includes("makeParamDecorator"))
return DecoratorType.Parameter;
return void 0;
}
function getDecoratorDeclaration(declaration, typeChecker) {
const decoratorName = declaration.name.getText();
const decoratorDeclaration = declaration;
const decoratorType = typeChecker.getTypeAtLocation(decoratorDeclaration);
const aliasDeclaration = decoratorType.getSymbol().getDeclarations()[0];
const decoratorInterface = aliasDeclaration;
if (!decoratorInterface || !ts8.isInterfaceDeclaration(decoratorInterface)) {
throw new Error(`No decorator interface found for "${decoratorName}".`);
}
return decoratorInterface;
}
function getDecoratorProperties(declaration, typeChecker) {
const decoratorCallSig = getDecoratorJsDocNode(declaration, typeChecker);
const decoratorFirstParam = decoratorCallSig.parameters[0];
const firstParamType = typeChecker.getTypeAtLocation(decoratorFirstParam);
let firstParamTypeDecl;
if (firstParamType.isUnion()) {
const firstParamTypeUnion = firstParamType.types.find((t) => (t.flags & ts8.TypeFlags.Undefined) === 0);
firstParamTypeDecl = firstParamTypeUnion?.getSymbol()?.getDeclarations()[0];
} else {
firstParamTypeDecl = firstParamType.getSymbol()?.getDeclarations()[0];
}
if (!firstParamTypeDecl || !ts8.isInterfaceDeclaration(firstParamTypeDecl)) {
return null;
}
const interfaceDeclaration = firstParamTypeDecl;
return extractInterface(interfaceDeclaration, typeChecker).members;
}
function getDecoratorSignatures(callSignatures, typeChecker) {
return callSignatures.map((signatureDecl) => {
return {
parameters: extractParams(signatureDecl.parameters, typeChecker),
jsdocTags: extractJsDocTags(signatureDecl)
};
});
}
function extractParams(params, typeChecker) {
return params.map((param) => ({
name: param.name.getText(),
description: extractJsDocDescription(param),
type: getParamTypeString(param, typeChecker),
isOptional: !!(param.questionToken || param.initializer),
isRestParam: !!param.dotDotDotToken
}));
}
function getDecoratorInterface(declaration, typeChecker) {
const name = declaration.name.getText();
const symbol = typeChecker.getSymbolAtLocation(declaration.name);
const decoratorType = typeChecker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration);
const decoratorInterface = decoratorType.getSymbol()?.getDeclarations()[0];
if (!decoratorInterface || !ts8.isInterfaceDeclaration(decoratorInterface)) {
throw new Error(`No decorator interface found for "${name}".`);
}
return decoratorInterface;
}
function getDecoratorJsDocNode(declaration, typeChecker) {
const name = declaration.name.getText();
const decoratorInterface = getDecoratorInterface(declaration, typeChecker);
const callSignature = decoratorInterface.members.filter((node) => {
return ts8.isCallSignatureDeclaration(node) && extractRawJsDoc(node);
}).at(-1);
if (!callSignature || !ts8.isCallSignatureDeclaration(callSignature)) {
throw new Error(`No call signature with JsDoc on "${name}Decorator"`);
}
return callSignature;
}
function getParamTypeString(paramNode, typeChecker) {
const type = typeChecker.getTypeAtLocation(paramNode);
const printer = ts8.createPrinter({ removeComments: true });
const sourceFile = paramNode.getSourceFile();
const replace = [];
if (type.isUnion()) {
for (const subType of type.types) {
const decl = subType.getSymbol()?.getDeclarations()?.[0];
if (decl && ts8.isInterfaceDeclaration(decl) && decl.name.text !== "Function") {
replace.push({
initial: subType.symbol.name,
replacedWith: expandType(decl, sourceFile, printer)
});
}
}
}
let result = printer.printNode(ts8.EmitHint.Unspecified, paramNode, sourceFile).replace(new RegExp(`${paramNode.name.getText()}\\??: `), "").replaceAll(/\s+/g, " ");
for (const { initial, replacedWith } of replace) {
result = result.replace(initial, replacedWith);
}
return result;
}
function expandType(decl, sourceFile, printer) {
const props = decl.members.map((member) => printer.printNode(ts8.EmitHint.Unspecified, member, sourceFile)).join(" ").replaceAll(/\s+/g, " ");
return `{${props}}`;
}
// packages/compiler-cli/src/ngtsc/docs/src/enum_extractor.js
import ts9 from "typescript";
function extractEnum(declaration, typeChecker) {
return {
name: declaration.name.getText(),
entryType: EntryType.Enum,
members: extractEnumMembers(declaration, typeChecker),
rawComment: extractRawJsDoc(declaration),
description: extractJsDocDescription(declaration),
jsdocTags: extractJsDocTags(declaration)
};
}
function extractEnumMembers(declaration, checker) {
return declaration.members.map((member) => ({
name: member.name.getText(),
type: extractResolvedTypeString(member, checker),
value: getEnumMemberValue(member),
memberType: MemberType.EnumItem,
jsdocTags: extractJsDocTags(member),
description: extractJsDocDescription(member),
memberTags: []
}));
}
function getEnumMemberValue(memberNode) {
const literal = memberNode.getChildren().find((n) => {
return ts9.isNumericLiteral(n) || ts9.isStringLiteral(n) || ts9.isPrefixUnaryExpression(n) && n.operator === ts9.SyntaxKind.MinusToken && ts9.isNumericLiteral(n.operand);
});
return literal?.getText() ?? "";
}
// packages/compiler-cli/src/ngtsc/docs/src/initializer_api_function_extractor.js
import ts10 from "typescript";
var initializerApiTag = "initializerApiFunction";
function isInitializerApiFunction(node, typeChecker) {
if (ts10.isFunctionDeclaration(node) && node.name !== void 0 && node.body === void 0) {
const implementation = findImplementationOfFunction(node, typeChecker);
if (implementation !== void 0) {
node = implementation;
}
}
if (!ts10.isFunctionDeclaration(node) && !ts10.isVariableDeclaration(node)) {
return false;
}
let tagContainer = ts10.isFunctionDeclaration(node) ? node : getContainerVariableStatement(node);
if (tagContainer === null) {
return false;
}
const tags = ts10.getJSDocTags(tagContainer);
return tags.some((t) => t.tagName.text === initializerApiTag);
}
function extractInitializerApiFunction(node, typeChecker) {
if (node.name === void 0 || !ts10.isIdentifier(node.name)) {
throw new Error(`Initializer API: Expected literal variable name.`);
}
const container = ts10.isFunctionDeclaration(node) ? node : getContainerVariableStatement(node);
if (container === null) {
throw new Error("Initializer API: Could not find container AST node of variable.");
}
const name = node.name.text;
const type = typeChecker.getTypeAtLocation(node);
const callFunction = extractFunctionWithOverloads(name, type, typeChecker);
const subFunctions = [];
for (const property of type.getProperties()) {
const subName = property.getName();
const subDecl = property.getDeclarations()?.[0];
if (subDecl === void 0 || !ts10.isPropertySignature(subDecl)) {
throw new Error(`Initializer API: Could not resolve declaration of sub-property: ${name}.${subName}`);
}
const subType = typeChecker.getTypeAtLocation(subDecl);
subFunctions.push(extractFunctionWithOverloads(subName, subType, typeChecker));
}
let jsdocTags;
let description;
let rawComment;
if (ts10.isFunctionDeclaration(node)) {
const implementation = findImplementationOfFunction(node, typeChecker);
if (implementation === void 0) {
throw new Error(`Initializer API: Could not find implementation of function: ${name}`);
}
callFunction.implementation = {
name,
entryType: EntryType.Function,
isNewType: false,
description: extractJsDocDescription(implementation),
generics: extractGenerics(implementation),
jsdocTags: extractJsDocTags(implementation),
params: extractAllParams(implementation.parameters, typeChecker),
rawComment: extractRawJsDoc(implementation),
returnType: typeChecker.typeToString(typeChecker.getReturnTypeOfSignature(typeChecker.getSignatureFromDeclaration(implementation)))
};
jsdocTags = callFunction.implementation.jsdocTags;
description = callFunction.implementation.description;
rawComment = callFunction.implementation.description;
} else {
jsdocTags = extractJsDocTags(container);
description = extractJsDocDescription(container);
rawComment = extractRawJsDoc(container);
}
const metadataTag = jsdocTags.find((t) => t.name === initializerApiTag);
if (metadataTag === void 0) {
throw new Error(`Initializer API: Detected initializer API function does not have "@initializerApiFunction" tag: ${name}`);
}
let parsedMetadata = void 0;
if (metadataTag.comment.trim() !== "") {
try {
parsedMetadata = JSON.parse(metadataTag.comment);
} catch (e) {
throw new Error(`Could not parse initializer API function metadata: ${e}`);
}
}
return {
entryType: EntryType.InitializerApiFunction,
name,
description,
jsdocTags,
rawComment,
callFunction,
subFunctions,
__docsMetadata__: parsedMetadata
};
}
function getContainerVariableStatement(node) {
if (!ts10.isVariableDeclarationList(node.parent)) {
return null;
}
if (!ts10.isVariableStatement(node.parent.parent)) {
return null;
}
return node.parent.parent;
}
function extractFunctionWithOverloads(name, type, typeChecker) {
return {
name,
signatures: extractCallSignatures(name, typeChecker, type),
// Implementation may be populated later.
implementation: null
};
}
// packages/compiler-cli/src/ngtsc/docs/src/type_alias_extractor.js
function extractTypeAlias(declaration) {
return {
name: declaration.name.getText(),
type: declaration.type.getText(),
entryType: EntryType.TypeAlias,
generics: extractGenerics(declaration),
rawComment: extractRawJsDoc(declaration),
description: extractJsDocDescription(declaration),
jsdocTags: extractJsDocTags(declaration)
};
}
// packages/compiler-cli/src/ngtsc/docs/src/import_extractor.js
import ts11 from "typescript";
function getImportedSymbols(sourceFile) {
const importSpecifiers = /* @__PURE__ */ new Map();
function visit(node) {
if (ts11.isImportDeclaration(node)) {
let moduleSpecifier = node.moduleSpecifier.getText(sourceFile).replace(/['"]/g, "");
if (moduleSpecifier.startsWith("@angular/")) {
const namedBindings = node.importClause?.namedBindings;
if (namedBindings && ts11.isNamedImports(namedBindings)) {
namedBindings.elements.forEach((importSpecifier) => {
const importName = importSpecifier.name.text;
const importAlias = importSpecifier.propertyName ? importSpecifier.propertyName.text : void 0;
importSpecifiers.set(importAlias ?? importName, moduleSpecifier);
});
}
}
}
ts11.forEachChild(node, visit);
}
visit(sourceFile);
return importSpecifiers;
}
// packages/compiler-cli/src/ngtsc/docs/src/extractor.js
var DocsExtractor = class {
typeChecker;
metadataReader;
constructor(typeChecker, metadataReader) {
this.typeChecker = typeChecker;
this.metadataReader = metadataReader;
}
/**
* Gets the set of all documentable entries from a source file, including
* declarations that are re-exported from this file as an entry-point.
*
* @param sourceFile The file from which to extract documentable entries.
*/
extractAll(sourceFile, rootDir, privateModules) {
const entries = [];
const symbols = /* @__PURE__ */ new Map();
const exportedDeclarations = this.getExportedDeclarations(sourceFile);
for (const [exportName, node] of exportedDeclarations) {
if (isAngularPrivateName(exportName)) {
continue;
}
const entry = this.extractDeclaration(node);
if (entry && !isIgnoredDocEntry(entry)) {
const realSourceFile = node.getSourceFile();
const importedSymbols = getImportedSymbols(realSourceFile);
importedSymbols.forEach((moduleName, symbolName) => {
if (symbolName.startsWith("\u0275") || privateModules.has(moduleName)) {
return;
}
if (symbols.has(symbolName) && symbols.get(symbolName) !== moduleName) {
throw new Error(`Ambigous symbol \`${symbolName}\` exported by both ${symbols.get(symbolName)} & ${moduleName}`);
}
symbols.set(symbolName, moduleName);
});
entry.source = {
filePath: getRelativeFilePath(realSourceFile, rootDir),
// Start & End are off by 1
startLine: ts12.getLineAndCharacterOfPosition(realSourceFile, node.getStart()).line + 1,
endLine: ts12.getLineAndCharacterOfPosition(realSourceFile, node.getEnd()).line + 1
};
entries.push({ ...entry, name: exportName });
}
}
return { entries, symbols };
}
/** Extract the doc entry for a single declaration. */
extractDeclaration(node) {
if (isNamedClassDeclaration(node)) {
return extractClass(node, this.metadataReader, this.typeChecker);
}
if (isInitializerApiFunction(node, this.typeChecker)) {
return extractInitializerApiFunction(node, this.typeChecker);
}
if (ts12.isInterfaceDeclaration(node) && !isIgnoredInterface(node)) {
return extractInterface(node, this.typeChecker);
}
if (ts12.isFunctionDeclaration(node)) {
const functionExtractor = new FunctionExtractor(node.name.getText(), node, this.typeChecker);
return functionExtractor.extract();
}
if (ts12.isVariableDeclaration(node) && !isSyntheticAngularConstant(node)) {
return isDecoratorDeclaration(node) ? extractorDecorator(node, this.typeChecker) : extractConstant(node, this.typeChecker);
}
if (ts12.isTypeAliasDeclaration(node)) {
return extractTypeAlias(node);
}
if (ts12.isEnumDeclaration(node)) {
return extractEnum(node, this.typeChecker);
}
return null;
}
/** Gets the list of exported declarations for doc extraction. */
getExportedDeclarations(sourceFile) {
const reflector = new TypeScriptReflectionHost(this.typeChecker, false, true);
const exportedDeclarationMap = reflector.getExportsOfModule(sourceFile);
let exportedDeclarations = Array.from(exportedDeclarationMap?.entries() ?? []).map(([exportName, declaration]) => [exportName, declaration.node]);
return exportedDeclarations.sort(([a, declarationA], [b, declarationB]) => declarationA.pos - declarationB.pos);
}
};
function isIgnoredInterface(node) {
return node.name.getText().endsWith("Decorator") || isDecoratorOptionsInterface(node);
}
function isIgnoredDocEntry(entry) {
const isDocsPrivate = entry.jsdocTags.find((e) => e.name === "docsPrivate");
if (isDocsPrivate !== void 0 && isDocsPrivate.comment === "") {
throw new Error(`Docs extraction: Entry "${entry.name}" is marked as "@docsPrivate" but without reasoning.`);
}
return isDocsPrivate !== void 0;
}
function getRelativeFilePath(sourceFile, rootDir) {
const fullPath = sourceFile.fileName;
const relativePath = fullPath.replace(rootDir, "");
return relativePath;
}
// packages/compiler-cli/src/ngtsc/program.js
import { HtmlParser, MessageBundle } from "@angular/compiler";
import ts27 from "typescript";
// packages/compiler-cli/src/transformers/i18n.js
import { Xliff, Xliff2, Xmb } from "@angular/compiler";
import * as path from "path";
function i18nGetExtension(formatName) {
const format = formatName.toLowerCase();
switch (format) {
case "xmb":
return "xmb";
case "xlf":
case "xlif":
case "xliff":
case "xlf2":
case "xliff2":
return "xlf";
}
throw new Error(`Unsupported format "${formatName}"`);
}
function i18nExtract(formatName, outFile, host, options, bundle, pathResolve = path.resolve) {
formatName = formatName || "xlf";
const ext = i18nGetExtension(formatName);
const content = i18nSerialize(bundle, formatName, options);
const dstFile = outFile || `messages.${ext}`;
const dstPath = pathResolve(options.outDir || options.basePath, dstFile);
host.writeFile(dstPath, content, false, void 0, []);
return [dstPath];
}
function i18nSerialize(bundle, formatName, options) {
const format = formatName.toLowerCase();
let serializer;
switch (format) {
case "xmb":
serializer = new Xmb();
break;
case "xliff2":
case "xlf2":
serializer = new Xliff2();
break;
case "xlf":
case "xliff":
default:
serializer = new Xliff();
}
return bundle.write(serializer, getPathNormalizer(options.basePath));
}
function getPathNormalizer(basePath) {
return (sourcePath) => {
sourcePath = basePath ? path.relative(basePath, sourcePath) : sourcePath;
return sourcePath.split(path.sep).join("/");
};
}
// packages/compiler-cli/src/typescript_support.js
import ts13 from "typescript";
// packages/compiler-cli/src/version_helpers.js
function toNumbers(value) {
const suffixIndex = value.lastIndexOf("-");
return value.slice(0, suffixIndex === -1 ? value.length : suffixIndex).split(".").map((segment) => {
const parsed = parseInt(segment, 10);
if (isNaN(parsed)) {
throw Error(`Unable to parse version string ${value}.`);
}
return parsed;
});
}
function compareNumbers(a, b) {
const max = Math.max(a.length, b.length);
const min = Math.min(a.length, b.length);
for (let i = 0; i < min; i++) {
if (a[i] > b[i])
return 1;
if (a[i] < b[i])
return -1;
}
if (min !== max) {
const longestArray = a.length === max ? a : b;
const comparisonResult = a.length === max ? 1 : -1;
for (let i = min; i < max; i++) {
if (longestArray[i] > 0) {
return comparisonResult;
}
}
}
return 0;
}
function compareVersions(v1, v2) {
return compareNumbers(toNumbers(v1), toNumbers(v2));
}
// packages/compiler-cli/src/typescript_support.js
var MIN_TS_VERSION = "5.8.0";
var MAX_TS_VERSION = "5.9.0";
var tsVersion = ts13.version;
function checkVersion(version, minVersion, maxVersion) {
if (compareVersions(version, minVersion) < 0 || compareVersions(version, maxVersion) >= 0) {
throw new Error(`The Angular Compiler requires TypeScript >=${minVersion} and <${maxVersion} but ${version} was found instead.`);
}
}