in tools/apiview/emitters/typespec-apiview/src/apiview.ts [524:879]
private tokenize(node: BaseNode) {
let obj;
let last = 0; // track the final index of an array
let parentNamespace: string;
switch (node.kind) {
case SyntaxKind.AliasStatement:
obj = node as AliasStatementNode;
this.namespaceStack.push(obj.id.sv);
this.keyword("alias", {HasSuffixSpace: true});
this.typeDeclaration(obj.id.sv, this.namespaceStack.value(), true);
this.tokenizeTemplateParameters(obj.templateParameters);
this.punctuation("=", {HasSuffixSpace: true, HasPrefixSpace: true});
this.tokenize(obj.value);
this.namespaceStack.pop();
break;
case SyntaxKind.ArrayExpression:
obj = node as ArrayExpressionNode;
this.tokenize(obj.elementType);
this.punctuation("[]");
break;
case SyntaxKind.ArrayLiteral:
obj = node as ArrayLiteralNode;
this.punctuation("#[");
last = obj.values.length - 1;
obj.values.forEach((val, i) => {
this.tokenize(val);
if (i !== last) {
this.punctuation(",", {HasSuffixSpace: true});
}
});
this.punctuation("]");
break;
case SyntaxKind.AugmentDecoratorStatement:
obj = node as AugmentDecoratorStatementNode;
const decoratorName = this.getNameForNode(obj.target);
this.namespaceStack.push(decoratorName);
this.punctuation("@@");
this.tokenizeIdentifier(obj.target, "keyword");
this.lineMarker();
if (obj.arguments.length) {
const last = obj.arguments.length - 1;
this.punctuation("(");
this.tokenize(obj.targetType);
if (obj.arguments.length) {
this.punctuation(",", {HasSuffixSpace: true});
}
for (let x = 0; x < obj.arguments.length; x++) {
const arg = obj.arguments[x];
this.tokenize(arg);
if (x !== last) {
this.punctuation(",", {HasSuffixSpace: true});
}
}
this.punctuation(")");
this.namespaceStack.pop();
}
break;
case SyntaxKind.BooleanLiteral:
obj = node as BooleanLiteralNode;
this.literal(obj.value.toString());
break;
case SyntaxKind.BlockComment:
throw new Error(`Case "BlockComment" not implemented`);
case SyntaxKind.TypeSpecScript:
throw new Error(`Case "TypeSpecScript" not implemented`);
case SyntaxKind.ConstStatement:
obj = node as ConstStatementNode;
this.namespaceStack.push(obj.id.sv);
this.keyword("const", {HasSuffixSpace: true});
this.tokenizeIdentifier(obj.id, "declaration");
this.punctuation("=", {HasSuffixSpace: true, HasPrefixSpace: true});
this.tokenize(obj.value);
this.namespaceStack.pop();
break;
case SyntaxKind.DecoratorExpression:
obj = node as DecoratorExpressionNode;
parentNamespace = this.namespaceStack.value();
this.namespaceStack.push(generateId(obj)!);
this.punctuation("@");
this.tokenizeIdentifier(obj.target, "keyword");
this.lineMarker({relatedLineId: parentNamespace});
if (obj.arguments.length) {
last = obj.arguments.length - 1;
this.punctuation("(");
for (let x = 0; x < obj.arguments.length; x++) {
const arg = obj.arguments[x];
this.tokenize(arg);
if (x !== last) {
this.punctuation(",", {HasSuffixSpace: true});
}
}
this.punctuation(")");
}
this.namespaceStack.pop();
break;
case SyntaxKind.DirectiveExpression:
obj = node as DirectiveExpressionNode;
parentNamespace = this.namespaceStack.value();
this.namespaceStack.push(generateId(node)!);
this.lineMarker({relatedLineId: parentNamespace});
this.keyword(`#${obj.target.sv}`, {HasSuffixSpace: true});
for (const arg of obj.arguments) {
switch (arg.kind) {
case SyntaxKind.StringLiteral:
this.stringLiteral(arg.value, {HasSuffixSpace: true});
break;
case SyntaxKind.Identifier:
this.stringLiteral(arg.sv, {HasSuffixSpace: true});
break;
}
}
this.newline();
this.namespaceStack.pop();
break;
case SyntaxKind.EmptyStatement:
throw new Error(`Case "EmptyStatement" not implemented`);
case SyntaxKind.EnumMember:
obj = node as EnumMemberNode;
this.tokenizeDecoratorsAndDirectives(obj.decorators, obj.directives, false);
this.tokenizeIdentifier(obj.id, "member");
this.lineMarker({addCrossLanguageId: true});
if (obj.value) {
this.punctuation(":", {HasSuffixSpace: true});
this.tokenize(obj.value);
}
break;
case SyntaxKind.EnumSpreadMember:
obj = node as EnumSpreadMemberNode;
this.punctuation("...");
this.tokenize(obj.target);
this.lineMarker();
break;
case SyntaxKind.EnumStatement:
this.tokenizeEnumStatement(node as EnumStatementNode);
break;
case SyntaxKind.JsNamespaceDeclaration:
throw new Error(`Case "JsNamespaceDeclaration" not implemented`);
case SyntaxKind.JsSourceFile:
throw new Error(`Case "JsSourceFile" not implemented`);
case SyntaxKind.Identifier:
obj = node as IdentifierNode;
const id = this.namespaceStack.value();
this.typeReference(obj.sv, {NavigateToId: id});
break;
case SyntaxKind.ImportStatement:
throw new Error(`Case "ImportStatement" not implemented`);
case SyntaxKind.IntersectionExpression:
obj = node as IntersectionExpressionNode;
for (let x = 0; x < obj.options.length; x++) {
const opt = obj.options[x];
this.tokenize(opt);
if (x !== obj.options.length - 1) {
this.punctuation("&", {HasPrefixSpace: true, HasSuffixSpace: true});
}
}
break;
case SyntaxKind.InterfaceStatement:
this.tokenizeInterfaceStatement(node as InterfaceStatementNode);
break;
case SyntaxKind.InvalidStatement:
throw new Error(`Case "InvalidStatement" not implemented`);
case SyntaxKind.LineComment:
throw new Error(`Case "LineComment" not implemented`);
case SyntaxKind.MemberExpression:
this.tokenizeIdentifier(node as MemberExpressionNode, "reference");
break;
case SyntaxKind.ModelExpression:
this.indent();
this.tokenizeModelExpression(node as ModelExpressionNode, {isOperationSignature: false});
this.deindent();
break;
case SyntaxKind.ModelProperty:
this.tokenizeModelProperty(node as ModelPropertyNode, false);
break;
case SyntaxKind.ModelSpreadProperty:
obj = node as ModelSpreadPropertyNode;
this.punctuation("...");
this.tokenize(obj.target);
this.lineMarker();
break;
case SyntaxKind.ModelStatement:
obj = node as ModelStatementNode;
this.tokenizeModelStatement(obj);
break;
case SyntaxKind.NamespaceStatement:
throw new Error(`Case "NamespaceStatement" not implemented`);
case SyntaxKind.NeverKeyword:
this.keyword("never");
break;
case SyntaxKind.NumericLiteral:
obj = node as NumericLiteralNode;
this.literal(obj.value.toString());
break;
case SyntaxKind.ObjectLiteral:
obj = node as ObjectLiteralNode;
this.punctuation("#{");
this.indent();
last = obj.properties.length - 1;
obj.properties.forEach((prop, i) => {
this.tokenize(prop);
if (i !== last) {
this.punctuation(",", {HasSuffixSpace: false});
}
this.newline();
});
this.deindent();
this.punctuation("}");
break;
case SyntaxKind.ObjectLiteralProperty:
obj = node as ObjectLiteralPropertyNode;
this.tokenizeIdentifier(obj.id, "member");
this.punctuation(":", {HasSuffixSpace: true});
this.tokenize(obj.value);
break;
case SyntaxKind.ObjectLiteralSpreadProperty:
obj = node as ObjectLiteralSpreadPropertyNode;
// TODO: Whenever there is an example?
throw new Error(`Case "ObjectLiteralSpreadProperty" not implemented`);
case SyntaxKind.OperationStatement:
this.tokenizeOperationStatement(node as OperationStatementNode);
break;
case SyntaxKind.OperationSignatureDeclaration:
obj = node as OperationSignatureDeclarationNode;
this.punctuation("(");
if (obj.parameters.properties.length) {
this.indent();
this.tokenizeModelExpression(obj.parameters, {isOperationSignature: true});
this.deindent();
}
this.punctuation("):", {HasSuffixSpace: true});
this.tokenizeReturnType(obj, {isExpanded: true});
break;
case SyntaxKind.OperationSignatureReference:
obj = node as OperationSignatureReferenceNode;
this.keyword("is", {HasPrefixSpace: true, HasSuffixSpace: true});
this.tokenize(obj.baseOperation);
break;
case SyntaxKind.Return:
throw new Error(`Case "Return" not implemented`);
case SyntaxKind.StringLiteral:
obj = node as StringLiteralNode;
this.stringLiteral(obj.value);
break;
case SyntaxKind.ScalarStatement:
this.tokenizeScalarStatement(node as ScalarStatementNode);
break;
case SyntaxKind.TemplateParameterDeclaration:
obj = node as TemplateParameterDeclarationNode;
this.tokenize(obj.id);
if (obj.constraint) {
this.keyword("extends", {HasSuffixSpace: true, HasPrefixSpace: true});
this.tokenize(obj.constraint);
}
if (obj.default) {
this.punctuation("=", {HasSuffixSpace: true, HasPrefixSpace: true});
this.tokenize(obj.default);
}
break;
case SyntaxKind.TupleExpression:
obj = node as TupleExpressionNode;
this.punctuation("[", {HasSuffixSpace: true});
for (let x = 0; x < obj.values.length; x++) {
const val = obj.values[x];
this.tokenize(val);
if (x !== obj.values.length - 1) {
this.punctuation(",", {HasSuffixSpace: true});
}
}
this.punctuation("]");
break;
case SyntaxKind.TypeReference:
obj = node as TypeReferenceNode;
this.tokenizeIdentifier(obj.target, "reference");
this.tokenizeTemplateInstantiation(obj);
break;
case SyntaxKind.UnionExpression:
obj = node as UnionExpressionNode;
for (let x = 0; x < obj.options.length; x++) {
const opt = obj.options[x];
this.tokenize(opt);
if (x !== obj.options.length - 1) {
this.punctuation("|", {HasPrefixSpace: true, HasSuffixSpace: true});
}
}
break;
case SyntaxKind.UnionStatement:
this.tokenizeUnionStatement(node as UnionStatementNode);
break;
case SyntaxKind.UnionVariant:
this.tokenizeUnionVariant(node as UnionVariantNode);
break;
case SyntaxKind.UnknownKeyword:
this.keyword("unknown");
break;
case SyntaxKind.UsingStatement:
throw new Error(`Case "UsingStatement" not implemented`);
case SyntaxKind.ValueOfExpression:
this.keyword("valueof", {HasSuffixSpace: true});
this.tokenize((node as ValueOfExpressionNode).target);
break;
case SyntaxKind.VoidKeyword:
this.keyword("void");
break;
case SyntaxKind.TemplateArgument:
case SyntaxKind.StringTemplateExpression:
obj = node as StringTemplateExpressionNode;
const stringValue = this.buildTemplateString(obj);
const multiLine = stringValue.includes("\n");
// single line case
if (!multiLine) {
this.stringLiteral(stringValue);
break;
}
// otherwise multiline case
const lines = stringValue.split("\n");
this.punctuation(`"""`);
this.indent();
for (const line of lines) {
this.literal(line);
this.newline();
}
this.deindent();
this.punctuation(`"""`);
break;
case SyntaxKind.StringTemplateSpan:
obj = node as StringTemplateSpanNode;
this.punctuation("${");
this.tokenize(obj.expression);
this.punctuation("}");
this.tokenize(obj.literal);
break;
case SyntaxKind.StringTemplateHead:
case SyntaxKind.StringTemplateMiddle:
case SyntaxKind.StringTemplateTail:
obj = node as StringTemplateHeadNode;
this.literal(obj.value);
break;
case SyntaxKind.CallExpression:
obj = node as CallExpressionNode;
this.tokenize(obj.target);
this.punctuation("(", {HasSuffixSpace: false});
for (let x = 0; x < obj.arguments.length; x++) {
const arg = obj.arguments[x];
this.tokenize(arg);
if (x !== obj.arguments.length - 1) {
this.punctuation(",", {HasSuffixSpace: true, snapTo: "}"});
}
}
this.punctuation(")");
break;
default:
// All Projection* cases should fail here...
throw new Error(`Case "${SyntaxKind[node.kind].toString()}" not implemented`);
}
}