diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 03faf578..d439eb18 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -43,6 +43,7 @@ "rolldown": "^1.0.0-beta.53", "semver": "^7.7.3", "shiki": "^3.19.0", + "to-vfile": "^8.0.0", "unified": "^11.0.5", "unist-builder": "^4.0.0", "unist-util-find-after": "^5.0.0", @@ -1243,7 +1244,6 @@ "resolved": "https://registry.npmjs.org/@orama/core/-/core-0.0.10.tgz", "integrity": "sha512-rZ4AHeHoFTxOXMhM0An2coO3OfR+FpL0ejXc1PPrNsGB4p6VNlky7FAGeuqOvS5gUYB5ywJsmDzCxeflPtgk4w==", "license": "AGPL-3.0", - "peer": true, "dependencies": { "@orama/cuid2": "2.2.3", "dedent": "1.5.3" @@ -1254,7 +1254,6 @@ "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", "license": "MIT", - "peer": true, "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, @@ -1284,6 +1283,7 @@ "resolved": "https://registry.npmjs.org/@orama/orama/-/orama-3.1.16.tgz", "integrity": "sha512-scSmQBD8eANlMUOglxHrN1JdSW8tDghsPuS83otqealBiIeMukCQMOf/wc0JJjDXomqwNdEQFLXLGHrU6PGxuA==", "license": "Apache-2.0", + "peer": true, "engines": { "node": ">= 20.0.0" } @@ -1292,8 +1292,7 @@ "version": "0.0.5", "resolved": "https://registry.npmjs.org/@orama/oramacore-events-parser/-/oramacore-events-parser-0.0.5.tgz", "integrity": "sha512-yAuSwog+HQBAXgZ60TNKEwu04y81/09mpbYBCmz1RCxnr4ObNY2JnPZI7HmALbjAhLJ8t5p+wc2JHRK93ubO4w==", - "license": "AGPL-3.0", - "peer": true + "license": "AGPL-3.0" }, "node_modules/@orama/react-components": { "version": "0.8.1", @@ -1515,6 +1514,7 @@ "resolved": "https://registry.npmjs.org/@oramacloud/client/-/client-2.1.4.tgz", "integrity": "sha512-uNPFs4wq/iOPbggCwTkVNbIr64Vfd7ZS/h+cricXVnzXWocjDTfJ3wLL4lr0qiSu41g8z+eCAGBqJ30RO2O4AA==", "license": "ISC", + "peer": true, "dependencies": { "@orama/cuid2": "^2.2.3", "@orama/orama": "^3.0.0", @@ -3949,6 +3949,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4489,8 +4490,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/debug": { "version": "4.4.3", @@ -4772,6 +4772,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -6617,6 +6618,7 @@ "resolved": "https://registry.npmjs.org/marked/-/marked-13.0.3.tgz", "integrity": "sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA==", "license": "MIT", + "peer": true, "bin": { "marked": "bin/marked.js" }, @@ -7898,6 +7900,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -7947,6 +7950,7 @@ "resolved": "https://registry.npmjs.org/preact/-/preact-10.28.0.tgz", "integrity": "sha512-rytDAoiXr3+t6OIP3WGlDd0ouCUG1iCWzkcY3++Nreuoi17y6T5i/zRhe6uYfoVcxq6YU+sBtJouuRDsq8vvqA==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -8514,8 +8518,7 @@ "version": "0.26.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/semver": { "version": "7.7.3", @@ -9116,6 +9119,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -9152,6 +9156,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/to-vfile": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-8.0.0.tgz", + "integrity": "sha512-IcmH1xB5576MJc9qcfEC/m/nQCFt3fzMHz45sSlgJyTWjRbKW1HAkJpuf3DgE57YzIlZcwcBZA5ENQbBo4aLkg==", + "license": "MIT", + "dependencies": { + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -9483,6 +9500,7 @@ "integrity": "sha512-VUyWiTNQD7itdiMuJy+EuLEErLj3uwX/EpHQF8EOf33Dq3Ju6VW1GXm+swk6+1h7a49uv9fKZ+dft9jU7esdLA==", "dev": true, "hasInstallScript": true, + "peer": true, "dependencies": { "napi-postinstall": "^0.2.4" }, @@ -9899,6 +9917,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.3.tgz", "integrity": "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index b92a40f4..f5dafb2e 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "rolldown": "^1.0.0-beta.53", "semver": "^7.7.3", "shiki": "^3.19.0", + "to-vfile": "^8.0.0", "unified": "^11.0.5", "unist-builder": "^4.0.0", "unist-util-find-after": "^5.0.0", diff --git a/src/generators/ast-js/index.mjs b/src/generators/ast-js/index.mjs index 6900adee..44f7f270 100644 --- a/src/generators/ast-js/index.mjs +++ b/src/generators/ast-js/index.mjs @@ -1,13 +1,9 @@ import { extname } from 'node:path'; import { globSync } from 'glob'; +import { read } from 'to-vfile'; -import createJsLoader from '../../loaders/javascript.mjs'; -import createJsParser from '../../parsers/javascript.mjs'; - -const { loadFiles } = createJsLoader(); - -const { parseJsSource } = createJsParser(); +import { parseJsSource } from '../../parsers/javascript.mjs'; /** * This generator parses Javascript sources passed into the generator's input @@ -40,19 +36,9 @@ export default { async processChunk(inputSlice, itemIndices) { const filePaths = itemIndices.map(idx => inputSlice[idx]); - const vfilesPromises = loadFiles(filePaths); - - const results = []; - - for (const vfilePromise of vfilesPromises) { - const vfile = await vfilePromise; - - const parsed = await parseJsSource(vfile); - - results.push(parsed); - } - - return results; + return Promise.all( + filePaths.map(async path => parseJsSource(await read(path, 'utf-8'))) + ); }, /** diff --git a/src/generators/ast/index.mjs b/src/generators/ast/index.mjs index ad917575..eaec9ff1 100644 --- a/src/generators/ast/index.mjs +++ b/src/generators/ast/index.mjs @@ -3,12 +3,12 @@ import { extname } from 'node:path'; import { globSync } from 'glob'; +import { read } from 'to-vfile'; -import createLoader from '../../loaders/markdown.mjs'; +import createQueries from '../../utils/queries/index.mjs'; import { getRemark } from '../../utils/remark.mjs'; -const { loadFiles } = createLoader(); - +const { updateStabilityPrefixToLink } = createQueries(); const remarkProcessor = getRemark(); /** @@ -38,20 +38,18 @@ export default { async processChunk(inputSlice, itemIndices) { const filePaths = itemIndices.map(idx => inputSlice[idx]); - const vfilesPromises = loadFiles(filePaths); - - const results = []; + return Promise.all( + filePaths.map(async path => { + const vfile = await read(path, 'utf-8'); - for (const vfilePromise of vfilesPromises) { - const vfile = await vfilePromise; - - results.push({ - tree: remarkProcessor.parse(vfile), - file: { stem: vfile.stem, basename: vfile.basename }, - }); - } + updateStabilityPrefixToLink(vfile); - return results; + return { + tree: remarkProcessor.parse(vfile), + file: { stem: vfile.stem, basename: vfile.basename }, + }; + }) + ); }, /** diff --git a/src/loaders/javascript.mjs b/src/loaders/javascript.mjs deleted file mode 100644 index 78fd2c45..00000000 --- a/src/loaders/javascript.mjs +++ /dev/null @@ -1,33 +0,0 @@ -'use strict'; - -import { readFile } from 'node:fs/promises'; -import { extname } from 'node:path'; - -import { globSync } from 'glob'; -import { VFile } from 'vfile'; - -/** - * This creates a "loader" for loading Javascript source files into VFiles. - */ -const createLoader = () => { - /** - * Loads the JavaScript source files and transforms them into VFiles - * - * @param {string | Array} searchPath - */ - const loadFiles = searchPath => { - const resolvedFiles = globSync(searchPath).filter( - filePath => extname(filePath) === '.js' - ); - - return resolvedFiles.map(async filePath => { - const fileContents = await readFile(filePath, 'utf-8'); - - return new VFile({ path: filePath, value: fileContents }); - }); - }; - - return { loadFiles }; -}; - -export default createLoader; diff --git a/src/loaders/markdown.mjs b/src/loaders/markdown.mjs deleted file mode 100644 index 26dae7c6..00000000 --- a/src/loaders/markdown.mjs +++ /dev/null @@ -1,44 +0,0 @@ -'use strict'; - -import { readFile } from 'node:fs/promises'; -import { extname } from 'node:path'; - -import { globSync } from 'glob'; -import { VFile } from 'vfile'; - -import createQueries from '../utils/queries/index.mjs'; - -const { updateStabilityPrefixToLink } = createQueries(); - -/** - * This creates a "loader" for loading Markdown API doc files into VFiles. - */ -const createLoader = () => { - /** - * Loads Markdown source files and transforms them into VFiles. - * Applies stability index normalization during load. - * - * @param {string | string[]} searchPath - Glob pattern(s) or file paths - * @returns {Promise[]} Array of promises resolving to VFiles - */ - const loadFiles = searchPath => { - const resolvedFiles = globSync(searchPath).filter( - filePath => extname(filePath) === '.md' - ); - - return resolvedFiles.map(async filePath => { - const fileContents = await readFile(filePath, 'utf-8'); - - const vfile = new VFile({ path: filePath, value: fileContents }); - - // Normalizes all the Stability Index prefixes with Markdown links - updateStabilityPrefixToLink(vfile); - - return vfile; - }); - }; - - return { loadFiles }; -}; - -export default createLoader; diff --git a/src/parsers/javascript.mjs b/src/parsers/javascript.mjs index d5a7714d..a964415d 100644 --- a/src/parsers/javascript.mjs +++ b/src/parsers/javascript.mjs @@ -3,50 +3,23 @@ import * as acorn from 'acorn'; /** - * Creates a Javascript source parser for a given source file + * Parses a given JavaScript file into an ESTree AST representation of it + * + * @param {import('vfile').VFile} sourceFile + * @returns {Promise} */ -const createParser = () => { - /** - * Parses a given JavaScript file into an ESTree AST representation of it - * - * @param {import('vfile').VFile | Promise} sourceFile - * @returns {Promise} - */ - const parseJsSource = async sourceFile => { - // We allow the API doc VFile to be a Promise of a VFile also, - // hence we want to ensure that it first resolves before we pass it to the parser - const resolvedSourceFile = await Promise.resolve(sourceFile); - - if (typeof resolvedSourceFile.value !== 'string') { - throw new TypeError( - `expected resolvedSourceFile.value to be string but got ${typeof resolvedSourceFile.value}` - ); - } - - const res = acorn.parse(resolvedSourceFile.value, { - allowReturnOutsideFunction: true, - ecmaVersion: 'latest', - locations: true, - }); - - return { ...res, path: resolvedSourceFile.path }; - }; - - /** - * Parses multiple JavaScript files into ESTree ASTs by wrapping parseJsSource - * - * @param {Array>} apiDocs List of API doc files to be parsed - * @returns {Promise>} - */ - const parseJsSources = async apiDocs => { - // We do a Promise.all, to ensure that each API doc is resolved asynchronously - // but all need to be resolved first before we return the result to the caller - const resolvedApiDocEntries = await Promise.all(apiDocs.map(parseJsSource)); - - return resolvedApiDocEntries; - }; - - return { parseJsSource, parseJsSources }; +export const parseJsSource = async sourceFile => { + if (typeof sourceFile.value !== 'string') { + throw new TypeError( + `expected sourceFile.value to be string but got ${typeof sourceFile.value}` + ); + } + + const res = acorn.parse(sourceFile.value, { + allowReturnOutsideFunction: true, + ecmaVersion: 'latest', + locations: true, + }); + + return { ...res, path: sourceFile.path }; }; - -export default createParser;