@ng-doc/utils 16.5.1 → 16.6.1

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.
@@ -2,3 +2,7 @@ export * from './attr-value';
2
2
  export * from './has-class';
3
3
  export * from './has-link-ancestor';
4
4
  export * from './is-code-node';
5
+ export * from './is-element';
6
+ export * from './is-text';
7
+ export * from './line-break';
8
+ export * from './text-element';
@@ -0,0 +1,6 @@
1
+ import { Element, ElementContent } from 'hast';
2
+ /**
3
+ *
4
+ * @param node
5
+ */
6
+ export declare function isElement(node?: ElementContent): node is Element;
@@ -0,0 +1,6 @@
1
+ import { ElementContent, Text } from 'hast';
2
+ /**
3
+ *
4
+ * @param element
5
+ */
6
+ export declare function isText(element?: ElementContent): element is Text;
@@ -0,0 +1,5 @@
1
+ import { Text } from 'hast';
2
+ /**
3
+ * Creates a line break
4
+ */
5
+ export declare function lineBreak(): Text;
@@ -0,0 +1,6 @@
1
+ import { Text } from 'hast';
2
+ /**
3
+ *
4
+ * @param value
5
+ */
6
+ export declare function textElement(value: string): Text;
@@ -0,0 +1,5 @@
1
+ import { Root } from 'hast';
2
+ /**
3
+ * Adds lines to code blocks
4
+ */
5
+ export default function codeBlockLinesPlugin(): (tree: Root) => void;
@@ -0,0 +1,5 @@
1
+ import { Root } from 'hast';
2
+ /**
3
+ * Highlight code lines
4
+ */
5
+ export default function highlightCodeLines(): (tree: Root) => void;
package/index.js CHANGED
@@ -14166,7 +14166,7 @@ function looksLikeAVFileValue(value) {
14166
14166
  * @returns
14167
14167
  * Whether `node` is an element and passes a test.
14168
14168
  */
14169
- const isElement =
14169
+ const isElement$1 =
14170
14170
  /**
14171
14171
  * @type {(
14172
14172
  * (() => false) &
@@ -14726,7 +14726,7 @@ function hasClass(node, cls) {
14726
14726
  * @param ancestors
14727
14727
  */
14728
14728
  function hasLinkAncestor(ancestors) {
14729
- return ancestors.some(ancestor => isElement(ancestor, 'a'));
14729
+ return ancestors.some(ancestor => isElement$1(ancestor, 'a'));
14730
14730
  }
14731
14731
 
14732
14732
  /**
@@ -14734,7 +14734,44 @@ function hasLinkAncestor(ancestors) {
14734
14734
  * @param node
14735
14735
  */
14736
14736
  function isCodeNode(node) {
14737
- return isElement(node, 'code') || isElement(node, 'ng-doc-code');
14737
+ return isElement$1(node, 'code') || isElement$1(node, 'ng-doc-code');
14738
+ }
14739
+
14740
+ /**
14741
+ *
14742
+ * @param node
14743
+ */
14744
+ function isElement(node) {
14745
+ return node?.type === 'element';
14746
+ }
14747
+
14748
+ /**
14749
+ *
14750
+ * @param element
14751
+ */
14752
+ function isText(element) {
14753
+ return element?.type === 'text';
14754
+ }
14755
+
14756
+ /**
14757
+ * Creates a line break
14758
+ */
14759
+ function lineBreak() {
14760
+ return {
14761
+ type: 'text',
14762
+ value: '\n'
14763
+ };
14764
+ }
14765
+
14766
+ /**
14767
+ *
14768
+ * @param value
14769
+ */
14770
+ function textElement(value) {
14771
+ return {
14772
+ type: 'text',
14773
+ value
14774
+ };
14738
14775
  }
14739
14776
 
14740
14777
  const languages = ['typescript', 'ts'];
@@ -14752,7 +14789,7 @@ function keywordsPlugin(config) {
14752
14789
  if (!isCodeNode(node)) {
14753
14790
  return;
14754
14791
  }
14755
- const isInlineCode = !isElement(ancestors[ancestors.length - 1], 'pre');
14792
+ const isInlineCode = !isElement$1(ancestors[ancestors.length - 1], 'pre');
14756
14793
  const lang = node.properties?.['lang']?.toString() || '';
14757
14794
  if (isInlineCode || languages.includes(lang)) {
14758
14795
  visitParents(node, 'text', (node, ancestors) => {
@@ -15168,7 +15205,7 @@ const NO_ANCHOR_CLASS = 'no-anchor';
15168
15205
  */
15169
15206
  function autolinkHeading(route) {
15170
15207
  return tree => visit(tree, 'element', node => {
15171
- if (route && isElement(node, HEADINGS) && node.properties && node.properties['id'] && !hasClass(node, NO_ANCHOR_CLASS)) {
15208
+ if (route && isElement$1(node, HEADINGS) && node.properties && node.properties['id'] && !hasClass(node, NO_ANCHOR_CLASS)) {
15172
15209
  node.children.push({
15173
15210
  type: 'element',
15174
15211
  tagName: 'a',
@@ -15191,6 +15228,106 @@ function autolinkHeading(route) {
15191
15228
  });
15192
15229
  }
15193
15230
 
15231
+ /**
15232
+ * Adds lines to code blocks
15233
+ */
15234
+ function codeBlockLinesPlugin() {
15235
+ return tree => {
15236
+ visit(tree, 'element', (node, _i, parent) => {
15237
+ if (parent?.type === 'element' && parent.tagName === 'pre' && node.tagName === 'code') {
15238
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
15239
+ // @ts-ignore
15240
+ node.properties['className'] = [...(node.properties?.['className'] ?? []), 'code-lines'];
15241
+ // Wraps each line in a span
15242
+ node.children = addLines(node);
15243
+ // Adds a line break to the end of each line
15244
+ node.children.forEach(child => {
15245
+ if (child.type === 'element' && child.tagName === 'span') {
15246
+ const lastChild = child.children[child.children.length - 1];
15247
+ if (!isText(lastChild) || isText(lastChild) && !hasLineBreak(lastChild)) {
15248
+ child.children.push(lineBreak());
15249
+ }
15250
+ }
15251
+ });
15252
+ }
15253
+ });
15254
+ };
15255
+ }
15256
+ /**
15257
+ * Adds lines to a node recursively and returns them
15258
+ *
15259
+ * @param node - The node to add lines to
15260
+ * @param lines - The current lines
15261
+ * @param copyParent - Whether to copy the parent node to save the original node styles
15262
+ */
15263
+ function addLines(node, lines = [], copyParent) {
15264
+ const line = () => lines[lines.length - 1] ?? (lines.push(createLine()) && lines[lines.length - 1]);
15265
+ node.children.forEach(child => {
15266
+ if (isText(child) && hasLineBreak(child)) {
15267
+ const split = child.value.split(/\n/);
15268
+ split.forEach((content, i) => {
15269
+ copyParent ? line().children.push({
15270
+ ...node,
15271
+ children: [textElement(content)]
15272
+ }) : line().children.push(textElement(content));
15273
+ i !== split.length - 1 && lines.push(createLine());
15274
+ });
15275
+ } else if (isElement(child) && child.children.some(hasLineBreak)) {
15276
+ addLines(child, lines, true);
15277
+ } else {
15278
+ line().children.push(child);
15279
+ }
15280
+ });
15281
+ return lines;
15282
+ }
15283
+ /**
15284
+ * Creates a new line element
15285
+ *
15286
+ * @param children - The children the line should have initially
15287
+ */
15288
+ function createLine(...children) {
15289
+ return {
15290
+ type: 'element',
15291
+ tagName: 'span',
15292
+ properties: {
15293
+ class: ['line']
15294
+ },
15295
+ children
15296
+ };
15297
+ }
15298
+ /**
15299
+ * Checks if a node has a line break
15300
+ *
15301
+ * @param node - The node to check
15302
+ */
15303
+ function hasLineBreak(node) {
15304
+ return isText(node) && /\r?\n/.test(node.value) || isElement(node) && node.children.some(hasLineBreak);
15305
+ }
15306
+
15307
+ /**
15308
+ * Highlight code lines
15309
+ */
15310
+ function highlightCodeLines() {
15311
+ return tree => {
15312
+ visit(tree, 'element', (node, _i, parent) => {
15313
+ if (parent?.type === 'element' && parent.tagName === 'pre' && node.tagName === 'code') {
15314
+ const highlightedLines = JSON.parse(attrValue(node, 'highlightedLines') ?? '[]');
15315
+ highlightedLines.length && node.children.forEach((child, i) => {
15316
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
15317
+ // @ts-ignore
15318
+ if (isElement(child) && child.properties.class?.includes('line')) {
15319
+ if (highlightedLines.includes(i + 1)) {
15320
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
15321
+ // @ts-ignore
15322
+ child.properties.class.push('highlighted');
15323
+ }
15324
+ }
15325
+ });
15326
+ }
15327
+ });
15328
+ };
15329
+ }
15330
+
15194
15331
  /**
15195
15332
  *
15196
15333
  * @param tree
@@ -15236,7 +15373,7 @@ async function htmlProcessor(html, config) {
15236
15373
  languages: {
15237
15374
  twig
15238
15375
  }
15239
- }).use(sluggerPlugin, config.addAnchor, config.headings).use(rehypeMinifyWhitespace).use(autolinkHeading, config.route).process(html).then(file => file.toString());
15376
+ }).use(codeBlockLinesPlugin).use(highlightCodeLines).use(sluggerPlugin, config.addAnchor, config.headings).use(rehypeMinifyWhitespace).use(autolinkHeading, config.route).process(html).then(file => file.toString());
15240
15377
  }
15241
15378
 
15242
15379
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ng-doc/utils",
3
- "version": "16.5.1",
3
+ "version": "16.6.1",
4
4
  "type": "module",
5
5
  "dependencies": {
6
6
  "rehype": "12.0.1",