@analogjs/content 3.0.0-alpha.5 → 3.0.0-alpha.51

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.
Files changed (63) hide show
  1. package/devtools/package.json +4 -0
  2. package/fesm2022/analogjs-content-devtools.mjs +162 -0
  3. package/fesm2022/analogjs-content-devtools.mjs.map +1 -0
  4. package/fesm2022/analogjs-content-md4x.mjs +291 -0
  5. package/fesm2022/analogjs-content-md4x.mjs.map +1 -0
  6. package/fesm2022/analogjs-content-mdc.mjs +170 -0
  7. package/fesm2022/analogjs-content-mdc.mjs.map +1 -0
  8. package/fesm2022/analogjs-content-og.mjs.map +1 -0
  9. package/fesm2022/analogjs-content-prism-highlighter.mjs +5 -4
  10. package/fesm2022/analogjs-content-prism-highlighter.mjs.map +1 -0
  11. package/fesm2022/analogjs-content-resources.mjs +39 -25
  12. package/fesm2022/analogjs-content-resources.mjs.map +1 -0
  13. package/fesm2022/analogjs-content-shiki-highlighter.mjs +1 -1
  14. package/fesm2022/analogjs-content-shiki-highlighter.mjs.map +1 -0
  15. package/fesm2022/analogjs-content.mjs +42 -354
  16. package/fesm2022/analogjs-content.mjs.map +1 -0
  17. package/fesm2022/content-list-loader.mjs +260 -0
  18. package/fesm2022/content-list-loader.mjs.map +1 -0
  19. package/fesm2022/content-renderer.mjs +128 -0
  20. package/fesm2022/content-renderer.mjs.map +1 -0
  21. package/fesm2022/marked-content-highlighter.mjs +40 -0
  22. package/fesm2022/marked-content-highlighter.mjs.map +1 -0
  23. package/fesm2022/parse-raw-content-file.mjs +45 -0
  24. package/fesm2022/parse-raw-content-file.mjs.map +1 -0
  25. package/md4x/package.json +4 -0
  26. package/mdc/package.json +4 -0
  27. package/package.json +71 -36
  28. package/plugin/migrations.json +1 -1
  29. package/plugin/package.json +2 -21
  30. package/plugin/src/index.d.ts +3 -1
  31. package/plugin/src/index.d.ts.map +1 -0
  32. package/plugin/src/index.js +5 -4
  33. package/plugin/src/index.js.map +1 -0
  34. package/plugin/src/migrations/update-markdown-version/compat.d.ts +5 -2
  35. package/plugin/src/migrations/update-markdown-version/compat.d.ts.map +1 -0
  36. package/plugin/src/migrations/update-markdown-version/compat.js +8 -7
  37. package/plugin/src/migrations/update-markdown-version/compat.js.map +1 -0
  38. package/plugin/src/migrations/update-markdown-version/update-markdown-version.d.ts +6 -2
  39. package/plugin/src/migrations/update-markdown-version/update-markdown-version.d.ts.map +1 -0
  40. package/plugin/src/migrations/update-markdown-version/update-markdown-version.js +18 -20
  41. package/plugin/src/migrations/update-markdown-version/update-markdown-version.js.map +1 -0
  42. package/src/lib/devtools/content-devtools-client.ts +215 -0
  43. package/src/lib/devtools/content-devtools.styles.css +194 -0
  44. package/types/devtools/src/index.d.ts +1 -0
  45. package/types/md4x/src/index.d.ts +5 -0
  46. package/types/md4x/src/lib/md4x-content-renderer.service.d.ts +33 -0
  47. package/types/md4x/src/lib/md4x-wasm-content-renderer.service.d.ts +16 -0
  48. package/types/md4x/src/lib/provide-md4x.d.ts +26 -0
  49. package/types/md4x/src/lib/streaming-markdown-renderer.d.ts +21 -0
  50. package/types/mdc/src/index.d.ts +2 -0
  51. package/types/mdc/src/lib/mdc-component-registry.d.ts +25 -0
  52. package/types/mdc/src/lib/mdc-renderer.directive.d.ts +33 -0
  53. package/types/prism-highlighter/src/lib/prism-highlighter.d.ts +1 -1
  54. package/types/resources/src/content-file-resource.d.ts +32 -7
  55. package/types/resources/src/content-files-resource.d.ts +2 -1
  56. package/types/src/index.d.ts +6 -3
  57. package/types/src/lib/content-locale.d.ts +68 -0
  58. package/types/src/lib/devtools/content-devtools-plugin.d.ts +23 -0
  59. package/types/src/lib/devtools/content-devtools-renderer.d.ts +23 -0
  60. package/types/src/lib/devtools/index.d.ts +23 -0
  61. package/types/src/lib/get-content-files.d.ts +19 -4
  62. package/types/src/lib/parse-raw-content-file.d.ts +15 -1
  63. package/plugin/README.md +0 -11
