Skip to content

Commit 1cb79d8

Browse files
committed
Make directives commentable.
1 parent a60c86f commit 1cb79d8

File tree

1 file changed

+84
-54
lines changed
  • tools/apiview/emitters/typespec-apiview/src

1 file changed

+84
-54
lines changed

tools/apiview/emitters/typespec-apiview/src/apiview.ts

Lines changed: 84 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export const enum ApiViewTokenKind {
6666
DeprecatedRangeStart = 13,
6767
DeprecatedRangeEnd = 14,
6868
SkipDiffRangeStart = 15,
69-
SkipDiffRangeEnd = 16
69+
SkipDiffRangeEnd = 16,
7070
}
7171

7272
export interface ApiViewToken {
@@ -138,7 +138,7 @@ export class ApiView {
138138
}
139139

140140
trim() {
141-
let last = this.tokens[this.tokens.length - 1]
141+
let last = this.tokens[this.tokens.length - 1];
142142
while (last) {
143143
if (last.Kind === ApiViewTokenKind.Whitespace) {
144144
this.tokens.pop();
@@ -297,7 +297,7 @@ export class ApiView {
297297
this.tokens.push({
298298
Kind: ApiViewTokenKind.StringLiteral,
299299
Value: `\u0022${value}\u0022`,
300-
});
300+
});
301301
} else {
302302
this.punctuation(`"""`);
303303
this.newline();
@@ -359,7 +359,7 @@ export class ApiView {
359359
const nsModel = new NamespaceModel(namespaceName, ns, program);
360360
if (nsModel.shouldEmit()) {
361361
this.tokenizeNamespaceModel(nsModel);
362-
this.buildNavigation(nsModel);
362+
this.buildNavigation(nsModel);
363363
}
364364
}
365365
}
@@ -379,6 +379,7 @@ export class ApiView {
379379

380380
tokenize(node: BaseNode) {
381381
let obj;
382+
let isExpanded = false;
382383
switch (node.kind) {
383384
case SyntaxKind.AliasStatement:
384385
obj = node as AliasStatementNode;
@@ -448,6 +449,7 @@ export class ApiView {
448449
break;
449450
case SyntaxKind.DirectiveExpression:
450451
obj = node as DirectiveExpressionNode;
452+
this.namespaceStack.push(generateId(node)!);
451453
this.keyword(`#${obj.target.sv}`, false, true);
452454
for (const arg of obj.arguments) {
453455
switch (arg.kind) {
@@ -462,6 +464,7 @@ export class ApiView {
462464
}
463465
}
464466
this.newline();
467+
this.namespaceStack.pop();
465468
break;
466469
case SyntaxKind.EmptyStatement:
467470
throw new Error(`Case "EmptyStatement" not implemented`);
@@ -591,10 +594,30 @@ export class ApiView {
591594
this.punctuation("]", true, false);
592595
break;
593596
case SyntaxKind.TypeReference:
597+
598+
// if (isExpanded) {
599+
// this.newline();
600+
// this.indent();
601+
// }
602+
// if (obj.name) {
603+
// this.text(obj.name.sv);
604+
// this.punctuation("=", true, true);
605+
// }
606+
// if (isExpanded) {
607+
// this.tokenizeModelExpressionExpanded(obj.argument as ModelExpressionNode, false, false);
608+
// this.deindent();
609+
// } else {
610+
// this.tokenize(obj.argument);
611+
// }
594612
obj = node as TypeReferenceNode;
613+
isExpanded = this.isTemplateExpanded(obj);
595614
this.tokenizeIdentifier(obj.target, "reference");
596615
if (obj.arguments.length) {
597-
this.punctuation("<", false, false);
616+
this.punctuation("<", false, false);
617+
if (isExpanded) {
618+
this.newline();
619+
this.indent();
620+
}
598621
for (let x = 0; x < obj.arguments.length; x++) {
599622
const arg = obj.arguments[x];
600623
this.tokenize(arg);
@@ -610,7 +633,7 @@ export class ApiView {
610633
for (let x = 0; x < obj.options.length; x++) {
611634
const opt = obj.options[x];
612635
this.tokenize(opt);
613-
if (x !== obj.options.length -1) {
636+
if (x !== obj.options.length - 1) {
614637
this.punctuation("|", true, true);
615638
}
616639
}
@@ -635,20 +658,20 @@ export class ApiView {
635658
break;
636659
case SyntaxKind.TemplateArgument:
637660
obj = node as TemplateArgumentNode;
638-
const isExpanded = obj.argument.kind === SyntaxKind.ModelExpression;
661+
isExpanded = false;//obj.argument.kind === SyntaxKind.ModelExpression;
639662
if (isExpanded) {
640-
this.newline();
641-
this.indent();
663+
this.newline();
664+
this.indent();
642665
}
643666
if (obj.name) {
644-
this.text(obj.name.sv);
645-
this.punctuation("=", true, true);
667+
this.text(obj.name.sv);
668+
this.punctuation("=", true, true);
646669
}
647670
if (isExpanded) {
648-
this.tokenizeModelExpressionExpanded(obj.argument as ModelExpressionNode, false, false);
649-
this.deindent();
671+
this.tokenizeModelExpressionExpanded(obj.argument as ModelExpressionNode, false, false);
672+
this.deindent();
650673
} else {
651-
this.tokenize(obj.argument);
674+
this.tokenize(obj.argument);
652675
}
653676
break;
654677
case SyntaxKind.StringTemplateExpression:
@@ -796,7 +819,7 @@ export class ApiView {
796819
for (let x = 0; x < node.operations.length; x++) {
797820
const op = node.operations[x];
798821
this.tokenizeOperationStatement(op, true);
799-
this.blankLines((x !== node.operations.length -1) ? 1 : 0);
822+
this.blankLines(x !== node.operations.length - 1 ? 1 : 0);
800823
}
801824
this.endGroup();
802825
this.namespaceStack.pop();
@@ -881,7 +904,7 @@ export class ApiView {
881904
if (isOperationSignature) {
882905
if (x !== node.properties.length - 1) {
883906
this.punctuation(",", false, true);
884-
}
907+
}
885908
} else {
886909
this.punctuation(";");
887910
}
@@ -892,7 +915,11 @@ export class ApiView {
892915
}
893916
}
894917

895-
private tokenizeModelExpressionExpanded(node: ModelExpressionNode, isOperationSignature: boolean, leadingNewline: boolean) {
918+
private tokenizeModelExpressionExpanded(
919+
node: ModelExpressionNode,
920+
isOperationSignature: boolean,
921+
leadingNewline: boolean,
922+
) {
896923
if (node.properties.length) {
897924
if (leadingNewline) {
898925
this.blankLines(0);
@@ -901,7 +928,7 @@ export class ApiView {
901928
if (!isOperationSignature) {
902929
this.punctuation("{", false, false);
903930
this.blankLines(0);
904-
this.indent();
931+
this.indent();
905932
}
906933
this.namespaceStack.push("anonymous");
907934
for (let x = 0; x < node.properties.length; x++) {
@@ -918,8 +945,9 @@ export class ApiView {
918945
this.namespaceStack.pop();
919946
if (isOperationSignature) {
920947
if (x !== node.properties.length - 1) {
948+
this.trim();
921949
this.renderPunctuation(",");
922-
}
950+
}
923951
} else {
924952
this.renderPunctuation(";");
925953
}
@@ -930,27 +958,22 @@ export class ApiView {
930958
if (!isOperationSignature) {
931959
this.deindent();
932960
this.punctuation("}", false, false);
933-
this.blankLines(0);
961+
this.blankLines(0);
934962
}
935963
this.trim();
936964
if (leadingNewline) {
937965
this.deindent();
938966
}
939-
940967
} else if (!isOperationSignature) {
941968
this.punctuation("{}", true, false);
942969
}
943970
}
944971

945-
private tokenizeModelExpression(
946-
node: ModelExpressionNode,
947-
isOperationSignature: boolean,
948-
inline: boolean
949-
) {
972+
private tokenizeModelExpression(node: ModelExpressionNode, isOperationSignature: boolean, inline: boolean) {
950973
if (inline) {
951-
this.tokenizeModelExpressionInline(node, isOperationSignature)
974+
this.tokenizeModelExpressionInline(node, isOperationSignature);
952975
} else {
953-
this.tokenizeModelExpressionExpanded(node, isOperationSignature, true)
976+
this.tokenizeModelExpressionExpanded(node, isOperationSignature, true);
954977
}
955978
}
956979

@@ -970,7 +993,7 @@ export class ApiView {
970993
private tokenizeNamespaceModel(model: NamespaceModel) {
971994
this.namespaceStack.push(model.name);
972995
if (model.node.kind === SyntaxKind.NamespaceStatement) {
973-
this.tokenizeDecoratorsAndDirectives(model.node.decorators, model.node.directives, false);
996+
this.tokenizeDecoratorsAndDirectives(model.node.decorators, model.node.directives, false);
974997
}
975998
this.keyword("namespace", false, true);
976999
this.typeDeclaration(model.name, this.namespaceStack.value(), true);
@@ -992,19 +1015,23 @@ export class ApiView {
9921015
this.blankLines(1);
9931016
}
9941017
for (const node of model.aliases.values()) {
995-
this.tokenize(node);
996-
this.punctuation(";");
997-
this.blankLines(1);
998-
}
1018+
this.tokenize(node);
1019+
this.punctuation(";");
1020+
this.blankLines(1);
1021+
}
9991022
this.endGroup();
10001023
this.blankLines(1);
10011024
this.namespaceStack.pop();
10021025
}
10031026

1004-
private tokenizeDecoratorsAndDirectives(decorators: readonly DecoratorExpressionNode[] | undefined, directives: readonly DirectiveExpressionNode[] | undefined, inline: boolean) {
1005-
const docDecorators = ["doc", "summary", "example"]
1027+
private tokenizeDecoratorsAndDirectives(
1028+
decorators: readonly DecoratorExpressionNode[] | undefined,
1029+
directives: readonly DirectiveExpressionNode[] | undefined,
1030+
inline: boolean,
1031+
) {
1032+
const docDecorators = ["doc", "summary", "example"];
10061033
if ((directives || []).length === 0 && (decorators || []).length === 0) {
1007-
return;
1034+
return;
10081035
}
10091036
for (const directive of directives ?? []) {
10101037
this.tokenize(directive);
@@ -1028,11 +1055,11 @@ export class ApiView {
10281055
// render each decorator
10291056
for (const node of decorators || []) {
10301057
this.namespaceStack.push(generateId(node)!);
1031-
const isDoc = docDecorators.includes((node.target as IdentifierNode).sv)
1058+
const isDoc = docDecorators.includes((node.target as IdentifierNode).sv);
10321059
if (isDoc) {
10331060
this.tokens.push({
1034-
Kind: ApiViewTokenKind.DocumentRangeStart
1035-
})
1061+
Kind: ApiViewTokenKind.DocumentRangeStart,
1062+
});
10361063
}
10371064
this.tokenize(node);
10381065
if (inline) {
@@ -1044,8 +1071,8 @@ export class ApiView {
10441071
}
10451072
if (isDoc) {
10461073
this.tokens.push({
1047-
Kind: ApiViewTokenKind.DocumentRangeEnd
1048-
})
1074+
Kind: ApiViewTokenKind.DocumentRangeEnd,
1075+
});
10491076
}
10501077
}
10511078
}
@@ -1061,7 +1088,7 @@ export class ApiView {
10611088

10621089
private tokenizeIdentifier(
10631090
node: IdentifierNode | MemberExpressionNode | StringLiteralNode,
1064-
style: "declaration" | "reference" | "member" | "keyword"
1091+
style: "declaration" | "reference" | "member" | "keyword",
10651092
) {
10661093
switch (node.kind) {
10671094
case SyntaxKind.MemberExpression:
@@ -1099,7 +1126,7 @@ export class ApiView {
10991126
this.member(this.getRawText(node));
11001127
break;
11011128
case "keyword":
1102-
this.keyword(node.sv)
1129+
this.keyword(node.sv);
11031130
break;
11041131
}
11051132
}
@@ -1109,10 +1136,17 @@ export class ApiView {
11091136
return getSourceLocation(node).file.text.slice(node.pos, node.end);
11101137
}
11111138

1139+
private isTemplateExpanded(node: TypeReferenceNode): boolean {
1140+
if (node.arguments.length === 0) {
1141+
return false;
1142+
}
1143+
const first = node.arguments[0];
1144+
return first.argument.kind === SyntaxKind.ModelExpression;
1145+
}
11121146

11131147
private tokenizeTemplateParameters(nodes: readonly TemplateParameterDeclarationNode[]) {
11141148
if (nodes.length) {
1115-
this.punctuation("<", false, false);
1149+
this.punctuation("<", false, false);
11161150
for (let x = 0; x < nodes.length; x++) {
11171151
const param = nodes[x];
11181152
this.tokenize(param);
@@ -1130,7 +1164,10 @@ export class ApiView {
11301164
const offset = this.tokens.length;
11311165
this.tokenize(node.returnType);
11321166
const returnTokens = this.tokens.slice(offset);
1133-
const returnTypeString = returnTokens.filter((x) => x.Value).flatMap((x) => x.Value).join("");
1167+
const returnTypeString = returnTokens
1168+
.filter((x) => x.Value)
1169+
.flatMap((x) => x.Value)
1170+
.join("");
11341171
this.namespaceStack.push(returnTypeString);
11351172
this.lineMarker();
11361173
this.namespaceStack.pop();
@@ -1154,13 +1191,6 @@ export class ApiView {
11541191
}
11551192

11561193
private renderPunctuation(punctuation: string) {
1157-
const last = this.tokens.pop()!;
1158-
if (last?.Kind === ApiViewTokenKind.Whitespace) {
1159-
// hacky workaround to ensure comma is after trailing bracket for expanded anonymous models
1160-
this.tokens.pop();
1161-
} else {
1162-
this.tokens.push(last);
1163-
}
11641194
this.punctuation(punctuation, false, true);
11651195
}
11661196

@@ -1181,7 +1211,7 @@ export class ApiView {
11811211
Diagnostics: this.diagnostics,
11821212
VersionString: this.versionString,
11831213
Language: "TypeSpec",
1184-
CrossLanguagePackageId: this.crossLanguagePackageId
1214+
CrossLanguagePackageId: this.crossLanguagePackageId,
11851215
};
11861216
}
11871217

@@ -1217,4 +1247,4 @@ export class NamespaceStack {
12171247
reset() {
12181248
this.stack = Array<string>();
12191249
}
1220-
};
1250+
}

0 commit comments

Comments
 (0)