├── .github
└── workflows
│ └── node.js.yml
├── LICENSE
├── README.md
├── dist
└── index.cjs
├── docs
└── api.md
├── example
├── explain-source.js
├── explain.js
├── render-source.js
├── render.js
├── using-config-explain.js
├── using-config-input.js
├── using-config-render.js
└── using-config.json
├── index.js
├── lib
├── explain.js
├── jsdoc-command.js
├── render.js
└── temp-file.js
├── package-lock.json
├── package.json
└── test
├── caching.js
├── explain.js
├── fixture
├── buggy
│ ├── bad-doclet-syntax.js
│ ├── broken-javascript.js
│ └── ignore-with-value.js
├── class-all
│ ├── 0-src.js
│ └── 1-jsdoc.json
└── folder with spaces
│ └── fake-jsdoc.js
├── lib
└── fixture.js
└── render.js
/.github/workflows/node.js.yml:
--------------------------------------------------------------------------------
1 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
2 |
3 | name: Node.js CI
4 |
5 | on:
6 | push:
7 | branches: [ master, next ]
8 | pull_request:
9 | branches: [ master ]
10 |
11 | jobs:
12 | build:
13 |
14 | runs-on: ${{ matrix.os }}
15 |
16 | strategy:
17 | matrix:
18 | os: [ubuntu-latest, windows-latest]
19 | node-version: [12, 14, 16, 18, 20, 22, 23]
20 |
21 | steps:
22 | - uses: actions/checkout@v4
23 | - name: Use Node.js ${{ matrix.node-version }}
24 | uses: actions/setup-node@v4
25 | with:
26 | node-version: ${{ matrix.node-version }}
27 | cache: 'npm'
28 | - run: npm install
29 | - run: npm i -D @75lb/nature
30 | - run: npm run test:ci
31 |
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-24 Lloyd Brookes <75pound@gmail.com>
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.npmjs.org/package/jsdoc-api)
2 | [](https://www.npmjs.org/package/jsdoc-api)
3 | [](https://github.com/jsdoc2md/jsdoc-api/network/dependents?dependent_type=REPOSITORY)
4 | [](https://github.com/jsdoc2md/jsdoc-api/network/dependents?dependent_type=PACKAGE)
5 | [](https://github.com/jsdoc2md/jsdoc-api/actions/workflows/node.js.yml)
6 | [](https://github.com/feross/standard)
7 |
8 | ***Upgraders, please check the [release notes](https://github.com/jsdoc2md/jsdoc-api/releases).***
9 |
10 | # jsdoc-api
11 |
12 | A programmatic interface for [jsdoc3](https://github.com/jsdoc3/jsdoc) with a few features:
13 |
14 | - Asynchronous 'explain' and 'render documentation' methods (the two main jsdoc operations).
15 | - Input (source code) can supplied as a string or set of file names and/or globs.
16 | - Optional caching, dramatically speeding up future invocations with the same input.
17 |
18 | ## Synopsis
19 |
20 | To output an array of json objects, each representing a doclet, use [.explain()](https://github.com/jsdoc2md/jsdoc-api/blob/master/docs/api.md#module_jsdoc-api--jsdoc.explain). Pass in an array of file names and/or glob expressions. Use the `cache: true` flag for a faster, more efficient invocation (cached output from a prior invocation will be returned if the input has not changed).
21 |
22 | ```js
23 | import jsdoc from 'jsdoc-api'
24 |
25 | const data = await jsdoc.explain({ files: ['index.js', 'lib/*.js'], cache: true })
26 | console.log(data)
27 | ```
28 |
29 | Typical output (truncated):
30 |
31 | ```js
32 | [
33 | {
34 | comment: '/**\n' +
35 | ' * The [cache-point](https://github.com/75lb/cache-point) instance used when `cache: true` is specified on `.explain()`.\n' +
36 | ' * @type {external:cache-point}\n' +
37 | ' */',
38 | meta: {
39 | range: [ 491, 554 ],
40 | filename: 'index.js',
41 | lineno: 21,
42 | columnno: 6,
43 | path: '/Users/lloyd/Documents/jsdoc2md/jsdoc-api',
44 | code: { id: 'astnode100000027', name: 'cache', type: 'NewExpression', value: '' }
45 | },
46 | description: 'The [cache-point](https://github.com/75lb/cache-point) instance used when `cache: true` is specified on `.explain()`.',
47 | type: { names: [ 'external:cache-point' ] },
48 | name: 'cache',
49 | longname: 'module:jsdoc-api~cache',
50 | kind: 'constant',
51 | scope: 'inner',
52 | memberof: 'module:jsdoc-api',
53 | params: []
54 | },
55 | // etc
56 | // etc
57 | ]
58 | ```
59 |
60 | As an alternative to passing in file names/globs (above), you can pass in one or more source code strings.
61 |
62 | ```js
63 | import jsdoc from 'jsdoc-api'
64 |
65 | const data = await jsdoc.explain({ source: '/** example doclet */ \n var example = true' })
66 | console.log(data)
67 | ```
68 |
69 | Output:
70 |
71 | ```js
72 | [
73 | {
74 | comment: '/** example doclet */',
75 | meta: {
76 | range: [ 28, 42 ],
77 | filename: '934b1fbe2810.js',
78 | lineno: 2,
79 | columnno: 5,
80 | path: '/var/folders/bt/jgn73jf50vsb5gj92dk00v3r0000gn/T/jsdoc-api-W854dk',
81 | code: { id: 'astnode100000003', name: 'example', type: 'Literal', value: true }
82 | },
83 | description: 'example doclet',
84 | name: 'example',
85 | longname: 'example',
86 | kind: 'member',
87 | scope: 'global',
88 | params: []
89 | },
90 | { kind: 'package', longname: 'package:undefined', files: [ '/var/folders/bt/jgn73jf50vsb5gj92dk00v3r0000gn/T/jsdoc-api-W854dk/934b1fbe2810.js' ] }
91 | ]
92 | ```
93 |
94 | Finally, use the `render()` method to invocate jsdoc directly, generating your documentation.
95 |
96 | ```js
97 | import jsdoc from 'jsdoc-api'
98 |
99 | await jsdoc.render({ files: ['index.js', 'lib/something.js'], destination: 'jsdoc-output' })
100 | ```
101 |
102 | If you need to use a specific `jsdoc` version or fork, specify its path via `JSDOC_PATH` and jsdoc-api will use it instead of the default.
103 |
104 | ```sh
105 | $ export JSDOC_PATH=./node_modules/.bin/jsdoc # An alternative jsdoc version you installed
106 | $ node my-jsdoc-api-script.js # Run your jsdoc-api app as usual
107 | ```
108 |
109 | See the [API documentation](https://github.com/jsdoc2md/jsdoc-api/blob/master/docs/api.md) for further details. See the [example folder](https://github.com/jsdoc2md/jsdoc-api/tree/master/example) for code examples.
110 |
111 | * * *
112 |
113 | © 2015-24 [Lloyd Brookes](https://github.com/75lb) \<75pound@gmail.com\>.
114 |
115 | Tested by [test-runner](https://github.com/test-runner-js/test-runner). Documented by [jsdoc-to-markdown](https://github.com/jsdoc2md/jsdoc-to-markdown).
116 |
--------------------------------------------------------------------------------
/dist/index.cjs:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Cache = require('cache-point');
4 | var arrayify = require('array-back');
5 | var path = require('path');
6 | var fs = require('node:fs');
7 | var os = require('os');
8 | var crypto = require('crypto');
9 | var FileSet = require('file-set');
10 | var assert = require('assert');
11 | var walkBack = require('walk-back');
12 | var currentModulePaths = require('current-module-paths');
13 | var toSpawnArgs = require('object-to-spawn-args');
14 | var cp = require('child_process');
15 | var util = require('node:util');
16 |
17 | var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
18 | class TempFile {
19 | constructor (source) {
20 | this.path = path.join(TempFile.tempFileDir, crypto.randomBytes(6).toString('hex') + '.js');
21 | fs.writeFileSync(this.path, source);
22 | }
23 |
24 | delete () {
25 | try {
26 | fs.unlinkSync(this.path);
27 | } catch (err) {
28 | // already deleted
29 | }
30 | }
31 |
32 | static tempFileDir = path.join(os.homedir(), '.jsdoc-api/temp')
33 | static cacheDir = path.join(os.homedir(), '.jsdoc-api/cache')
34 |
35 | static createTmpDirs () {
36 | /* No longer using os.tmpdir(). See: https://github.com/jsdoc2md/jsdoc-api/issues/19 */
37 | fs.mkdirSync(TempFile.tempFileDir, { recursive: true });
38 | fs.mkdirSync(TempFile.cacheDir, { recursive: true });
39 | }
40 | }
41 |
42 | const { __dirname: __dirname$1 } = currentModulePaths((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
43 |
44 | class JsdocCommand {
45 | constructor (options = {}, cache) {
46 | options.files = arrayify(options.files);
47 | options.source = arrayify(options.source);
48 | assert.ok(
49 | options.files.length || options.source.length || options.configure,
50 | 'Must set at least one of .files, .source or .configure'
51 | );
52 |
53 | this.cache = cache;
54 | this.tempFiles = [];
55 |
56 | const jsdocOptions = Object.assign({}, options);
57 | delete jsdocOptions.files;
58 | delete jsdocOptions.source;
59 | delete jsdocOptions.cache;
60 |
61 | /* see: https://github.com/jsdoc2md/jsdoc-api/issues/22 */
62 | if (!jsdocOptions.pedantic) {
63 | delete jsdocOptions.pedantic;
64 | }
65 |
66 | this.options = options;
67 | this.jsdocOptions = jsdocOptions;
68 |
69 | this.jsdocPath = process.env.JSDOC_PATH || walkBack(
70 | path.join(__dirname$1, '..'),
71 | path.join('node_modules', 'jsdoc', 'jsdoc.js')
72 | );
73 | }
74 |
75 | async execute () {
76 | this.inputFileSet = new FileSet();
77 | await this.inputFileSet.add(this.options.files);
78 | /* node-glob v9+ (used by file-set) no longer sorts the output by default. We will continue to sort the file list, for now, as it's what the user expected by default. The user's system locale is used. */
79 | const collator = new Intl.Collator();
80 | this.inputFileSet.files.sort(collator.compare);
81 |
82 | if (this.options.source.length) {
83 | this.tempFiles = this.options.source.map(source => new TempFile(source));
84 | this.tempFileSet = new FileSet();
85 | await this.tempFileSet.add(this.tempFiles.map(t => t.path));
86 | }
87 |
88 | let result;
89 | try {
90 | result = await this.getOutput();
91 | } finally {
92 | /* run even if getOutput fails */
93 | if (this.tempFiles) {
94 | for (const tempFile of this.tempFiles) {
95 | tempFile.delete();
96 | }
97 | }
98 | }
99 | return result
100 | }
101 | }
102 |
103 | util.promisify(cp.exec);
104 |
105 | class Explain extends JsdocCommand {
106 | async getOutput () {
107 | if (this.options.cache && !this.options.source.length) {
108 | try {
109 | return await this.readCache()
110 | } catch (err) {
111 | if (err.code === 'ENOENT') {
112 | return this._runJsdoc()
113 | } else {
114 | throw err
115 | }
116 | }
117 | } else {
118 | return this._runJsdoc()
119 | }
120 | }
121 |
122 | async _runJsdoc () {
123 | const jsdocArgs = [
124 | this.jsdocPath,
125 | ...toSpawnArgs(this.jsdocOptions),
126 | '-X',
127 | ...(this.options.source.length ? this.tempFileSet.files : this.inputFileSet.files)
128 | ];
129 | let jsdocOutput = { stdout: '', stderr: '' };
130 |
131 | const code = await new Promise((resolve, reject) => {
132 | const handle = cp.spawn('node', jsdocArgs);
133 | handle.stdout.setEncoding('utf8');
134 | handle.stderr.setEncoding('utf8');
135 | handle.stdout.on('data', chunk => {
136 | jsdocOutput.stdout += chunk;
137 | });
138 | handle.stderr.on('data', chunk => {
139 | jsdocOutput.stderr += chunk;
140 | });
141 | handle.on('exit', (code) => {
142 | resolve(code);
143 | });
144 | handle.on('error', reject);
145 | });
146 | try {
147 | if (code > 0) {
148 | throw new Error('jsdoc exited with non-zero code: ' + code)
149 | } else {
150 | const explainOutput = JSON.parse(jsdocOutput.stdout);
151 | if (this.options.cache) {
152 | await this.cache.write(this.cacheKey, explainOutput);
153 | }
154 | return explainOutput
155 | }
156 | } catch (err) {
157 | const firstLineOfStdout = jsdocOutput.stdout.split(/\r?\n/)[0];
158 | const jsdocErr = new Error(jsdocOutput.stderr.trim() || firstLineOfStdout || 'Jsdoc failed.');
159 | jsdocErr.name = 'JSDOC_ERROR';
160 | jsdocErr.cause = err;
161 | throw jsdocErr
162 | }
163 | }
164 |
165 | async readCache () {
166 | if (this.cache) {
167 | /* Create the cache key then check the cache for a match, returning pre-generated output if so.
168 | The current cache key is a union of the input file names plus their content - this could be expensive when processing a lot of files.
169 | */
170 | const promises = this.inputFileSet.files.map(file => {
171 | return fs.promises.readFile(file, 'utf8')
172 | });
173 | const contents = await Promise.all(promises);
174 | this.cacheKey = contents.concat(this.inputFileSet.files);
175 | return this.cache.read(this.cacheKey)
176 | } else {
177 | return Promise.reject()
178 | }
179 | }
180 | }
181 |
182 | class Render extends JsdocCommand {
183 | async getOutput () {
184 | return new Promise((resolve, reject) => {
185 | const jsdocArgs = toSpawnArgs(this.jsdocOptions)
186 | .concat(this.options.source.length ? this.tempFiles.map(t => t.path) : this.options.files);
187 |
188 | jsdocArgs.unshift(this.jsdocPath);
189 | const handle = cp.spawn('node', jsdocArgs, { stdio: 'inherit' });
190 | handle.on('close', resolve);
191 | })
192 | }
193 | }
194 |
195 | /**
196 | * @module jsdoc-api
197 | * @typicalname jsdoc
198 | */
199 |
200 | TempFile.createTmpDirs();
201 |
202 | /**
203 | * @external cache-point
204 | * @see https://github.com/75lb/cache-point
205 | */
206 | /**
207 | * The [cache-point](https://github.com/75lb/cache-point) instance used when `cache: true` is specified on `.explain()`.
208 | * @type {external:cache-point}
209 | */
210 | const cache = new Cache({ dir: TempFile.cacheDir });
211 |
212 | /**
213 | * @alias module:jsdoc-api
214 | */
215 | const jsdoc = {
216 | cache,
217 |
218 | /**
219 | * Returns a promise for the jsdoc explain output.
220 | *
221 | * @param [options] {module:jsdoc-api~JsdocOptions}
222 | * @fulfil {object[]} - jsdoc explain output
223 | * @returns {Promise}
224 | */
225 | async explain (options) {
226 | options = new JsdocOptions(options);
227 | const command = new Explain(options, cache);
228 | return command.execute()
229 | },
230 |
231 | /**
232 | * Render jsdoc documentation.
233 | *
234 | * @param [options] {module:jsdoc-api~JsdocOptions}
235 | * @prerequisite Requires node v0.12 or above
236 | * @example
237 | * await jsdoc.render({ files: 'lib/*', destination: 'api-docs' })
238 | */
239 | async render (options) {
240 | options = new JsdocOptions(options);
241 | const command = new Render(options);
242 | return command.execute()
243 | }
244 | };
245 |
246 | /**
247 | * The jsdoc options, common for all operations.
248 | * @typicalname options
249 | */
250 | class JsdocOptions {
251 | constructor (options = {}) {
252 | /**
253 | * One or more filenames to process. Either `files`, `source` or `configure` must be supplied.
254 | * @type {string|string[]}
255 | */
256 | this.files = arrayify(options.files);
257 |
258 | /**
259 | * A string or an array of strings containing source code to process. Either `files`, `source` or `configure` must be supplied.
260 | * @type {string|string[]}
261 | */
262 | this.source = options.source;
263 |
264 | /**
265 | * Set to `true` to cache the output - future invocations with the same input will return immediately.
266 | * @type {boolean}
267 | * @default
268 | */
269 | this.cache = options.cache;
270 |
271 | /**
272 | * Only display symbols with the given access: "public", "protected", "private" or "undefined", or "all" for all access levels. Default: all except "private".
273 | * @type {string}
274 | */
275 | this.access = options.access;
276 |
277 | /**
278 | * The path to the configuration file. Default: path/to/jsdoc/conf.json. Either `files`, `source` or `configure` must be supplied.
279 | * @type {string}
280 | */
281 | this.configure = options.configure;
282 |
283 | /**
284 | * The path to the output folder. Use "console" to dump data to the console. Default: ./out/.
285 | * @type {string}
286 | */
287 | this.destination = options.destination;
288 |
289 | /**
290 | * Assume this encoding when reading all source files. Default: utf8.
291 | * @type {string}
292 | */
293 | this.encoding = options.encoding;
294 |
295 | /**
296 | * Display symbols marked with the @private tag. Equivalent to "--access all". Default: false.
297 | * @type {boolean}
298 | */
299 | this.private = options.private;
300 |
301 | /**
302 | * The path to the project's package file. Default: path/to/sourcefiles/package.json
303 | * @type {string}
304 | */
305 | this.package = options.package;
306 |
307 | /**
308 | * Treat errors as fatal errors, and treat warnings as errors. Default: false.
309 | * @type {boolean}
310 | */
311 | this.pedantic = options.pedantic;
312 |
313 | /**
314 | * A query string to parse and store in jsdoc.env.opts.query. Example: foo=bar&baz=true.
315 | * @type {string}
316 | */
317 | this.query = options.query;
318 |
319 | /**
320 | * Recurse into subdirectories when scanning for source files and tutorials.
321 | * @type {boolean}
322 | */
323 | this.recurse = options.recurse;
324 |
325 | /**
326 | * The path to the project's README file. Default: path/to/sourcefiles/README.md.
327 | * @type {string}
328 | */
329 | this.readme = options.readme;
330 |
331 | /* Warning to avoid a common mistake where dmd templates are passed in.. a jsdoc template must be a filename. */
332 | if (typeof options.template === 'string' && options.template.split(/\r?\n/).length !== 1) {
333 | console.warn('Suspicious `options.template` value - the jsdoc `template` option must be a file path.');
334 | console.warn(options.template);
335 | }
336 |
337 | /**
338 | * The path to the template to use. Default: path/to/jsdoc/templates/default.
339 | * @type {string}
340 | */
341 | this.template = options.template;
342 |
343 | /**
344 | * Directory in which JSDoc should search for tutorials.
345 | * @type {string}
346 | */
347 | this.tutorials = options.tutorials;
348 | }
349 | }
350 |
351 | module.exports = jsdoc;
352 |
--------------------------------------------------------------------------------
/docs/api.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## jsdoc-api
4 |
5 | * [jsdoc-api](#module_jsdoc-api)
6 | * [jsdoc](#exp_module_jsdoc-api--jsdoc) ⏏
7 | * _static_
8 | * [.explain([options])](#module_jsdoc-api--jsdoc.explain) ⇒ Promise
9 | * [.render([options])](#module_jsdoc-api--jsdoc.render)
10 | * _inner_
11 | * [~JsdocOptions](#module_jsdoc-api--jsdoc..JsdocOptions)
12 | * [.files](#module_jsdoc-api--jsdoc..JsdocOptions+files) : string
\| Array.<string>
13 | * [.source](#module_jsdoc-api--jsdoc..JsdocOptions+source) : string
\| Array.<string>
14 | * [.cache](#module_jsdoc-api--jsdoc..JsdocOptions+cache) : boolean
15 | * [.access](#module_jsdoc-api--jsdoc..JsdocOptions+access) : string
16 | * [.configure](#module_jsdoc-api--jsdoc..JsdocOptions+configure) : string
17 | * [.destination](#module_jsdoc-api--jsdoc..JsdocOptions+destination) : string
18 | * [.encoding](#module_jsdoc-api--jsdoc..JsdocOptions+encoding) : string
19 | * [.private](#module_jsdoc-api--jsdoc..JsdocOptions+private) : boolean
20 | * [.package](#module_jsdoc-api--jsdoc..JsdocOptions+package) : string
21 | * [.pedantic](#module_jsdoc-api--jsdoc..JsdocOptions+pedantic) : boolean
22 | * [.query](#module_jsdoc-api--jsdoc..JsdocOptions+query) : string
23 | * [.recurse](#module_jsdoc-api--jsdoc..JsdocOptions+recurse) : boolean
24 | * [.readme](#module_jsdoc-api--jsdoc..JsdocOptions+readme) : string
25 | * [.template](#module_jsdoc-api--jsdoc..JsdocOptions+template) : string
26 | * [.tutorials](#module_jsdoc-api--jsdoc..JsdocOptions+tutorials) : string
27 | * [~cache](#module_jsdoc-api--jsdoc..cache) : [cache-point
](https://github.com/75lb/cache-point)
28 |
29 |
30 |
31 | ### jsdoc ⏏
32 | **Kind**: Exported constant
33 |
34 |
35 | #### jsdoc.explain([options]) ⇒ Promise
36 | Returns a promise for the jsdoc explain output.
37 |
38 | **Kind**: static method of [jsdoc
](#exp_module_jsdoc-api--jsdoc)
39 | **Fulfil**: object[]
- jsdoc explain output
40 |
41 | | Param | Type |
42 | | --- | --- |
43 | | [options] | [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions) |
44 |
45 |
46 |
47 | #### jsdoc.render([options])
48 | Render jsdoc documentation.
49 |
50 | **Kind**: static method of [jsdoc
](#exp_module_jsdoc-api--jsdoc)
51 | **Prerequisite**: Requires node v0.12 or above
52 |
53 | | Param | Type |
54 | | --- | --- |
55 | | [options] | [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions) |
56 |
57 | **Example**
58 | ```js
59 | await jsdoc.render({ files: 'lib/*', destination: 'api-docs' })
60 | ```
61 |
62 |
63 | #### jsdoc~JsdocOptions
64 | The jsdoc options, common for all operations.
65 |
66 | **Kind**: inner class of [jsdoc
](#exp_module_jsdoc-api--jsdoc)
67 |
68 | * [~JsdocOptions](#module_jsdoc-api--jsdoc..JsdocOptions)
69 | * [.files](#module_jsdoc-api--jsdoc..JsdocOptions+files) : string
\| Array.<string>
70 | * [.source](#module_jsdoc-api--jsdoc..JsdocOptions+source) : string
\| Array.<string>
71 | * [.cache](#module_jsdoc-api--jsdoc..JsdocOptions+cache) : boolean
72 | * [.access](#module_jsdoc-api--jsdoc..JsdocOptions+access) : string
73 | * [.configure](#module_jsdoc-api--jsdoc..JsdocOptions+configure) : string
74 | * [.destination](#module_jsdoc-api--jsdoc..JsdocOptions+destination) : string
75 | * [.encoding](#module_jsdoc-api--jsdoc..JsdocOptions+encoding) : string
76 | * [.private](#module_jsdoc-api--jsdoc..JsdocOptions+private) : boolean
77 | * [.package](#module_jsdoc-api--jsdoc..JsdocOptions+package) : string
78 | * [.pedantic](#module_jsdoc-api--jsdoc..JsdocOptions+pedantic) : boolean
79 | * [.query](#module_jsdoc-api--jsdoc..JsdocOptions+query) : string
80 | * [.recurse](#module_jsdoc-api--jsdoc..JsdocOptions+recurse) : boolean
81 | * [.readme](#module_jsdoc-api--jsdoc..JsdocOptions+readme) : string
82 | * [.template](#module_jsdoc-api--jsdoc..JsdocOptions+template) : string
83 | * [.tutorials](#module_jsdoc-api--jsdoc..JsdocOptions+tutorials) : string
84 |
85 |
86 |
87 | ##### options.files : string
\| Array.<string>
88 | One or more filenames to process. Either `files`, `source` or `configure` must be supplied.
89 |
90 | **Kind**: instance property of [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions)
91 |
92 |
93 | ##### options.source : string
\| Array.<string>
94 | A string or an array of strings containing source code to process. Either `files`, `source` or `configure` must be supplied.
95 |
96 | **Kind**: instance property of [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions)
97 |
98 |
99 | ##### options.cache : boolean
100 | Set to `true` to cache the output - future invocations with the same input will return immediately.
101 |
102 | **Kind**: instance property of [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions)
103 |
104 |
105 | ##### options.access : string
106 | Only display symbols with the given access: "public", "protected", "private" or "undefined", or "all" for all access levels. Default: all except "private".
107 |
108 | **Kind**: instance property of [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions)
109 |
110 |
111 | ##### options.configure : string
112 | The path to the configuration file. Default: path/to/jsdoc/conf.json. Either `files`, `source` or `configure` must be supplied.
113 |
114 | **Kind**: instance property of [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions)
115 |
116 |
117 | ##### options.destination : string
118 | The path to the output folder. Use "console" to dump data to the console. Default: ./out/.
119 |
120 | **Kind**: instance property of [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions)
121 |
122 |
123 | ##### options.encoding : string
124 | Assume this encoding when reading all source files. Default: utf8.
125 |
126 | **Kind**: instance property of [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions)
127 |
128 |
129 | ##### options.private : boolean
130 | Display symbols marked with the @private tag. Equivalent to "--access all". Default: false.
131 |
132 | **Kind**: instance property of [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions)
133 |
134 |
135 | ##### options.package : string
136 | The path to the project's package file. Default: path/to/sourcefiles/package.json
137 |
138 | **Kind**: instance property of [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions)
139 |
140 |
141 | ##### options.pedantic : boolean
142 | Treat errors as fatal errors, and treat warnings as errors. Default: false.
143 |
144 | **Kind**: instance property of [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions)
145 |
146 |
147 | ##### options.query : string
148 | A query string to parse and store in jsdoc.env.opts.query. Example: foo=bar&baz=true.
149 |
150 | **Kind**: instance property of [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions)
151 |
152 |
153 | ##### options.recurse : boolean
154 | Recurse into subdirectories when scanning for source files and tutorials.
155 |
156 | **Kind**: instance property of [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions)
157 |
158 |
159 | ##### options.readme : string
160 | The path to the project's README file. Default: path/to/sourcefiles/README.md.
161 |
162 | **Kind**: instance property of [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions)
163 |
164 |
165 | ##### options.template : string
166 | The path to the template to use. Default: path/to/jsdoc/templates/default.
167 |
168 | **Kind**: instance property of [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions)
169 |
170 |
171 | ##### options.tutorials : string
172 | Directory in which JSDoc should search for tutorials.
173 |
174 | **Kind**: instance property of [JsdocOptions
](#module_jsdoc-api--jsdoc..JsdocOptions)
175 |
176 |
177 | #### jsdoc~cache : [cache-point
](https://github.com/75lb/cache-point)
178 | The [cache-point](https://github.com/75lb/cache-point) instance used when `cache: true` is specified on `.explain()`.
179 |
180 | **Kind**: inner constant of [jsdoc
](#exp_module_jsdoc-api--jsdoc)
181 |
--------------------------------------------------------------------------------
/example/explain-source.js:
--------------------------------------------------------------------------------
1 | import jsdoc from 'jsdoc-api'
2 |
3 | const data = await jsdoc.explain({ source: '/** example doclet */ \n var example = true' })
4 | console.log(data)
5 |
--------------------------------------------------------------------------------
/example/explain.js:
--------------------------------------------------------------------------------
1 | import jsdoc from 'jsdoc-api'
2 |
3 | const data = await jsdoc.explain({ files: process.argv.slice(2), cache: true })
4 | console.log(data)
5 |
--------------------------------------------------------------------------------
/example/render-source.js:
--------------------------------------------------------------------------------
1 | import jsdoc from 'jsdoc-api'
2 |
3 | const source = [
4 | `import Foo from "foo"
5 | /**
6 | * FooPrime is some child class
7 | * @class
8 | * @param {Object} - an input
9 | * @extends Foo
10 | */
11 | function FooPrime() {}
12 | export default FooPrime
13 | `,
14 | `import Foo from "foo"
15 | /**
16 | * FooSecond is some other child class
17 | * @class
18 | * @param {Object} - an input
19 | * @extends Foo
20 | */
21 | function FooSecond() {}
22 | export default FooSecond
23 | `]
24 |
25 | await jsdoc.render({ source, destination: 'source-output' })
26 |
--------------------------------------------------------------------------------
/example/render.js:
--------------------------------------------------------------------------------
1 | import jsdoc from 'jsdoc-api'
2 |
3 | await jsdoc.render({ files: ['.'], destination: 'jsdoc-output' })
4 |
--------------------------------------------------------------------------------
/example/using-config-explain.js:
--------------------------------------------------------------------------------
1 | import jsdoc from 'jsdoc-api'
2 |
3 | const data = await jsdoc.explain({ cache: true, configure: './example/using-config.json' })
4 | console.log(data)
5 |
6 | /*
7 | The `using-config.json` file looks like this:
8 |
9 | {
10 | "source": {
11 | "include": [ "example/using-config-input.js" ]
12 | },
13 | "opts": {
14 | "destination": "./config-out/"
15 | }
16 | }
17 | */
18 |
--------------------------------------------------------------------------------
/example/using-config-input.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A documented function.
3 | */
4 | function something () {}
5 |
--------------------------------------------------------------------------------
/example/using-config-render.js:
--------------------------------------------------------------------------------
1 | import jsdoc from 'jsdoc-api'
2 |
3 | await jsdoc.render({ configure: './example/using-config.json' })
4 |
--------------------------------------------------------------------------------
/example/using-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "source": {
3 | "include": [ "example/using-config-input.js" ]
4 | },
5 | "opts": {
6 | "destination": "./config-out/"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @module jsdoc-api
3 | * @typicalname jsdoc
4 | */
5 | import Cache from 'cache-point'
6 | import Explain from './lib/explain.js'
7 | import Render from './lib/render.js'
8 | import arrayify from 'array-back'
9 | import TempFile from './lib/temp-file.js'
10 |
11 | TempFile.createTmpDirs()
12 |
13 | /**
14 | * @external cache-point
15 | * @see https://github.com/75lb/cache-point
16 | */
17 | /**
18 | * The [cache-point](https://github.com/75lb/cache-point) instance used when `cache: true` is specified on `.explain()`.
19 | * @type {external:cache-point}
20 | */
21 | const cache = new Cache({ dir: TempFile.cacheDir })
22 |
23 | /**
24 | * @alias module:jsdoc-api
25 | */
26 | const jsdoc = {
27 | cache,
28 |
29 | /**
30 | * Returns a promise for the jsdoc explain output.
31 | *
32 | * @param [options] {module:jsdoc-api~JsdocOptions}
33 | * @fulfil {object[]} - jsdoc explain output
34 | * @returns {Promise}
35 | */
36 | async explain (options) {
37 | options = new JsdocOptions(options)
38 | const command = new Explain(options, cache)
39 | return command.execute()
40 | },
41 |
42 | /**
43 | * Render jsdoc documentation.
44 | *
45 | * @param [options] {module:jsdoc-api~JsdocOptions}
46 | * @prerequisite Requires node v0.12 or above
47 | * @example
48 | * await jsdoc.render({ files: 'lib/*', destination: 'api-docs' })
49 | */
50 | async render (options) {
51 | options = new JsdocOptions(options)
52 | const command = new Render(options)
53 | return command.execute()
54 | }
55 | }
56 |
57 | /**
58 | * The jsdoc options, common for all operations.
59 | * @typicalname options
60 | */
61 | class JsdocOptions {
62 | constructor (options = {}) {
63 | /**
64 | * One or more filenames to process. Either `files`, `source` or `configure` must be supplied.
65 | * @type {string|string[]}
66 | */
67 | this.files = arrayify(options.files)
68 |
69 | /**
70 | * A string or an array of strings containing source code to process. Either `files`, `source` or `configure` must be supplied.
71 | * @type {string|string[]}
72 | */
73 | this.source = options.source
74 |
75 | /**
76 | * Set to `true` to cache the output - future invocations with the same input will return immediately.
77 | * @type {boolean}
78 | * @default
79 | */
80 | this.cache = options.cache
81 |
82 | /**
83 | * Only display symbols with the given access: "public", "protected", "private" or "undefined", or "all" for all access levels. Default: all except "private".
84 | * @type {string}
85 | */
86 | this.access = options.access
87 |
88 | /**
89 | * The path to the configuration file. Default: path/to/jsdoc/conf.json. Either `files`, `source` or `configure` must be supplied.
90 | * @type {string}
91 | */
92 | this.configure = options.configure
93 |
94 | /**
95 | * The path to the output folder. Use "console" to dump data to the console. Default: ./out/.
96 | * @type {string}
97 | */
98 | this.destination = options.destination
99 |
100 | /**
101 | * Assume this encoding when reading all source files. Default: utf8.
102 | * @type {string}
103 | */
104 | this.encoding = options.encoding
105 |
106 | /**
107 | * Display symbols marked with the @private tag. Equivalent to "--access all". Default: false.
108 | * @type {boolean}
109 | */
110 | this.private = options.private
111 |
112 | /**
113 | * The path to the project's package file. Default: path/to/sourcefiles/package.json
114 | * @type {string}
115 | */
116 | this.package = options.package
117 |
118 | /**
119 | * Treat errors as fatal errors, and treat warnings as errors. Default: false.
120 | * @type {boolean}
121 | */
122 | this.pedantic = options.pedantic
123 |
124 | /**
125 | * A query string to parse and store in jsdoc.env.opts.query. Example: foo=bar&baz=true.
126 | * @type {string}
127 | */
128 | this.query = options.query
129 |
130 | /**
131 | * Recurse into subdirectories when scanning for source files and tutorials.
132 | * @type {boolean}
133 | */
134 | this.recurse = options.recurse
135 |
136 | /**
137 | * The path to the project's README file. Default: path/to/sourcefiles/README.md.
138 | * @type {string}
139 | */
140 | this.readme = options.readme
141 |
142 | /* Warning to avoid a common mistake where dmd templates are passed in.. a jsdoc template must be a filename. */
143 | if (typeof options.template === 'string' && options.template.split(/\r?\n/).length !== 1) {
144 | console.warn('Suspicious `options.template` value - the jsdoc `template` option must be a file path.')
145 | console.warn(options.template)
146 | }
147 |
148 | /**
149 | * The path to the template to use. Default: path/to/jsdoc/templates/default.
150 | * @type {string}
151 | */
152 | this.template = options.template
153 |
154 | /**
155 | * Directory in which JSDoc should search for tutorials.
156 | * @type {string}
157 | */
158 | this.tutorials = options.tutorials
159 | }
160 | }
161 |
162 | export default jsdoc
163 |
--------------------------------------------------------------------------------
/lib/explain.js:
--------------------------------------------------------------------------------
1 | import JsdocCommand from './jsdoc-command.js'
2 | import toSpawnArgs from 'object-to-spawn-args'
3 | import cp from 'child_process'
4 | import util from 'node:util'
5 | import { promises as fs } from 'node:fs'
6 | const exec = util.promisify(cp.exec)
7 |
8 | class Explain extends JsdocCommand {
9 | async getOutput () {
10 | if (this.options.cache && !this.options.source.length) {
11 | try {
12 | return await this.readCache()
13 | } catch (err) {
14 | if (err.code === 'ENOENT') {
15 | return this._runJsdoc()
16 | } else {
17 | throw err
18 | }
19 | }
20 | } else {
21 | return this._runJsdoc()
22 | }
23 | }
24 |
25 | async _runJsdoc () {
26 | const jsdocArgs = [
27 | this.jsdocPath,
28 | ...toSpawnArgs(this.jsdocOptions),
29 | '-X',
30 | ...(this.options.source.length ? this.tempFileSet.files : this.inputFileSet.files)
31 | ]
32 | let jsdocOutput = { stdout: '', stderr: '' }
33 |
34 | const code = await new Promise((resolve, reject) => {
35 | const handle = cp.spawn('node', jsdocArgs)
36 | handle.stdout.setEncoding('utf8')
37 | handle.stderr.setEncoding('utf8')
38 | handle.stdout.on('data', chunk => {
39 | jsdocOutput.stdout += chunk
40 | })
41 | handle.stderr.on('data', chunk => {
42 | jsdocOutput.stderr += chunk
43 | })
44 | handle.on('exit', (code) => {
45 | resolve(code)
46 | })
47 | handle.on('error', reject)
48 | })
49 | try {
50 | if (code > 0) {
51 | throw new Error('jsdoc exited with non-zero code: ' + code)
52 | } else {
53 | const explainOutput = JSON.parse(jsdocOutput.stdout)
54 | if (this.options.cache) {
55 | await this.cache.write(this.cacheKey, explainOutput)
56 | }
57 | return explainOutput
58 | }
59 | } catch (err) {
60 | const firstLineOfStdout = jsdocOutput.stdout.split(/\r?\n/)[0]
61 | const jsdocErr = new Error(jsdocOutput.stderr.trim() || firstLineOfStdout || 'Jsdoc failed.')
62 | jsdocErr.name = 'JSDOC_ERROR'
63 | jsdocErr.cause = err
64 | throw jsdocErr
65 | }
66 | }
67 |
68 | async readCache () {
69 | if (this.cache) {
70 | /* Create the cache key then check the cache for a match, returning pre-generated output if so.
71 | The current cache key is a union of the input file names plus their content - this could be expensive when processing a lot of files.
72 | */
73 | const promises = this.inputFileSet.files.map(file => {
74 | return fs.readFile(file, 'utf8')
75 | })
76 | const contents = await Promise.all(promises)
77 | this.cacheKey = contents.concat(this.inputFileSet.files)
78 | return this.cache.read(this.cacheKey)
79 | } else {
80 | return Promise.reject()
81 | }
82 | }
83 | }
84 |
85 | export default Explain
86 |
--------------------------------------------------------------------------------
/lib/jsdoc-command.js:
--------------------------------------------------------------------------------
1 | import arrayify from 'array-back'
2 | import path from 'path'
3 | import TempFile from './temp-file.js'
4 | import FileSet from 'file-set'
5 | import assert from 'assert'
6 | import walkBack from 'walk-back'
7 | import currentModulePaths from 'current-module-paths'
8 |
9 | const { __dirname } = currentModulePaths(import.meta.url)
10 |
11 | class JsdocCommand {
12 | constructor (options = {}, cache) {
13 | options.files = arrayify(options.files)
14 | options.source = arrayify(options.source)
15 | assert.ok(
16 | options.files.length || options.source.length || options.configure,
17 | 'Must set at least one of .files, .source or .configure'
18 | )
19 |
20 | this.cache = cache
21 | this.tempFiles = []
22 |
23 | const jsdocOptions = Object.assign({}, options)
24 | delete jsdocOptions.files
25 | delete jsdocOptions.source
26 | delete jsdocOptions.cache
27 |
28 | /* see: https://github.com/jsdoc2md/jsdoc-api/issues/22 */
29 | if (!jsdocOptions.pedantic) {
30 | delete jsdocOptions.pedantic
31 | }
32 |
33 | this.options = options
34 | this.jsdocOptions = jsdocOptions
35 |
36 | this.jsdocPath = process.env.JSDOC_PATH || walkBack(
37 | path.join(__dirname, '..'),
38 | path.join('node_modules', 'jsdoc', 'jsdoc.js')
39 | )
40 | }
41 |
42 | async execute () {
43 | this.inputFileSet = new FileSet()
44 | await this.inputFileSet.add(this.options.files)
45 | /* node-glob v9+ (used by file-set) no longer sorts the output by default. We will continue to sort the file list, for now, as it's what the user expected by default. The user's system locale is used. */
46 | const collator = new Intl.Collator()
47 | this.inputFileSet.files.sort(collator.compare)
48 |
49 | if (this.options.source.length) {
50 | this.tempFiles = this.options.source.map(source => new TempFile(source))
51 | this.tempFileSet = new FileSet()
52 | await this.tempFileSet.add(this.tempFiles.map(t => t.path))
53 | }
54 |
55 | let result
56 | try {
57 | result = await this.getOutput()
58 | } finally {
59 | /* run even if getOutput fails */
60 | if (this.tempFiles) {
61 | for (const tempFile of this.tempFiles) {
62 | tempFile.delete()
63 | }
64 | }
65 | }
66 | return result
67 | }
68 | }
69 |
70 | export default JsdocCommand
71 |
--------------------------------------------------------------------------------
/lib/render.js:
--------------------------------------------------------------------------------
1 | import JsdocCommand from './jsdoc-command.js'
2 | import toSpawnArgs from 'object-to-spawn-args'
3 | import { spawn } from 'child_process'
4 |
5 | class Render extends JsdocCommand {
6 | async getOutput () {
7 | return new Promise((resolve, reject) => {
8 | const jsdocArgs = toSpawnArgs(this.jsdocOptions)
9 | .concat(this.options.source.length ? this.tempFiles.map(t => t.path) : this.options.files)
10 |
11 | jsdocArgs.unshift(this.jsdocPath)
12 | const handle = spawn('node', jsdocArgs, { stdio: 'inherit' })
13 | handle.on('close', resolve)
14 | })
15 | }
16 | }
17 |
18 | export default Render
19 |
--------------------------------------------------------------------------------
/lib/temp-file.js:
--------------------------------------------------------------------------------
1 | import fs from 'node:fs'
2 | import os from 'os'
3 | import crypto from 'crypto'
4 | import path from 'path'
5 |
6 | class TempFile {
7 | constructor (source) {
8 | this.path = path.join(TempFile.tempFileDir, crypto.randomBytes(6).toString('hex') + '.js')
9 | fs.writeFileSync(this.path, source)
10 | }
11 |
12 | delete () {
13 | try {
14 | fs.unlinkSync(this.path)
15 | } catch (err) {
16 | // already deleted
17 | }
18 | }
19 |
20 | static tempFileDir = path.join(os.homedir(), '.jsdoc-api/temp')
21 | static cacheDir = path.join(os.homedir(), '.jsdoc-api/cache')
22 |
23 | static createTmpDirs () {
24 | /* No longer using os.tmpdir(). See: https://github.com/jsdoc2md/jsdoc-api/issues/19 */
25 | fs.mkdirSync(TempFile.tempFileDir, { recursive: true })
26 | fs.mkdirSync(TempFile.cacheDir, { recursive: true })
27 | }
28 | }
29 |
30 | export default TempFile
31 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jsdoc-api",
3 | "version": "9.3.4",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "jsdoc-api",
9 | "version": "9.3.4",
10 | "license": "MIT",
11 | "dependencies": {
12 | "array-back": "^6.2.2",
13 | "cache-point": "^3.0.0",
14 | "current-module-paths": "^1.1.2",
15 | "file-set": "^5.2.2",
16 | "jsdoc": "^4.0.4",
17 | "object-to-spawn-args": "^2.0.1",
18 | "walk-back": "^5.1.1"
19 | },
20 | "engines": {
21 | "node": ">=12.17"
22 | },
23 | "peerDependencies": {
24 | "@75lb/nature": "latest"
25 | },
26 | "peerDependenciesMeta": {
27 | "@75lb/nature": {
28 | "optional": true
29 | }
30 | }
31 | },
32 | "node_modules/@babel/helper-string-parser": {
33 | "version": "7.25.9",
34 | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
35 | "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
36 | "license": "MIT",
37 | "engines": {
38 | "node": ">=6.9.0"
39 | }
40 | },
41 | "node_modules/@babel/helper-validator-identifier": {
42 | "version": "7.25.9",
43 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
44 | "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
45 | "license": "MIT",
46 | "engines": {
47 | "node": ">=6.9.0"
48 | }
49 | },
50 | "node_modules/@babel/parser": {
51 | "version": "7.26.2",
52 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz",
53 | "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==",
54 | "license": "MIT",
55 | "dependencies": {
56 | "@babel/types": "^7.26.0"
57 | },
58 | "bin": {
59 | "parser": "bin/babel-parser.js"
60 | },
61 | "engines": {
62 | "node": ">=6.0.0"
63 | }
64 | },
65 | "node_modules/@babel/types": {
66 | "version": "7.26.0",
67 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz",
68 | "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==",
69 | "license": "MIT",
70 | "dependencies": {
71 | "@babel/helper-string-parser": "^7.25.9",
72 | "@babel/helper-validator-identifier": "^7.25.9"
73 | },
74 | "engines": {
75 | "node": ">=6.9.0"
76 | }
77 | },
78 | "node_modules/@jsdoc/salty": {
79 | "version": "0.2.8",
80 | "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.8.tgz",
81 | "integrity": "sha512-5e+SFVavj1ORKlKaKr2BmTOekmXbelU7dC0cDkQLqag7xfuTPuGMUFx7KWJuv4bYZrTsoL2Z18VVCOKYxzoHcg==",
82 | "license": "Apache-2.0",
83 | "dependencies": {
84 | "lodash": "^4.17.21"
85 | },
86 | "engines": {
87 | "node": ">=v12.0.0"
88 | }
89 | },
90 | "node_modules/@nodelib/fs.scandir": {
91 | "version": "2.1.5",
92 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
93 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
94 | "license": "MIT",
95 | "dependencies": {
96 | "@nodelib/fs.stat": "2.0.5",
97 | "run-parallel": "^1.1.9"
98 | },
99 | "engines": {
100 | "node": ">= 8"
101 | }
102 | },
103 | "node_modules/@nodelib/fs.stat": {
104 | "version": "2.0.5",
105 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
106 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
107 | "license": "MIT",
108 | "engines": {
109 | "node": ">= 8"
110 | }
111 | },
112 | "node_modules/@nodelib/fs.walk": {
113 | "version": "1.2.8",
114 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
115 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
116 | "license": "MIT",
117 | "dependencies": {
118 | "@nodelib/fs.scandir": "2.1.5",
119 | "fastq": "^1.6.0"
120 | },
121 | "engines": {
122 | "node": ">= 8"
123 | }
124 | },
125 | "node_modules/@types/linkify-it": {
126 | "version": "5.0.0",
127 | "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
128 | "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
129 | "license": "MIT"
130 | },
131 | "node_modules/@types/markdown-it": {
132 | "version": "14.1.2",
133 | "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
134 | "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
135 | "license": "MIT",
136 | "dependencies": {
137 | "@types/linkify-it": "^5",
138 | "@types/mdurl": "^2"
139 | }
140 | },
141 | "node_modules/@types/mdurl": {
142 | "version": "2.0.0",
143 | "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
144 | "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
145 | "license": "MIT"
146 | },
147 | "node_modules/argparse": {
148 | "version": "2.0.1",
149 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
150 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
151 | "license": "Python-2.0"
152 | },
153 | "node_modules/array-back": {
154 | "version": "6.2.2",
155 | "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz",
156 | "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==",
157 | "license": "MIT",
158 | "engines": {
159 | "node": ">=12.17"
160 | }
161 | },
162 | "node_modules/bluebird": {
163 | "version": "3.7.2",
164 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
165 | "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
166 | "license": "MIT"
167 | },
168 | "node_modules/braces": {
169 | "version": "3.0.3",
170 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
171 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
172 | "license": "MIT",
173 | "dependencies": {
174 | "fill-range": "^7.1.1"
175 | },
176 | "engines": {
177 | "node": ">=8"
178 | }
179 | },
180 | "node_modules/cache-point": {
181 | "version": "3.0.0",
182 | "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-3.0.0.tgz",
183 | "integrity": "sha512-LDGNWYv/tqRWAAZxMy75PIYynaIuhcyoyjJtwA7X5uMZjdzvGm+XmTey/GXUy2EJ+lwc2eBFzFYxjvNYyE/0Iw==",
184 | "license": "MIT",
185 | "dependencies": {
186 | "array-back": "^6.2.2"
187 | },
188 | "engines": {
189 | "node": ">=12.17"
190 | },
191 | "peerDependencies": {
192 | "@75lb/nature": "^0.1.1"
193 | },
194 | "peerDependenciesMeta": {
195 | "@75lb/nature": {
196 | "optional": true
197 | }
198 | }
199 | },
200 | "node_modules/catharsis": {
201 | "version": "0.9.0",
202 | "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz",
203 | "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==",
204 | "license": "MIT",
205 | "dependencies": {
206 | "lodash": "^4.17.15"
207 | },
208 | "engines": {
209 | "node": ">= 10"
210 | }
211 | },
212 | "node_modules/current-module-paths": {
213 | "version": "1.1.2",
214 | "resolved": "https://registry.npmjs.org/current-module-paths/-/current-module-paths-1.1.2.tgz",
215 | "integrity": "sha512-H4s4arcLx/ugbu1XkkgSvcUZax0L6tXUqnppGniQb8l5VjUKGHoayXE5RiriiPhYDd+kjZnaok1Uig13PKtKYQ==",
216 | "license": "MIT",
217 | "engines": {
218 | "node": ">=12.17"
219 | }
220 | },
221 | "node_modules/entities": {
222 | "version": "4.5.0",
223 | "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
224 | "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
225 | "license": "BSD-2-Clause",
226 | "engines": {
227 | "node": ">=0.12"
228 | },
229 | "funding": {
230 | "url": "https://github.com/fb55/entities?sponsor=1"
231 | }
232 | },
233 | "node_modules/escape-string-regexp": {
234 | "version": "2.0.0",
235 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
236 | "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
237 | "license": "MIT",
238 | "engines": {
239 | "node": ">=8"
240 | }
241 | },
242 | "node_modules/fast-glob": {
243 | "version": "3.3.2",
244 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
245 | "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
246 | "license": "MIT",
247 | "dependencies": {
248 | "@nodelib/fs.stat": "^2.0.2",
249 | "@nodelib/fs.walk": "^1.2.3",
250 | "glob-parent": "^5.1.2",
251 | "merge2": "^1.3.0",
252 | "micromatch": "^4.0.4"
253 | },
254 | "engines": {
255 | "node": ">=8.6.0"
256 | }
257 | },
258 | "node_modules/fastq": {
259 | "version": "1.17.1",
260 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
261 | "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
262 | "license": "ISC",
263 | "dependencies": {
264 | "reusify": "^1.0.4"
265 | }
266 | },
267 | "node_modules/file-set": {
268 | "version": "5.2.2",
269 | "resolved": "https://registry.npmjs.org/file-set/-/file-set-5.2.2.tgz",
270 | "integrity": "sha512-/KgJI1V/QaDK4enOk/E2xMFk1cTWJghEr7UmWiRZfZ6upt6gQCfMn4jJ7aOm64OKurj4TaVnSSgSDqv5ZKYA3A==",
271 | "license": "MIT",
272 | "dependencies": {
273 | "array-back": "^6.2.2",
274 | "fast-glob": "^3.3.2"
275 | },
276 | "engines": {
277 | "node": ">=12.17"
278 | },
279 | "peerDependencies": {
280 | "@75lb/nature": "latest"
281 | },
282 | "peerDependenciesMeta": {
283 | "@75lb/nature": {
284 | "optional": true
285 | }
286 | }
287 | },
288 | "node_modules/fill-range": {
289 | "version": "7.1.1",
290 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
291 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
292 | "license": "MIT",
293 | "dependencies": {
294 | "to-regex-range": "^5.0.1"
295 | },
296 | "engines": {
297 | "node": ">=8"
298 | }
299 | },
300 | "node_modules/glob-parent": {
301 | "version": "5.1.2",
302 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
303 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
304 | "license": "ISC",
305 | "dependencies": {
306 | "is-glob": "^4.0.1"
307 | },
308 | "engines": {
309 | "node": ">= 6"
310 | }
311 | },
312 | "node_modules/graceful-fs": {
313 | "version": "4.2.11",
314 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
315 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
316 | "license": "ISC"
317 | },
318 | "node_modules/is-extglob": {
319 | "version": "2.1.1",
320 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
321 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
322 | "license": "MIT",
323 | "engines": {
324 | "node": ">=0.10.0"
325 | }
326 | },
327 | "node_modules/is-glob": {
328 | "version": "4.0.3",
329 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
330 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
331 | "license": "MIT",
332 | "dependencies": {
333 | "is-extglob": "^2.1.1"
334 | },
335 | "engines": {
336 | "node": ">=0.10.0"
337 | }
338 | },
339 | "node_modules/is-number": {
340 | "version": "7.0.0",
341 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
342 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
343 | "license": "MIT",
344 | "engines": {
345 | "node": ">=0.12.0"
346 | }
347 | },
348 | "node_modules/js2xmlparser": {
349 | "version": "4.0.2",
350 | "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz",
351 | "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==",
352 | "license": "Apache-2.0",
353 | "dependencies": {
354 | "xmlcreate": "^2.0.4"
355 | }
356 | },
357 | "node_modules/jsdoc": {
358 | "version": "4.0.4",
359 | "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.4.tgz",
360 | "integrity": "sha512-zeFezwyXeG4syyYHbvh1A967IAqq/67yXtXvuL5wnqCkFZe8I0vKfm+EO+YEvLguo6w9CDUbrAXVtJSHh2E8rw==",
361 | "license": "Apache-2.0",
362 | "dependencies": {
363 | "@babel/parser": "^7.20.15",
364 | "@jsdoc/salty": "^0.2.1",
365 | "@types/markdown-it": "^14.1.1",
366 | "bluebird": "^3.7.2",
367 | "catharsis": "^0.9.0",
368 | "escape-string-regexp": "^2.0.0",
369 | "js2xmlparser": "^4.0.2",
370 | "klaw": "^3.0.0",
371 | "markdown-it": "^14.1.0",
372 | "markdown-it-anchor": "^8.6.7",
373 | "marked": "^4.0.10",
374 | "mkdirp": "^1.0.4",
375 | "requizzle": "^0.2.3",
376 | "strip-json-comments": "^3.1.0",
377 | "underscore": "~1.13.2"
378 | },
379 | "bin": {
380 | "jsdoc": "jsdoc.js"
381 | },
382 | "engines": {
383 | "node": ">=12.0.0"
384 | }
385 | },
386 | "node_modules/klaw": {
387 | "version": "3.0.0",
388 | "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz",
389 | "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==",
390 | "license": "MIT",
391 | "dependencies": {
392 | "graceful-fs": "^4.1.9"
393 | }
394 | },
395 | "node_modules/linkify-it": {
396 | "version": "5.0.0",
397 | "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
398 | "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
399 | "license": "MIT",
400 | "dependencies": {
401 | "uc.micro": "^2.0.0"
402 | }
403 | },
404 | "node_modules/lodash": {
405 | "version": "4.17.21",
406 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
407 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
408 | "license": "MIT"
409 | },
410 | "node_modules/markdown-it": {
411 | "version": "14.1.0",
412 | "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
413 | "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
414 | "license": "MIT",
415 | "dependencies": {
416 | "argparse": "^2.0.1",
417 | "entities": "^4.4.0",
418 | "linkify-it": "^5.0.0",
419 | "mdurl": "^2.0.0",
420 | "punycode.js": "^2.3.1",
421 | "uc.micro": "^2.1.0"
422 | },
423 | "bin": {
424 | "markdown-it": "bin/markdown-it.mjs"
425 | }
426 | },
427 | "node_modules/markdown-it-anchor": {
428 | "version": "8.6.7",
429 | "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz",
430 | "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==",
431 | "license": "Unlicense",
432 | "peerDependencies": {
433 | "@types/markdown-it": "*",
434 | "markdown-it": "*"
435 | }
436 | },
437 | "node_modules/marked": {
438 | "version": "4.3.0",
439 | "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
440 | "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
441 | "license": "MIT",
442 | "bin": {
443 | "marked": "bin/marked.js"
444 | },
445 | "engines": {
446 | "node": ">= 12"
447 | }
448 | },
449 | "node_modules/mdurl": {
450 | "version": "2.0.0",
451 | "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
452 | "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
453 | "license": "MIT"
454 | },
455 | "node_modules/merge2": {
456 | "version": "1.4.1",
457 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
458 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
459 | "license": "MIT",
460 | "engines": {
461 | "node": ">= 8"
462 | }
463 | },
464 | "node_modules/micromatch": {
465 | "version": "4.0.8",
466 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
467 | "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
468 | "license": "MIT",
469 | "dependencies": {
470 | "braces": "^3.0.3",
471 | "picomatch": "^2.3.1"
472 | },
473 | "engines": {
474 | "node": ">=8.6"
475 | }
476 | },
477 | "node_modules/mkdirp": {
478 | "version": "1.0.4",
479 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
480 | "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
481 | "license": "MIT",
482 | "bin": {
483 | "mkdirp": "bin/cmd.js"
484 | },
485 | "engines": {
486 | "node": ">=10"
487 | }
488 | },
489 | "node_modules/object-to-spawn-args": {
490 | "version": "2.0.1",
491 | "resolved": "https://registry.npmjs.org/object-to-spawn-args/-/object-to-spawn-args-2.0.1.tgz",
492 | "integrity": "sha512-6FuKFQ39cOID+BMZ3QaphcC8Y4cw6LXBLyIgPU+OhIYwviJamPAn+4mITapnSBQrejB+NNp+FMskhD8Cq+Ys3w==",
493 | "license": "MIT",
494 | "engines": {
495 | "node": ">=8.0.0"
496 | }
497 | },
498 | "node_modules/picomatch": {
499 | "version": "2.3.1",
500 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
501 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
502 | "license": "MIT",
503 | "engines": {
504 | "node": ">=8.6"
505 | },
506 | "funding": {
507 | "url": "https://github.com/sponsors/jonschlinkert"
508 | }
509 | },
510 | "node_modules/punycode.js": {
511 | "version": "2.3.1",
512 | "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
513 | "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
514 | "license": "MIT",
515 | "engines": {
516 | "node": ">=6"
517 | }
518 | },
519 | "node_modules/queue-microtask": {
520 | "version": "1.2.3",
521 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
522 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
523 | "funding": [
524 | {
525 | "type": "github",
526 | "url": "https://github.com/sponsors/feross"
527 | },
528 | {
529 | "type": "patreon",
530 | "url": "https://www.patreon.com/feross"
531 | },
532 | {
533 | "type": "consulting",
534 | "url": "https://feross.org/support"
535 | }
536 | ],
537 | "license": "MIT"
538 | },
539 | "node_modules/requizzle": {
540 | "version": "0.2.4",
541 | "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz",
542 | "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==",
543 | "license": "MIT",
544 | "dependencies": {
545 | "lodash": "^4.17.21"
546 | }
547 | },
548 | "node_modules/reusify": {
549 | "version": "1.0.4",
550 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
551 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
552 | "license": "MIT",
553 | "engines": {
554 | "iojs": ">=1.0.0",
555 | "node": ">=0.10.0"
556 | }
557 | },
558 | "node_modules/run-parallel": {
559 | "version": "1.2.0",
560 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
561 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
562 | "funding": [
563 | {
564 | "type": "github",
565 | "url": "https://github.com/sponsors/feross"
566 | },
567 | {
568 | "type": "patreon",
569 | "url": "https://www.patreon.com/feross"
570 | },
571 | {
572 | "type": "consulting",
573 | "url": "https://feross.org/support"
574 | }
575 | ],
576 | "license": "MIT",
577 | "dependencies": {
578 | "queue-microtask": "^1.2.2"
579 | }
580 | },
581 | "node_modules/strip-json-comments": {
582 | "version": "3.1.1",
583 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
584 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
585 | "license": "MIT",
586 | "engines": {
587 | "node": ">=8"
588 | },
589 | "funding": {
590 | "url": "https://github.com/sponsors/sindresorhus"
591 | }
592 | },
593 | "node_modules/to-regex-range": {
594 | "version": "5.0.1",
595 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
596 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
597 | "license": "MIT",
598 | "dependencies": {
599 | "is-number": "^7.0.0"
600 | },
601 | "engines": {
602 | "node": ">=8.0"
603 | }
604 | },
605 | "node_modules/uc.micro": {
606 | "version": "2.1.0",
607 | "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
608 | "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
609 | "license": "MIT"
610 | },
611 | "node_modules/underscore": {
612 | "version": "1.13.7",
613 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz",
614 | "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==",
615 | "license": "MIT"
616 | },
617 | "node_modules/walk-back": {
618 | "version": "5.1.1",
619 | "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-5.1.1.tgz",
620 | "integrity": "sha512-e/FRLDVdZQWFrAzU6Hdvpm7D7m2ina833gIKLptQykRK49mmCYHLHq7UqjPDbxbKLZkTkW1rFqbengdE3sLfdw==",
621 | "license": "MIT",
622 | "engines": {
623 | "node": ">=12.17"
624 | }
625 | },
626 | "node_modules/xmlcreate": {
627 | "version": "2.0.4",
628 | "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz",
629 | "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==",
630 | "license": "Apache-2.0"
631 | }
632 | }
633 | }
634 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jsdoc-api",
3 | "author": "Lloyd Brookes <75pound@gmail.com>",
4 | "version": "9.3.4",
5 | "description": "A programmatic interface for jsdoc",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/jsdoc2md/jsdoc-api.git"
9 | },
10 | "type": "module",
11 | "exports": {
12 | "import": "./index.js",
13 | "require": "./dist/index.cjs"
14 | },
15 | "license": "MIT",
16 | "keywords": [
17 | "jsdoc",
18 | "api",
19 | "programmatic",
20 | "interface",
21 | "javascript",
22 | "documentation"
23 | ],
24 | "engines": {
25 | "node": ">=12.17"
26 | },
27 | "scripts": {
28 | "test": "npm run dist && npm run test:ci",
29 | "test:ci": "75lb-nature test-runner test/caching.js test/explain.js test/render.js",
30 | "dist": "75lb-nature cjs-build index.js",
31 | "docs": "75lb-nature jsdoc2md index.js lib/*.js > docs/api.md"
32 | },
33 | "dependencies": {
34 | "array-back": "^6.2.2",
35 | "cache-point": "^3.0.0",
36 | "current-module-paths": "^1.1.2",
37 | "file-set": "^5.2.2",
38 | "jsdoc": "^4.0.4",
39 | "object-to-spawn-args": "^2.0.1",
40 | "walk-back": "^5.1.1"
41 | },
42 | "peerDependencies": {
43 | "@75lb/nature": "latest"
44 | },
45 | "peerDependenciesMeta": {
46 | "@75lb/nature": {
47 | "optional": true
48 | }
49 | },
50 | "standard": {
51 | "ignore": [
52 | "tmp",
53 | "test/fixture",
54 | "dist"
55 | ]
56 | },
57 | "files": [
58 | "index.js",
59 | "lib",
60 | "dist"
61 | ]
62 | }
63 |
--------------------------------------------------------------------------------
/test/caching.js:
--------------------------------------------------------------------------------
1 | import jsdoc from 'jsdoc-api'
2 | import Fixture from './lib/fixture.js'
3 | import { readdirSync, readFileSync } from 'fs'
4 | import { strict as a } from 'assert'
5 | import path from 'path'
6 |
7 | /* tests need to run with a maxConcurrency of 1 as `jsdoc.cache` is shared between tests */
8 | const [test, only, skip] = [new Map(), new Map(), new Map()]
9 |
10 | test.set('.explain({ files, cache: true })', async function () {
11 | const f = new Fixture('class-all')
12 | jsdoc.cache.dir = 'tmp/test/cache1'
13 | await jsdoc.cache.clear()
14 | let output = await jsdoc.explain({ files: f.sourcePath, cache: true })
15 | output = Fixture.normaliseNewLines(output)
16 | const cachedFiles = readdirSync(jsdoc.cache.dir).map(file => path.resolve(jsdoc.cache.dir, file))
17 | a.equal(cachedFiles.length, 1)
18 | a.deepEqual(output, f.getExpectedOutput(output))
19 | let cachedData = JSON.parse(readFileSync(cachedFiles[0], 'utf8'))
20 | cachedData = Fixture.normaliseNewLines(cachedData)
21 | Fixture.removeFileSpecificData(cachedData)
22 | a.deepEqual(
23 | cachedData,
24 | f.getExpectedOutput(output)
25 | )
26 | })
27 |
28 | test.set('.explain({ source, cache: true }) - Ensure correct output (#147)', async function () {
29 | await jsdoc.cache.clear()
30 | jsdoc.cache.dir = 'tmp/test/cache2'
31 | let one = jsdoc.explain({ source: '/**\n * Function one\n */\nfunction one () {}\n', cache: true })
32 | let two = jsdoc.explain({ source: '/**\n * Function two\n */\nfunction two () {}\n', cache: true })
33 | let three = jsdoc.explain({ source: '/**\n * Function three\n */\nfunction three () {}\n', cache: true })
34 | const output = await Promise.all([one, two, three])
35 | a.equal(output[0][0].description, 'Function one')
36 | a.equal(output[1][0].description, 'Function two')
37 | a.equal(output[2][0].description, 'Function three')
38 |
39 | /* ensure it works correctly the second time */
40 | one = jsdoc.explain({ source: '/**\n * Function one\n */\nfunction one () {}\n', cache: true })
41 | two = jsdoc.explain({ source: '/**\n * Function two\n */\nfunction two () {}\n', cache: true })
42 | three = jsdoc.explain({ source: '/**\n * Function three\n */\nfunction three () {}\n', cache: true })
43 | const output2 = await Promise.all([one, two, three])
44 | a.equal(output2[0][0].description, 'Function one')
45 | a.equal(output2[1][0].description, 'Function two')
46 | a.equal(output2[2][0].description, 'Function three')
47 | })
48 |
49 | export { test, only, skip }
50 |
--------------------------------------------------------------------------------
/test/explain.js:
--------------------------------------------------------------------------------
1 | import jsdoc from 'jsdoc-api'
2 | import Fixture from './lib/fixture.js'
3 | import { strict as a } from 'assert'
4 | import path from 'path'
5 |
6 | const [test, only, skip] = [new Map(), new Map(), new Map()]
7 |
8 | test.set('.explain({ files })', async function () {
9 | const f = new Fixture('class-all')
10 | let output = await jsdoc.explain({ files: f.sourcePath })
11 | output = Fixture.normaliseNewLines(output)
12 | a.deepEqual(output, f.getExpectedOutput(output))
13 | })
14 |
15 | test.set('.explain({ source })', async function () {
16 | const f = new Fixture('class-all')
17 | let output = await jsdoc.explain({ source: f.getSource() })
18 | output = Fixture.normaliseNewLines(output)
19 | a.deepEqual(output, f.getExpectedOutput(output))
20 | })
21 |
22 | test.set(".explain: file doesn't exist", async function () {
23 | try {
24 | await jsdoc.explain({ files: 'sdfafafirifrj' })
25 | a.fail('should not reach here')
26 | } catch (err) {
27 | a.equal(err.name, 'JSDOC_ERROR')
28 | }
29 | })
30 |
31 | test.set('.explain: invalid doclet syntax', async function () {
32 | const input = path.resolve('test', 'fixture', 'buggy', 'bad-doclet-syntax.js')
33 | try {
34 | await jsdoc.explain({ files: input })
35 | a.fail('should not reach here')
36 | } catch (err) {
37 | a.equal(err.name, 'JSDOC_ERROR')
38 | }
39 | })
40 |
41 | test.set('.explain({ files }): generate a warning', async function () {
42 | return jsdoc.explain({ files: 'test/fixture/buggy/ignore-with-value.js' })
43 | })
44 |
45 | test.set('.explain({ files }): files is empty', async function () {
46 | a.rejects(
47 | () => jsdoc.explain({ files: [] }),
48 | /Must set at least one of .files, .source or .configure/
49 | )
50 | })
51 |
52 | test.set('Spaces in jsdoc command path', async function () {
53 | process.env.JSDOC_PATH = 'test/fixture/folder with spaces/fake-jsdoc.js'
54 | const f = new Fixture('class-all')
55 | let output = await jsdoc.explain({ files: f.sourcePath })
56 | a.equal(output.length, 4)
57 | process.env.JSDOC_PATH = ''
58 | })
59 |
60 | export { test, only, skip }
61 |
--------------------------------------------------------------------------------
/test/fixture/buggy/bad-doclet-syntax.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @param {89*&^(Gjhdsbfk)}
3 | */
4 | function badSyntax () {}
5 |
--------------------------------------------------------------------------------
/test/fixture/buggy/broken-javascript.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Documenting some broken code
3 | */
4 | function badJavascriptSyntax () {
5 | const a = { one: 1, two: 2 }
6 | const b = { ..a } // should be three fullstops
7 | }
8 |
--------------------------------------------------------------------------------
/test/fixture/buggy/ignore-with-value.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @ignore in favour of iOS' one
3 | * A handle to an image picker popover.
4 | */
5 | var CameraPopoverHandle = 1;
6 |
--------------------------------------------------------------------------------
/test/fixture/class-all/0-src.js:
--------------------------------------------------------------------------------
1 | /**
2 | the constructor description
3 | @class
4 | @classdesc a class with all of the things
5 | @param {object} - an input
6 | @param [options] {object} - optional shit
7 | @author 75lb <75pound@gmail.com>
8 | @deprecated
9 | @since v0.10.28
10 | @extends {Number}
11 | @example
12 | ```js
13 | var yeah = new Everything(true)
14 | ```
15 | */
16 | function All (input, second) {
17 | /**
18 | the ingredients on top
19 | @default
20 | @type {string}
21 | @since v1.0.0
22 | */
23 | this.topping = 'mud, lettuce'
24 |
25 | /**
26 | the general size
27 | */
28 | this.size = 'medium'
29 | }
30 |
31 | /**
32 | This function has all tags set
33 | @deprecated
34 | @param {string} - The input string
35 | @param {object} - a second input
36 | @author Lloyd <75pound@gmail.com>
37 | @since v0.10.28
38 | @returns {object | string} this return has several types
39 | @example
40 | ```js
41 | all.allTogether(true)
42 | ```
43 | */
44 | All.prototype.allThings = function (one, two) {
45 | /**
46 | a rarseclart inner
47 | */
48 | var some = 'bs code'
49 | }
50 |
--------------------------------------------------------------------------------
/test/fixture/class-all/1-jsdoc.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "comment": "/**\nthe constructor description\n@class\n@classdesc a class with all of the things\n@param {object} - an input\n@param [options] {object} - optional shit\n@author 75lb <75pound@gmail.com>\n@deprecated\n@since v0.10.28\n@extends {Number}\n@example\n```js\nvar yeah = new Everything(true)\n```\n*/",
4 | "meta": {
5 | "range": [
6 | 283,
7 | 481
8 | ],
9 | "filename": "0-src.js",
10 | "lineno": 16,
11 | "columnno": 0,
12 | "path": "/Users/lloydb/Documents/jsdoc2md/jsdoc-api/test/fixture/class-all",
13 | "code": {
14 | "id": "astnode100000002",
15 | "name": "All",
16 | "type": "FunctionDeclaration",
17 | "paramnames": [
18 | "input",
19 | "second"
20 | ]
21 | },
22 | "vars": {
23 | "this.topping": "All#topping",
24 | "this.size": "All#size"
25 | }
26 | },
27 | "description": "the constructor description",
28 | "kind": "class",
29 | "classdesc": "a class with all of the things",
30 | "params": [
31 | {
32 | "type": {
33 | "names": [
34 | "object"
35 | ]
36 | },
37 | "description": "an input",
38 | "name": "input"
39 | },
40 | {
41 | "type": {
42 | "names": [
43 | "object"
44 | ]
45 | },
46 | "optional": true,
47 | "description": "optional shit",
48 | "name": "options"
49 | }
50 | ],
51 | "author": [
52 | "75lb <75pound@gmail.com>"
53 | ],
54 | "deprecated": true,
55 | "since": "v0.10.28",
56 | "augments": [
57 | "Number"
58 | ],
59 | "examples": [
60 | "```js\nvar yeah = new Everything(true)\n```"
61 | ],
62 | "name": "All",
63 | "longname": "All",
64 | "scope": "global"
65 | },
66 | {
67 | "comment": "/**\n the ingredients on top\n @default\n @type {string}\n @since v1.0.0\n */",
68 | "meta": {
69 | "range": [
70 | 396,
71 | 425
72 | ],
73 | "filename": "0-src.js",
74 | "lineno": 23,
75 | "columnno": 2,
76 | "path": "/Users/lloydb/Documents/jsdoc2md/jsdoc-api/test/fixture/class-all",
77 | "code": {
78 | "id": "astnode100000008",
79 | "name": "this.topping",
80 | "type": "Literal",
81 | "value": "mud, lettuce",
82 | "paramnames": []
83 | }
84 | },
85 | "description": "the ingredients on top",
86 | "defaultvalue": "mud, lettuce",
87 | "type": {
88 | "names": [
89 | "string"
90 | ]
91 | },
92 | "since": "v1.0.0",
93 | "name": "topping",
94 | "longname": "All#topping",
95 | "kind": "member",
96 | "memberof": "All",
97 | "scope": "instance"
98 | },
99 | {
100 | "comment": "/**\n the general size\n */",
101 | "meta": {
102 | "range": [
103 | 459,
104 | 479
105 | ],
106 | "filename": "0-src.js",
107 | "lineno": 28,
108 | "columnno": 2,
109 | "path": "/Users/lloydb/Documents/jsdoc2md/jsdoc-api/test/fixture/class-all",
110 | "code": {
111 | "id": "astnode100000014",
112 | "name": "this.size",
113 | "type": "Literal",
114 | "value": "medium",
115 | "paramnames": []
116 | }
117 | },
118 | "description": "the general size",
119 | "name": "size",
120 | "longname": "All#size",
121 | "kind": "member",
122 | "memberof": "All",
123 | "scope": "instance"
124 | },
125 | {
126 | "comment": "/**\nThis function has all tags set\n@deprecated\n@param {string} - The input string\n@param {object} - a second input\n@author Lloyd <75pound@gmail.com>\n@since v0.10.28\n@returns {object | string} this return has several types\n@example\n```js\nall.allTogether(true)\n```\n*/",
127 | "meta": {
128 | "range": [
129 | 749,
130 | 853
131 | ],
132 | "filename": "0-src.js",
133 | "lineno": 44,
134 | "columnno": 0,
135 | "path": "/Users/lloydb/Documents/jsdoc2md/jsdoc-api/test/fixture/class-all",
136 | "code": {
137 | "id": "astnode100000020",
138 | "name": "All.prototype.allThings",
139 | "type": "FunctionExpression",
140 | "paramnames": [
141 | "one",
142 | "two"
143 | ]
144 | },
145 | "vars": {
146 | "some": "All#allThings~some"
147 | }
148 | },
149 | "description": "This function has all tags set",
150 | "deprecated": true,
151 | "params": [
152 | {
153 | "type": {
154 | "names": [
155 | "string"
156 | ]
157 | },
158 | "description": "The input string",
159 | "name": "one"
160 | },
161 | {
162 | "type": {
163 | "names": [
164 | "object"
165 | ]
166 | },
167 | "description": "a second input",
168 | "name": "two"
169 | }
170 | ],
171 | "author": [
172 | "Lloyd <75pound@gmail.com>"
173 | ],
174 | "since": "v0.10.28",
175 | "returns": [
176 | {
177 | "type": {
178 | "names": [
179 | "object",
180 | "string"
181 | ]
182 | },
183 | "description": "this return has several types"
184 | }
185 | ],
186 | "examples": [
187 | "```js\nall.allTogether(true)\n```"
188 | ],
189 | "name": "allThings",
190 | "longname": "All#allThings",
191 | "kind": "function",
192 | "memberof": "All",
193 | "scope": "instance"
194 | },
195 | {
196 | "comment": "/**\n a rarseclart inner\n */",
197 | "meta": {
198 | "range": [
199 | 835,
200 | 851
201 | ],
202 | "filename": "0-src.js",
203 | "lineno": 48,
204 | "columnno": 6,
205 | "path": "/Users/lloydb/Documents/jsdoc2md/jsdoc-api/test/fixture/class-all",
206 | "code": {
207 | "id": "astnode100000031",
208 | "name": "some",
209 | "type": "Literal",
210 | "value": "bs code"
211 | }
212 | },
213 | "description": "a rarseclart inner",
214 | "name": "some",
215 | "longname": "All#allThings~some",
216 | "kind": "member",
217 | "memberof": "All#allThings",
218 | "scope": "inner",
219 | "params": []
220 | },
221 | {
222 | "kind": "package",
223 | "longname": "package:undefined",
224 | "files": [
225 | "/Users/lloydb/Documents/jsdoc2md/jsdoc-api/test/fixture/class-all/0-src.js"
226 | ]
227 | }
228 | ]
229 |
--------------------------------------------------------------------------------
/test/fixture/folder with spaces/fake-jsdoc.js:
--------------------------------------------------------------------------------
1 | console.log(JSON.stringify(process.argv))
2 |
--------------------------------------------------------------------------------
/test/lib/fixture.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import fs from 'fs'
3 | import arrayify from 'array-back'
4 |
5 | class Fixture {
6 | constructor (name, filePath) {
7 | this.folder = path.resolve('test', 'fixture', name)
8 | this.sourcePath = path.resolve(this.folder, filePath || '0-src.js')
9 |
10 | this.getSource = function () {
11 | return fs.readFileSync(this.sourcePath, 'utf-8')
12 | }
13 |
14 | this.getExpectedOutput = function (output) {
15 | const expectedOutput = JSON.parse(fs.readFileSync(path.resolve(this.folder, '1-jsdoc.json'), 'utf-8'))
16 | Fixture.removeFileSpecificData(expectedOutput)
17 | if (output) Fixture.removeFileSpecificData(output)
18 | return expectedOutput
19 | }
20 |
21 | this.createReadStream = function () {
22 | return fs.createReadStream(this.sourcePath)
23 | }
24 | }
25 |
26 | static createTmpFolder (folder) {
27 | try {
28 | fs.statSync(folder)
29 | /* rmdirSync is node v12 friendly */
30 | fs.rmdirSync(folder, { recursive: true })
31 | fs.mkdirSync(folder)
32 | } catch (err) {
33 | fs.mkdirSync(folder)
34 | }
35 | }
36 |
37 | static removeFileSpecificData () {
38 | arrayify(arguments).forEach(function (input) {
39 | if (input) {
40 | input.forEach(function (i) {
41 | delete i.meta
42 | delete i.files
43 | })
44 | }
45 | })
46 | }
47 |
48 | static normaliseNewLines (doclets) {
49 | const input = JSON.stringify(doclets, null, ' ')
50 | /* Normalise all newlines to posix style to avoid differences while testing on Windows */
51 | let result = input.replace(/\\r?\\n/gm, '\\n')
52 | /* Additional check for naked \r characters created by jsdoc */
53 | /* See: https://github.com/jsdoc2md/dmd/issues/102 */
54 | result = result.replace(/\\r(?!\\n)/g, '\\n')
55 | return JSON.parse(result)
56 | }
57 | }
58 |
59 | export default Fixture
60 |
--------------------------------------------------------------------------------
/test/render.js:
--------------------------------------------------------------------------------
1 | import jsdoc from 'jsdoc-api'
2 | import Fixture from './lib/fixture.js'
3 | import { statSync } from 'fs'
4 | import { strict as a } from 'assert'
5 |
6 | const [test, only, skip] = [new Map(), new Map(), new Map()]
7 |
8 | test.set('.render({ files })', async function () {
9 | Fixture.createTmpFolder('tmp')
10 | Fixture.createTmpFolder('tmp/render')
11 | const f = new Fixture('class-all')
12 | await jsdoc.render({ files: f.sourcePath, destination: 'tmp/render/out' })
13 | a.doesNotThrow(function () {
14 | statSync('./tmp/render/out/index.html')
15 | })
16 | })
17 |
18 | test.set('.render({ source, destination })', async function () {
19 | Fixture.createTmpFolder('tmp')
20 | Fixture.createTmpFolder('tmp/render')
21 | const f = new Fixture('class-all')
22 | await jsdoc.render({ source: f.getSource(), destination: 'tmp/render/out' })
23 | a.doesNotThrow(function () {
24 | statSync('./tmp/render/out/index.html')
25 | })
26 | })
27 |
28 | test.set('.render({ source[], destination })', async function () {
29 | Fixture.createTmpFolder('tmp/renderSource')
30 | const sources = [
31 | `import Foo from "foo"
32 | /**
33 | * FooPrime is some child class
34 | * @class
35 | * @param {Object} - an input
36 | * @extends Foo
37 | */
38 | function FooPrime() {}
39 | export default FooPrime
40 | `,
41 | `import Foo from "foo"
42 | /**
43 | * FooSecond is some other child class
44 | * @class
45 | * @param {Object} - an input
46 | * @extends Foo
47 | */
48 | function FooSecond() {}
49 | export default FooSecond
50 | `]
51 | await jsdoc.render({ source: sources, destination: 'tmp/renderSource/out' })
52 | a.doesNotThrow(function () {
53 | statSync('./tmp/renderSource/out/FooPrime.html')
54 | statSync('./tmp/renderSource/out/FooSecond.html')
55 | })
56 | })
57 |
58 | export { test, only, skip }
59 |
--------------------------------------------------------------------------------