@@ -0,0 +1,194 @@
1
+ #analog-content-devtools {
2
+ position: fixed;
3
+ bottom: 0;
4
+ right: 0;
5
+ z-index: 99999;
6
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
7
+ font-size: 12px;
8
+ color: #e4e4e7;
9
+ pointer-events: none;
10
+ }
11
+
12
+ #analog-content-devtools * {
13
+ box-sizing: border-box;
14
+ }
15
+
16
+ #analog-content-devtools .acd-toggle {
17
+ position: fixed;
18
+ bottom: 12px;
19
+ right: 12px;
20
+ width: 36px;
21
+ height: 36px;
22
+ border-radius: 8px;
23
+ background: #18181b;
24
+ border: 1px solid #3f3f46;
25
+ cursor: pointer;
26
+ display: flex;
27
+ align-items: center;
28
+ justify-content: center;
29
+ pointer-events: auto;
30
+ opacity: 0.7;
31
+ transition: opacity 0.15s;
32
+ }
33
+
34
+ #analog-content-devtools .acd-toggle:hover {
35
+ opacity: 1;
36
+ }
37
+
38
+ #analog-content-devtools .acd-toggle svg {
39
+ width: 20px;
40
+ height: 20px;
41
+ fill: #a1a1aa;
42
+ }
43
+
44
+ #analog-content-devtools .acd-panel {
45
+ position: fixed;
46
+ bottom: 56px;
47
+ right: 12px;
48
+ width: 420px;
49
+ max-height: 70vh;
50
+ background: #18181b;
51
+ border: 1px solid #3f3f46;
52
+ border-radius: 10px;
53
+ overflow: hidden;
54
+ display: flex;
55
+ flex-direction: column;
56
+ pointer-events: auto;
57
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
58
+ }
59
+
60
+ #analog-content-devtools .acd-header {
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: space-between;
64
+ padding: 8px 12px;
65
+ background: #27272a;
66
+ border-bottom: 1px solid #3f3f46;
67
+ font-weight: 600;
68
+ font-size: 11px;
69
+ text-transform: uppercase;
70
+ letter-spacing: 0.05em;
71
+ color: #a1a1aa;
72
+ }
73
+
74
+ #analog-content-devtools .acd-tabs {
75
+ display: flex;
76
+ gap: 2px;
77
+ padding: 4px 8px;
78
+ background: #27272a;
79
+ border-bottom: 1px solid #3f3f46;
80
+ }
81
+
82
+ #analog-content-devtools .acd-tab {
83
+ padding: 4px 10px;
84
+ border-radius: 4px;
85
+ background: transparent;
86
+ border: none;
87
+ color: #71717a;
88
+ cursor: pointer;
89
+ font-size: 11px;
90
+ font-family: inherit;
91
+ }
92
+
93
+ #analog-content-devtools .acd-tab:hover {
94
+ color: #a1a1aa;
95
+ }
96
+
97
+ #analog-content-devtools .acd-tab[data-active='true'] {
98
+ background: #3f3f46;
99
+ color: #e4e4e7;
100
+ }
101
+
102
+ #analog-content-devtools .acd-body {
103
+ overflow-y: auto;
104
+ padding: 12px;
105
+ flex: 1;
106
+ }
107
+
108
+ #analog-content-devtools .acd-section {
109
+ margin-bottom: 12px;
110
+ }
111
+
112
+ #analog-content-devtools .acd-section-title {
113
+ font-size: 10px;
114
+ font-weight: 600;
115
+ text-transform: uppercase;
116
+ letter-spacing: 0.05em;
117
+ color: #71717a;
118
+ margin-bottom: 6px;
119
+ }
120
+
121
+ #analog-content-devtools .acd-kv {
122
+ display: flex;
123
+ justify-content: space-between;
124
+ padding: 2px 0;
125
+ border-bottom: 1px solid #27272a;
126
+ }
127
+
128
+ #analog-content-devtools .acd-key {
129
+ color: #a1a1aa;
130
+ }
131
+
132
+ #analog-content-devtools .acd-value {
133
+ color: #22d3ee;
134
+ }
135
+
136
+ #analog-content-devtools .acd-value.acd-fast {
137
+ color: #4ade80;
138
+ }
139
+
140
+ #analog-content-devtools .acd-value.acd-slow {
141
+ color: #fb923c;
142
+ }
143
+
144
+ #analog-content-devtools .acd-toc-item {
145
+ padding: 2px 0;
146
+ cursor: pointer;
147
+ color: #a1a1aa;
148
+ }
149
+
150
+ #analog-content-devtools .acd-toc-item:hover {
151
+ color: #e4e4e7;
152
+ }
153
+
154
+ #analog-content-devtools .acd-toc-item a {
155
+ color: inherit;
156
+ text-decoration: none;
157
+ }
158
+
159
+ #analog-content-devtools .acd-pre {
160
+ background: #09090b;
161
+ border: 1px solid #27272a;
162
+ border-radius: 6px;
163
+ padding: 8px;
164
+ overflow-x: auto;
165
+ white-space: pre-wrap;
166
+ overflow-wrap: anywhere;
167
+ font-size: 11px;
168
+ line-height: 1.5;
169
+ max-height: 300px;
170
+ overflow-y: auto;
171
+ }
172
+
173
+ #analog-content-devtools .acd-empty {
174
+ color: #52525b;
175
+ font-style: italic;
176
+ }
177
+
178
+ #analog-content-devtools .acd-badge {
179
+ display: inline-block;
180
+ padding: 1px 6px;
181
+ border-radius: 4px;
182
+ font-size: 10px;
183
+ font-weight: 600;
184
+ }
185
+
186
+ #analog-content-devtools .acd-badge-experimental {
187
+ background: #422006;
188
+ color: #fb923c;
189
+ }
190
+
191
+ #analog-content-devtools .acd-badge-renderer {
192
+ background: #042f2e;
193
+ color: #2dd4bf;
194
+ }
@@ -0,0 +1 @@
1
+ export { contentDevToolsPlugin, DevToolsContentRenderer, withContentDevTools, } from '../../src/lib/devtools/index';
@@ -0,0 +1,5 @@
1
+ export { withMd4xRenderer, withMd4xWasmRenderer } from './lib/provide-md4x';
2
+ export { Md4xContentRendererService, MD4X_RENDERER_OPTIONS, } from './lib/md4x-content-renderer.service';
3
+ export type { Md4xRendererOptions } from './lib/md4x-content-renderer.service';
4
+ export { Md4xWasmContentRendererService } from './lib/md4x-wasm-content-renderer.service';
5
+ export { streamMarkdown } from './lib/streaming-markdown-renderer';
@@ -0,0 +1,33 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ import { ContentRenderer, RenderedContent, TableOfContentItem } from '../../../src/lib/content-renderer';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Options for the experimental md4x-based content renderer.
6
+ *
7
+ * @experimental md4x integration is experimental and may change in future releases.
8
+ */
9
+ export interface Md4xRendererOptions {
10
+ /** Heal incomplete markdown (useful for streaming/LLM content). */
11
+ heal?: boolean;
12
+ /** Custom code block highlighter. Receives raw code and block metadata,
13
+ * returns highlighted HTML or undefined to keep default rendering. */
14
+ highlighter?: (code: string, block: {
15
+ lang: string;
16
+ filename?: string;
17
+ highlights?: number[];
18
+ }) => string | undefined;
19
+ }
20
+ export declare const MD4X_RENDERER_OPTIONS: InjectionToken<Md4xRendererOptions>;
21
+ /**
22
+ * Content renderer backed by md4x (C-based CommonMark parser compiled with Zig).
23
+ * 50-70x faster than marked for complex documents.
24
+ *
25
+ * @experimental md4x integration is experimental and may change in future releases.
26
+ */
27
+ export declare class Md4xContentRendererService extends ContentRenderer {
28
+ private options;
29
+ render(content: string): Promise<RenderedContent>;
30
+ getContentHeadings(content: string): TableOfContentItem[];
31
+ static ɵfac: i0.ɵɵFactoryDeclaration<Md4xContentRendererService, never>;
32
+ static ɵprov: i0.ɵɵInjectableDeclaration<Md4xContentRendererService>;
33
+ }
@@ -0,0 +1,16 @@
1
+ import { ContentRenderer, RenderedContent, TableOfContentItem } from '../../../src/lib/content-renderer';
2
+ import * as i0 from "@angular/core";
3
+ /**
4
+ * Content renderer backed by md4x/wasm for client-side (browser) rendering.
5
+ * ~100KB gzip, 3-6x faster than marked in the browser.
6
+ *
7
+ * @experimental md4x integration is experimental and may change in future releases.
8
+ */
9
+ export declare class Md4xWasmContentRendererService extends ContentRenderer {
10
+ private options;
11
+ private initPromise;
12
+ render(content: string): Promise<RenderedContent>;
13
+ getContentHeadings(content: string): TableOfContentItem[];
14
+ static ɵfac: i0.ɵɵFactoryDeclaration<Md4xWasmContentRendererService, never>;
15
+ static ɵprov: i0.ɵɵInjectableDeclaration<Md4xWasmContentRendererService>;
16
+ }
@@ -0,0 +1,26 @@
1
+ import { Provider } from '@angular/core';
2
+ import type { Md4xRendererOptions } from './md4x-content-renderer.service';
3
+ /**
4
+ * Provides the experimental md4x-based content renderer (NAPI, server/build-time).
5
+ *
6
+ * @experimental md4x integration is experimental and may change in future releases.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * provideContent(withMd4xRenderer());
11
+ * provideContent(withMd4xRenderer({ heal: true }));
12
+ * ```
13
+ */
14
+ export declare function withMd4xRenderer(options?: Md4xRendererOptions): Provider;
15
+ /**
16
+ * Provides the experimental md4x WASM content renderer (browser/CSR).
17
+ * ~100KB gzip, 3-6x faster than marked in the browser.
18
+ *
19
+ * @experimental md4x integration is experimental and may change in future releases.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * provideContent(withMd4xWasmRenderer());
24
+ * ```
25
+ */
26
+ export declare function withMd4xWasmRenderer(options?: Md4xRendererOptions): Provider;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Transforms a stream of markdown chunks into a stream of rendered HTML.
3
+ * Uses md4x's `heal()` to fix incomplete markdown from streaming sources
4
+ * (LLMs, collaborative editing) so each emitted HTML chunk is valid.
5
+ *
6
+ * @experimental Streaming markdown support is experimental and may change in future releases.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * // In a Nitro API route
11
+ * import { streamMarkdown } from '@analogjs/content';
12
+ *
13
+ * export default defineEventHandler(async (event) => {
14
+ * const llmStream = getAIStream(prompt);
15
+ * return streamMarkdown(llmStream, { heal: true });
16
+ * });
17
+ * ```
18
+ */
19
+ export declare function streamMarkdown(input: ReadableStream<string>, options?: {
20
+ heal?: boolean;
21
+ }): Promise<ReadableStream<string>>;
@@ -0,0 +1,2 @@
1
+ export { MdcRendererDirective } from './lib/mdc-renderer.directive';
2
+ export { MDC_COMPONENTS, withMdcComponents, } from './lib/mdc-component-registry';
@@ -0,0 +1,25 @@
1
+ import { InjectionToken, Type, Provider } from '@angular/core';
2
+ /**
3
+ * Registry mapping MDC component names to lazy-loaded Angular components.
4
+ *
5
+ * @experimental MDC component support is experimental and may change in future releases.
6
+ */
7
+ export declare const MDC_COMPONENTS: InjectionToken<Map<string, () => Promise<Type<unknown>>>>;
8
+ /**
9
+ * Provides a registry of Angular components that can be used in MDC
10
+ * (Markdown Components) syntax within markdown content.
11
+ *
12
+ * @experimental MDC component support is experimental and may change in future releases.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * provideContent(
17
+ * withMd4xRenderer(),
18
+ * withMdcComponents({
19
+ * alert: () => import('./components/alert.component').then(m => m.AlertComponent),
20
+ * card: () => import('./components/card.component').then(m => m.CardComponent),
21
+ * }),
22
+ * );
23
+ * ```
24
+ */
25
+ export declare function withMdcComponents(components: Record<string, () => Promise<Type<unknown>>>): Provider;
@@ -0,0 +1,33 @@
1
+ import { InputSignal } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ type ComarkNode = string | [string | null, Record<string, unknown>, ...ComarkNode[]];
4
+ /**
5
+ * Directive that renders MDC (Markdown Components) AST nodes as Angular components.
6
+ *
7
+ * Walks the ComarkTree AST from md4x's `parseAST()`, matches component nodes
8
+ * to the registered MDC_COMPONENTS map, and instantiates them via
9
+ * `ViewContainerRef.createComponent()` with MDC attributes bound as inputs.
10
+ *
11
+ * @experimental MDC component support is experimental and may change in future releases.
12
+ *
13
+ * @example
14
+ * ```html
15
+ * <div [mdcAst]="parsedAst"></div>
16
+ * ```
17
+ */
18
+ export declare class MdcRendererDirective {
19
+ readonly ast: InputSignal<{
20
+ nodes: ComarkNode[];
21
+ } | null>;
22
+ private readonly viewContainer;
23
+ private readonly renderer;
24
+ private readonly el;
25
+ private readonly components;
26
+ private renderId;
27
+ constructor();
28
+ private renderNodes;
29
+ private renderNode;
30
+ static ɵfac: i0.ɵɵFactoryDeclaration<MdcRendererDirective, never>;
31
+ static ɵdir: i0.ɵɵDirectiveDeclaration<MdcRendererDirective, "[mdcAst]", never, { "ast": { "alias": "mdcAst"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
32
+ }
33
+ export {};
@@ -1,4 +1,4 @@
1
- import { MarkedContentHighlighter } from '@analogjs/content';
1
+ import { MarkedContentHighlighter } from '../../../src/lib/marked-content-highlighter';
2
2
  import * as i0 from "@angular/core";
3
3
  export declare class PrismHighlighter extends MarkedContentHighlighter {
4
4
  augmentCodeBlock(code: string, lang: string): string;
@@ -1,14 +1,39 @@
1
- import { ResourceRef, Signal } from '@angular/core';
2
- import { ContentFile } from '@analogjs/content';
1
+ import type { StandardSchemaV1 } from '@standard-schema/spec';
2
+ import { Signal, type ResourceRef } from '@angular/core';
3
+ import type { ContentFile } from '../../src/lib/content-file';
4
+ export interface ContentFileResourceResult<Attributes extends Record<string, any> = Record<string, any>> extends ContentFile<Attributes | Record<string, never>> {
5
+ toc: Array<{
6
+ id: string;
7
+ level: number;
8
+ text: string;
9
+ }>;
10
+ }
3
11
  type ContentFileParams = Signal<string | {
4
12
  customFilename: string;
13
+ }> | Signal<string> | Signal<{
14
+ customFilename: string;
5
15
  }>;
6
16
  /**
7
- * Resource for requesting an individual content file
17
+ * Resource for requesting an individual content file.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * // Without schema (existing behavior)
22
+ * const post = contentFileResource<BlogAttributes>();
8
23
  *
9
- * @param params
10
- * @param fallback
11
- * @returns
24
+ * // With schema validation
25
+ * import * as v from 'valibot';
26
+ * const BlogSchema = v.object({
27
+ * title: v.string(),
28
+ * date: v.pipe(v.string(), v.isoDate()),
29
+ * });
30
+ * const post = contentFileResource({ schema: BlogSchema });
31
+ * ```
12
32
  */
13
- export declare function contentFileResource<Attributes extends Record<string, any> = Record<string, any>>(params?: ContentFileParams, fallback?: string): ResourceRef<ContentFile<Attributes | Record<string, never>> | undefined>;
33
+ export declare function contentFileResource<Attributes extends Record<string, any> = Record<string, any>>(params?: ContentFileParams, fallback?: string): ResourceRef<ContentFileResourceResult<Attributes> | undefined>;
34
+ export declare function contentFileResource<TSchema extends StandardSchemaV1>(options: {
35
+ params?: ContentFileParams;
36
+ fallback?: string;
37
+ schema: TSchema;
38
+ }): ResourceRef<ContentFileResourceResult<StandardSchemaV1.InferOutput<TSchema> & Record<string, any>> | undefined>;
14
39
  export {};
@@ -1,3 +1,4 @@
1
1
  import { ResourceRef } from '@angular/core';
2
- import { ContentFile, InjectContentFilesFilterFunction } from '@analogjs/content';
2
+ import type { ContentFile } from '../../src/lib/content-file';
3
+ import type { InjectContentFilesFilterFunction } from '../../src/lib/inject-content-files';
3
4
  export declare function contentFilesResource<Attributes extends Record<string, any>>(filterFn?: InjectContentFilesFilterFunction<Attributes> | undefined): ResourceRef<ContentFile<Attributes>[] | undefined>;
@@ -1,15 +1,18 @@
1
1
  export { AnchorNavigationDirective } from './lib/anchor-navigation.directive';
2
2
  export { injectContent } from './lib/content';
3
- export { ContentFile } from './lib/content-file';
3
+ export type { ContentFile } from './lib/content-file';
4
4
  export { ContentRenderer, NoopContentRenderer } from './lib/content-renderer';
5
- export { injectContentFiles, InjectContentFilesFilterFunction, } from './lib/inject-content-files';
5
+ export type { RenderedContent, TableOfContentItem, } from './lib/content-renderer';
6
+ export { injectContentFiles } from './lib/inject-content-files';
7
+ export type { InjectContentFilesFilterFunction } from './lib/inject-content-files';
6
8
  export { MarkdownContentRendererService } from './lib/markdown-content-renderer.service';
7
9
  export { provideContent, withMarkdownRenderer, MERMAID_IMPORT_TOKEN, } from './lib/provide-content';
8
10
  export { default as MarkdownRouteComponent } from './lib/markdown-route.component';
9
11
  export { default as MarkdownComponent } from './lib/markdown.component';
10
- export { parseRawContentFile } from './lib/parse-raw-content-file';
12
+ export { parseRawContentFile, parseRawContentFileAsync, FrontmatterValidationError, } from './lib/parse-raw-content-file';
11
13
  export { MarkedSetupService } from './lib/marked-setup.service';
12
14
  export { MarkedContentHighlighter, withHighlighter, } from './lib/marked-content-highlighter';
13
15
  export { injectContentFilesMap } from './lib/inject-content-files';
14
16
  export { injectContentListLoader, withContentListLoader, CONTENT_LIST_LOADER, } from './lib/content-list-loader';
15
17
  export { injectContentFileLoader, withContentFileLoader, CONTENT_FILE_LOADER, } from './lib/content-file-loader';
18
+ export { CONTENT_LOCALE, injectContentLocale, withLocale, filterByLocale, withLocaleCandidates, } from './lib/content-locale';
@@ -0,0 +1,68 @@
1
+ import { InjectionToken, Provider } from '@angular/core';
2
+ import { ContentFile } from './content-file';
3
+ /**
4
+ * Token for the active content locale.
5
+ * Provided via `withLocale()` in `provideContent()`.
6
+ *
7
+ * When set, `injectContentFiles()` filters to content matching this locale,
8
+ * and `injectContent()` resolves locale-prefixed content paths first.
9
+ */
10
+ export declare const CONTENT_LOCALE: InjectionToken<string>;
11
+ /**
12
+ * Injects the content locale, returning null if not configured.
13
+ */
14
+ export declare function injectContentLocale(): string | null;
15
+ export interface ContentLocaleOptions {
16
+ /**
17
+ * Function that returns the active locale.
18
+ * Runs in injection context so `inject()` can be used to read
19
+ * from other tokens (e.g., a LOCALE token from a router package).
20
+ *
21
+ * ```typescript
22
+ * withLocale({ loadLocale: injectLocale })
23
+ * withLocale({ loadLocale: () => navigator.language.split('-')[0] })
24
+ * ```
25
+ */
26
+ loadLocale: () => string | null;
27
+ }
28
+ /**
29
+ * Content feature that sets the active locale for content resolution.
30
+ *
31
+ * When provided, content APIs become locale-aware:
32
+ * - `injectContentFiles()` filters to files in the locale subdirectory
33
+ * or with a matching `locale` frontmatter attribute.
34
+ * - `injectContent()` tries locale-prefixed paths first
35
+ * (e.g., `content/fr/blog/post.md` before `content/blog/post.md`).
36
+ *
37
+ * Usage:
38
+ * ```typescript
39
+ * // With loader — runs in injection context
40
+ * provideContent(
41
+ * withMarkdownRenderer(),
42
+ * withLocale({ loadLocale: injectLocale }),
43
+ * )
44
+ *
45
+ * // Static locale
46
+ * provideContent(
47
+ * withMarkdownRenderer(),
48
+ * withLocale('fr'),
49
+ * )
50
+ * ```
51
+ */
52
+ export declare function withLocale(locale: string | ContentLocaleOptions): Provider;
53
+ /**
54
+ * Filters content files by locale using map-based key lookup.
55
+ *
56
+ * Matching rules:
57
+ * 1. Frontmatter `locale` attribute matches the active locale.
58
+ * 2. File is in the active locale subdirectory (e.g., `/content/fr/blog/post`).
59
+ * 3. File has no locale marker and no localized variant exists — included as universal content.
60
+ *
61
+ * Files in a different locale's subdirectory are always excluded.
62
+ */
63
+ export declare function filterByLocale<T extends Record<string, any>>(files: ContentFile<T>[], locale: string): ContentFile<T>[];
64
+ /**
65
+ * Prepends locale-prefixed candidates before the standard candidates
66
+ * for content file map key lookup.
67
+ */
68
+ export declare function withLocaleCandidates(candidates: string[], locale: string | null | undefined): string[];
@@ -0,0 +1,23 @@
1
+ import type { Plugin } from 'vite';
2
+ /**
3
+ * Vite plugin that injects the Analog Content DevTools panel in dev mode.
4
+ *
5
+ * Shows render time, frontmatter data, TOC, and content stats in a floating
6
+ * panel. Dev-only — completely stripped from production builds.
7
+ *
8
+ * @experimental Content DevTools is experimental and may change in future releases.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * // vite.config.ts
13
+ * import { contentDevToolsPlugin } from '@analogjs/content/devtools';
14
+ *
15
+ * export default defineConfig({
16
+ * plugins: [
17
+ * analog({ ... }),
18
+ * contentDevToolsPlugin(),
19
+ * ],
20
+ * });
21
+ * ```
22
+ */
23
+ export declare function contentDevToolsPlugin(): Plugin;
@@ -0,0 +1,23 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ import { ContentRenderer, RenderedContent, TableOfContentItem } from '../content-renderer';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Token for the wrapped renderer that DevTools delegates to.
6
+ * @internal
7
+ */
8
+ export declare const DEVTOOLS_INNER_RENDERER: InjectionToken<ContentRenderer>;
9
+ /**
10
+ * Wraps an existing ContentRenderer to collect timing and metadata for the
11
+ * Content DevTools panel. Dispatches a custom event on the window after
12
+ * each render so the devtools client can update.
13
+ *
14
+ * @experimental Content DevTools is experimental and may change in future releases.
15
+ */
16
+ export declare class DevToolsContentRenderer extends ContentRenderer {
17
+ private readonly inner;
18
+ render(content: string): Promise<RenderedContent>;
19
+ getContentHeadings(content: string): TableOfContentItem[];
20
+ enhance(): void;
21
+ static ɵfac: i0.ɵɵFactoryDeclaration<DevToolsContentRenderer, never>;
22
+ static ɵprov: i0.ɵɵInjectableDeclaration<DevToolsContentRenderer>;
23
+ }
@@ -0,0 +1,23 @@
1
+ import { Provider, Type } from '@angular/core';
2
+ import { ContentRenderer } from '../content-renderer';
3
+ export { contentDevToolsPlugin } from './content-devtools-plugin';
4
+ export { DevToolsContentRenderer, DEVTOOLS_INNER_RENDERER, } from './content-devtools-renderer';
5
+ /**
6
+ * Wraps the given ContentRenderer with DevTools instrumentation.
7
+ *
8
+ * The supplied renderer class is provided under DEVTOOLS_INNER_RENDERER and
9
+ * DevToolsContentRenderer becomes the new ContentRenderer, delegating
10
+ * all calls and collecting timing data.
11
+ *
12
+ * @param innerRenderer The renderer class to wrap with devtools instrumentation.
13
+ *
14
+ * @experimental Content DevTools is experimental and may change in future releases.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * provideContent(
19
+ * withContentDevTools(NoopContentRenderer),
20
+ * );
21
+ * ```
22
+ */
23
+ export declare function withContentDevTools(innerRenderer: Type<ContentRenderer>): Provider;
@@ -1,14 +1,29 @@
1
+ /**
2
+ * These bindings are rewritten at build time:
3
+ * - `ANALOG_CONTENT_FILE_LIST` by `@analogjs/platform`'s content plugin,
4
+ * which substitutes the empty-object initializer with the frontmatter
5
+ * map for discovered content files.
6
+ * - `ANALOG_CONTENT_ROUTE_FILES` by `@analogjs/platform`'s router plugin,
7
+ * which substitutes the empty-object initializer with the lazy-import
8
+ * map for discovered content files. The router plugin already rewrites
9
+ * a same-named binding exported from `@analogjs/router/content`; it
10
+ * matches this module for free because its filter keys off `_ROUTE_FILES`.
11
+ *
12
+ * They are declared as `export const` at module scope so the bundler treats
13
+ * them as public module bindings and cannot constant-fold them away during
14
+ * library build. Previously these lived as local consts inside each getter,
15
+ * and Rolldown collapsed `const X = {}; return X;` into `return {};`, which
16
+ * erased the rewrite target the platform plugins rely on.
17
+ */
18
+ export declare const ANALOG_CONTENT_FILE_LIST: {};
19
+ export declare const ANALOG_CONTENT_ROUTE_FILES: {};
1
20
  /**
2
21
  * Returns the list of content files by filename with ?analog-content-list=true.
3
22
  * We use the query param to transform the return into an array of
4
23
  * just front matter attributes.
5
- *
6
- * @returns
7
24
  */
8
25
  export declare const getContentFilesList: () => Record<string, Record<string, any>>;
9
26
  /**
10
27
  * Returns the lazy loaded content files for lookups.
11
- *
12
- * @returns
13
28
  */
14
29
  export declare const getContentFiles: () => Record<string, () => Promise<string>>;
@@ -1,4 +1,18 @@
1
- export declare function parseRawContentFile<Attributes extends Record<string, any>>(rawContentFile: string): {
1
+ import type { StandardSchemaV1 } from '@standard-schema/spec';
2
+ export declare class FrontmatterValidationError extends Error {
3
+ readonly issues: ReadonlyArray<StandardSchemaV1.Issue>;
4
+ readonly filename?: string | undefined;
5
+ constructor(issues: ReadonlyArray<StandardSchemaV1.Issue>, filename?: string | undefined);
6
+ }
7
+ export declare function parseRawContentFile<Attributes extends Record<string, any> = Record<string, any>>(rawContentFile: string): {
2
8
  content: string;
3
9
  attributes: Attributes;
4
10
  };
11
+ export declare function parseRawContentFile<TSchema extends StandardSchemaV1>(rawContentFile: string, schema: TSchema, filename?: string): {
12
+ content: string;
13
+ attributes: StandardSchemaV1.InferOutput<TSchema>;
14
+ };
15
+ export declare function parseRawContentFileAsync<TSchema extends StandardSchemaV1>(rawContentFile: string, schema: TSchema, filename?: string): Promise<{
16
+ content: string;
17
+ attributes: StandardSchemaV1.InferOutput<TSchema>;
18
+ }>;
package/plugin/README.md DELETED
@@ -1,11 +0,0 @@
1
- # content-plugin
2
-
3
- This library was generated with [Nx](https://nx.dev).
4
-
5
- ## Building
6
-
7
- Run `nx build content-plugin` to build the library.
8
-
9
- ## Running unit tests
10
-
11
- Run `nx test content-plugin` to execute the unit tests via [Vitest](https://vitest.dev).