@ng-doc/utils 16.5.1 → 16.6.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.
@@ -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,103 @@ 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
+ // Wraps each line in a span
15239
+ node.children = addLines(node);
15240
+ // Adds a line break to the end of each line
15241
+ node.children.forEach(child => {
15242
+ if (child.type === 'element' && child.tagName === 'span') {
15243
+ const lastChild = child.children[child.children.length - 1];
15244
+ if (!isText(lastChild) || isText(lastChild) && !hasLineBreak(lastChild)) {
15245
+ child.children.push(lineBreak());
15246
+ }
15247
+ }
15248
+ });
15249
+ }
15250
+ });
15251
+ };
15252
+ }
15253
+ /**
15254
+ * Adds lines to a node recursively and returns them
15255
+ *
15256
+ * @param node - The node to add lines to
15257
+ * @param lines - The current lines
15258
+ * @param copyParent - Whether to copy the parent node to save the original node styles
15259
+ */
15260
+ function addLines(node, lines = [], copyParent) {
15261
+ const line = () => lines[lines.length - 1] ?? (lines.push(createLine()) && lines[lines.length - 1]);
15262
+ node.children.forEach(child => {
15263
+ if (isText(child) && hasLineBreak(child)) {
15264
+ const split = child.value.split(/\n/);
15265
+ split.forEach((content, i) => {
15266
+ copyParent ? line().children.push({
15267
+ ...node,
15268
+ children: [textElement(content)]
15269
+ }) : line().children.push(textElement(content));
15270
+ i !== split.length - 1 && lines.push(createLine());
15271
+ });
15272
+ } else if (isElement(child) && child.children.some(hasLineBreak)) {
15273
+ addLines(child, lines, true);
15274
+ } else {
15275
+ line().children.push(child);
15276
+ }
15277
+ });
15278
+ return lines;
15279
+ }
15280
+ /**
15281
+ * Creates a new line element
15282
+ *
15283
+ * @param children - The children the line should have initially
15284
+ */
15285
+ function createLine(...children) {
15286
+ return {
15287
+ type: 'element',
15288
+ tagName: 'span',
15289
+ properties: {
15290
+ class: ['line']
15291
+ },
15292
+ children
15293
+ };
15294
+ }
15295
+ /**
15296
+ * Checks if a node has a line break
15297
+ *
15298
+ * @param node - The node to check
15299
+ */
15300
+ function hasLineBreak(node) {
15301
+ return isText(node) && /\r?\n/.test(node.value) || isElement(node) && node.children.some(hasLineBreak);
15302
+ }
15303
+
15304
+ /**
15305
+ * Highlight code lines
15306
+ */
15307
+ function highlightCodeLines() {
15308
+ return tree => {
15309
+ visit(tree, 'element', (node, _i, parent) => {
15310
+ if (parent?.type === 'element' && parent.tagName === 'pre' && node.tagName === 'code') {
15311
+ const highlightedLines = JSON.parse(attrValue(node, 'highlightedLines') ?? '[]');
15312
+ highlightedLines.length && node.children.forEach((child, i) => {
15313
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
15314
+ // @ts-ignore
15315
+ if (isElement(child) && child.properties.class?.includes('line')) {
15316
+ if (highlightedLines.includes(i + 1)) {
15317
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
15318
+ // @ts-ignore
15319
+ child.properties.class.push('highlighted');
15320
+ }
15321
+ }
15322
+ });
15323
+ }
15324
+ });
15325
+ };
15326
+ }
15327
+
15194
15328
  /**
15195
15329
  *
15196
15330
  * @param tree
@@ -15236,7 +15370,7 @@ async function htmlProcessor(html, config) {
15236
15370
  languages: {
15237
15371
  twig
15238
15372
  }
15239
- }).use(sluggerPlugin, config.addAnchor, config.headings).use(rehypeMinifyWhitespace).use(autolinkHeading, config.route).process(html).then(file => file.toString());
15373
+ }).use(codeBlockLinesPlugin).use(highlightCodeLines).use(sluggerPlugin, config.addAnchor, config.headings).use(rehypeMinifyWhitespace).use(autolinkHeading, config.route).process(html).then(file => file.toString());
15240
15374
  }
15241
15375
 
15242
15376
  /**
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.0",
4
4
  "type": "module",
5
5
  "dependencies": {
6
6
  "rehype": "12.0.1",