@nowline/embed 0.9.0 → 0.11.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/meta.json CHANGED
@@ -5103,7 +5103,7 @@
5103
5103
  "format": "esm"
5104
5104
  },
5105
5105
  "../core/dist/diagnostics/index.js": {
5106
- "bytes": 4615,
5106
+ "bytes": 6188,
5107
5107
  "imports": [],
5108
5108
  "format": "esm"
5109
5109
  },
@@ -5135,17 +5135,17 @@
5135
5135
  "format": "esm"
5136
5136
  },
5137
5137
  "../core/dist/i18n/codes.js": {
5138
- "bytes": 2642,
5138
+ "bytes": 2770,
5139
5139
  "imports": [],
5140
5140
  "format": "esm"
5141
5141
  },
5142
5142
  "../core/dist/i18n/messages.en.js": {
5143
- "bytes": 20818,
5143
+ "bytes": 23135,
5144
5144
  "imports": [],
5145
5145
  "format": "esm"
5146
5146
  },
5147
5147
  "../core/dist/i18n/messages.fr.js": {
5148
- "bytes": 24547,
5148
+ "bytes": 27177,
5149
5149
  "imports": [],
5150
5150
  "format": "esm"
5151
5151
  },
@@ -5186,7 +5186,7 @@
5186
5186
  "format": "esm"
5187
5187
  },
5188
5188
  "../core/dist/util/posix-path.js": {
5189
- "bytes": 3360,
5189
+ "bytes": 4409,
5190
5190
  "imports": [],
5191
5191
  "format": "esm"
5192
5192
  },
@@ -5274,7 +5274,7 @@
5274
5274
  "format": "esm"
5275
5275
  },
