@jarenjs/play 0.72.0 → 0.72.2

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/README.md CHANGED
@@ -49,7 +49,10 @@ The datasets list length is the whole story: **0** → the engine takes no
49
49
  data (markdown/mermaid); **1** → one dataset; **N** → a switcher that runs
50
50
  the *same* source over each shape. Adding an engine is a descriptor plus
51
51
  examples — the picker, panes and switcher all derive from the descriptor.
52
- See [docs/PLAY-FORMAT.md](docs/PLAY-FORMAT.md).
52
+ See [docs/PLAY-FORMAT.md](docs/PLAY-FORMAT.md) for descriptors and results,
53
+ and [ARCHITECTURE.md](ARCHITECTURE.md) for the state, action and run-loop
54
+ contract an embedding host supplies. Query, JSLT, JTLT and XQuery expose
55
+ an editable JSON externals pane.
53
56
 
54
57
  ## Exports
55
58
 
@@ -21,6 +21,10 @@ EnginePane = { key: string, label: string, control?: 'code' | 'text' }
21
21
  - `sourcePanes` are the engine's input(s): a JSONPath `selector`, a JSLT
22
22
  `stylesheet`, a JSON `patch`, a query + its `externals`, a markdown
23
23
  `source`. Editable in the playground.
24
+ Query, JSLT, JTLT and XQuery each expose an `externals` JSON pane; an
25
+ empty pane means `{}` and malformed JSON is attributed to that pane.
26
+ XQuery's Data pane supplies the declared `$doc` external and takes
27
+ precedence over an `externals.doc` member.
24
28
  - `dataPanes` are the JSON the engine runs against: usually one `data`; a
25
29
  patch's is its `target`; markdown / mermaid / charts have **none** — the
26
30
  source is everything.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jarenjs/play",
3
3
  "private": false,
4
- "version": "0.72.0",
4
+ "version": "0.72.2",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
7
7
  "types": "./dist/types/index.d.ts",
@@ -56,10 +56,10 @@
56
56
  "prepack": "npm run build:types"
57
57
  },
58
58
  "dependencies": {
59
- "@jarenjs/contract": "^0.72.0",
60
- "@jarenjs/core": "^0.72.0",
61
- "@jarenjs/josl": "^0.72.0",
62
- "@jarenjs/json": "^0.72.0",
63
- "@jarenjs/validate": "^0.72.0"
59
+ "@jarenjs/contract": "^0.72.2",
60
+ "@jarenjs/core": "^0.72.2",
61
+ "@jarenjs/josl": "^0.72.2",
62
+ "@jarenjs/json": "^0.72.2",
63
+ "@jarenjs/validate": "^0.72.2"
64
64
  }
65
65
  }
package/src/engines.js CHANGED
@@ -44,6 +44,12 @@ function parseJson(text, pane, label = pane) {
44
44
  catch (err) { return { error: `${label}: ${msg(err)}`, pane }; }
45
45
  }
46
46
 
47
+ /** The optional JSON bindings pane shared by every engine accepting externals. */
48
+ function parseExternals(source) {
49
+ return source.externals === undefined || String(source.externals).trim() === ''
50
+ ? { value: {} } : parseJson(source.externals, 'externals');
51
+ }
52
+
47
53
  /** A single-`code`-panel Result — the shape most engines return. */
48
54
  /** @returns {import('./index.js').PlayResult} */
49
55
  const ok = (text, compileMs, runMs, deep) => okPanels([{ id: 'out', label: 'Output', kind: 'code', text }, ...(deep ?? [])], compileMs, runMs);
