tools: add [src] links to assert.html
Parse `const assert = module.exports = ok;` as exporting a constructor named `assert`. PR-URL: https://github.com/nodejs/node/pull/22601 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
This commit is contained in:
Родитель
3f9186e03c
Коммит
3f35e88329
|
@ -0,0 +1,13 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Parallel assignment to the exported variable and module.exports.
|
||||||
|
|
||||||
|
function ok() {
|
||||||
|
}
|
||||||
|
|
||||||
|
const asserts = module.exports = ok;
|
||||||
|
|
||||||
|
asserts.ok = ok;
|
||||||
|
|
||||||
|
asserts.strictEqual = function() {
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"asserts": "reverse.js#L8",
|
||||||
|
"asserts.ok": "reverse.js#L5",
|
||||||
|
"asserts.strictEqual": "reverse.js#L12"
|
||||||
|
}
|
|
@ -55,10 +55,14 @@ process.argv.slice(2).forEach((file) => {
|
||||||
const ast = acorn.parse(source, { ecmaVersion: 10, locations: true });
|
const ast = acorn.parse(source, { ecmaVersion: 10, locations: true });
|
||||||
const program = ast.body;
|
const program = ast.body;
|
||||||
|
|
||||||
|
// Build link
|
||||||
|
const link = `https://github.com/${repo}/blob/${tag}/` +
|
||||||
|
path.relative('.', file).replace(/\\/g, '/');
|
||||||
|
|
||||||
// Scan for exports.
|
// Scan for exports.
|
||||||
const exported = { constructors: [], identifiers: [] };
|
const exported = { constructors: [], identifiers: [] };
|
||||||
program.forEach((statement) => {
|
program.forEach((statement) => {
|
||||||
if (statement.type !== 'ExpressionStatement') return;
|
if (statement.type === 'ExpressionStatement') {
|
||||||
const expr = statement.expression;
|
const expr = statement.expression;
|
||||||
if (expr.type !== 'AssignmentExpression') return;
|
if (expr.type !== 'AssignmentExpression') return;
|
||||||
|
|
||||||
|
@ -85,6 +89,17 @@ process.argv.slice(2).forEach((file) => {
|
||||||
} else if (rhs.type === 'Identifier') {
|
} else if (rhs.type === 'Identifier') {
|
||||||
exported.identifiers.push(rhs.name);
|
exported.identifiers.push(rhs.name);
|
||||||
}
|
}
|
||||||
|
} else if (statement.type === 'VariableDeclaration') {
|
||||||
|
for (const decl of statement.declarations) {
|
||||||
|
let init = decl.init;
|
||||||
|
while (init && init.type === 'AssignmentExpression') init = init.left;
|
||||||
|
if (!init || init.type !== 'MemberExpression') continue;
|
||||||
|
if (init.object.name !== 'module') continue;
|
||||||
|
if (init.property.name !== 'exports') continue;
|
||||||
|
exported.constructors.push(decl.id.name);
|
||||||
|
definition[decl.id.name] = `${link}#L${statement.loc.start.line}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Scan for definitions matching those exports; currently supports:
|
// Scan for definitions matching those exports; currently supports:
|
||||||
|
@ -93,8 +108,7 @@ process.argv.slice(2).forEach((file) => {
|
||||||
// ClassName.prototype.foo = ...;
|
// ClassName.prototype.foo = ...;
|
||||||
// function Identifier(...) {...};
|
// function Identifier(...) {...};
|
||||||
//
|
//
|
||||||
const link = `https://github.com/${repo}/blob/${tag}/` +
|
const indirect = {};
|
||||||
path.relative('.', file).replace(/\\/g, '/');
|
|
||||||
|
|
||||||
program.forEach((statement) => {
|
program.forEach((statement) => {
|
||||||
if (statement.type === 'ExpressionStatement') {
|
if (statement.type === 'ExpressionStatement') {
|
||||||
|
@ -128,6 +142,11 @@ process.argv.slice(2).forEach((file) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
definition[name] = `${link}#L${statement.loc.start.line}`;
|
definition[name] = `${link}#L${statement.loc.start.line}`;
|
||||||
|
|
||||||
|
if (expr.left.property.name === expr.right.name) {
|
||||||
|
indirect[expr.right.name] = name;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (statement.type === 'FunctionDeclaration') {
|
} else if (statement.type === 'FunctionDeclaration') {
|
||||||
const name = statement.id.name;
|
const name = statement.id.name;
|
||||||
if (!exported.identifiers.includes(name)) return;
|
if (!exported.identifiers.includes(name)) return;
|
||||||
|
@ -136,6 +155,18 @@ process.argv.slice(2).forEach((file) => {
|
||||||
`${link}#L${statement.loc.start.line}`;
|
`${link}#L${statement.loc.start.line}`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Search for indirect references of the form ClassName.foo = foo;
|
||||||
|
if (Object.keys(indirect).length > 0) {
|
||||||
|
program.forEach((statement) => {
|
||||||
|
if (statement.type === 'FunctionDeclaration') {
|
||||||
|
const name = statement.id.name;
|
||||||
|
if (indirect[name]) {
|
||||||
|
definition[indirect[name]] = `${link}#L${statement.loc.start.line}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(JSON.stringify(definition, null, 2));
|
console.log(JSON.stringify(definition, null, 2));
|
||||||
|
|
Загрузка…
Ссылка в новой задаче