@ng-doc/app 22.0.0-beta.2 → 22.0.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 +20 -29
- package/fesm2022/ng-doc-app-classes-content-anchor-controller.mjs +363 -0
- package/fesm2022/ng-doc-app-classes-content-anchor-controller.mjs.map +1 -0
- package/fesm2022/ng-doc-app-classes-content-controller.mjs +299 -0
- package/fesm2022/ng-doc-app-classes-content-controller.mjs.map +1 -0
- package/fesm2022/ng-doc-app-classes-default-search-engine.mjs +51 -35
- package/fesm2022/ng-doc-app-classes-default-search-engine.mjs.map +1 -1
- package/fesm2022/ng-doc-app-classes-root-page.mjs.map +1 -1
- package/fesm2022/ng-doc-app-classes-search-engine.mjs.map +1 -1
- package/fesm2022/ng-doc-app-classes.mjs +2 -0
- package/fesm2022/ng-doc-app-classes.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-api-list.mjs +173 -69
- package/fesm2022/ng-doc-app-components-api-list.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-breadcrumb.mjs +13 -10
- package/fesm2022/ng-doc-app-components-breadcrumb.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-code.mjs +152 -25
- package/fesm2022/ng-doc-app-components-code.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-command-palette.mjs +498 -0
- package/fesm2022/ng-doc-app-components-command-palette.mjs.map +1 -0
- package/fesm2022/ng-doc-app-components-copy-button.mjs +38 -21
- package/fesm2022/ng-doc-app-components-copy-button.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-demo-displayer.mjs +36 -29
- package/fesm2022/ng-doc-app-components-demo-displayer.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-demo-pane.mjs +39 -36
- package/fesm2022/ng-doc-app-components-demo-pane.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-demo.mjs +129 -44
- package/fesm2022/ng-doc-app-components-demo.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-fullscreen-button.mjs +12 -9
- package/fesm2022/ng-doc-app-components-fullscreen-button.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-fullscreen-toggle.mjs +79 -0
- package/fesm2022/ng-doc-app-components-fullscreen-toggle.mjs.map +1 -0
- package/fesm2022/ng-doc-app-components-heading-anchor.mjs +54 -21
- package/fesm2022/ng-doc-app-components-heading-anchor.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-image-viewer.mjs +183 -89
- package/fesm2022/ng-doc-app-components-image-viewer.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-kind-icon.mjs +42 -25
- package/fesm2022/ng-doc-app-components-kind-icon.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-link.mjs +12 -9
- package/fesm2022/ng-doc-app-components-link.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-members.mjs +30 -0
- package/fesm2022/ng-doc-app-components-members.mjs.map +1 -0
- package/fesm2022/ng-doc-app-components-mermaid-viewer.mjs +61 -20
- package/fesm2022/ng-doc-app-components-mermaid-viewer.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-navbar.mjs +39 -49
- package/fesm2022/ng-doc-app-components-navbar.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-page-header.mjs +73 -10
- package/fesm2022/ng-doc-app-components-page-header.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-page-link.mjs +123 -31
- package/fesm2022/ng-doc-app-components-page-link.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-page-navigation.mjs +17 -19
- package/fesm2022/ng-doc-app-components-page-navigation.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-page-wrapper.mjs +56 -35
- package/fesm2022/ng-doc-app-components-page-wrapper.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-page.mjs +168 -24
- package/fesm2022/ng-doc-app-components-page.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-playground.mjs +392 -263
- package/fesm2022/ng-doc-app-components-playground.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-root.mjs +48 -31
- package/fesm2022/ng-doc-app-components-root.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-search-result.mjs +22 -21
- package/fesm2022/ng-doc-app-components-search-result.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-search.mjs +64 -33
- package/fesm2022/ng-doc-app-components-search.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-sidebar.mjs +86 -61
- package/fesm2022/ng-doc-app-components-sidebar.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-tabs.mjs +18 -12
- package/fesm2022/ng-doc-app-components-tabs.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-theme-toggle.mjs +33 -21
- package/fesm2022/ng-doc-app-components-theme-toggle.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-toc.mjs +267 -90
- package/fesm2022/ng-doc-app-components-toc.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components.mjs +3 -1
- package/fesm2022/ng-doc-app-components.mjs.map +1 -1
- package/fesm2022/ng-doc-app-defaults-default-processors.mjs +2 -1
- package/fesm2022/ng-doc-app-defaults-default-processors.mjs.map +1 -1
- package/fesm2022/ng-doc-app-directives-code-highlighter.mjs +11 -5
- package/fesm2022/ng-doc-app-directives-code-highlighter.mjs.map +1 -1
- package/fesm2022/ng-doc-app-directives-members-filter.mjs +276 -0
- package/fesm2022/ng-doc-app-directives-members-filter.mjs.map +1 -0
- package/fesm2022/ng-doc-app-directives-route-active.mjs +34 -30
- package/fesm2022/ng-doc-app-directives-route-active.mjs.map +1 -1
- package/fesm2022/ng-doc-app-directives.mjs +1 -0
- package/fesm2022/ng-doc-app-directives.mjs.map +1 -1
- package/fesm2022/ng-doc-app-helpers.mjs +285 -1
- package/fesm2022/ng-doc-app-helpers.mjs.map +1 -1
- package/fesm2022/ng-doc-app-pipes-decode-uri-component.mjs +6 -4
- package/fesm2022/ng-doc-app-pipes-decode-uri-component.mjs.map +1 -1
- package/fesm2022/ng-doc-app-pipes-extract-value.mjs +6 -4
- package/fesm2022/ng-doc-app-pipes-extract-value.mjs.map +1 -1
- package/fesm2022/ng-doc-app-pipes-filter-by-text.mjs +7 -4
- package/fesm2022/ng-doc-app-pipes-filter-by-text.mjs.map +1 -1
- package/fesm2022/ng-doc-app-pipes-sanitize-html.mjs +8 -5
- package/fesm2022/ng-doc-app-pipes-sanitize-html.mjs.map +1 -1
- package/fesm2022/ng-doc-app-processors-page-processor.mjs +86 -23
- package/fesm2022/ng-doc-app-processors-page-processor.mjs.map +1 -1
- package/fesm2022/ng-doc-app-processors-processors-tooltip.mjs +26 -25
- package/fesm2022/ng-doc-app-processors-processors-tooltip.mjs.map +1 -1
- package/fesm2022/ng-doc-app-processors-processors.mjs +12 -1
- package/fesm2022/ng-doc-app-processors-processors.mjs.map +1 -1
- package/fesm2022/ng-doc-app-providers-ng-doc-app.mjs +31 -2
- package/fesm2022/ng-doc-app-providers-ng-doc-app.mjs.map +1 -1
- package/fesm2022/ng-doc-app-services-content-scroll-intent.mjs +122 -0
- package/fesm2022/ng-doc-app-services-content-scroll-intent.mjs.map +1 -0
- package/fesm2022/ng-doc-app-services-content-state.mjs +57 -0
- package/fesm2022/ng-doc-app-services-content-state.mjs.map +1 -0
- package/fesm2022/ng-doc-app-services-fullscreen-route.mjs +74 -0
- package/fesm2022/ng-doc-app-services-fullscreen-route.mjs.map +1 -0
- package/fesm2022/ng-doc-app-services-highlighter.mjs +83 -14
- package/fesm2022/ng-doc-app-services-highlighter.mjs.map +1 -1
- package/fesm2022/ng-doc-app-services-route-preloader.mjs +360 -0
- package/fesm2022/ng-doc-app-services-route-preloader.mjs.map +1 -0
- package/fesm2022/ng-doc-app-services-shortcuts.mjs +214 -0
- package/fesm2022/ng-doc-app-services-shortcuts.mjs.map +1 -0
- package/fesm2022/ng-doc-app-services-sidebar.mjs +59 -25
- package/fesm2022/ng-doc-app-services-sidebar.mjs.map +1 -1
- package/fesm2022/ng-doc-app-services-store.mjs +8 -8
- package/fesm2022/ng-doc-app-services-store.mjs.map +1 -1
- package/fesm2022/ng-doc-app-services-theme.mjs +32 -12
- package/fesm2022/ng-doc-app-services-theme.mjs.map +1 -1
- package/fesm2022/ng-doc-app-services.mjs +143 -0
- package/fesm2022/ng-doc-app-services.mjs.map +1 -1
- package/fesm2022/ng-doc-app-tokens.mjs +7 -28
- package/fesm2022/ng-doc-app-tokens.mjs.map +1 -1
- package/fesm2022/ng-doc-app-type-controls-boolean-control.mjs +18 -9
- package/fesm2022/ng-doc-app-type-controls-boolean-control.mjs.map +1 -1
- package/fesm2022/ng-doc-app-type-controls-number-control.mjs +12 -9
- package/fesm2022/ng-doc-app-type-controls-number-control.mjs.map +1 -1
- package/fesm2022/ng-doc-app-type-controls-string-control.mjs +12 -9
- package/fesm2022/ng-doc-app-type-controls-string-control.mjs.map +1 -1
- package/fesm2022/ng-doc-app-type-controls-type-alias-control.mjs +22 -16
- package/fesm2022/ng-doc-app-type-controls-type-alias-control.mjs.map +1 -1
- package/package.json +69 -28
- package/styles/global.css +1125 -201
- package/styles/main.css +1125 -201
- package/styles/themes/dark.css +78 -56
- package/types/ng-doc-app-classes-content-anchor-controller.d.ts +54 -0
- package/types/ng-doc-app-classes-content-controller.d.ts +94 -0
- package/types/ng-doc-app-classes-default-search-engine.d.ts +9 -1
- package/types/ng-doc-app-classes-root-page.d.ts +6 -1
- package/types/ng-doc-app-classes-search-engine.d.ts +5 -0
- package/types/ng-doc-app-classes.d.ts +2 -0
- package/types/ng-doc-app-components-api-list.d.ts +69 -20
- package/types/ng-doc-app-components-breadcrumb.d.ts +8 -3
- package/types/ng-doc-app-components-code.d.ts +46 -12
- package/types/ng-doc-app-components-command-palette.d.ts +147 -0
- package/types/ng-doc-app-components-copy-button.d.ts +18 -6
- package/types/ng-doc-app-components-demo-displayer.d.ts +23 -10
- package/types/ng-doc-app-components-demo-pane.d.ts +19 -15
- package/types/ng-doc-app-components-demo.d.ts +62 -15
- package/types/ng-doc-app-components-fullscreen-button.d.ts +4 -2
- package/types/ng-doc-app-components-fullscreen-toggle.d.ts +24 -0
- package/types/ng-doc-app-components-heading-anchor.d.ts +26 -7
- package/types/ng-doc-app-components-image-viewer.d.ts +71 -7
- package/types/ng-doc-app-components-kind-icon.d.ts +28 -7
- package/types/ng-doc-app-components-link.d.ts +6 -2
- package/types/ng-doc-app-components-members.d.ts +13 -0
- package/types/ng-doc-app-components-mermaid-viewer.d.ts +21 -6
- package/types/ng-doc-app-components-navbar.d.ts +25 -15
- package/types/ng-doc-app-components-page-header.d.ts +28 -4
- package/types/ng-doc-app-components-page-link.d.ts +34 -15
- package/types/ng-doc-app-components-page-navigation.d.ts +10 -5
- package/types/ng-doc-app-components-page-wrapper.d.ts +35 -11
- package/types/ng-doc-app-components-page.d.ts +57 -6
- package/types/ng-doc-app-components-playground.d.ts +146 -78
- package/types/ng-doc-app-components-root.d.ts +28 -7
- package/types/ng-doc-app-components-search-result.d.ts +14 -6
- package/types/ng-doc-app-components-search.d.ts +19 -7
- package/types/ng-doc-app-components-tabs.d.ts +13 -4
- package/types/ng-doc-app-components-theme-toggle.d.ts +18 -5
- package/types/ng-doc-app-components-toc.d.ts +76 -29
- package/types/ng-doc-app-components.d.ts +3 -1
- package/types/ng-doc-app-directives-code-highlighter.d.ts +8 -4
- package/types/ng-doc-app-directives-members-filter.d.ts +61 -0
- package/types/ng-doc-app-directives-route-active.d.ts +21 -7
- package/types/ng-doc-app-directives.d.ts +1 -0
- package/types/ng-doc-app-helpers.d.ts +124 -3
- package/types/ng-doc-app-interfaces.d.ts +48 -28
- package/types/ng-doc-app-pipes-decode-uri-component.d.ts +3 -0
- package/types/ng-doc-app-pipes-extract-value.d.ts +3 -0
- package/types/ng-doc-app-pipes-filter-by-text.d.ts +4 -0
- package/types/ng-doc-app-pipes-sanitize-html.d.ts +4 -2
- package/types/ng-doc-app-processors-page-processor.d.ts +39 -10
- package/types/ng-doc-app-processors-processors-tooltip.d.ts +11 -10
- package/types/ng-doc-app-processors-processors.d.ts +5 -1
- package/types/ng-doc-app-providers-ng-doc-app.d.ts +17 -0
- package/types/ng-doc-app-services-content-scroll-intent.d.ts +52 -0
- package/types/ng-doc-app-services-content-state.d.ts +40 -0
- package/types/ng-doc-app-services-fullscreen-route.d.ts +35 -0
- package/types/ng-doc-app-services-highlighter.d.ts +40 -5
- package/types/ng-doc-app-services-route-preloader.d.ts +109 -0
- package/types/ng-doc-app-services-shortcuts.d.ts +96 -0
- package/types/ng-doc-app-services-sidebar.d.ts +24 -4
- package/types/ng-doc-app-services-store.d.ts +24 -1
- package/types/ng-doc-app-services-theme.d.ts +19 -3
- package/types/ng-doc-app-services.d.ts +77 -0
- package/types/ng-doc-app-tokens.d.ts +10 -30
- package/types/ng-doc-app-type-controls-boolean-control.d.ts +11 -6
- package/types/ng-doc-app-type-controls-number-control.d.ts +5 -3
- package/types/ng-doc-app-type-controls-string-control.d.ts +5 -3
- package/types/ng-doc-app-type-controls-type-alias-control.d.ts +13 -6
- package/fesm2022/ng-doc-app-components-search-dialog.mjs +0 -78
- package/fesm2022/ng-doc-app-components-search-dialog.mjs.map +0 -1
- package/types/ng-doc-app-components-search-dialog.d.ts +0 -28
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { signal, inject, PendingTasks, DestroyRef, Injectable } from '@angular/core';
|
|
3
|
+
import { ɵforgetNgDocContent as _forgetNgDocContent, ɵpeekNgDocContent as _peekNgDocContent, ɵpendingNgDocContent as _pendingNgDocContent } from '@ng-doc/app/helpers';
|
|
4
|
+
import { NgDocContentState } from '@ng-doc/app/services/content-state';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Owns one body or header content source for one component instance. Provide it in the
|
|
8
|
+
* component's `providers`; it holds a pending task from each load until the processors accept
|
|
9
|
+
* the loaded HTML.
|
|
10
|
+
*/
|
|
11
|
+
class NgDocContentController {
|
|
12
|
+
constructor() {
|
|
13
|
+
/** The loaded HTML. */
|
|
14
|
+
this.html = signal('', /* @ts-ignore */
|
|
15
|
+
...(ngDevMode ? [{ debugName: "html" }] : /* istanbul ignore next */ []));
|
|
16
|
+
/** Increments whenever the HTML must be processed again. */
|
|
17
|
+
this.version = signal(0, /* @ts-ignore */
|
|
18
|
+
...(ngDevMode ? [{ debugName: "version" }] : /* istanbul ignore next */ []));
|
|
19
|
+
/** The load or processing error of the current source. */
|
|
20
|
+
this.error = signal(undefined, /* @ts-ignore */
|
|
21
|
+
...(ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []));
|
|
22
|
+
/**
|
|
23
|
+
* Whether the latest load of the current source has been rendered: its version was processed,
|
|
24
|
+
* or the load or its processing failed. False while a load or its processing is pending.
|
|
25
|
+
*/
|
|
26
|
+
this.settled = signal(false, /* @ts-ignore */
|
|
27
|
+
...(ngDevMode ? [{ debugName: "settled" }] : /* istanbul ignore next */ []));
|
|
28
|
+
/**
|
|
29
|
+
* The version of the latest loaded content of the current source, or undefined before the
|
|
30
|
+
* first load. A processing pass of this version renders loaded content.
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
this.loadedVersion = signal(undefined, /* @ts-ignore */
|
|
34
|
+
...(ngDevMode ? [{ debugName: "loadedVersion" }] : /* istanbul ignore next */ []));
|
|
35
|
+
this.pendingTasks = inject(PendingTasks);
|
|
36
|
+
this.contentState = inject(NgDocContentState);
|
|
37
|
+
this.owner = {};
|
|
38
|
+
this.request = 0;
|
|
39
|
+
this.sourceEpoch = 0;
|
|
40
|
+
this.renderState = {
|
|
41
|
+
version: 0,
|
|
42
|
+
status: 'pending',
|
|
43
|
+
};
|
|
44
|
+
this.destroyed = false;
|
|
45
|
+
inject(DestroyRef).onDestroy(() => this.destroy());
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Loads the source and reloads it whenever the source reports a change. Connecting the
|
|
49
|
+
* connected source again does nothing.
|
|
50
|
+
* @param source - The content source.
|
|
51
|
+
*/
|
|
52
|
+
connect(source) {
|
|
53
|
+
if (this.destroyed || this.source === source)
|
|
54
|
+
return;
|
|
55
|
+
const previousId = this.source?.id;
|
|
56
|
+
this.cancelCurrent();
|
|
57
|
+
this.unsubscribeCurrent();
|
|
58
|
+
const sourceEpoch = ++this.sourceEpoch;
|
|
59
|
+
this.source = source;
|
|
60
|
+
this.loadedVersion.set(undefined);
|
|
61
|
+
if (previousId !== undefined && previousId !== source.id) {
|
|
62
|
+
this.html.set('');
|
|
63
|
+
this.version.update((version) => version + 1);
|
|
64
|
+
this.renderState = { version: this.version(), status: 'pending' };
|
|
65
|
+
}
|
|
66
|
+
this.contentState.clear(this.owner);
|
|
67
|
+
this.error.set(undefined);
|
|
68
|
+
try {
|
|
69
|
+
this.unsubscribe = source.subscribe?.(() => {
|
|
70
|
+
if (this.source !== source || this.sourceEpoch !== sourceEpoch)
|
|
71
|
+
return;
|
|
72
|
+
// The source has a new revision, so a preloaded payload is stale.
|
|
73
|
+
_forgetNgDocContent(source);
|
|
74
|
+
this.reload(false);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
this.fail(source.id, error);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
this.reload(true);
|
|
82
|
+
}
|
|
83
|
+
/** Drops the current source and clears the HTML. */
|
|
84
|
+
disconnect() {
|
|
85
|
+
if (this.destroyed || !this.source)
|
|
86
|
+
return;
|
|
87
|
+
this.cancelCurrent();
|
|
88
|
+
this.sourceEpoch++;
|
|
89
|
+
this.unsubscribeCurrent();
|
|
90
|
+
this.source = undefined;
|
|
91
|
+
this.loadedVersion.set(undefined);
|
|
92
|
+
this.settled.set(false);
|
|
93
|
+
this.contentState.clear(this.owner);
|
|
94
|
+
this.error.set(undefined);
|
|
95
|
+
if (this.html()) {
|
|
96
|
+
this.html.set('');
|
|
97
|
+
this.version.update((version) => version + 1);
|
|
98
|
+
this.renderState = { version: this.version(), status: 'pending' };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Accepts a processing pass. Only the pass of the current version counts.
|
|
103
|
+
* @param version - The content version the pass rendered.
|
|
104
|
+
*/
|
|
105
|
+
processed(version) {
|
|
106
|
+
if (version !== this.version())
|
|
107
|
+
return;
|
|
108
|
+
this.renderState = { version, status: 'complete' };
|
|
109
|
+
if (this.pending?.awaitingVersion === version)
|
|
110
|
+
this.settle(this.pending.request);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Reports a failed processing pass. Only a failure of the current version counts.
|
|
114
|
+
* @param failure - The version and the error.
|
|
115
|
+
*/
|
|
116
|
+
processingFailed(failure) {
|
|
117
|
+
if (failure.version !== this.version() || !this.source)
|
|
118
|
+
return;
|
|
119
|
+
this.renderState = { version: failure.version, status: 'failed' };
|
|
120
|
+
if (this.pending?.awaitingVersion !== failure.version)
|
|
121
|
+
return;
|
|
122
|
+
this.fail(this.source.id, failure.error);
|
|
123
|
+
}
|
|
124
|
+
/** Cancels the current load and releases its pending task. Called on destroy. */
|
|
125
|
+
destroy() {
|
|
126
|
+
if (this.destroyed)
|
|
127
|
+
return;
|
|
128
|
+
this.destroyed = true;
|
|
129
|
+
this.request++;
|
|
130
|
+
this.sourceEpoch++;
|
|
131
|
+
this.abort?.abort();
|
|
132
|
+
this.abort = undefined;
|
|
133
|
+
try {
|
|
134
|
+
this.unsubscribeCurrent();
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
this.finishPending();
|
|
138
|
+
this.contentState.clear(this.owner);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Loads the current source.
|
|
143
|
+
* @param preloaded - Whether a payload that was preloaded for the source (by the route resolver
|
|
144
|
+
* or by link preloading) may be used. It is applied at once, so the first render of the
|
|
145
|
+
* component already shows the content instead of an empty page.
|
|
146
|
+
*/
|
|
147
|
+
reload(preloaded) {
|
|
148
|
+
const source = this.source;
|
|
149
|
+
if (!source || this.destroyed)
|
|
150
|
+
return;
|
|
151
|
+
this.cancelCurrent();
|
|
152
|
+
this.settled.set(false);
|
|
153
|
+
const request = ++this.request;
|
|
154
|
+
const abort = new AbortController();
|
|
155
|
+
this.abort = abort;
|
|
156
|
+
this.pending = { request, release: once(this.pendingTasks.add()) };
|
|
157
|
+
const payload = preloaded ? _peekNgDocContent(source) : undefined;
|
|
158
|
+
if (payload) {
|
|
159
|
+
try {
|
|
160
|
+
this.apply(validatePayload(payload, source.id), request);
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
this.fail(source.id, error);
|
|
164
|
+
}
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
// A page that opened before its preload finished (the router stopped waiting) waits for the
|
|
168
|
+
// same load instead of starting a second one.
|
|
169
|
+
void this.load(source, request, abort.signal, preloaded ? _pendingNgDocContent(source) : undefined);
|
|
170
|
+
}
|
|
171
|
+
async load(source, request, signal, pending) {
|
|
172
|
+
try {
|
|
173
|
+
const payload = validatePayload(await (pending ?? source.load(signal)), source.id);
|
|
174
|
+
if (!this.isCurrent(source, request, signal))
|
|
175
|
+
return;
|
|
176
|
+
this.apply(payload, request);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
if (!this.isCurrent(source, request, signal))
|
|
180
|
+
return;
|
|
181
|
+
this.fail(source.id, error);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
apply(payload, request) {
|
|
185
|
+
this.contentState.clear(this.owner);
|
|
186
|
+
this.error.set(undefined);
|
|
187
|
+
if (payload.html === this.html()) {
|
|
188
|
+
if (this.renderState.version !== this.version() || this.renderState.status === 'failed') {
|
|
189
|
+
this.version.update((version) => version + 1);
|
|
190
|
+
this.renderState = { version: this.version(), status: 'pending' };
|
|
191
|
+
this.loadedVersion.set(this.version());
|
|
192
|
+
if (this.pending?.request === request)
|
|
193
|
+
this.pending.awaitingVersion = this.version();
|
|
194
|
+
}
|
|
195
|
+
else if (this.renderState.status === 'complete') {
|
|
196
|
+
// The loaded content is already on the page (for example an empty body).
|
|
197
|
+
this.loadedVersion.set(this.version());
|
|
198
|
+
this.settle(request);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
this.loadedVersion.set(this.version());
|
|
202
|
+
if (this.pending?.request === request)
|
|
203
|
+
this.pending.awaitingVersion = this.version();
|
|
204
|
+
}
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
this.html.set(payload.html);
|
|
208
|
+
this.version.update((version) => version + 1);
|
|
209
|
+
this.loadedVersion.set(this.version());
|
|
210
|
+
this.renderState = { version: this.version(), status: 'pending' };
|
|
211
|
+
if (this.pending?.request === request)
|
|
212
|
+
this.pending.awaitingVersion = this.version();
|
|
213
|
+
}
|
|
214
|
+
isCurrent(source, request, signal) {
|
|
215
|
+
return !this.destroyed && !signal.aborted && this.source === source && this.request === request;
|
|
216
|
+
}
|
|
217
|
+
fail(contentId, error) {
|
|
218
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
219
|
+
this.contentState.report(this.owner, { contentId, error });
|
|
220
|
+
this.error.set(normalized);
|
|
221
|
+
this.finishPending();
|
|
222
|
+
this.settled.set(true);
|
|
223
|
+
}
|
|
224
|
+
settle(request) {
|
|
225
|
+
if (this.pending?.request !== request)
|
|
226
|
+
return;
|
|
227
|
+
this.finishPending(request);
|
|
228
|
+
this.settled.set(true);
|
|
229
|
+
}
|
|
230
|
+
cancelCurrent() {
|
|
231
|
+
this.request++;
|
|
232
|
+
this.abort?.abort();
|
|
233
|
+
this.abort = undefined;
|
|
234
|
+
this.finishPending();
|
|
235
|
+
}
|
|
236
|
+
finishPending(request) {
|
|
237
|
+
if (!this.pending || (request !== undefined && this.pending.request !== request))
|
|
238
|
+
return;
|
|
239
|
+
this.pending.release();
|
|
240
|
+
this.pending = undefined;
|
|
241
|
+
}
|
|
242
|
+
unsubscribeCurrent() {
|
|
243
|
+
const unsubscribe = this.unsubscribe;
|
|
244
|
+
this.unsubscribe = undefined;
|
|
245
|
+
try {
|
|
246
|
+
unsubscribe?.();
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
// Cleanup cannot keep an application unstable or revive an obsolete source.
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocContentController, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
253
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocContentController }); }
|
|
254
|
+
}
|
|
255
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocContentController, decorators: [{
|
|
256
|
+
type: Injectable
|
|
257
|
+
}], ctorParameters: () => [] });
|
|
258
|
+
/**
|
|
259
|
+
* Checks that a loaded content module has the expected shape and id.
|
|
260
|
+
* @param payload - The loaded value.
|
|
261
|
+
* @param expectedId - The id of the source that loaded it.
|
|
262
|
+
* @returns The payload, typed.
|
|
263
|
+
*/
|
|
264
|
+
function validatePayload(payload, expectedId) {
|
|
265
|
+
if (typeof payload !== 'object' ||
|
|
266
|
+
payload === null ||
|
|
267
|
+
!('schemaVersion' in payload) ||
|
|
268
|
+
payload.schemaVersion !== 1 ||
|
|
269
|
+
!('id' in payload) ||
|
|
270
|
+
payload.id !== expectedId ||
|
|
271
|
+
!('revision' in payload) ||
|
|
272
|
+
typeof payload.revision !== 'string' ||
|
|
273
|
+
!('html' in payload) ||
|
|
274
|
+
typeof payload.html !== 'string') {
|
|
275
|
+
throw new Error(`Invalid NgDoc content payload for "${expectedId}".`);
|
|
276
|
+
}
|
|
277
|
+
return payload;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Wraps a callback so that only its first call runs.
|
|
281
|
+
* @param callback - The callback.
|
|
282
|
+
* @returns The wrapped callback.
|
|
283
|
+
*/
|
|
284
|
+
function once(callback) {
|
|
285
|
+
let active = true;
|
|
286
|
+
return () => {
|
|
287
|
+
if (!active)
|
|
288
|
+
return;
|
|
289
|
+
active = false;
|
|
290
|
+
callback();
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Generated bundle index. Do not edit.
|
|
296
|
+
*/
|
|
297
|
+
|
|
298
|
+
export { NgDocContentController, validatePayload };
|
|
299
|
+
//# sourceMappingURL=ng-doc-app-classes-content-controller.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ng-doc-app-classes-content-controller.mjs","sources":["../../../../libs/app/classes/content-controller/content-controller.ts","../../../../libs/app/classes/content-controller/ng-doc-app-classes-content-controller.ts"],"sourcesContent":["import {\n DestroyRef,\n inject,\n Injectable,\n PendingTasks,\n signal,\n WritableSignal,\n} from '@angular/core';\nimport { ɵforgetNgDocContent, ɵpeekNgDocContent, ɵpendingNgDocContent } from '@ng-doc/app/helpers';\nimport { NgDocContentState } from '@ng-doc/app/services/content-state';\nimport type { NgDocContentModule, NgDocContentSource } from '@ng-doc/core/interfaces';\n\n/** A failed processing pass of one content version. */\nexport interface NgDocContentRenderFailure {\n /** The content version the pass rendered. */\n readonly version: number;\n /** The error the pass failed with. */\n readonly error: unknown;\n}\n\n/**\n * Owns one body or header content source for one component instance. Provide it in the\n * component's `providers`; it holds a pending task from each load until the processors accept\n * the loaded HTML.\n */\n@Injectable()\nexport class NgDocContentController {\n /** The loaded HTML. */\n readonly html: WritableSignal<string> = signal('');\n /** Increments whenever the HTML must be processed again. */\n readonly version: WritableSignal<number> = signal(0);\n /** The load or processing error of the current source. */\n readonly error: WritableSignal<Error | undefined> = signal(undefined);\n /**\n * Whether the latest load of the current source has been rendered: its version was processed,\n * or the load or its processing failed. False while a load or its processing is pending.\n */\n readonly settled: WritableSignal<boolean> = signal(false);\n /**\n * The version of the latest loaded content of the current source, or undefined before the\n * first load. A processing pass of this version renders loaded content.\n * @internal\n */\n readonly loadedVersion: WritableSignal<number | undefined> = signal(undefined);\n\n private readonly pendingTasks = inject(PendingTasks);\n private readonly contentState = inject(NgDocContentState);\n\n private readonly owner = {};\n private source?: NgDocContentSource;\n private unsubscribe?: () => void;\n private abort?: AbortController;\n private pending?: {\n readonly request: number;\n readonly release: () => void;\n awaitingVersion?: number;\n };\n private request = 0;\n private sourceEpoch = 0;\n private renderState: { version: number; status: 'pending' | 'complete' | 'failed' } = {\n version: 0,\n status: 'pending',\n };\n private destroyed = false;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => this.destroy());\n }\n\n /**\n * Loads the source and reloads it whenever the source reports a change. Connecting the\n * connected source again does nothing.\n * @param source - The content source.\n */\n connect(source: NgDocContentSource): void {\n if (this.destroyed || this.source === source) return;\n\n const previousId = this.source?.id;\n this.cancelCurrent();\n this.unsubscribeCurrent();\n const sourceEpoch = ++this.sourceEpoch;\n this.source = source;\n this.loadedVersion.set(undefined);\n if (previousId !== undefined && previousId !== source.id) {\n this.html.set('');\n this.version.update((version) => version + 1);\n this.renderState = { version: this.version(), status: 'pending' };\n }\n this.contentState.clear(this.owner);\n this.error.set(undefined);\n\n try {\n this.unsubscribe = source.subscribe?.(() => {\n if (this.source !== source || this.sourceEpoch !== sourceEpoch) return;\n // The source has a new revision, so a preloaded payload is stale.\n ɵforgetNgDocContent(source);\n this.reload(false);\n });\n } catch (error) {\n this.fail(source.id, error);\n return;\n }\n this.reload(true);\n }\n\n /** Drops the current source and clears the HTML. */\n disconnect(): void {\n if (this.destroyed || !this.source) return;\n this.cancelCurrent();\n this.sourceEpoch++;\n this.unsubscribeCurrent();\n this.source = undefined;\n this.loadedVersion.set(undefined);\n this.settled.set(false);\n this.contentState.clear(this.owner);\n this.error.set(undefined);\n if (this.html()) {\n this.html.set('');\n this.version.update((version) => version + 1);\n this.renderState = { version: this.version(), status: 'pending' };\n }\n }\n\n /**\n * Accepts a processing pass. Only the pass of the current version counts.\n * @param version - The content version the pass rendered.\n */\n processed(version: number): void {\n if (version !== this.version()) return;\n this.renderState = { version, status: 'complete' };\n if (this.pending?.awaitingVersion === version) this.settle(this.pending.request);\n }\n\n /**\n * Reports a failed processing pass. Only a failure of the current version counts.\n * @param failure - The version and the error.\n */\n processingFailed(failure: NgDocContentRenderFailure): void {\n if (failure.version !== this.version() || !this.source) return;\n this.renderState = { version: failure.version, status: 'failed' };\n if (this.pending?.awaitingVersion !== failure.version) return;\n this.fail(this.source.id, failure.error);\n }\n\n /** Cancels the current load and releases its pending task. Called on destroy. */\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.request++;\n this.sourceEpoch++;\n this.abort?.abort();\n this.abort = undefined;\n try {\n this.unsubscribeCurrent();\n } finally {\n this.finishPending();\n this.contentState.clear(this.owner);\n }\n }\n\n /**\n * Loads the current source.\n * @param preloaded - Whether a payload that was preloaded for the source (by the route resolver\n * or by link preloading) may be used. It is applied at once, so the first render of the\n * component already shows the content instead of an empty page.\n */\n private reload(preloaded: boolean): void {\n const source = this.source;\n if (!source || this.destroyed) return;\n\n this.cancelCurrent();\n this.settled.set(false);\n const request = ++this.request;\n const abort = new AbortController();\n this.abort = abort;\n this.pending = { request, release: once(this.pendingTasks.add()) };\n\n const payload = preloaded ? ɵpeekNgDocContent(source) : undefined;\n\n if (payload) {\n try {\n this.apply(validatePayload(payload, source.id), request);\n } catch (error) {\n this.fail(source.id, error);\n }\n return;\n }\n // A page that opened before its preload finished (the router stopped waiting) waits for the\n // same load instead of starting a second one.\n void this.load(\n source,\n request,\n abort.signal,\n preloaded ? ɵpendingNgDocContent(source) : undefined,\n );\n }\n\n private async load(\n source: NgDocContentSource,\n request: number,\n signal: AbortSignal,\n pending?: Promise<NgDocContentModule>,\n ): Promise<void> {\n try {\n const payload = validatePayload(await (pending ?? source.load(signal)), source.id);\n if (!this.isCurrent(source, request, signal)) return;\n\n this.apply(payload, request);\n } catch (error) {\n if (!this.isCurrent(source, request, signal)) return;\n this.fail(source.id, error);\n }\n }\n\n private apply(payload: NgDocContentModule, request: number): void {\n this.contentState.clear(this.owner);\n this.error.set(undefined);\n if (payload.html === this.html()) {\n if (this.renderState.version !== this.version() || this.renderState.status === 'failed') {\n this.version.update((version) => version + 1);\n this.renderState = { version: this.version(), status: 'pending' };\n this.loadedVersion.set(this.version());\n if (this.pending?.request === request) this.pending.awaitingVersion = this.version();\n } else if (this.renderState.status === 'complete') {\n // The loaded content is already on the page (for example an empty body).\n this.loadedVersion.set(this.version());\n this.settle(request);\n } else {\n this.loadedVersion.set(this.version());\n if (this.pending?.request === request) this.pending.awaitingVersion = this.version();\n }\n return;\n }\n\n this.html.set(payload.html);\n this.version.update((version) => version + 1);\n this.loadedVersion.set(this.version());\n this.renderState = { version: this.version(), status: 'pending' };\n if (this.pending?.request === request) this.pending.awaitingVersion = this.version();\n }\n\n private isCurrent(source: NgDocContentSource, request: number, signal: AbortSignal): boolean {\n return !this.destroyed && !signal.aborted && this.source === source && this.request === request;\n }\n\n private fail(contentId: string, error: unknown): void {\n const normalized = error instanceof Error ? error : new Error(String(error));\n this.contentState.report(this.owner, { contentId, error });\n this.error.set(normalized);\n this.finishPending();\n this.settled.set(true);\n }\n\n private settle(request: number): void {\n if (this.pending?.request !== request) return;\n this.finishPending(request);\n this.settled.set(true);\n }\n\n private cancelCurrent(): void {\n this.request++;\n this.abort?.abort();\n this.abort = undefined;\n this.finishPending();\n }\n\n private finishPending(request?: number): void {\n if (!this.pending || (request !== undefined && this.pending.request !== request)) return;\n this.pending.release();\n this.pending = undefined;\n }\n\n private unsubscribeCurrent(): void {\n const unsubscribe = this.unsubscribe;\n this.unsubscribe = undefined;\n try {\n unsubscribe?.();\n } catch {\n // Cleanup cannot keep an application unstable or revive an obsolete source.\n }\n }\n}\n\n/**\n * Checks that a loaded content module has the expected shape and id.\n * @param payload - The loaded value.\n * @param expectedId - The id of the source that loaded it.\n * @returns The payload, typed.\n */\nexport function validatePayload(payload: unknown, expectedId: string): NgDocContentModule {\n if (\n typeof payload !== 'object' ||\n payload === null ||\n !('schemaVersion' in payload) ||\n payload.schemaVersion !== 1 ||\n !('id' in payload) ||\n payload.id !== expectedId ||\n !('revision' in payload) ||\n typeof payload.revision !== 'string' ||\n !('html' in payload) ||\n typeof payload.html !== 'string'\n ) {\n throw new Error(`Invalid NgDoc content payload for \"${expectedId}\".`);\n }\n return payload as NgDocContentModule;\n}\n\n/**\n * Wraps a callback so that only its first call runs.\n * @param callback - The callback.\n * @returns The wrapped callback.\n */\nfunction once(callback: () => void): () => void {\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n callback();\n };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["ɵforgetNgDocContent","ɵpeekNgDocContent","ɵpendingNgDocContent"],"mappings":"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"}
|
|
@@ -1,66 +1,82 @@
|
|
|
1
1
|
import { NgDocSearchEngine } from '@ng-doc/app/classes/search-engine';
|
|
2
2
|
import { asArray } from '@ng-doc/core/helpers/as-array';
|
|
3
|
-
import { objectKeys } from '@ng-doc/core/helpers/object-keys';
|
|
4
3
|
import { create, insertMultiple } from '@orama/orama';
|
|
5
|
-
import {
|
|
6
|
-
import { from } from 'rxjs';
|
|
7
|
-
import { switchMap,
|
|
4
|
+
import { searchWithHighlight, afterInsert } from '@orama/plugin-match-highlight';
|
|
5
|
+
import { from, defer } from 'rxjs';
|
|
6
|
+
import { switchMap, shareReplay, map } from 'rxjs/operators';
|
|
8
7
|
|
|
8
|
+
/** The properties the engine searches in; the page type only filters the results. */
|
|
9
|
+
const SEARCHED_PROPERTIES = ['title', 'section', 'content'];
|
|
9
10
|
/**
|
|
10
11
|
* Search engine for the documentation, it loads the index and provides a search method.
|
|
12
|
+
*
|
|
13
|
+
* Guides rank above API references: the results list the matching guides first, then the
|
|
14
|
+
* matching API references, each in order of relevance. Guides take up to half of the `limit`
|
|
15
|
+
* (rounded up), or more when fewer API references match; API references fill the rest, and take
|
|
16
|
+
* more than half when fewer guides match.
|
|
11
17
|
*/
|
|
12
18
|
class NgDocDefaultSearchEngine extends NgDocSearchEngine {
|
|
13
19
|
constructor(options) {
|
|
14
20
|
super();
|
|
15
21
|
this.options = options;
|
|
16
|
-
this.db$ =
|
|
17
|
-
schema: {
|
|
18
|
-
title: 'string',
|
|
19
|
-
section: 'string',
|
|
20
|
-
content: 'string',
|
|
21
|
-
},
|
|
22
|
-
plugins: [
|
|
23
|
-
{
|
|
24
|
-
name: 'highlight',
|
|
25
|
-
afterInsert,
|
|
26
|
-
},
|
|
27
|
-
],
|
|
28
|
-
components: {
|
|
29
|
-
tokenizer: {
|
|
30
|
-
stemmer: options?.stemmer,
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
})).pipe(switchMap((db) => this.request(`assets/ng-doc/indexes.json`).pipe(switchMap((pages) => insertMultiple(db, pages)), map(() => db))), shareReplay(1));
|
|
22
|
+
this.db$ = this.request(`assets/ng-doc/indexes.json`).pipe(switchMap((pages) => this.createDatabase(pages)), shareReplay(1));
|
|
34
23
|
}
|
|
35
24
|
/**
|
|
36
25
|
* Search the documentation for the given query.
|
|
37
26
|
* @param query The query to search for.
|
|
38
27
|
*/
|
|
39
28
|
search(query) {
|
|
40
|
-
return this.db$.pipe(switchMap((db) =>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
})), map((result) => result.hits.map((hit) => {
|
|
49
|
-
const keys = objectKeys(hit.positions);
|
|
29
|
+
return this.db$.pipe(switchMap((db) =>
|
|
30
|
+
// Each type of page is searched on its own, so that API references, which usually have
|
|
31
|
+
// many more records, cannot push the guides out of the limit.
|
|
32
|
+
from(Promise.all([
|
|
33
|
+
this.searchPages(db, query, { eq: 'guide' }),
|
|
34
|
+
this.searchPages(db, query, { nin: ['guide'] }),
|
|
35
|
+
]))), map(([guides, others]) => share(guides.hits, others.hits, this.options?.limit ?? 10).map((hit) => {
|
|
36
|
+
const keys = SEARCHED_PROPERTIES.filter((key) => hit.positions[key]);
|
|
50
37
|
return {
|
|
51
38
|
index: hit.document,
|
|
52
39
|
positions: keys.reduce((acc, key) => {
|
|
53
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
54
|
-
// @ts-ignore
|
|
55
40
|
acc[key] = [...asArray(acc[key]), ...Object.values(hit.positions[key]).flat()];
|
|
56
41
|
return acc;
|
|
57
42
|
}, {}),
|
|
58
43
|
};
|
|
59
44
|
})));
|
|
60
45
|
}
|
|
46
|
+
searchPages(db, query, pageType) {
|
|
47
|
+
return searchWithHighlight(db, {
|
|
48
|
+
term: query,
|
|
49
|
+
boost: { title: 4, section: 2 },
|
|
50
|
+
threshold: 0.3,
|
|
51
|
+
properties: [...SEARCHED_PROPERTIES],
|
|
52
|
+
where: { pageType },
|
|
53
|
+
tolerance: this.options?.tolerance,
|
|
54
|
+
exact: this.options?.exact,
|
|
55
|
+
// Each type may need the whole limit when the other one has few matches.
|
|
56
|
+
limit: this.options?.limit ?? 10,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
61
59
|
request(url) {
|
|
62
|
-
return
|
|
60
|
+
return defer(() => fetch(url)).pipe(switchMap((response) => response.json()));
|
|
63
61
|
}
|
|
62
|
+
createDatabase(pages) {
|
|
63
|
+
return from(create({
|
|
64
|
+
schema: { title: 'string', section: 'string', content: 'string', pageType: 'enum' },
|
|
65
|
+
plugins: [{ name: 'highlight', afterInsert }],
|
|
66
|
+
components: { tokenizer: { stemmer: this.options?.stemmer } },
|
|
67
|
+
})).pipe(switchMap((db) => from(insertMultiple(db, pages)).pipe(map(() => db))));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Shares the limit between the guide and the API hits: guides first, with up to half of the
|
|
72
|
+
* limit (rounded up) or whatever the API hits leave, then the API hits.
|
|
73
|
+
* @param guides - The guide hits, in order of relevance.
|
|
74
|
+
* @param others - The API hits, in order of relevance.
|
|
75
|
+
* @param limit - The total number of results.
|
|
76
|
+
*/
|
|
77
|
+
function share(guides, others, limit) {
|
|
78
|
+
const guideCount = Math.min(guides.length, Math.max(Math.ceil(limit / 2), limit - others.length));
|
|
79
|
+
return [...guides.slice(0, guideCount), ...others.slice(0, limit - guideCount)];
|
|
64
80
|
}
|
|
65
81
|
|
|
66
82
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-doc-app-classes-default-search-engine.mjs","sources":["../../../../libs/app/classes/default-search-engine/default-search-engine.ts","../../../../libs/app/classes/default-search-engine/ng-doc-app-classes-default-search-engine.ts"],"sourcesContent":["import { NgDocSearchEngine } from '@ng-doc/app/classes/search-engine';\nimport { NgDocSearchResult } from '@ng-doc/app/interfaces';\nimport { asArray } from '@ng-doc/core/helpers/as-array';\nimport {
|
|
1
|
+
{"version":3,"file":"ng-doc-app-classes-default-search-engine.mjs","sources":["../../../../libs/app/classes/default-search-engine/default-search-engine.ts","../../../../libs/app/classes/default-search-engine/ng-doc-app-classes-default-search-engine.ts"],"sourcesContent":["import { NgDocSearchEngine } from '@ng-doc/app/classes/search-engine';\nimport { NgDocSearchResult } from '@ng-doc/app/interfaces';\nimport { asArray } from '@ng-doc/core/helpers/as-array';\nimport { NgDocPageIndex } from '@ng-doc/core/interfaces';\nimport { NgDocHighlightPosition } from '@ng-doc/ui-kit';\nimport { create, insertMultiple, Orama } from '@orama/orama';\nimport {\n afterInsert,\n OramaWithHighlight,\n searchWithHighlight,\n} from '@orama/plugin-match-highlight';\nimport { stemmer } from '@orama/stemmers/english';\nimport { defer, from, Observable } from 'rxjs';\nimport { map, shareReplay, switchMap } from 'rxjs/operators';\n\ntype OramaDb = OramaWithHighlight<\n Orama<{\n title: 'string';\n section: 'string';\n content: 'string';\n pageType: 'enum';\n }>\n>;\n\n/** The properties the engine searches in; the page type only filters the results. */\nconst SEARCHED_PROPERTIES = ['title', 'section', 'content'] as const;\n\n/**\n * Options for the `NgDocDefaultSearchEngine`.\n */\nexport interface NgDocDefaultSearchEngineOptions {\n /**\n * The language to use for the search engine. See https://www.npmjs.com/package/@orama/stemmers for available languages\n */\n stemmer?: typeof stemmer;\n /**\n * Specifies the maximum distance (following the Levenshtein algorithm) between the term and the searchable property.\n * (doesn't work with `exact` option)\n */\n tolerance?: number;\n /**\n * If `true`, finds all the document with an exact match of the term property.\n */\n exact?: boolean;\n /**\n * Number of results to return (default: 10). Guides get up to half of them, and more when\n * fewer API references match; API references fill the rest.\n */\n limit?: number;\n}\n\n/**\n * Search engine for the documentation, it loads the index and provides a search method.\n *\n * Guides rank above API references: the results list the matching guides first, then the\n * matching API references, each in order of relevance. Guides take up to half of the `limit`\n * (rounded up), or more when fewer API references match; API references fill the rest, and take\n * more than half when fewer guides match.\n */\nexport class NgDocDefaultSearchEngine extends NgDocSearchEngine {\n private db$: Observable<OramaDb>;\n\n constructor(private options?: NgDocDefaultSearchEngineOptions) {\n super();\n\n this.db$ = this.request<NgDocPageIndex[]>(`assets/ng-doc/indexes.json`).pipe(\n switchMap((pages) => this.createDatabase(pages)),\n shareReplay(1),\n ) as Observable<OramaDb>;\n }\n\n /**\n * Search the documentation for the given query.\n * @param query The query to search for.\n */\n search(query: string): Observable<NgDocSearchResult[]> {\n return this.db$.pipe(\n switchMap((db) =>\n // Each type of page is searched on its own, so that API references, which usually have\n // many more records, cannot push the guides out of the limit.\n from(\n Promise.all([\n this.searchPages(db, query, { eq: 'guide' }),\n this.searchPages(db, query, { nin: ['guide'] }),\n ]),\n ),\n ),\n map(([guides, others]) =>\n share(guides.hits, others.hits, this.options?.limit ?? 10).map((hit) => {\n const keys = SEARCHED_PROPERTIES.filter((key) => hit.positions[key]);\n\n return {\n index: hit.document as unknown as NgDocPageIndex,\n positions: keys.reduce(\n (acc: Partial<Record<keyof NgDocPageIndex, NgDocHighlightPosition[]>>, key) => {\n acc[key] = [...asArray(acc[key]), ...Object.values(hit.positions[key]).flat()];\n\n return acc;\n },\n {},\n ),\n };\n }),\n ),\n );\n }\n\n private searchPages(\n db: OramaDb,\n query: string,\n pageType: { eq: string } | { nin: string[] },\n ): ReturnType<typeof searchWithHighlight> {\n return searchWithHighlight(db, {\n term: query,\n boost: { title: 4, section: 2 },\n threshold: 0.3,\n properties: [...SEARCHED_PROPERTIES],\n where: { pageType },\n tolerance: this.options?.tolerance,\n exact: this.options?.exact,\n // Each type may need the whole limit when the other one has few matches.\n limit: this.options?.limit ?? 10,\n });\n }\n\n private request<T>(url: string): Observable<T> {\n return defer(() => fetch(url)).pipe(\n switchMap((response: Response) => response.json() as Promise<T>),\n );\n }\n\n private createDatabase(pages: NgDocPageIndex[]): Observable<OramaDb> {\n return from(\n create({\n schema: { title: 'string', section: 'string', content: 'string', pageType: 'enum' },\n plugins: [{ name: 'highlight', afterInsert }],\n components: { tokenizer: { stemmer: this.options?.stemmer } },\n }),\n ).pipe(\n switchMap((db) =>\n from(insertMultiple(db, pages as any)).pipe(map(() => db as unknown as OramaDb)),\n ),\n );\n }\n}\n\n/**\n * Shares the limit between the guide and the API hits: guides first, with up to half of the\n * limit (rounded up) or whatever the API hits leave, then the API hits.\n * @param guides - The guide hits, in order of relevance.\n * @param others - The API hits, in order of relevance.\n * @param limit - The total number of results.\n */\nfunction share<T>(guides: T[], others: T[], limit: number): T[] {\n const guideCount = Math.min(guides.length, Math.max(Math.ceil(limit / 2), limit - others.length));\n\n return [...guides.slice(0, guideCount), ...others.slice(0, limit - guideCount)];\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-doc-app-classes-root-page.mjs","sources":["../../../../libs/app/classes/root-page/root-page.ts","../../../../libs/app/classes/root-page/ng-doc-app-classes-root-page.ts"],"sourcesContent":["import { NgDocDemoAssets } from '@ng-doc/app/interfaces';\nimport { NgDocPage } from '@ng-doc/core/interfaces';\nimport { NgDocPageType } from '@ng-doc/core/types';\n\n/**\n * Base class for NgDoc page\n */\nexport abstract class NgDocRootPage {\n /**\n * The type of the page\n */\n abstract readonly pageType: NgDocPageType;\n /**\n * Html content of the page\n */\n abstract readonly pageContent: string;\n\n /**\n * Edit URL that can be used to edit the page source file in the repository\n */\n abstract readonly editSourceFileUrl?: string;\n\n /**\n * View URL that can be used to view the page source file in the repository\n */\n abstract readonly viewSourceFileUrl?: string;\n\n /**\n * The page dependencies file\n */\n readonly page?: NgDocPage;\n\n /**\n * The page demo assets that have code examples of the demo components\n */\n readonly demoAssets?: NgDocDemoAssets;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"AAIA;;AAEG;MACmB,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"ng-doc-app-classes-root-page.mjs","sources":["../../../../libs/app/classes/root-page/root-page.ts","../../../../libs/app/classes/root-page/ng-doc-app-classes-root-page.ts"],"sourcesContent":["import { NgDocDemoAssets } from '@ng-doc/app/interfaces';\nimport type { NgDocContentSource, NgDocPage } from '@ng-doc/core/interfaces';\nimport { NgDocPageType } from '@ng-doc/core/types';\n\n/**\n * Base class for NgDoc page\n */\nexport abstract class NgDocRootPage {\n /**\n * The type of the page\n */\n abstract readonly pageType: NgDocPageType;\n /**\n * Html content of the page\n */\n abstract readonly pageContent: string;\n\n /**\n * Deferred content for generated pages. Legacy pages can continue to provide\n * {@link pageContent} only.\n */\n readonly pageContentSource?: NgDocContentSource;\n\n /**\n * Edit URL that can be used to edit the page source file in the repository\n */\n abstract readonly editSourceFileUrl?: string;\n\n /**\n * View URL that can be used to view the page source file in the repository\n */\n abstract readonly viewSourceFileUrl?: string;\n\n /**\n * The page dependencies file\n */\n readonly page?: NgDocPage;\n\n /**\n * The page demo assets that have code examples of the demo components\n */\n readonly demoAssets?: NgDocDemoAssets;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"AAIA;;AAEG;MACmB,aAAa,CAAA;AAmClC;;AC1CD;;AAEG;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-doc-app-classes-search-engine.mjs","sources":["../../../../libs/app/classes/search-engine/search-engine.ts","../../../../libs/app/classes/search-engine/ng-doc-app-classes-search-engine.ts"],"sourcesContent":["import { NgDocSearchResult } from '@ng-doc/app/interfaces';\nimport { Observable } from 'rxjs';\n\n/**\n * Abstract search engine class, that can be used to implement a custom search engine.\n */\nexport abstract class NgDocSearchEngine {\n abstract search(query: string): Observable<NgDocSearchResult[]>;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"AAGA;;AAEG;MACmB,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"ng-doc-app-classes-search-engine.mjs","sources":["../../../../libs/app/classes/search-engine/search-engine.ts","../../../../libs/app/classes/search-engine/ng-doc-app-classes-search-engine.ts"],"sourcesContent":["import { NgDocSearchResult } from '@ng-doc/app/interfaces';\nimport { Observable } from 'rxjs';\n\n/**\n * Abstract search engine class, that can be used to implement a custom search engine.\n */\nexport abstract class NgDocSearchEngine {\n /**\n * Searches the documentation.\n * @param query - The text the user typed.\n * @returns The results for the query.\n */\n abstract search(query: string): Observable<NgDocSearchResult[]>;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"AAGA;;AAEG;MACmB,iBAAiB,CAAA;AAOtC;;ACbD;;AAEG;;;;"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export * from '@ng-doc/app/classes/content-anchor-controller';
|
|
2
|
+
export * from '@ng-doc/app/classes/content-controller';
|
|
1
3
|
export * from '@ng-doc/app/classes/default-search-engine';
|
|
2
4
|
export * from '@ng-doc/app/classes/root-page';
|
|
3
5
|
export * from '@ng-doc/app/classes/search-engine';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-doc-app-classes.mjs","sources":["../../../../libs/app/classes/ng-doc-app-classes.ts"],"sourcesContent":["/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ng-doc-app-classes.mjs","sources":["../../../../libs/app/classes/ng-doc-app-classes.ts"],"sourcesContent":["/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;AAAA;;AAEG"}
|