tutuca 0.9.93 → 0.9.95

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.
@@ -5800,1386 +5800,1549 @@ class LintParseContext extends ParseContext {
5800
5800
  }
5801
5801
  }
5802
5802
 
5803
- // tools/core/results.js
5804
- class ModuleInfo {
5805
- constructor({ path = null, present = new Set, counts = {}, warnings = [] }) {
5806
- this.path = path;
5807
- this.present = present;
5808
- this.counts = counts;
5809
- this.warnings = warnings;
5810
- }
5811
- }
5812
-
5813
- class ComponentSummary {
5814
- constructor({ name, views, fields }) {
5815
- this.name = name;
5816
- this.views = views;
5817
- this.fields = fields;
5818
- }
5819
- }
5820
-
5821
- class ComponentList {
5822
- constructor({ items, total = null, truncated = false }) {
5823
- this.items = items;
5824
- this.total = total ?? items.length;
5825
- this.truncated = truncated;
5803
+ // src/components.js
5804
+ class Components {
5805
+ constructor() {
5806
+ this.getComponentSymbol = Symbol("getComponent");
5807
+ this.byId = new Map;
5826
5808
  }
5827
- }
5828
-
5829
- class ExampleIndex {
5830
- constructor({ sections, total = null, truncated = false }) {
5831
- this.sections = sections;
5832
- this.total = total ?? sections.reduce((n, s) => n + (s.items?.length ?? 0), 0);
5833
- this.truncated = truncated;
5809
+ registerComponent(comp) {
5810
+ comp.Class.prototype[this.getComponentSymbol] = () => comp;
5811
+ this.byId.set(comp.id, comp);
5834
5812
  }
5835
- }
5836
-
5837
- class ComponentDocs {
5838
- constructor({ items }) {
5839
- this.items = items;
5813
+ getComponentForId(id) {
5814
+ return this.byId.get(id) ?? null;
5840
5815
  }
5841
- }
5842
-
5843
- class LintFinding {
5844
- constructor({ id, level, info, context = {}, suggestion = null }) {
5845
- this.id = id;
5846
- this.level = level;
5847
- this.info = info;
5848
- this.context = context;
5849
- this.suggestion = suggestion;
5816
+ getCompFor(v) {
5817
+ return v?.[this.getComponentSymbol]?.() ?? null;
5850
5818
  }
5851
- }
5852
-
5853
- class LintComponentResult {
5854
- constructor({ componentName, findings }) {
5855
- this.componentName = componentName;
5856
- this.findings = findings;
5819
+ getHandlerFor(v, name, key) {
5820
+ return this.getCompFor(v)?.[key][name] ?? null;
5857
5821
  }
5858
- get errorCount() {
5859
- return this.findings.filter((f) => f.level === "error").length;
5822
+ getRequestFor(v, name) {
5823
+ return this.getCompFor(v)?.scope.lookupRequest(name) ?? null;
5860
5824
  }
5861
- get warnCount() {
5862
- return this.findings.filter((f) => f.level === "warn").length;
5825
+ compileStyles() {
5826
+ const styles = [];
5827
+ for (const comp of this.byId.values())
5828
+ styles.push(comp.compileStyle());
5829
+ return styles.join(`
5830
+ `);
5863
5831
  }
5864
5832
  }
5865
5833
 
5866
- class LintReport {
5867
- constructor({ components }) {
5868
- this.components = components;
5869
- }
5870
- get hasErrors() {
5871
- return this.components.some((c) => c.errorCount > 0);
5834
+ class ComponentStack {
5835
+ constructor(comps = new Components, parent = null) {
5836
+ this.comps = comps;
5837
+ this.parent = parent;
5838
+ this.byName = {};
5839
+ this.reqsByName = {};
5840
+ this.macros = {};
5872
5841
  }
5873
- get totalErrors() {
5874
- return this.components.reduce((n, c) => n + c.errorCount, 0);
5842
+ enter() {
5843
+ return new ComponentStack(this.comps, this);
5875
5844
  }
5876
- get totalWarnings() {
5877
- return this.components.reduce((n, c) => n + c.warnCount, 0);
5845
+ registerComponents(comps, opts) {
5846
+ const { aliases = {} } = opts ?? {};
5847
+ for (let i = 0;i < comps.length; i++) {
5848
+ const comp = comps[i];
5849
+ comp.scope = this.enter();
5850
+ comp.Class.scope = comp.scope;
5851
+ this.comps.registerComponent(comp);
5852
+ this.byName[comp.name] = comp;
5853
+ }
5854
+ for (const alias in aliases) {
5855
+ const comp = this.byName[aliases[alias]];
5856
+ console.assert(this.byName[alias] === undefined, "alias overrides component", alias);
5857
+ if (comp !== undefined)
5858
+ this.byName[alias] = comp;
5859
+ else
5860
+ console.warn("alias", alias, "to inexistent component", aliases[alias]);
5861
+ }
5878
5862
  }
5879
- }
5880
-
5881
- class RenderedExample {
5882
- constructor({ title, description = null, componentName, view, html, error = null }) {
5883
- this.title = title;
5884
- this.description = description;
5885
- this.componentName = componentName;
5886
- this.view = view;
5887
- this.html = html;
5888
- this.error = error;
5863
+ registerMacros(macros) {
5864
+ for (const key in macros) {
5865
+ const lower = key.toLowerCase();
5866
+ console.assert(this.macros[lower] === undefined, "macro key collision", lower);
5867
+ this.macros[lower] = macros[key];
5868
+ }
5889
5869
  }
5890
- }
5891
-
5892
- class RenderedSection {
5893
- constructor({ title, description = null, items }) {
5894
- this.title = title;
5895
- this.description = description;
5896
- this.items = items;
5870
+ getCompFor(v) {
5871
+ return this.comps.getCompFor(v);
5897
5872
  }
5898
- }
5899
-
5900
- class RenderBatch {
5901
- constructor({ sections }) {
5902
- this.sections = sections;
5873
+ registerRequestHandlers(handlers) {
5874
+ for (const name in handlers)
5875
+ this.reqsByName[name] = new RequestHandler(name, handlers[name]);
5903
5876
  }
5904
- get hasErrors() {
5905
- return this.sections.some((s) => s.items.some((i) => i.error !== null));
5877
+ lookupRequest(name) {
5878
+ return this.reqsByName[name] ?? this.parent?.lookupRequest(name) ?? null;
5906
5879
  }
5907
- }
5908
-
5909
- class TestResult {
5910
- constructor({ title, fullPath, componentName = null, status, durationMs = 0, error = null }) {
5911
- this.title = title;
5912
- this.fullPath = fullPath;
5913
- this.componentName = componentName;
5914
- this.status = status;
5915
- this.durationMs = durationMs;
5916
- this.error = error;
5880
+ lookupComponent(name) {
5881
+ return this.byName[name] ?? this.parent?.lookupComponent(name) ?? null;
5917
5882
  }
5918
- }
5919
-
5920
- class DescribeResult {
5921
- constructor({ title, componentName = null, children = [] }) {
5922
- this.title = title;
5923
- this.componentName = componentName;
5924
- this.children = children;
5883
+ lookupMacro(name) {
5884
+ return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
5925
5885
  }
5926
5886
  }
5927
5887
 
5928
- class ModuleTestReport {
5929
- constructor({ path = null, suites = [], counts = { pass: 0, fail: 0, skip: 0, total: 0 } }) {
5930
- this.path = path;
5931
- this.suites = suites;
5932
- this.counts = counts;
5888
+ class ProvideInfo {
5889
+ constructor(name, val, symbol) {
5890
+ this.name = name;
5891
+ this.val = val;
5892
+ this.symbol = symbol;
5933
5893
  }
5934
5894
  }
5935
5895
 
5936
- class TestReport {
5937
- constructor({ modules = [] }) {
5938
- this.modules = modules;
5939
- }
5940
- get totals() {
5941
- return this.modules.reduce((acc, m) => ({
5942
- pass: acc.pass + m.counts.pass,
5943
- fail: acc.fail + m.counts.fail,
5944
- skip: acc.skip + m.counts.skip,
5945
- total: acc.total + m.counts.total
5946
- }), { pass: 0, fail: 0, skip: 0, total: 0 });
5896
+ class LookupInfo {
5897
+ constructor(name, compName, provideName, val) {
5898
+ this.name = name;
5899
+ this.compName = compName;
5900
+ this.provideName = provideName;
5901
+ this.val = val;
5902
+ this._sym = undefined;
5947
5903
  }
5948
- get hasFailures() {
5949
- return this.modules.some((m) => m.counts.fail > 0);
5904
+ getProducerSymbol(stack) {
5905
+ if (this._sym === undefined)
5906
+ this._sym = stack.lookupType(this.compName)?.provide?.[this.provideName]?.symbol ?? null;
5907
+ return this._sym;
5950
5908
  }
5951
5909
  }
5910
+ var isString = (v) => typeof v === "string";
5911
+ var _rawSpecKeys = "name view style commonStyle globalStyle input receive bubble response alter views provide lookup fields methods statics";
5912
+ var KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
5913
+ var _compId = 0;
5952
5914
 
5953
- // tools/core/tests.js
5954
- class Describe {
5955
- constructor({ title, componentName = null, parent = null }) {
5956
- this.title = title;
5957
- this.componentName = componentName;
5958
- this.parent = parent;
5959
- this.children = [];
5915
+ class Component {
5916
+ constructor(Class, o) {
5917
+ this.id = _compId++;
5918
+ this.name = o.name ?? "UnkComp";
5919
+ this.Class = Class;
5920
+ this.views = { main: new View("main", o.view, o.style) };
5921
+ this.commonStyle = o.commonStyle ?? "";
5922
+ this.globalStyle = o.globalStyle ?? "";
5923
+ this.input = o.input ?? {};
5924
+ this.receive = o.receive ?? {};
5925
+ this.bubble = o.bubble ?? {};
5926
+ this.response = o.response ?? {};
5927
+ this.alter = o.alter ?? {};
5928
+ for (const name in o.views ?? {}) {
5929
+ const v = o.views[name];
5930
+ const { view, style } = isString(v) ? { view: v } : v;
5931
+ this.views[name] = new View(name, view, style);
5932
+ }
5933
+ this._rawProvide = o.provide ?? {};
5934
+ this._rawLookup = o.lookup ?? {};
5935
+ this.provide = {};
5936
+ this.lookup = {};
5937
+ this.scope = null;
5938
+ this.spec = o;
5939
+ this.extra = {};
5940
+ for (const key of Object.keys(o))
5941
+ if (!KNOWN_SPEC_KEYS.has(key))
5942
+ this.extra[key] = o[key];
5960
5943
  }
5961
- }
5962
-
5963
- class Test {
5964
- constructor({ title, fn, componentName = null, parent = null }) {
5965
- this.title = title;
5966
- this.fn = fn;
5967
- this.componentName = componentName;
5968
- this.parent = parent;
5944
+ clone() {
5945
+ return Component.fromSpec(this.spec);
5969
5946
  }
5970
- }
5971
-
5972
- class ModuleTests {
5973
- constructor({ path = null, suites = [] } = {}) {
5974
- this.path = path;
5975
- this.suites = suites;
5947
+ compile(ParseContext2) {
5948
+ for (const name in this.views)
5949
+ this.views[name].compile(new ParseContext2, this.scope, this.id);
5950
+ const ctx = this.views.main.ctx;
5951
+ for (const key in this._rawProvide) {
5952
+ const val = vp.parseProvide(this._rawProvide[key], ctx);
5953
+ if (val)
5954
+ this.provide[key] = new ProvideInfo(key, val, Symbol(key));
5955
+ }
5956
+ for (const key in this._rawLookup) {
5957
+ const linfo = this._rawLookup[key];
5958
+ const forStr = isString(linfo) ? linfo : isString(linfo?.for) ? linfo.for : null;
5959
+ const [compName, provideName] = forStr === null ? [] : forStr.split(".");
5960
+ if (!isString(compName) || !isString(provideName))
5961
+ continue;
5962
+ const defStr = isString(linfo?.default) ? linfo.default : null;
5963
+ const val = defStr === null ? null : vp.parseField(defStr, ctx);
5964
+ this.lookup[key] = new LookupInfo(key, compName, provideName, val);
5965
+ }
5966
+ for (const key in this.lookup)
5967
+ if (this.provide[key] !== undefined)
5968
+ console.warn("name declared in both provide and lookup", this.name, key);
5969
+ }
5970
+ make(args, opts) {
5971
+ return this.Class.make(args, opts ?? { scope: this.scope });
5972
+ }
5973
+ getView(name) {
5974
+ return this.views[name] ?? this.views.main;
5975
+ }
5976
+ getEventForId(id, name = "main") {
5977
+ return this.getView(name).ctx.getEventForId(id);
5978
+ }
5979
+ getNodeForId(id, name = "main") {
5980
+ return this.getView(name).ctx.getNodeForId(id);
5981
+ }
5982
+ compileStyle() {
5983
+ const { id, commonStyle, globalStyle, views } = this;
5984
+ const styles = commonStyle ? [`[data-cid="${id}"]{${commonStyle}}`] : [];
5985
+ if (globalStyle !== "")
5986
+ styles.push(globalStyle);
5987
+ for (const name in views) {
5988
+ const { style } = views[name];
5989
+ if (style !== "")
5990
+ styles.push(`[data-cid="${id}"][data-vid="${name}"]{${style}}`);
5991
+ }
5992
+ return styles.join(`
5993
+ `);
5976
5994
  }
5977
5995
  }
5978
5996
 
5979
- class TestIndex {
5980
- constructor({ modules = [] } = {}) {
5981
- this.modules = modules;
5982
- }
5997
+ // src/on.js
5998
+ var OP_KINDS = ["send", "bubble", "request", "input"];
5999
+ function phaseOps(phase) {
6000
+ const ops = [];
6001
+ for (const type of OP_KINDS)
6002
+ for (const a of phase[type] ?? [])
6003
+ ops.push({ type, ...a });
6004
+ for (const a of phase.do ?? [])
6005
+ ops.push(a);
6006
+ return ops;
5983
6007
  }
5984
- function isComponentObject(x) {
5985
- return x !== null && typeof x === "object" && typeof x.name === "string" && typeof x.Class === "function";
6008
+ function resolveArgs(args, self) {
6009
+ return typeof args === "function" ? args(self) ?? [] : args ?? [];
5986
6010
  }
5987
- function resolveComponentName(arg, components) {
5988
- if (isComponentObject(arg))
5989
- return arg.name;
5990
- if (typeof arg === "function") {
5991
- for (const c of components)
5992
- if (c.Class === arg)
5993
- return c.name;
6011
+ function dispatchPhase(dispatcher, targetPath, phase, self) {
6012
+ if (!phase)
6013
+ return;
6014
+ for (const op of phaseOps(phase)) {
6015
+ const args = resolveArgs(op.args, self);
6016
+ switch (op.type) {
6017
+ case "send":
6018
+ dispatcher.sendAtPath(targetPath, op.name, args, op.opts);
6019
+ break;
6020
+ case "bubble":
6021
+ dispatcher.sendAtPath(targetPath, op.name, args, {
6022
+ skipSelf: true,
6023
+ bubbles: true,
6024
+ ...op.opts
6025
+ });
6026
+ break;
6027
+ case "request":
6028
+ dispatcher.requestAtPath(targetPath, op.name, args, op.opts);
6029
+ break;
6030
+ case "input":
6031
+ dispatcher.inputAtPath(targetPath, op.name, args, op.opts);
6032
+ break;
6033
+ }
5994
6034
  }
5995
- return null;
5996
6035
  }
5997
- function titleFromArg(arg) {
5998
- if (typeof arg === "string")
5999
- return arg;
6000
- if (isComponentObject(arg))
6001
- return arg.name;
6002
- if (typeof arg === "function")
6003
- return arg.name || "(anonymous)";
6004
- return String(arg);
6036
+
6037
+ // src/stack.js
6038
+ var STOP = Symbol("STOP");
6039
+ var NEXT = Symbol("NEXT");
6040
+ function lookup(chain, name, dv = null) {
6041
+ let n = chain;
6042
+ while (n !== null) {
6043
+ const r = n[0].lookup(name);
6044
+ if (r === STOP)
6045
+ return dv;
6046
+ if (r !== NEXT)
6047
+ return r;
6048
+ n = n[1];
6049
+ }
6050
+ return dv;
6005
6051
  }
6006
- function makeCollector({ path = null, components = [] } = {}) {
6007
- const moduleTests = new ModuleTests({ path, suites: [] });
6008
- const stack = [];
6009
- function describe(...args) {
6010
- let head;
6011
- let options = null;
6012
- let fn;
6013
- if (args.length === 2) {
6014
- [head, fn] = args;
6015
- } else if (args.length === 3) {
6016
- [head, options, fn] = args;
6017
- } else {
6018
- throw new Error(`describe() expects 2 or 3 arguments, got ${args.length}`);
6019
- }
6020
- if (typeof fn !== "function") {
6021
- throw new Error(`describe(${JSON.stringify(titleFromArg(head))}): final argument must be a function`);
6022
- }
6023
- let componentName = null;
6024
- if (typeof head !== "string") {
6025
- componentName = resolveComponentName(head, components);
6026
- }
6027
- if (componentName === null && options && options.component != null) {
6028
- componentName = resolveComponentName(options.component, components);
6029
- }
6030
- if (componentName === null) {
6031
- const parent2 = stack.length ? stack[stack.length - 1] : null;
6032
- if (parent2)
6033
- componentName = parent2.componentName;
6034
- }
6035
- const parent = stack.length ? stack[stack.length - 1] : null;
6036
- const node = new Describe({
6037
- title: titleFromArg(head),
6038
- componentName,
6039
- parent
6040
- });
6041
- if (parent)
6042
- parent.children.push(node);
6043
- else
6044
- moduleTests.suites.push(node);
6045
- stack.push(node);
6046
- try {
6047
- fn();
6048
- } finally {
6049
- stack.pop();
6050
- }
6052
+
6053
+ class BindFrame {
6054
+ constructor(it, binds, isFrame) {
6055
+ this.it = it;
6056
+ this.binds = binds;
6057
+ this.isFrame = isFrame;
6051
6058
  }
6052
- function test(title, fn) {
6053
- if (typeof title !== "string") {
6054
- throw new Error("test(title, fn): title must be a string");
6055
- }
6056
- if (typeof fn !== "function") {
6057
- throw new Error(`test(${JSON.stringify(title)}): fn must be a function`);
6058
- }
6059
- const parent = stack.length ? stack[stack.length - 1] : null;
6060
- if (!parent) {
6061
- throw new Error(`test(${JSON.stringify(title)}) must be called inside a describe()`);
6062
- }
6063
- parent.children.push(new Test({
6064
- title,
6065
- fn,
6066
- componentName: parent.componentName,
6067
- parent
6068
- }));
6059
+ lookup(name) {
6060
+ const v = this.binds[name];
6061
+ return v === undefined ? this.isFrame ? STOP : NEXT : v;
6069
6062
  }
6070
- return { describe, test, moduleTests };
6071
6063
  }
6072
6064
 
6073
- // tools/core/test.js
6074
- function buildPath(node) {
6075
- const parts = [];
6076
- let cur = node;
6077
- while (cur) {
6078
- parts.unshift(cur.title);
6079
- cur = cur.parent;
6065
+ class ObjectFrame {
6066
+ constructor(binds) {
6067
+ this.binds = binds;
6068
+ }
6069
+ lookup(key) {
6070
+ const v = this.binds[key];
6071
+ return v === undefined ? NEXT : v;
6080
6072
  }
6081
- return parts.join(" > ");
6082
6073
  }
6083
- function captureError(e) {
6084
- const out = { message: e.message, stack: e.stack };
6085
- if ("expected" in e)
6086
- out.expected = e.expected;
6087
- if ("actual" in e)
6088
- out.actual = e.actual;
6089
- return out;
6074
+ function computeViewsId(views) {
6075
+ let s = "";
6076
+ let n = views;
6077
+ while (n !== null) {
6078
+ s += n[0];
6079
+ n = n[1];
6080
+ }
6081
+ return s === "main" ? "" : s;
6090
6082
  }
6091
- async function runTests({
6092
- getTests,
6093
- components = [],
6094
- path = null,
6095
- expect: expect2,
6096
- name = null,
6097
- grep = null,
6098
- bail = false
6099
- } = {}) {
6100
- const counts = { pass: 0, fail: 0, skip: 0, total: 0 };
6101
- if (typeof getTests !== "function") {
6102
- return new TestReport({
6103
- modules: [new ModuleTestReport({ path, suites: [], counts })]
6104
- });
6083
+
6084
+ class Stack {
6085
+ constructor(comps, it, binds, dynBinds, views, viewsId, ctx = null) {
6086
+ this.comps = comps;
6087
+ this.it = it;
6088
+ this.binds = binds;
6089
+ this.dynBinds = dynBinds;
6090
+ this.views = views;
6091
+ this.viewsId = viewsId;
6092
+ this.ctx = ctx;
6105
6093
  }
6106
- if (typeof expect2 !== "function") {
6107
- throw new Error("runTests: expect must be provided (e.g. chai's expect)");
6094
+ _pushProvides() {
6095
+ const provide = this.comps.getCompFor(this.it)?.provide;
6096
+ if (provide == null)
6097
+ return this;
6098
+ const dynObj = {};
6099
+ let has = false;
6100
+ for (const k in provide) {
6101
+ dynObj[provide[k].symbol] = provide[k].val.eval(this);
6102
+ has = true;
6103
+ }
6104
+ if (!has)
6105
+ return this;
6106
+ const newDynBinds = [new ObjectFrame(dynObj), this.dynBinds];
6107
+ const { comps, it, binds, views, viewsId, ctx } = this;
6108
+ return new Stack(comps, it, binds, newDynBinds, views, viewsId, ctx);
6108
6109
  }
6109
- const { describe, test, moduleTests } = makeCollector({ path, components });
6110
- await getTests({ describe, test, expect: expect2 });
6111
- let bailed = false;
6112
- async function visit(node) {
6113
- if (node instanceof Test) {
6114
- if (name !== null && node.componentName !== name)
6115
- return null;
6116
- const fullPath = buildPath(node);
6117
- if (grep !== null && !fullPath.includes(grep))
6118
- return null;
6119
- counts.total++;
6120
- if (bailed) {
6121
- counts.skip++;
6122
- return new TestResult({
6123
- title: node.title,
6124
- fullPath,
6125
- componentName: node.componentName,
6126
- status: "skip"
6127
- });
6128
- }
6129
- const start = performance.now();
6130
- try {
6131
- await node.fn();
6132
- counts.pass++;
6133
- return new TestResult({
6134
- title: node.title,
6135
- fullPath,
6136
- componentName: node.componentName,
6137
- status: "pass",
6138
- durationMs: performance.now() - start
6139
- });
6140
- } catch (e) {
6141
- counts.fail++;
6142
- if (bail)
6143
- bailed = true;
6144
- return new TestResult({
6145
- title: node.title,
6146
- fullPath,
6147
- componentName: node.componentName,
6148
- status: "fail",
6149
- durationMs: performance.now() - start,
6150
- error: captureError(e)
6151
- });
6152
- }
6153
- }
6154
- const childResults = [];
6155
- for (const child of node.children) {
6156
- const r = await visit(child);
6157
- if (r !== null)
6158
- childResults.push(r);
6159
- }
6160
- if (childResults.length === 0)
6110
+ static root(comps, it, ctx) {
6111
+ const binds = [new BindFrame(it, { it }, true), null];
6112
+ const dynBinds = [new ObjectFrame({}), null];
6113
+ const views = ["main", null];
6114
+ return new Stack(comps, it, binds, dynBinds, views, "", ctx)._pushProvides();
6115
+ }
6116
+ enter(it, bindings = {}, isFrame = true) {
6117
+ const { comps, binds, dynBinds, views, viewsId, ctx } = this;
6118
+ const newBinds = [new BindFrame(it, bindings, isFrame), binds];
6119
+ const stack = new Stack(comps, it, newBinds, dynBinds, views, viewsId, ctx);
6120
+ return isFrame ? stack._pushProvides() : stack;
6121
+ }
6122
+ pushViewName(name) {
6123
+ const { comps, it, binds, dynBinds, views, ctx } = this;
6124
+ const newViews = [name, views];
6125
+ return new Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
6126
+ }
6127
+ _pushDynBindValuesToArray(arr, comp) {
6128
+ for (const k in comp.provide)
6129
+ arr.push(this._lookupProvide(comp.provide[k]));
6130
+ for (const k in comp.lookup)
6131
+ arr.push(this._lookupAlias(comp.lookup[k]));
6132
+ }
6133
+ _lookupProvide(p) {
6134
+ return lookup(this.dynBinds, p.symbol) ?? p.val.eval(this) ?? null;
6135
+ }
6136
+ _lookupAlias(lk) {
6137
+ const sym = lk.getProducerSymbol(this);
6138
+ return (sym != null ? lookup(this.dynBinds, sym) : null) ?? lk.val?.eval(this) ?? null;
6139
+ }
6140
+ lookupDynamic(name) {
6141
+ const comp = this.comps.getCompFor(this.it);
6142
+ if (comp == null)
6161
6143
  return null;
6162
- return new DescribeResult({
6163
- title: node.title,
6164
- componentName: node.componentName,
6165
- children: childResults
6166
- });
6144
+ const lk = comp.lookup[name];
6145
+ if (lk !== undefined)
6146
+ return this._lookupAlias(lk);
6147
+ const p = comp.provide[name];
6148
+ return p !== undefined ? this._lookupProvide(p) : null;
6167
6149
  }
6168
- const suiteResults = [];
6169
- for (const suite of moduleTests.suites) {
6170
- const r = await visit(suite);
6171
- if (r !== null)
6172
- suiteResults.push(r);
6150
+ lookupBind(name) {
6151
+ return lookup(this.binds, name);
6173
6152
  }
6174
- return new TestReport({
6175
- modules: [new ModuleTestReport({ path, suites: suiteResults, counts })]
6176
- });
6177
- }
6178
-
6179
- // tools/core/test-console.js
6180
- var PASS = "color: #0a0; font-weight: bold";
6181
- var FAIL = "color: #c00; font-weight: bold";
6182
- var SKIP = "color: #888";
6183
- var DIM = "color: #888";
6184
- var RESET = "color: inherit; font-weight: normal";
6185
- function reportTestNode(node) {
6186
- if (node.children) {
6187
- const label = node.componentName ? `${node.title} [${node.componentName}]` : node.title;
6188
- console.group(label);
6189
- for (const child of node.children)
6190
- reportTestNode(child);
6191
- console.groupEnd();
6192
- return;
6153
+ lookupType(name) {
6154
+ return this.comps.getCompFor(this.it).scope.lookupComponent(name);
6193
6155
  }
6194
- const dur = node.status === "skip" ? "" : ` (${Math.round(node.durationMs)}ms)`;
6195
- if (node.status === "pass") {
6196
- console.log(`%c✓%c ${node.title}%c${dur}`, PASS, RESET, DIM);
6197
- } else if (node.status === "skip") {
6198
- console.log(`%c○ ${node.title}%c (skipped)`, SKIP, RESET);
6199
- } else {
6200
- console.group(`%c✗%c ${node.title}%c${dur}`, FAIL, RESET, DIM);
6201
- console.error(node.error?.message ?? "(no error message)");
6202
- if (node.error && (("expected" in node.error) || ("actual" in node.error))) {
6203
- console.log("expected:", node.error.expected);
6204
- console.log("actual: ", node.error.actual);
6205
- }
6206
- if (node.error?.stack)
6207
- console.log(node.error.stack);
6208
- console.groupEnd();
6156
+ lookupFieldRaw(name) {
6157
+ return this.it[name] ?? null;
6209
6158
  }
6210
- }
6211
- function reportTestReportToConsole(report) {
6212
- for (const m of report.modules) {
6213
- const label = `tutuca tests${m.path ? ` — ${m.path}` : ""}`;
6214
- console.group(label);
6215
- if (m.suites.length === 0) {
6216
- console.log("(no tests)");
6217
- } else {
6218
- for (const s of m.suites)
6219
- reportTestNode(s);
6159
+ lookupMethod(name) {
6160
+ const fn = this.it[name];
6161
+ return fn instanceof Function ? fn.call(this.it) : null;
6162
+ }
6163
+ lookupName(name) {
6164
+ return this.ctx.lookupName(name);
6165
+ }
6166
+ getHandlerFor(name, key) {
6167
+ return this.comps.getHandlerFor(this.it, name, key);
6168
+ }
6169
+ lookupRequest(name) {
6170
+ return this.comps.getRequestFor(this.it, name);
6171
+ }
6172
+ lookupBestView(views, defaultViewName) {
6173
+ let n = this.views;
6174
+ while (n !== null) {
6175
+ const view = views[n[0]];
6176
+ if (view !== undefined)
6177
+ return view;
6178
+ n = n[1];
6220
6179
  }
6221
- const c = m.counts;
6222
- const summary = `${c.pass} passed, ${c.fail} failed, ${c.skip} skipped (${c.total} total)`;
6223
- if (c.fail > 0)
6224
- console.error(`%c${summary}`, FAIL);
6225
- else if (c.total === 0)
6226
- console.log(`%c${summary}`, DIM);
6227
- else
6228
- console.log(`%c${summary}`, PASS);
6229
- console.groupEnd();
6180
+ return views[defaultViewName];
6230
6181
  }
6231
- return report;
6232
6182
  }
6233
6183
 
6234
- // tools/format/lint.js
6235
- var UNSUPPORTED_EXPR_LABEL = {
6236
- ternary: "ternary expression",
6237
- comparison: "comparison",
6238
- logical: "logical expression",
6239
- "call-with-args": "method call with arguments"
6240
- };
6241
- function unsupportedExprMessage(info) {
6242
- const v = JSON.stringify(info.value);
6243
- const label = UNSUPPORTED_EXPR_LABEL[info.detected] ?? "expression";
6244
- switch (info.role) {
6245
- case "attr":
6246
- return `Unsupported ${label} ${v} in dynamic attribute ':${info.attr}'`;
6247
- case "directive":
6248
- return `Unsupported ${label} ${v} in directive '@${info.directive}'`;
6249
- case "if":
6250
- return `Unsupported ${label} ${v} in '@if.${info.attr}' condition`;
6251
- case "x-op":
6252
- return `Unsupported ${label} ${v} in <x ${info.op}>`;
6253
- default:
6254
- return `Unsupported ${label} ${v}`;
6184
+ // src/transactor.js
6185
+ class State2 {
6186
+ constructor(val) {
6187
+ this.val = val;
6188
+ this.changeSubs = [];
6255
6189
  }
6256
- }
6257
- function badValueMessage(info) {
6258
- const v = JSON.stringify(info.value);
6259
- switch (info.role) {
6260
- case "attr":
6261
- return `Cannot parse value ${v} for attribute ':${info.attr}'`;
6262
- case "directive":
6263
- return `Cannot parse value ${v} for directive '@${info.directive}'`;
6264
- case "if":
6265
- return `Cannot parse condition ${v} for '@if.${info.attr}'`;
6266
- case "x-op":
6267
- return `Cannot parse value ${v} for <x ${info.op}>`;
6268
- case "handler-name":
6269
- return `Cannot parse handler name ${v}`;
6270
- case "handler-arg":
6271
- return `Cannot parse handler argument ${v}`;
6272
- case "macro-var":
6273
- return `Macro variable '^${info.name}' is not defined`;
6274
- default:
6275
- return `Cannot parse value ${v}`;
6190
+ onChange(cb) {
6191
+ this.changeSubs.push(cb);
6276
6192
  }
6277
- }
6278
- function tagDisplay(tag) {
6279
- return tag ? String(tag).toLowerCase() : null;
6280
- }
6281
- function fmtTagSuffix(info) {
6282
- const t = tagDisplay(info?.tag);
6283
- return t && t !== "x" ? ` on <${t}>` : "";
6284
- }
6285
- function fmtOriginSuffix(info) {
6286
- if (!info)
6287
- return "";
6288
- const parts = [];
6289
- if (info.originAttr) {
6290
- const branch = info.branch ? `[${info.branch}]` : "";
6291
- parts.push(`in ${info.originAttr}${branch}`);
6193
+ set(val, info) {
6194
+ const old = this.val;
6195
+ this.val = val;
6196
+ for (const sub of this.changeSubs)
6197
+ sub({ val, old, info, timestamp: Date.now() });
6292
6198
  }
6293
- if (info.handlerName) {
6294
- parts.push(`handler '${info.handlerName}'${info.argIndex !== undefined ? ` arg ${info.argIndex}` : ""}`);
6199
+ update(fn, info) {
6200
+ return this.set(fn(this.val), info);
6295
6201
  }
6296
- const t = tagDisplay(info.tag);
6297
- if (t && t !== "x")
6298
- parts.push(`on <${t}>`);
6299
- return parts.length ? ` (${parts.join(", ")})` : "";
6300
- }
6301
- function fmtEventSuffix(info) {
6302
- if (info?.originAttr)
6303
- return ` in ${info.originAttr}`;
6304
- if (info?.eventName)
6305
- return ` in @on.${info.eventName}`;
6306
- return "";
6307
6202
  }
6308
- function lintIdToMessage(id, info) {
6309
- switch (id) {
6310
- case "RENDER_IT_OUTSIDE_OF_LOOP":
6311
- return "<x render-it> used outside of a loop";
6312
- case "UNKNOWN_EVENT_MODIFIER": {
6313
- const mods = info.handler?.modifiers ?? [info.modifier];
6314
- const written = `@on.${info.name}+${mods.join("+")}`;
6315
- return `Unknown modifier '+${info.modifier}' in '${written}'`;
6316
- }
6317
- case "UNKNOWN_HANDLER_ARG_NAME":
6318
- return `Unknown handler argument '${info.name}'${fmtOriginSuffix(info)}`;
6319
- case "INPUT_HANDLER_NOT_IMPLEMENTED":
6320
- return `Input handler '${info.name}' is not implemented${fmtEventSuffix(info)}`;
6321
- case "INPUT_HANDLER_NOT_REFERENCED":
6322
- return `Input handler '${info.name}' is defined but never used — remove it or wire it to an @on.* event`;
6323
- case "INPUT_HANDLER_METHOD_NOT_IMPLEMENTED":
6324
- return `Method '$${info.name}' is not implemented${fmtEventSuffix(info)}`;
6325
- case "INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD":
6326
- return `'$${info.name}' is a method reference, but '${info.name}' is defined as an input handler${fmtEventSuffix(info)}`;
6327
- case "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER":
6328
- return `'${info.name}' is an input handler reference, but '${info.name}' is defined as a method${fmtEventSuffix(info)}`;
6329
- case "FIELD_VAL_NOT_DEFINED":
6330
- return `Field '.${info.name}' is not defined${fmtOriginSuffix(info)}`;
6331
- case "FIELD_VAL_IS_METHOD":
6332
- return `'.${info.name}' reads a field, but '${info.name}' is defined as a method — use '$${info.name}'${fmtOriginSuffix(info)}`;
6333
- case "METHOD_VAL_NOT_DEFINED":
6334
- return `Method '$${info.name}' is not defined${fmtOriginSuffix(info)}`;
6335
- case "METHOD_VAL_IS_FIELD":
6336
- return `'$${info.name}' calls a method, but '${info.name}' is defined as a field — use '.${info.name}'${fmtOriginSuffix(info)}`;
6337
- case "DUPLICATE_ATTR_DEFINITION": {
6338
- const sources = info.sources?.length ? ` (${info.sources.join(", ")})` : "";
6339
- const tag = info.tag ? ` on <${String(info.tag).toLowerCase()}>` : "";
6340
- return `Attribute '${info.name}' is set ${info.sources?.length ?? "multiple"} times${sources}${tag}`;
6203
+
6204
+ class Transactor {
6205
+ constructor(comps, rootValue) {
6206
+ this.comps = comps;
6207
+ this.transactions = [];
6208
+ this.state = new State2(rootValue);
6209
+ this.onTransactionPushed = () => {};
6210
+ this._inflight = new Set;
6211
+ }
6212
+ pushTransaction(t) {
6213
+ this.transactions.push(t);
6214
+ this.onTransactionPushed(t);
6215
+ }
6216
+ _link(child, parent) {
6217
+ if (parent) {
6218
+ const release = parent.completion.track();
6219
+ child.completion.whenSubtreeSettled().then(release);
6341
6220
  }
6342
- case "IF_NO_BRANCH_SET":
6343
- return `'@if.${info.attr}' has no '@then' or '@else' branch — add '@then="…"' or '@else="…"' (or both)${fmtTagSuffix(info)}`;
6344
- case "UNKNOWN_REQUEST_NAME":
6345
- return `Unknown request '!${info.name}'${fmtOriginSuffix(info)}`;
6346
- case "UNKNOWN_COMPONENT_NAME":
6347
- return `Unknown component '${info.name}'${fmtOriginSuffix(info)}`;
6348
- case "ALT_HANDLER_NOT_DEFINED":
6349
- return `Alter handler '${info.name}' is not defined${fmtOriginSuffix(info)}`;
6350
- case "ALT_HANDLER_NOT_REFERENCED":
6351
- return `Alter handler '${info.name}' is defined but never used — remove it or reference it from @when, @enrich-with, or @loop-with`;
6352
- case "DYN_VAL_NOT_DEFINED":
6353
- return `Dynamic variable '*${info.name}' is not defined${fmtOriginSuffix(info)}`;
6354
- case "DYN_ALIAS_NOT_REFERENCED":
6355
- return `Lookup '${info.name}' is defined but never used — remove it or reference it as '*${info.name}' in a view`;
6356
- case "PROVIDE_NOT_ADDRESSABLE":
6357
- return `Provide '${info.name}' value '${info.value}' must be a field ('.f') or seq-access ('.s[.k]') — a method/constant can't be a render target`;
6358
- case "LOOKUP_BAD_SHAPE":
6359
- return `Lookup '${info.name}' has an invalid shape: ${info.problem}`;
6360
- case "LOOKUP_TARGET_MALFORMED":
6361
- return `Lookup '${info.name}' target '${info.target}' must be 'Producer.provideName' (a string, or the 'for' of { for, default })`;
6362
- case "UNKNOWN_MACRO_ARG":
6363
- return `Argument '${info.name}' is not declared in macro '${info.macroName}'`;
6364
- case "UNKNOWN_DIRECTIVE":
6365
- return `Unknown directive '@${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
6366
- case "UNKNOWN_X_OP":
6367
- return `Unknown <x> op '${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
6368
- case "UNKNOWN_X_ATTR":
6369
- return `Unknown attribute '${info.name}=${JSON.stringify(info.value)}' on <x ${info.op}>${fmtTagSuffix(info)}`;
6370
- case "MAYBE_DROP_AT_PREFIX": {
6371
- const written = info.value !== undefined ? `${info.name}=${JSON.stringify(info.value)}` : info.name;
6372
- return `'${written}' on <x> looks like a directive but is actually an x op/attr written with a leading '@'`;
6221
+ return child;
6222
+ }
6223
+ pushSend(path, name, args = [], opts = {}, parent = null) {
6224
+ const t = new SendEvent(path, this, name, args, parent, opts);
6225
+ this.pushTransaction(t);
6226
+ return this._link(t, parent);
6227
+ }
6228
+ pushInput(path, name, args = [], opts = {}, parent = null) {
6229
+ const t = new InputDispatchEvent(path, this, name, args, parent, opts);
6230
+ this.pushTransaction(t);
6231
+ return this._link(t, parent);
6232
+ }
6233
+ pushBubble(path, name, args = [], opts = {}, parent = null, targetPath = null) {
6234
+ const newOpts = opts.skipSelf ? { ...opts, skipSelf: false } : opts;
6235
+ const t = new BubbleEvent(path, this, name, args, parent, newOpts, targetPath);
6236
+ this.pushTransaction(t);
6237
+ return this._link(t, parent);
6238
+ }
6239
+ pushRequest(path, name, args = [], opts = {}, parent = null) {
6240
+ const release = parent ? parent.completion.track() : null;
6241
+ const p = this._runRequest(path, name, args, opts, parent, release);
6242
+ this._inflight.add(p);
6243
+ p.finally(() => this._inflight.delete(p));
6244
+ return p;
6245
+ }
6246
+ async settle(maxTurns = 1e4) {
6247
+ while ((this.hasPendingTransactions || this._inflight.size) && maxTurns-- > 0) {
6248
+ while (this.hasPendingTransactions)
6249
+ this.transactNext();
6250
+ if (this._inflight.size)
6251
+ await Promise.allSettled([...this._inflight]);
6252
+ }
6253
+ }
6254
+ async _runRequest(path, name, args = [], opts = {}, parent = null, release = null) {
6255
+ let released = false;
6256
+ const transfer = (t) => {
6257
+ if (release) {
6258
+ released = true;
6259
+ t.completion.whenSubtreeSettled().then(release);
6260
+ }
6261
+ };
6262
+ try {
6263
+ const curRoot = this.state.val;
6264
+ const txnPath = path.toTransactionPath();
6265
+ const curLeaf = txnPath.lookup(curRoot);
6266
+ const handler = this.comps.getRequestFor(curLeaf, name) ?? mkReq404(name);
6267
+ const reqCtx = new RequestContext(path, this, parent, curRoot);
6268
+ const resHandlerName = opts?.onResName ?? name;
6269
+ const resPath = opts?.livePath ? null : txnPath.pinKeys(curRoot);
6270
+ const push = (specificName, baseName, singleArg, result, error) => {
6271
+ const resArgs = specificName ? [singleArg] : [result, error];
6272
+ const t = new ResponseEvent(path, this, specificName ?? baseName, resArgs, parent, resPath);
6273
+ transfer(t);
6274
+ this.pushTransaction(t);
6275
+ };
6276
+ try {
6277
+ const result = await handler.fn.apply(null, [...args, reqCtx]);
6278
+ push(opts?.onOkName, resHandlerName, result, result, null);
6279
+ } catch (error) {
6280
+ push(opts?.onErrorName, resHandlerName, error, null, error);
6281
+ }
6282
+ } finally {
6283
+ if (release && !released)
6284
+ release();
6373
6285
  }
6374
- case "MAYBE_ADD_AT_PREFIX":
6375
- return `'${info.name}' on <${(info.tag ?? "").toLowerCase()}> is a plain attribute, but '@${info.name}' is a directive — add the leading '@'`;
6376
- case "BAD_VALUE":
6377
- return `${badValueMessage(info)}${fmtTagSuffix(info)}`;
6378
- case "UNSUPPORTED_EXPR_SYNTAX":
6379
- return `${unsupportedExprMessage(info)}${fmtTagSuffix(info)}`;
6380
- case "REDUNDANT_TEMPLATE_STRING":
6381
- return `Redundant template string — '{${info.simpler}}' should be just '${info.simpler}'${fmtOriginSuffix(info)}`;
6382
- case "PLACEHOLDERLESS_TEMPLATE_STRING":
6383
- return `Template string has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
6384
- case "UNKNOWN_COMPONENT_SPEC_KEY":
6385
- return `Unknown component spec key '${info.key}' — value will be ignored at runtime`;
6386
- case "COMP_FIELD_BAD_SHAPE":
6387
- return info.kind === "args-not-object" ? `Field '${info.fieldName}': in { component, args }, 'args' must be a plain object, got ${info.got}` : `Field '${info.fieldName}': in { component, args }, 'component' must be the component name as a string, got ${info.gotName ? `the ${info.gotName} class` : info.got}`;
6388
- case "HTML_TAG_NAME_HAS_UPPERCASE":
6389
- return `Tag <${info.raw}> will be lowercased to <${info.lowercased}>${fmtLocationSuffix(info)}`;
6390
- case "HTML_SVG_TAG_WILL_LOWERCASE":
6391
- return `SVG tag <${info.raw}> is not in the WHATWG case-correction list — will be lowercased to <${info.lowercased}>${fmtLocationSuffix(info)}`;
6392
- case "HTML_TAG_NOT_ALLOWED_IN_PARENT":
6393
- return `<${info.tag}> not allowed under <${info.parent ?? "?"}> in ${info.mode} — ${htmlActionPhrase(info.action, info.tag, info.parent)}${fmtLocationSuffix(info)}`;
6394
- case "HTML_TEXT_NOT_ALLOWED_IN_PARENT":
6395
- return `Non-whitespace text not allowed in ${info.mode}: ${JSON.stringify(info.snippet)}${fmtLocationSuffix(info)}`;
6396
- case "HTML_VOID_ELEMENT_HAS_CLOSE_TAG":
6397
- return `Void element <${info.tag}> has an explicit close tag${fmtLocationSuffix(info)}`;
6398
- case "HTML_DUPLICATE_FORM":
6399
- return `Nested <form> — the inner form will be dropped by the parser${fmtLocationSuffix(info)}`;
6400
- case "HTML_NESTED_INTERACTIVE":
6401
- return `<${info.tag}> nested inside another <${info.tag}> — adoption agency will reorder${fmtLocationSuffix(info)}`;
6402
- case "HTML_MISNESTED_FORMATTING":
6403
- return `Misnested formatting tag </${info.tag}> — adoption agency will reorder nodes${fmtLocationSuffix(info)}`;
6404
- case "HTML_UNEXPECTED_END_TAG":
6405
- return `Unexpected end tag </${info.tag}>${fmtLocationSuffix(info)}`;
6406
- case "HTML_UNCLOSED_BEFORE_END":
6407
- return `<${info.unclosed}> still open when </${info.tag}> was seen — implicitly closed${fmtLocationSuffix(info)}`;
6408
- case "HTML_DUPLICATE_ATTRIBUTE":
6409
- return `Duplicate attribute '${info.name}' — second occurrence dropped${fmtLocationSuffix(info)}`;
6410
- case "HTML_ATTRIBUTES_ON_END_TAG":
6411
- return `Attributes on end tag </${info.tag}> — dropped by the parser${fmtLocationSuffix(info)}`;
6412
- case "HTML_SELF_CLOSING_END_TAG":
6413
- return `Self-closing end tag </${info.tag}/> — trailing '/' is meaningless${fmtLocationSuffix(info)}`;
6414
- case "HTML_MISSING_ATTRIBUTE_VALUE":
6415
- return `Attribute '${info.name}' is missing a value${fmtLocationSuffix(info)}`;
6416
- case "HTML_CDATA_IN_HTML_NAMESPACE":
6417
- return `CDATA section in HTML namespace — reinterpreted as a bogus comment${fmtLocationSuffix(info)}`;
6418
- case "HTML_BOGUS_COMMENT":
6419
- return `Bogus comment — content dropped by the parser${fmtLocationSuffix(info)}`;
6420
- case "HTML_SVG_ATTR_WILL_LOWERCASE":
6421
- return `SVG attribute '${info.raw}' will be rewritten to '${info.canonical}'${fmtLocationSuffix(info)}`;
6422
- case "HTML_MATHML_ATTR_WILL_LOWERCASE":
6423
- return `MathML attribute '${info.raw}' will be rewritten to '${info.canonical}'${fmtLocationSuffix(info)}`;
6424
- case "ASYNC_HANDLER":
6425
- return `Handler '${info.name}' in '${info.channel}' is an async function — handlers must be synchronous and return the updated state (an async function returns a Promise the framework won't await)`;
6426
- case "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE":
6427
- return `'@${info.atRule}' is a top-level-only at-rule, but '${info.key}' is wrapped in a component-scoped selector ([data-cid=…]{…}) where it is invalid and silently dropped — move it to 'globalStyle'${fmtLocationSuffix(info)}`;
6428
- case "GLOBAL_SELECTOR_IN_SCOPED_STYLE":
6429
- return `Selector '${info.selector}' targets the document root, but '${info.key}' is wrapped in a component-scoped selector, so it becomes a descendant selector that never matches — move it to 'globalStyle'${fmtLocationSuffix(info)}`;
6430
- case "LINT_ERROR":
6431
- return info.message;
6432
- default:
6433
- return id;
6434
6286
  }
6435
- }
6436
- function suggestionToMessage(suggestion) {
6437
- if (!suggestion)
6438
- return null;
6439
- switch (suggestion.kind) {
6440
- case "replace-name":
6441
- return `did you mean '${suggestion.to}'?`;
6442
- case "drop-prefix":
6443
- return `did you mean '${suggestion.to}'? (drop the leading '${suggestion.from.slice(0, suggestion.from.length - suggestion.to.length)}')`;
6444
- case "add-prefix":
6445
- return `did you mean '${suggestion.to}'? (add the leading '${suggestion.to.slice(0, suggestion.to.length - suggestion.from.length)}')`;
6446
- case "remove":
6447
- return `remove ${suggestion.what}`;
6448
- case "rewrite":
6449
- return `use '${suggestion.to}' instead of '${suggestion.from}'`;
6450
- case "wrap":
6451
- return `wrap it in ${suggestion.to}`;
6452
- case "rephrase":
6453
- return suggestion.text ?? null;
6454
- default:
6455
- return null;
6287
+ get hasPendingTransactions() {
6288
+ return this.transactions.length > 0;
6289
+ }
6290
+ transactNext() {
6291
+ if (this.hasPendingTransactions)
6292
+ this.transact(this.transactions.shift());
6293
+ }
6294
+ transact(transaction) {
6295
+ try {
6296
+ const curState = this.state.val;
6297
+ const newState = transaction.run(curState, this.comps);
6298
+ if (newState !== undefined) {
6299
+ this.state.set(newState, { transaction });
6300
+ transaction.afterTransaction();
6301
+ } else
6302
+ console.warn("undefined new state", { curState, transaction });
6303
+ } finally {
6304
+ transaction._completion?.ensureSelfSettled();
6305
+ transaction._completion?.releaseSelf();
6306
+ }
6307
+ }
6308
+ transactInputNow(path, event, eventHandler, dragInfo) {
6309
+ this.transact(new InputEvent(path, event, eventHandler, this, dragInfo));
6456
6310
  }
6457
6311
  }
6458
- function fmtLocationSuffix(info) {
6459
- const loc = info?.location;
6460
- if (!loc)
6461
- return "";
6462
- return ` at line ${loc.line}, col ${loc.column}`;
6312
+ function mkReq404(name) {
6313
+ const fn = () => {
6314
+ throw new Error(`Request not found: ${name}`);
6315
+ };
6316
+ return { fn };
6463
6317
  }
6464
- function htmlActionPhrase(action, tag, parent) {
6465
- switch (action) {
6466
- case "ignored":
6467
- return `the parser will drop this <${tag}>`;
6468
- case "drop":
6469
- return `the parser will drop this <${tag}>`;
6470
- case "auto-close-implicit":
6471
- return `the parser will close <${parent ?? "?"}> first, then place <${tag}> as a sibling`;
6472
- case "foster-parent":
6473
- return `the parser will move <${tag}> outside <${parent ?? "?"}> (foster-parenting)`;
6474
- case "foreign-breakout":
6475
- return `the parser will exit foreign content and re-process <${tag}> in HTML mode`;
6476
- default:
6477
- return `parser action: ${action}`;
6478
- }
6318
+ function nullHandler() {
6319
+ return this;
6479
6320
  }
6480
6321
 
6481
- // src/components.js
6482
- class Components {
6483
- constructor() {
6484
- this.getComponentSymbol = Symbol("getComponent");
6485
- this.byId = new Map;
6322
+ class Transaction {
6323
+ constructor(path, transactor, parentTransaction = null) {
6324
+ this.path = path;
6325
+ this.transactor = transactor;
6326
+ this.parentTransaction = parentTransaction;
6327
+ this._completion = null;
6486
6328
  }
6487
- registerComponent(comp) {
6488
- comp.Class.prototype[this.getComponentSymbol] = () => comp;
6489
- this.byId.set(comp.id, comp);
6329
+ get completion() {
6330
+ this._completion ??= new Completion;
6331
+ return this._completion;
6490
6332
  }
6491
- getComponentForId(id) {
6492
- return this.byId.get(id) ?? null;
6333
+ whenSettled() {
6334
+ return this.completion.whenSettled();
6493
6335
  }
6494
- getCompFor(v) {
6495
- return v?.[this.getComponentSymbol]?.() ?? null;
6336
+ whenSubtreeSettled() {
6337
+ return this.completion.whenSubtreeSettled();
6496
6338
  }
6497
- getHandlerFor(v, name, key) {
6498
- return this.getCompFor(v)?.[key][name] ?? null;
6339
+ run(rootValue, comps) {
6340
+ return this.updateRootValue(rootValue, comps);
6499
6341
  }
6500
- getRequestFor(v, name) {
6501
- return this.getCompFor(v)?.scope.lookupRequest(name) ?? null;
6342
+ afterTransaction() {}
6343
+ buildRootStack(root, comps) {
6344
+ return Stack.root(comps, root);
6502
6345
  }
6503
- compileStyles() {
6504
- const styles = [];
6505
- for (const comp of this.byId.values())
6506
- styles.push(comp.compileStyle());
6507
- return styles.join(`
6508
- `);
6346
+ buildStack(root, comps) {
6347
+ return this.path.toTransactionPath().buildStack(this.buildRootStack(root, comps));
6509
6348
  }
6510
- }
6511
-
6512
- class ComponentStack {
6513
- constructor(comps = new Components, parent = null) {
6514
- this.comps = comps;
6515
- this.parent = parent;
6516
- this.byName = {};
6517
- this.reqsByName = {};
6518
- this.macros = {};
6349
+ callHandler(root, instance, comps) {
6350
+ const [handler, args] = this.getHandlerAndArgs(root, instance, comps);
6351
+ return handler.apply(instance, args);
6519
6352
  }
6520
- enter() {
6521
- return new ComponentStack(this.comps, this);
6353
+ getHandlerAndArgs(_root, _instance, _comps) {
6354
+ return null;
6522
6355
  }
6523
- registerComponents(comps, opts) {
6524
- const { aliases = {} } = opts ?? {};
6525
- for (let i = 0;i < comps.length; i++) {
6526
- const comp = comps[i];
6527
- comp.scope = this.enter();
6528
- comp.Class.scope = comp.scope;
6529
- this.comps.registerComponent(comp);
6530
- this.byName[comp.name] = comp;
6531
- }
6532
- for (const alias in aliases) {
6533
- const comp = this.byName[aliases[alias]];
6534
- console.assert(this.byName[alias] === undefined, "alias overrides component", alias);
6535
- if (comp !== undefined)
6536
- this.byName[alias] = comp;
6537
- else
6538
- console.warn("alias", alias, "to inexistent component", aliases[alias]);
6539
- }
6356
+ getTransactionPath() {
6357
+ return this.path.toTransactionPath();
6540
6358
  }
6541
- registerMacros(macros) {
6542
- for (const key in macros) {
6543
- const lower = key.toLowerCase();
6544
- console.assert(this.macros[lower] === undefined, "macro key collision", lower);
6545
- this.macros[lower] = macros[key];
6546
- }
6359
+ updateRootValue(curRoot, comps) {
6360
+ const txnPath = this.getTransactionPath();
6361
+ const curLeaf = txnPath.lookup(curRoot);
6362
+ const newLeaf = this.callHandler(curRoot, curLeaf, comps);
6363
+ this._completion?.markSelfSettled({ value: newLeaf, old: curLeaf });
6364
+ return curLeaf !== newLeaf ? txnPath.setValue(curRoot, newLeaf) : curRoot;
6547
6365
  }
6548
- getCompFor(v) {
6549
- return this.comps.getCompFor(v);
6366
+ lookupName(_name) {
6367
+ return null;
6550
6368
  }
6551
- registerRequestHandlers(handlers) {
6552
- for (const name in handlers)
6553
- this.reqsByName[name] = new RequestHandler(name, handlers[name]);
6369
+ }
6370
+ var toNullIfNaN = (v) => Number.isNaN(v) ? null : v;
6371
+ function getValue(e) {
6372
+ return e.target.type === "checkbox" ? e.target.checked : (e instanceof CustomEvent ? e.detail : e.target.value) ?? null;
6373
+ }
6374
+
6375
+ class InputEvent extends Transaction {
6376
+ constructor(path, e, handler, transactor, dragInfo) {
6377
+ super(path, transactor);
6378
+ this.e = e;
6379
+ this.handler = handler;
6380
+ this.dragInfo = dragInfo;
6381
+ this._dispatchPath = null;
6554
6382
  }
6555
- lookupRequest(name) {
6556
- return this.reqsByName[name] ?? this.parent?.lookupRequest(name) ?? null;
6383
+ get dispatchPath() {
6384
+ this._dispatchPath ??= this.path.compact();
6385
+ return this._dispatchPath;
6557
6386
  }
6558
- lookupComponent(name) {
6559
- return this.byName[name] ?? this.parent?.lookupComponent(name) ?? null;
6387
+ buildRootStack(root, comps) {
6388
+ return Stack.root(comps, root, this);
6560
6389
  }
6561
- lookupMacro(name) {
6562
- return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
6390
+ getHandlerAndArgs(root, _instance, comps) {
6391
+ const stack = this.buildStack(root, comps);
6392
+ const [handler, args] = this.handler.getHandlerAndArgs(stack, this);
6393
+ const path = this.dispatchPath;
6394
+ let dispatcher;
6395
+ for (let i = 0;i < args.length; i++) {
6396
+ if (args[i]?.toHandlerArg) {
6397
+ dispatcher ??= new Dispatcher(path, this.transactor, this);
6398
+ args[i] = args[i].toHandlerArg(dispatcher);
6399
+ }
6400
+ }
6401
+ args.push(new EventContext(path, this.transactor, this));
6402
+ return [handler, args];
6403
+ }
6404
+ lookupName(name) {
6405
+ const { e } = this;
6406
+ switch (name) {
6407
+ case "value":
6408
+ return getValue(e);
6409
+ case "valueAsInt":
6410
+ return toNullIfNaN(parseInt(getValue(e), 10));
6411
+ case "valueAsFloat":
6412
+ return toNullIfNaN(parseFloat(getValue(e)));
6413
+ case "target":
6414
+ return e.target;
6415
+ case "event":
6416
+ return e;
6417
+ case "isAlt":
6418
+ return e.altKey;
6419
+ case "isShift":
6420
+ return e.shiftKey;
6421
+ case "isCtrl":
6422
+ case "isCmd":
6423
+ return isMac && e.metaKey || e.ctrlKey;
6424
+ case "key":
6425
+ return e.key;
6426
+ case "keyCode":
6427
+ return e.keyCode;
6428
+ case "isUpKey":
6429
+ return e.key === "ArrowUp";
6430
+ case "isDownKey":
6431
+ return e.key === "ArrowDown";
6432
+ case "isSend":
6433
+ return e.key === "Enter";
6434
+ case "isCancel":
6435
+ return e.key === "Escape";
6436
+ case "isTabKey":
6437
+ return e.key === "Tab";
6438
+ case "ctx":
6439
+ return new EventContext(this.dispatchPath, this.transactor, this);
6440
+ case "dragInfo":
6441
+ return this.dragInfo;
6442
+ }
6443
+ return null;
6563
6444
  }
6564
6445
  }
6565
6446
 
6566
- class ProvideInfo {
6567
- constructor(name, val, symbol) {
6447
+ class NameArgsTransaction extends Transaction {
6448
+ constructor(path, transactor, name, args, parentTransaction, opts = {}) {
6449
+ super(path, transactor, parentTransaction);
6568
6450
  this.name = name;
6569
- this.val = val;
6570
- this.symbol = symbol;
6451
+ this.args = args;
6452
+ this.opts = opts;
6453
+ this.targetPath = path;
6454
+ }
6455
+ handlerProp = null;
6456
+ getHandlerForName(comp) {
6457
+ const handlers = comp?.[this.handlerProp];
6458
+ return handlers?.[this.name] ?? handlers?.$unknown ?? nullHandler;
6459
+ }
6460
+ getHandlerAndArgs(_root, instance, comps) {
6461
+ const handler = this.getHandlerForName(comps.getCompFor(instance));
6462
+ return [handler, [...this.args, new EventContext(this.path, this.transactor, this)]];
6571
6463
  }
6572
6464
  }
6573
6465
 
6574
- class LookupInfo {
6575
- constructor(name, compName, provideName, val) {
6576
- this.name = name;
6577
- this.compName = compName;
6578
- this.provideName = provideName;
6579
- this.val = val;
6580
- this._sym = undefined;
6466
+ class ResponseEvent extends NameArgsTransaction {
6467
+ handlerProp = "response";
6468
+ constructor(path, transactor, name, args, parent, txnPath = null) {
6469
+ super(path, transactor, name, args, parent);
6470
+ this._txnPath = txnPath;
6581
6471
  }
6582
- getProducerSymbol(stack) {
6583
- if (this._sym === undefined)
6584
- this._sym = stack.lookupType(this.compName)?.provide?.[this.provideName]?.symbol ?? null;
6585
- return this._sym;
6472
+ getTransactionPath() {
6473
+ return this._txnPath ?? super.getTransactionPath();
6586
6474
  }
6587
6475
  }
6588
- var isString = (v) => typeof v === "string";
6589
- var _rawSpecKeys = "name view style commonStyle globalStyle input receive bubble response alter views provide lookup fields methods statics";
6590
- var KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
6591
- var _compId = 0;
6592
6476
 
6593
- class Component {
6594
- constructor(Class, o) {
6595
- this.id = _compId++;
6596
- this.name = o.name ?? "UnkComp";
6597
- this.Class = Class;
6598
- this.views = { main: new View("main", o.view, o.style) };
6599
- this.commonStyle = o.commonStyle ?? "";
6600
- this.globalStyle = o.globalStyle ?? "";
6601
- this.input = o.input ?? {};
6602
- this.receive = o.receive ?? {};
6603
- this.bubble = o.bubble ?? {};
6604
- this.response = o.response ?? {};
6605
- this.alter = o.alter ?? {};
6606
- for (const name in o.views ?? {}) {
6607
- const v = o.views[name];
6608
- const { view, style } = isString(v) ? { view: v } : v;
6609
- this.views[name] = new View(name, view, style);
6610
- }
6611
- this._rawProvide = o.provide ?? {};
6612
- this._rawLookup = o.lookup ?? {};
6613
- this.provide = {};
6614
- this.lookup = {};
6615
- this.scope = null;
6616
- this.spec = o;
6617
- this.extra = {};
6618
- for (const key of Object.keys(o))
6619
- if (!KNOWN_SPEC_KEYS.has(key))
6620
- this.extra[key] = o[key];
6477
+ class SendEvent extends NameArgsTransaction {
6478
+ handlerProp = "receive";
6479
+ run(rootVal, comps) {
6480
+ return this.opts.skipSelf ? rootVal : this.updateRootValue(rootVal, comps);
6621
6481
  }
6622
- clone() {
6623
- return Component.fromSpec(this.spec);
6482
+ afterTransaction() {
6483
+ const { path, name, args, opts, targetPath } = this;
6484
+ if (opts.bubbles && path.steps.length > 0)
6485
+ this.transactor.pushBubble(path.popStep(), name, args, opts, this, targetPath);
6624
6486
  }
6625
- compile(ParseContext2) {
6626
- for (const name in this.views)
6627
- this.views[name].compile(new ParseContext2, this.scope, this.id);
6628
- const ctx = this.views.main.ctx;
6629
- for (const key in this._rawProvide) {
6630
- const val = vp.parseProvide(this._rawProvide[key], ctx);
6631
- if (val)
6632
- this.provide[key] = new ProvideInfo(key, val, Symbol(key));
6633
- }
6634
- for (const key in this._rawLookup) {
6635
- const linfo = this._rawLookup[key];
6636
- const forStr = isString(linfo) ? linfo : isString(linfo?.for) ? linfo.for : null;
6637
- const [compName, provideName] = forStr === null ? [] : forStr.split(".");
6638
- if (!isString(compName) || !isString(provideName))
6639
- continue;
6640
- const defStr = isString(linfo?.default) ? linfo.default : null;
6641
- const val = defStr === null ? null : vp.parseField(defStr, ctx);
6642
- this.lookup[key] = new LookupInfo(key, compName, provideName, val);
6643
- }
6644
- for (const key in this.lookup)
6645
- if (this.provide[key] !== undefined)
6646
- console.warn("name declared in both provide and lookup", this.name, key);
6487
+ }
6488
+
6489
+ class BubbleEvent extends SendEvent {
6490
+ handlerProp = "bubble";
6491
+ constructor(path, transactor, name, args, parent, opts, targetPath) {
6492
+ super(path, transactor, name, args, parent, opts);
6493
+ this.targetPath = targetPath ?? path;
6647
6494
  }
6648
- make(args, opts) {
6649
- return this.Class.make(args, opts ?? { scope: this.scope });
6495
+ stopPropagation() {
6496
+ this.opts.bubbles = false;
6650
6497
  }
6651
- getView(name) {
6652
- return this.views[name] ?? this.views.main;
6498
+ }
6499
+
6500
+ class InputDispatchEvent extends NameArgsTransaction {
6501
+ handlerProp = "input";
6502
+ }
6503
+
6504
+ class Completion {
6505
+ constructor() {
6506
+ this.val = undefined;
6507
+ this.selfSettled = false;
6508
+ this.subtreeSettled = false;
6509
+ this.pending = 1;
6510
+ this._selfResolve = null;
6511
+ this._selfPromise = null;
6512
+ this._subtreeResolve = null;
6513
+ this._subtreePromise = null;
6514
+ this._selfReleased = false;
6515
+ }
6516
+ whenSettled() {
6517
+ if (this.selfSettled)
6518
+ return Promise.resolve(this.val);
6519
+ this._selfPromise ??= new Promise((res) => {
6520
+ this._selfResolve = res;
6521
+ });
6522
+ return this._selfPromise;
6653
6523
  }
6654
- getEventForId(id, name = "main") {
6655
- return this.getView(name).ctx.getEventForId(id);
6524
+ whenSubtreeSettled() {
6525
+ if (this.subtreeSettled)
6526
+ return Promise.resolve(this.val);
6527
+ this._subtreePromise ??= new Promise((res) => {
6528
+ this._subtreeResolve = res;
6529
+ });
6530
+ return this._subtreePromise;
6656
6531
  }
6657
- getNodeForId(id, name = "main") {
6658
- return this.getView(name).ctx.getNodeForId(id);
6532
+ markSelfSettled(val) {
6533
+ if (this.selfSettled)
6534
+ return;
6535
+ this.selfSettled = true;
6536
+ this.val = val;
6537
+ this._selfResolve?.(val);
6659
6538
  }
6660
- compileStyle() {
6661
- const { id, commonStyle, globalStyle, views } = this;
6662
- const styles = commonStyle ? [`[data-cid="${id}"]{${commonStyle}}`] : [];
6663
- if (globalStyle !== "")
6664
- styles.push(globalStyle);
6665
- for (const name in views) {
6666
- const { style } = views[name];
6667
- if (style !== "")
6668
- styles.push(`[data-cid="${id}"][data-vid="${name}"]{${style}}`);
6539
+ ensureSelfSettled() {
6540
+ if (!this.selfSettled)
6541
+ this.markSelfSettled(this.val);
6542
+ }
6543
+ track() {
6544
+ this.pending++;
6545
+ let done = false;
6546
+ return () => {
6547
+ if (done)
6548
+ return;
6549
+ done = true;
6550
+ this._release();
6551
+ };
6552
+ }
6553
+ releaseSelf() {
6554
+ if (this._selfReleased)
6555
+ return;
6556
+ this._selfReleased = true;
6557
+ this._release();
6558
+ }
6559
+ _release() {
6560
+ if (--this.pending === 0) {
6561
+ this.subtreeSettled = true;
6562
+ this._subtreeResolve?.(this.val);
6669
6563
  }
6670
- return styles.join(`
6671
- `);
6672
6564
  }
6673
6565
  }
6674
6566
 
6675
- // src/stack.js
6676
- var STOP = Symbol("STOP");
6677
- var NEXT = Symbol("NEXT");
6678
- function lookup(chain, name, dv = null) {
6679
- let n = chain;
6680
- while (n !== null) {
6681
- const r = n[0].lookup(name);
6682
- if (r === STOP)
6683
- return dv;
6684
- if (r !== NEXT)
6685
- return r;
6686
- n = n[1];
6687
- }
6688
- return dv;
6689
- }
6690
-
6691
- class BindFrame {
6692
- constructor(it, binds, isFrame) {
6693
- this.it = it;
6694
- this.binds = binds;
6695
- this.isFrame = isFrame;
6567
+ class Dispatcher {
6568
+ constructor(path, transactor, parentTransaction, root = transactor.state.val) {
6569
+ this.path = path;
6570
+ this.transactor = transactor;
6571
+ this.parent = parentTransaction;
6572
+ this.root = root;
6696
6573
  }
6697
- lookup(name) {
6698
- const v = this.binds[name];
6699
- return v === undefined ? this.isFrame ? STOP : NEXT : v;
6574
+ walkPath(callback) {
6575
+ const comps = this.transactor.comps;
6576
+ const chain = this.path.toTransactionPath().resolveChain(this.root);
6577
+ for (let i = chain.length - 1;i >= 0; i--) {
6578
+ const comp = comps.getCompFor(chain[i]);
6579
+ if (comp && callback(comp, chain[i]) === false)
6580
+ return;
6581
+ }
6700
6582
  }
6701
- }
6702
-
6703
- class ObjectFrame {
6704
- constructor(binds) {
6705
- this.binds = binds;
6583
+ get at() {
6584
+ return new PathChanges(this);
6706
6585
  }
6707
- lookup(key) {
6708
- const v = this.binds[key];
6709
- return v === undefined ? NEXT : v;
6586
+ send(name, args, opts) {
6587
+ return this.sendAtPath(this.path, name, args, opts);
6710
6588
  }
6711
- }
6712
- function computeViewsId(views) {
6713
- let s = "";
6714
- let n = views;
6715
- while (n !== null) {
6716
- s += n[0];
6717
- n = n[1];
6589
+ bubble(name, args, opts) {
6590
+ return this.send(name, args, { skipSelf: true, bubbles: true, ...opts });
6718
6591
  }
6719
- return s === "main" ? "" : s;
6720
- }
6721
-
6722
- class Stack {
6723
- constructor(comps, it, binds, dynBinds, views, viewsId, ctx = null) {
6724
- this.comps = comps;
6725
- this.it = it;
6726
- this.binds = binds;
6727
- this.dynBinds = dynBinds;
6728
- this.views = views;
6729
- this.viewsId = viewsId;
6730
- this.ctx = ctx;
6592
+ sendAtPath(path, name, args, opts) {
6593
+ return this.transactor.pushSend(path, name, args, opts, this.parent);
6731
6594
  }
6732
- _pushProvides() {
6733
- const provide = this.comps.getCompFor(this.it)?.provide;
6734
- if (provide == null)
6735
- return this;
6736
- const dynObj = {};
6737
- let has = false;
6738
- for (const k in provide) {
6739
- dynObj[provide[k].symbol] = provide[k].val.eval(this);
6740
- has = true;
6741
- }
6742
- if (!has)
6743
- return this;
6744
- const newDynBinds = [new ObjectFrame(dynObj), this.dynBinds];
6745
- const { comps, it, binds, views, viewsId, ctx } = this;
6746
- return new Stack(comps, it, binds, newDynBinds, views, viewsId, ctx);
6595
+ request(name, args, opts) {
6596
+ return this.requestAtPath(this.path, name, args, opts);
6747
6597
  }
6748
- static root(comps, it, ctx) {
6749
- const binds = [new BindFrame(it, { it }, true), null];
6750
- const dynBinds = [new ObjectFrame({}), null];
6751
- const views = ["main", null];
6752
- return new Stack(comps, it, binds, dynBinds, views, "", ctx)._pushProvides();
6598
+ requestAtPath(path, name, args, opts) {
6599
+ return this.transactor.pushRequest(path, name, args, opts, this.parent);
6753
6600
  }
6754
- enter(it, bindings = {}, isFrame = true) {
6755
- const { comps, binds, dynBinds, views, viewsId, ctx } = this;
6756
- const newBinds = [new BindFrame(it, bindings, isFrame), binds];
6757
- const stack = new Stack(comps, it, newBinds, dynBinds, views, viewsId, ctx);
6758
- return isFrame ? stack._pushProvides() : stack;
6601
+ inputAtPath(path, name, args, opts) {
6602
+ return this.transactor.pushInput(path, name, args, opts, this.parent);
6759
6603
  }
6760
- pushViewName(name) {
6761
- const { comps, it, binds, dynBinds, views, ctx } = this;
6762
- const newViews = [name, views];
6763
- return new Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
6604
+ lookupTypeFor(name, inst) {
6605
+ return this.transactor.comps.getCompFor(inst).scope.lookupComponent(name);
6764
6606
  }
6765
- _pushDynBindValuesToArray(arr, comp) {
6766
- for (const k in comp.provide)
6767
- arr.push(this._lookupProvide(comp.provide[k]));
6768
- for (const k in comp.lookup)
6769
- arr.push(this._lookupAlias(comp.lookup[k]));
6607
+ }
6608
+
6609
+ class EventContext extends Dispatcher {
6610
+ get name() {
6611
+ return this.parent?.name ?? null;
6770
6612
  }
6771
- _lookupProvide(p) {
6772
- return lookup(this.dynBinds, p.symbol) ?? p.val.eval(this) ?? null;
6613
+ get targetPath() {
6614
+ return this.parent.targetPath;
6773
6615
  }
6774
- _lookupAlias(lk) {
6775
- const sym = lk.getProducerSymbol(this);
6776
- return (sym != null ? lookup(this.dynBinds, sym) : null) ?? lk.val?.eval(this) ?? null;
6616
+ stopPropagation() {
6617
+ return this.parent.stopPropagation();
6777
6618
  }
6778
- lookupDynamic(name) {
6779
- const comp = this.comps.getCompFor(this.it);
6780
- if (comp == null)
6781
- return null;
6782
- const lk = comp.lookup[name];
6783
- if (lk !== undefined)
6784
- return this._lookupAlias(lk);
6785
- const p = comp.provide[name];
6786
- return p !== undefined ? this._lookupProvide(p) : null;
6619
+ }
6620
+
6621
+ class RequestContext extends Dispatcher {
6622
+ }
6623
+
6624
+ class PathChanges extends PathBuilder {
6625
+ constructor(dispatcher) {
6626
+ super();
6627
+ this.dispatcher = dispatcher;
6787
6628
  }
6788
- lookupBind(name) {
6789
- return lookup(this.binds, name);
6629
+ send(name, args, opts) {
6630
+ return this.dispatcher.sendAtPath(this.buildPath(), name, args, opts);
6790
6631
  }
6791
- lookupType(name) {
6792
- return this.comps.getCompFor(this.it).scope.lookupComponent(name);
6632
+ bubble(name, args, opts) {
6633
+ return this.send(name, args, { skipSelf: true, bubbles: true, ...opts });
6793
6634
  }
6794
- lookupFieldRaw(name) {
6795
- return this.it[name] ?? null;
6635
+ buildPath() {
6636
+ return this.dispatcher.path.concat(this.pathChanges);
6796
6637
  }
6797
- lookupMethod(name) {
6798
- const fn = this.it[name];
6799
- return fn instanceof Function ? fn.call(this.it) : null;
6638
+ }
6639
+ function rootDispatcher(transactor) {
6640
+ return new Dispatcher(new Path([]), transactor, null);
6641
+ }
6642
+
6643
+ // tools/core/results.js
6644
+ class ModuleInfo {
6645
+ constructor({ path = null, present = new Set, counts = {}, warnings = [] }) {
6646
+ this.path = path;
6647
+ this.present = present;
6648
+ this.counts = counts;
6649
+ this.warnings = warnings;
6800
6650
  }
6801
- lookupName(name) {
6802
- return this.ctx.lookupName(name);
6651
+ }
6652
+
6653
+ class ComponentSummary {
6654
+ constructor({ name, views, fields }) {
6655
+ this.name = name;
6656
+ this.views = views;
6657
+ this.fields = fields;
6803
6658
  }
6804
- getHandlerFor(name, key) {
6805
- return this.comps.getHandlerFor(this.it, name, key);
6659
+ }
6660
+
6661
+ class ComponentList {
6662
+ constructor({ items, total = null, truncated = false }) {
6663
+ this.items = items;
6664
+ this.total = total ?? items.length;
6665
+ this.truncated = truncated;
6806
6666
  }
6807
- lookupRequest(name) {
6808
- return this.comps.getRequestFor(this.it, name);
6667
+ }
6668
+
6669
+ class ExampleIndex {
6670
+ constructor({ sections, total = null, truncated = false }) {
6671
+ this.sections = sections;
6672
+ this.total = total ?? sections.reduce((n, s) => n + (s.items?.length ?? 0), 0);
6673
+ this.truncated = truncated;
6809
6674
  }
6810
- lookupBestView(views, defaultViewName) {
6811
- let n = this.views;
6812
- while (n !== null) {
6813
- const view = views[n[0]];
6814
- if (view !== undefined)
6815
- return view;
6816
- n = n[1];
6817
- }
6818
- return views[defaultViewName];
6675
+ }
6676
+
6677
+ class ComponentDocs {
6678
+ constructor({ items }) {
6679
+ this.items = items;
6819
6680
  }
6820
6681
  }
6821
6682
 
6822
- // src/transactor.js
6823
- class State2 {
6824
- constructor(val) {
6825
- this.val = val;
6826
- this.changeSubs = [];
6683
+ class LintFinding {
6684
+ constructor({ id, level, info, context = {}, suggestion = null }) {
6685
+ this.id = id;
6686
+ this.level = level;
6687
+ this.info = info;
6688
+ this.context = context;
6689
+ this.suggestion = suggestion;
6827
6690
  }
6828
- onChange(cb) {
6829
- this.changeSubs.push(cb);
6691
+ }
6692
+
6693
+ class LintComponentResult {
6694
+ constructor({ componentName, findings }) {
6695
+ this.componentName = componentName;
6696
+ this.findings = findings;
6830
6697
  }
6831
- set(val, info) {
6832
- const old = this.val;
6833
- this.val = val;
6834
- for (const sub of this.changeSubs)
6835
- sub({ val, old, info, timestamp: Date.now() });
6698
+ get errorCount() {
6699
+ return this.findings.filter((f) => f.level === "error").length;
6836
6700
  }
6837
- update(fn, info) {
6838
- return this.set(fn(this.val), info);
6701
+ get warnCount() {
6702
+ return this.findings.filter((f) => f.level === "warn").length;
6839
6703
  }
6840
6704
  }
6841
6705
 
6842
- class Transactor {
6843
- constructor(comps, rootValue) {
6844
- this.comps = comps;
6845
- this.transactions = [];
6846
- this.state = new State2(rootValue);
6847
- this.onTransactionPushed = () => {};
6706
+ class LintReport {
6707
+ constructor({ components }) {
6708
+ this.components = components;
6848
6709
  }
6849
- pushTransaction(t) {
6850
- this.transactions.push(t);
6851
- this.onTransactionPushed(t);
6710
+ get hasErrors() {
6711
+ return this.components.some((c) => c.errorCount > 0);
6852
6712
  }
6853
- pushSend(path, name, args = [], opts = {}, parent = null) {
6854
- this.pushTransaction(new SendEvent(path, this, name, args, parent, opts));
6713
+ get totalErrors() {
6714
+ return this.components.reduce((n, c) => n + c.errorCount, 0);
6855
6715
  }
6856
- pushBubble(path, name, args = [], opts = {}, parent = null, targetPath = null) {
6857
- const newOpts = opts.skipSelf ? { ...opts, skipSelf: false } : opts;
6858
- this.pushTransaction(new BubbleEvent(path, this, name, args, parent, newOpts, targetPath));
6859
- }
6860
- async pushRequest(path, name, args = [], opts = {}, parent = null) {
6861
- const curRoot = this.state.val;
6862
- const txnPath = path.toTransactionPath();
6863
- const curLeaf = txnPath.lookup(curRoot);
6864
- const handler = this.comps.getRequestFor(curLeaf, name) ?? mkReq404(name);
6865
- const reqCtx = new RequestContext(path, this, parent, curRoot);
6866
- const resHandlerName = opts?.onResName ?? name;
6867
- const resPath = opts?.livePath ? null : txnPath.pinKeys(curRoot);
6868
- const push = (specificName, baseName, singleArg, result, error) => {
6869
- const resArgs = specificName ? [singleArg] : [result, error];
6870
- const t = new ResponseEvent(path, this, specificName ?? baseName, resArgs, parent, resPath);
6871
- this.pushTransaction(t);
6872
- };
6873
- try {
6874
- const result = await handler.fn.apply(null, [...args, reqCtx]);
6875
- push(opts?.onOkName, resHandlerName, result, result, null);
6876
- } catch (error) {
6877
- push(opts?.onErrorName, resHandlerName, error, null, error);
6878
- }
6879
- }
6880
- get hasPendingTransactions() {
6881
- return this.transactions.length > 0;
6882
- }
6883
- transactNext() {
6884
- if (this.hasPendingTransactions)
6885
- this.transact(this.transactions.shift());
6886
- }
6887
- transact(transaction) {
6888
- const curState = this.state.val;
6889
- const newState = transaction.run(curState, this.comps);
6890
- if (newState !== undefined) {
6891
- this.state.set(newState, { transaction });
6892
- transaction.afterTransaction();
6893
- } else
6894
- console.warn("undefined new state", { curState, transaction });
6895
- }
6896
- transactInputNow(path, event, eventHandler, dragInfo) {
6897
- this.transact(new InputEvent(path, event, eventHandler, this, dragInfo));
6716
+ get totalWarnings() {
6717
+ return this.components.reduce((n, c) => n + c.warnCount, 0);
6898
6718
  }
6899
6719
  }
6900
- function mkReq404(name) {
6901
- const fn = () => {
6902
- throw new Error(`Request not found: ${name}`);
6903
- };
6904
- return { fn };
6905
- }
6906
- function nullHandler() {
6907
- return this;
6908
- }
6909
6720
 
6910
- class Transaction {
6911
- constructor(path, transactor, parentTransaction = null) {
6912
- this.path = path;
6913
- this.transactor = transactor;
6914
- this.parentTransaction = parentTransaction;
6915
- this._task = null;
6916
- }
6917
- get task() {
6918
- this._task ??= new Task;
6919
- return this._task;
6920
- }
6921
- getCompletionPromise() {
6922
- return this.task.promise;
6923
- }
6924
- setParent(parentTransaction) {
6925
- this.parentTransaction = parentTransaction;
6926
- parentTransaction.task.addDep(this.task);
6927
- }
6928
- run(rootValue, comps) {
6929
- return this.updateRootValue(rootValue, comps);
6930
- }
6931
- afterTransaction() {}
6932
- buildRootStack(root, comps) {
6933
- return Stack.root(comps, root);
6934
- }
6935
- buildStack(root, comps) {
6936
- return this.path.toTransactionPath().buildStack(this.buildRootStack(root, comps));
6937
- }
6938
- callHandler(root, instance, comps) {
6939
- const [handler, args] = this.getHandlerAndArgs(root, instance, comps);
6940
- return handler.apply(instance, args);
6941
- }
6942
- getHandlerAndArgs(_root, _instance, _comps) {
6943
- return null;
6944
- }
6945
- getTransactionPath() {
6946
- return this.path.toTransactionPath();
6947
- }
6948
- updateRootValue(curRoot, comps) {
6949
- const txnPath = this.getTransactionPath();
6950
- const curLeaf = txnPath.lookup(curRoot);
6951
- const newLeaf = this.callHandler(curRoot, curLeaf, comps);
6952
- this._task?.complete?.({ value: newLeaf, old: curLeaf });
6953
- return curLeaf !== newLeaf ? txnPath.setValue(curRoot, newLeaf) : curRoot;
6954
- }
6955
- lookupName(_name) {
6956
- return null;
6721
+ class RenderedExample {
6722
+ constructor({ title, description = null, componentName, view, html, error = null }) {
6723
+ this.title = title;
6724
+ this.description = description;
6725
+ this.componentName = componentName;
6726
+ this.view = view;
6727
+ this.html = html;
6728
+ this.error = error;
6957
6729
  }
6958
6730
  }
6959
- var toNullIfNaN = (v) => Number.isNaN(v) ? null : v;
6960
- function getValue(e) {
6961
- return e.target.type === "checkbox" ? e.target.checked : (e instanceof CustomEvent ? e.detail : e.target.value) ?? null;
6962
- }
6963
6731
 
6964
- class InputEvent extends Transaction {
6965
- constructor(path, e, handler, transactor, dragInfo) {
6966
- super(path, transactor);
6967
- this.e = e;
6968
- this.handler = handler;
6969
- this.dragInfo = dragInfo;
6970
- this._dispatchPath = null;
6971
- }
6972
- get dispatchPath() {
6973
- this._dispatchPath ??= this.path.compact();
6974
- return this._dispatchPath;
6975
- }
6976
- buildRootStack(root, comps) {
6977
- return Stack.root(comps, root, this);
6978
- }
6979
- getHandlerAndArgs(root, _instance, comps) {
6980
- const stack = this.buildStack(root, comps);
6981
- const [handler, args] = this.handler.getHandlerAndArgs(stack, this);
6982
- const path = this.dispatchPath;
6983
- let dispatcher;
6984
- for (let i = 0;i < args.length; i++) {
6985
- if (args[i]?.toHandlerArg) {
6986
- dispatcher ??= new Dispatcher(path, this.transactor, this);
6987
- args[i] = args[i].toHandlerArg(dispatcher);
6988
- }
6989
- }
6990
- args.push(new EventContext(path, this.transactor, this));
6991
- return [handler, args];
6992
- }
6993
- lookupName(name) {
6994
- const { e } = this;
6995
- switch (name) {
6996
- case "value":
6997
- return getValue(e);
6998
- case "valueAsInt":
6999
- return toNullIfNaN(parseInt(getValue(e), 10));
7000
- case "valueAsFloat":
7001
- return toNullIfNaN(parseFloat(getValue(e)));
7002
- case "target":
7003
- return e.target;
7004
- case "event":
7005
- return e;
7006
- case "isAlt":
7007
- return e.altKey;
7008
- case "isShift":
7009
- return e.shiftKey;
7010
- case "isCtrl":
7011
- case "isCmd":
7012
- return isMac && e.metaKey || e.ctrlKey;
7013
- case "key":
7014
- return e.key;
7015
- case "keyCode":
7016
- return e.keyCode;
7017
- case "isUpKey":
7018
- return e.key === "ArrowUp";
7019
- case "isDownKey":
7020
- return e.key === "ArrowDown";
7021
- case "isSend":
7022
- return e.key === "Enter";
7023
- case "isCancel":
7024
- return e.key === "Escape";
7025
- case "isTabKey":
7026
- return e.key === "Tab";
7027
- case "ctx":
7028
- return new EventContext(this.dispatchPath, this.transactor, this);
7029
- case "dragInfo":
7030
- return this.dragInfo;
7031
- }
7032
- return null;
6732
+ class RenderedSection {
6733
+ constructor({ title, description = null, items }) {
6734
+ this.title = title;
6735
+ this.description = description;
6736
+ this.items = items;
7033
6737
  }
7034
6738
  }
7035
6739
 
7036
- class NameArgsTransaction extends Transaction {
7037
- constructor(path, transactor, name, args, parentTransaction, opts = {}) {
7038
- super(path, transactor, parentTransaction);
7039
- this.name = name;
7040
- this.args = args;
7041
- this.opts = opts;
7042
- this.targetPath = path;
7043
- }
7044
- handlerProp = null;
7045
- getHandlerForName(comp) {
7046
- const handlers = comp?.[this.handlerProp];
7047
- return handlers?.[this.name] ?? handlers?.$unknown ?? nullHandler;
6740
+ class RenderBatch {
6741
+ constructor({ sections }) {
6742
+ this.sections = sections;
7048
6743
  }
7049
- getHandlerAndArgs(_root, instance, comps) {
7050
- const handler = this.getHandlerForName(comps.getCompFor(instance));
7051
- return [handler, [...this.args, new EventContext(this.path, this.transactor, this)]];
6744
+ get hasErrors() {
6745
+ return this.sections.some((s) => s.items.some((i) => i.error !== null));
7052
6746
  }
7053
6747
  }
7054
6748
 
7055
- class ResponseEvent extends NameArgsTransaction {
7056
- handlerProp = "response";
7057
- constructor(path, transactor, name, args, parent, txnPath = null) {
7058
- super(path, transactor, name, args, parent);
7059
- this._txnPath = txnPath;
7060
- }
7061
- getTransactionPath() {
7062
- return this._txnPath ?? super.getTransactionPath();
6749
+ class TestResult {
6750
+ constructor({ title, fullPath, componentName = null, status, durationMs = 0, error = null }) {
6751
+ this.title = title;
6752
+ this.fullPath = fullPath;
6753
+ this.componentName = componentName;
6754
+ this.status = status;
6755
+ this.durationMs = durationMs;
6756
+ this.error = error;
7063
6757
  }
7064
6758
  }
7065
6759
 
7066
- class SendEvent extends NameArgsTransaction {
7067
- handlerProp = "receive";
7068
- run(rootVal, comps) {
7069
- return this.opts.skipSelf ? rootVal : this.updateRootValue(rootVal, comps);
7070
- }
7071
- afterTransaction() {
7072
- const { path, name, args, opts, targetPath } = this;
7073
- if (opts.bubbles && path.steps.length > 0)
7074
- this.transactor.pushBubble(path.popStep(), name, args, opts, this, targetPath);
6760
+ class DescribeResult {
6761
+ constructor({ title, componentName = null, children = [] }) {
6762
+ this.title = title;
6763
+ this.componentName = componentName;
6764
+ this.children = children;
7075
6765
  }
7076
6766
  }
7077
6767
 
7078
- class BubbleEvent extends SendEvent {
7079
- handlerProp = "bubble";
7080
- constructor(path, transactor, name, args, parent, opts, targetPath) {
7081
- super(path, transactor, name, args, parent, opts);
7082
- this.targetPath = targetPath ?? path;
7083
- }
7084
- stopPropagation() {
7085
- this.opts.bubbles = false;
6768
+ class ModuleTestReport {
6769
+ constructor({ path = null, suites = [], counts = { pass: 0, fail: 0, skip: 0, total: 0 } }) {
6770
+ this.path = path;
6771
+ this.suites = suites;
6772
+ this.counts = counts;
7086
6773
  }
7087
6774
  }
7088
6775
 
7089
- class Task {
7090
- constructor() {
7091
- this.deps = [];
7092
- this.val = this.resolve = this.reject = null;
7093
- this.promise = new Promise((res, rej) => {
7094
- this.resolve = res;
7095
- this.reject = rej;
7096
- });
7097
- this.isCompleted = false;
6776
+ class TestReport {
6777
+ constructor({ modules = [] }) {
6778
+ this.modules = modules;
7098
6779
  }
7099
- addDep(task) {
7100
- console.assert(!this.isCompleted, "addDep for completed task", this, task);
7101
- this.deps.push(task);
7102
- task.promise.then((_) => this._check());
6780
+ get totals() {
6781
+ return this.modules.reduce((acc, m) => ({
6782
+ pass: acc.pass + m.counts.pass,
6783
+ fail: acc.fail + m.counts.fail,
6784
+ skip: acc.skip + m.counts.skip,
6785
+ total: acc.total + m.counts.total
6786
+ }), { pass: 0, fail: 0, skip: 0, total: 0 });
7103
6787
  }
7104
- complete(val) {
7105
- this.val = val;
7106
- this._check();
6788
+ get hasFailures() {
6789
+ return this.modules.some((m) => m.counts.fail > 0);
7107
6790
  }
7108
- _check() {
7109
- if (this.deps.every((task) => task.isCompleted)) {
7110
- this.isCompleted = true;
7111
- this.resolve(this);
7112
- }
6791
+ }
6792
+
6793
+ // tools/core/tests.js
6794
+ class Describe {
6795
+ constructor({ title, componentName = null, parent = null }) {
6796
+ this.title = title;
6797
+ this.componentName = componentName;
6798
+ this.parent = parent;
6799
+ this.children = [];
7113
6800
  }
7114
6801
  }
7115
6802
 
7116
- class Dispatcher {
7117
- constructor(path, transactor, parentTransaction, root = transactor.state.val) {
7118
- this.path = path;
7119
- this.transactor = transactor;
7120
- this.parent = parentTransaction;
7121
- this.root = root;
6803
+ class Test {
6804
+ constructor({ title, fn, componentName = null, parent = null }) {
6805
+ this.title = title;
6806
+ this.fn = fn;
6807
+ this.componentName = componentName;
6808
+ this.parent = parent;
7122
6809
  }
7123
- walkPath(callback) {
7124
- const comps = this.transactor.comps;
7125
- const chain = this.path.toTransactionPath().resolveChain(this.root);
7126
- for (let i = chain.length - 1;i >= 0; i--) {
7127
- const comp = comps.getCompFor(chain[i]);
7128
- if (comp && callback(comp, chain[i]) === false)
7129
- return;
7130
- }
7131
- }
7132
- get at() {
7133
- return new PathChanges(this);
7134
- }
7135
- send(name, args, opts) {
7136
- return this.sendAtPath(this.path, name, args, opts);
7137
- }
7138
- bubble(name, args, opts) {
7139
- return this.send(name, args, { skipSelf: true, bubbles: true, ...opts });
6810
+ }
6811
+
6812
+ class ModuleTests {
6813
+ constructor({ path = null, suites = [] } = {}) {
6814
+ this.path = path;
6815
+ this.suites = suites;
7140
6816
  }
7141
- sendAtPath(path, name, args, opts) {
7142
- return this.transactor.pushSend(path, name, args, opts, this.parent);
6817
+ }
6818
+
6819
+ class TestIndex {
6820
+ constructor({ modules = [] } = {}) {
6821
+ this.modules = modules;
7143
6822
  }
7144
- request(name, args, opts) {
7145
- return this.requestAtPath(this.path, name, args, opts);
6823
+ }
6824
+ function isComponentObject(x) {
6825
+ return x !== null && typeof x === "object" && typeof x.name === "string" && typeof x.Class === "function";
6826
+ }
6827
+ function resolveComponentName(arg, components) {
6828
+ if (isComponentObject(arg))
6829
+ return arg.name;
6830
+ if (typeof arg === "function") {
6831
+ for (const c of components)
6832
+ if (c.Class === arg)
6833
+ return c.name;
7146
6834
  }
7147
- requestAtPath(path, name, args, opts) {
7148
- return this.transactor.pushRequest(path, name, args, opts, this.parent);
6835
+ return null;
6836
+ }
6837
+ function titleFromArg(arg) {
6838
+ if (typeof arg === "string")
6839
+ return arg;
6840
+ if (isComponentObject(arg))
6841
+ return arg.name;
6842
+ if (typeof arg === "function")
6843
+ return arg.name || "(anonymous)";
6844
+ return String(arg);
6845
+ }
6846
+ function makeCollector({ path = null, components = [] } = {}) {
6847
+ const moduleTests = new ModuleTests({ path, suites: [] });
6848
+ const stack = [];
6849
+ function describe(...args) {
6850
+ let head;
6851
+ let options = null;
6852
+ let fn;
6853
+ if (args.length === 2) {
6854
+ [head, fn] = args;
6855
+ } else if (args.length === 3) {
6856
+ [head, options, fn] = args;
6857
+ } else {
6858
+ throw new Error(`describe() expects 2 or 3 arguments, got ${args.length}`);
6859
+ }
6860
+ if (typeof fn !== "function") {
6861
+ throw new Error(`describe(${JSON.stringify(titleFromArg(head))}): final argument must be a function`);
6862
+ }
6863
+ let componentName = null;
6864
+ if (typeof head !== "string") {
6865
+ componentName = resolveComponentName(head, components);
6866
+ }
6867
+ if (componentName === null && options && options.component != null) {
6868
+ componentName = resolveComponentName(options.component, components);
6869
+ }
6870
+ if (componentName === null) {
6871
+ const parent2 = stack.length ? stack[stack.length - 1] : null;
6872
+ if (parent2)
6873
+ componentName = parent2.componentName;
6874
+ }
6875
+ const parent = stack.length ? stack[stack.length - 1] : null;
6876
+ const node = new Describe({
6877
+ title: titleFromArg(head),
6878
+ componentName,
6879
+ parent
6880
+ });
6881
+ if (parent)
6882
+ parent.children.push(node);
6883
+ else
6884
+ moduleTests.suites.push(node);
6885
+ stack.push(node);
6886
+ try {
6887
+ fn();
6888
+ } finally {
6889
+ stack.pop();
6890
+ }
7149
6891
  }
7150
- lookupTypeFor(name, inst) {
7151
- return this.transactor.comps.getCompFor(inst).scope.lookupComponent(name);
6892
+ function test(title, fn) {
6893
+ if (typeof title !== "string") {
6894
+ throw new Error("test(title, fn): title must be a string");
6895
+ }
6896
+ if (typeof fn !== "function") {
6897
+ throw new Error(`test(${JSON.stringify(title)}): fn must be a function`);
6898
+ }
6899
+ const parent = stack.length ? stack[stack.length - 1] : null;
6900
+ if (!parent) {
6901
+ throw new Error(`test(${JSON.stringify(title)}) must be called inside a describe()`);
6902
+ }
6903
+ parent.children.push(new Test({
6904
+ title,
6905
+ fn,
6906
+ componentName: parent.componentName,
6907
+ parent
6908
+ }));
7152
6909
  }
6910
+ return { describe, test, moduleTests };
7153
6911
  }
7154
6912
 
7155
- class EventContext extends Dispatcher {
7156
- get name() {
7157
- return this.parent?.name ?? null;
7158
- }
7159
- get targetPath() {
7160
- return this.parent.targetPath;
7161
- }
7162
- stopPropagation() {
7163
- return this.parent.stopPropagation();
6913
+ // tools/core/test.js
6914
+ function buildPath(node) {
6915
+ const parts = [];
6916
+ let cur = node;
6917
+ while (cur) {
6918
+ parts.unshift(cur.title);
6919
+ cur = cur.parent;
7164
6920
  }
6921
+ return parts.join(" > ");
7165
6922
  }
7166
-
7167
- class RequestContext extends Dispatcher {
6923
+ function captureError(e) {
6924
+ const out = { message: e.message, stack: e.stack };
6925
+ if ("expected" in e)
6926
+ out.expected = e.expected;
6927
+ if ("actual" in e)
6928
+ out.actual = e.actual;
6929
+ return out;
7168
6930
  }
7169
-
7170
- class PathChanges extends PathBuilder {
7171
- constructor(dispatcher) {
7172
- super();
7173
- this.dispatcher = dispatcher;
6931
+ function buildStack({ components = [], macros = null, requestHandlers = null } = {}) {
6932
+ const stack = new ComponentStack;
6933
+ stack.registerComponents(components);
6934
+ if (macros)
6935
+ stack.registerMacros(macros);
6936
+ if (requestHandlers)
6937
+ stack.registerRequestHandlers(requestHandlers);
6938
+ return stack;
6939
+ }
6940
+ async function driveStack(stack, value, phase, opts = {}) {
6941
+ const transactor = new Transactor(stack.comps, value);
6942
+ if (opts.onMessage)
6943
+ transactor.state.onChange(({ val, old, info }) => {
6944
+ const t = info?.transaction;
6945
+ opts.onMessage({ kind: t?.handlerProp ?? "input", name: t?.name, args: t?.args, path: t?.path }, old, val);
6946
+ });
6947
+ dispatchPhase(rootDispatcher(transactor), new Path([]), phase, value);
6948
+ await transactor.settle();
6949
+ return transactor.state.val;
6950
+ }
6951
+ async function drive(cfg, value, phase, opts = {}) {
6952
+ return driveStack(buildStack(cfg), value, phase, opts);
6953
+ }
6954
+ async function runTests({
6955
+ getTests,
6956
+ components = [],
6957
+ path = null,
6958
+ expect: expect2,
6959
+ name = null,
6960
+ grep = null,
6961
+ bail = false,
6962
+ requestHandlers = null,
6963
+ macros = null
6964
+ } = {}) {
6965
+ const counts = { pass: 0, fail: 0, skip: 0, total: 0 };
6966
+ if (typeof getTests !== "function") {
6967
+ return new TestReport({
6968
+ modules: [new ModuleTestReport({ path, suites: [], counts })]
6969
+ });
7174
6970
  }
7175
- send(name, args, opts) {
7176
- return this.dispatcher.sendAtPath(this.buildPath(), name, args, opts);
6971
+ if (typeof expect2 !== "function") {
6972
+ throw new Error("runTests: expect must be provided (e.g. chai's expect)");
7177
6973
  }
7178
- bubble(name, args, opts) {
7179
- return this.send(name, args, { skipSelf: true, bubbles: true, ...opts });
6974
+ const { describe, test, moduleTests } = makeCollector({ path, components });
6975
+ let _stack = null;
6976
+ const getStack = () => _stack ??= buildStack({ components, macros, requestHandlers });
6977
+ const driveLocal = (value, phase, opts = {}) => driveStack(getStack(), value, phase, opts);
6978
+ await getTests({ describe, test, expect: expect2, drive: driveLocal });
6979
+ let bailed = false;
6980
+ async function visit(node) {
6981
+ if (node instanceof Test) {
6982
+ if (name !== null && node.componentName !== name)
6983
+ return null;
6984
+ const fullPath = buildPath(node);
6985
+ if (grep !== null && !fullPath.includes(grep))
6986
+ return null;
6987
+ counts.total++;
6988
+ if (bailed) {
6989
+ counts.skip++;
6990
+ return new TestResult({
6991
+ title: node.title,
6992
+ fullPath,
6993
+ componentName: node.componentName,
6994
+ status: "skip"
6995
+ });
6996
+ }
6997
+ const start = performance.now();
6998
+ try {
6999
+ await node.fn();
7000
+ counts.pass++;
7001
+ return new TestResult({
7002
+ title: node.title,
7003
+ fullPath,
7004
+ componentName: node.componentName,
7005
+ status: "pass",
7006
+ durationMs: performance.now() - start
7007
+ });
7008
+ } catch (e) {
7009
+ counts.fail++;
7010
+ if (bail)
7011
+ bailed = true;
7012
+ return new TestResult({
7013
+ title: node.title,
7014
+ fullPath,
7015
+ componentName: node.componentName,
7016
+ status: "fail",
7017
+ durationMs: performance.now() - start,
7018
+ error: captureError(e)
7019
+ });
7020
+ }
7021
+ }
7022
+ const childResults = [];
7023
+ for (const child of node.children) {
7024
+ const r = await visit(child);
7025
+ if (r !== null)
7026
+ childResults.push(r);
7027
+ }
7028
+ if (childResults.length === 0)
7029
+ return null;
7030
+ return new DescribeResult({
7031
+ title: node.title,
7032
+ componentName: node.componentName,
7033
+ children: childResults
7034
+ });
7180
7035
  }
7181
- buildPath() {
7182
- return this.dispatcher.path.concat(this.pathChanges);
7036
+ const suiteResults = [];
7037
+ for (const suite of moduleTests.suites) {
7038
+ const r = await visit(suite);
7039
+ if (r !== null)
7040
+ suiteResults.push(r);
7041
+ }
7042
+ return new TestReport({
7043
+ modules: [new ModuleTestReport({ path, suites: suiteResults, counts })]
7044
+ });
7045
+ }
7046
+
7047
+ // tools/core/test-console.js
7048
+ var PASS = "color: #0a0; font-weight: bold";
7049
+ var FAIL = "color: #c00; font-weight: bold";
7050
+ var SKIP = "color: #888";
7051
+ var DIM = "color: #888";
7052
+ var RESET = "color: inherit; font-weight: normal";
7053
+ function reportTestNode(node) {
7054
+ if (node.children) {
7055
+ const label = node.componentName ? `${node.title} [${node.componentName}]` : node.title;
7056
+ console.group(label);
7057
+ for (const child of node.children)
7058
+ reportTestNode(child);
7059
+ console.groupEnd();
7060
+ return;
7061
+ }
7062
+ const dur = node.status === "skip" ? "" : ` (${Math.round(node.durationMs)}ms)`;
7063
+ if (node.status === "pass") {
7064
+ console.log(`%c✓%c ${node.title}%c${dur}`, PASS, RESET, DIM);
7065
+ } else if (node.status === "skip") {
7066
+ console.log(`%c○ ${node.title}%c (skipped)`, SKIP, RESET);
7067
+ } else {
7068
+ console.group(`%c✗%c ${node.title}%c${dur}`, FAIL, RESET, DIM);
7069
+ console.error(node.error?.message ?? "(no error message)");
7070
+ if (node.error && (("expected" in node.error) || ("actual" in node.error))) {
7071
+ console.log("expected:", node.error.expected);
7072
+ console.log("actual: ", node.error.actual);
7073
+ }
7074
+ if (node.error?.stack)
7075
+ console.log(node.error.stack);
7076
+ console.groupEnd();
7077
+ }
7078
+ }
7079
+ function reportTestReportToConsole(report) {
7080
+ for (const m of report.modules) {
7081
+ const label = `tutuca tests${m.path ? ` — ${m.path}` : ""}`;
7082
+ console.group(label);
7083
+ if (m.suites.length === 0) {
7084
+ console.log("(no tests)");
7085
+ } else {
7086
+ for (const s of m.suites)
7087
+ reportTestNode(s);
7088
+ }
7089
+ const c = m.counts;
7090
+ const summary = `${c.pass} passed, ${c.fail} failed, ${c.skip} skipped (${c.total} total)`;
7091
+ if (c.fail > 0)
7092
+ console.error(`%c${summary}`, FAIL);
7093
+ else if (c.total === 0)
7094
+ console.log(`%c${summary}`, DIM);
7095
+ else
7096
+ console.log(`%c${summary}`, PASS);
7097
+ console.groupEnd();
7098
+ }
7099
+ return report;
7100
+ }
7101
+
7102
+ // tools/format/lint.js
7103
+ var UNSUPPORTED_EXPR_LABEL = {
7104
+ ternary: "ternary expression",
7105
+ comparison: "comparison",
7106
+ logical: "logical expression",
7107
+ "call-with-args": "method call with arguments"
7108
+ };
7109
+ function unsupportedExprMessage(info) {
7110
+ const v = JSON.stringify(info.value);
7111
+ const label = UNSUPPORTED_EXPR_LABEL[info.detected] ?? "expression";
7112
+ switch (info.role) {
7113
+ case "attr":
7114
+ return `Unsupported ${label} ${v} in dynamic attribute ':${info.attr}'`;
7115
+ case "directive":
7116
+ return `Unsupported ${label} ${v} in directive '@${info.directive}'`;
7117
+ case "if":
7118
+ return `Unsupported ${label} ${v} in '@if.${info.attr}' condition`;
7119
+ case "x-op":
7120
+ return `Unsupported ${label} ${v} in <x ${info.op}>`;
7121
+ default:
7122
+ return `Unsupported ${label} ${v}`;
7123
+ }
7124
+ }
7125
+ function badValueMessage(info) {
7126
+ const v = JSON.stringify(info.value);
7127
+ switch (info.role) {
7128
+ case "attr":
7129
+ return `Cannot parse value ${v} for attribute ':${info.attr}'`;
7130
+ case "directive":
7131
+ return `Cannot parse value ${v} for directive '@${info.directive}'`;
7132
+ case "if":
7133
+ return `Cannot parse condition ${v} for '@if.${info.attr}'`;
7134
+ case "x-op":
7135
+ return `Cannot parse value ${v} for <x ${info.op}>`;
7136
+ case "handler-name":
7137
+ return `Cannot parse handler name ${v}`;
7138
+ case "handler-arg":
7139
+ return `Cannot parse handler argument ${v}`;
7140
+ case "macro-var":
7141
+ return `Macro variable '^${info.name}' is not defined`;
7142
+ default:
7143
+ return `Cannot parse value ${v}`;
7144
+ }
7145
+ }
7146
+ function tagDisplay(tag) {
7147
+ return tag ? String(tag).toLowerCase() : null;
7148
+ }
7149
+ function fmtTagSuffix(info) {
7150
+ const t = tagDisplay(info?.tag);
7151
+ return t && t !== "x" ? ` on <${t}>` : "";
7152
+ }
7153
+ function fmtOriginSuffix(info) {
7154
+ if (!info)
7155
+ return "";
7156
+ const parts = [];
7157
+ if (info.originAttr) {
7158
+ const branch = info.branch ? `[${info.branch}]` : "";
7159
+ parts.push(`in ${info.originAttr}${branch}`);
7160
+ }
7161
+ if (info.handlerName) {
7162
+ parts.push(`handler '${info.handlerName}'${info.argIndex !== undefined ? ` arg ${info.argIndex}` : ""}`);
7163
+ }
7164
+ const t = tagDisplay(info.tag);
7165
+ if (t && t !== "x")
7166
+ parts.push(`on <${t}>`);
7167
+ return parts.length ? ` (${parts.join(", ")})` : "";
7168
+ }
7169
+ function fmtEventSuffix(info) {
7170
+ if (info?.originAttr)
7171
+ return ` in ${info.originAttr}`;
7172
+ if (info?.eventName)
7173
+ return ` in @on.${info.eventName}`;
7174
+ return "";
7175
+ }
7176
+ function lintIdToMessage(id, info) {
7177
+ switch (id) {
7178
+ case "RENDER_IT_OUTSIDE_OF_LOOP":
7179
+ return "<x render-it> used outside of a loop";
7180
+ case "UNKNOWN_EVENT_MODIFIER": {
7181
+ const mods = info.handler?.modifiers ?? [info.modifier];
7182
+ const written = `@on.${info.name}+${mods.join("+")}`;
7183
+ return `Unknown modifier '+${info.modifier}' in '${written}'`;
7184
+ }
7185
+ case "UNKNOWN_HANDLER_ARG_NAME":
7186
+ return `Unknown handler argument '${info.name}'${fmtOriginSuffix(info)}`;
7187
+ case "INPUT_HANDLER_NOT_IMPLEMENTED":
7188
+ return `Input handler '${info.name}' is not implemented${fmtEventSuffix(info)}`;
7189
+ case "INPUT_HANDLER_NOT_REFERENCED":
7190
+ return `Input handler '${info.name}' is defined but never used — remove it or wire it to an @on.* event`;
7191
+ case "INPUT_HANDLER_METHOD_NOT_IMPLEMENTED":
7192
+ return `Method '$${info.name}' is not implemented${fmtEventSuffix(info)}`;
7193
+ case "INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD":
7194
+ return `'$${info.name}' is a method reference, but '${info.name}' is defined as an input handler${fmtEventSuffix(info)}`;
7195
+ case "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER":
7196
+ return `'${info.name}' is an input handler reference, but '${info.name}' is defined as a method${fmtEventSuffix(info)}`;
7197
+ case "FIELD_VAL_NOT_DEFINED":
7198
+ return `Field '.${info.name}' is not defined${fmtOriginSuffix(info)}`;
7199
+ case "FIELD_VAL_IS_METHOD":
7200
+ return `'.${info.name}' reads a field, but '${info.name}' is defined as a method — use '$${info.name}'${fmtOriginSuffix(info)}`;
7201
+ case "METHOD_VAL_NOT_DEFINED":
7202
+ return `Method '$${info.name}' is not defined${fmtOriginSuffix(info)}`;
7203
+ case "METHOD_VAL_IS_FIELD":
7204
+ return `'$${info.name}' calls a method, but '${info.name}' is defined as a field — use '.${info.name}'${fmtOriginSuffix(info)}`;
7205
+ case "DUPLICATE_ATTR_DEFINITION": {
7206
+ const sources = info.sources?.length ? ` (${info.sources.join(", ")})` : "";
7207
+ const tag = info.tag ? ` on <${String(info.tag).toLowerCase()}>` : "";
7208
+ return `Attribute '${info.name}' is set ${info.sources?.length ?? "multiple"} times${sources}${tag}`;
7209
+ }
7210
+ case "IF_NO_BRANCH_SET":
7211
+ return `'@if.${info.attr}' has no '@then' or '@else' branch — add '@then="…"' or '@else="…"' (or both)${fmtTagSuffix(info)}`;
7212
+ case "UNKNOWN_REQUEST_NAME":
7213
+ return `Unknown request '!${info.name}'${fmtOriginSuffix(info)}`;
7214
+ case "UNKNOWN_COMPONENT_NAME":
7215
+ return `Unknown component '${info.name}'${fmtOriginSuffix(info)}`;
7216
+ case "ALT_HANDLER_NOT_DEFINED":
7217
+ return `Alter handler '${info.name}' is not defined${fmtOriginSuffix(info)}`;
7218
+ case "ALT_HANDLER_NOT_REFERENCED":
7219
+ return `Alter handler '${info.name}' is defined but never used — remove it or reference it from @when, @enrich-with, or @loop-with`;
7220
+ case "DYN_VAL_NOT_DEFINED":
7221
+ return `Dynamic variable '*${info.name}' is not defined${fmtOriginSuffix(info)}`;
7222
+ case "DYN_ALIAS_NOT_REFERENCED":
7223
+ return `Lookup '${info.name}' is defined but never used — remove it or reference it as '*${info.name}' in a view`;
7224
+ case "PROVIDE_NOT_ADDRESSABLE":
7225
+ return `Provide '${info.name}' value '${info.value}' must be a field ('.f') or seq-access ('.s[.k]') — a method/constant can't be a render target`;
7226
+ case "LOOKUP_BAD_SHAPE":
7227
+ return `Lookup '${info.name}' has an invalid shape: ${info.problem}`;
7228
+ case "LOOKUP_TARGET_MALFORMED":
7229
+ return `Lookup '${info.name}' target '${info.target}' must be 'Producer.provideName' (a string, or the 'for' of { for, default })`;
7230
+ case "UNKNOWN_MACRO_ARG":
7231
+ return `Argument '${info.name}' is not declared in macro '${info.macroName}'`;
7232
+ case "UNKNOWN_DIRECTIVE":
7233
+ return `Unknown directive '@${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
7234
+ case "UNKNOWN_X_OP":
7235
+ return `Unknown <x> op '${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
7236
+ case "UNKNOWN_X_ATTR":
7237
+ return `Unknown attribute '${info.name}=${JSON.stringify(info.value)}' on <x ${info.op}>${fmtTagSuffix(info)}`;
7238
+ case "MAYBE_DROP_AT_PREFIX": {
7239
+ const written = info.value !== undefined ? `${info.name}=${JSON.stringify(info.value)}` : info.name;
7240
+ return `'${written}' on <x> looks like a directive but is actually an x op/attr written with a leading '@'`;
7241
+ }
7242
+ case "MAYBE_ADD_AT_PREFIX":
7243
+ return `'${info.name}' on <${(info.tag ?? "").toLowerCase()}> is a plain attribute, but '@${info.name}' is a directive — add the leading '@'`;
7244
+ case "BAD_VALUE":
7245
+ return `${badValueMessage(info)}${fmtTagSuffix(info)}`;
7246
+ case "UNSUPPORTED_EXPR_SYNTAX":
7247
+ return `${unsupportedExprMessage(info)}${fmtTagSuffix(info)}`;
7248
+ case "REDUNDANT_TEMPLATE_STRING":
7249
+ return `Redundant template string — '{${info.simpler}}' should be just '${info.simpler}'${fmtOriginSuffix(info)}`;
7250
+ case "PLACEHOLDERLESS_TEMPLATE_STRING":
7251
+ return `Template string has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
7252
+ case "UNKNOWN_COMPONENT_SPEC_KEY":
7253
+ return `Unknown component spec key '${info.key}' — value will be ignored at runtime`;
7254
+ case "COMP_FIELD_BAD_SHAPE":
7255
+ return info.kind === "args-not-object" ? `Field '${info.fieldName}': in { component, args }, 'args' must be a plain object, got ${info.got}` : `Field '${info.fieldName}': in { component, args }, 'component' must be the component name as a string, got ${info.gotName ? `the ${info.gotName} class` : info.got}`;
7256
+ case "HTML_TAG_NAME_HAS_UPPERCASE":
7257
+ return `Tag <${info.raw}> will be lowercased to <${info.lowercased}>${fmtLocationSuffix(info)}`;
7258
+ case "HTML_SVG_TAG_WILL_LOWERCASE":
7259
+ return `SVG tag <${info.raw}> is not in the WHATWG case-correction list — will be lowercased to <${info.lowercased}>${fmtLocationSuffix(info)}`;
7260
+ case "HTML_TAG_NOT_ALLOWED_IN_PARENT":
7261
+ return `<${info.tag}> not allowed under <${info.parent ?? "?"}> in ${info.mode} — ${htmlActionPhrase(info.action, info.tag, info.parent)}${fmtLocationSuffix(info)}`;
7262
+ case "HTML_TEXT_NOT_ALLOWED_IN_PARENT":
7263
+ return `Non-whitespace text not allowed in ${info.mode}: ${JSON.stringify(info.snippet)}${fmtLocationSuffix(info)}`;
7264
+ case "HTML_VOID_ELEMENT_HAS_CLOSE_TAG":
7265
+ return `Void element <${info.tag}> has an explicit close tag${fmtLocationSuffix(info)}`;
7266
+ case "HTML_DUPLICATE_FORM":
7267
+ return `Nested <form> — the inner form will be dropped by the parser${fmtLocationSuffix(info)}`;
7268
+ case "HTML_NESTED_INTERACTIVE":
7269
+ return `<${info.tag}> nested inside another <${info.tag}> — adoption agency will reorder${fmtLocationSuffix(info)}`;
7270
+ case "HTML_MISNESTED_FORMATTING":
7271
+ return `Misnested formatting tag </${info.tag}> — adoption agency will reorder nodes${fmtLocationSuffix(info)}`;
7272
+ case "HTML_UNEXPECTED_END_TAG":
7273
+ return `Unexpected end tag </${info.tag}>${fmtLocationSuffix(info)}`;
7274
+ case "HTML_UNCLOSED_BEFORE_END":
7275
+ return `<${info.unclosed}> still open when </${info.tag}> was seen — implicitly closed${fmtLocationSuffix(info)}`;
7276
+ case "HTML_DUPLICATE_ATTRIBUTE":
7277
+ return `Duplicate attribute '${info.name}' — second occurrence dropped${fmtLocationSuffix(info)}`;
7278
+ case "HTML_ATTRIBUTES_ON_END_TAG":
7279
+ return `Attributes on end tag </${info.tag}> — dropped by the parser${fmtLocationSuffix(info)}`;
7280
+ case "HTML_SELF_CLOSING_END_TAG":
7281
+ return `Self-closing end tag </${info.tag}/> — trailing '/' is meaningless${fmtLocationSuffix(info)}`;
7282
+ case "HTML_MISSING_ATTRIBUTE_VALUE":
7283
+ return `Attribute '${info.name}' is missing a value${fmtLocationSuffix(info)}`;
7284
+ case "HTML_CDATA_IN_HTML_NAMESPACE":
7285
+ return `CDATA section in HTML namespace — reinterpreted as a bogus comment${fmtLocationSuffix(info)}`;
7286
+ case "HTML_BOGUS_COMMENT":
7287
+ return `Bogus comment — content dropped by the parser${fmtLocationSuffix(info)}`;
7288
+ case "HTML_SVG_ATTR_WILL_LOWERCASE":
7289
+ return `SVG attribute '${info.raw}' will be rewritten to '${info.canonical}'${fmtLocationSuffix(info)}`;
7290
+ case "HTML_MATHML_ATTR_WILL_LOWERCASE":
7291
+ return `MathML attribute '${info.raw}' will be rewritten to '${info.canonical}'${fmtLocationSuffix(info)}`;
7292
+ case "ASYNC_HANDLER":
7293
+ return `Handler '${info.name}' in '${info.channel}' is an async function — handlers must be synchronous and return the updated state (an async function returns a Promise the framework won't await)`;
7294
+ case "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE":
7295
+ return `'@${info.atRule}' is a top-level-only at-rule, but '${info.key}' is wrapped in a component-scoped selector ([data-cid=…]{…}) where it is invalid and silently dropped — move it to 'globalStyle'${fmtLocationSuffix(info)}`;
7296
+ case "GLOBAL_SELECTOR_IN_SCOPED_STYLE":
7297
+ return `Selector '${info.selector}' targets the document root, but '${info.key}' is wrapped in a component-scoped selector, so it becomes a descendant selector that never matches — move it to 'globalStyle'${fmtLocationSuffix(info)}`;
7298
+ case "LINT_ERROR":
7299
+ return info.message;
7300
+ default:
7301
+ return id;
7302
+ }
7303
+ }
7304
+ function suggestionToMessage(suggestion) {
7305
+ if (!suggestion)
7306
+ return null;
7307
+ switch (suggestion.kind) {
7308
+ case "replace-name":
7309
+ return `did you mean '${suggestion.to}'?`;
7310
+ case "drop-prefix":
7311
+ return `did you mean '${suggestion.to}'? (drop the leading '${suggestion.from.slice(0, suggestion.from.length - suggestion.to.length)}')`;
7312
+ case "add-prefix":
7313
+ return `did you mean '${suggestion.to}'? (add the leading '${suggestion.to.slice(0, suggestion.to.length - suggestion.from.length)}')`;
7314
+ case "remove":
7315
+ return `remove ${suggestion.what}`;
7316
+ case "rewrite":
7317
+ return `use '${suggestion.to}' instead of '${suggestion.from}'`;
7318
+ case "wrap":
7319
+ return `wrap it in ${suggestion.to}`;
7320
+ case "rephrase":
7321
+ return suggestion.text ?? null;
7322
+ default:
7323
+ return null;
7324
+ }
7325
+ }
7326
+ function fmtLocationSuffix(info) {
7327
+ const loc = info?.location;
7328
+ if (!loc)
7329
+ return "";
7330
+ return ` at line ${loc.line}, col ${loc.column}`;
7331
+ }
7332
+ function htmlActionPhrase(action, tag, parent) {
7333
+ switch (action) {
7334
+ case "ignored":
7335
+ return `the parser will drop this <${tag}>`;
7336
+ case "drop":
7337
+ return `the parser will drop this <${tag}>`;
7338
+ case "auto-close-implicit":
7339
+ return `the parser will close <${parent ?? "?"}> first, then place <${tag}> as a sibling`;
7340
+ case "foster-parent":
7341
+ return `the parser will move <${tag}> outside <${parent ?? "?"}> (foster-parenting)`;
7342
+ case "foreign-breakout":
7343
+ return `the parser will exit foreign content and re-process <${tag}> in HTML mode`;
7344
+ default:
7345
+ return `parser action: ${action}`;
7183
7346
  }
7184
7347
  }
7185
7348
 
@@ -8208,9 +8371,11 @@ export {
8208
8371
  setIn,
8209
8372
  set,
8210
8373
  runTests,
8374
+ resolveArgs,
8211
8375
  reportTestReportToConsole,
8212
8376
  removeIn,
8213
8377
  remove,
8378
+ phaseOps,
8214
8379
  mergeWith,
8215
8380
  mergeDeepWith,
8216
8381
  mergeDeep,
@@ -8246,7 +8411,9 @@ export {
8246
8411
  getComponentsDocs,
8247
8412
  get,
8248
8413
  fromJS,
8414
+ drive,
8249
8415
  docComponents,
8416
+ dispatchPhase,
8250
8417
  css,
8251
8418
  component,
8252
8419
  compileClassesToStyleText,