diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..c53ce87a --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +# Tests files +src/generators/api-links/test/fixtures/ +*.snapshot diff --git a/eslint.config.mjs b/eslint.config.mjs index 26689c91..3eb1bc7a 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -47,4 +47,7 @@ export default [ // @see https://eslint.org/docs/latest/rules to learn more about these rules pluginJs.configs.recommended, eslintConfigPrettier, + { + ignores: ['src/generators/api-links/test/fixtures/**'], + }, ]; diff --git a/package.json b/package.json index 3563eee8..631c8991 100644 --- a/package.json +++ b/package.json @@ -5,13 +5,14 @@ "url": "git+https://github.com/nodejs/api-docs-tooling.git" }, "scripts": { - "lint": "eslint .", - "lint:fix": "eslint --fix .", + "lint": "eslint . --no-warn-ignored", + "lint:fix": "eslint --fix . --no-warn-ignored", "format": "prettier .", "format:write": "prettier --write .", "test": "node --test", - "test:watch": "node --test --watch", "test:coverage": "node --experimental-test-coverage --test", + "test:update-snapshots": "node --test --test-update-snapshots", + "test:watch": "node --test --watch", "prepare": "husky", "run": "node bin/cli.mjs", "watch": "node --watch bin/cli.mjs" diff --git a/src/generators/api-links/test/fixtures.test.mjs b/src/generators/api-links/test/fixtures.test.mjs new file mode 100644 index 00000000..9f8ee53e --- /dev/null +++ b/src/generators/api-links/test/fixtures.test.mjs @@ -0,0 +1,32 @@ +import { describe, it } from 'node:test'; +import { readdir } from 'node:fs/promises'; +import { basename, extname, join } from 'node:path'; +import astJs from '../../ast-js/index.mjs'; +import apiLinks from '../index.mjs'; + +const FIXTURES_DIRECTORY = join(import.meta.dirname, 'fixtures'); +const fixtures = await readdir(FIXTURES_DIRECTORY); + +const sourceFiles = fixtures + .filter(fixture => extname(fixture) === '.js') + .map(fixture => join(FIXTURES_DIRECTORY, fixture)); + +describe('api links', () => { + describe('should work correctly for all fixtures', () => { + sourceFiles.forEach(sourceFile => { + it(`${basename(sourceFile)}`, async t => { + const astJsResult = await astJs.generate(undefined, { + input: [sourceFile], + }); + + const actualOutput = await apiLinks.generate(astJsResult, {}); + + for (const [k, v] of Object.entries(actualOutput)) { + actualOutput[k] = v.replace(/.*(?=lib\/)/, ''); + } + + t.assert.snapshot(actualOutput); + }); + }); + }); +}); diff --git a/src/generators/api-links/test/fixtures.test.mjs.snapshot b/src/generators/api-links/test/fixtures.test.mjs.snapshot new file mode 100644 index 00000000..2821ea09 --- /dev/null +++ b/src/generators/api-links/test/fixtures.test.mjs.snapshot @@ -0,0 +1,49 @@ +exports[`api links > should work correctly for all fixtures > buffer.js 1`] = ` +{ + "buffer.Buffer": "lib/buffer.js#L5", + "buf.instanceMethod": "lib/buffer.js#L8" +} +`; + +exports[`api links > should work correctly for all fixtures > class.js 1`] = ` +{ + "Class": "lib/class.js#L5", + "new Class": "lib/class.js#L6", + "class.method": "lib/class.js#L7" +} +`; + +exports[`api links > should work correctly for all fixtures > exports.js 1`] = ` +{ + "exports.fn1": "lib/exports.js#L8", + "exports.fn2": "lib/exports.js#L10", + "exports.Buffer": "lib/exports.js#L5", + "exports.fn3": "lib/exports.js#L12" +} +`; + +exports[`api links > should work correctly for all fixtures > mod.js 1`] = ` +{ + "mod.foo": "lib/mod.js#L5" +} +`; + +exports[`api links > should work correctly for all fixtures > prototype.js 1`] = ` +{ + "prototype.Class": "lib/prototype.js#L5", + "Class.classMethod": "lib/prototype.js#L8", + "class.instanceMethod": "lib/prototype.js#L9" +} +`; + +exports[`api links > should work correctly for all fixtures > reverse.js 1`] = ` +{ + "asserts": "lib/reverse.js#L8", + "asserts.ok": "lib/reverse.js#L5", + "asserts.strictEqual": "lib/reverse.js#L12" +} +`; + +exports[`api links > should work correctly for all fixtures > root.js 1`] = ` +{} +`; diff --git a/src/generators/api-links/test/fixtures/buffer.js b/src/generators/api-links/test/fixtures/buffer.js new file mode 100644 index 00000000..8ee44123 --- /dev/null +++ b/src/generators/api-links/test/fixtures/buffer.js @@ -0,0 +1,12 @@ +'use strict'; + +// Buffer instance methods are exported as 'buf'. + +function Buffer() { +} + +Buffer.prototype.instanceMethod = function() {} + +module.exports = { + Buffer +}; diff --git a/src/generators/api-links/test/fixtures/class.js b/src/generators/api-links/test/fixtures/class.js new file mode 100644 index 00000000..7db5c008 --- /dev/null +++ b/src/generators/api-links/test/fixtures/class.js @@ -0,0 +1,12 @@ +'use strict'; + +// An exported class using ES2015 class syntax. + +class Class { + constructor() {}; + method() {}; +} + +module.exports = { + Class +}; diff --git a/src/generators/api-links/test/fixtures/exports.js b/src/generators/api-links/test/fixtures/exports.js new file mode 100644 index 00000000..880fdf6c --- /dev/null +++ b/src/generators/api-links/test/fixtures/exports.js @@ -0,0 +1,13 @@ +'use strict'; + +// Support `exports` as an alternative to `module.exports`. + +function Buffer() {}; + +exports.Buffer = Buffer; +exports.fn1 = function fn1() {}; + +var fn2 = exports.fn2 = function() {}; + +function fn3() {}; +exports.fn3 = fn3; diff --git a/src/generators/api-links/test/fixtures/mod.js b/src/generators/api-links/test/fixtures/mod.js new file mode 100644 index 00000000..72606121 --- /dev/null +++ b/src/generators/api-links/test/fixtures/mod.js @@ -0,0 +1,11 @@ +'use strict'; + +// A module may export one or more methods. + +function foo() { +} + + +module.exports = { + foo +}; diff --git a/src/generators/api-links/test/fixtures/prototype.js b/src/generators/api-links/test/fixtures/prototype.js new file mode 100644 index 00000000..40218e84 --- /dev/null +++ b/src/generators/api-links/test/fixtures/prototype.js @@ -0,0 +1,13 @@ +'use strict'; + +// An exported class using classic prototype syntax. + +function Class() { +} + +Class.classMethod = function() {} +Class.prototype.instanceMethod = function() {} + +module.exports = { + Class +}; diff --git a/src/generators/api-links/test/fixtures/reverse.js b/src/generators/api-links/test/fixtures/reverse.js new file mode 100644 index 00000000..5a61e50d --- /dev/null +++ b/src/generators/api-links/test/fixtures/reverse.js @@ -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() { +} diff --git a/src/generators/api-links/test/fixtures/root.js b/src/generators/api-links/test/fixtures/root.js new file mode 100644 index 00000000..6cf9fee9 --- /dev/null +++ b/src/generators/api-links/test/fixtures/root.js @@ -0,0 +1,10 @@ +'use strict'; + +// Set root member +let foo = true; +foo = false; + +// Return outside of function +if (!foo) { + return; +} diff --git a/src/generators/api-links/utils/extractExports.mjs b/src/generators/api-links/utils/extractExports.mjs index 228eb5bc..a318c800 100644 --- a/src/generators/api-links/utils/extractExports.mjs +++ b/src/generators/api-links/utils/extractExports.mjs @@ -179,7 +179,7 @@ function handleVariableDeclaration(node, basename, nameToLineNumberMap) { switch (lhs.object.name) { case 'exports': { nameToLineNumberMap[`${basename}.${lhs.property.name}`] = - node.start.line; + node.loc.start.line; break; }