@nowline/browser 0.8.5 → 0.9.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/dist/diagnostic-row.d.ts +10 -2
- package/dist/diagnostic-row.d.ts.map +1 -1
- package/dist/diagnostic-row.js +35 -7
- package/dist/diagnostic-row.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/pipeline.d.ts +9 -2
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +88 -65
- package/dist/pipeline.js.map +1 -1
- package/package.json +9 -9
- package/src/diagnostic-row.ts +36 -6
- package/src/index.ts +4 -0
- package/src/pipeline.ts +97 -64
package/dist/diagnostic-row.d.ts
CHANGED
|
@@ -27,9 +27,17 @@ export declare function fromLexerError(err: LexerErrorLike, file: string): Diagn
|
|
|
27
27
|
* is 0-based in the resolver (it comes from a CST range) and may be
|
|
28
28
|
* undefined for whole-file diagnostics like circular include — fall
|
|
29
29
|
* back to line 1 so a click-to-jump still puts the cursor near the top
|
|
30
|
-
* of the offending file.
|
|
30
|
+
* of the offending file. A routed diagnostic with a `range` takes its
|
|
31
|
+
* column from it, the validator's column for the same finding; without
|
|
32
|
+
* one the column is 1.
|
|
33
|
+
*
|
|
34
|
+
* A wave-rule diagnostic (specs/waves.md §6.1) keeps its stable code
|
|
35
|
+
* (`NL.Exxxx`), and its message is rendered in `locale` when the caller
|
|
36
|
+
* knows one; WV8, the uncoded wave rule, is labelled like the validator's
|
|
37
|
+
* copy. An included file's syntax error is the row that file's own check
|
|
38
|
+
* gives. Every other resolver diagnostic is an `include` row, verbatim.
|
|
31
39
|
*/
|
|
32
|
-
export declare function fromResolveDiagnostic(diag: ResolveDiagnostic): DiagnosticRow;
|
|
40
|
+
export declare function fromResolveDiagnostic(diag: ResolveDiagnostic, locale?: string): DiagnosticRow;
|
|
33
41
|
/**
|
|
34
42
|
* Adapt a render-time warning message into a diagnostic row. Renderer
|
|
35
43
|
* warnings are bare strings without a source location, so callers
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostic-row.d.ts","sourceRoot":"","sources":["../src/diagnostic-row.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"diagnostic-row.d.ts","sourceRoot":"","sources":["../src/diagnostic-row.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EAEnB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EAEzB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC1B,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAClB;AAQD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CAa9F;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CASjF;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CAS/E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,iBAAiB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,aAAa,CA4B7F;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC7B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,aAAa,CAAC,UAAU,CAAa,GAChD,aAAa,CASf;AAED,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CASrF"}
|
package/dist/diagnostic-row.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { extractSuggestion, resolveDiagnosticCode, } from '@nowline/core';
|
|
1
|
+
import { extractSuggestion, inferCodeFromMessage, isRoutedResolveDiagnostic, localizeResolveDiagnostic, resolveDiagnosticCode, } from '@nowline/core';
|
|
2
2
|
function mapLangiumSeverity(severity) {
|
|
3
3
|
if (severity === 2)
|
|
4
4
|
return 'warning';
|
|
@@ -45,16 +45,44 @@ export function fromLexerError(err, file) {
|
|
|
45
45
|
* is 0-based in the resolver (it comes from a CST range) and may be
|
|
46
46
|
* undefined for whole-file diagnostics like circular include — fall
|
|
47
47
|
* back to line 1 so a click-to-jump still puts the cursor near the top
|
|
48
|
-
* of the offending file.
|
|
48
|
+
* of the offending file. A routed diagnostic with a `range` takes its
|
|
49
|
+
* column from it, the validator's column for the same finding; without
|
|
50
|
+
* one the column is 1.
|
|
51
|
+
*
|
|
52
|
+
* A wave-rule diagnostic (specs/waves.md §6.1) keeps its stable code
|
|
53
|
+
* (`NL.Exxxx`), and its message is rendered in `locale` when the caller
|
|
54
|
+
* knows one; WV8, the uncoded wave rule, is labelled like the validator's
|
|
55
|
+
* copy. An included file's syntax error is the row that file's own check
|
|
56
|
+
* gives. Every other resolver diagnostic is an `include` row, verbatim.
|
|
49
57
|
*/
|
|
50
|
-
export function fromResolveDiagnostic(diag) {
|
|
58
|
+
export function fromResolveDiagnostic(diag, locale) {
|
|
59
|
+
if (diag.syntax?.origin === 'lexer')
|
|
60
|
+
return fromLexerError(diag.syntax.error, diag.sourcePath);
|
|
61
|
+
if (diag.syntax?.origin === 'parser') {
|
|
62
|
+
return fromParserError(diag.syntax.error, diag.sourcePath);
|
|
63
|
+
}
|
|
64
|
+
const line = (diag.range?.start.line ?? diag.line ?? 0) + 1;
|
|
65
|
+
const column = (diag.range?.start.character ?? 0) + 1;
|
|
66
|
+
if (!isRoutedResolveDiagnostic(diag)) {
|
|
67
|
+
return {
|
|
68
|
+
severity: diag.severity,
|
|
69
|
+
code: 'include',
|
|
70
|
+
message: diag.message,
|
|
71
|
+
file: diag.sourcePath,
|
|
72
|
+
line,
|
|
73
|
+
column: 1,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const message = locale ? localizeResolveDiagnostic(locale, diag) : diag.message;
|
|
77
|
+
const suggestion = extractSuggestion(message);
|
|
51
78
|
return {
|
|
52
79
|
severity: diag.severity,
|
|
53
|
-
code:
|
|
54
|
-
message
|
|
80
|
+
code: diag.code ?? inferCodeFromMessage(diag.message),
|
|
81
|
+
message,
|
|
82
|
+
...(suggestion === undefined ? {} : { suggestion }),
|
|
55
83
|
file: diag.sourcePath,
|
|
56
|
-
line
|
|
57
|
-
column
|
|
84
|
+
line,
|
|
85
|
+
column,
|
|
58
86
|
};
|
|
59
87
|
}
|
|
60
88
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostic-row.js","sourceRoot":"","sources":["../src/diagnostic-row.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,iBAAiB,
|
|
1
|
+
{"version":3,"file":"diagnostic-row.js","sourceRoot":"","sources":["../src/diagnostic-row.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { LangiumLikeDiagnostic } from '@nowline/core';
|
|
2
|
-
export { civilDateInZone, type NormalizedZone, normalizeZone, type ResolveTodayOptions, resolveToday, TimezoneError, } from '@nowline/layout';
|
|
2
|
+
export { civilDateInZone, isNonWorkingDisplay, NON_WORKING_DISPLAYS, type NonWorkingDisplay, type NormalizedZone, normalizeZone, parseNonWorkingDisplay, type ResolveTodayOptions, resolveToday, TimezoneError, } from '@nowline/layout';
|
|
3
3
|
export { type DiagnosticRow, fromLangiumDiagnostic, fromLayoutInsight, fromLexerError, fromParserError, fromRenderWarning, fromResolveDiagnostic, } from './diagnostic-row.js';
|
|
4
4
|
export { showcaseSource } from './generated/showcase.js';
|
|
5
5
|
export { isNoOpIncludeDiagnosticMessage, NOWLINE_BROWSER_NOOP_INCLUDE_TAG, noOpIncludeReadFile, type SkippedInclude, } from './no-op-include-resolver.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EACH,eAAe,EACf,KAAK,cAAc,EACnB,aAAa,EACb,KAAK,mBAAmB,EACxB,YAAY,EACZ,aAAa,GAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACH,KAAK,aAAa,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,qBAAqB,GACxB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EACH,8BAA8B,EAC9B,gCAAgC,EAChC,mBAAmB,EACnB,KAAK,cAAc,GACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACH,8BAA8B,EAC9B,sBAAsB,EACtB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,YAAY,EACZ,4BAA4B,GAC/B,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EACH,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,aAAa,EACb,sBAAsB,EACtB,KAAK,mBAAmB,EACxB,YAAY,EACZ,aAAa,GAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACH,KAAK,aAAa,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,qBAAqB,GACxB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EACH,8BAA8B,EAC9B,gCAAgC,EAChC,mBAAmB,EACnB,KAAK,cAAc,GACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACH,8BAA8B,EAC9B,sBAAsB,EACtB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,YAAY,EACZ,4BAA4B,GAC/B,MAAM,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// behaviour cannot drift between them. Surface-specific concerns (DOM
|
|
7
7
|
// auto-scan, postMessage transport, save/copy commands) belong in the
|
|
8
8
|
// consumer; this package stays a pure data transform.
|
|
9
|
-
export { civilDateInZone, normalizeZone, resolveToday, TimezoneError, } from '@nowline/layout';
|
|
9
|
+
export { civilDateInZone, isNonWorkingDisplay, NON_WORKING_DISPLAYS, normalizeZone, parseNonWorkingDisplay, resolveToday, TimezoneError, } from '@nowline/layout';
|
|
10
10
|
export { fromLangiumDiagnostic, fromLayoutInsight, fromLexerError, fromParserError, fromRenderWarning, fromResolveDiagnostic, } from './diagnostic-row.js';
|
|
11
11
|
// Showcase source string is generated from `examples/showcase.nowline`
|
|
12
12
|
// by `scripts/bundle-showcase.mjs` (m4.7 slice F) and re-exported here
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,qEAAqE;AACrE,qEAAqE;AACrE,uEAAuE;AACvE,sEAAsE;AACtE,sEAAsE;AACtE,sDAAsD;AAMtD,OAAO,EACH,eAAe,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,qEAAqE;AACrE,qEAAqE;AACrE,uEAAuE;AACvE,sEAAsE;AACtE,sEAAsE;AACtE,sDAAsD;AAMtD,OAAO,EACH,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EAGpB,aAAa,EACb,sBAAsB,EAEtB,YAAY,EACZ,aAAa,GAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAEH,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,qBAAqB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,uEAAuE;AACvE,uEAAuE;AACvE,2CAA2C;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EACH,8BAA8B,EAC9B,gCAAgC,EAChC,mBAAmB,GAEtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACH,8BAA8B,EAC9B,sBAAsB,EAItB,WAAW,EAGX,YAAY,EACZ,4BAA4B,GAC/B,MAAM,eAAe,CAAC"}
|
package/dist/pipeline.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type NowlineFile } from '@nowline/core';
|
|
2
|
-
import { type ThemeName } from '@nowline/layout';
|
|
2
|
+
import { type NonWorkingDisplay, type ThemeName } from '@nowline/layout';
|
|
3
3
|
import { type AssetResolver, type FontFamilies } from '@nowline/renderer';
|
|
4
4
|
import { type DiagnosticRow } from './diagnostic-row.js';
|
|
5
5
|
import { type SkippedInclude } from './no-op-include-resolver.js';
|
|
@@ -65,8 +65,15 @@ export interface RenderOptions extends ParseOptions {
|
|
|
65
65
|
timezone?: string;
|
|
66
66
|
/** BCP-47 locale forwarded to the layout engine for axis labels. */
|
|
67
67
|
locale?: string;
|
|
68
|
-
/**
|
|
68
|
+
/** Best-effort maximum canvas width in px. Unset fits the content. */
|
|
69
69
|
width?: number;
|
|
70
|
+
/**
|
|
71
|
+
* How a calendar's non-working days appear: `hide` collapses them,
|
|
72
|
+
* `show` draws them as shaded bands. Wins over the file's
|
|
73
|
+
* `default roadmap non-working:` key; leave it undefined to let the key
|
|
74
|
+
* apply, then `hide`.
|
|
75
|
+
*/
|
|
76
|
+
nonWorking?: NonWorkingDisplay;
|
|
70
77
|
/**
|
|
71
78
|
* Override the deterministic id prefix used for in-SVG `<style>`
|
|
72
79
|
* scoping. Multi-block surfaces (auto-scan) supply a fresh prefix
|
package/dist/pipeline.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAmBA,OAAO,
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAmBA,OAAO,EAIH,KAAK,WAAW,EAGnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEH,KAAK,iBAAiB,EAItB,KAAK,SAAS,EAEjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAA2B,MAAM,mBAAmB,CAAC;AAEnG,OAAO,EACH,KAAK,aAAa,EAOrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAGH,KAAK,cAAc,EACtB,MAAM,6BAA6B,CAAC;AAErC;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,4BAA4B,CAAC;AAEhE,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAc3D,wBAAgB,4BAA4B,CACxC,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,EACnC,KAAK,EAAE,eAAe,GACvB,OAAO,CAET;AAED,MAAM,WAAW,YAAY;IACzB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAClD;;;OAGG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;CACrC;AAED,MAAM,WAAW,WAAW;IACxB,GAAG,EAAE,WAAW,CAAC;IACjB,WAAW,EAAE,aAAa,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,aAAc,SAAQ,YAAY;IAC/C,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAAC;IAC7B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,mEAAmE;IACnE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;;OAIG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;CAC/B;AAED,MAAM,MAAM,YAAY,GAClB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,aAAa,EAAE,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,WAAW,EAAE,aAAa,EAAE,CAAA;CAAE,CAAC;AAqB5D;;;;;GAKG;AACH,wBAAsB,WAAW,CAC7B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,YAAiB,GAC3B,OAAO,CAAC,WAAW,CAAC,CAQtB;AAoBD;;;;;GAKG;AACH,wBAAsB,YAAY,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,aAAkB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAiHvB;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,IAAI,IAAI,CAGrD"}
|
package/dist/pipeline.js
CHANGED
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
//
|
|
17
17
|
// The package itself imports zero `node:*` modules so the embed esbuild
|
|
18
18
|
// bundle stays free of any Node literal even before tree-shaking.
|
|
19
|
-
import { collectDocumentDiagnostics, createNowlineServices,
|
|
20
|
-
import { collectLayoutInsights,
|
|
21
|
-
import { renderSvg } from '@nowline/renderer';
|
|
19
|
+
import { collectDocumentDiagnostics, createNowlineServices, isRoutedResolveDiagnostic, } from '@nowline/core';
|
|
20
|
+
import { collectLayoutInsights, normalizeZone, resolveToday, TimezoneError, } from '@nowline/layout';
|
|
21
|
+
import { renderSvg, stageRoadmap } from '@nowline/renderer';
|
|
22
22
|
import { URI } from 'langium';
|
|
23
23
|
import { fromLangiumDiagnostic, fromLayoutInsight, fromLexerError, fromParserError, fromRenderWarning, fromResolveDiagnostic, } from './diagnostic-row.js';
|
|
24
24
|
import { isNoOpIncludeDiagnosticMessage, noOpIncludeReadFile, } from './no-op-include-resolver.js';
|
|
@@ -65,22 +65,25 @@ export async function parseSource(source, options = {}) {
|
|
|
65
65
|
const docFactory = services.shared.workspace.LangiumDocumentFactory;
|
|
66
66
|
const doc = docFactory.fromString(source, freshUri());
|
|
67
67
|
await services.shared.workspace.DocumentBuilder.build([doc], { validation: true });
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
68
|
+
return { ast: doc.parseResult.value, diagnostics: documentRows(doc, filePath) };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Parse and validation diagnostics of a built document as rows.
|
|
72
|
+
* collectDocumentDiagnostics owns the de-dup: Langium re-folds lexer +
|
|
73
|
+
* parser errors into doc.diagnostics, so the shared collector skips those
|
|
74
|
+
* copies and we map each origin to a row here.
|
|
75
|
+
*/
|
|
76
|
+
function documentRows(doc, filePath) {
|
|
77
|
+
return rawRows(collectDocumentDiagnostics(doc), filePath);
|
|
78
|
+
}
|
|
79
|
+
function rawRows(raws, filePath) {
|
|
80
|
+
return raws.map((raw) => {
|
|
81
|
+
if (raw.origin === 'lexer')
|
|
82
|
+
return fromLexerError(raw.error, filePath);
|
|
83
|
+
if (raw.origin === 'parser')
|
|
84
|
+
return fromParserError(raw.error, filePath);
|
|
85
|
+
return fromLangiumDiagnostic(raw.diagnostic, filePath);
|
|
86
|
+
});
|
|
84
87
|
}
|
|
85
88
|
/**
|
|
86
89
|
* Run the full pipeline (parse + validate + resolveIncludes + layout
|
|
@@ -90,18 +93,50 @@ export async function parseSource(source, options = {}) {
|
|
|
90
93
|
*/
|
|
91
94
|
export async function renderSource(source, options = {}) {
|
|
92
95
|
const filePath = options.filePath ?? DEFAULT_SYNTHETIC_PATH;
|
|
93
|
-
const parsed = await parseSource(source, { filePath });
|
|
94
|
-
if (parsed.diagnostics.some((d) => d.severity === 'error')) {
|
|
95
|
-
return { kind: 'diagnostics', diagnostics: parsed.diagnostics };
|
|
96
|
-
}
|
|
97
96
|
const services = getServices();
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
// A bad timezone is reported after validation and include errors, as it
|
|
98
|
+
// always was: stage with no now-line, then return the timezone row only
|
|
99
|
+
// if the roadmap staged.
|
|
100
|
+
let zone;
|
|
101
|
+
let zoneError;
|
|
102
|
+
if (options.timezone) {
|
|
103
|
+
try {
|
|
104
|
+
zone = normalizeZone(options.timezone);
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
if (!(err instanceof TimezoneError))
|
|
108
|
+
throw err;
|
|
109
|
+
zoneError = err;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Pass today as-is: null suppresses the now-line, undefined defaults to
|
|
113
|
+
// local today (or zone), a string is parsed, a Date is used directly.
|
|
114
|
+
const today = zoneError ? undefined : resolveToday({ now: options.today, zone });
|
|
115
|
+
const stage = await stageRoadmap({
|
|
116
|
+
source,
|
|
117
|
+
sourcePath: filePath,
|
|
118
|
+
services,
|
|
119
|
+
readSource: options.readFile ?? noOpIncludeReadFile,
|
|
120
|
+
assetResolver: options.assetResolver,
|
|
121
|
+
// The no-op reader's skipped includes are not errors in single-file
|
|
122
|
+
// mode: they are reported through `onSkippedInclude` instead.
|
|
123
|
+
isToleratedIncludeError: (d) => isNoOpIncludeDiagnosticMessage(d.message),
|
|
124
|
+
layout: {
|
|
125
|
+
theme: options.theme,
|
|
126
|
+
today,
|
|
127
|
+
locale: options.locale,
|
|
128
|
+
width: options.width,
|
|
129
|
+
nonWorking: options.nonWorking,
|
|
130
|
+
},
|
|
102
131
|
});
|
|
103
|
-
|
|
104
|
-
|
|
132
|
+
if (stage.kind === 'invalid') {
|
|
133
|
+
return { kind: 'diagnostics', diagnostics: rawRows(stage.diagnostics, filePath) };
|
|
134
|
+
}
|
|
135
|
+
// An uncoded include error takes precedence: when one is reported, the
|
|
136
|
+
// routed (wave-rule) diagnostics are dropped (specs/waves.md §6.1).
|
|
137
|
+
const hasLegacyError = stage.kind === 'include-error' && stage.legacy !== undefined;
|
|
138
|
+
const rows = documentRows(stage.document, filePath);
|
|
139
|
+
for (const diag of stage.resolved.diagnostics) {
|
|
105
140
|
if (diag.severity === 'error' && isNoOpIncludeDiagnosticMessage(diag.message)) {
|
|
106
141
|
options.onSkippedInclude?.({
|
|
107
142
|
sourcePath: diag.sourcePath,
|
|
@@ -109,46 +144,34 @@ export async function renderSource(source, options = {}) {
|
|
|
109
144
|
});
|
|
110
145
|
continue;
|
|
111
146
|
}
|
|
147
|
+
if (hasLegacyError && isRoutedResolveDiagnostic(diag))
|
|
148
|
+
continue;
|
|
112
149
|
rows.push(fromResolveDiagnostic(diag));
|
|
113
150
|
}
|
|
114
|
-
if (rows.some((r) => r.severity === 'error')) {
|
|
151
|
+
if (stage.kind === 'include-error' || rows.some((r) => r.severity === 'error')) {
|
|
115
152
|
return { kind: 'diagnostics', diagnostics: rows };
|
|
116
153
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
file: filePath,
|
|
134
|
-
line: 1,
|
|
135
|
-
column: 1,
|
|
136
|
-
},
|
|
137
|
-
],
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
throw err;
|
|
141
|
-
}
|
|
154
|
+
if (zoneError) {
|
|
155
|
+
// Surface timezone errors as a diagnostic row rather than throwing
|
|
156
|
+
// so the caller gets a structured result instead of an uncaught error.
|
|
157
|
+
return {
|
|
158
|
+
kind: 'diagnostics',
|
|
159
|
+
diagnostics: [
|
|
160
|
+
{
|
|
161
|
+
severity: 'error',
|
|
162
|
+
code: 'invalid-timezone',
|
|
163
|
+
message: zoneError.message,
|
|
164
|
+
file: filePath,
|
|
165
|
+
line: 1,
|
|
166
|
+
column: 1,
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
};
|
|
142
170
|
}
|
|
143
|
-
//
|
|
144
|
-
//
|
|
145
|
-
const
|
|
146
|
-
const model =
|
|
147
|
-
theme: options.theme,
|
|
148
|
-
today,
|
|
149
|
-
locale: options.locale,
|
|
150
|
-
width: options.width,
|
|
151
|
-
});
|
|
171
|
+
// Renderer warnings, starting with the logo load: a failed load lays out
|
|
172
|
+
// as if no logo were declared and reports like any render warning.
|
|
173
|
+
const warnMessages = [...stage.warnings];
|
|
174
|
+
const { logo, model } = stage;
|
|
152
175
|
const diagnosticLevel = options.diagnosticLevel ?? 'error';
|
|
153
176
|
// Filtered once below as part of the combined `warnings` array.
|
|
154
177
|
const layoutInsightRows = collectLayoutInsights(model, {
|
|
@@ -157,10 +180,10 @@ export async function renderSource(source, options = {}) {
|
|
|
157
180
|
}).map((insight) => fromLayoutInsight(insight, filePath));
|
|
158
181
|
const showLinks = options.showLinks !== false;
|
|
159
182
|
const strict = options.strict === true;
|
|
160
|
-
const warnMessages = [];
|
|
161
183
|
const svg = await renderSvg(model, {
|
|
162
184
|
idPrefix: options.idPrefix,
|
|
163
185
|
assetResolver: options.assetResolver,
|
|
186
|
+
logo,
|
|
164
187
|
noLinks: !showLinks,
|
|
165
188
|
strict,
|
|
166
189
|
warn: (msg) => warnMessages.push(msg),
|
package/dist/pipeline.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,mEAAmE;AACnE,mBAAmB;AACnB,EAAE;AACF,uEAAuE;AACvE,wEAAwE;AACxE,sEAAsE;AACtE,yEAAyE;AACzE,yDAAyD;AACzD,EAAE;AACF,mEAAmE;AACnE,kEAAkE;AAClE,yEAAyE;AACzE,kEAAkE;AAClE,wEAAwE;AACxE,EAAE;AACF,wEAAwE;AACxE,kEAAkE;AAElE,OAAO,EACH,0BAA0B,EAC1B,qBAAqB,
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nowline/browser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Runs the whole Nowline pipeline — parse, validate, resolve includes, lay out, and render — in the browser, with pluggable I/O hooks. Powers @nowline/embed and the VS Code preview.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"engines": {
|
|
@@ -38,16 +38,16 @@
|
|
|
38
38
|
"pipeline"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"
|
|
42
|
-
"@nowline/
|
|
43
|
-
"@nowline/renderer": "0.
|
|
44
|
-
"
|
|
41
|
+
"@nowline/core": "0.9.0",
|
|
42
|
+
"@nowline/layout": "0.9.0",
|
|
43
|
+
"@nowline/renderer": "0.9.0",
|
|
44
|
+
"langium": "~4.4.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@types/node": "^
|
|
48
|
-
"happy-dom": "^
|
|
49
|
-
"typescript": "^
|
|
50
|
-
"vitest": "^
|
|
47
|
+
"@types/node": "^26.6.5",
|
|
48
|
+
"happy-dom": "^21.0.4",
|
|
49
|
+
"typescript": "^7.0.2",
|
|
50
|
+
"vitest": "^5.0.5"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"prebuild": "node scripts/bundle-showcase.mjs",
|
package/src/diagnostic-row.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
extractSuggestion,
|
|
3
|
+
inferCodeFromMessage,
|
|
4
|
+
isRoutedResolveDiagnostic,
|
|
3
5
|
type LangiumLikeDiagnostic,
|
|
4
6
|
type LexerErrorLike,
|
|
7
|
+
localizeResolveDiagnostic,
|
|
5
8
|
type ParserErrorLike,
|
|
6
9
|
type ResolveDiagnostic,
|
|
7
10
|
resolveDiagnosticCode,
|
|
@@ -76,16 +79,43 @@ export function fromLexerError(err: LexerErrorLike, file: string): DiagnosticRow
|
|
|
76
79
|
* is 0-based in the resolver (it comes from a CST range) and may be
|
|
77
80
|
* undefined for whole-file diagnostics like circular include — fall
|
|
78
81
|
* back to line 1 so a click-to-jump still puts the cursor near the top
|
|
79
|
-
* of the offending file.
|
|
82
|
+
* of the offending file. A routed diagnostic with a `range` takes its
|
|
83
|
+
* column from it, the validator's column for the same finding; without
|
|
84
|
+
* one the column is 1.
|
|
85
|
+
*
|
|
86
|
+
* A wave-rule diagnostic (specs/waves.md §6.1) keeps its stable code
|
|
87
|
+
* (`NL.Exxxx`), and its message is rendered in `locale` when the caller
|
|
88
|
+
* knows one; WV8, the uncoded wave rule, is labelled like the validator's
|
|
89
|
+
* copy. An included file's syntax error is the row that file's own check
|
|
90
|
+
* gives. Every other resolver diagnostic is an `include` row, verbatim.
|
|
80
91
|
*/
|
|
81
|
-
export function fromResolveDiagnostic(diag: ResolveDiagnostic): DiagnosticRow {
|
|
92
|
+
export function fromResolveDiagnostic(diag: ResolveDiagnostic, locale?: string): DiagnosticRow {
|
|
93
|
+
if (diag.syntax?.origin === 'lexer') return fromLexerError(diag.syntax.error, diag.sourcePath);
|
|
94
|
+
if (diag.syntax?.origin === 'parser') {
|
|
95
|
+
return fromParserError(diag.syntax.error, diag.sourcePath);
|
|
96
|
+
}
|
|
97
|
+
const line = (diag.range?.start.line ?? diag.line ?? 0) + 1;
|
|
98
|
+
const column = (diag.range?.start.character ?? 0) + 1;
|
|
99
|
+
if (!isRoutedResolveDiagnostic(diag)) {
|
|
100
|
+
return {
|
|
101
|
+
severity: diag.severity,
|
|
102
|
+
code: 'include',
|
|
103
|
+
message: diag.message,
|
|
104
|
+
file: diag.sourcePath,
|
|
105
|
+
line,
|
|
106
|
+
column: 1,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const message = locale ? localizeResolveDiagnostic(locale, diag) : diag.message;
|
|
110
|
+
const suggestion = extractSuggestion(message);
|
|
82
111
|
return {
|
|
83
112
|
severity: diag.severity,
|
|
84
|
-
code:
|
|
85
|
-
message
|
|
113
|
+
code: diag.code ?? inferCodeFromMessage(diag.message),
|
|
114
|
+
message,
|
|
115
|
+
...(suggestion === undefined ? {} : { suggestion }),
|
|
86
116
|
file: diag.sourcePath,
|
|
87
|
-
line
|
|
88
|
-
column
|
|
117
|
+
line,
|
|
118
|
+
column,
|
|
89
119
|
};
|
|
90
120
|
}
|
|
91
121
|
|
package/src/index.ts
CHANGED
|
@@ -13,8 +13,12 @@
|
|
|
13
13
|
export type { LangiumLikeDiagnostic } from '@nowline/core';
|
|
14
14
|
export {
|
|
15
15
|
civilDateInZone,
|
|
16
|
+
isNonWorkingDisplay,
|
|
17
|
+
NON_WORKING_DISPLAYS,
|
|
18
|
+
type NonWorkingDisplay,
|
|
16
19
|
type NormalizedZone,
|
|
17
20
|
normalizeZone,
|
|
21
|
+
parseNonWorkingDisplay,
|
|
18
22
|
type ResolveTodayOptions,
|
|
19
23
|
resolveToday,
|
|
20
24
|
TimezoneError,
|
package/src/pipeline.ts
CHANGED
|
@@ -20,21 +20,22 @@
|
|
|
20
20
|
import {
|
|
21
21
|
collectDocumentDiagnostics,
|
|
22
22
|
createNowlineServices,
|
|
23
|
+
isRoutedResolveDiagnostic,
|
|
23
24
|
type NowlineFile,
|
|
24
25
|
type NowlineServices,
|
|
25
|
-
|
|
26
|
+
type RawDiagnostic,
|
|
26
27
|
} from '@nowline/core';
|
|
27
28
|
import {
|
|
28
29
|
collectLayoutInsights,
|
|
29
|
-
|
|
30
|
+
type NonWorkingDisplay,
|
|
30
31
|
type NormalizedZone,
|
|
31
32
|
normalizeZone,
|
|
32
33
|
resolveToday,
|
|
33
34
|
type ThemeName,
|
|
34
35
|
TimezoneError,
|
|
35
36
|
} from '@nowline/layout';
|
|
36
|
-
import { type AssetResolver, type FontFamilies, renderSvg } from '@nowline/renderer';
|
|
37
|
-
import { URI } from 'langium';
|
|
37
|
+
import { type AssetResolver, type FontFamilies, renderSvg, stageRoadmap } from '@nowline/renderer';
|
|
38
|
+
import { type LangiumDocument, URI } from 'langium';
|
|
38
39
|
import {
|
|
39
40
|
type DiagnosticRow,
|
|
40
41
|
fromLangiumDiagnostic,
|
|
@@ -134,8 +135,15 @@ export interface RenderOptions extends ParseOptions {
|
|
|
134
135
|
timezone?: string;
|
|
135
136
|
/** BCP-47 locale forwarded to the layout engine for axis labels. */
|
|
136
137
|
locale?: string;
|
|
137
|
-
/**
|
|
138
|
+
/** Best-effort maximum canvas width in px. Unset fits the content. */
|
|
138
139
|
width?: number;
|
|
140
|
+
/**
|
|
141
|
+
* How a calendar's non-working days appear: `hide` collapses them,
|
|
142
|
+
* `show` draws them as shaded bands. Wins over the file's
|
|
143
|
+
* `default roadmap non-working:` key; leave it undefined to let the key
|
|
144
|
+
* apply, then `hide`.
|
|
145
|
+
*/
|
|
146
|
+
nonWorking?: NonWorkingDisplay;
|
|
139
147
|
/**
|
|
140
148
|
* Override the deterministic id prefix used for in-SVG `<style>`
|
|
141
149
|
* scoping. Multi-block surfaces (auto-scan) supply a fresh prefix
|
|
@@ -199,20 +207,25 @@ export async function parseSource(
|
|
|
199
207
|
const doc = docFactory.fromString<NowlineFile>(source, freshUri());
|
|
200
208
|
await services.shared.workspace.DocumentBuilder.build([doc], { validation: true });
|
|
201
209
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
210
|
+
return { ast: doc.parseResult.value, diagnostics: documentRows(doc, filePath) };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Parse and validation diagnostics of a built document as rows.
|
|
215
|
+
* collectDocumentDiagnostics owns the de-dup: Langium re-folds lexer +
|
|
216
|
+
* parser errors into doc.diagnostics, so the shared collector skips those
|
|
217
|
+
* copies and we map each origin to a row here.
|
|
218
|
+
*/
|
|
219
|
+
function documentRows(doc: LangiumDocument<NowlineFile>, filePath: string): DiagnosticRow[] {
|
|
220
|
+
return rawRows(collectDocumentDiagnostics(doc), filePath);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function rawRows(raws: readonly RawDiagnostic[], filePath: string): DiagnosticRow[] {
|
|
224
|
+
return raws.map((raw) => {
|
|
225
|
+
if (raw.origin === 'lexer') return fromLexerError(raw.error, filePath);
|
|
226
|
+
if (raw.origin === 'parser') return fromParserError(raw.error, filePath);
|
|
227
|
+
return fromLangiumDiagnostic(raw.diagnostic, filePath);
|
|
228
|
+
});
|
|
216
229
|
}
|
|
217
230
|
|
|
218
231
|
/**
|
|
@@ -226,20 +239,51 @@ export async function renderSource(
|
|
|
226
239
|
options: RenderOptions = {},
|
|
227
240
|
): Promise<RenderResult> {
|
|
228
241
|
const filePath = options.filePath ?? DEFAULT_SYNTHETIC_PATH;
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
242
|
+
const services = getServices();
|
|
243
|
+
|
|
244
|
+
// A bad timezone is reported after validation and include errors, as it
|
|
245
|
+
// always was: stage with no now-line, then return the timezone row only
|
|
246
|
+
// if the roadmap staged.
|
|
247
|
+
let zone: NormalizedZone | undefined;
|
|
248
|
+
let zoneError: TimezoneError | undefined;
|
|
249
|
+
if (options.timezone) {
|
|
250
|
+
try {
|
|
251
|
+
zone = normalizeZone(options.timezone);
|
|
252
|
+
} catch (err) {
|
|
253
|
+
if (!(err instanceof TimezoneError)) throw err;
|
|
254
|
+
zoneError = err;
|
|
255
|
+
}
|
|
232
256
|
}
|
|
257
|
+
// Pass today as-is: null suppresses the now-line, undefined defaults to
|
|
258
|
+
// local today (or zone), a string is parsed, a Date is used directly.
|
|
259
|
+
const today = zoneError ? undefined : resolveToday({ now: options.today, zone });
|
|
233
260
|
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
services
|
|
238
|
-
readFile,
|
|
261
|
+
const stage = await stageRoadmap({
|
|
262
|
+
source,
|
|
263
|
+
sourcePath: filePath,
|
|
264
|
+
services,
|
|
265
|
+
readSource: options.readFile ?? noOpIncludeReadFile,
|
|
266
|
+
assetResolver: options.assetResolver,
|
|
267
|
+
// The no-op reader's skipped includes are not errors in single-file
|
|
268
|
+
// mode: they are reported through `onSkippedInclude` instead.
|
|
269
|
+
isToleratedIncludeError: (d) => isNoOpIncludeDiagnosticMessage(d.message),
|
|
270
|
+
layout: {
|
|
271
|
+
theme: options.theme,
|
|
272
|
+
today,
|
|
273
|
+
locale: options.locale,
|
|
274
|
+
width: options.width,
|
|
275
|
+
nonWorking: options.nonWorking,
|
|
276
|
+
},
|
|
239
277
|
});
|
|
278
|
+
if (stage.kind === 'invalid') {
|
|
279
|
+
return { kind: 'diagnostics', diagnostics: rawRows(stage.diagnostics, filePath) };
|
|
280
|
+
}
|
|
240
281
|
|
|
241
|
-
|
|
242
|
-
|
|
282
|
+
// An uncoded include error takes precedence: when one is reported, the
|
|
283
|
+
// routed (wave-rule) diagnostics are dropped (specs/waves.md §6.1).
|
|
284
|
+
const hasLegacyError = stage.kind === 'include-error' && stage.legacy !== undefined;
|
|
285
|
+
const rows: DiagnosticRow[] = documentRows(stage.document, filePath);
|
|
286
|
+
for (const diag of stage.resolved.diagnostics) {
|
|
243
287
|
if (diag.severity === 'error' && isNoOpIncludeDiagnosticMessage(diag.message)) {
|
|
244
288
|
options.onSkippedInclude?.({
|
|
245
289
|
sourcePath: diag.sourcePath,
|
|
@@ -247,46 +291,35 @@ export async function renderSource(
|
|
|
247
291
|
});
|
|
248
292
|
continue;
|
|
249
293
|
}
|
|
294
|
+
if (hasLegacyError && isRoutedResolveDiagnostic(diag)) continue;
|
|
250
295
|
rows.push(fromResolveDiagnostic(diag));
|
|
251
296
|
}
|
|
252
|
-
if (rows.some((r) => r.severity === 'error')) {
|
|
297
|
+
if (stage.kind === 'include-error' || rows.some((r) => r.severity === 'error')) {
|
|
253
298
|
return { kind: 'diagnostics', diagnostics: rows };
|
|
254
299
|
}
|
|
255
300
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
line: 1,
|
|
273
|
-
column: 1,
|
|
274
|
-
},
|
|
275
|
-
],
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
throw err;
|
|
279
|
-
}
|
|
301
|
+
if (zoneError) {
|
|
302
|
+
// Surface timezone errors as a diagnostic row rather than throwing
|
|
303
|
+
// so the caller gets a structured result instead of an uncaught error.
|
|
304
|
+
return {
|
|
305
|
+
kind: 'diagnostics',
|
|
306
|
+
diagnostics: [
|
|
307
|
+
{
|
|
308
|
+
severity: 'error' as const,
|
|
309
|
+
code: 'invalid-timezone',
|
|
310
|
+
message: zoneError.message,
|
|
311
|
+
file: filePath,
|
|
312
|
+
line: 1,
|
|
313
|
+
column: 1,
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
};
|
|
280
317
|
}
|
|
281
|
-
|
|
282
|
-
//
|
|
283
|
-
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
today,
|
|
287
|
-
locale: options.locale,
|
|
288
|
-
width: options.width,
|
|
289
|
-
});
|
|
318
|
+
|
|
319
|
+
// Renderer warnings, starting with the logo load: a failed load lays out
|
|
320
|
+
// as if no logo were declared and reports like any render warning.
|
|
321
|
+
const warnMessages: string[] = [...stage.warnings];
|
|
322
|
+
const { logo, model } = stage;
|
|
290
323
|
|
|
291
324
|
const diagnosticLevel = options.diagnosticLevel ?? 'error';
|
|
292
325
|
// Filtered once below as part of the combined `warnings` array.
|
|
@@ -297,11 +330,11 @@ export async function renderSource(
|
|
|
297
330
|
|
|
298
331
|
const showLinks = options.showLinks !== false;
|
|
299
332
|
const strict = options.strict === true;
|
|
300
|
-
const warnMessages: string[] = [];
|
|
301
333
|
|
|
302
334
|
const svg = await renderSvg(model, {
|
|
303
335
|
idPrefix: options.idPrefix,
|
|
304
336
|
assetResolver: options.assetResolver,
|
|
337
|
+
logo,
|
|
305
338
|
noLinks: !showLinks,
|
|
306
339
|
strict,
|
|
307
340
|
warn: (msg) => warnMessages.push(msg),
|