@rohal12/spindle 0.58.0 → 0.59.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/src/tooling.ts CHANGED
@@ -11,8 +11,11 @@ import {
11
11
  } from './markup/validate';
12
12
  import { isBlockMacro } from './markup/ast';
13
13
  import { tokenizeMarkupTolerant } from './markup/parse';
14
- import { collectPassageReferences, type PassageReference } from './code-check';
15
- import { subMacroParameters } from './components/macros/option-utils';
14
+ import {
15
+ collectPassageReferences,
16
+ parameterLookup,
17
+ type PassageReference,
18
+ } from './code-check';
16
19
  import { blockWidgetNames } from './widgets/widget-def';
17
20
  import type { ParameterDef } from './registry';
18
21
 
@@ -71,8 +74,13 @@ export interface ToolingMacro {
71
74
  name: string;
72
75
  block: boolean;
73
76
  subMacros: string[];
74
- /** Its declared parameters: their types tell which arguments are code. */
77
+ /**
78
+ * Its declared parameters: their types tell which arguments are code, and
79
+ * what a `string` or `text` argument holds (see ParameterDef.holds).
80
+ */
75
81
  parameters?: readonly ParameterDef[];
82
+ /** Whether it resolves markup: its strings hold markup by default. */
83
+ interpolate?: boolean;
76
84
  }
77
85
 
78
86
  /**
@@ -87,20 +95,19 @@ export function validateStoryMarkup(
87
95
  options: ValidateMarkupOptions = {},
88
96
  ): MarkupDiagnostic[] {
89
97
  const list = [...passages];
98
+ const all = [...macros];
90
99
  const known = new Set<string>();
91
- const parameters = new Map<string, readonly ParameterDef[] | undefined>();
92
100
  const blocks = new Set(blockWidgetNames(list).map((n) => n.toLowerCase()));
93
- for (const macro of macros) {
101
+ for (const macro of all) {
94
102
  const name = macro.name.toLowerCase();
95
103
  known.add(name);
96
- parameters.set(name, macro.parameters);
97
104
  for (const sub of macro.subMacros) known.add(sub.toLowerCase());
98
105
  if (macro.block) blocks.add(name);
99
106
  }
100
107
  return validateMarkup(list, {
101
108
  isKnownMacro: (name) => known.has(name),
102
109
  macroNames: known,
103
- parametersOf: (name) => parameters.get(name),
110
+ parametersOf: parameterLookup(all),
104
111
  isBlockMacro: (name) =>
105
112
  blocks.has(name.toLowerCase()) || isBlockMacro(name),
106
113
  checkPassageNames: options.checkPassageNames,
@@ -116,14 +123,6 @@ export function collectStoryPassageReferences(
116
123
  source: string,
117
124
  macros: Iterable<ToolingMacro>,
118
125
  ): PassageReference[] {
119
- const parameters = new Map<string, readonly ParameterDef[] | undefined>();
120
- for (const macro of macros) {
121
- parameters.set(macro.name.toLowerCase(), macro.parameters);
122
- }
123
126
  const { tokens } = tokenizeMarkupTolerant(source);
124
- return collectPassageReferences(
125
- source,
126
- tokens,
127
- (name) => parameters.get(name.toLowerCase()) ?? subMacroParameters(name),
128
- );
127
+ return collectPassageReferences(source, tokens, parameterLookup(macros));
129
128
  }
@@ -7,8 +7,8 @@ import type { MacroArgs } from '../registry';
7
7
 
8
8
  /** A {widget} definition's name, then its `@` parameters. */
9
9
  export const WIDGET_PARAMETERS = [
10
- { name: 'name', type: 'text', required: true },
11
- { name: 'parameters', type: 'text' },
10
+ { name: 'name', type: 'text', holds: 'text', required: true },
11
+ { name: 'parameters', type: 'text', holds: 'text' },
12
12
  ] as const;
13
13
 
