mirror of
https://github.com/jsdoc/jsdoc.git
synced 2025-12-08 19:46:11 +00:00
feat(jsdoc-core): move generateDocs() to public API
This commit is contained in:
parent
44671a57e6
commit
301a3a4e5d
@ -20,6 +20,8 @@ import path from 'node:path';
|
||||
import { Env } from '@jsdoc/core';
|
||||
import glob from 'fast-glob';
|
||||
|
||||
const DEFAULT_TEMPLATE = '@jsdoc/template-legacy';
|
||||
|
||||
/**
|
||||
* The API for programmatically generating documentation with JSDoc.
|
||||
*
|
||||
@ -38,10 +40,14 @@ export default class Api {
|
||||
constructor(opts) {
|
||||
/**
|
||||
* An event emitter that acts as a message bus for all JSDoc modules.
|
||||
*
|
||||
* @type {node:events.EventEmitter}
|
||||
*/
|
||||
this.emitter = opts?.emitter ?? new EventEmitter();
|
||||
/**
|
||||
* The JSDoc environment, including configuration settings, for this API instance.
|
||||
*
|
||||
* @type {module:@jsdoc/core.Env}
|
||||
*/
|
||||
this.env = opts?.env ?? new Env();
|
||||
}
|
||||
@ -97,4 +103,52 @@ export default class Api {
|
||||
|
||||
return this.env.sourceFiles?.slice() ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates documentation with the template specified in the JSDoc environment, or with
|
||||
* `@jsdoc/template-legacy` if no template is specified.
|
||||
*
|
||||
* The template must export a `publish` function that generates output when called and returns a
|
||||
* `Promise`.
|
||||
*
|
||||
* @param {module:@jsdoc/doclet.DocletStore} docletStore - The doclet store obtained by parsing
|
||||
* the source files.
|
||||
* @returns {Promise<*>} A promise that is fulfilled after the template runs.
|
||||
*/
|
||||
async generateDocs(docletStore) {
|
||||
let message;
|
||||
const { log, options } = this.env;
|
||||
let template;
|
||||
|
||||
options.template ??= DEFAULT_TEMPLATE;
|
||||
|
||||
try {
|
||||
template = await import(options.template);
|
||||
} catch (e) {
|
||||
if (options.template === DEFAULT_TEMPLATE) {
|
||||
message =
|
||||
`Unable to load the default template, \`${DEFAULT_TEMPLATE}\`. You can install ` +
|
||||
'the default template, or you can install a different template and configure JSDoc to ' +
|
||||
'use that template.';
|
||||
} else {
|
||||
message = `Unable to load the template \`${options.template}\`: ${e.message ?? e}`;
|
||||
}
|
||||
|
||||
log.fatal(message);
|
||||
|
||||
return Promise.reject(new Error(message));
|
||||
}
|
||||
|
||||
// Templates must export a `publish` function.
|
||||
if (template.publish && typeof template.publish === 'function') {
|
||||
log.info('Generating output files...');
|
||||
|
||||
return template.publish(docletStore, this.env);
|
||||
} else {
|
||||
message = `\`${options.template}\` does not export a \`publish\` function.`;
|
||||
log.fatal(message);
|
||||
|
||||
return Promise.reject(new Error(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
17
packages/jsdoc-core/test/fixtures/templates/bad-publish-template.js
vendored
Normal file
17
packages/jsdoc-core/test/fixtures/templates/bad-publish-template.js
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
Copyright 2024 the JSDoc Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
export const publish = 'foo';
|
||||
22
packages/jsdoc-core/test/fixtures/templates/fake-template.js
vendored
Normal file
22
packages/jsdoc-core/test/fixtures/templates/fake-template.js
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
Copyright 2024 the JSDoc Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
export function publish(docletStore, env) {
|
||||
env.docletStore = docletStore;
|
||||
env.foo = 'bar';
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
17
packages/jsdoc-core/test/fixtures/templates/no-publish-template.js
vendored
Normal file
17
packages/jsdoc-core/test/fixtures/templates/no-publish-template.js
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
Copyright 2024 the JSDoc Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
export const foo = 'bar';
|
||||
@ -173,4 +173,100 @@ describe('Api', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateDocs', () => {
|
||||
let env;
|
||||
let options;
|
||||
|
||||
beforeEach(() => {
|
||||
env = instance.env;
|
||||
options = env.options;
|
||||
options.template = path.resolve(
|
||||
path.join(__dirname, '../../fixtures/templates/fake-template.js')
|
||||
);
|
||||
});
|
||||
|
||||
it('calls the `publish` function from the specified template', async () => {
|
||||
await instance.generateDocs();
|
||||
|
||||
expect(env.foo).toBe('bar');
|
||||
});
|
||||
|
||||
it('passes the `DocletStore` and `Env` to the template', async () => {
|
||||
const fakeDocletStore = {};
|
||||
|
||||
await instance.generateDocs(fakeDocletStore);
|
||||
|
||||
expect(env.docletStore).toBe(fakeDocletStore);
|
||||
});
|
||||
|
||||
it('uses the legacy template by default', async () => {
|
||||
options.template = null;
|
||||
|
||||
try {
|
||||
await instance.generateDocs();
|
||||
|
||||
// We shouldn't get here.
|
||||
expect(false).toBeTrue();
|
||||
} catch (e) {
|
||||
expect(e.message).toContain('default template');
|
||||
expect(e.message).toContain('@jsdoc/template-legacy');
|
||||
}
|
||||
});
|
||||
|
||||
it('rejects the promise and logs a fatal error if the template cannot be found', async () => {
|
||||
spyOn(env.log, 'fatal');
|
||||
options.template = 'fleeble';
|
||||
|
||||
try {
|
||||
await instance.generateDocs();
|
||||
|
||||
// We shouldn't get here.
|
||||
expect(false).toBeTrue();
|
||||
} catch (e) {
|
||||
expect(e.message).toContain('fleeble');
|
||||
}
|
||||
|
||||
expect(env.log.fatal).toHaveBeenCalled();
|
||||
expect(env.log.fatal.calls.first().args[0]).toContain('fleeble');
|
||||
});
|
||||
|
||||
it('rejects the promise and logs a fatal error if `publish` is undefined', async () => {
|
||||
spyOn(env.log, 'fatal');
|
||||
options.template = path.resolve(
|
||||
path.join(__dirname, '../../fixtures/templates/no-publish-template.js')
|
||||
);
|
||||
|
||||
try {
|
||||
await instance.generateDocs();
|
||||
|
||||
// We shouldn't get here.
|
||||
expect(false).toBeTrue();
|
||||
} catch (e) {
|
||||
expect(e.message).toContain('no-publish-template.js');
|
||||
}
|
||||
|
||||
expect(env.log.fatal).toHaveBeenCalled();
|
||||
expect(env.log.fatal.calls.first().args[0]).toContain('no-publish-template.js');
|
||||
});
|
||||
|
||||
it('rejects the promise and logs a fatal error if `publish` is not a function', async () => {
|
||||
spyOn(env.log, 'fatal');
|
||||
options.template = path.resolve(
|
||||
path.join(__dirname, '../../fixtures/templates/bad-publish-template.js')
|
||||
);
|
||||
|
||||
try {
|
||||
await instance.generateDocs();
|
||||
|
||||
// We shouldn't get here.
|
||||
expect(false).toBeTrue();
|
||||
} catch (e) {
|
||||
expect(e.message).toContain('bad-publish-template.js');
|
||||
}
|
||||
|
||||
expect(env.log.fatal).toHaveBeenCalled();
|
||||
expect(env.log.fatal.calls.first().args[0]).toContain('bad-publish-template.js');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -260,36 +260,7 @@ export default (() => {
|
||||
return cli;
|
||||
};
|
||||
|
||||
cli.generateDocs = async () => {
|
||||
let message;
|
||||
const { options } = env;
|
||||
let template;
|
||||
|
||||
options.template ??= '@jsdoc/template-legacy';
|
||||
|
||||
try {
|
||||
template = await import(options.template);
|
||||
} catch (e) {
|
||||
log.fatal(`Unable to load template: ${e.message ?? e}`);
|
||||
}
|
||||
|
||||
// templates should export a "publish" function
|
||||
if (template.publish && typeof template.publish === 'function') {
|
||||
let publishPromise;
|
||||
|
||||
log.info('Generating output files...');
|
||||
publishPromise = template.publish(props.docs, env);
|
||||
|
||||
return Promise.resolve(publishPromise);
|
||||
} else {
|
||||
message =
|
||||
`${options.template} does not export a "publish" function. ` +
|
||||
'Global "publish" functions are no longer supported.';
|
||||
log.fatal(message);
|
||||
|
||||
return Promise.reject(new Error(message));
|
||||
}
|
||||
};
|
||||
cli.generateDocs = () => api.generateDocs(props.docs);
|
||||
|
||||
return cli;
|
||||
})();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user