@markii/stdlib 0.15.0 → 0.17.0-next.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.
@@ -22,8 +22,18 @@
22
22
  * `'unsafe-image-src'` — a component-built `<img>` (the standard `figure`)
23
23
  * had its `src` refused as an unsafe URL scheme; the component rendered
24
24
  * without the image, with a quiet marker.
25
+ *
26
+ * `'form-mismatch'` — a registered block component was written as an
27
+ * inline directive (`:callout[x]`); it rendered as the inline fallback
28
+ * marker instead of the component.
29
+ *
30
+ * `'no-engine-view'` — a directive names a component of an INSTALLED pack
31
+ * that ships no view for this render engine (a React-only pack in the
32
+ * terminal, a terminal-only component in an editor preview). It rendered
33
+ * the fallback box, labeled as a missing view rather than an unknown
34
+ * component. Only reported when the host passed `unavailableComponents`.
25
35
  */
26
- export type DiagnosticKind = 'invalid-attribute-value' | 'unsafe-image-src';
36
+ export type DiagnosticKind = 'invalid-attribute-value' | 'unsafe-image-src' | 'form-mismatch' | 'no-engine-view';
27
37
  export interface DiagnosticEvent {
28
38
  readonly kind: DiagnosticKind;
29
39
  /** The directive name the event happened on, when there is a single unambiguous one. */
@@ -43,3 +53,29 @@ export type OnDiagnostic = (event: DiagnosticEvent) => void;
43
53
  * guard cannot drift between them.
44
54
  */
45
55
  export declare function reportDiagnostic(onDiagnostic: OnDiagnostic | undefined, event: DiagnosticEvent): void;
56
+ /**
57
+ * One component of an installed pack that the current render cannot draw,
58
+ * as plain data a host hands to a renderer's `unavailableComponents`
59
+ * option. The renderer uses it only to tell this case apart from a typo:
60
+ * the fallback box keeps its structure and the label changes.
61
+ *
62
+ * `directive` is the composed directive name (`ana_meter`), `pack` the
63
+ * pack's namespace, and `engines` the engine ids (`react`, `ansi`) the
64
+ * component DOES ship a view for.
65
+ */
66
+ export interface UnavailableComponent {
67
+ readonly directive: string;
68
+ readonly pack: string;
69
+ readonly engines: readonly string[];
70
+ }
71
+ /** A lookup from a directive name to its `UnavailableComponent`, or `undefined`. */
72
+ export type UnavailableComponentLookup = (directive: string) => UnavailableComponent | undefined;
73
+ /**
74
+ * Builds the lookup a renderer queries per directive. Backed by a `Map`
75
+ * (never a plain object), so a directive named `constructor` or
76
+ * `__proto__` cannot resolve through the prototype chain. An omitted or
77
+ * empty list gives `undefined`, so a renderer given no option takes
78
+ * exactly the path it took before the option existed. Entries that are not
79
+ * well-formed are skipped, and the first entry for a name wins.
80
+ */
81
+ export declare function createUnavailableComponentLookup(components: readonly UnavailableComponent[] | undefined): UnavailableComponentLookup | undefined;
@@ -32,3 +32,35 @@ export function reportDiagnostic(onDiagnostic, event) {
32
32
  // A throwing callback must never break rendering.
33
33
  }
34
34
  }
35
+ /**
36
+ * Builds the lookup a renderer queries per directive. Backed by a `Map`
37
+ * (never a plain object), so a directive named `constructor` or
38
+ * `__proto__` cannot resolve through the prototype chain. An omitted or
39
+ * empty list gives `undefined`, so a renderer given no option takes
40
+ * exactly the path it took before the option existed. Entries that are not
41
+ * well-formed are skipped, and the first entry for a name wins.
42
+ */
43
+ export function createUnavailableComponentLookup(components) {
44
+ if (!Array.isArray(components) || components.length === 0)
45
+ return undefined;
46
+ const byName = new Map();
47
+ for (const entry of components) {
48
+ if (entry === null || typeof entry !== 'object')
49
+ continue;
50
+ const { directive, pack, engines } = entry;
51
+ if (typeof directive !== 'string' || typeof pack !== 'string')
52
+ continue;
53
+ if (!Array.isArray(engines))
54
+ continue;
55
+ if (byName.has(directive))
56
+ continue;
57
+ byName.set(directive, {
58
+ directive,
59
+ pack,
60
+ engines: engines.filter((e) => typeof e === 'string'),
61
+ });
62
+ }
63
+ if (byName.size === 0)
64
+ return undefined;
65
+ return (directive) => byName.get(directive);
66
+ }
package/dist/index.d.ts CHANGED
@@ -3,5 +3,5 @@ export { ALIGN_PRESETS, LAYOUT_ATTRIBUTE_KEYS, LAYOUT_ATTRIBUTES, WIDTH_PRESETS,
3
3
  export { TEXT_ALIGN_ATTRIBUTE, TEXT_ALIGN_COMPONENTS, TEXT_ALIGN_PRESETS, type TextAlignPreset, } from './text-align.js';
4
4
  export { formatValue, isNumericLike, FORMAT_ATTRIBUTE, DECIMALS_ATTRIBUTE, type ValueFormat, } from './value-format.js';
5
5
  export { deriveTableShape, type TableShape } from './table-shape.js';
6
- export { reportDiagnostic, type DiagnosticEvent, type DiagnosticKind, type OnDiagnostic, } from './diagnostics.js';
6
+ export { reportDiagnostic, createUnavailableComponentLookup, type UnavailableComponent, type UnavailableComponentLookup, type DiagnosticEvent, type DiagnosticKind, type OnDiagnostic, } from './diagnostics.js';
7
7
  export { INTERACTIVE_ATTRIBUTE } from './interactive.js';
package/dist/index.js CHANGED
@@ -3,5 +3,5 @@ export { ALIGN_PRESETS, LAYOUT_ATTRIBUTE_KEYS, LAYOUT_ATTRIBUTES, WIDTH_PRESETS,
3
3
  export { TEXT_ALIGN_ATTRIBUTE, TEXT_ALIGN_COMPONENTS, TEXT_ALIGN_PRESETS, } from './text-align.js';
4
4
  export { formatValue, isNumericLike, FORMAT_ATTRIBUTE, DECIMALS_ATTRIBUTE, } from './value-format.js';
5
5
  export { deriveTableShape } from './table-shape.js';
6
- export { reportDiagnostic, } from './diagnostics.js';
6
+ export { reportDiagnostic, createUnavailableComponentLookup, } from './diagnostics.js';
7
7
  export { INTERACTIVE_ATTRIBUTE } from './interactive.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markii/stdlib",
3
- "version": "0.15.0",
3
+ "version": "0.17.0-next.0",
4
4
  "description": "Neutral, framework-agnostic standard component contracts for Mark (.mk.md) — the kind/attribute-schema seam every renderer (e.g. @markii/react) implements against. No React, zero dependencies.",
5
5
  "keywords": [
6
6
  "markdown",