• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import fs from 'fs';
2import { resolve } from 'path';
3import assert from 'assert';
4
5import { unified } from 'unified';
6import remarkParse from 'remark-parse';
7
8const source = resolve(process.argv[2]);
9
10const skipDeprecationComment = /^<!-- md-lint skip-deprecation (DEP\d{4}) -->$/;
11
12const generateDeprecationCode = (codeAsNumber) =>
13  `DEP${codeAsNumber.toString().padStart(4, '0')}`;
14
15const addMarkdownPathToErrorStack = (error, node) => {
16  const { line, column } = node.position.start;
17  const [header, ...lines] = error.stack.split('\n');
18  error.stack =
19          header +
20          `\n    at <anonymous> (${source}:${line}:${column})\n` +
21          lines.join('\n');
22  return error;
23};
24
25const testHeading = (headingNode, expectedDeprecationCode) => {
26  try {
27    assert.strictEqual(
28      headingNode?.children[0]?.value.substring(0, 9),
29      `${expectedDeprecationCode}: `,
30      'Ill-formed or out-of-order deprecation code.',
31    );
32  } catch (e) {
33    throw addMarkdownPathToErrorStack(e, headingNode);
34  }
35};
36
37const testYAMLComment = (commentNode) => {
38  try {
39    assert.match(
40      commentNode?.value?.substring(0, 21),
41      /^<!-- YAML\r?\nchanges:\r?\n/,
42      'Missing or ill-formed YAML comment.',
43    );
44  } catch (e) {
45    throw addMarkdownPathToErrorStack(e, commentNode);
46  }
47};
48
49const testDeprecationType = (paragraphNode) => {
50  try {
51    assert.strictEqual(
52      paragraphNode?.children[0]?.value?.substring(0, 6),
53      'Type: ',
54      'Missing deprecation type.',
55    );
56  } catch (e) {
57    throw addMarkdownPathToErrorStack(e, paragraphNode);
58  }
59};
60
61const tree = unified()
62  .use(remarkParse)
63  .parse(fs.readFileSync(source));
64
65let expectedDeprecationCodeNumber = 0;
66for (let i = 0; i < tree.children.length; i++) {
67  const node = tree.children[i];
68  if (node.type === 'html' && skipDeprecationComment.test(node.value)) {
69    const expectedDeprecationCode =
70          generateDeprecationCode(++expectedDeprecationCodeNumber);
71    const deprecationCodeAsText = node.value.match(skipDeprecationComment)[1];
72
73    try {
74      assert.strictEqual(
75        deprecationCodeAsText,
76        expectedDeprecationCode,
77        'Deprecation codes are not ordered correctly.',
78      );
79    } catch (e) {
80      throw addMarkdownPathToErrorStack(e, node);
81    }
82  }
83  if (node.type === 'heading' && node.depth === 3) {
84    const expectedDeprecationCode =
85          generateDeprecationCode(++expectedDeprecationCodeNumber);
86
87    testHeading(node, expectedDeprecationCode);
88
89    testYAMLComment(tree.children[i + 1]);
90    testDeprecationType(tree.children[i + 2]);
91  }
92}
93