@ng-doc/builder 22.0.0 → 22.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/LICENSE +21 -0
  2. package/engine/builders/helpers/get-playground-metadata.js +7 -1
  3. package/engine/builders/helpers/get-playground-metadata.js.map +1 -1
  4. package/engine/builders/page/demo-assets.builder.js +2 -0
  5. package/engine/builders/page/demo-assets.builder.js.map +1 -1
  6. package/engine/builders/shared/content.builder.js +2 -0
  7. package/engine/builders/shared/content.builder.js.map +1 -1
  8. package/engine/builders/shared/page-wrapper.builder.js +2 -0
  9. package/engine/builders/shared/page-wrapper.builder.js.map +1 -1
  10. package/generator/bootstrap/bin.js +174 -107
  11. package/generator/bootstrap/cli.js +174 -107
  12. package/generator/bootstrap/index.js +139 -99
  13. package/generator/bootstrap/process-tree.d.ts +5 -4
  14. package/generator/build-metafile.json +647 -240
  15. package/generator/build-provenance.json +6 -4
  16. package/generator/compiler/index.d.ts +20 -0
  17. package/generator/compiler/index.js +2400 -945
  18. package/generator/compiler/plan.d.ts +24 -0
  19. package/generator/content/code-snippet.d.ts +20 -0
  20. package/generator/content/content-compiler.d.ts +5 -1
  21. package/generator/content/format-cache.d.ts +108 -0
  22. package/generator/content/highlight-cache.d.ts +12 -36
  23. package/generator/content/html-pipeline.d.ts +10 -1
  24. package/generator/content/html-pool.d.ts +8 -2
  25. package/generator/content/html-worker.js +630 -39
  26. package/generator/contracts.d.ts +57 -0
  27. package/generator/discovery/index.d.ts +2 -0
  28. package/generator/kernel/flags.d.ts +5 -0
  29. package/generator/outputs/index.d.ts +29 -0
  30. package/generator/semantic/angular.d.ts +21 -1
  31. package/generator/semantic/formatting.d.ts +27 -0
  32. package/generator/semantic/fragments.d.ts +11 -2
  33. package/generator/templates/api/class-declaration.html.nunj +5 -3
  34. package/generator/templates/demo-app.ts.nunj +37 -0
  35. package/generator/templates/demo-routes.ts.nunj +43 -0
  36. package/generator/templates/index.ts.nunj +5 -0
  37. package/generator/templates/page-wrapper.ts.nunj +6 -1
  38. package/generator/templates/page.ts.nunj +13 -2
  39. package/generator/templates/routes.ts.nunj +7 -3
  40. package/generator/templates/symbol/members.html.nunj +6 -4
  41. package/generator/templates/symbol/page.html.nunj +1 -1
  42. package/generator/vite/angular/analog-provenance.json +1 -1
  43. package/generator/vite/angular-composition.d.ts +25 -1
  44. package/generator/vite/application-builder.js +6 -1
  45. package/generator/vite/application.d.ts +14 -0
  46. package/generator/vite/content-updates.d.ts +62 -0
  47. package/generator/vite/demo-application.d.ts +34 -0
  48. package/generator/vite/dev-server-builder.js +6 -1
  49. package/generator/vite/host-updates.d.ts +153 -6
  50. package/generator/vite/index.js +985 -247
  51. package/generator/vite/lifecycle.d.ts +40 -2
  52. package/generator/vite/prerender-entry.js +72 -2
  53. package/generator/vite/prerender-runtime.d.ts +13 -0
  54. package/generator/vite/prerender.d.ts +2 -0
  55. package/helpers/format-cache.d.ts +34 -0
  56. package/helpers/format-cache.js +26 -0
  57. package/helpers/format-cache.js.map +1 -0
  58. package/helpers/format-code.js +9 -2
  59. package/helpers/format-code.js.map +1 -1
  60. package/helpers/playground/get-playground-inputs.js +6 -3
  61. package/helpers/playground/get-playground-inputs.js.map +1 -1
  62. package/helpers/playground/playground-options.d.ts +28 -0
  63. package/helpers/playground/playground-options.js +122 -0
  64. package/helpers/playground/playground-options.js.map +1 -0
  65. package/helpers/playground/written-union-order.d.ts +33 -0
  66. package/helpers/playground/written-union-order.js +106 -0
  67. package/helpers/playground/written-union-order.js.map +1 -0
  68. package/helpers/to-template-string.d.ts +5 -1
  69. package/helpers/to-template-string.js +7 -2
  70. package/helpers/to-template-string.js.map +1 -1
  71. package/interfaces/code-block-options.d.ts +5 -0
  72. package/interfaces/configuration.d.ts +92 -1
  73. package/package.json +6 -5
  74. package/parsers/parse-code-block-params.d.ts +10 -1
  75. package/parsers/parse-code-block-params.js +29 -3
  76. package/parsers/parse-code-block-params.js.map +1 -1
  77. package/schematics/collection.json +1 -1
  78. package/schematics/migrate-to-vite/analyze.js +46 -3
  79. package/schematics/migrate-to-vite/analyze.js.map +1 -1
  80. package/schematics/migrate-to-vite/setup/workspace.d.ts +5 -0
  81. package/schematics/migrate-to-vite/setup/workspace.js +20 -0
  82. package/schematics/migrate-to-vite/setup/workspace.js.map +1 -1
  83. package/schematics/migrate-to-vite/testing/fixtures.d.ts +12 -0
  84. package/schematics/migrate-to-vite/testing/fixtures.js +27 -0
  85. package/schematics/migrate-to-vite/testing/fixtures.js.map +1 -1
  86. package/schematics/vite-setup/index.d.ts +9 -5
  87. package/schematics/vite-setup/index.js +11 -5
  88. package/schematics/vite-setup/index.js.map +1 -1
  89. package/schematics/vite-setup/schema.json +1 -1
  90. package/templates/api/class-declaration.html.nunj +5 -3
  91. package/templates/demo-app.ts.nunj +37 -0
  92. package/templates/demo-routes.ts.nunj +43 -0
  93. package/templates/index.ts.nunj +5 -0
  94. package/templates/page-wrapper.ts.nunj +6 -1
  95. package/templates/page.ts.nunj +13 -2
  96. package/templates/routes.ts.nunj +7 -3
  97. package/templates/symbol/members.html.nunj +6 -4
  98. package/templates/symbol/page.html.nunj +1 -1
