@nowline/embed 0.2.5 → 0.4.1
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/dist/auth/allowlist.d.ts +20 -0
- package/dist/auth/allowlist.d.ts.map +1 -0
- package/dist/auth/allowlist.js +33 -0
- package/dist/auth/allowlist.js.map +1 -0
- package/dist/auth/env.d.ts +23 -0
- package/dist/auth/env.d.ts.map +1 -0
- package/dist/auth/env.js +24 -0
- package/dist/auth/env.js.map +1 -0
- package/dist/auth/firebase-auth.client.d.ts +21 -0
- package/dist/auth/firebase-auth.client.d.ts.map +1 -0
- package/dist/auth/firebase-auth.client.js +142 -0
- package/dist/auth/firebase-auth.client.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -1
- package/dist/meta.json +578 -411
- package/dist/nowline.esm.js +952 -222
- package/dist/nowline.esm.js.map +4 -4
- package/dist/nowline.min.js +78 -77
- package/dist/nowline.min.js.map +4 -4
- package/dist/pipeline.d.ts +3 -3
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +40 -69
- package/dist/pipeline.js.map +1 -1
- package/package.json +17 -10
- package/src/auth/allowlist.ts +32 -0
- package/src/auth/env.ts +37 -0
- package/src/auth/firebase-auth.client.ts +174 -0
- package/src/index.ts +42 -0
- package/src/pipeline.ts +52 -89
- package/dist/no-op-include-resolver.d.ts +0 -4
- package/dist/no-op-include-resolver.d.ts.map +0 -1
- package/dist/no-op-include-resolver.js +0 -18
- package/dist/no-op-include-resolver.js.map +0 -1
- package/src/no-op-include-resolver.ts +0 -22
package/src/pipeline.ts
CHANGED
|
@@ -1,20 +1,28 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
1
|
+
// Thin shim around `@nowline/browser`'s pipeline. The browser package
|
|
2
|
+
// owns parse / resolveIncludes / layout / render; the embed layers two
|
|
3
|
+
// embed-specific behaviours on top:
|
|
4
|
+
//
|
|
5
|
+
// - Throws `EmbedRenderError` on failure instead of returning a
|
|
6
|
+
// discriminated union. The Mermaid-compatible `nowline.render(source)`
|
|
7
|
+
// surface promises a string; throwing matches the documented v1
|
|
8
|
+
// contract and keeps the auto-scan path's per-block error handling
|
|
9
|
+
// simple.
|
|
10
|
+
// - Latches a once-per-page-load `console.warn` the first time an
|
|
11
|
+
// `include` directive is encountered. The browser pipeline emits a
|
|
12
|
+
// structured callback for each skip; the embed converts that into a
|
|
13
|
+
// single, deduped user-visible message.
|
|
7
14
|
|
|
8
15
|
import {
|
|
9
|
-
|
|
10
|
-
type
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
import {
|
|
17
|
-
|
|
16
|
+
__resetBrowserPipelineForTests,
|
|
17
|
+
type RenderOptions as BrowserRenderOptions,
|
|
18
|
+
parseSource as browserParseSource,
|
|
19
|
+
renderSource as browserRenderSource,
|
|
20
|
+
type DiagnosticRow,
|
|
21
|
+
type ParseResult,
|
|
22
|
+
} from '@nowline/browser';
|
|
23
|
+
import type { ThemeName } from '@nowline/layout';
|
|
24
|
+
|
|
25
|
+
const EMBED_SOURCE_PATH = '/embed.nowline';
|
|
18
26
|
|
|
19
27
|
export interface EmbedRenderOptions {
|
|
20
28
|
theme?: ThemeName;
|
|
@@ -31,96 +39,52 @@ export interface EmbedRenderOptions {
|
|
|
31
39
|
}
|
|
32
40
|
|
|
33
41
|
export interface EmbedParseResult {
|
|
34
|
-
ast:
|
|
42
|
+
ast: ParseResult['ast'];
|
|
35
43
|
/** Lexer + parser + Langium validation diagnostics, normalized to strings. */
|
|
36
44
|
errors: string[];
|
|
37
45
|
}
|
|
38
46
|
|
|
39
|
-
interface CachedServices {
|
|
40
|
-
shared: ReturnType<typeof createNowlineServices>['shared'];
|
|
41
|
-
Nowline: NowlineServices;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
let cachedServices: CachedServices | undefined;
|
|
45
|
-
let docCounter = 0;
|
|
46
47
|
let includeWarningEmitted = false;
|
|
47
48
|
|
|
48
|
-
function getServices(): CachedServices {
|
|
49
|
-
if (!cachedServices) cachedServices = createNowlineServices();
|
|
50
|
-
return cachedServices;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function freshUri(): URI {
|
|
54
|
-
return URI.parse(`memory:///nowline-embed-${++docCounter}.nowline`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
49
|
export async function parseSource(source: string): Promise<EmbedParseResult> {
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if (d.severity === 1) errors.push(d.message);
|
|
68
|
-
}
|
|
69
|
-
return { ast: doc.parseResult.value, errors };
|
|
50
|
+
const { ast, diagnostics } = await browserParseSource(source, {
|
|
51
|
+
filePath: EMBED_SOURCE_PATH,
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
ast,
|
|
55
|
+
errors: diagnostics
|
|
56
|
+
.filter((d: DiagnosticRow) => d.severity === 'error')
|
|
57
|
+
.map((d) => d.message),
|
|
58
|
+
};
|
|
70
59
|
}
|
|
71
60
|
|
|
72
61
|
export async function renderSource(
|
|
73
62
|
source: string,
|
|
74
63
|
options: EmbedRenderOptions = {},
|
|
75
64
|
): Promise<string> {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
throw new EmbedRenderError(
|
|
79
|
-
`Failed to parse Nowline source: ${parsed.errors.join('; ')}`,
|
|
80
|
-
parsed.errors,
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const services = getServices();
|
|
85
|
-
const resolved = await resolveIncludes(parsed.ast, '/embed.nowline', {
|
|
86
|
-
services: services.Nowline,
|
|
87
|
-
readFile: noOpIncludeReadFile,
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
let sawIncludeWarning = false;
|
|
91
|
-
const blockingErrors: string[] = [];
|
|
92
|
-
for (const diag of resolved.diagnostics) {
|
|
93
|
-
if (diag.severity !== 'error') continue;
|
|
94
|
-
if (isNoOpIncludeDiagnosticMessage(diag.message)) {
|
|
95
|
-
sawIncludeWarning = true;
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
blockingErrors.push(diag.message);
|
|
99
|
-
}
|
|
100
|
-
if (blockingErrors.length > 0) {
|
|
101
|
-
throw new EmbedRenderError(
|
|
102
|
-
`Failed to resolve Nowline source: ${blockingErrors.join('; ')}`,
|
|
103
|
-
blockingErrors,
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
if (sawIncludeWarning && !includeWarningEmitted) {
|
|
107
|
-
includeWarningEmitted = true;
|
|
108
|
-
console.warn(
|
|
109
|
-
'nowline: `include` directives are skipped in the browser embed (single-file mode). ' +
|
|
110
|
-
'Render multi-file roadmaps with the CLI or the GitHub Action.',
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const model = layoutRoadmap(parsed.ast, resolved, {
|
|
65
|
+
const browserOptions: BrowserRenderOptions = {
|
|
66
|
+
filePath: EMBED_SOURCE_PATH,
|
|
115
67
|
theme: options.theme,
|
|
116
68
|
today: options.today,
|
|
117
69
|
locale: options.locale,
|
|
118
70
|
width: options.width,
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
return renderSvg(model, {
|
|
122
71
|
idPrefix: options.idPrefix,
|
|
123
|
-
|
|
72
|
+
onSkippedInclude: () => {
|
|
73
|
+
if (!includeWarningEmitted) {
|
|
74
|
+
includeWarningEmitted = true;
|
|
75
|
+
console.warn(
|
|
76
|
+
'nowline: `include` directives are skipped in the browser embed (single-file mode). ' +
|
|
77
|
+
'Render multi-file roadmaps with the CLI or the GitHub Action.',
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const result = await browserRenderSource(source, browserOptions);
|
|
84
|
+
if (result.kind === 'svg') return result.svg;
|
|
85
|
+
|
|
86
|
+
const messages = result.diagnostics.filter((d) => d.severity === 'error').map((d) => d.message);
|
|
87
|
+
throw new EmbedRenderError(`Failed to render Nowline source: ${messages.join('; ')}`, messages);
|
|
124
88
|
}
|
|
125
89
|
|
|
126
90
|
export class EmbedRenderError extends Error {
|
|
@@ -138,6 +102,5 @@ export class EmbedRenderError extends Error {
|
|
|
138
102
|
// reset the latch between cases.
|
|
139
103
|
export function __resetEmbedPipelineForTests(): void {
|
|
140
104
|
includeWarningEmitted = false;
|
|
141
|
-
|
|
142
|
-
docCounter = 0;
|
|
105
|
+
__resetBrowserPipelineForTests();
|
|
143
106
|
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export declare const NOWLINE_EMBED_NOOP_INCLUDE_TAG = "__nowline_embed_noop_include__";
|
|
2
|
-
export declare function noOpIncludeReadFile(absPath: string): Promise<string>;
|
|
3
|
-
export declare function isNoOpIncludeDiagnosticMessage(message: string): boolean;
|
|
4
|
-
//# sourceMappingURL=no-op-include-resolver.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"no-op-include-resolver.d.ts","sourceRoot":"","sources":["../src/no-op-include-resolver.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,8BAA8B,mCAAmC,CAAC;AAE/E,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI1E;AAED,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvE"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// Browser-side `readFile` that always rejects with a stable, sniff-able
|
|
2
|
-
// error. The render pipeline catches matching diagnostics and converts
|
|
3
|
-
// them into a single `console.warn` (deduped), so authors notice when
|
|
4
|
-
// they ship a file with `include` directives that the embed cannot
|
|
5
|
-
// satisfy without a network fetch.
|
|
6
|
-
//
|
|
7
|
-
// A real HTTP-fetch resolver is intentionally out of scope for m4 (see
|
|
8
|
-
// `specs/handoffs/handoff-m4-embed.md`): CORS, relative-URL semantics,
|
|
9
|
-
// and waterfall performance each warrant their own decision and are
|
|
10
|
-
// best handled behind an opt-in flag in a follow-up.
|
|
11
|
-
export const NOWLINE_EMBED_NOOP_INCLUDE_TAG = '__nowline_embed_noop_include__';
|
|
12
|
-
export async function noOpIncludeReadFile(absPath) {
|
|
13
|
-
throw new Error(`${NOWLINE_EMBED_NOOP_INCLUDE_TAG}: include "${absPath}" was skipped — the embed runs in single-file mode.`);
|
|
14
|
-
}
|
|
15
|
-
export function isNoOpIncludeDiagnosticMessage(message) {
|
|
16
|
-
return message.includes(NOWLINE_EMBED_NOOP_INCLUDE_TAG);
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=no-op-include-resolver.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"no-op-include-resolver.js","sourceRoot":"","sources":["../src/no-op-include-resolver.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,uEAAuE;AACvE,sEAAsE;AACtE,mEAAmE;AACnE,mCAAmC;AACnC,EAAE;AACF,uEAAuE;AACvE,uEAAuE;AACvE,oEAAoE;AACpE,qDAAqD;AAErD,MAAM,CAAC,MAAM,8BAA8B,GAAG,gCAAgC,CAAC;AAE/E,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAe;IACrD,MAAM,IAAI,KAAK,CACX,GAAG,8BAA8B,cAAc,OAAO,qDAAqD,CAC9G,CAAC;AACN,CAAC;AAED,MAAM,UAAU,8BAA8B,CAAC,OAAe;IAC1D,OAAO,OAAO,CAAC,QAAQ,CAAC,8BAA8B,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
// Browser-side `readFile` that always rejects with a stable, sniff-able
|
|
2
|
-
// error. The render pipeline catches matching diagnostics and converts
|
|
3
|
-
// them into a single `console.warn` (deduped), so authors notice when
|
|
4
|
-
// they ship a file with `include` directives that the embed cannot
|
|
5
|
-
// satisfy without a network fetch.
|
|
6
|
-
//
|
|
7
|
-
// A real HTTP-fetch resolver is intentionally out of scope for m4 (see
|
|
8
|
-
// `specs/handoffs/handoff-m4-embed.md`): CORS, relative-URL semantics,
|
|
9
|
-
// and waterfall performance each warrant their own decision and are
|
|
10
|
-
// best handled behind an opt-in flag in a follow-up.
|
|
11
|
-
|
|
12
|
-
export const NOWLINE_EMBED_NOOP_INCLUDE_TAG = '__nowline_embed_noop_include__';
|
|
13
|
-
|
|
14
|
-
export async function noOpIncludeReadFile(absPath: string): Promise<string> {
|
|
15
|
-
throw new Error(
|
|
16
|
-
`${NOWLINE_EMBED_NOOP_INCLUDE_TAG}: include "${absPath}" was skipped — the embed runs in single-file mode.`,
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function isNoOpIncludeDiagnosticMessage(message: string): boolean {
|
|
21
|
-
return message.includes(NOWLINE_EMBED_NOOP_INCLUDE_TAG);
|
|
22
|
-
}
|