@@ -295,16 +301,13 @@ export const ENGINE_LIST = [
295
301
  run(source, data, options) {
296
302
  const d = parseJson(data.data, 'data'); if (d.error) return failParse(d);
297
303
  const q = parseJson(source.query, 'query'); if (q.error) return failParse(q);
298
- let externals = {};
299
- if (source.externals !== undefined && String(source.externals).trim() !== '') {
300
- const e = parseJson(source.externals, 'externals'); if (e.error) return failParse(e); externals = e.value;
301
- }
304
+ const e = parseExternals(source); if (e.error) return failParse(e);
302
305
  let fn; const t0 = now();
303
306
  try { fn = compileJsonQuery(q.value, compileOptions(options)); }
304
307
  catch (err) { return fail(msg(err), code(err), locate(err, 'query')); }
305
308
  const t1 = now();
306
309
  let out;
307
- try { out = fn(d.value, externals); }
310
+ try { out = fn(d.value, e.value); }
308
311
  catch (err) { return fail(msg(err), code(err), locate(err, 'query')); }
309
312
  const t2 = now();
310
313
  const items = out === undefined ? 0 : Array.isArray(out) ? out.length : 1;
@@ -319,17 +322,18 @@ export const ENGINE_LIST = [
319
322
  },
320
323
  {
321
324
  id: 'jslt', label: 'JSLT', lead: 'JSON stylesheet transform (registered operators included).',
322
- sourcePanes: [{ key: 'stylesheet', label: 'Stylesheet', control: 'code' }],
325
+ sourcePanes: [{ key: 'stylesheet', label: 'Stylesheet', control: 'code' }, { key: 'externals', label: 'Externals', control: 'code' }],
323
326
  dataPanes: [{ key: 'data', label: 'Data' }],
324
327
  run(source, data, options) {
325
328
  const d = parseJson(data.data, 'data'); if (d.error) return failParse(d);
326
329
  const s = parseJson(source.stylesheet, 'stylesheet'); if (s.error) return failParse(s);
330
+ const e = parseExternals(source); if (e.error) return failParse(e);
327
331
  let compiled; const t0 = now();
328
332
  try { compiled = compileJsltStylesheet(s.value, compileOptions(options)); }
329
333
  catch (err) { return fail(msg(err), code(err), locate(err, 'stylesheet')); }
330
334
  const t1 = now();
331
335
  let out;
332
- try { out = compiled(d.value); }
336
+ try { out = compiled(d.value, e.value); }
333
337
  catch (err) { return fail(msg(err), code(err), locate(err, 'stylesheet')); }
334
338
  const t2 = now();
335
339
  // the identity lesson: a rule that changes nothing hands the INPUT back
@@ -345,17 +349,18 @@ export const ENGINE_LIST = [
345
349
  },
346
350
  {
347
351
  id: 'jtlt', label: 'JTLT', lead: 'JSLT\'s text front-end — render JSON as Markdown, XML or code.',
348
- sourcePanes: [{ key: 'template', label: 'Template', control: 'code' }],
352
+ sourcePanes: [{ key: 'template', label: 'Template', control: 'code' }, { key: 'externals', label: 'Externals', control: 'code' }],
349
353
  dataPanes: [{ key: 'data', label: 'Data' }],
350
354
  run(source, data, options) {
351
355
  const d = parseJson(data.data, 'data'); if (d.error) return failParse(d);
352
356
  const t = parseJson(source.template, 'template'); if (t.error) return failParse(t);
357
+ const e = parseExternals(source); if (e.error) return failParse(e);
353
358
  let render; const t0 = now();
354
359
  try { render = compileJtltStylesheet(t.value, compileOptions(options)); }
355
360
  catch (err) { return fail(msg(err), code(err), locate(err, 'template')); }
356
361
  const t1 = now();
357
362
  let out;
358
- try { out = render(d.value); }
363
+ try { out = render(d.value, e.value); }
359
364
  catch (err) { return fail(msg(err), code(err), locate(err, 'template')); }
360
365
  const t2 = now();
361
366
  // JTLT emits TEXT (markdown / xml / source) — show it verbatim, not fmt'd
@@ -367,11 +372,12 @@ export const ENGINE_LIST = [
367
372
  },
368
373
  {
369
374
  id: 'xquery', label: 'XQuery', lead: 'The XQuery 3.1 text subset — parsed to a query document and run over $doc.',
370
- sourcePanes: [{ key: 'text', label: 'XQuery', control: 'code' }],
375
+ sourcePanes: [{ key: 'text', label: 'XQuery', control: 'code' }, { key: 'externals', label: 'Externals', control: 'code' }],
371
376
  dataPanes: [{ key: 'data', label: 'Data' }],
372
377
  run(source, data, options) {
373
378
  const d = parseJson(data.data, 'data'); if (d.error) return failParse(d);
374
379
  let doc, fn; const t0 = now();
380
+ const e = parseExternals(source); if (e.error) return failParse(e);
375
381
  // two phases: the text parses (a syntax error locates a position in
376
382
  // the XQuery pane), then the GENERATED query document compiles and
377
383
  // runs — a location in that document has no pane the learner typed
@@ -382,7 +388,7 @@ export const ENGINE_LIST = [
382
388
  const t1 = now();
383
389
  let out;
384
390
  try {
385
- const externals = fn.externals.includes('doc') ? { doc: d.value } : {};
391
+ const externals = fn.externals.includes('doc') ? { ...e.value, doc: d.value } : e.value;
386
392
  out = fn(d.value, externals);
387
393
  }
388
394
  catch (err) { return fail(msg(err), code(err), locate(err)); }