@@ -387,6 +387,13 @@ var init_kebab_case = __esm({
387
387
  }
388
388
  });
389
389
 
390
+ // libs/core/helpers/playground-target-slugs.ts
391
+ var init_playground_target_slugs = __esm({
392
+ "libs/core/helpers/playground-target-slugs.ts"() {
393
+ "use strict";
394
+ }
395
+ });
396
+
390
397
  // libs/core/helpers/stringify.ts
391
398
  var init_stringify = __esm({
392
399
  "libs/core/helpers/stringify.ts"() {
@@ -428,6 +435,7 @@ var init_helpers = __esm({
428
435
  init_is_same_object();
429
436
  init_kebab_case();
430
437
  init_object_keys();
438
+ init_playground_target_slugs();
431
439
  init_stringify();
432
440
  init_uid();
433
441
  init_unique();
@@ -776,6 +784,329 @@ var init_helpers2 = __esm({
776
784
  }
777
785
  });
778
786
 
787
+ // libs/utils/html/plugins/keyword-positions.ts
788
+ function scanInlineCode(text) {
789
+ if (WHOLE_KEYWORD.test(text)) {
790
+ return { whole: true, position: () => REFERENCE };
791
+ }
792
+ if (HTML_START.test(text) || !(CODE_PUNCTUATION.test(text) || DECLARATION_START.test(text))) {
793
+ return void 0;
794
+ }
795
+ const scan = scanTypeScript(text);
796
+ return isProse(text, scan.masked) ? void 0 : scan;
797
+ }
798
+ function scanCodeBlock(text, mode) {
799
+ return mode === "html" ? scanHtml(text) : scanTypeScript(text);
800
+ }
801
+ function scanTypeScript(text) {
802
+ const masked = maskTypeScript(text);
803
+ const locals = localBindings(text, masked);
804
+ return {
805
+ whole: false,
806
+ masked,
807
+ position(start, end, key) {
808
+ if (masked[start] === TEMPLATE) {
809
+ const before = text[start - 1] ?? "";
810
+ const element = key.includes("-") && (before === "<" || before === "/" && text[start - 2] === "<");
811
+ const controlFlow = CONTROL_FLOW.test(key) && !WORD_CHARACTER.test(before);
812
+ return element || controlFlow ? REFERENCE : NOT_A_REFERENCE;
813
+ }
814
+ if (masked[start] !== CODE) {
815
+ return NOT_A_REFERENCE;
816
+ }
817
+ const previous = previousSignificant(text, start, masked);
818
+ const next = nextSignificant(text, end, masked);
819
+ const nextCharacter = text[next] ?? "";
820
+ if (SYNTAX_WORDS.has(key) || RESERVED_WORDS.has(key) && nextCharacter !== "(") {
821
+ return NOT_A_REFERENCE;
822
+ }
823
+ if (text[previous] === "." && text[previous - 1] !== ".") {
824
+ const ownerEnd = text[previous - 1] === "?" ? previous - 1 : previous;
825
+ const owner = text.slice(0, ownerEnd).match(IDENTIFIER_BEFORE)?.[0];
826
+ const word = text.slice(start, end);
827
+ return owner && !/[.#]/.test(word) ? { link: true, keyword: `${owner}.${key.toLowerCase()}` } : NOT_A_REFERENCE;
828
+ }
829
+ if (isDeclaredName(text, masked, previous, next)) {
830
+ return NOT_A_REFERENCE;
831
+ }
832
+ return locals.has(key) ? NOT_A_REFERENCE : REFERENCE;
833
+ }
834
+ };
835
+ }
836
+ function isDeclaredName(text, masked, previous, next) {
837
+ const after = text[next];
838
+ const afterNext = text[nextSignificant(text, next + 1, masked)];
839
+ if (after === ":" && text[next + 1] !== ":") {
840
+ const ternary = text[previous] === "?" && text[previous + 1] !== ".";
841
+ return !ternary && previousWord(text, previous) !== "case";
842
+ }
843
+ if ((after === "?" || after === "!") && afterNext === ":") {
844
+ return true;
845
+ }
846
+ if (after === "?" && (afterNext === ")" || afterNext === ",")) {
847
+ return true;
848
+ }
849
+ if (after === "=" && text[next + 1] !== "=" && text[next + 1] !== ">") {
850
+ return !TYPE_CONTEXT.includes(text[previous] ?? "") && !TYPE_WORDS.includes(previousWord(text, previous));
851
+ }
852
+ return false;
853
+ }
854
+ function scanHtml(text) {
855
+ const masked = maskHtml(text);
856
+ return {
857
+ whole: false,
858
+ position: (start) => masked[start] === CODE ? REFERENCE : NOT_A_REFERENCE
859
+ };
860
+ }
861
+ function maskTypeScript(text) {
862
+ const masked = new Uint8Array(text.length);
863
+ const templates = [];
864
+ let depth = 0;
865
+ let index = 0;
866
+ const string = (quote) => {
867
+ const start = index++;
868
+ while (index < text.length && text[index] !== quote && text[index] !== "\n") {
869
+ index += text[index] === "\\" ? 2 : 1;
870
+ }
871
+ masked.fill(STRING, start, Math.min(++index, text.length));
872
+ };
873
+ const template = () => {
874
+ const start = index++;
875
+ while (index < text.length && text[index] !== "`") {
876
+ if (text[index] === "\\") {
877
+ index += 2;
878
+ } else if (text[index] === "$" && text[index + 1] === "{") {
879
+ masked.fill(TEMPLATE, start, index);
880
+ templates.push(depth);
881
+ index += 2;
882
+ return;
883
+ } else {
884
+ index++;
885
+ }
886
+ }
887
+ masked.fill(TEMPLATE, start, Math.min(++index, text.length));
888
+ };
889
+ while (index < text.length) {
890
+ const character = text[index];
891
+ if (character === "/" && text[index + 1] === "/") {
892
+ const end = text.indexOf("\n", index);
893
+ const stop = end < 0 ? text.length : end;
894
+ masked.fill(COMMENT, index, stop);
895
+ index = stop;
896
+ } else if (character === "/" && text[index + 1] === "*") {
897
+ const end = text.indexOf("*/", index + 2);
898
+ const stop = end < 0 ? text.length : end + 2;
899
+ masked.fill(COMMENT, index, stop);
900
+ index = stop;
901
+ } else if (character === "'" || character === '"') {
902
+ string(character);
903
+ } else if (character === "`") {
904
+ template();
905
+ } else if (character === "{") {
906
+ depth++;
907
+ index++;
908
+ } else if (character === "}") {
909
+ if (templates.length && templates[templates.length - 1] === depth) {
910
+ templates.pop();
911
+ template();
912
+ } else {
913
+ depth--;
914
+ index++;
915
+ }
916
+ } else {
917
+ index++;
918
+ }
919
+ }
920
+ return masked;
921
+ }
922
+ function maskHtml(text) {
923
+ const masked = new Uint8Array(text.length);
924
+ let index = 0;
925
+ while (index < text.length) {
926
+ if (text.startsWith("<!--", index)) {
927
+ const end = text.indexOf("-->", index + 4);
928
+ const stop = end < 0 ? text.length : end + 3;
929
+ masked.fill(COMMENT, index, stop);
930
+ index = stop;
931
+ } else if (text[index] === "<" && /[A-Za-z/]/.test(text[index + 1] ?? "")) {
932
+ index = maskTag(text, index + 1, masked);
933
+ } else {
934
+ index++;
935
+ }
936
+ }
937
+ return masked;
938
+ }
939
+ function maskTag(text, index, masked) {
940
+ while (index < text.length && text[index] !== ">") {
941
+ if (text[index] !== "=") {
942
+ index++;
943
+ continue;
944
+ }
945
+ index++;
946
+ while (text[index] === " " || text[index] === " " || text[index] === "\n") index++;
947
+ const quote = text[index];
948
+ const start = index;
949
+ if (quote === '"' || quote === "'") {
950
+ const end = text.indexOf(quote, index + 1);
951
+ index = end < 0 ? text.length : end + 1;
952
+ } else {
953
+ while (index < text.length && !/[\s>]/.test(text[index] ?? "")) index++;
954
+ }
955
+ masked.fill(STRING, start, index);
956
+ }
957
+ return index + 1;
958
+ }
959
+ function localBindings(text, masked) {
960
+ const names = /* @__PURE__ */ new Set();
961
+ for (const match of text.matchAll(/\b(?:const|let|var)\s+([\p{L}_$][\p{L}\w$]*)/gu)) {
962
+ if (!masked[match.index]) names.add(match[1] ?? "");
963
+ }
964
+ for (const match of text.matchAll(
965
+ /\bimport\s+(?:type\s+)?([^;]*?)\s+from\s+(['"])\.{1,2}\/[^'"]*\2/gu
966
+ )) {
967
+ if (masked[match.index]) continue;
968
+ for (const name of (match[1] ?? "").matchAll(
969
+ /([\p{L}_$][\p{L}\w$]*)(?:\s+as\s+([\p{L}_$][\p{L}\w$]*))?/gu
970
+ )) {
971
+ const local = name[2] ?? name[1] ?? "";
972
+ if (local !== "type" && local !== "as") names.add(local);
973
+ }
974
+ }
975
+ return names;
976
+ }
977
+ function isProse(text, masked) {
978
+ for (const match of text.matchAll(/[\p{L}_$][\p{L}\w$]*(?: [\p{L}_$][\p{L}\w$]*){2,}/gu)) {
979
+ const words = match[0].split(" ");
980
+ const plain = words.filter((word) => !SYNTAX_WORDS.has(word) && !RESERVED_WORDS.has(word));
981
+ if (!masked[match.index] && plain.length >= 3) {
982
+ return true;
983
+ }
984
+ }
985
+ return false;
986
+ }
987
+ function previousSignificant(text, index, masked) {
988
+ let position = index - 1;
989
+ while (position >= 0 && insignificant(text, position, masked)) position--;
990
+ return position;
991
+ }
992
+ function nextSignificant(text, index, masked) {
993
+ let position = index;
994
+ while (position < text.length && insignificant(text, position, masked)) position++;
995
+ return position;
996
+ }
997
+ function insignificant(text, index, masked) {
998
+ return masked[index] === COMMENT || /\s/.test(text[index] ?? "");
999
+ }
1000
+ function previousWord(text, index) {
1001
+ let start = index;
1002
+ while (start >= 0 && WORD_CHARACTER.test(text[start] ?? "")) start--;
1003
+ return text.slice(start + 1, index + 1);
1004
+ }
1005
+ var WORD_CHARACTER, IDENTIFIER_BEFORE, WHOLE_KEYWORD, CODE_PUNCTUATION, DECLARATION_START, HTML_START, SYNTAX_WORDS, RESERVED_WORDS, TYPE_CONTEXT, TYPE_WORDS, CODE, STRING, COMMENT, TEMPLATE, CONTROL_FLOW, NOT_A_REFERENCE, REFERENCE;
1006
+ var init_keyword_positions = __esm({
1007
+ "libs/utils/html/plugins/keyword-positions.ts"() {
1008
+ "use strict";
1009
+ WORD_CHARACTER = /[*\p{L}\w$@-]/u;
1010
+ IDENTIFIER_BEFORE = /[\p{L}\w$@-]+$/u;
1011
+ WHOLE_KEYWORD = /^\s*[*\p{L}\w$@-]+(?:[.#][\p{L}\w-]+)?(?:\?[\w=&]+)?\s*$/u;
1012
+ CODE_PUNCTUATION = /[(){}[\]<>|:=@]/;
1013
+ DECLARATION_START = /^\s*(?:export|import|class|interface|type|const|let|var|function|enum|abstract|declare)\s/;
1014
+ HTML_START = /^\s*<\/?[A-Za-z]/;
1015
+ SYNTAX_WORDS = /* @__PURE__ */ new Set([
1016
+ "await",
1017
+ "break",
1018
+ "case",
1019
+ "catch",
1020
+ "continue",
1021
+ "debugger",
1022
+ "delete",
1023
+ "do",
1024
+ "else",
1025
+ "false",
1026
+ "finally",
1027
+ "for",
1028
+ "function",
1029
+ "if",
1030
+ "instanceof",
1031
+ "new",
1032
+ "null",
1033
+ "return",
1034
+ "super",
1035
+ "switch",
1036
+ "this",
1037
+ "throw",
1038
+ "true",
1039
+ "try",
1040
+ "typeof",
1041
+ "void",
1042
+ "while",
1043
+ "with",
1044
+ "yield"
1045
+ ]);
1046
+ RESERVED_WORDS = /* @__PURE__ */ new Set([
1047
+ "abstract",
1048
+ "accessor",
1049
+ "any",
1050
+ "as",
1051
+ "asserts",
1052
+ "async",
1053
+ "bigint",
1054
+ "boolean",
1055
+ "class",
1056
+ "const",
1057
+ "constructor",
1058
+ "declare",
1059
+ "default",
1060
+ "enum",
1061
+ "export",
1062
+ "extends",
1063
+ "from",
1064
+ "get",
1065
+ "implements",
1066
+ "import",
1067
+ "in",
1068
+ "infer",
1069
+ "interface",
1070
+ "is",
1071
+ "keyof",
1072
+ "let",
1073
+ "module",
1074
+ "namespace",
1075
+ "never",
1076
+ "number",
1077
+ "object",
1078
+ "of",
1079
+ "out",
1080
+ "override",
1081
+ "package",
1082
+ "private",
1083
+ "protected",
1084
+ "public",
1085
+ "readonly",
1086
+ "require",
1087
+ "satisfies",
1088
+ "set",
1089
+ "static",
1090
+ "string",
1091
+ "symbol",
1092
+ "type",
1093
+ "undefined",
1094
+ "unique",
1095
+ "unknown",
1096
+ "var"
1097
+ ]);
1098
+ TYPE_CONTEXT = [":", "|", "&", "<"];
1099
+ TYPE_WORDS = ["type", "extends", "keyof", "typeof"];
1100
+ CODE = 0;
1101
+ STRING = 1;
1102
+ COMMENT = 2;
1103
+ TEMPLATE = 3;
1104
+ CONTROL_FLOW = /^@[a-z]+$/;
1105
+ NOT_A_REFERENCE = Object.freeze({ link: false });
1106
+ REFERENCE = Object.freeze({ link: true });
1107
+ }
1108
+ });
1109
+
779
1110
  // libs/utils/html/plugins/keywords.plugin.ts
780
1111
  import { isElement as isElement5 } from "hast-util-is-element";
781
1112
  import { toString } from "hast-util-to-string";
@@ -787,23 +1118,50 @@ function keywordsPlugin(config) {
787
1118
  }
788
1119
  const isInlineCode = !isElement5(ancestors[ancestors.length - 1], "pre");
789
1120
  const lang = asArray(node.properties?.["className"] ?? []).find((className) => className.startsWith("language-"))?.replace("language-", "") ?? "";
790
- if (isInlineCode || LANGUAGES.includes(lang)) {
791
- visitParents(node, "text", (node2, ancestors2) => {
792
- if (hasLinkAncestor(ancestors2)) {
793
- return;
794
- }
795
- const parent = ancestors2[ancestors2.length - 1];
796
- const index = parent.children.indexOf(node2);
797
- const nodes = getNodes(node2, parent, isInlineCode, config, lang);
798
- Array.prototype.splice.apply(parent.children, [index, 1].concat(nodes));
799
- return [SKIP, index + nodes.length];
800
- });
1121
+ if (!isInlineCode && !LANGUAGES.includes(lang)) {
1122
+ return;
801
1123
  }
1124
+ const offsets = textOffsets(node);
1125
+ const text = Array.from(offsets.keys()).map((textNode) => textNode.value).join("");
1126
+ const scan = isInlineCode ? scanInlineCode(text) : scanCodeBlock(text, HTML_LANGUAGES.includes(lang) ? "html" : "typescript");
1127
+ if (!scan) {
1128
+ return;
1129
+ }
1130
+ visitParents(node, "text", (node2, ancestors2) => {
1131
+ if (hasLinkAncestor(ancestors2)) {
1132
+ return;
1133
+ }
1134
+ const parent = ancestors2[ancestors2.length - 1];
1135
+ const index = parent.children.indexOf(node2);
1136
+ const nodes = getNodes(
1137
+ node2,
1138
+ parent,
1139
+ isInlineCode,
1140
+ config,
1141
+ lang,
1142
+ scan,
1143
+ offsets.get(node2) ?? 0
1144
+ );
1145
+ Array.prototype.splice.apply(parent.children, [index, 1].concat(nodes));
1146
+ return [SKIP, index + nodes.length];
1147
+ });
802
1148
  });
803
1149
  }
804
- function getNodes(node, parent, isInlineCode, config, language) {
1150
+ function textOffsets(node) {
1151
+ const offsets = /* @__PURE__ */ new Map();
1152
+ let offset = 0;
1153
+ visitParents(node, "text", (text) => {
1154
+ offsets.set(text, offset);
1155
+ offset += text.value.length;
1156
+ });
1157
+ return offsets;
1158
+ }
1159
+ function getNodes(node, parent, isInlineCode, config, language, scan, offset) {
805
1160
  const { addUsedKeyword, getKeyword } = config;
1161
+ let start = offset;
806
1162
  return toString(node).split(SPLIT_REGEXP).map((word) => {
1163
+ const wordStart = start;
1164
+ start += word.length;
807
1165
  const match = word.match(MATCH_KEYWORD_REGEXP);
808
1166
  if (!match) {
809
1167
  return { type: "text", value: word };
@@ -814,8 +1172,13 @@ function getNodes(node, parent, isInlineCode, config, language) {
814
1172
  anchor = "",
815
1173
  queryParams = ""
816
1174
  } = match.groups;
817
- const usedKeyword = `${key}${delimiter}${anchor?.toLowerCase()}`;
818
- const rootKeyword = getKeyword?.(key);
1175
+ const position = scan.position(wordStart, wordStart + word.length, key);
1176
+ if (!position.link) {
1177
+ return { type: "text", value: word };
1178
+ }
1179
+ const isMember = position.keyword !== void 0;
1180
+ const usedKeyword = position.keyword ?? `${key}${delimiter}${anchor?.toLowerCase()}`;
1181
+ const rootKeyword = isMember ? void 0 : getKeyword?.(key);
819
1182
  const keyword = getKeyword?.(usedKeyword);
820
1183
  const isGuideKeyword = key.startsWith("*");
821
1184
  const isLanguageAllowed = !keyword?.languages && ALWAYS_ALLOWED_LANGUAGES.includes(language) || !!keyword?.languages?.includes(language);
@@ -828,7 +1191,7 @@ function getNodes(node, parent, isInlineCode, config, language) {
828
1191
  addUsedKeyword?.(usedKeyword);
829
1192
  const notFoundGuideKeyword = isGuideKeyword && !keyword;
830
1193
  const notFoundApiAnchorKeyword = !!rootKeyword && !!anchor && !keyword;
831
- if (getKeyword && isInlineCode && (notFoundGuideKeyword || notFoundApiAnchorKeyword)) {
1194
+ if (getKeyword && scan.whole && (notFoundGuideKeyword || notFoundApiAnchorKeyword)) {
832
1195
  throw new Error(`Route with keyword "${word}" is missing.`);
833
1196
  }
834
1197
  if (parent.properties) {
@@ -844,7 +1207,7 @@ function getNodes(node, parent, isInlineCode, config, language) {
844
1207
  }
845
1208
  }
846
1209
  return keyword ? createLinkNode(
847
- isInlineCode ? keyword.title : word,
1210
+ isInlineCode && !isMember ? keyword.title : word,
848
1211
  keyword.path,
849
1212
  keyword.type,
850
1213
  keyword.description
@@ -864,14 +1227,16 @@ function createLinkNode(text, href, type, description) {
864
1227
  children: [{ type: "text", value: text }]
865
1228
  };
866
1229
  }
867
- var ALWAYS_ALLOWED_LANGUAGES, LANGUAGES, SPLIT_REGEXP, MATCH_KEYWORD_REGEXP;
1230
+ var ALWAYS_ALLOWED_LANGUAGES, HTML_LANGUAGES, LANGUAGES, SPLIT_REGEXP, MATCH_KEYWORD_REGEXP;
868
1231
  var init_keywords_plugin = __esm({
869
1232
  "libs/utils/html/plugins/keywords.plugin.ts"() {
870
1233
  "use strict";
871
1234
  init_core();
872
1235
  init_helpers2();
1236
+ init_keyword_positions();
873
1237
  ALWAYS_ALLOWED_LANGUAGES = ["typescript", "ts", "angular-ts"];
874
- LANGUAGES = ["typescript", "ts", "angular-ts", ...KEYWORD_ALLOWED_LANGUAGES];
1238
+ HTML_LANGUAGES = [...KEYWORD_ALLOWED_LANGUAGES];
1239
+ LANGUAGES = [...ALWAYS_ALLOWED_LANGUAGES, ...HTML_LANGUAGES];
875
1240
  SPLIT_REGEXP = /([*\p{L}\w$@-]+(?:[.#][\p{L}\w-]+)?(?:\?[\w=&]+)?)/u;
876
1241
  MATCH_KEYWORD_REGEXP = /(?<key>[*\p{L}\w$@-]+)((?<delimiter>[.#])(?<anchor>[\p{L}\w-]+))?(?<queryParams>\?[\w=&]+)?/u;
877
1242
  }
@@ -929,13 +1294,14 @@ var init_add_heading_anchors_plugin = __esm({
929
1294
  });
930
1295
 
931
1296
  // libs/utils/html/plugins/cached-shiki.plugin.ts
932
- import rehypeShiki from "@shikijs/rehype";
933
1297
  import { toString as toString2 } from "hast-util-to-string";
934
1298
  import { visit as visit2 } from "unist-util-visit";
935
1299
  function cachedShikiPlugin(settings) {
936
- const { cache, themes, identity, defaultLanguage } = settings;
1300
+ const { cache, themes, languages, identity, defaultLanguage } = settings;
937
1301
  const id = `${themes.light}
938
- ${themes.dark}`;
1302
+ ${themes.dark}
1303
+ ${languages ?? ""}
1304
+ ${settings.grammars ?? "all"}`;
939
1305
  return async (tree) => {
940
1306
  const blocks = [];
941
1307
  visit2(tree, "element", (node, index, parent) => {
@@ -952,11 +1318,18 @@ ${themes.dark}`;
952
1318
  blocks.push({
953
1319
  node,
954
1320
  parent,
955
- key: cache.key({ options: identity, themes, lang, meta, code })
1321
+ key: cache.key({
1322
+ options: identity,
1323
+ themes,
1324
+ ...languages === void 0 ? {} : { languages },
1325
+ lang,
1326
+ meta,
1327
+ code
1328
+ })
956
1329
  });
957
1330
  });
958
1331
  let highlighter;
959
- const load = async () => highlighter ??= await highlighterFor(id, settings.options);
1332
+ const load = async () => highlighter ??= await highlighterFor(id, settings.transformer);
960
1333
  if (cache.loads?.(themes) !== true) await load();
961
1334
  const values = [];
962
1335
  for (const block of blocks) {
@@ -977,13 +1350,11 @@ ${themes.dark}`;
977
1350
  });
978
1351
  };
979
1352
  }
980
- function highlighterFor(id, options) {
1353
+ function highlighterFor(id, transformer) {
981
1354
  const known = highlighters.get(id);
982
1355
  if (known) return known;
983
1356
  const created = (async () => {
984
- const transform = rehypeShiki(
985
- options()
986
- );
1357
+ const transform = transformer();
987
1358
  await transform({ type: "root", children: [] });
988
1359
  return transform;
989
1360
  })();
@@ -1001,11 +1372,18 @@ async function highlight(transform, node) {
1001
1372
  function fragment(value) {
1002
1373
  try {
1003
1374
  const parsed = JSON.parse(value);
1004
- return Array.isArray(parsed) && parsed.length > 0 && parsed.every((item) => isNode(item) && item.type === "element") ? parsed : void 0;
1375
+ return Array.isArray(parsed) && parsed.length > 0 && parsed.every(isReplacement) ? parsed : void 0;
1005
1376
  } catch {
1006
1377
  return void 0;
1007
1378
  }
1008
1379
  }
1380
+ function isReplacement(value) {
1381
+ if (isNode(value)) return value.type === "element";
1382
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
1383
+ const node = value;
1384
+ const children = node["children"];
1385
+ return node["type"] === "root" && Array.isArray(children) && children.length > 0 && children.every((child) => isNode(child) && child.type === "element");
1386
+ }
1009
1387
  function isNode(value) {
1010
1388
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
1011
1389
  const node = value;
@@ -1198,11 +1576,158 @@ var init_table_wrapper = __esm({
1198
1576
  }
1199
1577
  });
1200
1578
 
1579
+ // libs/utils/html/shiki-grammars.ts
1580
+ import {
1581
+ bundledLanguages,
1582
+ createHighlighter
1583
+ } from "shiki";
1584
+ import { visit as visit7 } from "unist-util-visit";
1585
+ function shikiGrammars() {
1586
+ grammars ??= ShikiGrammars.create().catch((error) => {
1587
+ grammars = void 0;
1588
+ throw error;
1589
+ });
1590
+ return grammars;
1591
+ }
1592
+ function createGrammarlessHighlighter(themes) {
1593
+ return createHighlighter({ themes, langs: [] });
1594
+ }
1595
+ function blockLanguages(tree, defaultLanguage) {
1596
+ const languages = /* @__PURE__ */ new Set();
1597
+ visit7(tree, "element", (node) => {
1598
+ if (node.tagName !== "pre") return;
1599
+ const head = node.children[0];
1600
+ if (!head || head.type !== "element" || head.tagName !== "code" || !head.properties) return;
1601
+ const classes = head.properties["className"];
1602
+ const languageClass = Array.isArray(classes) ? classes.find((item) => typeof item === "string" && item.startsWith(languagePrefix2)) : void 0;
1603
+ languages.add(
1604
+ typeof languageClass === "string" ? languageClass.slice(languagePrefix2.length) : defaultLanguage
1605
+ );
1606
+ });
1607
+ return languages;
1608
+ }
1609
+ function includedScopes(registration) {
1610
+ const scopes = /* @__PURE__ */ new Set();
1611
+ const walk = (value) => {
1612
+ if (Array.isArray(value)) value.forEach(walk);
1613
+ else if (value && typeof value === "object")
1614
+ for (const [key, item] of Object.entries(value)) {
1615
+ if (key === "include" && typeof item === "string") {
1616
+ if (!item.startsWith("#") && !item.startsWith("$")) scopes.add(item.split("#")[0]);
1617
+ } else walk(item);
1618
+ }
1619
+ };
1620
+ walk(registration);
1621
+ return scopes;
1622
+ }
1623
+ function prefixes(scope) {
1624
+ const parts = scope.split(".");
1625
+ return parts.map((_, index) => parts.slice(0, index + 1).join("."));
1626
+ }
1627
+ var ShikiGrammars, grammars, languagePrefix2;
1628
+ var init_shiki_grammars = __esm({
1629
+ "libs/utils/html/shiki-grammars.ts"() {
1630
+ "use strict";
1631
+ ShikiGrammars = class _ShikiGrammars {
1632
+ constructor(registrations) {
1633
+ this.byName = /* @__PURE__ */ new Map();
1634
+ this.byScope = /* @__PURE__ */ new Map();
1635
+ this.injectors = /* @__PURE__ */ new Map();
1636
+ this.order = /* @__PURE__ */ new Map();
1637
+ this.closures = /* @__PURE__ */ new Map();
1638
+ this.loaded = /* @__PURE__ */ new WeakMap();
1639
+ const mention = (name) => {
1640
+ if (!this.order.has(name)) this.order.set(name, this.order.size);
1641
+ };
1642
+ for (const registration of registrations) {
1643
+ mention(registration.name);
1644
+ for (const embedded of registration.embeddedLangs ?? []) mention(embedded);
1645
+ if (this.byScope.has(registration.scopeName)) continue;
1646
+ this.byScope.set(registration.scopeName, registration);
1647
+ this.byName.set(registration.name, registration);
1648
+ for (const alias of registration.aliases ?? []) this.byName.set(alias, registration);
1649
+ for (const target of registration.injectTo ?? []) {
1650
+ const list = this.injectors.get(target) ?? [];
1651
+ list.push(registration);
1652
+ this.injectors.set(target, list);
1653
+ }
1654
+ }
1655
+ }
1656
+ /**
1657
+ * The bundled grammars, in the order `@shikijs/rehype` registers them: every bundled language
1658
+ * name, each with the registrations of its module.
1659
+ */
1660
+ static async create() {
1661
+ const modules = await Promise.all(
1662
+ Object.keys(bundledLanguages).map(
1663
+ (name) => bundledLanguages[name]()
1664
+ )
1665
+ );
1666
+ return new _ShikiGrammars(modules.flatMap((module) => module.default));
1667
+ }
1668
+ /**
1669
+ * The grammars that a block of `language` can reach, in registration order; empty for a
1670
+ * language that no bundled grammar names (it falls back to plain text, as before).
1671
+ * @param language
1672
+ */
1673
+ closure(language) {
1674
+ const known = this.closures.get(language);
1675
+ if (known) return known;
1676
+ const set = /* @__PURE__ */ new Set();
1677
+ const queue = [this.byName.get(language)];
1678
+ while (queue.length) {
1679
+ const registration = queue.pop();
1680
+ if (!registration || set.has(registration)) continue;
1681
+ set.add(registration);
1682
+ for (const name of [
1683
+ ...registration.embeddedLangs ?? [],
1684
+ ...registration.embeddedLangsLazy ?? []
1685
+ ])
1686
+ queue.push(this.byName.get(name));
1687
+ for (const scope of includedScopes(registration)) queue.push(this.byScope.get(scope));
1688
+ for (const prefix of prefixes(registration.scopeName))
1689
+ queue.push(...this.injectors.get(prefix) ?? []);
1690
+ for (const target of registration.injectTo ?? [])
1691
+ queue.push(...this.injectors.get(target) ?? []);
1692
+ }
1693
+ const closure = [...set].sort(
1694
+ (left, right) => this.order.get(left.name) - this.order.get(right.name)
1695
+ );
1696
+ this.closures.set(language, closure);
1697
+ return closure;
1698
+ }
1699
+ /**
1700
+ * Loads the closures of `languages` that `highlighter` does not hold yet.
1701
+ * @param highlighter
1702
+ * @param languages
1703
+ */
1704
+ load(highlighter, languages) {
1705
+ let loaded = this.loaded.get(highlighter);
1706
+ if (!loaded) this.loaded.set(highlighter, loaded = /* @__PURE__ */ new Set());
1707
+ const missing = /* @__PURE__ */ new Set();
1708
+ for (const language of languages)
1709
+ for (const registration of this.closure(language))
1710
+ if (!loaded.has(registration.name)) missing.add(registration);
1711
+ if (!missing.size) return;
1712
+ const batch = [...missing].sort(
1713
+ (left, right) => this.order.get(left.name) - this.order.get(right.name)
1714
+ );
1715
+ highlighter.loadLanguageSync(batch);
1716
+ for (const registration of batch) loaded.add(registration.name);
1717
+ }
1718
+ };
1719
+ languagePrefix2 = "language-";
1720
+ }
1721
+ });
1722
+
1201
1723
  // libs/utils/html/process-html.ts
1202
- import rehypeShiki2 from "@shikijs/rehype";
1724
+ import rehypeShiki from "@shikijs/rehype";
1725
+ import rehypeShikiFromHighlighter from "@shikijs/rehype/core";
1726
+ import { createHash as createHash2 } from "node:crypto";
1203
1727
  import rehypeMinifyWhitespace2 from "rehype-minify-whitespace";
1204
1728
  import rehypeParse3 from "rehype-parse";
1205
1729
  import rehypeStringify3 from "rehype-stringify";
1730
+ import { bundledLanguages as bundledLanguages2, createHighlighter as createHighlighter2 } from "shiki";
1206
1731
  import { unified as unified3 } from "unified";
1207
1732
  async function processHtml(html, config) {
1208
1733
  const anchors = /* @__PURE__ */ new Set();
@@ -1210,6 +1735,8 @@ async function processHtml(html, config) {
1210
1735
  light: config.lightTheme ?? "github-light",
1211
1736
  dark: config.darkTheme ?? "ayu-dark"
1212
1737
  };
1738
+ const langs = config.langs?.length ? config.langs : void 0;
1739
+ const used = !langs && config.grammars === "used";
1213
1740
  try {
1214
1741
  const content = await unified3().use(rehypeParse3, { fragment: true }).use(rehypeStringify3).use(mermaidPlugin).use(
1215
1742
  config.highlight ? [
@@ -1218,12 +1745,16 @@ async function processHtml(html, config) {
1218
1745
  {
1219
1746
  cache: config.highlight,
1220
1747
  themes,
1748
+ ...langs ? { languages: languagesId(langs) } : {},
1749
+ ...used ? { grammars: "used" } : {},
1221
1750
  identity: HIGHLIGHT_IDENTITY,
1222
1751
  defaultLanguage: DEFAULT_LANGUAGE,
1223
- options: () => shikiOptions(themes)
1752
+ transformer: () => langs ? withLanguages(themes, langs) : used ? withUsedGrammars(themes) : rehypeShiki(
1753
+ shikiOptions(themes)
1754
+ )
1224
1755
  }
1225
1756
  ]
1226
- ] : [[rehypeShiki2, shikiOptions(themes)]]
1757
+ ] : langs ? [[() => withLanguages(themes, langs)]] : used ? [[() => withUsedGrammars(themes)]] : [[rehypeShiki, shikiOptions(themes)]]
1227
1758
  ).use(highlightCodeLines).use(table_wrapper_default).use(sluggerPlugin, anchors.add.bind(anchors), config.headings).use(rehypeMinifyWhitespace2).use(addHeadingAnchors, config.route).use(markElementsPlugin).process(html).then((file) => file.toString());
1228
1759
  return { content, anchors: Array.from(anchors) };
1229
1760
  } catch (error) {
@@ -1249,7 +1780,59 @@ function shikiOptions(themes) {
1249
1780
  function shikiTheme(name) {
1250
1781
  return name === NG_DOC_SYNTAX_THEME_NAME ? ngDocSyntaxTheme() : name;
1251
1782
  }
1252
- var DEFAULT_LANGUAGE, HIGHLIGHT_IDENTITY;
1783
+ function languagesId(langs) {
1784
+ let id = languageIds.get(langs);
1785
+ if (id === void 0) {
1786
+ id = createHash2("sha256").update(JSON.stringify(langs)).digest("hex");
1787
+ languageIds.set(langs, id);
1788
+ }
1789
+ return id;
1790
+ }
1791
+ function withLanguages(themes, langs) {
1792
+ const id = `${themes.light}
1793
+ ${themes.dark}
1794
+ ${languagesId(langs)}`;
1795
+ return async (tree) => {
1796
+ let highlighter = languageHighlighters.get(id);
1797
+ if (!highlighter) {
1798
+ highlighter = createHighlighter2({
1799
+ themes: [shikiTheme(themes.light), shikiTheme(themes.dark)],
1800
+ // Later registrations of a name replace earlier ones, so the given languages win.
1801
+ langs: [...Object.keys(bundledLanguages2), ...langs]
1802
+ });
1803
+ languageHighlighters.set(id, highlighter);
1804
+ const created = highlighter;
1805
+ created.catch(() => {
1806
+ if (languageHighlighters.get(id) === created) languageHighlighters.delete(id);
1807
+ });
1808
+ }
1809
+ const transform = rehypeShikiFromHighlighter(await highlighter, shikiOptions(themes));
1810
+ await transform(tree);
1811
+ };
1812
+ }
1813
+ function withUsedGrammars(themes) {
1814
+ const id = `${themes.light}
1815
+ ${themes.dark}`;
1816
+ return async (tree) => {
1817
+ let highlighter = usedHighlighters.get(id);
1818
+ if (!highlighter) {
1819
+ highlighter = createGrammarlessHighlighter([
1820
+ shikiTheme(themes.light),
1821
+ shikiTheme(themes.dark)
1822
+ ]);
1823
+ usedHighlighters.set(id, highlighter);
1824
+ const created = highlighter;
1825
+ created.catch(() => {
1826
+ if (usedHighlighters.get(id) === created) usedHighlighters.delete(id);
1827
+ });
1828
+ }
1829
+ const [grammars2, ready] = await Promise.all([shikiGrammars(), highlighter]);
1830
+ grammars2.load(ready, blockLanguages(tree, DEFAULT_LANGUAGE));
1831
+ const transform = rehypeShikiFromHighlighter(ready, shikiOptions(themes));
1832
+ await transform(tree);
1833
+ };
1834
+ }
1835
+ var DEFAULT_LANGUAGE, HIGHLIGHT_IDENTITY, languageHighlighters, languageIds, usedHighlighters;
1253
1836
  var init_process_html = __esm({
1254
1837
  "libs/utils/html/process-html.ts"() {
1255
1838
  "use strict";
@@ -1261,24 +1844,28 @@ var init_process_html = __esm({
1261
1844
  init_mermaid_plugin();
1262
1845
  init_slugger_plugin();
1263
1846
  init_table_wrapper();
1847
+ init_shiki_grammars();
1264
1848
  DEFAULT_LANGUAGE = "ts";
1265
1849
  HIGHLIGHT_IDENTITY = {
1266
- format: 1,
1850
+ format: 2,
1267
1851
  defaultLanguage: DEFAULT_LANGUAGE,
1268
1852
  fallbackLanguage: "text",
1269
1853
  addLanguageClass: true,
1270
1854
  parseMetaString: "json-without-backslashes",
1271
1855
  tokenizeTimeLimit: 0
1272
1856
  };
1857
+ languageHighlighters = /* @__PURE__ */ new Map();
1858
+ languageIds = /* @__PURE__ */ new WeakMap();
1859
+ usedHighlighters = /* @__PURE__ */ new Map();
1273
1860
  }
1274
1861
  });
1275
1862
 
1276
1863
  // libs/utils/html/plugins/remove-not-indexable-content.plugin.ts
1277
1864
  import { filter } from "unist-util-filter";
1278
- import { visit as visit7 } from "unist-util-visit";
1865
+ import { visit as visit8 } from "unist-util-visit";
1279
1866
  function removeNotIndexableContentPlugin() {
1280
1867
  return (tree) => {
1281
- visit7(tree, "element", (node) => {
1868
+ visit8(tree, "element", (node) => {
1282
1869
  if (isHeading(node) && isHiddenSpan(node.children[0])) {
1283
1870
  node.children = node.children.slice(1);
1284
1871
  }
@@ -1364,13 +1951,13 @@ import { parseFile } from "@orama/plugin-parsedoc";
1364
1951
  async function renderDocuments(task, highlight2, aborted = notAborted) {
1365
1952
  const results = [];
1366
1953
  for (const document of task.documents) {
1367
- const result = await renderDocument(document, task.themes, highlight2, aborted);
1954
+ const result = await renderDocument(document, task, highlight2, aborted);
1368
1955
  results.push(result);
1369
1956
  if (!("html" in result)) break;
1370
1957
  }
1371
1958
  return results;
1372
1959
  }
1373
- async function renderDocument(document, themes, highlight2, aborted) {
1960
+ async function renderDocument(document, { themes, langs, grammars: grammars2 }, highlight2, aborted) {
1374
1961
  if (aborted()) return { aborted: true, mismatches: 0 };
1375
1962
  const utilities = await htmlUtilities();
1376
1963
  if (aborted()) return { aborted: true, mismatches: 0 };
@@ -1380,6 +1967,8 @@ async function renderDocument(document, themes, highlight2, aborted) {
1380
1967
  ...document.route === void 0 ? {} : { route: document.route },
1381
1968
  lightTheme: themes.light,
1382
1969
  darkTheme: themes.dark,
1970
+ ...langs ? { langs } : {},
1971
+ grammars: grammars2 ?? "used",
1383
1972
  ...call ? { highlight: call } : {}
1384
1973
  });
1385
1974
  const mismatches = call?.mismatches.length ?? 0;
@@ -1554,7 +2143,9 @@ function serveHtmlThread(port) {
1554
2143
  await renderDocuments(
1555
2144
  {
1556
2145
  documents: [{ html: WARM_DOCUMENT }],
1557
- themes: job["themes"]
2146
+ themes: job["themes"],
2147
+ ...job["langs"] ? { langs: job["langs"] } : {},
2148
+ ...job["grammars"] === "all" ? { grammars: "all" } : {}
1558
2149
  },
1559
2150
  () => job["cache"] === true ? cache : void 0
1560
2151
  );
@@ -1583,7 +2174,7 @@ var init_html_pipeline = __esm({
1583
2174
  init_protocol();
1584
2175
  htmlUtilities = () => Promise.resolve().then(() => (init_utils(), utils_exports));
1585
2176
  notAborted = () => false;
1586
- WARM_DOCUMENT = '<pre><code class="language-ts">const warm = 1;</code></pre>';
2177
+ WARM_DOCUMENT = ["ts", "angular-ts", "angular-html"].map((language) => `<pre><code class="language-${language}">warm</code></pre>`).join("");
1587
2178
  }
1588
2179
  });
1589
2180