@typespec/compiler
Version:
TypeSpec Compiler Preview
171 lines • 7.24 kB
JavaScript
import { getSymNode } from "../core/binder.js";
import { compilerAssert } from "../core/diagnostics.js";
import { printIdentifier } from "../core/helpers/syntax-utils.js";
import { getEntityName, getTypeName, isStdNamespace } from "../core/helpers/type-name-utils.js";
import { getFullyQualifiedSymbolName } from "../core/type-utils.js";
import { SyntaxKind, } from "../core/types.js";
import { walkPropertiesInherited } from "../index.js";
/** @internal */
export function getSymbolSignature(program, sym, options = {
includeBody: false,
}) {
const decl = getSymNode(sym);
switch (decl?.kind) {
case SyntaxKind.AliasStatement:
return fence(`alias ${getAliasSignature(decl)}`);
}
const entity = sym.type ?? program.checker.getTypeOrValueForNode(decl);
return getEntitySignature(sym, entity, options);
}
function getEntitySignature(sym, entity, options) {
if (entity === null) {
return "(error)";
}
if ("valueKind" in entity) {
return fence(`const ${sym.name}: ${getTypeName(entity.type)}`);
}
return getTypeSignature(entity, options);
}
function getTypeSignature(type, options) {
switch (type.kind) {
case "Scalar":
case "Enum":
case "Union":
case "Namespace":
return fence(`${type.kind.toLowerCase()} ${getPrintableTypeName(type)}`);
case "Interface":
return fence(getInterfaceSignature(type, options.includeBody));
case "Model":
return fence(getModelSignature(type, options.includeBody));
case "ScalarConstructor":
return fence(`init ${getTypeSignature(type.scalar, options)}.${type.name}`);
case "Decorator":
return fence(getDecoratorSignature(type));
case "Operation":
return fence(getOperationSignature(type));
case "String":
// BUG: https://github.com/microsoft/typespec/issues/1350 - should escape string literal values
return `(string)\n${fence(`"${type.value}"`)}`;
case "Boolean":
return `(boolean)\n${fence(type.value ? "true" : "false")}`;
case "Number":
return `(number)\n${fence(type.value.toString())}`;
case "StringTemplate":
return `(string template)\n${fence(getStringTemplateSignature(type))}`;
case "StringTemplateSpan":
return `(string template span)\n${fence(getTypeName(type.type))}`;
case "Intrinsic":
return "";
case "FunctionParameter":
return `(function parameter)\n${fence(getFunctionParameterSignature(type))}`;
case "ModelProperty":
return `(model property)\n${fence(getModelPropertySignature(type))}`;
case "EnumMember":
return `(enum member)\n${fence(getEnumMemberSignature(type))}`;
case "TemplateParameter":
return `(template parameter)\n${fence(type.node.id.sv)}`;
case "UnionVariant":
return `(union variant)\n${fence(getUnionVariantSignature(type))}`;
case "Tuple":
return `(tuple)\n[${fence(type.values.map((v) => getTypeSignature(v, options)).join(", "))}]`;
default:
const _assertNever = type;
compilerAssert(false, "Unexpected type kind");
}
}
function getDecoratorSignature(type) {
const ns = getQualifier(type.namespace);
const name = type.name.slice(1);
const parameters = [type.target, ...type.parameters].map((x) => getFunctionParameterSignature(x));
return `dec ${ns}${name}(${parameters.join(", ")})`;
}
function getOperationSignature(type, includeQualifier = true) {
const parameters = [...type.parameters.properties.values()].map((p) => getModelPropertySignature(p, false /* includeQualifier */));
return `op ${getTypeName(type, {
nameOnly: !includeQualifier,
})}(${parameters.join(", ")}): ${getPrintableTypeName(type.returnType)}`;
}
function getInterfaceSignature(type, includeBody) {
if (includeBody) {
const INDENT = " ";
const opDesc = Array.from(type.operations).map(([name, op]) => INDENT + getOperationSignature(op, false /* includeQualifier */) + ";");
return `${type.kind.toLowerCase()} ${getPrintableTypeName(type)} {\n${opDesc.join("\n")}\n}`;
}
else {
return `${type.kind.toLowerCase()} ${getPrintableTypeName(type)}`;
}
}
/**
* All properties from 'extends' and 'is' will be included if includeBody is true.
*/
function getModelSignature(type, includeBody) {
if (includeBody) {
const propDesc = [];
const INDENT = " ";
for (const prop of walkPropertiesInherited(type)) {
propDesc.push(INDENT + getModelPropertySignature(prop, false /*includeQualifier*/));
}
return `${type.kind.toLowerCase()} ${getPrintableTypeName(type)}{\n${propDesc.map((d) => `${d};`).join("\n")}\n}`;
}
else {
return `${type.kind.toLowerCase()} ${getPrintableTypeName(type)}`;
}
}
function getFunctionParameterSignature(parameter) {
const rest = parameter.rest ? "..." : "";
const optional = parameter.optional ? "?" : "";
return `${rest}${printIdentifier(parameter.name, "allow-reserved")}${optional}: ${getEntityName(parameter.type)}`;
}
function getStringTemplateSignature(stringTemplate) {
return ("`" +
[
stringTemplate.spans.map((span) => {
return span.isInterpolated ? "${" + getTypeName(span.type) + "}" : span.type.value;
}),
].join("") +
"`");
}
function getModelPropertySignature(property, includeQualifier = true) {
const ns = includeQualifier ? getQualifier(property.model) : "";
return `${ns}${printIdentifier(property.name, "allow-reserved")}: ${getPrintableTypeName(property.type)}`;
}
function getUnionVariantSignature(variant) {
if (typeof variant.name !== "string") {
return getPrintableTypeName(variant.type);
}
const ns = getQualifier(variant.union);
return `${ns}${printIdentifier(variant.name, "allow-reserved")}: ${getPrintableTypeName(variant.type)}`;
}
function getEnumMemberSignature(member) {
const ns = getQualifier(member.enum);
const value = typeof member.value === "string" ? `"${member.value}"` : member.value;
return value === undefined
? `${ns}${printIdentifier(member.name, "allow-reserved")}`
: `${ns}${printIdentifier(member.name, "allow-reserved")}: ${value}`;
}
function getAliasSignature(alias) {
const fullName = getFullyQualifiedSymbolName(alias.symbol);
const args = alias.templateParameters.map((t) => t.id.sv);
return args.length === 0 ? fullName : `${fullName}<${args.join(", ")}>`;
}
function getQualifier(parent) {
if (!parent?.name ||
typeof parent.name !== "string" ||
(parent.kind === "Namespace" && isStdNamespace(parent))) {
return "";
}
const parentName = getPrintableTypeName(parent);
if (!parentName) {
return "";
}
return parentName + ".";
}
function getPrintableTypeName(type) {
return getTypeName(type, {
printable: true,
});
}
function fence(code) {
return `\`\`\`typespec\n${code}\n\`\`\``;
}
//# sourceMappingURL=type-signature.js.map