14
14
  export interface WidgetDef {
package/types/index.d.ts CHANGED
@@ -272,6 +272,27 @@ export type ParameterType =
272
272
  | 'separator'
273
273
  | 'options';
274
274
 
275
+ /**
276
+ * What the value of a `string` or `text` argument holds, for the check at
277
+ * story start and for tooling:
278
+ * - `markup`: markup the macro renders (`{button}`'s label): its markup
279
+ * is checked.
280
+ * - `text`: plain text the macro uses as written (`{checkbox}`'s label).
281
+ * - `passage`: a passage name (`{watch}`'s `goto`): the passage must exist.
282
+ * - `expression`, `statements`: code (`{watch}`'s condition and `run`): it
283
+ * is checked as code, and its variable references against the schema.
284
+ *
285
+ * Without it, the argument of a macro with `interpolate` holds `markup`,
286
+ * any other `text`.
287
+ * @see {@link ../../src/registry.ts} for the implementation.
288
+ */
289
+ export type StringHolds =
290
+ | 'markup'
291
+ | 'text'
292
+ | 'passage'
293
+ | 'expression'
294
+ | 'statements';
295
+
275
296
  /**
276
297
  * Parameter metadata for a macro definition.
277
298
  * @see {@link ../../src/registry.ts} for the implementation.
@@ -282,6 +303,8 @@ export interface ParameterDef {
282
303
  description?: string;
283
304
  /** How the argument is read: required, there is no default. */
284
305
  type: ParameterType;
306
+ /** What a `string` or `text` argument holds (see StringHolds). */
307
+ holds?: StringHolds;
285
308
  /** The options of an `options` parameter. */
286
309
  parameters?: readonly ParameterDef[];
287
310
  }
@@ -30,12 +30,34 @@ export type ParameterType =
30
30
  | 'separator'
31
31
  | 'options';
32
32
 
33
+ /**
34
+ * What the value of a `string` or `text` argument holds, for the check at
35
+ * story start and for tooling:
36
+ * - `markup`: markup the macro renders (`{button}`'s label): its markup
37
+ * is checked.
38
+ * - `text`: plain text the macro uses as written (`{checkbox}`'s label).
39
+ * - `passage`: a passage name (`{watch}`'s `goto`): the passage must exist.
40
+ * - `expression`, `statements`: code (`{watch}`'s condition and `run`): it
41
+ * is checked as code, and its variable references against the schema.
42
+ *
43
+ * Without it, the argument of a macro with `interpolate` holds `markup`,
44
+ * any other `text`.
45
+ */
46
+ export type StringHolds =
47
+ | 'markup'
48
+ | 'text'
49
+ | 'passage'
50
+ | 'expression'
51
+ | 'statements';
52
+
33
53
  export interface ParameterDef {
34
54
  name: string;
35
55
  required?: boolean;
36
56
  description?: string;
37
57
  /** How the argument is read: required, there is no default. */
38
58
  type: ParameterType;
59
+ /** What a `string` or `text` argument holds (see StringHolds). */
60
+ holds?: StringHolds;
39
61
  /** The options of an `options` parameter. */
40
62
  parameters?: readonly ParameterDef[];
41
63
  }
@@ -285,6 +307,9 @@ export interface LinkToken extends TokenSpan, Selectors {
285
307
  type: 'link';
286
308
  display: string;
287
309
  target: string;
310
+ /** Where the target is written, from `targetStart` to `targetEnd`. */
311
+ targetStart: number;
312
+ targetEnd: number;
288
313
  }
289
314
 
290
315
  export interface MacroToken extends TokenSpan, Selectors {
@@ -465,8 +490,9 @@ export interface PassageReference {
465
490
  * The passages the markup of `source` names, in source order: `[[…]]` links,
466
491
  * the passage of `{goto}`, `{include}` and `{link}` (and of macros that
467
492
  * declare a `passage` argument), the `goto` and `dialog` actions of
468
- * `{watch}` and the body of `{dialog}`. Malformed tags are skipped, so
469
- * half-typed markup reads.
493
+ * `{watch}` (and the `string` and `text` arguments of macros that declare
494
+ * they hold a passage name) and the body of `{dialog}`. Malformed tags are
495
+ * skipped, so half-typed markup reads.
470
496
  */
471
497
  export declare function collectPassageReferences(
472
498
  source: string,