@ng-prism/plugin-jsdoc 22.5.0 → 22.7.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -15
- package/dist/api-page/api-page.helpers.d.ts +79 -0
- package/dist/api-page/api-page.helpers.d.ts.map +1 -0
- package/dist/api-page/api-page.helpers.js +133 -0
- package/dist/api-page/api-page.model.d.ts +62 -0
- package/dist/api-page/api-page.model.d.ts.map +1 -0
- package/dist/api-page/api-page.model.js +122 -0
- package/dist/api-page/component-usage.d.ts +14 -0
- package/dist/api-page/component-usage.d.ts.map +1 -0
- package/dist/api-page/component-usage.js +120 -0
- package/dist/api-page/doc-links.d.ts +15 -0
- package/dist/api-page/doc-links.d.ts.map +1 -0
- package/dist/api-page/doc-links.js +45 -0
- package/dist/api-page/jsdoc-api-page.component.d.ts +98 -0
- package/dist/api-page/jsdoc-api-page.component.d.ts.map +1 -0
- package/dist/api-page/jsdoc-api-page.component.js +1458 -0
- package/dist/api-page/pipe-usage.d.ts +13 -0
- package/dist/api-page/pipe-usage.d.ts.map +1 -0
- package/dist/api-page/pipe-usage.js +35 -0
- package/dist/api-page/service-usage.d.ts +31 -0
- package/dist/api-page/service-usage.d.ts.map +1 -0
- package/dist/api-page/service-usage.js +66 -0
- package/dist/jsdoc-extractor.d.ts.map +1 -1
- package/dist/jsdoc-extractor.js +17 -10
- package/dist/jsdoc-panel.component.d.ts +8 -25
- package/dist/jsdoc-panel.component.d.ts.map +1 -1
- package/dist/jsdoc-panel.component.js +34 -474
- package/dist/jsdoc-plugin.browser.js +2 -2
- package/dist/jsdoc-plugin.d.ts.map +1 -1
- package/dist/jsdoc-plugin.js +4 -1
- package/dist/service-page/api-page.model.d.ts +35 -0
- package/dist/service-page/api-page.model.d.ts.map +1 -0
- package/dist/service-page/api-page.model.js +54 -0
- package/dist/service-page/jsdoc-service-page.component.d.ts +82 -0
- package/dist/service-page/jsdoc-service-page.component.d.ts.map +1 -0
- package/dist/service-page/jsdoc-service-page.component.js +1178 -0
- package/dist/service-page/pipe-usage.d.ts +13 -0
- package/dist/service-page/pipe-usage.d.ts.map +1 -0
- package/dist/service-page/pipe-usage.js +35 -0
- package/dist/service-page/service-page.model.d.ts +78 -0
- package/dist/service-page/service-page.model.d.ts.map +1 -0
- package/dist/service-page/service-page.model.js +130 -0
- package/dist/service-page/service-usage.d.ts +28 -0
- package/dist/service-page/service-usage.d.ts.map +1 -0
- package/dist/service-page/service-usage.js +61 -0
- package/package.json +3 -2
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ScannedPipe } from '@ng-prism/core/plugin';
|
|
2
|
+
/**
|
|
3
|
+
* The snippet that shows how to use a pipe: the imports, the `providers`
|
|
4
|
+
* entries its setup asks for, the component's `imports` entry and a template
|
|
5
|
+
* line. Imports and setup are written as for a service.
|
|
6
|
+
*
|
|
7
|
+
* Like the service snippet it is generated and says nothing about values: the
|
|
8
|
+
* template line names the piped value `value` and each argument by its
|
|
9
|
+
* parameter name. It shows the first signature that is not `@deprecated`, the
|
|
10
|
+
* way a new template should call the pipe, or the first one when all are.
|
|
11
|
+
*/
|
|
12
|
+
export declare function generatePipeUsage(pipe: ScannedPipe): string;
|
|
13
|
+
//# sourceMappingURL=pipe-usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipe-usage.d.ts","sourceRoot":"","sources":["../../src/api-page/pipe-usage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGpE;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAU3D"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { importLines, joinUsageBlocks, setupBlock, setupImports } from './service-usage.js';
|
|
2
|
+
/**
|
|
3
|
+
* The snippet that shows how to use a pipe: the imports, the `providers`
|
|
4
|
+
* entries its setup asks for, the component's `imports` entry and a template
|
|
5
|
+
* line. Imports and setup are written as for a service.
|
|
6
|
+
*
|
|
7
|
+
* Like the service snippet it is generated and says nothing about values: the
|
|
8
|
+
* template line names the piped value `value` and each argument by its
|
|
9
|
+
* parameter name. It shows the first signature that is not `@deprecated`, the
|
|
10
|
+
* way a new template should call the pipe, or the first one when all are.
|
|
11
|
+
*/
|
|
12
|
+
export function generatePipeUsage(pipe) {
|
|
13
|
+
const { className, pipeName, api } = pipe;
|
|
14
|
+
const signature = api.transform.find((method) => !method.tags.deprecated) ?? api.transform[0];
|
|
15
|
+
return joinUsageBlocks([
|
|
16
|
+
importLines(pipe, setupImports(api.setup)),
|
|
17
|
+
setupBlock(api.setup),
|
|
18
|
+
['// in the component that uses it', `@Component({ imports: [${className}], … })`],
|
|
19
|
+
['// in its template', `{{ value | ${pipeName}${pipeArguments(signature)} }}`]
|
|
20
|
+
]);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The arguments of the template line, from a signature's parameters after the
|
|
24
|
+
* piped value: `: pattern` for each one the call has to pass. Pipe arguments
|
|
25
|
+
* are positional, so what can be left out is the optional and rest parameters
|
|
26
|
+
* at the end; one with a default that a required parameter follows stays in.
|
|
27
|
+
*/
|
|
28
|
+
function pipeArguments(signature) {
|
|
29
|
+
const params = signature?.params.slice(1) ?? [];
|
|
30
|
+
const lastRequired = params.map((param) => !param.optional && !param.rest).lastIndexOf(true);
|
|
31
|
+
return params
|
|
32
|
+
.slice(0, lastRequired + 1)
|
|
33
|
+
.map((param) => `: ${param.name}`)
|
|
34
|
+
.join('');
|
|
35
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ApiSetupEntry, ScannedService } from '@ng-prism/core/plugin';
|
|
2
|
+
/** A name an import line brings in, and the module it comes from. */
|
|
3
|
+
export interface UsageImport {
|
|
4
|
+
name: string;
|
|
5
|
+
from: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The snippet that shows how to bring a service into an application: the
|
|
9
|
+
* imports, the `providers` entries its setup asks for, and the `inject()` call.
|
|
10
|
+
*
|
|
11
|
+
* It is generated from the scanned API, not taken from the author, so it says
|
|
12
|
+
* nothing about values: a setup function's arguments and a token's value are
|
|
13
|
+
* left as `…` for the reader to fill in.
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateServiceUsage(service: ScannedService): string;
|
|
16
|
+
/**
|
|
17
|
+
* One line per entry point, the class's first, each naming the class before
|
|
18
|
+
* the `extra` names it shares a module with. Shared with the pipe and the
|
|
19
|
+
* component snippet.
|
|
20
|
+
*/
|
|
21
|
+
export declare function importLines({ className, importPath }: {
|
|
22
|
+
className: string;
|
|
23
|
+
importPath?: string;
|
|
24
|
+
}, extra?: UsageImport[]): string[];
|
|
25
|
+
/** What the setup entries of a service or pipe import. Shared with the pipe snippet. */
|
|
26
|
+
export declare function setupImports(setup: ApiSetupEntry[]): UsageImport[];
|
|
27
|
+
/** The `app.config.ts` block with one `providers` entry per setup entry, or nothing without setup. Shared with the pipe snippet. */
|
|
28
|
+
export declare function setupBlock(setup: ApiSetupEntry[]): string[];
|
|
29
|
+
/** The blocks of a snippet, each a list of lines, with a blank line between them; an empty block is left out. */
|
|
30
|
+
export declare function joinUsageBlocks(blocks: string[][]): string;
|
|
31
|
+
//# sourceMappingURL=service-usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-usage.d.ts","sourceRoot":"","sources":["../../src/api-page/service-usage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE3E,qEAAqE;AACrE,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAmBpE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,GAAE,WAAW,EAAO,GAAG,MAAM,EAAE,CAStI;AAED,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,WAAW,EAAE,CAElE;AAED,oIAAoI;AACpI,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,CAG3D;AAED,iHAAiH;AACjH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,CAK1D"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The snippet that shows how to bring a service into an application: the
|
|
3
|
+
* imports, the `providers` entries its setup asks for, and the `inject()` call.
|
|
4
|
+
*
|
|
5
|
+
* It is generated from the scanned API, not taken from the author, so it says
|
|
6
|
+
* nothing about values: a setup function's arguments and a token's value are
|
|
7
|
+
* left as `…` for the reader to fill in.
|
|
8
|
+
*/
|
|
9
|
+
export function generateServiceUsage(service) {
|
|
10
|
+
const { className, provision, api } = service;
|
|
11
|
+
const variable = className.charAt(0).toLowerCase() + className.slice(1);
|
|
12
|
+
const blocks = [importLines(service, setupImports(api.setup)), setupBlock(api.setup)];
|
|
13
|
+
// A setup function of a service provided by hand normally provides it; a token never does.
|
|
14
|
+
if (provision === 'manual' && !api.setup.some((entry) => entry.kind === 'function')) {
|
|
15
|
+
blocks.push([
|
|
16
|
+
'// the component that uses it',
|
|
17
|
+
`@Component({ …, providers: [${className}] })`,
|
|
18
|
+
'export class MyComponent {',
|
|
19
|
+
` private readonly ${variable} = inject(${className});`,
|
|
20
|
+
'}'
|
|
21
|
+
]);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
blocks.push(['// in a component or service', `private readonly ${variable} = inject(${className});`]);
|
|
25
|
+
}
|
|
26
|
+
return joinUsageBlocks(blocks);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* One line per entry point, the class's first, each naming the class before
|
|
30
|
+
* the `extra` names it shares a module with. Shared with the pipe and the
|
|
31
|
+
* component snippet.
|
|
32
|
+
*/
|
|
33
|
+
export function importLines({ className, importPath }, extra = []) {
|
|
34
|
+
const groups = new Map();
|
|
35
|
+
const add = (path, name) => groups.set(path, [...(groups.get(path) ?? []), name]);
|
|
36
|
+
// A class the scanner could not place has no import path; there is nothing true to write for it.
|
|
37
|
+
if (importPath)
|
|
38
|
+
add(importPath, className);
|
|
39
|
+
for (const { name, from } of extra)
|
|
40
|
+
add(from, name);
|
|
41
|
+
return [...groups].map(([path, names]) => `import { ${names.join(', ')} } from '${path}';`);
|
|
42
|
+
}
|
|
43
|
+
/** What the setup entries of a service or pipe import. Shared with the pipe snippet. */
|
|
44
|
+
export function setupImports(setup) {
|
|
45
|
+
return setup.map(({ name, importPath }) => ({ name, from: importPath }));
|
|
46
|
+
}
|
|
47
|
+
/** The `app.config.ts` block with one `providers` entry per setup entry, or nothing without setup. Shared with the pipe snippet. */
|
|
48
|
+
export function setupBlock(setup) {
|
|
49
|
+
if (!setup.length)
|
|
50
|
+
return [];
|
|
51
|
+
return ['// app.config.ts', `providers: [${setup.map(providerEntry).join(', ')}]`];
|
|
52
|
+
}
|
|
53
|
+
/** The blocks of a snippet, each a list of lines, with a blank line between them; an empty block is left out. */
|
|
54
|
+
export function joinUsageBlocks(blocks) {
|
|
55
|
+
return blocks
|
|
56
|
+
.filter((lines) => lines.length)
|
|
57
|
+
.map((lines) => lines.join('\n'))
|
|
58
|
+
.join('\n\n');
|
|
59
|
+
}
|
|
60
|
+
function providerEntry(entry) {
|
|
61
|
+
if (entry.kind === 'token')
|
|
62
|
+
return `{ provide: ${entry.name}, useValue: … }`;
|
|
63
|
+
// A rest parameter can be left out as well as an optional one.
|
|
64
|
+
const callableBare = (entry.params ?? []).every((param) => param.optional || param.rest);
|
|
65
|
+
return `${entry.name}(${callableBare ? '' : '…'})`;
|
|
66
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsdoc-extractor.d.ts","sourceRoot":"","sources":["../src/jsdoc-extractor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAkC,MAAM,kBAAkB,CAAC;AAElF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EAAO,GAAG,SAAS,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"jsdoc-extractor.d.ts","sourceRoot":"","sources":["../src/jsdoc-extractor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAkC,MAAM,kBAAkB,CAAC;AAElF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EAAO,GAAG,SAAS,GAAG,IAAI,CAenJ"}
|
package/dist/jsdoc-extractor.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
1
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
2
2
|
import ts from 'typescript';
|
|
3
3
|
/**
|
|
4
4
|
* `baseClasses` come from the scanner, nearest first. Members are read from
|
|
@@ -6,15 +6,7 @@ import ts from 'typescript';
|
|
|
6
6
|
* member decides its tags, as a redeclaration replaces the inherited one.
|
|
7
7
|
*/
|
|
8
8
|
export function extractJsDocData(filePath, className, baseClasses = []) {
|
|
9
|
-
const
|
|
10
|
-
const findClass = (path, name) => {
|
|
11
|
-
let sourceFile = sourceFiles.get(path);
|
|
12
|
-
if (!sourceFile) {
|
|
13
|
-
sourceFile = ts.createSourceFile(path, readFileSync(path, 'utf-8'), ts.ScriptTarget.ES2022, true);
|
|
14
|
-
sourceFiles.set(path, sourceFile);
|
|
15
|
-
}
|
|
16
|
-
return findClassByName(sourceFile, name);
|
|
17
|
-
};
|
|
9
|
+
const findClass = (path, name) => findClassByName(parseFile(path), name);
|
|
18
10
|
const classDecl = findClass(filePath, className);
|
|
19
11
|
if (!classDecl)
|
|
20
12
|
return null;
|
|
@@ -26,6 +18,21 @@ export function extractJsDocData(filePath, className, baseClasses = []) {
|
|
|
26
18
|
methods: extractPublicMethods(hierarchy)
|
|
27
19
|
};
|
|
28
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* The files parsed so far, with the size and modification time they had then.
|
|
23
|
+
* `serve` runs the hook for every component again on each change in the
|
|
24
|
+
* library, so a file that has not changed since is neither read nor parsed again.
|
|
25
|
+
*/
|
|
26
|
+
const parsedFiles = new Map();
|
|
27
|
+
function parseFile(path) {
|
|
28
|
+
const { mtimeMs, size } = statSync(path);
|
|
29
|
+
const cached = parsedFiles.get(path);
|
|
30
|
+
if (cached?.mtimeMs === mtimeMs && cached.size === size)
|
|
31
|
+
return cached.sourceFile;
|
|
32
|
+
const sourceFile = ts.createSourceFile(path, readFileSync(path, 'utf-8'), ts.ScriptTarget.ES2022, true);
|
|
33
|
+
parsedFiles.set(path, { mtimeMs, size, sourceFile });
|
|
34
|
+
return sourceFile;
|
|
35
|
+
}
|
|
29
36
|
function findClassByName(sourceFile, className) {
|
|
30
37
|
let found = null;
|
|
31
38
|
function visit(node) {
|
|
@@ -1,31 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { InputMeta, OutputMeta } from '@ng-prism/core/plugin';
|
|
3
|
-
import type { JsDocData, MethodDoc } from './jsdoc.types.js';
|
|
4
|
-
import { type ParsedExample } from './markdown.js';
|
|
1
|
+
import { type ApiPageModel } from './api-page/api-page.model.js';
|
|
5
2
|
import * as i0 from "@angular/core";
|
|
6
3
|
export declare class JsDocPanelComponent {
|
|
7
4
|
readonly activeComponent: import("@angular/core").InputSignal<unknown>;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
protected readonly
|
|
14
|
-
protected readonly classTags: import("@angular/core").Signal<import("./jsdoc.types.js").JsDocTags>;
|
|
15
|
-
protected readonly isDeprecated: import("@angular/core").Signal<boolean>;
|
|
16
|
-
protected readonly deprecatedMessage: import("@angular/core").Signal<string | undefined>;
|
|
17
|
-
protected readonly since: import("@angular/core").Signal<string | undefined>;
|
|
18
|
-
protected readonly version: import("@angular/core").Signal<string | undefined>;
|
|
19
|
-
protected readonly seeRefs: import("@angular/core").Signal<string[]>;
|
|
20
|
-
protected readonly examples: import("@angular/core").Signal<string[]>;
|
|
21
|
-
protected readonly methods: import("@angular/core").Signal<MethodDoc[]>;
|
|
22
|
-
protected readonly hasTags: import("@angular/core").Signal<boolean>;
|
|
23
|
-
protected isMemberDeprecated(name: string): boolean;
|
|
24
|
-
protected getMemberSince(name: string): string | undefined;
|
|
25
|
-
protected renderInline(text: string | undefined): SafeHtml;
|
|
26
|
-
protected parseExample(raw: string): ParsedExample;
|
|
27
|
-
protected formatDefault(value: unknown): string;
|
|
5
|
+
/** Set on a service page, where `activeComponent` is `null`. */
|
|
6
|
+
readonly activeService: import("@angular/core").InputSignal<unknown>;
|
|
7
|
+
/** Set on a pipe page, where `activeComponent` is `null`. */
|
|
8
|
+
readonly activePipe: import("@angular/core").InputSignal<unknown>;
|
|
9
|
+
/** The API page of whatever is on screen; `null` when nothing is selected. */
|
|
10
|
+
protected readonly apiPage: import("@angular/core").Signal<ApiPageModel | null>;
|
|
28
11
|
static ɵfac: i0.ɵɵFactoryDeclaration<JsDocPanelComponent, never>;
|
|
29
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<JsDocPanelComponent, "prism-jsdoc-panel", never, { "activeComponent": { "alias": "activeComponent"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
12
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<JsDocPanelComponent, "prism-jsdoc-panel", never, { "activeComponent": { "alias": "activeComponent"; "required": false; "isSignal": true; }; "activeService": { "alias": "activeService"; "required": false; "isSignal": true; }; "activePipe": { "alias": "activePipe"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
30
13
|
}
|
|
31
14
|
//# sourceMappingURL=jsdoc-panel.component.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsdoc-panel.component.d.ts","sourceRoot":"","sources":["../src/jsdoc-panel.component.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"jsdoc-panel.component.d.ts","sourceRoot":"","sources":["../src/jsdoc-panel.component.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAA2C,MAAM,8BAA8B,CAAC;;AAG1G,qBAQa,mBAAmB;IAC5B,QAAQ,CAAC,eAAe,+CAAwB;IAChD,gEAAgE;IAChE,QAAQ,CAAC,aAAa,+CAAwB;IAC9C,6DAA6D;IAC7D,QAAQ,CAAC,UAAU,+CAAwB;IAE3C,8EAA8E;IAC9E,SAAS,CAAC,QAAQ,CAAC,OAAO,sDAQvB;yCAhBM,mBAAmB;2CAAnB,mBAAmB;CAiB/B"}
|