mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
57 lines
2.1 KiB
TypeScript
57 lines
2.1 KiB
TypeScript
/**
|
|
* JSON pretty-printer for Vega-Lite specs (spec §03A; docs/architecture/08 →
|
|
* "compact formatter").
|
|
*
|
|
* Uses `json-stringify-pretty-compact` for Vega's house style — arrays/objects
|
|
* stay on one line until they exceed a width budget, then wrap — which reads far
|
|
* better for VL specs than `JSON.stringify(…, null, 2)`. Pure and portable: no
|
|
* Monaco, no browser. The Monaco formatting adapter
|
|
* (`infrastructure/monaco-format`) is a thin wrapper over this.
|
|
*/
|
|
|
|
import stringify from 'json-stringify-pretty-compact';
|
|
|
|
/** Width budget before an array/object wraps onto multiple lines. */
|
|
const DEFAULT_MAX_LINE = 80;
|
|
|
|
/** Default indent (spaces) — matches the editor's default tab size (spec §07). */
|
|
const DEFAULT_INDENT = 2;
|
|
|
|
/**
|
|
* Pretty-print a spec *object* (not text) in the same Vega house style as
|
|
* {@link formatJson}. Object-in callers — the lesson source panes, anything that
|
|
* holds a spec as a parsed value — use this so their rendered JSON matches the
|
|
* editor's formatting exactly. Key order is the object's own insertion order,
|
|
* deliberately: where consecutive specs are small edits of one another (a lesson's
|
|
* 80%→100% chain), a stable order is what keeps a line-diff between them legible.
|
|
*/
|
|
export function formatSpec(
|
|
value: unknown,
|
|
opts: { indent?: number; maxLength?: number } = {},
|
|
): string {
|
|
return stringify(value, {
|
|
indent: opts.indent ?? DEFAULT_INDENT,
|
|
maxLength: opts.maxLength ?? DEFAULT_MAX_LINE,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Reformat `text` as consistently-indented JSON, or return `null` when it is not
|
|
* valid JSON. Returning `null` (rather than throwing) lets callers skip a no-op
|
|
* rather than mangle an in-progress edit, mirroring auto-save's "skip when
|
|
* unparseable" rule (spec §03B). The result is idempotent: formatting
|
|
* already-formatted text returns it unchanged.
|
|
*/
|
|
export function formatJson(
|
|
text: string,
|
|
opts: { indent?: number; maxLength?: number } = {},
|
|
): string | null {
|
|
let parsed: unknown;
|
|
try {
|
|
parsed = JSON.parse(text);
|
|
} catch {
|
|
return null;
|
|
}
|
|
return formatSpec(parsed, opts);
|
|
}
|