Skip to content

Commit

Permalink
doc: lint deprecation codes
Browse files Browse the repository at this point in the history
Add a rule to make sure deprecation codes are in order.
  • Loading branch information
aduh95 committed May 18, 2020
1 parent ef1eb8d commit ca5f40f
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 1 deletion.
5 changes: 4 additions & 1 deletion doc/api/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -1129,7 +1129,7 @@ Type: Documentation-only
The [`util.isNumber()`][] API is deprecated.

<a id="DEP0053"></a>
### DEP0053 `util.isObject()`
### DEP0053: `util.isObject()`
<!-- YAML
changes:
- version:
Expand Down Expand Up @@ -1795,6 +1795,9 @@ Type: End-of-Life
`runInAsyncIdScope` doesn't emit the `'before'` or `'after'` event and can thus
cause a lot of issues. See <https://github.com/nodejs/node/issues/14328>.
<!-- md-lint skip-deprecation DEP0087 -->
<!-- md-lint skip-deprecation DEP0088 -->
<a id="DEP0089"></a>
### DEP0089: `require('assert')`
<!-- YAML
Expand Down
25 changes: 25 additions & 0 deletions test/doctool/test-deprecation-codes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict';

require('../common');
const path = require('path');
const { execFileSync } = require('child_process');

const script = path.join(
__dirname,
'..',
'..',
'tools',
'doc',
'deprecationCodes.js'
);

const mdPath = path.join(
__dirname,
'..',
'..',
'doc',
'api',
'deprecations.md'
);

execFileSync(process.execPath, [script, mdPath], { encoding: 'utf-8' });
105 changes: 105 additions & 0 deletions tools/doc/deprecationCodes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
'use strict';

const fs = require('fs');
const { resolve } = require('path');

const unified = require('unified');
const assert = require('assert');
const source = resolve(process.argv[2]);

const skipDeprecationComment = /^<!-- md-lint skip-deprecation (DEP\d{4}) -->$/;

const generateDeprecationCode = (codeAsNumber) =>
`DEP${codeAsNumber.toString().padStart(4, '0')}`;

const addMarkdownPathToErrorStack = (error, node) => {
const { line, column } = node.position.start;
const [header, ...lines] = error.stack.split('\n');
error.stack =
header +
`\n at <anonymous> (${source}:${line}:${column})\n` +
lines.join('\n');
return error;
};

const testAnchor = (anchorNode, expectedDeprecationCode) => {
try {
assert.strictEqual(
anchorNode?.children[0]?.value,
`<a id="${expectedDeprecationCode}">`,
`Missing or ill-formed anchor for ${expectedDeprecationCode}.`
);
} catch (e) {
throw addMarkdownPathToErrorStack(e, anchorNode);
}
};

const testHeading = (headingNode, expectedDeprecationCode) => {
try {
assert.strictEqual(
headingNode?.children[0]?.value.substring(0, 9),
`${expectedDeprecationCode}: `,
'Ill-formed or out-of-order deprecation code.'
);
} catch (e) {
throw addMarkdownPathToErrorStack(e, headingNode);
}
};

const testYAMLComment = (commentNode) => {
try {
assert.strictEqual(
commentNode?.value?.substring(0, 19),
'<!-- YAML\nchanges:\n',
'Missing or ill-formed YAML comment.'
);
} catch (e) {
throw addMarkdownPathToErrorStack(e, commentNode);
}
};

const testDeprecationType = (paragraphNode) => {
try {
assert.strictEqual(
paragraphNode?.children[0]?.value?.substring(0, 6),
'Type: ',
'Missing deprecation type.'
);
} catch (e) {
throw addMarkdownPathToErrorStack(e, paragraphNode);
}
};

const tree = unified()
.use(require('remark-parse'))
.parse(fs.readFileSync(source));

let expectedDeprecationCodeNumber = 0;
for (let i = 0; i < tree.children.length; i++) {
const node = tree.children[i];
if (node.type === 'html' && skipDeprecationComment.test(node.value)) {
const expectedDeprecationCode =
generateDeprecationCode(++expectedDeprecationCodeNumber);
const deprecationCodeAsText = node.value.match(skipDeprecationComment)[1];

try {
assert.strictEqual(
deprecationCodeAsText,
expectedDeprecationCode,
'Deprecation codes are not ordered correctly.'
);
} catch (e) {
throw addMarkdownPathToErrorStack(e, node);
}
}
if (node.type === 'heading' && node.depth === 3) {
const expectedDeprecationCode =
generateDeprecationCode(++expectedDeprecationCodeNumber);

testHeading(node, expectedDeprecationCode);

testAnchor(tree.children[i - 1], expectedDeprecationCode);
testYAMLComment(tree.children[i + 1]);
testDeprecationType(tree.children[i + 2]);
}
}

0 comments on commit ca5f40f

Please sign in to comment.