5276
5276
  "../core/dist/language/include-waves.js": {
5277
- "bytes": 12694,
5277
+ "bytes": 12647,
5278
5278
  "imports": [
5279
5279
  {
5280
5280
  "path": "../../node_modules/.pnpm/langium@4.4.0/node_modules/langium/lib/index.js",
@@ -5372,7 +5372,7 @@
5372
5372
  "format": "esm"
5373
5373
  },
5374
5374
  "../core/dist/language/include-resolver.js": {
5375
- "bytes": 23037,
5375
+ "bytes": 25389,
5376
5376
  "imports": [
5377
5377
  {
5378
5378
  "path": "../../node_modules/.pnpm/langium@4.4.0/node_modules/langium/lib/index.js",
@@ -5389,6 +5389,11 @@
5389
5389
  "kind": "import-statement",
5390
5390
  "original": "../generated/ast.js"
5391
5391
  },
5392
+ {
5393
+ "path": "../core/dist/i18n/index.js",
5394
+ "kind": "import-statement",
5395
+ "original": "../i18n/index.js"
5396
+ },
5392
5397
  {
5393
5398
  "path": "../core/dist/util/posix-path.js",
5394
5399
  "kind": "import-statement",
@@ -5414,6 +5419,11 @@
5414
5419
  "kind": "import-statement",
5415
5420
  "original": "./waves.js"
5416
5421
  },
5422
+ {
5423
+ "path": "stub-node-read-file:../util/node-read-file.js",
5424
+ "kind": "dynamic-import",
5425
+ "original": "../util/node-read-file.js"
5426
+ },
5417
5427
  {
5418
5428
  "path": "stub-node-read-file:../util/node-read-file.js",
5419
5429
  "kind": "dynamic-import",
@@ -5835,7 +5845,7 @@
5835
5845
  "format": "esm"
5836
5846
  },
5837
5847
  "../core/dist/index.js": {
5838
- "bytes": 1352,
5848
+ "bytes": 1400,
5839
5849
  "imports": [
5840
5850
  {
5841
5851
  "path": "../core/dist/convert/parse-json.js",
@@ -10030,7 +10040,7 @@
10030
10040
  "format": "esm"
10031
10041
  },
10032
10042
  "../browser/dist/diagnostic-row.js": {
10033
- "bytes": 4103,
10043
+ "bytes": 4226,
10034
10044
  "imports": [
10035
10045
  {
10036
10046
  "path": "../core/dist/index.js",
@@ -10077,7 +10087,7 @@
10077
10087
  "format": "esm"
10078
10088
  },
10079
10089
  "../renderer/dist/stage.js": {
10080
- "bytes": 3853,
10090
+ "bytes": 4072,
10081
10091
  "imports": [
10082
10092
  {
10083
10093
  "path": "../core/dist/index.js",
@@ -10661,7 +10671,7 @@
10661
10671
  "imports": [],
10662
10672
  "exports": [],
10663
10673
  "inputs": {},
10664
- "bytes": 3710243
10674
+ "bytes": 3728511
10665
10675
  },
10666
10676
  "dist/nowline.min.js": {
10667
10677
  "imports": [],
@@ -10687,7 +10697,7 @@
10687
10697
  "bytesInOutput": 161
10688
10698
  },
10689
10699
  "src/index.ts": {
10690
- "bytesInOutput": 1535
10700
+ "bytesInOutput": 1536
10691
10701
  },
10692
10702
  "../../node_modules/.pnpm/langium@4.4.0/node_modules/langium/lib/syntax-tree.js": {
10693
10703
  "bytesInOutput": 1806
@@ -11518,7 +11528,7 @@
11518
11528
  "bytesInOutput": 309
11519
11529
  },
11520
11530
  "../core/dist/diagnostics/index.js": {
11521
- "bytesInOutput": 1168
11531
+ "bytesInOutput": 1378
11522
11532
  },
11523
11533
  "../core/dist/index.js": {
11524
11534
  "bytesInOutput": 0
@@ -11530,10 +11540,10 @@
11530
11540
  "bytesInOutput": 182
11531
11541
  },
11532
11542
  "../core/dist/i18n/messages.en.js": {
11533
- "bytesInOutput": 15721
11543
+ "bytesInOutput": 17491
11534
11544
  },
11535
11545
  "../core/dist/i18n/messages.fr.js": {
11536
- "bytesInOutput": 19755
11546
+ "bytesInOutput": 21876
11537
11547
  },
11538
11548
  "../core/dist/i18n/messages.fr-CA.js": {
11539
11549
  "bytesInOutput": 10
@@ -11545,7 +11555,7 @@
11545
11555
  "bytesInOutput": 460
11546
11556
  },
11547
11557
  "../core/dist/util/posix-path.js": {
11548
- "bytesInOutput": 924
11558
+ "bytesInOutput": 1356
11549
11559
  },
11550
11560
  "../core/dist/util/single-line.js": {
11551
11561
  "bytesInOutput": 79
@@ -11560,7 +11570,7 @@
11560
11570
  "bytesInOutput": 9621
11561
11571
  },
11562
11572
  "../core/dist/language/include-waves.js": {
11563
- "bytesInOutput": 3941
11573
+ "bytesInOutput": 3936
11564
11574
  },
11565
11575
  "../core/dist/language/references.js": {
11566
11576
  "bytesInOutput": 281
@@ -11569,7 +11579,7 @@
11569
11579
  "bytesInOutput": 375
11570
11580
  },
11571
11581
  "../core/dist/language/include-resolver.js": {
11572
- "bytesInOutput": 7670
11582
+ "bytesInOutput": 8116
11573
11583
  },
11574
11584
  "../core/dist/language/validator/support.js": {
11575
11585
  "bytesInOutput": 580
@@ -11788,7 +11798,7 @@
11788
11798
  "bytesInOutput": 2184
11789
11799
  },
11790
11800
  "../browser/dist/diagnostic-row.js": {
11791
- "bytesInOutput": 1204
11801
+ "bytesInOutput": 1264
11792
11802
  },
11793
11803
  "../browser/dist/no-op-include-resolver.js": {
11794
11804
  "bytesInOutput": 189
@@ -11803,7 +11813,7 @@
11803
11813
  "bytesInOutput": 777
11804
11814
  },
11805
11815
  "../renderer/dist/stage.js": {
11806
- "bytesInOutput": 1220
11816
+ "bytesInOutput": 1294
11807
11817
  },
11808
11818
  "../renderer/dist/index.js": {
11809
11819
  "bytesInOutput": 0
@@ -11881,7 +11891,7 @@
11881
11891
  "bytesInOutput": 257
11882
11892
  }
11883
11893
  },
11884
- "bytes": 674153
11894
+ "bytes": 679263
11885
11895
  }
11886
11896
  }
11887
11897
  }
@@ -1,4 +1,4 @@
1
- /*! @nowline/embed 0.9.0 sha=06f9e6f built=2026-10-23T06:13:14Z */
1
+ /*! @nowline/embed 0.11.0 sha=d8d931f built=2026-10-26T06:05:00Z */
2
2
  var __create = Object.create;
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -15082,7 +15082,7 @@ var UriUtils;
15082
15082
  return a?.toString() === b?.toString();
15083
15083
  }
15084
15084
  UriUtils2.equals = equals;
15085
- function relative(from, to) {
15085
+ function relative2(from, to) {
15086
15086
  const fromPath = typeof from === "string" ? URI.parse(from).path : from.path;
15087
15087
  const toPath = typeof to === "string" ? URI.parse(to).path : to.path;
15088
15088
  const fromParts = fromPath.split("/").filter((e) => e.length > 0);
@@ -15109,7 +15109,7 @@ var UriUtils;
15109
15109
  const toPart = toParts.slice(i2).join("/");
15110
15110
  return backPart + toPart;
15111
15111
  }
15112
- UriUtils2.relative = relative;
15112
+ UriUtils2.relative = relative2;
15113
15113
  function normalize3(uri) {
15114
15114
  return URI.parse(uri.toString()).toString();
15115
15115
  }
@@ -23468,6 +23468,20 @@ function extractSuggestion(message) {
23468
23468
  const match = message.match(DID_YOU_MEAN_RE);
23469
23469
  return match ? match[1].trim() : void 0;
23470
23470
  }
23471
+ var SUGGESTION_FROM_ARGS = {
23472
+ "NL.W0700": (a) => a.suggested || void 0,
23473
+ "NL.E1101": (a) => "suggestion" in a ? a.suggestion?.id : void 0
23474
+ };
23475
+ function suggestionFromArgs(code, args) {
23476
+ const pick = SUGGESTION_FROM_ARGS[code];
23477
+ return pick?.(...args);
23478
+ }
23479
+ function resolveDiagnosticSuggestion(message, data) {
23480
+ const code = stableValidatorCode(data);
23481
+ if (code === void 0)
23482
+ return extractSuggestion(message);
23483
+ return suggestionFromArgs(code, data.args);
23484
+ }
23471
23485
  function inferCodeFromMessage(message) {
23472
23486
  const lower = message.toLowerCase();
23473
23487
  if (lower.includes("duplicate identifier"))
@@ -26425,6 +26439,44 @@ var messages = {
26425
26439
  return `Wave "${a.id}" in "${a.path}" ${floorClause(a.childFloor)}, but this file's wave "${a.id}" ${floorClause(a.parentFloor)}. A wave must have the same start floor in every included roadmap.`;
26426
26440
  }
26427
26441
  },
26442
+ "NL.E0203": (a) => {
26443
+ switch (a.reason) {
26444
+ case "not-found":
26445
+ return `Cannot read include "${a.path}": file not found.`;
26446
+ case "is-directory":
26447
+ return `Cannot read include "${a.path}": it is a directory.`;
26448
+ case "permission-denied":
26449
+ return `Cannot read include "${a.path}": permission denied.`;
26450
+ case "not-nowline":
26451
+ return `Cannot read include "${a.path}": only .nowline files can be included.`;
26452
+ case "unreadable":
26453
+ return a.detail ? `Cannot read include "${a.path}": ${a.detail}` : `Cannot read include "${a.path}".`;
26454
+ }
26455
+ },
26456
+ "NL.E0204": (a) => `Circular include: "${a.path}" is already being included (${a.chain}).`,
26457
+ "NL.E0205": (a) => `Duplicate include "${a.path}". Include each file once.`,
26458
+ "NL.E0206": (a) => `Cannot isolate "${a.path}": it has no roadmap declaration.`,
26459
+ "NL.E0207": (a) => {
26460
+ if (a.parentStart && a.childStart) {
26461
+ return `Included "${a.path}" declares start:${a.childStart}, which doesn't match this file's start:${a.parentStart}. Both files must declare the same start date, or neither should.`;
26462
+ }
26463
+ if (a.parentStart) {
26464
+ return `Included "${a.path}" has no start:, but this file declares start:${a.parentStart}. Both files must declare the same start date, or neither should.`;
26465
+ }
26466
+ return `Included "${a.path}" declares start:${a.childStart}, but this file has no start:. Both files must declare the same start date, or neither should.`;
26467
+ },
26468
+ "NL.E0208": (a) => {
26469
+ switch (a.reason) {
26470
+ case "absolute":
26471
+ return `Include "${a.path}" is an absolute path. With an include root, an include must be a relative path inside it.`;
26472
+ case "parent":
26473
+ return `Include "${a.path}" resolves outside the include root.`;
26474
+ case "symlink":
26475
+ return `Include "${a.path}" resolves outside the include root through a symbolic link.`;
26476
+ }
26477
+ },
26478
+ "NL.E0209": (a) => `Includes are not supported in this context: "${a.path}" was not read.`,
26479
+ "NL.E0210": (a) => `Include "${a.path}" is more than ${a.max} includes deep. Flatten the include chain.`,
26428
26480
  // Identifier
26429
26481
  "NL.E0300": (a) => `Duplicate identifier "${a.name}". First declared at ${a.location}.`,
26430
26482
  "NL.E0301": (a) => `${a.type} must have an identifier, a title, or both.`,
@@ -26687,6 +26739,44 @@ var messages2 = {
26687
26739
  return `La vague ${q(a.id)} dans ${q(a.path)} ${floorText(a.childFloor)}, mais la vague ${q(a.id)} de ce fichier ${floorText(a.parentFloor)}. Une vague doit avoir la m\xEAme borne de d\xE9part dans chaque roadmap incluse.`;
26688
26740
  }
26689
26741
  },
26742
+ "NL.E0203": (a) => {
26743
+ switch (a.reason) {
26744
+ case "not-found":
26745
+ return `Impossible de lire l'include ${q(a.path)}\xA0: fichier introuvable.`;
26746
+ case "is-directory":
26747
+ return `Impossible de lire l'include ${q(a.path)}\xA0: c'est un r\xE9pertoire.`;
26748
+ case "permission-denied":
26749
+ return `Impossible de lire l'include ${q(a.path)}\xA0: permission refus\xE9e.`;
26750
+ case "not-nowline":
26751
+ return `Impossible de lire l'include ${q(a.path)}\xA0: seuls les fichiers .nowline peuvent \xEAtre inclus.`;
26752
+ case "unreadable":
26753
+ return a.detail ? `Impossible de lire l'include ${q(a.path)}\xA0: ${a.detail}` : `Impossible de lire l'include ${q(a.path)}.`;
26754
+ }
26755
+ },
26756
+ "NL.E0204": (a) => `Include circulaire\xA0: ${q(a.path)} est d\xE9j\xE0 en cours d'inclusion (${a.chain}).`,
26757
+ "NL.E0205": (a) => `Include ${q(a.path)} en double. Incluez chaque fichier une seule fois.`,
26758
+ "NL.E0206": (a) => `Impossible d'isoler ${q(a.path)}\xA0: il ne d\xE9clare aucune roadmap.`,
26759
+ "NL.E0207": (a) => {
26760
+ if (a.parentStart && a.childStart) {
26761
+ return `L'include ${q(a.path)} d\xE9clare start:${a.childStart}, qui ne correspond pas au start:${a.parentStart} de ce fichier. Les deux fichiers doivent d\xE9clarer la m\xEAme date de d\xE9but, ou aucun des deux.`;
26762
+ }
26763
+ if (a.parentStart) {
26764
+ return `L'include ${q(a.path)} n'a pas de start:, mais ce fichier d\xE9clare start:${a.parentStart}. Les deux fichiers doivent d\xE9clarer la m\xEAme date de d\xE9but, ou aucun des deux.`;
26765
+ }
26766
+ return `L'include ${q(a.path)} d\xE9clare start:${a.childStart}, mais ce fichier n'a pas de start:. Les deux fichiers doivent d\xE9clarer la m\xEAme date de d\xE9but, ou aucun des deux.`;
26767
+ },
26768
+ "NL.E0208": (a) => {
26769
+ switch (a.reason) {
26770
+ case "absolute":
26771
+ return `L'include ${q(a.path)} est un chemin absolu. Avec une racine d'include, un include doit \xEAtre un chemin relatif \xE0 l'int\xE9rieur de celle-ci.`;
26772
+ case "parent":
26773
+ return `L'include ${q(a.path)} se r\xE9sout hors de la racine d'include.`;
26774
+ case "symlink":
26775
+ return `L'include ${q(a.path)} se r\xE9sout hors de la racine d'include par un lien symbolique.`;
26776
+ }
26777
+ },
26778
+ "NL.E0209": (a) => `Les includes ne sont pas pris en charge dans ce contexte\xA0: ${q(a.path)} n'a pas \xE9t\xE9 lu.`,
26779
+ "NL.E0210": (a) => `L'include ${q(a.path)} d\xE9passe ${a.max} niveaux d'inclusion. Aplatissez la cha\xEEne d'includes.`,
26690
26780
  // Identifiant
26691
26781
  "NL.E0300": (a) => `Identifiant en double \xAB\xA0${a.name}\xA0\xBB. Premi\xE8re d\xE9claration \xE0 ${a.location}.`,
26692
26782
  "NL.E0301": (a) => `${a.type} doit comporter un identifiant, un titre, ou les deux.`,
@@ -26942,6 +27032,27 @@ function normalize2(p, sep) {
26942
27032
  }
26943
27033
  return prefix + segments.join(sep);
26944
27034
  }
27035
+ function segmentsOf(p) {
27036
+ const normalized = resolve("", p).replace(/\\/g, "/");
27037
+ const drive = /^[A-Za-z]:/.test(normalized) ? normalized.slice(0, 2).toLowerCase() : "";
27038
+ const body = drive ? normalized.slice(2) : normalized;
27039
+ return [drive, ...body.split("/").filter((s) => s !== "")];
27040
+ }
27041
+ function isWithin(dir, p) {
27042
+ const d = segmentsOf(dir);
27043
+ const t = segmentsOf(p);
27044
+ return d.length <= t.length && d.every((seg, i2) => seg === t[i2]);
27045
+ }
27046
+ function relative(from, to) {
27047
+ const f = segmentsOf(from);
27048
+ const t = segmentsOf(to);
27049
+ if (f[0] !== t[0])
27050
+ return to;
27051
+ let i2 = 0;
27052
+ while (i2 < f.length && i2 < t.length && f[i2] === t[i2])
27053
+ i2++;
27054
+ return [...f.slice(i2).map(() => ".."), ...t.slice(i2)].join("/") || ".";
27055
+ }
26945
27056
 
26946
27057
  // ../core/dist/util/single-line.js
26947
27058
  function singleLine(text) {
@@ -28158,8 +28269,8 @@ function hasParseErrors(file) {
28158
28269
  const result = file.$document?.parseResult;
28159
28270
  return !!result && (result.lexerErrors.length > 0 || result.parserErrors.length > 0);
28160
28271
  }
28161
- function participates(childFile, childContent, isStub) {
28162
- if (isStub || hasParseErrors(childFile))
28272
+ function participates(childFile, childContent) {
28273
+ if (hasParseErrors(childFile))
28163
28274
  return false;
28164
28275
  return !!childFile.roadmapDecl || childContent.swimlanes.size > 0 || ownWaves(childFile).length > 0;
28165
28276
  }
@@ -28464,15 +28575,6 @@ function readStartProp(decl) {
28464
28575
  return void 0;
28465
28576
  return prop.value;
28466
28577
  }
28467
- function formatStartMismatch(childRelPath, parentStart, childStart) {
28468
- if (parentStart && childStart) {
28469
- return `Included "${childRelPath}" declares start:${childStart}, which doesn't match this file's start:${parentStart}. Both files must declare the same start date, or neither should.`;
28470
- }
28471
- if (parentStart) {
28472
- return `Included "${childRelPath}" has no start:, but this file declares start:${parentStart}. Both files must declare the same start date, or neither should.`;
28473
- }
28474
- return `Included "${childRelPath}" declares start:${childStart}, but this file has no start:. Both files must declare the same start date, or neither should.`;
28475
- }
28476
28578
  function isRoutedResolveDiagnostic(d) {
28477
28579
  return d.code !== void 0 || d.rule === "wave" || d.syntax !== void 0;
28478
28580
  }
@@ -28498,22 +28600,30 @@ function emptyContent() {
28498
28600
  isolatedRegions: []
28499
28601
  };
28500
28602
  }
28603
+ var MAX_INCLUDE_DEPTH = 16;
28501
28604
  async function resolveIncludes(file, filePath, options) {
28502
28605
  const readFile = options.readFile ?? (async (p) => {
28503
28606
  const { nodeReadFile: nodeReadFile2 } = await Promise.resolve().then(() => (init_node_read_file(), node_read_file_exports));
28504
28607
  return nodeReadFile2(p);
28505
28608
  });
28609
+ const policy = options.includePolicy;
28610
+ const realPath = (policy?.kind === "rooted" ? policy.realPath : void 0) ?? (async (p) => {
28611
+ const { nodeRealPath } = await Promise.resolve().then(() => (init_node_read_file(), node_read_file_exports));
28612
+ return nodeRealPath(p);
28613
+ });
28506
28614
  const absPath = resolve("", filePath);
28507
28615
  const ctx = {
28508
28616
  services: options.services,
28509
28617
  rootAbs: absPath,
28618
+ policy,
28619
+ realPath,
28620
+ displayBase: policy?.kind === "rooted" ? policy.root : dirname(absPath),
28510
28621
  diagnostics: [],
28511
28622
  resolving: [],
28512
28623
  processed: /* @__PURE__ */ new Map(),
28513
28624
  readFile,
28514
28625
  files: /* @__PURE__ */ new Map(),
28515
28626
  edges: /* @__PURE__ */ new Map(),
28516
- stubs: /* @__PURE__ */ new Set(),
28517
28627
  failedWaves: /* @__PURE__ */ new Set()
28518
28628
  };
28519
28629
  const { config: config2, content } = await resolveFile(file, absPath, ctx);
@@ -28537,17 +28647,6 @@ async function resolveFile(file, absPath, ctx) {
28537
28647
  if (ctx.processed.has(absPath)) {
28538
28648
  return ctx.processed.get(absPath);
28539
28649
  }
28540
- if (ctx.resolving.includes(absPath)) {
28541
- ctx.diagnostics.push({
28542
- severity: "error",
28543
- message: `Circular include detected: ${[...ctx.resolving, absPath].join(" \u2192 ")}`,
28544
- sourcePath: absPath
28545
- });
28546
- const empty = { config: emptyConfig(), content: emptyContent() };
28547
- ctx.stubs.add(empty.content);
28548
- ctx.processed.set(absPath, empty);
28549
- return empty;
28550
- }
28551
28650
  if (absPath !== ctx.rootAbs)
28552
28651
  ctx.diagnostics.push(...syntaxDiagnostics(file, absPath));
28553
28652
  ctx.resolving.push(absPath);
@@ -28565,17 +28664,42 @@ async function resolveFile(file, absPath, ctx) {
28565
28664
  const seenIncludes = /* @__PURE__ */ new Set();
28566
28665
  for (const inc of file.includes) {
28567
28666
  const childRelPath = inc.path;
28568
- const childAbsPath = resolve(dirname(absPath), childRelPath);
28667
+ const fail = (code, ...args) => {
28668
+ ctx.diagnostics.push(includeError(absPath, inc, code, ...args));
28669
+ };
28670
+ if (ctx.policy?.kind === "disabled") {
28671
+ fail("NL.E0209", { path: childRelPath });
28672
+ continue;
28673
+ }
28674
+ const located = await locateInclude(absPath, childRelPath, ctx);
28675
+ if ("refused" in located) {
28676
+ fail("NL.E0208", located.refused);
28677
+ continue;
28678
+ }
28679
+ if ("unreadable" in located) {
28680
+ fail("NL.E0203", located.unreadable);
28681
+ continue;
28682
+ }
28683
+ const childAbsPath = located.absPath;
28569
28684
  if (seenIncludes.has(childAbsPath)) {
28570
- ctx.diagnostics.push({
28571
- severity: "error",
28572
- message: `Duplicate include "${childRelPath}" in ${basename(absPath)}.`,
28573
- sourcePath: absPath,
28574
- line: inc.$cstNode?.range.start.line
28575
- });
28685
+ fail("NL.E0205", { path: childRelPath });
28576
28686
  continue;
28577
28687
  }
28578
28688
  seenIncludes.add(childAbsPath);
28689
+ const cycleStart = ctx.resolving.indexOf(childAbsPath);
28690
+ if (cycleStart >= 0) {
28691
+ const chain = [...ctx.resolving.slice(cycleStart), childAbsPath].map((p) => relative(ctx.displayBase, p)).join(" \u2192 ");
28692
+ fail("NL.E0204", { path: childRelPath, chain });
28693
+ continue;
28694
+ }
28695
+ if (ctx.resolving.length > MAX_INCLUDE_DEPTH) {
28696
+ fail("NL.E0210", { path: childRelPath, max: MAX_INCLUDE_DEPTH });
28697
+ continue;
28698
+ }
28699
+ if (!childAbsPath.endsWith(".nowline")) {
28700
+ fail("NL.E0203", { reason: "not-nowline", path: childRelPath });
28701
+ continue;
28702
+ }
28579
28703
  const configMode = getIncludeMode(inc, "config") ?? "merge";
28580
28704
  const roadmapMode = getIncludeMode(inc, "roadmap") ?? "merge";
28581
28705
  let childFile;
@@ -28583,12 +28707,7 @@ async function resolveFile(file, absPath, ctx) {
28583
28707
  const text = await ctx.readFile(childAbsPath);
28584
28708
  childFile = await parseString(ctx.services, text, childAbsPath);
28585
28709
  } catch (err) {
28586
- ctx.diagnostics.push({
28587
- severity: "error",
28588
- message: `Could not read include "${childRelPath}": ${err.message}`,
28589
- sourcePath: absPath,
28590
- line: inc.$cstNode?.range.start.line
28591
- });
28710
+ fail("NL.E0203", unreadableArgs(childRelPath, err));
28592
28711
  continue;
28593
28712
  }
28594
28713
  const { config: childConfig, content: childContent } = await resolveFile(childFile, childAbsPath, ctx);
@@ -28600,28 +28719,22 @@ async function resolveFile(file, absPath, ctx) {
28600
28719
  mode: roadmapMode,
28601
28720
  childFile,
28602
28721
  childContent,
28603
- participates: participates(childFile, childContent, ctx.stubs.has(childContent))
28722
+ participates: participates(childFile, childContent)
28604
28723
  });
28605
28724
  applyConfigMode(config2, childConfig, configMode, childAbsPath, ctx.diagnostics);
28606
28725
  applyRoadmapMode(content, childContent, childConfig, roadmapMode, childAbsPath, childRelPath, ctx.diagnostics);
28607
28726
  const isParsed = !hasParseErrors(childFile);
28608
28727
  if (isParsed && roadmapMode === "isolate" && !childContent.roadmap) {
28609
- ctx.diagnostics.push({
28610
- severity: "error",
28611
- message: `Cannot isolate "${childRelPath}": it has no roadmap declaration.`,
28612
- sourcePath: absPath,
28613
- line: inc.$cstNode?.range.start.line
28614
- });
28728
+ fail("NL.E0206", { path: childRelPath });
28615
28729
  }
28616
28730
  if (isParsed && roadmapMode !== "ignore" && childFile.roadmapDecl) {
28617
28731
  const parentStart = readStartProp(file.roadmapDecl);
28618
28732
  const childStart = readStartProp(childFile.roadmapDecl);
28619
28733
  if (parentStart !== childStart) {
28620
- ctx.diagnostics.push({
28621
- severity: "error",
28622
- message: formatStartMismatch(childRelPath, parentStart, childStart),
28623
- sourcePath: absPath,
28624
- line: inc.$cstNode?.range.start.line
28734
+ fail("NL.E0207", {
28735
+ path: childRelPath,
28736
+ ...parentStart ? { parentStart } : {},
28737
+ ...childStart ? { childStart } : {}
28625
28738
  });
28626
28739
  }
28627
28740
  }
@@ -28639,6 +28752,49 @@ async function resolveFile(file, absPath, ctx) {
28639
28752
  ctx.processed.set(absPath, result);
28640
28753
  return result;
28641
28754
  }
28755
+ function includeError(sourcePath, inc, code, ...args) {
28756
+ return {
28757
+ severity: "error",
28758
+ message: tr("en-US", code, ...args),
28759
+ sourcePath,
28760
+ ...nodeLocation(inc, "path"),
28761
+ code,
28762
+ args
28763
+ };
28764
+ }
28765
+ async function locateInclude(parentAbs, path, ctx) {
28766
+ const policy = ctx.policy;
28767
+ if (policy?.kind !== "rooted")
28768
+ return { absPath: resolve(dirname(parentAbs), path) };
28769
+ if (isAbsolute(path))
28770
+ return { refused: { reason: "absolute", path } };
28771
+ const lexical = resolve(dirname(parentAbs), path);
28772
+ if (!isWithin(policy.root, lexical))
28773
+ return { refused: { reason: "parent", path } };
28774
+ let real;
28775
+ try {
28776
+ real = await ctx.realPath(lexical);
28777
+ } catch (err) {
28778
+ return { unreadable: unreadableArgs(path, err) };
28779
+ }
28780
+ if (!isWithin(policy.root, real))
28781
+ return { refused: { reason: "symlink", path } };
28782
+ return { absPath: real };
28783
+ }
28784
+ function unreadableArgs(path, err) {
28785
+ switch (err?.code) {
28786
+ case "ENOENT":
28787
+ case "ENOTDIR":
28788
+ return { reason: "not-found", path };
28789
+ case "EISDIR":
28790
+ return { reason: "is-directory", path };
28791
+ case "EACCES":
28792
+ case "EPERM":
28793
+ return { reason: "permission-denied", path };
28794
+ }
28795
+ const detail = err instanceof Error ? err.message : void 0;
28796
+ return { reason: "unreadable", path, ...detail ? { detail } : {} };
28797
+ }
28642
28798
  function syntaxDiagnostics(file, absPath) {
28643
28799
  const doc = file.$document;
28644
28800
  if (!doc)
@@ -37275,7 +37431,7 @@ function fromLangiumDiagnostic(diag, file) {
37275
37431
  // panel, then falls back to Langium's `code`, then a message heuristic.
37276
37432
  code: resolveDiagnosticCode(diag),
37277
37433
  message: diag.message,
37278
- suggestion: extractSuggestion(diag.message),
37434
+ suggestion: resolveDiagnosticSuggestion(diag.message, diag.data),
37279
37435
  file,
37280
37436
  line: (diag.range?.start.line ?? 0) + 1,
37281
37437
  column: (diag.range?.start.character ?? 0) + 1
@@ -37320,7 +37476,7 @@ function fromResolveDiagnostic(diag, locale) {
37320
37476
  };
37321
37477
  }
37322
37478
  const message = locale ? localizeResolveDiagnostic(locale, diag) : diag.message;
37323
- const suggestion = extractSuggestion(message);
37479
+ const suggestion = resolveDiagnosticSuggestion(message, diag.code === void 0 ? void 0 : { code: diag.code, args: diag.args ?? [] });
37324
37480
  return {
37325
37481
  severity: diag.severity,
37326
37482
  code: diag.code ?? inferCodeFromMessage(diag.message),
@@ -38071,11 +38227,13 @@ async function stageRoadmap(inputs) {
38071
38227
  const ast = document2.parseResult.value;
38072
38228
  const resolved = await resolveIncludes(ast, inputs.sourcePath, {
38073
38229
  services: inputs.services.Nowline,
38074
- readFile: inputs.readSource
38230
+ readFile: inputs.readSource,
38231
+ includePolicy: inputs.includePolicy
38075
38232
  });
38076
38233
  const isTolerated = inputs.isToleratedIncludeError ?? (() => false);
38077
- const errors = resolved.diagnostics.filter((d) => d.severity === "error" && !isTolerated(d));
38078
- const routed = resolved.diagnostics.filter(isRoutedResolveDiagnostic);
38234
+ const isCounted = (d) => d.severity !== "error" || !isTolerated(d);
38235
+ const errors = resolved.diagnostics.filter((d) => d.severity === "error" && isCounted(d));
38236
+ const routed = resolved.diagnostics.filter((d) => isRoutedResolveDiagnostic(d) && isCounted(d));
38079
38237
  const legacy = errors.find((d) => !isRoutedResolveDiagnostic(d));
38080
38238
  if (legacy) {
38081
38239
  return { kind: "include-error", document: document2, legacy, routed: [], resolved };
@@ -40879,8 +41037,8 @@ function effectiveTheme(theme, systemTheme) {
40879
41037
  }
40880
41038
 
40881
41039
  // src/index.ts
40882
- var version = true ? "0.9.0" : "0.0.0";
40883
- var sha = true ? "06f9e6f" : "unknown";
41040
+ var version = true ? "0.11.0" : "0.0.0";
41041
+ var sha = true ? "d8d931f" : "unknown";
40884
41042
  var DEFAULT_SELECTOR = "pre code.language-nowline, code.language-nowline";
40885
41043
  var initialConfig = {
40886
41044
  theme: "auto",