@diagrammo/dgmo 0.8.15 → 0.8.16

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/src/echarts.ts CHANGED
@@ -105,7 +105,7 @@ import { mix } from './palettes/color-utils';
105
105
  import { parseChart } from './chart';
106
106
  import type { ParsedChart, ChartEra } from './chart';
107
107
  import { makeDgmoError, formatDgmoError, suggest } from './diagnostics';
108
- import { resolveColor } from './colors';
108
+ import { resolveColorWithDiagnostic } from './colors';
109
109
  import {
110
110
  collectIndentedValues,
111
111
  extractColor,
@@ -300,7 +300,12 @@ export function parseExtendedChart(
300
300
  if (categoryMatch) {
301
301
  const catName = categoryMatch[1].trim();
302
302
  const catColor = categoryMatch[2]
303
- ? resolveColor(categoryMatch[2].trim(), palette)
303
+ ? (resolveColorWithDiagnostic(
304
+ categoryMatch[2].trim(),
305
+ lineNumber,
306
+ result.diagnostics,
307
+ palette
308
+ ) ?? null)
304
309
  : null;
305
310
  if (catColor) {
306
311
  if (!result.categoryColors) result.categoryColors = {};
@@ -332,7 +337,12 @@ export function parseExtendedChart(
332
337
  if (targetColor) result.nodeColors[target] = targetColor;
333
338
  }
334
339
  const linkColor = rawLinkColor
335
- ? resolveColor(rawLinkColor.trim(), palette)
340
+ ? resolveColorWithDiagnostic(
341
+ rawLinkColor.trim(),
342
+ lineNumber,
343
+ result.diagnostics,
344
+ palette
345
+ )
336
346
  : undefined;
337
347
  if (!result.links) result.links = [];
338
348
  result.links.push({
@@ -368,7 +378,12 @@ export function parseExtendedChart(
368
378
  if (dataRow && dataRow.values.length === 1) {
369
379
  const source = sankeyStack.at(-1)!.name;
370
380
  const linkColor = valColorMatch?.[2]
371
- ? resolveColor(valColorMatch[2].trim(), palette)
381
+ ? resolveColorWithDiagnostic(
382
+ valColorMatch[2].trim(),
383
+ lineNumber,
384
+ result.diagnostics,
385
+ palette
386
+ )
372
387
  : undefined;
373
388
  const { label: target, color: targetColor } = extractColor(
374
389
  dataRow.label,
package/src/er/parser.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { resolveColor } from '../colors';
1
+ import { resolveColorWithDiagnostic } from '../colors';
2
2
  import type { PaletteColors } from '../palettes';
3
3
  import { makeDgmoError, formatDgmoError, suggest } from '../diagnostics';
4
4
  import {
@@ -43,8 +43,9 @@ const TABLE_DECL_RE = /^([a-zA-Z_]\w*)(?:\s*\(([^)]+)\))?(?:\s*\|(.+))?$/;
43
43
  // Remaining tokens are constraint keywords (pk, fk, unique, nullable).
44
44
  // Handled programmatically, not with a single regex.
45
45
 
46
- // Indented relationship: 1-* target or 1-label-* target
47
- const INDENT_REL_RE = /^([1*?])-(?:(.+)-)?([1*?])\s+([a-zA-Z_]\w*)\s*$/;
46
+ // Indented relationship: 1-* target, 1--* target, or 1-label-* target / 1--label--* target
47
+ const INDENT_REL_RE =
48
+ /^([1*?])-{1,2}(?:(.+?)-{1,2})?([1*?])\s+([a-zA-Z_]\w*)\s*$/;
48
49
 
49
50
  // Constraint keywords
50
51
  const CONSTRAINT_MAP: Record<string, ERConstraint> = {
@@ -372,7 +373,14 @@ export function parseERDiagram(
372
373
  if (tableDecl) {
373
374
  const name = tableDecl[1];
374
375
  const colorName = tableDecl[2]?.trim();
375
- const color = colorName ? resolveColor(colorName, palette) : undefined;
376
+ const color = colorName
377
+ ? resolveColorWithDiagnostic(
378
+ colorName,
379
+ lineNumber,
380
+ result.diagnostics,
381
+ palette
382
+ )
383
+ : undefined;
376
384
 
377
385
  const table = getOrCreateTable(name, lineNumber);
378
386
  if (color) table.color = color;
@@ -1,4 +1,5 @@
1
- import { resolveColor } from '../colors';
1
+ import { resolveColorWithDiagnostic } from '../colors';
2
+ import type { DgmoError } from '../diagnostics';
2
3
  import type { PaletteColors } from '../palettes';
3
4
  import { makeDgmoError, formatDgmoError, suggest } from '../diagnostics';
4
5
  import {
@@ -185,23 +186,46 @@ interface ArrowInfo {
185
186
  color?: string;
186
187
  }
187
188
 
188
- function parseArrowToken(token: string, palette?: PaletteColors): ArrowInfo {
189
+ function parseArrowToken(
190
+ token: string,
191
+ palette: PaletteColors | undefined,
192
+ lineNumber: number,
193
+ diagnostics: DgmoError[]
194
+ ): ArrowInfo {
189
195
  if (token === '->') return {};
190
196
  // Color-only: -(color)->
191
197
  const colorOnly = token.match(/^-\(([^)]+)\)->$/);
192
198
  if (colorOnly) {
193
- return { color: resolveColor(colorOnly[1].trim(), palette) ?? undefined };
199
+ return {
200
+ color: resolveColorWithDiagnostic(
201
+ colorOnly[1].trim(),
202
+ lineNumber,
203
+ diagnostics,
204
+ palette
205
+ ),
206
+ };
194
207
  }
195
208
  // -label(color)-> or -label->
196
209
  const m = token.match(/^-(.+?)(?:\(([^)]+)\))?->$/);
197
210
  if (m) {
198
211
  const label = m[1]?.trim() || undefined;
199
212
  let color = m[2]
200
- ? (resolveColor(m[2].trim(), palette) ?? undefined)
213
+ ? resolveColorWithDiagnostic(
214
+ m[2].trim(),
215
+ lineNumber,
216
+ diagnostics,
217
+ palette
218
+ )
201
219
  : undefined;
202
220
  if (label && !color) {
203
221
  const inferred = inferArrowColor(label);
204
- if (inferred) color = resolveColor(inferred, palette) ?? undefined;
222
+ if (inferred)
223
+ color = resolveColorWithDiagnostic(
224
+ inferred,
225
+ lineNumber,
226
+ diagnostics,
227
+ palette
228
+ );
205
229
  }
206
230
  return { label, color };
207
231
  }
@@ -327,7 +351,12 @@ export function parseFlowchart(
327
351
 
328
352
  // Check if this is an arrow token
329
353
  if (seg === '->' || /^-.+->$/.test(seg)) {
330
- pendingArrow = parseArrowToken(seg, palette);
354
+ pendingArrow = parseArrowToken(
355
+ seg,
356
+ palette,
357
+ lineNumber,
358
+ result.diagnostics
359
+ );
331
360
  continue;
332
361
  }
333
362
 
@@ -1,4 +1,5 @@
1
- import { resolveColor } from '../colors';
1
+ import { resolveColorWithDiagnostic } from '../colors';
2
+ import type { DgmoError } from '../diagnostics';
2
3
  import type { PaletteColors } from '../palettes';
3
4
  import { makeDgmoError, formatDgmoError, suggest } from '../diagnostics';
4
5
  import {
@@ -103,16 +104,33 @@ interface ArrowInfo {
103
104
  color?: string;
104
105
  }
105
106
 
106
- function parseArrowToken(token: string, palette?: PaletteColors): ArrowInfo {
107
+ function parseArrowToken(
108
+ token: string,
109
+ palette: PaletteColors | undefined,
110
+ lineNumber: number,
111
+ diagnostics: DgmoError[]
112
+ ): ArrowInfo {
107
113
  if (token === '->') return {};
108
114
  const colorOnly = token.match(/^-\(([^)]+)\)->$/);
109
115
  if (colorOnly)
110
- return { color: resolveColor(colorOnly[1].trim(), palette) ?? undefined };
116
+ return {
117
+ color: resolveColorWithDiagnostic(
118
+ colorOnly[1].trim(),
119
+ lineNumber,
120
+ diagnostics,
121
+ palette
122
+ ),
123
+ };
111
124
  const m = token.match(/^-(.+?)(?:\(([^)]+)\))?->$/);
112
125
  if (m) {
113
126
  const label = m[1]?.trim() || undefined;
114
127
  const color = m[2]
115
- ? (resolveColor(m[2].trim(), palette) ?? undefined)
128
+ ? resolveColorWithDiagnostic(
129
+ m[2].trim(),
130
+ lineNumber,
131
+ diagnostics,
132
+ palette
133
+ )
116
134
  : undefined;
117
135
  return { label, color };
118
136
  }
@@ -265,7 +283,12 @@ export function parseState(
265
283
  const groupLabel = groupMatch[1].trim();
266
284
  const groupColorName = groupMatch[2]?.trim();
267
285
  const groupColor = groupColorName
268
- ? resolveColor(groupColorName, palette)
286
+ ? resolveColorWithDiagnostic(
287
+ groupColorName,
288
+ lineNumber,
289
+ result.diagnostics,
290
+ palette
291
+ )
269
292
  : undefined;
270
293
 
271
294
  currentGroup = {
@@ -352,7 +375,12 @@ export function parseState(
352
375
  const seg = segments[j];
353
376
 
354
377
  if (seg === '->' || /^-.+->$/.test(seg)) {
355
- pendingArrow = parseArrowToken(seg, palette);
378
+ pendingArrow = parseArrowToken(
379
+ seg,
380
+ palette,
381
+ lineNumber,
382
+ result.diagnostics
383
+ );
356
384
  continue;
357
385
  }
358
386
 
package/src/index.ts CHANGED
@@ -414,7 +414,15 @@ export type {
414
414
  // Colors & Palettes
415
415
  // ============================================================
416
416
 
417
- export { resolveColor, colorNames, nord, seriesColors } from './colors';
417
+ export {
418
+ resolveColor,
419
+ resolveColorWithDiagnostic,
420
+ colorNames,
421
+ nord,
422
+ seriesColors,
423
+ RECOGNIZED_COLOR_NAMES,
424
+ isRecognizedColorName,
425
+ } from './colors';
418
426
 
419
427
  export {
420
428
  // Registry
@@ -7,6 +7,7 @@
7
7
  // and connections, [Group] containers, tag groups, pipe metadata.
8
8
 
9
9
  import { makeDgmoError, formatDgmoError, suggest } from '../diagnostics';
10
+ import { resolveColorWithDiagnostic } from '../colors';
10
11
  import {
11
12
  measureIndent,
12
13
  parseFirstLine,
@@ -349,9 +350,14 @@ export function parseInfra(content: string): ParsedInfra {
349
350
  const tvMatch = cleanEntry.match(TAG_VALUE_RE);
350
351
  if (tvMatch) {
351
352
  const valueName = tvMatch[1].trim();
353
+ const rawColor = tvMatch[2]?.trim();
354
+ if (rawColor) {
355
+ // Validate the color name; emit diagnostic if invalid
356
+ resolveColorWithDiagnostic(rawColor, lineNumber, result.diagnostics);
357
+ }
352
358
  currentTagGroup.values.push({
353
359
  name: valueName,
354
- color: tvMatch[2]?.trim(),
360
+ color: rawColor,
355
361
  });
356
362
  if (isDefault) {
357
363
  currentTagGroup.defaultValue = valueName;
@@ -1,6 +1,6 @@
1
1
  import type { PaletteColors } from '../palettes';
2
2
  import { makeDgmoError, formatDgmoError, suggest } from '../diagnostics';
3
- import { resolveColor } from '../colors';
3
+ import { resolveColorWithDiagnostic } from '../colors';
4
4
  import {
5
5
  matchTagBlockHeading,
6
6
  stripDefaultModifier,
@@ -237,7 +237,12 @@ export function parseKanban(
237
237
  columnCounter++;
238
238
  const colName = columnMatch[1].trim();
239
239
  const colColor = columnMatch[2]
240
- ? (resolveColor(columnMatch[2].trim(), palette) ?? undefined)
240
+ ? resolveColorWithDiagnostic(
241
+ columnMatch[2].trim(),
242
+ lineNumber,
243
+ result.diagnostics,
244
+ palette
245
+ )
241
246
  : undefined;
242
247
 
243
248
  // Parse pipe metadata (e.g., "| wip: 3, t: Sprint1")
@@ -298,7 +303,8 @@ export function parseKanban(
298
303
  lineNumber,
299
304
  cardCounter,
300
305
  aliasMap,
301
- palette
306
+ palette,
307
+ result.diagnostics
302
308
  );
303
309
  // Cascade column metadata to card tags (card overrides on conflict)
304
310
  // Exclude 'wip' from cascading — it's a column-level property, not a card tag
@@ -381,7 +387,8 @@ function parseCardLine(
381
387
  lineNumber: number,
382
388
  counter: number,
383
389
  aliasMap: Map<string, string>,
384
- palette?: PaletteColors
390
+ palette?: PaletteColors,
391
+ diagnostics?: import('../diagnostics').DgmoError[]
385
392
  ): KanbanCard {
386
393
  // Split on first pipe: Title | tag: value, tag: value
387
394
  const pipeIdx = trimmed.indexOf('|');
@@ -396,7 +403,12 @@ function parseCardLine(
396
403
  }
397
404
 
398
405
  // Extract optional color suffix from title
399
- const { label: title, color } = extractColor(rawTitle, palette);
406
+ const { label: title, color } = extractColor(
407
+ rawTitle,
408
+ palette,
409
+ diagnostics,
410
+ lineNumber
411
+ );
400
412
 
401
413
  // Parse tags: comma-separated key: value pairs
402
414
  const tags: Record<string, string> = {};