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