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.js
CHANGED
|
@@ -12684,6 +12684,8 @@ var PLACEHOLDERLESS_TEMPLATE_STRING = "PLACEHOLDERLESS_TEMPLATE_STRING";
|
|
|
12684
12684
|
var UNKNOWN_COMPONENT_SPEC_KEY = "UNKNOWN_COMPONENT_SPEC_KEY";
|
|
12685
12685
|
var COMP_FIELD_BAD_SHAPE = "COMP_FIELD_BAD_SHAPE";
|
|
12686
12686
|
var ASYNC_HANDLER = "ASYNC_HANDLER";
|
|
12687
|
+
var TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE = "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE";
|
|
12688
|
+
var GLOBAL_SELECTOR_IN_SCOPED_STYLE = "GLOBAL_SELECTOR_IN_SCOPED_STYLE";
|
|
12687
12689
|
var X_KNOWN_OP_NAMES = new Set([
|
|
12688
12690
|
"slot",
|
|
12689
12691
|
"text",
|
|
@@ -12775,6 +12777,7 @@ function checkComponent(Comp, lx = new LintContext, { wellKnownExtras = EMPTY_SE
|
|
|
12775
12777
|
checkProvidesAreAddressable(lx, Comp);
|
|
12776
12778
|
checkLookupShapes(lx, Comp);
|
|
12777
12779
|
checkHandlersNotAsync(lx, Comp);
|
|
12780
|
+
checkScopedStyleTopLevel(lx, Comp);
|
|
12778
12781
|
const referencedAlters = new Set;
|
|
12779
12782
|
const referencedInputs = new Set;
|
|
12780
12783
|
const referencedDynamics = new Set;
|
|
@@ -13292,6 +13295,69 @@ function checkHandlersNotAsync(lx, Comp) {
|
|
|
13292
13295
|
}
|
|
13293
13296
|
}
|
|
13294
13297
|
}
|
|
13298
|
+
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;
|
|
13299
|
+
var GLOBAL_LEADING_SELECTOR = /(?:^|[{}])\s*(html|body|:root)\b[^{};]*\{/gi;
|
|
13300
|
+
var IGNORE_DIRECTIVE = /\/\*\s*tutuca-lint-ignore\s*\*\//g;
|
|
13301
|
+
var blankRun = (m) => m.replace(/[^\n]/g, " ");
|
|
13302
|
+
function blankCssNoise(css) {
|
|
13303
|
+
return css.replace(/\/\*[\s\S]*?\*\//g, blankRun).replace(/"(?:[^"\\\n]|\\.)*"/g, blankRun).replace(/'(?:[^'\\\n]|\\.)*'/g, blankRun);
|
|
13304
|
+
}
|
|
13305
|
+
function offsetToLineCol2(str, index) {
|
|
13306
|
+
let line = 1;
|
|
13307
|
+
let lineStart = 0;
|
|
13308
|
+
for (let i = 0;i < index; i++) {
|
|
13309
|
+
if (str[i] === `
|
|
13310
|
+
`) {
|
|
13311
|
+
line++;
|
|
13312
|
+
lineStart = i + 1;
|
|
13313
|
+
}
|
|
13314
|
+
}
|
|
13315
|
+
return { line, column: index - lineStart + 1 };
|
|
13316
|
+
}
|
|
13317
|
+
function suppressedLines(css) {
|
|
13318
|
+
const lines = new Set;
|
|
13319
|
+
IGNORE_DIRECTIVE.lastIndex = 0;
|
|
13320
|
+
for (let m = IGNORE_DIRECTIVE.exec(css);m !== null; m = IGNORE_DIRECTIVE.exec(css)) {
|
|
13321
|
+
lines.add(offsetToLineCol2(css, m.index).line);
|
|
13322
|
+
}
|
|
13323
|
+
return lines;
|
|
13324
|
+
}
|
|
13325
|
+
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.";
|
|
13326
|
+
function scanScopedCss(lx, css, key) {
|
|
13327
|
+
if (!css)
|
|
13328
|
+
return;
|
|
13329
|
+
const ignore = suppressedLines(css);
|
|
13330
|
+
const clean = blankCssNoise(css);
|
|
13331
|
+
const report = (id, info) => {
|
|
13332
|
+
if (ignore.has(info.location.line))
|
|
13333
|
+
return;
|
|
13334
|
+
lx.error(id, { key, ...info }, { kind: "rephrase", text: STYLE_TO_GLOBAL_HELP });
|
|
13335
|
+
};
|
|
13336
|
+
NON_NESTABLE_AT_RULE.lastIndex = 0;
|
|
13337
|
+
for (let m = NON_NESTABLE_AT_RULE.exec(clean);m !== null; m = NON_NESTABLE_AT_RULE.exec(clean)) {
|
|
13338
|
+
const at = m.index + m[0].indexOf("@");
|
|
13339
|
+
report(TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE, {
|
|
13340
|
+
atRule: m[1].toLowerCase(),
|
|
13341
|
+
location: offsetToLineCol2(clean, at)
|
|
13342
|
+
});
|
|
13343
|
+
}
|
|
13344
|
+
GLOBAL_LEADING_SELECTOR.lastIndex = 0;
|
|
13345
|
+
for (let m = GLOBAL_LEADING_SELECTOR.exec(clean);m !== null; m = GLOBAL_LEADING_SELECTOR.exec(clean)) {
|
|
13346
|
+
const at = m.index + m[0].indexOf(m[1]);
|
|
13347
|
+
report(GLOBAL_SELECTOR_IN_SCOPED_STYLE, {
|
|
13348
|
+
selector: m[1].toLowerCase(),
|
|
13349
|
+
location: offsetToLineCol2(clean, at)
|
|
13350
|
+
});
|
|
13351
|
+
}
|
|
13352
|
+
}
|
|
13353
|
+
function checkScopedStyleTopLevel(lx, Comp) {
|
|
13354
|
+
scanScopedCss(lx, Comp.commonStyle, "commonStyle");
|
|
13355
|
+
for (const name in Comp.views) {
|
|
13356
|
+
const { style } = Comp.views[name];
|
|
13357
|
+
if (style)
|
|
13358
|
+
lx.push({ viewName: name }, () => scanScopedCss(lx, style, "style"));
|
|
13359
|
+
}
|
|
13360
|
+
}
|
|
13295
13361
|
function checkProvidesAreAddressable(lx, Comp) {
|
|
13296
13362
|
for (const name in Comp._rawProvide) {
|
|
13297
13363
|
if (Comp.provide[name] === undefined) {
|
|
@@ -13385,1382 +13451,1546 @@ class LintParseContext extends ParseContext {
|
|
|
13385
13451
|
}
|
|
13386
13452
|
}
|
|
13387
13453
|
|
|
13388
|
-
//
|
|
13389
|
-
class
|
|
13390
|
-
constructor(
|
|
13391
|
-
this.
|
|
13392
|
-
this.
|
|
13393
|
-
this.counts = counts;
|
|
13394
|
-
this.warnings = warnings;
|
|
13395
|
-
}
|
|
13396
|
-
}
|
|
13397
|
-
|
|
13398
|
-
class ComponentSummary {
|
|
13399
|
-
constructor({ name, views, fields }) {
|
|
13400
|
-
this.name = name;
|
|
13401
|
-
this.views = views;
|
|
13402
|
-
this.fields = fields;
|
|
13403
|
-
}
|
|
13404
|
-
}
|
|
13405
|
-
|
|
13406
|
-
class ComponentList {
|
|
13407
|
-
constructor({ items, total = null, truncated = false }) {
|
|
13408
|
-
this.items = items;
|
|
13409
|
-
this.total = total ?? items.length;
|
|
13410
|
-
this.truncated = truncated;
|
|
13454
|
+
// src/components.js
|
|
13455
|
+
class Components {
|
|
13456
|
+
constructor() {
|
|
13457
|
+
this.getComponentSymbol = Symbol("getComponent");
|
|
13458
|
+
this.byId = new Map;
|
|
13411
13459
|
}
|
|
13412
|
-
|
|
13413
|
-
|
|
13414
|
-
|
|
13415
|
-
constructor({ sections, total = null, truncated = false }) {
|
|
13416
|
-
this.sections = sections;
|
|
13417
|
-
this.total = total ?? sections.reduce((n, s) => n + (s.items?.length ?? 0), 0);
|
|
13418
|
-
this.truncated = truncated;
|
|
13460
|
+
registerComponent(comp) {
|
|
13461
|
+
comp.Class.prototype[this.getComponentSymbol] = () => comp;
|
|
13462
|
+
this.byId.set(comp.id, comp);
|
|
13419
13463
|
}
|
|
13420
|
-
|
|
13421
|
-
|
|
13422
|
-
class ComponentDocs {
|
|
13423
|
-
constructor({ items }) {
|
|
13424
|
-
this.items = items;
|
|
13464
|
+
getComponentForId(id) {
|
|
13465
|
+
return this.byId.get(id) ?? null;
|
|
13425
13466
|
}
|
|
13426
|
-
|
|
13427
|
-
|
|
13428
|
-
class LintFinding {
|
|
13429
|
-
constructor({ id, level, info, context = {}, suggestion = null }) {
|
|
13430
|
-
this.id = id;
|
|
13431
|
-
this.level = level;
|
|
13432
|
-
this.info = info;
|
|
13433
|
-
this.context = context;
|
|
13434
|
-
this.suggestion = suggestion;
|
|
13467
|
+
getCompFor(v) {
|
|
13468
|
+
return v?.[this.getComponentSymbol]?.() ?? null;
|
|
13435
13469
|
}
|
|
13436
|
-
|
|
13437
|
-
|
|
13438
|
-
class LintComponentResult {
|
|
13439
|
-
constructor({ componentName, findings }) {
|
|
13440
|
-
this.componentName = componentName;
|
|
13441
|
-
this.findings = findings;
|
|
13470
|
+
getHandlerFor(v, name, key) {
|
|
13471
|
+
return this.getCompFor(v)?.[key][name] ?? null;
|
|
13442
13472
|
}
|
|
13443
|
-
|
|
13444
|
-
return this.
|
|
13473
|
+
getRequestFor(v, name) {
|
|
13474
|
+
return this.getCompFor(v)?.scope.lookupRequest(name) ?? null;
|
|
13445
13475
|
}
|
|
13446
|
-
|
|
13447
|
-
|
|
13476
|
+
compileStyles() {
|
|
13477
|
+
const styles2 = [];
|
|
13478
|
+
for (const comp of this.byId.values())
|
|
13479
|
+
styles2.push(comp.compileStyle());
|
|
13480
|
+
return styles2.join(`
|
|
13481
|
+
`);
|
|
13448
13482
|
}
|
|
13449
13483
|
}
|
|
13450
13484
|
|
|
13451
|
-
class
|
|
13452
|
-
constructor(
|
|
13453
|
-
this.
|
|
13485
|
+
class ComponentStack {
|
|
13486
|
+
constructor(comps = new Components, parent = null) {
|
|
13487
|
+
this.comps = comps;
|
|
13488
|
+
this.parent = parent;
|
|
13489
|
+
this.byName = {};
|
|
13490
|
+
this.reqsByName = {};
|
|
13491
|
+
this.macros = {};
|
|
13454
13492
|
}
|
|
13455
|
-
|
|
13456
|
-
return this.
|
|
13493
|
+
enter() {
|
|
13494
|
+
return new ComponentStack(this.comps, this);
|
|
13457
13495
|
}
|
|
13458
|
-
|
|
13459
|
-
|
|
13496
|
+
registerComponents(comps, opts) {
|
|
13497
|
+
const { aliases: aliases2 = {} } = opts ?? {};
|
|
13498
|
+
for (let i = 0;i < comps.length; i++) {
|
|
13499
|
+
const comp = comps[i];
|
|
13500
|
+
comp.scope = this.enter();
|
|
13501
|
+
comp.Class.scope = comp.scope;
|
|
13502
|
+
this.comps.registerComponent(comp);
|
|
13503
|
+
this.byName[comp.name] = comp;
|
|
13504
|
+
}
|
|
13505
|
+
for (const alias in aliases2) {
|
|
13506
|
+
const comp = this.byName[aliases2[alias]];
|
|
13507
|
+
console.assert(this.byName[alias] === undefined, "alias overrides component", alias);
|
|
13508
|
+
if (comp !== undefined)
|
|
13509
|
+
this.byName[alias] = comp;
|
|
13510
|
+
else
|
|
13511
|
+
console.warn("alias", alias, "to inexistent component", aliases2[alias]);
|
|
13512
|
+
}
|
|
13460
13513
|
}
|
|
13461
|
-
|
|
13462
|
-
|
|
13514
|
+
registerMacros(macros) {
|
|
13515
|
+
for (const key in macros) {
|
|
13516
|
+
const lower = key.toLowerCase();
|
|
13517
|
+
console.assert(this.macros[lower] === undefined, "macro key collision", lower);
|
|
13518
|
+
this.macros[lower] = macros[key];
|
|
13519
|
+
}
|
|
13463
13520
|
}
|
|
13464
|
-
|
|
13465
|
-
|
|
13466
|
-
class RenderedExample {
|
|
13467
|
-
constructor({ title, description = null, componentName, view, html, error = null }) {
|
|
13468
|
-
this.title = title;
|
|
13469
|
-
this.description = description;
|
|
13470
|
-
this.componentName = componentName;
|
|
13471
|
-
this.view = view;
|
|
13472
|
-
this.html = html;
|
|
13473
|
-
this.error = error;
|
|
13521
|
+
getCompFor(v) {
|
|
13522
|
+
return this.comps.getCompFor(v);
|
|
13474
13523
|
}
|
|
13475
|
-
|
|
13476
|
-
|
|
13477
|
-
|
|
13478
|
-
constructor({ title, description = null, items }) {
|
|
13479
|
-
this.title = title;
|
|
13480
|
-
this.description = description;
|
|
13481
|
-
this.items = items;
|
|
13524
|
+
registerRequestHandlers(handlers) {
|
|
13525
|
+
for (const name in handlers)
|
|
13526
|
+
this.reqsByName[name] = new RequestHandler(name, handlers[name]);
|
|
13482
13527
|
}
|
|
13483
|
-
|
|
13484
|
-
|
|
13485
|
-
class RenderBatch {
|
|
13486
|
-
constructor({ sections }) {
|
|
13487
|
-
this.sections = sections;
|
|
13528
|
+
lookupRequest(name) {
|
|
13529
|
+
return this.reqsByName[name] ?? this.parent?.lookupRequest(name) ?? null;
|
|
13488
13530
|
}
|
|
13489
|
-
|
|
13490
|
-
return this.
|
|
13531
|
+
lookupComponent(name) {
|
|
13532
|
+
return this.byName[name] ?? this.parent?.lookupComponent(name) ?? null;
|
|
13491
13533
|
}
|
|
13492
|
-
|
|
13493
|
-
|
|
13494
|
-
class TestResult {
|
|
13495
|
-
constructor({ title, fullPath, componentName = null, status, durationMs = 0, error = null }) {
|
|
13496
|
-
this.title = title;
|
|
13497
|
-
this.fullPath = fullPath;
|
|
13498
|
-
this.componentName = componentName;
|
|
13499
|
-
this.status = status;
|
|
13500
|
-
this.durationMs = durationMs;
|
|
13501
|
-
this.error = error;
|
|
13534
|
+
lookupMacro(name) {
|
|
13535
|
+
return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
|
|
13502
13536
|
}
|
|
13503
13537
|
}
|
|
13504
13538
|
|
|
13505
|
-
class
|
|
13506
|
-
constructor(
|
|
13507
|
-
this.
|
|
13508
|
-
this.
|
|
13509
|
-
this.
|
|
13539
|
+
class ProvideInfo {
|
|
13540
|
+
constructor(name, val, symbol) {
|
|
13541
|
+
this.name = name;
|
|
13542
|
+
this.val = val;
|
|
13543
|
+
this.symbol = symbol;
|
|
13510
13544
|
}
|
|
13511
13545
|
}
|
|
13512
13546
|
|
|
13513
|
-
class
|
|
13514
|
-
constructor(
|
|
13515
|
-
this.
|
|
13516
|
-
this.
|
|
13517
|
-
this.
|
|
13547
|
+
class LookupInfo {
|
|
13548
|
+
constructor(name, compName, provideName, val) {
|
|
13549
|
+
this.name = name;
|
|
13550
|
+
this.compName = compName;
|
|
13551
|
+
this.provideName = provideName;
|
|
13552
|
+
this.val = val;
|
|
13553
|
+
this._sym = undefined;
|
|
13554
|
+
}
|
|
13555
|
+
getProducerSymbol(stack) {
|
|
13556
|
+
if (this._sym === undefined)
|
|
13557
|
+
this._sym = stack.lookupType(this.compName)?.provide?.[this.provideName]?.symbol ?? null;
|
|
13558
|
+
return this._sym;
|
|
13518
13559
|
}
|
|
13519
13560
|
}
|
|
13561
|
+
var isString = (v) => typeof v === "string";
|
|
13562
|
+
var _rawSpecKeys = "name view style commonStyle globalStyle input receive bubble response alter views provide lookup fields methods statics";
|
|
13563
|
+
var KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
|
|
13564
|
+
var _compId = 0;
|
|
13520
13565
|
|
|
13521
|
-
class
|
|
13522
|
-
constructor(
|
|
13523
|
-
this.
|
|
13524
|
-
|
|
13525
|
-
|
|
13526
|
-
|
|
13527
|
-
|
|
13528
|
-
|
|
13529
|
-
|
|
13530
|
-
|
|
13531
|
-
|
|
13566
|
+
class Component {
|
|
13567
|
+
constructor(Class, o) {
|
|
13568
|
+
this.id = _compId++;
|
|
13569
|
+
this.name = o.name ?? "UnkComp";
|
|
13570
|
+
this.Class = Class;
|
|
13571
|
+
this.views = { main: new View("main", o.view, o.style) };
|
|
13572
|
+
this.commonStyle = o.commonStyle ?? "";
|
|
13573
|
+
this.globalStyle = o.globalStyle ?? "";
|
|
13574
|
+
this.input = o.input ?? {};
|
|
13575
|
+
this.receive = o.receive ?? {};
|
|
13576
|
+
this.bubble = o.bubble ?? {};
|
|
13577
|
+
this.response = o.response ?? {};
|
|
13578
|
+
this.alter = o.alter ?? {};
|
|
13579
|
+
for (const name in o.views ?? {}) {
|
|
13580
|
+
const v = o.views[name];
|
|
13581
|
+
const { view, style } = isString(v) ? { view: v } : v;
|
|
13582
|
+
this.views[name] = new View(name, view, style);
|
|
13583
|
+
}
|
|
13584
|
+
this._rawProvide = o.provide ?? {};
|
|
13585
|
+
this._rawLookup = o.lookup ?? {};
|
|
13586
|
+
this.provide = {};
|
|
13587
|
+
this.lookup = {};
|
|
13588
|
+
this.scope = null;
|
|
13589
|
+
this.spec = o;
|
|
13590
|
+
this.extra = {};
|
|
13591
|
+
for (const key of Object.keys(o))
|
|
13592
|
+
if (!KNOWN_SPEC_KEYS.has(key))
|
|
13593
|
+
this.extra[key] = o[key];
|
|
13532
13594
|
}
|
|
13533
|
-
|
|
13534
|
-
return
|
|
13595
|
+
clone() {
|
|
13596
|
+
return Component.fromSpec(this.spec);
|
|
13535
13597
|
}
|
|
13536
|
-
|
|
13537
|
-
|
|
13538
|
-
|
|
13539
|
-
|
|
13540
|
-
|
|
13541
|
-
|
|
13542
|
-
|
|
13543
|
-
|
|
13544
|
-
|
|
13598
|
+
compile(ParseContext2) {
|
|
13599
|
+
for (const name in this.views)
|
|
13600
|
+
this.views[name].compile(new ParseContext2, this.scope, this.id);
|
|
13601
|
+
const ctx = this.views.main.ctx;
|
|
13602
|
+
for (const key in this._rawProvide) {
|
|
13603
|
+
const val = vp.parseProvide(this._rawProvide[key], ctx);
|
|
13604
|
+
if (val)
|
|
13605
|
+
this.provide[key] = new ProvideInfo(key, val, Symbol(key));
|
|
13606
|
+
}
|
|
13607
|
+
for (const key in this._rawLookup) {
|
|
13608
|
+
const linfo = this._rawLookup[key];
|
|
13609
|
+
const forStr = isString(linfo) ? linfo : isString(linfo?.for) ? linfo.for : null;
|
|
13610
|
+
const [compName, provideName] = forStr === null ? [] : forStr.split(".");
|
|
13611
|
+
if (!isString(compName) || !isString(provideName))
|
|
13612
|
+
continue;
|
|
13613
|
+
const defStr = isString(linfo?.default) ? linfo.default : null;
|
|
13614
|
+
const val = defStr === null ? null : vp.parseField(defStr, ctx);
|
|
13615
|
+
this.lookup[key] = new LookupInfo(key, compName, provideName, val);
|
|
13616
|
+
}
|
|
13617
|
+
for (const key in this.lookup)
|
|
13618
|
+
if (this.provide[key] !== undefined)
|
|
13619
|
+
console.warn("name declared in both provide and lookup", this.name, key);
|
|
13545
13620
|
}
|
|
13546
|
-
|
|
13547
|
-
|
|
13548
|
-
class Test {
|
|
13549
|
-
constructor({ title, fn, componentName = null, parent = null }) {
|
|
13550
|
-
this.title = title;
|
|
13551
|
-
this.fn = fn;
|
|
13552
|
-
this.componentName = componentName;
|
|
13553
|
-
this.parent = parent;
|
|
13621
|
+
make(args, opts) {
|
|
13622
|
+
return this.Class.make(args, opts ?? { scope: this.scope });
|
|
13554
13623
|
}
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
13559
|
-
this.
|
|
13560
|
-
|
|
13624
|
+
getView(name) {
|
|
13625
|
+
return this.views[name] ?? this.views.main;
|
|
13626
|
+
}
|
|
13627
|
+
getEventForId(id, name = "main") {
|
|
13628
|
+
return this.getView(name).ctx.getEventForId(id);
|
|
13629
|
+
}
|
|
13630
|
+
getNodeForId(id, name = "main") {
|
|
13631
|
+
return this.getView(name).ctx.getNodeForId(id);
|
|
13632
|
+
}
|
|
13633
|
+
compileStyle() {
|
|
13634
|
+
const { id, commonStyle, globalStyle, views } = this;
|
|
13635
|
+
const styles2 = commonStyle ? [`[data-cid="${id}"]{${commonStyle}}`] : [];
|
|
13636
|
+
if (globalStyle !== "")
|
|
13637
|
+
styles2.push(globalStyle);
|
|
13638
|
+
for (const name in views) {
|
|
13639
|
+
const { style } = views[name];
|
|
13640
|
+
if (style !== "")
|
|
13641
|
+
styles2.push(`[data-cid="${id}"][data-vid="${name}"]{${style}}`);
|
|
13642
|
+
}
|
|
13643
|
+
return styles2.join(`
|
|
13644
|
+
`);
|
|
13561
13645
|
}
|
|
13562
13646
|
}
|
|
13563
13647
|
|
|
13564
|
-
|
|
13565
|
-
|
|
13566
|
-
|
|
13567
|
-
|
|
13648
|
+
// src/on.js
|
|
13649
|
+
var OP_KINDS = ["send", "bubble", "request", "input"];
|
|
13650
|
+
function phaseOps(phase) {
|
|
13651
|
+
const ops = [];
|
|
13652
|
+
for (const type3 of OP_KINDS)
|
|
13653
|
+
for (const a of phase[type3] ?? [])
|
|
13654
|
+
ops.push({ type: type3, ...a });
|
|
13655
|
+
for (const a of phase.do ?? [])
|
|
13656
|
+
ops.push(a);
|
|
13657
|
+
return ops;
|
|
13568
13658
|
}
|
|
13569
|
-
function
|
|
13570
|
-
return
|
|
13659
|
+
function resolveArgs(args, self) {
|
|
13660
|
+
return typeof args === "function" ? args(self) ?? [] : args ?? [];
|
|
13571
13661
|
}
|
|
13572
|
-
function
|
|
13573
|
-
if (
|
|
13574
|
-
return
|
|
13575
|
-
|
|
13576
|
-
|
|
13577
|
-
|
|
13578
|
-
|
|
13662
|
+
function dispatchPhase(dispatcher, targetPath, phase, self) {
|
|
13663
|
+
if (!phase)
|
|
13664
|
+
return;
|
|
13665
|
+
for (const op of phaseOps(phase)) {
|
|
13666
|
+
const args = resolveArgs(op.args, self);
|
|
13667
|
+
switch (op.type) {
|
|
13668
|
+
case "send":
|
|
13669
|
+
dispatcher.sendAtPath(targetPath, op.name, args, op.opts);
|
|
13670
|
+
break;
|
|
13671
|
+
case "bubble":
|
|
13672
|
+
dispatcher.sendAtPath(targetPath, op.name, args, {
|
|
13673
|
+
skipSelf: true,
|
|
13674
|
+
bubbles: true,
|
|
13675
|
+
...op.opts
|
|
13676
|
+
});
|
|
13677
|
+
break;
|
|
13678
|
+
case "request":
|
|
13679
|
+
dispatcher.requestAtPath(targetPath, op.name, args, op.opts);
|
|
13680
|
+
break;
|
|
13681
|
+
case "input":
|
|
13682
|
+
dispatcher.inputAtPath(targetPath, op.name, args, op.opts);
|
|
13683
|
+
break;
|
|
13684
|
+
}
|
|
13579
13685
|
}
|
|
13580
|
-
return null;
|
|
13581
13686
|
}
|
|
13582
|
-
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
13586
|
-
|
|
13587
|
-
|
|
13588
|
-
|
|
13589
|
-
|
|
13687
|
+
|
|
13688
|
+
// src/stack.js
|
|
13689
|
+
var STOP = Symbol("STOP");
|
|
13690
|
+
var NEXT = Symbol("NEXT");
|
|
13691
|
+
function lookup(chain, name, dv = null) {
|
|
13692
|
+
let n = chain;
|
|
13693
|
+
while (n !== null) {
|
|
13694
|
+
const r = n[0].lookup(name);
|
|
13695
|
+
if (r === STOP)
|
|
13696
|
+
return dv;
|
|
13697
|
+
if (r !== NEXT)
|
|
13698
|
+
return r;
|
|
13699
|
+
n = n[1];
|
|
13700
|
+
}
|
|
13701
|
+
return dv;
|
|
13590
13702
|
}
|
|
13591
|
-
|
|
13592
|
-
|
|
13593
|
-
|
|
13594
|
-
|
|
13595
|
-
|
|
13596
|
-
|
|
13597
|
-
let fn;
|
|
13598
|
-
if (args.length === 2) {
|
|
13599
|
-
[head, fn] = args;
|
|
13600
|
-
} else if (args.length === 3) {
|
|
13601
|
-
[head, options, fn] = args;
|
|
13602
|
-
} else {
|
|
13603
|
-
throw new Error(`describe() expects 2 or 3 arguments, got ${args.length}`);
|
|
13604
|
-
}
|
|
13605
|
-
if (typeof fn !== "function") {
|
|
13606
|
-
throw new Error(`describe(${JSON.stringify(titleFromArg(head))}): final argument must be a function`);
|
|
13607
|
-
}
|
|
13608
|
-
let componentName = null;
|
|
13609
|
-
if (typeof head !== "string") {
|
|
13610
|
-
componentName = resolveComponentName(head, components);
|
|
13611
|
-
}
|
|
13612
|
-
if (componentName === null && options && options.component != null) {
|
|
13613
|
-
componentName = resolveComponentName(options.component, components);
|
|
13614
|
-
}
|
|
13615
|
-
if (componentName === null) {
|
|
13616
|
-
const parent2 = stack.length ? stack[stack.length - 1] : null;
|
|
13617
|
-
if (parent2)
|
|
13618
|
-
componentName = parent2.componentName;
|
|
13619
|
-
}
|
|
13620
|
-
const parent = stack.length ? stack[stack.length - 1] : null;
|
|
13621
|
-
const node = new Describe({
|
|
13622
|
-
title: titleFromArg(head),
|
|
13623
|
-
componentName,
|
|
13624
|
-
parent
|
|
13625
|
-
});
|
|
13626
|
-
if (parent)
|
|
13627
|
-
parent.children.push(node);
|
|
13628
|
-
else
|
|
13629
|
-
moduleTests.suites.push(node);
|
|
13630
|
-
stack.push(node);
|
|
13631
|
-
try {
|
|
13632
|
-
fn();
|
|
13633
|
-
} finally {
|
|
13634
|
-
stack.pop();
|
|
13635
|
-
}
|
|
13703
|
+
|
|
13704
|
+
class BindFrame {
|
|
13705
|
+
constructor(it, binds, isFrame) {
|
|
13706
|
+
this.it = it;
|
|
13707
|
+
this.binds = binds;
|
|
13708
|
+
this.isFrame = isFrame;
|
|
13636
13709
|
}
|
|
13637
|
-
|
|
13638
|
-
|
|
13639
|
-
|
|
13640
|
-
}
|
|
13641
|
-
if (typeof fn !== "function") {
|
|
13642
|
-
throw new Error(`test(${JSON.stringify(title)}): fn must be a function`);
|
|
13643
|
-
}
|
|
13644
|
-
const parent = stack.length ? stack[stack.length - 1] : null;
|
|
13645
|
-
if (!parent) {
|
|
13646
|
-
throw new Error(`test(${JSON.stringify(title)}) must be called inside a describe()`);
|
|
13647
|
-
}
|
|
13648
|
-
parent.children.push(new Test({
|
|
13649
|
-
title,
|
|
13650
|
-
fn,
|
|
13651
|
-
componentName: parent.componentName,
|
|
13652
|
-
parent
|
|
13653
|
-
}));
|
|
13710
|
+
lookup(name) {
|
|
13711
|
+
const v = this.binds[name];
|
|
13712
|
+
return v === undefined ? this.isFrame ? STOP : NEXT : v;
|
|
13654
13713
|
}
|
|
13655
|
-
return { describe, test: test2, moduleTests };
|
|
13656
13714
|
}
|
|
13657
13715
|
|
|
13658
|
-
|
|
13659
|
-
|
|
13660
|
-
|
|
13661
|
-
|
|
13662
|
-
|
|
13663
|
-
|
|
13664
|
-
|
|
13716
|
+
class ObjectFrame {
|
|
13717
|
+
constructor(binds) {
|
|
13718
|
+
this.binds = binds;
|
|
13719
|
+
}
|
|
13720
|
+
lookup(key) {
|
|
13721
|
+
const v = this.binds[key];
|
|
13722
|
+
return v === undefined ? NEXT : v;
|
|
13665
13723
|
}
|
|
13666
|
-
return parts.join(" > ");
|
|
13667
13724
|
}
|
|
13668
|
-
function
|
|
13669
|
-
|
|
13670
|
-
|
|
13671
|
-
|
|
13672
|
-
|
|
13673
|
-
|
|
13674
|
-
|
|
13725
|
+
function computeViewsId(views) {
|
|
13726
|
+
let s = "";
|
|
13727
|
+
let n = views;
|
|
13728
|
+
while (n !== null) {
|
|
13729
|
+
s += n[0];
|
|
13730
|
+
n = n[1];
|
|
13731
|
+
}
|
|
13732
|
+
return s === "main" ? "" : s;
|
|
13675
13733
|
}
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
if (typeof getTests !== "function") {
|
|
13687
|
-
return new TestReport({
|
|
13688
|
-
modules: [new ModuleTestReport({ path, suites: [], counts })]
|
|
13689
|
-
});
|
|
13734
|
+
|
|
13735
|
+
class Stack2 {
|
|
13736
|
+
constructor(comps, it, binds, dynBinds, views, viewsId, ctx = null) {
|
|
13737
|
+
this.comps = comps;
|
|
13738
|
+
this.it = it;
|
|
13739
|
+
this.binds = binds;
|
|
13740
|
+
this.dynBinds = dynBinds;
|
|
13741
|
+
this.views = views;
|
|
13742
|
+
this.viewsId = viewsId;
|
|
13743
|
+
this.ctx = ctx;
|
|
13690
13744
|
}
|
|
13691
|
-
|
|
13692
|
-
|
|
13745
|
+
_pushProvides() {
|
|
13746
|
+
const provide = this.comps.getCompFor(this.it)?.provide;
|
|
13747
|
+
if (provide == null)
|
|
13748
|
+
return this;
|
|
13749
|
+
const dynObj = {};
|
|
13750
|
+
let has2 = false;
|
|
13751
|
+
for (const k in provide) {
|
|
13752
|
+
dynObj[provide[k].symbol] = provide[k].val.eval(this);
|
|
13753
|
+
has2 = true;
|
|
13754
|
+
}
|
|
13755
|
+
if (!has2)
|
|
13756
|
+
return this;
|
|
13757
|
+
const newDynBinds = [new ObjectFrame(dynObj), this.dynBinds];
|
|
13758
|
+
const { comps, it, binds, views, viewsId, ctx } = this;
|
|
13759
|
+
return new Stack2(comps, it, binds, newDynBinds, views, viewsId, ctx);
|
|
13693
13760
|
}
|
|
13694
|
-
|
|
13695
|
-
|
|
13696
|
-
|
|
13697
|
-
|
|
13698
|
-
|
|
13699
|
-
|
|
13700
|
-
|
|
13701
|
-
|
|
13702
|
-
|
|
13703
|
-
|
|
13704
|
-
|
|
13705
|
-
|
|
13706
|
-
|
|
13707
|
-
|
|
13708
|
-
|
|
13709
|
-
|
|
13710
|
-
|
|
13711
|
-
|
|
13712
|
-
|
|
13713
|
-
|
|
13714
|
-
|
|
13715
|
-
|
|
13716
|
-
|
|
13717
|
-
|
|
13718
|
-
|
|
13719
|
-
|
|
13720
|
-
|
|
13721
|
-
|
|
13722
|
-
|
|
13723
|
-
|
|
13724
|
-
|
|
13725
|
-
|
|
13726
|
-
|
|
13727
|
-
if (bail)
|
|
13728
|
-
bailed = true;
|
|
13729
|
-
return new TestResult({
|
|
13730
|
-
title: node.title,
|
|
13731
|
-
fullPath,
|
|
13732
|
-
componentName: node.componentName,
|
|
13733
|
-
status: "fail",
|
|
13734
|
-
durationMs: performance.now() - start,
|
|
13735
|
-
error: captureError(e)
|
|
13736
|
-
});
|
|
13737
|
-
}
|
|
13738
|
-
}
|
|
13739
|
-
const childResults = [];
|
|
13740
|
-
for (const child of node.children) {
|
|
13741
|
-
const r = await visit(child);
|
|
13742
|
-
if (r !== null)
|
|
13743
|
-
childResults.push(r);
|
|
13744
|
-
}
|
|
13745
|
-
if (childResults.length === 0)
|
|
13761
|
+
static root(comps, it, ctx) {
|
|
13762
|
+
const binds = [new BindFrame(it, { it }, true), null];
|
|
13763
|
+
const dynBinds = [new ObjectFrame({}), null];
|
|
13764
|
+
const views = ["main", null];
|
|
13765
|
+
return new Stack2(comps, it, binds, dynBinds, views, "", ctx)._pushProvides();
|
|
13766
|
+
}
|
|
13767
|
+
enter(it, bindings = {}, isFrame = true) {
|
|
13768
|
+
const { comps, binds, dynBinds, views, viewsId, ctx } = this;
|
|
13769
|
+
const newBinds = [new BindFrame(it, bindings, isFrame), binds];
|
|
13770
|
+
const stack = new Stack2(comps, it, newBinds, dynBinds, views, viewsId, ctx);
|
|
13771
|
+
return isFrame ? stack._pushProvides() : stack;
|
|
13772
|
+
}
|
|
13773
|
+
pushViewName(name) {
|
|
13774
|
+
const { comps, it, binds, dynBinds, views, ctx } = this;
|
|
13775
|
+
const newViews = [name, views];
|
|
13776
|
+
return new Stack2(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
|
|
13777
|
+
}
|
|
13778
|
+
_pushDynBindValuesToArray(arr, comp) {
|
|
13779
|
+
for (const k in comp.provide)
|
|
13780
|
+
arr.push(this._lookupProvide(comp.provide[k]));
|
|
13781
|
+
for (const k in comp.lookup)
|
|
13782
|
+
arr.push(this._lookupAlias(comp.lookup[k]));
|
|
13783
|
+
}
|
|
13784
|
+
_lookupProvide(p) {
|
|
13785
|
+
return lookup(this.dynBinds, p.symbol) ?? p.val.eval(this) ?? null;
|
|
13786
|
+
}
|
|
13787
|
+
_lookupAlias(lk) {
|
|
13788
|
+
const sym = lk.getProducerSymbol(this);
|
|
13789
|
+
return (sym != null ? lookup(this.dynBinds, sym) : null) ?? lk.val?.eval(this) ?? null;
|
|
13790
|
+
}
|
|
13791
|
+
lookupDynamic(name) {
|
|
13792
|
+
const comp = this.comps.getCompFor(this.it);
|
|
13793
|
+
if (comp == null)
|
|
13746
13794
|
return null;
|
|
13747
|
-
|
|
13748
|
-
|
|
13749
|
-
|
|
13750
|
-
|
|
13751
|
-
|
|
13795
|
+
const lk = comp.lookup[name];
|
|
13796
|
+
if (lk !== undefined)
|
|
13797
|
+
return this._lookupAlias(lk);
|
|
13798
|
+
const p = comp.provide[name];
|
|
13799
|
+
return p !== undefined ? this._lookupProvide(p) : null;
|
|
13752
13800
|
}
|
|
13753
|
-
|
|
13754
|
-
|
|
13755
|
-
const r = await visit(suite);
|
|
13756
|
-
if (r !== null)
|
|
13757
|
-
suiteResults.push(r);
|
|
13801
|
+
lookupBind(name) {
|
|
13802
|
+
return lookup(this.binds, name);
|
|
13758
13803
|
}
|
|
13759
|
-
|
|
13760
|
-
|
|
13761
|
-
});
|
|
13762
|
-
}
|
|
13763
|
-
|
|
13764
|
-
// tools/core/test-console.js
|
|
13765
|
-
var PASS = "color: #0a0; font-weight: bold";
|
|
13766
|
-
var FAIL = "color: #c00; font-weight: bold";
|
|
13767
|
-
var SKIP = "color: #888";
|
|
13768
|
-
var DIM = "color: #888";
|
|
13769
|
-
var RESET = "color: inherit; font-weight: normal";
|
|
13770
|
-
function reportTestNode(node) {
|
|
13771
|
-
if (node.children) {
|
|
13772
|
-
const label = node.componentName ? `${node.title} [${node.componentName}]` : node.title;
|
|
13773
|
-
console.group(label);
|
|
13774
|
-
for (const child of node.children)
|
|
13775
|
-
reportTestNode(child);
|
|
13776
|
-
console.groupEnd();
|
|
13777
|
-
return;
|
|
13804
|
+
lookupType(name) {
|
|
13805
|
+
return this.comps.getCompFor(this.it).scope.lookupComponent(name);
|
|
13778
13806
|
}
|
|
13779
|
-
|
|
13780
|
-
|
|
13781
|
-
console.log(`%c✓%c ${node.title}%c${dur}`, PASS, RESET, DIM);
|
|
13782
|
-
} else if (node.status === "skip") {
|
|
13783
|
-
console.log(`%c○ ${node.title}%c (skipped)`, SKIP, RESET);
|
|
13784
|
-
} else {
|
|
13785
|
-
console.group(`%c✗%c ${node.title}%c${dur}`, FAIL, RESET, DIM);
|
|
13786
|
-
console.error(node.error?.message ?? "(no error message)");
|
|
13787
|
-
if (node.error && (("expected" in node.error) || ("actual" in node.error))) {
|
|
13788
|
-
console.log("expected:", node.error.expected);
|
|
13789
|
-
console.log("actual: ", node.error.actual);
|
|
13790
|
-
}
|
|
13791
|
-
if (node.error?.stack)
|
|
13792
|
-
console.log(node.error.stack);
|
|
13793
|
-
console.groupEnd();
|
|
13807
|
+
lookupFieldRaw(name) {
|
|
13808
|
+
return this.it[name] ?? null;
|
|
13794
13809
|
}
|
|
13795
|
-
|
|
13796
|
-
|
|
13797
|
-
|
|
13798
|
-
|
|
13799
|
-
|
|
13800
|
-
|
|
13801
|
-
|
|
13802
|
-
|
|
13803
|
-
|
|
13804
|
-
|
|
13810
|
+
lookupMethod(name) {
|
|
13811
|
+
const fn = this.it[name];
|
|
13812
|
+
return fn instanceof Function ? fn.call(this.it) : null;
|
|
13813
|
+
}
|
|
13814
|
+
lookupName(name) {
|
|
13815
|
+
return this.ctx.lookupName(name);
|
|
13816
|
+
}
|
|
13817
|
+
getHandlerFor(name, key) {
|
|
13818
|
+
return this.comps.getHandlerFor(this.it, name, key);
|
|
13819
|
+
}
|
|
13820
|
+
lookupRequest(name) {
|
|
13821
|
+
return this.comps.getRequestFor(this.it, name);
|
|
13822
|
+
}
|
|
13823
|
+
lookupBestView(views, defaultViewName) {
|
|
13824
|
+
let n = this.views;
|
|
13825
|
+
while (n !== null) {
|
|
13826
|
+
const view = views[n[0]];
|
|
13827
|
+
if (view !== undefined)
|
|
13828
|
+
return view;
|
|
13829
|
+
n = n[1];
|
|
13805
13830
|
}
|
|
13806
|
-
|
|
13807
|
-
const summary = `${c.pass} passed, ${c.fail} failed, ${c.skip} skipped (${c.total} total)`;
|
|
13808
|
-
if (c.fail > 0)
|
|
13809
|
-
console.error(`%c${summary}`, FAIL);
|
|
13810
|
-
else if (c.total === 0)
|
|
13811
|
-
console.log(`%c${summary}`, DIM);
|
|
13812
|
-
else
|
|
13813
|
-
console.log(`%c${summary}`, PASS);
|
|
13814
|
-
console.groupEnd();
|
|
13831
|
+
return views[defaultViewName];
|
|
13815
13832
|
}
|
|
13816
|
-
return report;
|
|
13817
13833
|
}
|
|
13818
13834
|
|
|
13819
|
-
//
|
|
13820
|
-
|
|
13821
|
-
|
|
13822
|
-
|
|
13823
|
-
|
|
13824
|
-
"call-with-args": "method call with arguments"
|
|
13825
|
-
};
|
|
13826
|
-
function unsupportedExprMessage(info) {
|
|
13827
|
-
const v = JSON.stringify(info.value);
|
|
13828
|
-
const label = UNSUPPORTED_EXPR_LABEL[info.detected] ?? "expression";
|
|
13829
|
-
switch (info.role) {
|
|
13830
|
-
case "attr":
|
|
13831
|
-
return `Unsupported ${label} ${v} in dynamic attribute ':${info.attr}'`;
|
|
13832
|
-
case "directive":
|
|
13833
|
-
return `Unsupported ${label} ${v} in directive '@${info.directive}'`;
|
|
13834
|
-
case "if":
|
|
13835
|
-
return `Unsupported ${label} ${v} in '@if.${info.attr}' condition`;
|
|
13836
|
-
case "x-op":
|
|
13837
|
-
return `Unsupported ${label} ${v} in <x ${info.op}>`;
|
|
13838
|
-
default:
|
|
13839
|
-
return `Unsupported ${label} ${v}`;
|
|
13835
|
+
// src/transactor.js
|
|
13836
|
+
class State2 {
|
|
13837
|
+
constructor(val) {
|
|
13838
|
+
this.val = val;
|
|
13839
|
+
this.changeSubs = [];
|
|
13840
13840
|
}
|
|
13841
|
-
|
|
13842
|
-
|
|
13843
|
-
const v = JSON.stringify(info.value);
|
|
13844
|
-
switch (info.role) {
|
|
13845
|
-
case "attr":
|
|
13846
|
-
return `Cannot parse value ${v} for attribute ':${info.attr}'`;
|
|
13847
|
-
case "directive":
|
|
13848
|
-
return `Cannot parse value ${v} for directive '@${info.directive}'`;
|
|
13849
|
-
case "if":
|
|
13850
|
-
return `Cannot parse condition ${v} for '@if.${info.attr}'`;
|
|
13851
|
-
case "x-op":
|
|
13852
|
-
return `Cannot parse value ${v} for <x ${info.op}>`;
|
|
13853
|
-
case "handler-name":
|
|
13854
|
-
return `Cannot parse handler name ${v}`;
|
|
13855
|
-
case "handler-arg":
|
|
13856
|
-
return `Cannot parse handler argument ${v}`;
|
|
13857
|
-
case "macro-var":
|
|
13858
|
-
return `Macro variable '^${info.name}' is not defined`;
|
|
13859
|
-
default:
|
|
13860
|
-
return `Cannot parse value ${v}`;
|
|
13841
|
+
onChange(cb) {
|
|
13842
|
+
this.changeSubs.push(cb);
|
|
13861
13843
|
}
|
|
13862
|
-
|
|
13863
|
-
|
|
13864
|
-
|
|
13865
|
-
|
|
13866
|
-
|
|
13867
|
-
const t = tagDisplay(info?.tag);
|
|
13868
|
-
return t && t !== "x" ? ` on <${t}>` : "";
|
|
13869
|
-
}
|
|
13870
|
-
function fmtOriginSuffix(info) {
|
|
13871
|
-
if (!info)
|
|
13872
|
-
return "";
|
|
13873
|
-
const parts = [];
|
|
13874
|
-
if (info.originAttr) {
|
|
13875
|
-
const branch = info.branch ? `[${info.branch}]` : "";
|
|
13876
|
-
parts.push(`in ${info.originAttr}${branch}`);
|
|
13844
|
+
set(val, info) {
|
|
13845
|
+
const old = this.val;
|
|
13846
|
+
this.val = val;
|
|
13847
|
+
for (const sub of this.changeSubs)
|
|
13848
|
+
sub({ val, old, info, timestamp: Date.now() });
|
|
13877
13849
|
}
|
|
13878
|
-
|
|
13879
|
-
|
|
13850
|
+
update(fn, info) {
|
|
13851
|
+
return this.set(fn(this.val), info);
|
|
13880
13852
|
}
|
|
13881
|
-
const t = tagDisplay(info.tag);
|
|
13882
|
-
if (t && t !== "x")
|
|
13883
|
-
parts.push(`on <${t}>`);
|
|
13884
|
-
return parts.length ? ` (${parts.join(", ")})` : "";
|
|
13885
13853
|
}
|
|
13886
|
-
|
|
13887
|
-
|
|
13888
|
-
|
|
13889
|
-
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
}
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
|
|
13897
|
-
|
|
13898
|
-
|
|
13899
|
-
|
|
13900
|
-
|
|
13854
|
+
|
|
13855
|
+
class Transactor {
|
|
13856
|
+
constructor(comps, rootValue) {
|
|
13857
|
+
this.comps = comps;
|
|
13858
|
+
this.transactions = [];
|
|
13859
|
+
this.state = new State2(rootValue);
|
|
13860
|
+
this.onTransactionPushed = () => {};
|
|
13861
|
+
this._inflight = new Set;
|
|
13862
|
+
}
|
|
13863
|
+
pushTransaction(t) {
|
|
13864
|
+
this.transactions.push(t);
|
|
13865
|
+
this.onTransactionPushed(t);
|
|
13866
|
+
}
|
|
13867
|
+
_link(child, parent) {
|
|
13868
|
+
if (parent) {
|
|
13869
|
+
const release = parent.completion.track();
|
|
13870
|
+
child.completion.whenSubtreeSettled().then(release);
|
|
13901
13871
|
}
|
|
13902
|
-
|
|
13903
|
-
|
|
13904
|
-
|
|
13905
|
-
|
|
13906
|
-
|
|
13907
|
-
|
|
13908
|
-
|
|
13909
|
-
|
|
13910
|
-
|
|
13911
|
-
|
|
13912
|
-
|
|
13913
|
-
|
|
13914
|
-
|
|
13915
|
-
|
|
13916
|
-
|
|
13917
|
-
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13872
|
+
return child;
|
|
13873
|
+
}
|
|
13874
|
+
pushSend(path, name, args = [], opts = {}, parent = null) {
|
|
13875
|
+
const t = new SendEvent(path, this, name, args, parent, opts);
|
|
13876
|
+
this.pushTransaction(t);
|
|
13877
|
+
return this._link(t, parent);
|
|
13878
|
+
}
|
|
13879
|
+
pushInput(path, name, args = [], opts = {}, parent = null) {
|
|
13880
|
+
const t = new InputDispatchEvent(path, this, name, args, parent, opts);
|
|
13881
|
+
this.pushTransaction(t);
|
|
13882
|
+
return this._link(t, parent);
|
|
13883
|
+
}
|
|
13884
|
+
pushBubble(path, name, args = [], opts = {}, parent = null, targetPath = null) {
|
|
13885
|
+
const newOpts = opts.skipSelf ? { ...opts, skipSelf: false } : opts;
|
|
13886
|
+
const t = new BubbleEvent(path, this, name, args, parent, newOpts, targetPath);
|
|
13887
|
+
this.pushTransaction(t);
|
|
13888
|
+
return this._link(t, parent);
|
|
13889
|
+
}
|
|
13890
|
+
pushRequest(path, name, args = [], opts = {}, parent = null) {
|
|
13891
|
+
const release = parent ? parent.completion.track() : null;
|
|
13892
|
+
const p = this._runRequest(path, name, args, opts, parent, release);
|
|
13893
|
+
this._inflight.add(p);
|
|
13894
|
+
p.finally(() => this._inflight.delete(p));
|
|
13895
|
+
return p;
|
|
13896
|
+
}
|
|
13897
|
+
async settle(maxTurns = 1e4) {
|
|
13898
|
+
while ((this.hasPendingTransactions || this._inflight.size) && maxTurns-- > 0) {
|
|
13899
|
+
while (this.hasPendingTransactions)
|
|
13900
|
+
this.transactNext();
|
|
13901
|
+
if (this._inflight.size)
|
|
13902
|
+
await Promise.allSettled([...this._inflight]);
|
|
13903
|
+
}
|
|
13904
|
+
}
|
|
13905
|
+
async _runRequest(path, name, args = [], opts = {}, parent = null, release = null) {
|
|
13906
|
+
let released = false;
|
|
13907
|
+
const transfer = (t) => {
|
|
13908
|
+
if (release) {
|
|
13909
|
+
released = true;
|
|
13910
|
+
t.completion.whenSubtreeSettled().then(release);
|
|
13911
|
+
}
|
|
13912
|
+
};
|
|
13913
|
+
try {
|
|
13914
|
+
const curRoot = this.state.val;
|
|
13915
|
+
const txnPath = path.toTransactionPath();
|
|
13916
|
+
const curLeaf = txnPath.lookup(curRoot);
|
|
13917
|
+
const handler = this.comps.getRequestFor(curLeaf, name) ?? mkReq404(name);
|
|
13918
|
+
const reqCtx = new RequestContext(path, this, parent, curRoot);
|
|
13919
|
+
const resHandlerName = opts?.onResName ?? name;
|
|
13920
|
+
const resPath = opts?.livePath ? null : txnPath.pinKeys(curRoot);
|
|
13921
|
+
const push = (specificName, baseName, singleArg, result, error) => {
|
|
13922
|
+
const resArgs = specificName ? [singleArg] : [result, error];
|
|
13923
|
+
const t = new ResponseEvent(path, this, specificName ?? baseName, resArgs, parent, resPath);
|
|
13924
|
+
transfer(t);
|
|
13925
|
+
this.pushTransaction(t);
|
|
13926
|
+
};
|
|
13927
|
+
try {
|
|
13928
|
+
const result = await handler.fn.apply(null, [...args, reqCtx]);
|
|
13929
|
+
push(opts?.onOkName, resHandlerName, result, result, null);
|
|
13930
|
+
} catch (error) {
|
|
13931
|
+
push(opts?.onErrorName, resHandlerName, error, null, error);
|
|
13932
|
+
}
|
|
13933
|
+
} finally {
|
|
13934
|
+
if (release && !released)
|
|
13935
|
+
release();
|
|
13926
13936
|
}
|
|
13927
|
-
|
|
13928
|
-
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
13939
|
-
|
|
13940
|
-
|
|
13941
|
-
|
|
13942
|
-
|
|
13943
|
-
|
|
13944
|
-
|
|
13945
|
-
|
|
13946
|
-
|
|
13947
|
-
case "UNKNOWN_MACRO_ARG":
|
|
13948
|
-
return `Argument '${info.name}' is not declared in macro '${info.macroName}'`;
|
|
13949
|
-
case "UNKNOWN_DIRECTIVE":
|
|
13950
|
-
return `Unknown directive '@${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
|
|
13951
|
-
case "UNKNOWN_X_OP":
|
|
13952
|
-
return `Unknown <x> op '${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
|
|
13953
|
-
case "UNKNOWN_X_ATTR":
|
|
13954
|
-
return `Unknown attribute '${info.name}=${JSON.stringify(info.value)}' on <x ${info.op}>${fmtTagSuffix(info)}`;
|
|
13955
|
-
case "MAYBE_DROP_AT_PREFIX": {
|
|
13956
|
-
const written = info.value !== undefined ? `${info.name}=${JSON.stringify(info.value)}` : info.name;
|
|
13957
|
-
return `'${written}' on <x> looks like a directive but is actually an x op/attr written with a leading '@'`;
|
|
13937
|
+
}
|
|
13938
|
+
get hasPendingTransactions() {
|
|
13939
|
+
return this.transactions.length > 0;
|
|
13940
|
+
}
|
|
13941
|
+
transactNext() {
|
|
13942
|
+
if (this.hasPendingTransactions)
|
|
13943
|
+
this.transact(this.transactions.shift());
|
|
13944
|
+
}
|
|
13945
|
+
transact(transaction) {
|
|
13946
|
+
try {
|
|
13947
|
+
const curState = this.state.val;
|
|
13948
|
+
const newState = transaction.run(curState, this.comps);
|
|
13949
|
+
if (newState !== undefined) {
|
|
13950
|
+
this.state.set(newState, { transaction });
|
|
13951
|
+
transaction.afterTransaction();
|
|
13952
|
+
} else
|
|
13953
|
+
console.warn("undefined new state", { curState, transaction });
|
|
13954
|
+
} finally {
|
|
13955
|
+
transaction._completion?.ensureSelfSettled();
|
|
13956
|
+
transaction._completion?.releaseSelf();
|
|
13958
13957
|
}
|
|
13959
|
-
case "MAYBE_ADD_AT_PREFIX":
|
|
13960
|
-
return `'${info.name}' on <${(info.tag ?? "").toLowerCase()}> is a plain attribute, but '@${info.name}' is a directive — add the leading '@'`;
|
|
13961
|
-
case "BAD_VALUE":
|
|
13962
|
-
return `${badValueMessage(info)}${fmtTagSuffix(info)}`;
|
|
13963
|
-
case "UNSUPPORTED_EXPR_SYNTAX":
|
|
13964
|
-
return `${unsupportedExprMessage(info)}${fmtTagSuffix(info)}`;
|
|
13965
|
-
case "REDUNDANT_TEMPLATE_STRING":
|
|
13966
|
-
return `Redundant template string — '{${info.simpler}}' should be just '${info.simpler}'${fmtOriginSuffix(info)}`;
|
|
13967
|
-
case "PLACEHOLDERLESS_TEMPLATE_STRING":
|
|
13968
|
-
return `Template string has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
|
|
13969
|
-
case "UNKNOWN_COMPONENT_SPEC_KEY":
|
|
13970
|
-
return `Unknown component spec key '${info.key}' — value will be ignored at runtime`;
|
|
13971
|
-
case "COMP_FIELD_BAD_SHAPE":
|
|
13972
|
-
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}`;
|
|
13973
|
-
case "HTML_TAG_NAME_HAS_UPPERCASE":
|
|
13974
|
-
return `Tag <${info.raw}> will be lowercased to <${info.lowercased}>${fmtLocationSuffix(info)}`;
|
|
13975
|
-
case "HTML_SVG_TAG_WILL_LOWERCASE":
|
|
13976
|
-
return `SVG tag <${info.raw}> is not in the WHATWG case-correction list — will be lowercased to <${info.lowercased}>${fmtLocationSuffix(info)}`;
|
|
13977
|
-
case "HTML_TAG_NOT_ALLOWED_IN_PARENT":
|
|
13978
|
-
return `<${info.tag}> not allowed under <${info.parent ?? "?"}> in ${info.mode} — ${htmlActionPhrase(info.action, info.tag, info.parent)}${fmtLocationSuffix(info)}`;
|
|
13979
|
-
case "HTML_TEXT_NOT_ALLOWED_IN_PARENT":
|
|
13980
|
-
return `Non-whitespace text not allowed in ${info.mode}: ${JSON.stringify(info.snippet)}${fmtLocationSuffix(info)}`;
|
|
13981
|
-
case "HTML_VOID_ELEMENT_HAS_CLOSE_TAG":
|
|
13982
|
-
return `Void element <${info.tag}> has an explicit close tag${fmtLocationSuffix(info)}`;
|
|
13983
|
-
case "HTML_DUPLICATE_FORM":
|
|
13984
|
-
return `Nested <form> — the inner form will be dropped by the parser${fmtLocationSuffix(info)}`;
|
|
13985
|
-
case "HTML_NESTED_INTERACTIVE":
|
|
13986
|
-
return `<${info.tag}> nested inside another <${info.tag}> — adoption agency will reorder${fmtLocationSuffix(info)}`;
|
|
13987
|
-
case "HTML_MISNESTED_FORMATTING":
|
|
13988
|
-
return `Misnested formatting tag </${info.tag}> — adoption agency will reorder nodes${fmtLocationSuffix(info)}`;
|
|
13989
|
-
case "HTML_UNEXPECTED_END_TAG":
|
|
13990
|
-
return `Unexpected end tag </${info.tag}>${fmtLocationSuffix(info)}`;
|
|
13991
|
-
case "HTML_UNCLOSED_BEFORE_END":
|
|
13992
|
-
return `<${info.unclosed}> still open when </${info.tag}> was seen — implicitly closed${fmtLocationSuffix(info)}`;
|
|
13993
|
-
case "HTML_DUPLICATE_ATTRIBUTE":
|
|
13994
|
-
return `Duplicate attribute '${info.name}' — second occurrence dropped${fmtLocationSuffix(info)}`;
|
|
13995
|
-
case "HTML_ATTRIBUTES_ON_END_TAG":
|
|
13996
|
-
return `Attributes on end tag </${info.tag}> — dropped by the parser${fmtLocationSuffix(info)}`;
|
|
13997
|
-
case "HTML_SELF_CLOSING_END_TAG":
|
|
13998
|
-
return `Self-closing end tag </${info.tag}/> — trailing '/' is meaningless${fmtLocationSuffix(info)}`;
|
|
13999
|
-
case "HTML_MISSING_ATTRIBUTE_VALUE":
|
|
14000
|
-
return `Attribute '${info.name}' is missing a value${fmtLocationSuffix(info)}`;
|
|
14001
|
-
case "HTML_CDATA_IN_HTML_NAMESPACE":
|
|
14002
|
-
return `CDATA section in HTML namespace — reinterpreted as a bogus comment${fmtLocationSuffix(info)}`;
|
|
14003
|
-
case "HTML_BOGUS_COMMENT":
|
|
14004
|
-
return `Bogus comment — content dropped by the parser${fmtLocationSuffix(info)}`;
|
|
14005
|
-
case "HTML_SVG_ATTR_WILL_LOWERCASE":
|
|
14006
|
-
return `SVG attribute '${info.raw}' will be rewritten to '${info.canonical}'${fmtLocationSuffix(info)}`;
|
|
14007
|
-
case "HTML_MATHML_ATTR_WILL_LOWERCASE":
|
|
14008
|
-
return `MathML attribute '${info.raw}' will be rewritten to '${info.canonical}'${fmtLocationSuffix(info)}`;
|
|
14009
|
-
case "ASYNC_HANDLER":
|
|
14010
|
-
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)`;
|
|
14011
|
-
case "LINT_ERROR":
|
|
14012
|
-
return info.message;
|
|
14013
|
-
default:
|
|
14014
|
-
return id;
|
|
14015
13958
|
}
|
|
14016
|
-
|
|
14017
|
-
|
|
14018
|
-
if (!suggestion)
|
|
14019
|
-
return null;
|
|
14020
|
-
switch (suggestion.kind) {
|
|
14021
|
-
case "replace-name":
|
|
14022
|
-
return `did you mean '${suggestion.to}'?`;
|
|
14023
|
-
case "drop-prefix":
|
|
14024
|
-
return `did you mean '${suggestion.to}'? (drop the leading '${suggestion.from.slice(0, suggestion.from.length - suggestion.to.length)}')`;
|
|
14025
|
-
case "add-prefix":
|
|
14026
|
-
return `did you mean '${suggestion.to}'? (add the leading '${suggestion.to.slice(0, suggestion.to.length - suggestion.from.length)}')`;
|
|
14027
|
-
case "remove":
|
|
14028
|
-
return `remove ${suggestion.what}`;
|
|
14029
|
-
case "rewrite":
|
|
14030
|
-
return `use '${suggestion.to}' instead of '${suggestion.from}'`;
|
|
14031
|
-
case "wrap":
|
|
14032
|
-
return `wrap it in ${suggestion.to}`;
|
|
14033
|
-
case "rephrase":
|
|
14034
|
-
return suggestion.text ?? null;
|
|
14035
|
-
default:
|
|
14036
|
-
return null;
|
|
13959
|
+
transactInputNow(path, event, eventHandler, dragInfo) {
|
|
13960
|
+
this.transact(new InputEvent(path, event, eventHandler, this, dragInfo));
|
|
14037
13961
|
}
|
|
14038
13962
|
}
|
|
14039
|
-
function
|
|
14040
|
-
const
|
|
14041
|
-
|
|
14042
|
-
|
|
14043
|
-
return
|
|
13963
|
+
function mkReq404(name) {
|
|
13964
|
+
const fn = () => {
|
|
13965
|
+
throw new Error(`Request not found: ${name}`);
|
|
13966
|
+
};
|
|
13967
|
+
return { fn };
|
|
14044
13968
|
}
|
|
14045
|
-
function
|
|
14046
|
-
|
|
14047
|
-
case "ignored":
|
|
14048
|
-
return `the parser will drop this <${tag}>`;
|
|
14049
|
-
case "drop":
|
|
14050
|
-
return `the parser will drop this <${tag}>`;
|
|
14051
|
-
case "auto-close-implicit":
|
|
14052
|
-
return `the parser will close <${parent ?? "?"}> first, then place <${tag}> as a sibling`;
|
|
14053
|
-
case "foster-parent":
|
|
14054
|
-
return `the parser will move <${tag}> outside <${parent ?? "?"}> (foster-parenting)`;
|
|
14055
|
-
case "foreign-breakout":
|
|
14056
|
-
return `the parser will exit foreign content and re-process <${tag}> in HTML mode`;
|
|
14057
|
-
default:
|
|
14058
|
-
return `parser action: ${action}`;
|
|
14059
|
-
}
|
|
13969
|
+
function nullHandler() {
|
|
13970
|
+
return this;
|
|
14060
13971
|
}
|
|
14061
13972
|
|
|
14062
|
-
|
|
14063
|
-
|
|
14064
|
-
|
|
14065
|
-
this.
|
|
14066
|
-
this.
|
|
14067
|
-
|
|
14068
|
-
registerComponent(comp) {
|
|
14069
|
-
comp.Class.prototype[this.getComponentSymbol] = () => comp;
|
|
14070
|
-
this.byId.set(comp.id, comp);
|
|
13973
|
+
class Transaction {
|
|
13974
|
+
constructor(path, transactor, parentTransaction = null) {
|
|
13975
|
+
this.path = path;
|
|
13976
|
+
this.transactor = transactor;
|
|
13977
|
+
this.parentTransaction = parentTransaction;
|
|
13978
|
+
this._completion = null;
|
|
14071
13979
|
}
|
|
14072
|
-
|
|
14073
|
-
|
|
13980
|
+
get completion() {
|
|
13981
|
+
this._completion ??= new Completion;
|
|
13982
|
+
return this._completion;
|
|
14074
13983
|
}
|
|
14075
|
-
|
|
14076
|
-
return
|
|
13984
|
+
whenSettled() {
|
|
13985
|
+
return this.completion.whenSettled();
|
|
14077
13986
|
}
|
|
14078
|
-
|
|
14079
|
-
return this.
|
|
13987
|
+
whenSubtreeSettled() {
|
|
13988
|
+
return this.completion.whenSubtreeSettled();
|
|
14080
13989
|
}
|
|
14081
|
-
|
|
14082
|
-
return this.
|
|
13990
|
+
run(rootValue, comps) {
|
|
13991
|
+
return this.updateRootValue(rootValue, comps);
|
|
14083
13992
|
}
|
|
14084
|
-
|
|
14085
|
-
|
|
14086
|
-
|
|
14087
|
-
styles2.push(comp.compileStyle());
|
|
14088
|
-
return styles2.join(`
|
|
14089
|
-
`);
|
|
13993
|
+
afterTransaction() {}
|
|
13994
|
+
buildRootStack(root, comps) {
|
|
13995
|
+
return Stack2.root(comps, root);
|
|
14090
13996
|
}
|
|
14091
|
-
|
|
14092
|
-
|
|
14093
|
-
class ComponentStack {
|
|
14094
|
-
constructor(comps = new Components, parent = null) {
|
|
14095
|
-
this.comps = comps;
|
|
14096
|
-
this.parent = parent;
|
|
14097
|
-
this.byName = {};
|
|
14098
|
-
this.reqsByName = {};
|
|
14099
|
-
this.macros = {};
|
|
13997
|
+
buildStack(root, comps) {
|
|
13998
|
+
return this.path.toTransactionPath().buildStack(this.buildRootStack(root, comps));
|
|
14100
13999
|
}
|
|
14101
|
-
|
|
14102
|
-
|
|
14000
|
+
callHandler(root, instance, comps) {
|
|
14001
|
+
const [handler, args] = this.getHandlerAndArgs(root, instance, comps);
|
|
14002
|
+
return handler.apply(instance, args);
|
|
14103
14003
|
}
|
|
14104
|
-
|
|
14105
|
-
|
|
14106
|
-
|
|
14107
|
-
|
|
14108
|
-
|
|
14109
|
-
|
|
14110
|
-
|
|
14111
|
-
|
|
14112
|
-
|
|
14113
|
-
|
|
14114
|
-
|
|
14115
|
-
|
|
14116
|
-
|
|
14117
|
-
|
|
14118
|
-
|
|
14119
|
-
|
|
14004
|
+
getHandlerAndArgs(_root, _instance, _comps) {
|
|
14005
|
+
return null;
|
|
14006
|
+
}
|
|
14007
|
+
getTransactionPath() {
|
|
14008
|
+
return this.path.toTransactionPath();
|
|
14009
|
+
}
|
|
14010
|
+
updateRootValue(curRoot, comps) {
|
|
14011
|
+
const txnPath = this.getTransactionPath();
|
|
14012
|
+
const curLeaf = txnPath.lookup(curRoot);
|
|
14013
|
+
const newLeaf = this.callHandler(curRoot, curLeaf, comps);
|
|
14014
|
+
this._completion?.markSelfSettled({ value: newLeaf, old: curLeaf });
|
|
14015
|
+
return curLeaf !== newLeaf ? txnPath.setValue(curRoot, newLeaf) : curRoot;
|
|
14016
|
+
}
|
|
14017
|
+
lookupName(_name) {
|
|
14018
|
+
return null;
|
|
14019
|
+
}
|
|
14020
|
+
}
|
|
14021
|
+
var toNullIfNaN = (v) => Number.isNaN(v) ? null : v;
|
|
14022
|
+
function getValue(e) {
|
|
14023
|
+
return e.target.type === "checkbox" ? e.target.checked : (e instanceof CustomEvent ? e.detail : e.target.value) ?? null;
|
|
14024
|
+
}
|
|
14025
|
+
|
|
14026
|
+
class InputEvent extends Transaction {
|
|
14027
|
+
constructor(path, e, handler, transactor, dragInfo) {
|
|
14028
|
+
super(path, transactor);
|
|
14029
|
+
this.e = e;
|
|
14030
|
+
this.handler = handler;
|
|
14031
|
+
this.dragInfo = dragInfo;
|
|
14032
|
+
this._dispatchPath = null;
|
|
14033
|
+
}
|
|
14034
|
+
get dispatchPath() {
|
|
14035
|
+
this._dispatchPath ??= this.path.compact();
|
|
14036
|
+
return this._dispatchPath;
|
|
14037
|
+
}
|
|
14038
|
+
buildRootStack(root, comps) {
|
|
14039
|
+
return Stack2.root(comps, root, this);
|
|
14040
|
+
}
|
|
14041
|
+
getHandlerAndArgs(root, _instance, comps) {
|
|
14042
|
+
const stack = this.buildStack(root, comps);
|
|
14043
|
+
const [handler, args] = this.handler.getHandlerAndArgs(stack, this);
|
|
14044
|
+
const path = this.dispatchPath;
|
|
14045
|
+
let dispatcher;
|
|
14046
|
+
for (let i = 0;i < args.length; i++) {
|
|
14047
|
+
if (args[i]?.toHandlerArg) {
|
|
14048
|
+
dispatcher ??= new Dispatcher(path, this.transactor, this);
|
|
14049
|
+
args[i] = args[i].toHandlerArg(dispatcher);
|
|
14050
|
+
}
|
|
14120
14051
|
}
|
|
14052
|
+
args.push(new EventContext(path, this.transactor, this));
|
|
14053
|
+
return [handler, args];
|
|
14121
14054
|
}
|
|
14122
|
-
|
|
14123
|
-
|
|
14124
|
-
|
|
14125
|
-
|
|
14126
|
-
|
|
14055
|
+
lookupName(name) {
|
|
14056
|
+
const { e } = this;
|
|
14057
|
+
switch (name) {
|
|
14058
|
+
case "value":
|
|
14059
|
+
return getValue(e);
|
|
14060
|
+
case "valueAsInt":
|
|
14061
|
+
return toNullIfNaN(parseInt(getValue(e), 10));
|
|
14062
|
+
case "valueAsFloat":
|
|
14063
|
+
return toNullIfNaN(parseFloat(getValue(e)));
|
|
14064
|
+
case "target":
|
|
14065
|
+
return e.target;
|
|
14066
|
+
case "event":
|
|
14067
|
+
return e;
|
|
14068
|
+
case "isAlt":
|
|
14069
|
+
return e.altKey;
|
|
14070
|
+
case "isShift":
|
|
14071
|
+
return e.shiftKey;
|
|
14072
|
+
case "isCtrl":
|
|
14073
|
+
case "isCmd":
|
|
14074
|
+
return isMac && e.metaKey || e.ctrlKey;
|
|
14075
|
+
case "key":
|
|
14076
|
+
return e.key;
|
|
14077
|
+
case "keyCode":
|
|
14078
|
+
return e.keyCode;
|
|
14079
|
+
case "isUpKey":
|
|
14080
|
+
return e.key === "ArrowUp";
|
|
14081
|
+
case "isDownKey":
|
|
14082
|
+
return e.key === "ArrowDown";
|
|
14083
|
+
case "isSend":
|
|
14084
|
+
return e.key === "Enter";
|
|
14085
|
+
case "isCancel":
|
|
14086
|
+
return e.key === "Escape";
|
|
14087
|
+
case "isTabKey":
|
|
14088
|
+
return e.key === "Tab";
|
|
14089
|
+
case "ctx":
|
|
14090
|
+
return new EventContext(this.dispatchPath, this.transactor, this);
|
|
14091
|
+
case "dragInfo":
|
|
14092
|
+
return this.dragInfo;
|
|
14127
14093
|
}
|
|
14094
|
+
return null;
|
|
14128
14095
|
}
|
|
14129
|
-
|
|
14130
|
-
|
|
14096
|
+
}
|
|
14097
|
+
|
|
14098
|
+
class NameArgsTransaction extends Transaction {
|
|
14099
|
+
constructor(path, transactor, name, args, parentTransaction, opts = {}) {
|
|
14100
|
+
super(path, transactor, parentTransaction);
|
|
14101
|
+
this.name = name;
|
|
14102
|
+
this.args = args;
|
|
14103
|
+
this.opts = opts;
|
|
14104
|
+
this.targetPath = path;
|
|
14131
14105
|
}
|
|
14132
|
-
|
|
14133
|
-
|
|
14134
|
-
|
|
14106
|
+
handlerProp = null;
|
|
14107
|
+
getHandlerForName(comp) {
|
|
14108
|
+
const handlers = comp?.[this.handlerProp];
|
|
14109
|
+
return handlers?.[this.name] ?? handlers?.$unknown ?? nullHandler;
|
|
14135
14110
|
}
|
|
14136
|
-
|
|
14137
|
-
|
|
14111
|
+
getHandlerAndArgs(_root, instance, comps) {
|
|
14112
|
+
const handler = this.getHandlerForName(comps.getCompFor(instance));
|
|
14113
|
+
return [handler, [...this.args, new EventContext(this.path, this.transactor, this)]];
|
|
14138
14114
|
}
|
|
14139
|
-
|
|
14140
|
-
|
|
14115
|
+
}
|
|
14116
|
+
|
|
14117
|
+
class ResponseEvent extends NameArgsTransaction {
|
|
14118
|
+
handlerProp = "response";
|
|
14119
|
+
constructor(path, transactor, name, args, parent, txnPath = null) {
|
|
14120
|
+
super(path, transactor, name, args, parent);
|
|
14121
|
+
this._txnPath = txnPath;
|
|
14141
14122
|
}
|
|
14142
|
-
|
|
14143
|
-
return this.
|
|
14123
|
+
getTransactionPath() {
|
|
14124
|
+
return this._txnPath ?? super.getTransactionPath();
|
|
14144
14125
|
}
|
|
14145
14126
|
}
|
|
14146
14127
|
|
|
14147
|
-
class
|
|
14148
|
-
|
|
14149
|
-
|
|
14150
|
-
this.
|
|
14151
|
-
|
|
14128
|
+
class SendEvent extends NameArgsTransaction {
|
|
14129
|
+
handlerProp = "receive";
|
|
14130
|
+
run(rootVal, comps) {
|
|
14131
|
+
return this.opts.skipSelf ? rootVal : this.updateRootValue(rootVal, comps);
|
|
14132
|
+
}
|
|
14133
|
+
afterTransaction() {
|
|
14134
|
+
const { path, name, args, opts, targetPath } = this;
|
|
14135
|
+
if (opts.bubbles && path.steps.length > 0)
|
|
14136
|
+
this.transactor.pushBubble(path.popStep(), name, args, opts, this, targetPath);
|
|
14152
14137
|
}
|
|
14153
14138
|
}
|
|
14154
14139
|
|
|
14155
|
-
class
|
|
14156
|
-
|
|
14157
|
-
|
|
14158
|
-
|
|
14159
|
-
this.
|
|
14160
|
-
this.val = val;
|
|
14161
|
-
this._sym = undefined;
|
|
14140
|
+
class BubbleEvent extends SendEvent {
|
|
14141
|
+
handlerProp = "bubble";
|
|
14142
|
+
constructor(path, transactor, name, args, parent, opts, targetPath) {
|
|
14143
|
+
super(path, transactor, name, args, parent, opts);
|
|
14144
|
+
this.targetPath = targetPath ?? path;
|
|
14162
14145
|
}
|
|
14163
|
-
|
|
14164
|
-
|
|
14165
|
-
this._sym = stack.lookupType(this.compName)?.provide?.[this.provideName]?.symbol ?? null;
|
|
14166
|
-
return this._sym;
|
|
14146
|
+
stopPropagation() {
|
|
14147
|
+
this.opts.bubbles = false;
|
|
14167
14148
|
}
|
|
14168
14149
|
}
|
|
14169
|
-
var isString = (v) => typeof v === "string";
|
|
14170
|
-
var _rawSpecKeys = "name view style commonStyle globalStyle input receive bubble response alter views provide lookup fields methods statics";
|
|
14171
|
-
var KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
|
|
14172
|
-
var _compId = 0;
|
|
14173
14150
|
|
|
14174
|
-
class
|
|
14175
|
-
|
|
14176
|
-
|
|
14177
|
-
|
|
14178
|
-
|
|
14179
|
-
|
|
14180
|
-
this.
|
|
14181
|
-
this.
|
|
14182
|
-
this.
|
|
14183
|
-
this.
|
|
14184
|
-
this.
|
|
14185
|
-
this.
|
|
14186
|
-
this.
|
|
14187
|
-
|
|
14188
|
-
|
|
14189
|
-
|
|
14190
|
-
|
|
14191
|
-
|
|
14192
|
-
|
|
14193
|
-
this.
|
|
14194
|
-
|
|
14195
|
-
|
|
14196
|
-
this.
|
|
14197
|
-
this.spec = o;
|
|
14198
|
-
this.extra = {};
|
|
14199
|
-
for (const key of Object.keys(o))
|
|
14200
|
-
if (!KNOWN_SPEC_KEYS.has(key))
|
|
14201
|
-
this.extra[key] = o[key];
|
|
14151
|
+
class InputDispatchEvent extends NameArgsTransaction {
|
|
14152
|
+
handlerProp = "input";
|
|
14153
|
+
}
|
|
14154
|
+
|
|
14155
|
+
class Completion {
|
|
14156
|
+
constructor() {
|
|
14157
|
+
this.val = undefined;
|
|
14158
|
+
this.selfSettled = false;
|
|
14159
|
+
this.subtreeSettled = false;
|
|
14160
|
+
this.pending = 1;
|
|
14161
|
+
this._selfResolve = null;
|
|
14162
|
+
this._selfPromise = null;
|
|
14163
|
+
this._subtreeResolve = null;
|
|
14164
|
+
this._subtreePromise = null;
|
|
14165
|
+
this._selfReleased = false;
|
|
14166
|
+
}
|
|
14167
|
+
whenSettled() {
|
|
14168
|
+
if (this.selfSettled)
|
|
14169
|
+
return Promise.resolve(this.val);
|
|
14170
|
+
this._selfPromise ??= new Promise((res) => {
|
|
14171
|
+
this._selfResolve = res;
|
|
14172
|
+
});
|
|
14173
|
+
return this._selfPromise;
|
|
14202
14174
|
}
|
|
14203
|
-
|
|
14204
|
-
|
|
14175
|
+
whenSubtreeSettled() {
|
|
14176
|
+
if (this.subtreeSettled)
|
|
14177
|
+
return Promise.resolve(this.val);
|
|
14178
|
+
this._subtreePromise ??= new Promise((res) => {
|
|
14179
|
+
this._subtreeResolve = res;
|
|
14180
|
+
});
|
|
14181
|
+
return this._subtreePromise;
|
|
14205
14182
|
}
|
|
14206
|
-
|
|
14207
|
-
|
|
14208
|
-
|
|
14209
|
-
|
|
14210
|
-
|
|
14211
|
-
|
|
14212
|
-
if (val)
|
|
14213
|
-
this.provide[key] = new ProvideInfo(key, val, Symbol(key));
|
|
14214
|
-
}
|
|
14215
|
-
for (const key in this._rawLookup) {
|
|
14216
|
-
const linfo = this._rawLookup[key];
|
|
14217
|
-
const forStr = isString(linfo) ? linfo : isString(linfo?.for) ? linfo.for : null;
|
|
14218
|
-
const [compName, provideName] = forStr === null ? [] : forStr.split(".");
|
|
14219
|
-
if (!isString(compName) || !isString(provideName))
|
|
14220
|
-
continue;
|
|
14221
|
-
const defStr = isString(linfo?.default) ? linfo.default : null;
|
|
14222
|
-
const val = defStr === null ? null : vp.parseField(defStr, ctx);
|
|
14223
|
-
this.lookup[key] = new LookupInfo(key, compName, provideName, val);
|
|
14224
|
-
}
|
|
14225
|
-
for (const key in this.lookup)
|
|
14226
|
-
if (this.provide[key] !== undefined)
|
|
14227
|
-
console.warn("name declared in both provide and lookup", this.name, key);
|
|
14183
|
+
markSelfSettled(val) {
|
|
14184
|
+
if (this.selfSettled)
|
|
14185
|
+
return;
|
|
14186
|
+
this.selfSettled = true;
|
|
14187
|
+
this.val = val;
|
|
14188
|
+
this._selfResolve?.(val);
|
|
14228
14189
|
}
|
|
14229
|
-
|
|
14230
|
-
|
|
14190
|
+
ensureSelfSettled() {
|
|
14191
|
+
if (!this.selfSettled)
|
|
14192
|
+
this.markSelfSettled(this.val);
|
|
14231
14193
|
}
|
|
14232
|
-
|
|
14233
|
-
|
|
14194
|
+
track() {
|
|
14195
|
+
this.pending++;
|
|
14196
|
+
let done = false;
|
|
14197
|
+
return () => {
|
|
14198
|
+
if (done)
|
|
14199
|
+
return;
|
|
14200
|
+
done = true;
|
|
14201
|
+
this._release();
|
|
14202
|
+
};
|
|
14234
14203
|
}
|
|
14235
|
-
|
|
14236
|
-
|
|
14204
|
+
releaseSelf() {
|
|
14205
|
+
if (this._selfReleased)
|
|
14206
|
+
return;
|
|
14207
|
+
this._selfReleased = true;
|
|
14208
|
+
this._release();
|
|
14237
14209
|
}
|
|
14238
|
-
|
|
14239
|
-
|
|
14210
|
+
_release() {
|
|
14211
|
+
if (--this.pending === 0) {
|
|
14212
|
+
this.subtreeSettled = true;
|
|
14213
|
+
this._subtreeResolve?.(this.val);
|
|
14214
|
+
}
|
|
14240
14215
|
}
|
|
14241
|
-
compileStyle() {
|
|
14242
|
-
const { id, commonStyle, globalStyle, views } = this;
|
|
14243
|
-
const styles2 = commonStyle ? [`[data-cid="${id}"]{${commonStyle}}`] : [];
|
|
14244
|
-
if (globalStyle !== "")
|
|
14245
|
-
styles2.push(globalStyle);
|
|
14246
|
-
for (const name in views) {
|
|
14247
|
-
const { style } = views[name];
|
|
14248
|
-
if (style !== "")
|
|
14249
|
-
styles2.push(`[data-cid="${id}"][data-vid="${name}"]{${style}}`);
|
|
14250
|
-
}
|
|
14251
|
-
return styles2.join(`
|
|
14252
|
-
`);
|
|
14253
|
-
}
|
|
14254
|
-
}
|
|
14255
|
-
|
|
14256
|
-
// src/stack.js
|
|
14257
|
-
var STOP = Symbol("STOP");
|
|
14258
|
-
var NEXT = Symbol("NEXT");
|
|
14259
|
-
function lookup(chain, name, dv = null) {
|
|
14260
|
-
let n = chain;
|
|
14261
|
-
while (n !== null) {
|
|
14262
|
-
const r = n[0].lookup(name);
|
|
14263
|
-
if (r === STOP)
|
|
14264
|
-
return dv;
|
|
14265
|
-
if (r !== NEXT)
|
|
14266
|
-
return r;
|
|
14267
|
-
n = n[1];
|
|
14268
|
-
}
|
|
14269
|
-
return dv;
|
|
14270
14216
|
}
|
|
14271
14217
|
|
|
14272
|
-
class
|
|
14273
|
-
constructor(
|
|
14274
|
-
this.
|
|
14275
|
-
this.
|
|
14276
|
-
this.
|
|
14218
|
+
class Dispatcher {
|
|
14219
|
+
constructor(path, transactor, parentTransaction, root = transactor.state.val) {
|
|
14220
|
+
this.path = path;
|
|
14221
|
+
this.transactor = transactor;
|
|
14222
|
+
this.parent = parentTransaction;
|
|
14223
|
+
this.root = root;
|
|
14277
14224
|
}
|
|
14278
|
-
|
|
14279
|
-
const
|
|
14280
|
-
|
|
14225
|
+
walkPath(callback) {
|
|
14226
|
+
const comps = this.transactor.comps;
|
|
14227
|
+
const chain = this.path.toTransactionPath().resolveChain(this.root);
|
|
14228
|
+
for (let i = chain.length - 1;i >= 0; i--) {
|
|
14229
|
+
const comp = comps.getCompFor(chain[i]);
|
|
14230
|
+
if (comp && callback(comp, chain[i]) === false)
|
|
14231
|
+
return;
|
|
14232
|
+
}
|
|
14281
14233
|
}
|
|
14282
|
-
|
|
14283
|
-
|
|
14284
|
-
class ObjectFrame {
|
|
14285
|
-
constructor(binds) {
|
|
14286
|
-
this.binds = binds;
|
|
14234
|
+
get at() {
|
|
14235
|
+
return new PathChanges(this);
|
|
14287
14236
|
}
|
|
14288
|
-
|
|
14289
|
-
|
|
14290
|
-
return v === undefined ? NEXT : v;
|
|
14237
|
+
send(name, args, opts) {
|
|
14238
|
+
return this.sendAtPath(this.path, name, args, opts);
|
|
14291
14239
|
}
|
|
14292
|
-
|
|
14293
|
-
|
|
14294
|
-
let s = "";
|
|
14295
|
-
let n = views;
|
|
14296
|
-
while (n !== null) {
|
|
14297
|
-
s += n[0];
|
|
14298
|
-
n = n[1];
|
|
14240
|
+
bubble(name, args, opts) {
|
|
14241
|
+
return this.send(name, args, { skipSelf: true, bubbles: true, ...opts });
|
|
14299
14242
|
}
|
|
14300
|
-
|
|
14301
|
-
|
|
14302
|
-
|
|
14303
|
-
class Stack2 {
|
|
14304
|
-
constructor(comps, it, binds, dynBinds, views, viewsId, ctx = null) {
|
|
14305
|
-
this.comps = comps;
|
|
14306
|
-
this.it = it;
|
|
14307
|
-
this.binds = binds;
|
|
14308
|
-
this.dynBinds = dynBinds;
|
|
14309
|
-
this.views = views;
|
|
14310
|
-
this.viewsId = viewsId;
|
|
14311
|
-
this.ctx = ctx;
|
|
14243
|
+
sendAtPath(path, name, args, opts) {
|
|
14244
|
+
return this.transactor.pushSend(path, name, args, opts, this.parent);
|
|
14312
14245
|
}
|
|
14313
|
-
|
|
14314
|
-
|
|
14315
|
-
if (provide == null)
|
|
14316
|
-
return this;
|
|
14317
|
-
const dynObj = {};
|
|
14318
|
-
let has2 = false;
|
|
14319
|
-
for (const k in provide) {
|
|
14320
|
-
dynObj[provide[k].symbol] = provide[k].val.eval(this);
|
|
14321
|
-
has2 = true;
|
|
14322
|
-
}
|
|
14323
|
-
if (!has2)
|
|
14324
|
-
return this;
|
|
14325
|
-
const newDynBinds = [new ObjectFrame(dynObj), this.dynBinds];
|
|
14326
|
-
const { comps, it, binds, views, viewsId, ctx } = this;
|
|
14327
|
-
return new Stack2(comps, it, binds, newDynBinds, views, viewsId, ctx);
|
|
14246
|
+
request(name, args, opts) {
|
|
14247
|
+
return this.requestAtPath(this.path, name, args, opts);
|
|
14328
14248
|
}
|
|
14329
|
-
|
|
14330
|
-
|
|
14331
|
-
const dynBinds = [new ObjectFrame({}), null];
|
|
14332
|
-
const views = ["main", null];
|
|
14333
|
-
return new Stack2(comps, it, binds, dynBinds, views, "", ctx)._pushProvides();
|
|
14249
|
+
requestAtPath(path, name, args, opts) {
|
|
14250
|
+
return this.transactor.pushRequest(path, name, args, opts, this.parent);
|
|
14334
14251
|
}
|
|
14335
|
-
|
|
14336
|
-
|
|
14337
|
-
const newBinds = [new BindFrame(it, bindings, isFrame), binds];
|
|
14338
|
-
const stack = new Stack2(comps, it, newBinds, dynBinds, views, viewsId, ctx);
|
|
14339
|
-
return isFrame ? stack._pushProvides() : stack;
|
|
14252
|
+
inputAtPath(path, name, args, opts) {
|
|
14253
|
+
return this.transactor.pushInput(path, name, args, opts, this.parent);
|
|
14340
14254
|
}
|
|
14341
|
-
|
|
14342
|
-
|
|
14343
|
-
const newViews = [name, views];
|
|
14344
|
-
return new Stack2(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
|
|
14255
|
+
lookupTypeFor(name, inst) {
|
|
14256
|
+
return this.transactor.comps.getCompFor(inst).scope.lookupComponent(name);
|
|
14345
14257
|
}
|
|
14346
|
-
|
|
14347
|
-
|
|
14348
|
-
|
|
14349
|
-
|
|
14350
|
-
|
|
14258
|
+
}
|
|
14259
|
+
|
|
14260
|
+
class EventContext extends Dispatcher {
|
|
14261
|
+
get name() {
|
|
14262
|
+
return this.parent?.name ?? null;
|
|
14351
14263
|
}
|
|
14352
|
-
|
|
14353
|
-
return
|
|
14264
|
+
get targetPath() {
|
|
14265
|
+
return this.parent.targetPath;
|
|
14354
14266
|
}
|
|
14355
|
-
|
|
14356
|
-
|
|
14357
|
-
return (sym != null ? lookup(this.dynBinds, sym) : null) ?? lk.val?.eval(this) ?? null;
|
|
14267
|
+
stopPropagation() {
|
|
14268
|
+
return this.parent.stopPropagation();
|
|
14358
14269
|
}
|
|
14359
|
-
|
|
14360
|
-
|
|
14361
|
-
|
|
14362
|
-
|
|
14363
|
-
|
|
14364
|
-
|
|
14365
|
-
|
|
14366
|
-
|
|
14367
|
-
|
|
14270
|
+
}
|
|
14271
|
+
|
|
14272
|
+
class RequestContext extends Dispatcher {
|
|
14273
|
+
}
|
|
14274
|
+
|
|
14275
|
+
class PathChanges extends PathBuilder {
|
|
14276
|
+
constructor(dispatcher) {
|
|
14277
|
+
super();
|
|
14278
|
+
this.dispatcher = dispatcher;
|
|
14368
14279
|
}
|
|
14369
|
-
|
|
14370
|
-
return
|
|
14280
|
+
send(name, args, opts) {
|
|
14281
|
+
return this.dispatcher.sendAtPath(this.buildPath(), name, args, opts);
|
|
14371
14282
|
}
|
|
14372
|
-
|
|
14373
|
-
return this.
|
|
14283
|
+
bubble(name, args, opts) {
|
|
14284
|
+
return this.send(name, args, { skipSelf: true, bubbles: true, ...opts });
|
|
14374
14285
|
}
|
|
14375
|
-
|
|
14376
|
-
return this.
|
|
14286
|
+
buildPath() {
|
|
14287
|
+
return this.dispatcher.path.concat(this.pathChanges);
|
|
14377
14288
|
}
|
|
14378
|
-
|
|
14379
|
-
|
|
14380
|
-
|
|
14289
|
+
}
|
|
14290
|
+
function rootDispatcher(transactor) {
|
|
14291
|
+
return new Dispatcher(new Path([]), transactor, null);
|
|
14292
|
+
}
|
|
14293
|
+
|
|
14294
|
+
// tools/core/results.js
|
|
14295
|
+
class ModuleInfo {
|
|
14296
|
+
constructor({ path = null, present = new Set, counts = {}, warnings = [] }) {
|
|
14297
|
+
this.path = path;
|
|
14298
|
+
this.present = present;
|
|
14299
|
+
this.counts = counts;
|
|
14300
|
+
this.warnings = warnings;
|
|
14381
14301
|
}
|
|
14382
|
-
|
|
14383
|
-
|
|
14302
|
+
}
|
|
14303
|
+
|
|
14304
|
+
class ComponentSummary {
|
|
14305
|
+
constructor({ name, views, fields }) {
|
|
14306
|
+
this.name = name;
|
|
14307
|
+
this.views = views;
|
|
14308
|
+
this.fields = fields;
|
|
14384
14309
|
}
|
|
14385
|
-
|
|
14386
|
-
|
|
14310
|
+
}
|
|
14311
|
+
|
|
14312
|
+
class ComponentList {
|
|
14313
|
+
constructor({ items, total = null, truncated = false }) {
|
|
14314
|
+
this.items = items;
|
|
14315
|
+
this.total = total ?? items.length;
|
|
14316
|
+
this.truncated = truncated;
|
|
14387
14317
|
}
|
|
14388
|
-
|
|
14389
|
-
|
|
14318
|
+
}
|
|
14319
|
+
|
|
14320
|
+
class ExampleIndex {
|
|
14321
|
+
constructor({ sections, total = null, truncated = false }) {
|
|
14322
|
+
this.sections = sections;
|
|
14323
|
+
this.total = total ?? sections.reduce((n, s) => n + (s.items?.length ?? 0), 0);
|
|
14324
|
+
this.truncated = truncated;
|
|
14390
14325
|
}
|
|
14391
|
-
|
|
14392
|
-
|
|
14393
|
-
|
|
14394
|
-
|
|
14395
|
-
|
|
14396
|
-
return view;
|
|
14397
|
-
n = n[1];
|
|
14398
|
-
}
|
|
14399
|
-
return views[defaultViewName];
|
|
14326
|
+
}
|
|
14327
|
+
|
|
14328
|
+
class ComponentDocs {
|
|
14329
|
+
constructor({ items }) {
|
|
14330
|
+
this.items = items;
|
|
14400
14331
|
}
|
|
14401
14332
|
}
|
|
14402
14333
|
|
|
14403
|
-
|
|
14404
|
-
|
|
14405
|
-
|
|
14406
|
-
this.
|
|
14407
|
-
this.
|
|
14334
|
+
class LintFinding {
|
|
14335
|
+
constructor({ id, level, info, context = {}, suggestion = null }) {
|
|
14336
|
+
this.id = id;
|
|
14337
|
+
this.level = level;
|
|
14338
|
+
this.info = info;
|
|
14339
|
+
this.context = context;
|
|
14340
|
+
this.suggestion = suggestion;
|
|
14408
14341
|
}
|
|
14409
|
-
|
|
14410
|
-
|
|
14342
|
+
}
|
|
14343
|
+
|
|
14344
|
+
class LintComponentResult {
|
|
14345
|
+
constructor({ componentName, findings }) {
|
|
14346
|
+
this.componentName = componentName;
|
|
14347
|
+
this.findings = findings;
|
|
14411
14348
|
}
|
|
14412
|
-
|
|
14413
|
-
|
|
14414
|
-
this.val = val;
|
|
14415
|
-
for (const sub of this.changeSubs)
|
|
14416
|
-
sub({ val, old, info, timestamp: Date.now() });
|
|
14349
|
+
get errorCount() {
|
|
14350
|
+
return this.findings.filter((f) => f.level === "error").length;
|
|
14417
14351
|
}
|
|
14418
|
-
|
|
14419
|
-
return this.
|
|
14352
|
+
get warnCount() {
|
|
14353
|
+
return this.findings.filter((f) => f.level === "warn").length;
|
|
14420
14354
|
}
|
|
14421
14355
|
}
|
|
14422
14356
|
|
|
14423
|
-
class
|
|
14424
|
-
constructor(
|
|
14425
|
-
this.
|
|
14426
|
-
this.transactions = [];
|
|
14427
|
-
this.state = new State2(rootValue);
|
|
14428
|
-
this.onTransactionPushed = () => {};
|
|
14429
|
-
}
|
|
14430
|
-
pushTransaction(t) {
|
|
14431
|
-
this.transactions.push(t);
|
|
14432
|
-
this.onTransactionPushed(t);
|
|
14433
|
-
}
|
|
14434
|
-
pushSend(path, name, args = [], opts = {}, parent = null) {
|
|
14435
|
-
this.pushTransaction(new SendEvent(path, this, name, args, parent, opts));
|
|
14436
|
-
}
|
|
14437
|
-
pushBubble(path, name, args = [], opts = {}, parent = null, targetPath = null) {
|
|
14438
|
-
const newOpts = opts.skipSelf ? { ...opts, skipSelf: false } : opts;
|
|
14439
|
-
this.pushTransaction(new BubbleEvent(path, this, name, args, parent, newOpts, targetPath));
|
|
14440
|
-
}
|
|
14441
|
-
async pushRequest(path, name, args = [], opts = {}, parent = null) {
|
|
14442
|
-
const curRoot = this.state.val;
|
|
14443
|
-
const txnPath = path.toTransactionPath();
|
|
14444
|
-
const curLeaf = txnPath.lookup(curRoot);
|
|
14445
|
-
const handler = this.comps.getRequestFor(curLeaf, name) ?? mkReq404(name);
|
|
14446
|
-
const reqCtx = new RequestContext(path, this, parent, curRoot);
|
|
14447
|
-
const resHandlerName = opts?.onResName ?? name;
|
|
14448
|
-
const resPath = opts?.livePath ? null : txnPath.pinKeys(curRoot);
|
|
14449
|
-
const push = (specificName, baseName, singleArg, result, error) => {
|
|
14450
|
-
const resArgs = specificName ? [singleArg] : [result, error];
|
|
14451
|
-
const t = new ResponseEvent(path, this, specificName ?? baseName, resArgs, parent, resPath);
|
|
14452
|
-
this.pushTransaction(t);
|
|
14453
|
-
};
|
|
14454
|
-
try {
|
|
14455
|
-
const result = await handler.fn.apply(null, [...args, reqCtx]);
|
|
14456
|
-
push(opts?.onOkName, resHandlerName, result, result, null);
|
|
14457
|
-
} catch (error) {
|
|
14458
|
-
push(opts?.onErrorName, resHandlerName, error, null, error);
|
|
14459
|
-
}
|
|
14460
|
-
}
|
|
14461
|
-
get hasPendingTransactions() {
|
|
14462
|
-
return this.transactions.length > 0;
|
|
14357
|
+
class LintReport {
|
|
14358
|
+
constructor({ components }) {
|
|
14359
|
+
this.components = components;
|
|
14463
14360
|
}
|
|
14464
|
-
|
|
14465
|
-
|
|
14466
|
-
this.transact(this.transactions.shift());
|
|
14361
|
+
get hasErrors() {
|
|
14362
|
+
return this.components.some((c) => c.errorCount > 0);
|
|
14467
14363
|
}
|
|
14468
|
-
|
|
14469
|
-
|
|
14470
|
-
const newState = transaction.run(curState, this.comps);
|
|
14471
|
-
if (newState !== undefined) {
|
|
14472
|
-
this.state.set(newState, { transaction });
|
|
14473
|
-
transaction.afterTransaction();
|
|
14474
|
-
} else
|
|
14475
|
-
console.warn("undefined new state", { curState, transaction });
|
|
14364
|
+
get totalErrors() {
|
|
14365
|
+
return this.components.reduce((n, c) => n + c.errorCount, 0);
|
|
14476
14366
|
}
|
|
14477
|
-
|
|
14478
|
-
this.
|
|
14367
|
+
get totalWarnings() {
|
|
14368
|
+
return this.components.reduce((n, c) => n + c.warnCount, 0);
|
|
14479
14369
|
}
|
|
14480
14370
|
}
|
|
14481
|
-
function mkReq404(name) {
|
|
14482
|
-
const fn = () => {
|
|
14483
|
-
throw new Error(`Request not found: ${name}`);
|
|
14484
|
-
};
|
|
14485
|
-
return { fn };
|
|
14486
|
-
}
|
|
14487
|
-
function nullHandler() {
|
|
14488
|
-
return this;
|
|
14489
|
-
}
|
|
14490
14371
|
|
|
14491
|
-
class
|
|
14492
|
-
constructor(
|
|
14493
|
-
this.
|
|
14494
|
-
this.
|
|
14495
|
-
this.
|
|
14496
|
-
this.
|
|
14497
|
-
|
|
14498
|
-
|
|
14499
|
-
this._task ??= new Task;
|
|
14500
|
-
return this._task;
|
|
14501
|
-
}
|
|
14502
|
-
getCompletionPromise() {
|
|
14503
|
-
return this.task.promise;
|
|
14504
|
-
}
|
|
14505
|
-
setParent(parentTransaction) {
|
|
14506
|
-
this.parentTransaction = parentTransaction;
|
|
14507
|
-
parentTransaction.task.addDep(this.task);
|
|
14508
|
-
}
|
|
14509
|
-
run(rootValue, comps) {
|
|
14510
|
-
return this.updateRootValue(rootValue, comps);
|
|
14511
|
-
}
|
|
14512
|
-
afterTransaction() {}
|
|
14513
|
-
buildRootStack(root, comps) {
|
|
14514
|
-
return Stack2.root(comps, root);
|
|
14515
|
-
}
|
|
14516
|
-
buildStack(root, comps) {
|
|
14517
|
-
return this.path.toTransactionPath().buildStack(this.buildRootStack(root, comps));
|
|
14518
|
-
}
|
|
14519
|
-
callHandler(root, instance, comps) {
|
|
14520
|
-
const [handler, args] = this.getHandlerAndArgs(root, instance, comps);
|
|
14521
|
-
return handler.apply(instance, args);
|
|
14522
|
-
}
|
|
14523
|
-
getHandlerAndArgs(_root, _instance, _comps) {
|
|
14524
|
-
return null;
|
|
14525
|
-
}
|
|
14526
|
-
getTransactionPath() {
|
|
14527
|
-
return this.path.toTransactionPath();
|
|
14528
|
-
}
|
|
14529
|
-
updateRootValue(curRoot, comps) {
|
|
14530
|
-
const txnPath = this.getTransactionPath();
|
|
14531
|
-
const curLeaf = txnPath.lookup(curRoot);
|
|
14532
|
-
const newLeaf = this.callHandler(curRoot, curLeaf, comps);
|
|
14533
|
-
this._task?.complete?.({ value: newLeaf, old: curLeaf });
|
|
14534
|
-
return curLeaf !== newLeaf ? txnPath.setValue(curRoot, newLeaf) : curRoot;
|
|
14535
|
-
}
|
|
14536
|
-
lookupName(_name) {
|
|
14537
|
-
return null;
|
|
14372
|
+
class RenderedExample {
|
|
14373
|
+
constructor({ title, description = null, componentName, view, html, error = null }) {
|
|
14374
|
+
this.title = title;
|
|
14375
|
+
this.description = description;
|
|
14376
|
+
this.componentName = componentName;
|
|
14377
|
+
this.view = view;
|
|
14378
|
+
this.html = html;
|
|
14379
|
+
this.error = error;
|
|
14538
14380
|
}
|
|
14539
14381
|
}
|
|
14540
|
-
var toNullIfNaN = (v) => Number.isNaN(v) ? null : v;
|
|
14541
|
-
function getValue(e) {
|
|
14542
|
-
return e.target.type === "checkbox" ? e.target.checked : (e instanceof CustomEvent ? e.detail : e.target.value) ?? null;
|
|
14543
|
-
}
|
|
14544
14382
|
|
|
14545
|
-
class
|
|
14546
|
-
constructor(
|
|
14547
|
-
|
|
14548
|
-
this.
|
|
14549
|
-
this.
|
|
14550
|
-
this.dragInfo = dragInfo;
|
|
14551
|
-
this._dispatchPath = null;
|
|
14552
|
-
}
|
|
14553
|
-
get dispatchPath() {
|
|
14554
|
-
this._dispatchPath ??= this.path.compact();
|
|
14555
|
-
return this._dispatchPath;
|
|
14556
|
-
}
|
|
14557
|
-
buildRootStack(root, comps) {
|
|
14558
|
-
return Stack2.root(comps, root, this);
|
|
14559
|
-
}
|
|
14560
|
-
getHandlerAndArgs(root, _instance, comps) {
|
|
14561
|
-
const stack = this.buildStack(root, comps);
|
|
14562
|
-
const [handler, args] = this.handler.getHandlerAndArgs(stack, this);
|
|
14563
|
-
const path = this.dispatchPath;
|
|
14564
|
-
let dispatcher;
|
|
14565
|
-
for (let i = 0;i < args.length; i++) {
|
|
14566
|
-
if (args[i]?.toHandlerArg) {
|
|
14567
|
-
dispatcher ??= new Dispatcher(path, this.transactor, this);
|
|
14568
|
-
args[i] = args[i].toHandlerArg(dispatcher);
|
|
14569
|
-
}
|
|
14570
|
-
}
|
|
14571
|
-
args.push(new EventContext(path, this.transactor, this));
|
|
14572
|
-
return [handler, args];
|
|
14573
|
-
}
|
|
14574
|
-
lookupName(name) {
|
|
14575
|
-
const { e } = this;
|
|
14576
|
-
switch (name) {
|
|
14577
|
-
case "value":
|
|
14578
|
-
return getValue(e);
|
|
14579
|
-
case "valueAsInt":
|
|
14580
|
-
return toNullIfNaN(parseInt(getValue(e), 10));
|
|
14581
|
-
case "valueAsFloat":
|
|
14582
|
-
return toNullIfNaN(parseFloat(getValue(e)));
|
|
14583
|
-
case "target":
|
|
14584
|
-
return e.target;
|
|
14585
|
-
case "event":
|
|
14586
|
-
return e;
|
|
14587
|
-
case "isAlt":
|
|
14588
|
-
return e.altKey;
|
|
14589
|
-
case "isShift":
|
|
14590
|
-
return e.shiftKey;
|
|
14591
|
-
case "isCtrl":
|
|
14592
|
-
case "isCmd":
|
|
14593
|
-
return isMac && e.metaKey || e.ctrlKey;
|
|
14594
|
-
case "key":
|
|
14595
|
-
return e.key;
|
|
14596
|
-
case "keyCode":
|
|
14597
|
-
return e.keyCode;
|
|
14598
|
-
case "isUpKey":
|
|
14599
|
-
return e.key === "ArrowUp";
|
|
14600
|
-
case "isDownKey":
|
|
14601
|
-
return e.key === "ArrowDown";
|
|
14602
|
-
case "isSend":
|
|
14603
|
-
return e.key === "Enter";
|
|
14604
|
-
case "isCancel":
|
|
14605
|
-
return e.key === "Escape";
|
|
14606
|
-
case "isTabKey":
|
|
14607
|
-
return e.key === "Tab";
|
|
14608
|
-
case "ctx":
|
|
14609
|
-
return new EventContext(this.dispatchPath, this.transactor, this);
|
|
14610
|
-
case "dragInfo":
|
|
14611
|
-
return this.dragInfo;
|
|
14612
|
-
}
|
|
14613
|
-
return null;
|
|
14383
|
+
class RenderedSection {
|
|
14384
|
+
constructor({ title, description = null, items }) {
|
|
14385
|
+
this.title = title;
|
|
14386
|
+
this.description = description;
|
|
14387
|
+
this.items = items;
|
|
14614
14388
|
}
|
|
14615
14389
|
}
|
|
14616
14390
|
|
|
14617
|
-
class
|
|
14618
|
-
constructor(
|
|
14619
|
-
|
|
14620
|
-
this.name = name;
|
|
14621
|
-
this.args = args;
|
|
14622
|
-
this.opts = opts;
|
|
14623
|
-
this.targetPath = path;
|
|
14624
|
-
}
|
|
14625
|
-
handlerProp = null;
|
|
14626
|
-
getHandlerForName(comp) {
|
|
14627
|
-
const handlers = comp?.[this.handlerProp];
|
|
14628
|
-
return handlers?.[this.name] ?? handlers?.$unknown ?? nullHandler;
|
|
14391
|
+
class RenderBatch {
|
|
14392
|
+
constructor({ sections }) {
|
|
14393
|
+
this.sections = sections;
|
|
14629
14394
|
}
|
|
14630
|
-
|
|
14631
|
-
|
|
14632
|
-
return [handler, [...this.args, new EventContext(this.path, this.transactor, this)]];
|
|
14395
|
+
get hasErrors() {
|
|
14396
|
+
return this.sections.some((s) => s.items.some((i) => i.error !== null));
|
|
14633
14397
|
}
|
|
14634
14398
|
}
|
|
14635
14399
|
|
|
14636
|
-
class
|
|
14637
|
-
|
|
14638
|
-
|
|
14639
|
-
|
|
14640
|
-
this.
|
|
14641
|
-
|
|
14642
|
-
|
|
14643
|
-
|
|
14400
|
+
class TestResult {
|
|
14401
|
+
constructor({ title, fullPath, componentName = null, status, durationMs = 0, error = null }) {
|
|
14402
|
+
this.title = title;
|
|
14403
|
+
this.fullPath = fullPath;
|
|
14404
|
+
this.componentName = componentName;
|
|
14405
|
+
this.status = status;
|
|
14406
|
+
this.durationMs = durationMs;
|
|
14407
|
+
this.error = error;
|
|
14644
14408
|
}
|
|
14645
14409
|
}
|
|
14646
14410
|
|
|
14647
|
-
class
|
|
14648
|
-
|
|
14649
|
-
|
|
14650
|
-
|
|
14651
|
-
|
|
14652
|
-
afterTransaction() {
|
|
14653
|
-
const { path, name, args, opts, targetPath } = this;
|
|
14654
|
-
if (opts.bubbles && path.steps.length > 0)
|
|
14655
|
-
this.transactor.pushBubble(path.popStep(), name, args, opts, this, targetPath);
|
|
14411
|
+
class DescribeResult {
|
|
14412
|
+
constructor({ title, componentName = null, children = [] }) {
|
|
14413
|
+
this.title = title;
|
|
14414
|
+
this.componentName = componentName;
|
|
14415
|
+
this.children = children;
|
|
14656
14416
|
}
|
|
14657
14417
|
}
|
|
14658
14418
|
|
|
14659
|
-
class
|
|
14660
|
-
|
|
14661
|
-
|
|
14662
|
-
|
|
14663
|
-
this.
|
|
14664
|
-
}
|
|
14665
|
-
stopPropagation() {
|
|
14666
|
-
this.opts.bubbles = false;
|
|
14419
|
+
class ModuleTestReport {
|
|
14420
|
+
constructor({ path = null, suites = [], counts = { pass: 0, fail: 0, skip: 0, total: 0 } }) {
|
|
14421
|
+
this.path = path;
|
|
14422
|
+
this.suites = suites;
|
|
14423
|
+
this.counts = counts;
|
|
14667
14424
|
}
|
|
14668
14425
|
}
|
|
14669
14426
|
|
|
14670
|
-
class
|
|
14671
|
-
constructor() {
|
|
14672
|
-
this.
|
|
14673
|
-
this.val = this.resolve = this.reject = null;
|
|
14674
|
-
this.promise = new Promise((res, rej) => {
|
|
14675
|
-
this.resolve = res;
|
|
14676
|
-
this.reject = rej;
|
|
14677
|
-
});
|
|
14678
|
-
this.isCompleted = false;
|
|
14427
|
+
class TestReport {
|
|
14428
|
+
constructor({ modules = [] }) {
|
|
14429
|
+
this.modules = modules;
|
|
14679
14430
|
}
|
|
14680
|
-
|
|
14681
|
-
|
|
14682
|
-
|
|
14683
|
-
|
|
14431
|
+
get totals() {
|
|
14432
|
+
return this.modules.reduce((acc, m) => ({
|
|
14433
|
+
pass: acc.pass + m.counts.pass,
|
|
14434
|
+
fail: acc.fail + m.counts.fail,
|
|
14435
|
+
skip: acc.skip + m.counts.skip,
|
|
14436
|
+
total: acc.total + m.counts.total
|
|
14437
|
+
}), { pass: 0, fail: 0, skip: 0, total: 0 });
|
|
14684
14438
|
}
|
|
14685
|
-
|
|
14686
|
-
this.
|
|
14687
|
-
this._check();
|
|
14439
|
+
get hasFailures() {
|
|
14440
|
+
return this.modules.some((m) => m.counts.fail > 0);
|
|
14688
14441
|
}
|
|
14689
|
-
|
|
14690
|
-
|
|
14691
|
-
|
|
14692
|
-
|
|
14693
|
-
|
|
14442
|
+
}
|
|
14443
|
+
|
|
14444
|
+
// tools/core/tests.js
|
|
14445
|
+
class Describe {
|
|
14446
|
+
constructor({ title, componentName = null, parent = null }) {
|
|
14447
|
+
this.title = title;
|
|
14448
|
+
this.componentName = componentName;
|
|
14449
|
+
this.parent = parent;
|
|
14450
|
+
this.children = [];
|
|
14694
14451
|
}
|
|
14695
14452
|
}
|
|
14696
14453
|
|
|
14697
|
-
class
|
|
14698
|
-
constructor(
|
|
14699
|
-
this.
|
|
14700
|
-
this.
|
|
14701
|
-
this.
|
|
14702
|
-
this.
|
|
14703
|
-
}
|
|
14704
|
-
walkPath(callback) {
|
|
14705
|
-
const comps = this.transactor.comps;
|
|
14706
|
-
const chain = this.path.toTransactionPath().resolveChain(this.root);
|
|
14707
|
-
for (let i = chain.length - 1;i >= 0; i--) {
|
|
14708
|
-
const comp = comps.getCompFor(chain[i]);
|
|
14709
|
-
if (comp && callback(comp, chain[i]) === false)
|
|
14710
|
-
return;
|
|
14711
|
-
}
|
|
14712
|
-
}
|
|
14713
|
-
get at() {
|
|
14714
|
-
return new PathChanges(this);
|
|
14715
|
-
}
|
|
14716
|
-
send(name, args, opts) {
|
|
14717
|
-
return this.sendAtPath(this.path, name, args, opts);
|
|
14454
|
+
class Test {
|
|
14455
|
+
constructor({ title, fn, componentName = null, parent = null }) {
|
|
14456
|
+
this.title = title;
|
|
14457
|
+
this.fn = fn;
|
|
14458
|
+
this.componentName = componentName;
|
|
14459
|
+
this.parent = parent;
|
|
14718
14460
|
}
|
|
14719
|
-
|
|
14720
|
-
|
|
14461
|
+
}
|
|
14462
|
+
|
|
14463
|
+
class ModuleTests {
|
|
14464
|
+
constructor({ path = null, suites = [] } = {}) {
|
|
14465
|
+
this.path = path;
|
|
14466
|
+
this.suites = suites;
|
|
14721
14467
|
}
|
|
14722
|
-
|
|
14723
|
-
|
|
14468
|
+
}
|
|
14469
|
+
|
|
14470
|
+
class TestIndex {
|
|
14471
|
+
constructor({ modules = [] } = {}) {
|
|
14472
|
+
this.modules = modules;
|
|
14724
14473
|
}
|
|
14725
|
-
|
|
14726
|
-
|
|
14474
|
+
}
|
|
14475
|
+
function isComponentObject(x) {
|
|
14476
|
+
return x !== null && typeof x === "object" && typeof x.name === "string" && typeof x.Class === "function";
|
|
14477
|
+
}
|
|
14478
|
+
function resolveComponentName(arg, components) {
|
|
14479
|
+
if (isComponentObject(arg))
|
|
14480
|
+
return arg.name;
|
|
14481
|
+
if (typeof arg === "function") {
|
|
14482
|
+
for (const c of components)
|
|
14483
|
+
if (c.Class === arg)
|
|
14484
|
+
return c.name;
|
|
14727
14485
|
}
|
|
14728
|
-
|
|
14729
|
-
|
|
14486
|
+
return null;
|
|
14487
|
+
}
|
|
14488
|
+
function titleFromArg(arg) {
|
|
14489
|
+
if (typeof arg === "string")
|
|
14490
|
+
return arg;
|
|
14491
|
+
if (isComponentObject(arg))
|
|
14492
|
+
return arg.name;
|
|
14493
|
+
if (typeof arg === "function")
|
|
14494
|
+
return arg.name || "(anonymous)";
|
|
14495
|
+
return String(arg);
|
|
14496
|
+
}
|
|
14497
|
+
function makeCollector({ path = null, components = [] } = {}) {
|
|
14498
|
+
const moduleTests = new ModuleTests({ path, suites: [] });
|
|
14499
|
+
const stack = [];
|
|
14500
|
+
function describe(...args) {
|
|
14501
|
+
let head;
|
|
14502
|
+
let options = null;
|
|
14503
|
+
let fn;
|
|
14504
|
+
if (args.length === 2) {
|
|
14505
|
+
[head, fn] = args;
|
|
14506
|
+
} else if (args.length === 3) {
|
|
14507
|
+
[head, options, fn] = args;
|
|
14508
|
+
} else {
|
|
14509
|
+
throw new Error(`describe() expects 2 or 3 arguments, got ${args.length}`);
|
|
14510
|
+
}
|
|
14511
|
+
if (typeof fn !== "function") {
|
|
14512
|
+
throw new Error(`describe(${JSON.stringify(titleFromArg(head))}): final argument must be a function`);
|
|
14513
|
+
}
|
|
14514
|
+
let componentName = null;
|
|
14515
|
+
if (typeof head !== "string") {
|
|
14516
|
+
componentName = resolveComponentName(head, components);
|
|
14517
|
+
}
|
|
14518
|
+
if (componentName === null && options && options.component != null) {
|
|
14519
|
+
componentName = resolveComponentName(options.component, components);
|
|
14520
|
+
}
|
|
14521
|
+
if (componentName === null) {
|
|
14522
|
+
const parent2 = stack.length ? stack[stack.length - 1] : null;
|
|
14523
|
+
if (parent2)
|
|
14524
|
+
componentName = parent2.componentName;
|
|
14525
|
+
}
|
|
14526
|
+
const parent = stack.length ? stack[stack.length - 1] : null;
|
|
14527
|
+
const node = new Describe({
|
|
14528
|
+
title: titleFromArg(head),
|
|
14529
|
+
componentName,
|
|
14530
|
+
parent
|
|
14531
|
+
});
|
|
14532
|
+
if (parent)
|
|
14533
|
+
parent.children.push(node);
|
|
14534
|
+
else
|
|
14535
|
+
moduleTests.suites.push(node);
|
|
14536
|
+
stack.push(node);
|
|
14537
|
+
try {
|
|
14538
|
+
fn();
|
|
14539
|
+
} finally {
|
|
14540
|
+
stack.pop();
|
|
14541
|
+
}
|
|
14730
14542
|
}
|
|
14731
|
-
|
|
14732
|
-
|
|
14543
|
+
function test2(title, fn) {
|
|
14544
|
+
if (typeof title !== "string") {
|
|
14545
|
+
throw new Error("test(title, fn): title must be a string");
|
|
14546
|
+
}
|
|
14547
|
+
if (typeof fn !== "function") {
|
|
14548
|
+
throw new Error(`test(${JSON.stringify(title)}): fn must be a function`);
|
|
14549
|
+
}
|
|
14550
|
+
const parent = stack.length ? stack[stack.length - 1] : null;
|
|
14551
|
+
if (!parent) {
|
|
14552
|
+
throw new Error(`test(${JSON.stringify(title)}) must be called inside a describe()`);
|
|
14553
|
+
}
|
|
14554
|
+
parent.children.push(new Test({
|
|
14555
|
+
title,
|
|
14556
|
+
fn,
|
|
14557
|
+
componentName: parent.componentName,
|
|
14558
|
+
parent
|
|
14559
|
+
}));
|
|
14733
14560
|
}
|
|
14561
|
+
return { describe, test: test2, moduleTests };
|
|
14734
14562
|
}
|
|
14735
14563
|
|
|
14736
|
-
|
|
14737
|
-
|
|
14738
|
-
|
|
14739
|
-
|
|
14740
|
-
|
|
14741
|
-
|
|
14742
|
-
|
|
14743
|
-
stopPropagation() {
|
|
14744
|
-
return this.parent.stopPropagation();
|
|
14564
|
+
// tools/core/test.js
|
|
14565
|
+
function buildPath(node) {
|
|
14566
|
+
const parts = [];
|
|
14567
|
+
let cur = node;
|
|
14568
|
+
while (cur) {
|
|
14569
|
+
parts.unshift(cur.title);
|
|
14570
|
+
cur = cur.parent;
|
|
14745
14571
|
}
|
|
14572
|
+
return parts.join(" > ");
|
|
14746
14573
|
}
|
|
14747
|
-
|
|
14748
|
-
|
|
14574
|
+
function captureError(e) {
|
|
14575
|
+
const out = { message: e.message, stack: e.stack };
|
|
14576
|
+
if ("expected" in e)
|
|
14577
|
+
out.expected = e.expected;
|
|
14578
|
+
if ("actual" in e)
|
|
14579
|
+
out.actual = e.actual;
|
|
14580
|
+
return out;
|
|
14749
14581
|
}
|
|
14750
|
-
|
|
14751
|
-
|
|
14752
|
-
|
|
14753
|
-
|
|
14754
|
-
|
|
14582
|
+
async function runTests({
|
|
14583
|
+
getTests,
|
|
14584
|
+
components = [],
|
|
14585
|
+
path = null,
|
|
14586
|
+
expect: expect2,
|
|
14587
|
+
name = null,
|
|
14588
|
+
grep = null,
|
|
14589
|
+
bail = false,
|
|
14590
|
+
requestHandlers = null,
|
|
14591
|
+
macros = null
|
|
14592
|
+
} = {}) {
|
|
14593
|
+
const counts = { pass: 0, fail: 0, skip: 0, total: 0 };
|
|
14594
|
+
if (typeof getTests !== "function") {
|
|
14595
|
+
return new TestReport({
|
|
14596
|
+
modules: [new ModuleTestReport({ path, suites: [], counts })]
|
|
14597
|
+
});
|
|
14755
14598
|
}
|
|
14756
|
-
|
|
14757
|
-
|
|
14599
|
+
if (typeof expect2 !== "function") {
|
|
14600
|
+
throw new Error("runTests: expect must be provided (e.g. chai's expect)");
|
|
14758
14601
|
}
|
|
14759
|
-
|
|
14760
|
-
|
|
14602
|
+
const { describe, test: test2, moduleTests } = makeCollector({ path, components });
|
|
14603
|
+
await getTests({ describe, test: test2, expect: expect2, drive });
|
|
14604
|
+
let _stack = null;
|
|
14605
|
+
function getStack() {
|
|
14606
|
+
if (_stack)
|
|
14607
|
+
return _stack;
|
|
14608
|
+
_stack = new ComponentStack;
|
|
14609
|
+
_stack.registerComponents(components);
|
|
14610
|
+
if (macros)
|
|
14611
|
+
_stack.registerMacros(macros);
|
|
14612
|
+
if (requestHandlers)
|
|
14613
|
+
_stack.registerRequestHandlers(requestHandlers);
|
|
14614
|
+
return _stack;
|
|
14615
|
+
}
|
|
14616
|
+
async function drive(value, phase, opts = {}) {
|
|
14617
|
+
const transactor = new Transactor(getStack().comps, value);
|
|
14618
|
+
if (opts.onMessage)
|
|
14619
|
+
transactor.state.onChange(({ val, old, info }) => {
|
|
14620
|
+
const t = info?.transaction;
|
|
14621
|
+
opts.onMessage({ kind: t?.handlerProp ?? "input", name: t?.name, args: t?.args, path: t?.path }, old, val);
|
|
14622
|
+
});
|
|
14623
|
+
dispatchPhase(rootDispatcher(transactor), new Path([]), phase, value);
|
|
14624
|
+
await transactor.settle();
|
|
14625
|
+
return transactor.state.val;
|
|
14761
14626
|
}
|
|
14762
|
-
|
|
14763
|
-
|
|
14627
|
+
let bailed = false;
|
|
14628
|
+
async function visit(node) {
|
|
14629
|
+
if (node instanceof Test) {
|
|
14630
|
+
if (name !== null && node.componentName !== name)
|
|
14631
|
+
return null;
|
|
14632
|
+
const fullPath = buildPath(node);
|
|
14633
|
+
if (grep !== null && !fullPath.includes(grep))
|
|
14634
|
+
return null;
|
|
14635
|
+
counts.total++;
|
|
14636
|
+
if (bailed) {
|
|
14637
|
+
counts.skip++;
|
|
14638
|
+
return new TestResult({
|
|
14639
|
+
title: node.title,
|
|
14640
|
+
fullPath,
|
|
14641
|
+
componentName: node.componentName,
|
|
14642
|
+
status: "skip"
|
|
14643
|
+
});
|
|
14644
|
+
}
|
|
14645
|
+
const start = performance.now();
|
|
14646
|
+
try {
|
|
14647
|
+
await node.fn();
|
|
14648
|
+
counts.pass++;
|
|
14649
|
+
return new TestResult({
|
|
14650
|
+
title: node.title,
|
|
14651
|
+
fullPath,
|
|
14652
|
+
componentName: node.componentName,
|
|
14653
|
+
status: "pass",
|
|
14654
|
+
durationMs: performance.now() - start
|
|
14655
|
+
});
|
|
14656
|
+
} catch (e) {
|
|
14657
|
+
counts.fail++;
|
|
14658
|
+
if (bail)
|
|
14659
|
+
bailed = true;
|
|
14660
|
+
return new TestResult({
|
|
14661
|
+
title: node.title,
|
|
14662
|
+
fullPath,
|
|
14663
|
+
componentName: node.componentName,
|
|
14664
|
+
status: "fail",
|
|
14665
|
+
durationMs: performance.now() - start,
|
|
14666
|
+
error: captureError(e)
|
|
14667
|
+
});
|
|
14668
|
+
}
|
|
14669
|
+
}
|
|
14670
|
+
const childResults = [];
|
|
14671
|
+
for (const child of node.children) {
|
|
14672
|
+
const r = await visit(child);
|
|
14673
|
+
if (r !== null)
|
|
14674
|
+
childResults.push(r);
|
|
14675
|
+
}
|
|
14676
|
+
if (childResults.length === 0)
|
|
14677
|
+
return null;
|
|
14678
|
+
return new DescribeResult({
|
|
14679
|
+
title: node.title,
|
|
14680
|
+
componentName: node.componentName,
|
|
14681
|
+
children: childResults
|
|
14682
|
+
});
|
|
14683
|
+
}
|
|
14684
|
+
const suiteResults = [];
|
|
14685
|
+
for (const suite of moduleTests.suites) {
|
|
14686
|
+
const r = await visit(suite);
|
|
14687
|
+
if (r !== null)
|
|
14688
|
+
suiteResults.push(r);
|
|
14689
|
+
}
|
|
14690
|
+
return new TestReport({
|
|
14691
|
+
modules: [new ModuleTestReport({ path, suites: suiteResults, counts })]
|
|
14692
|
+
});
|
|
14693
|
+
}
|
|
14694
|
+
|
|
14695
|
+
// tools/core/test-console.js
|
|
14696
|
+
var PASS = "color: #0a0; font-weight: bold";
|
|
14697
|
+
var FAIL = "color: #c00; font-weight: bold";
|
|
14698
|
+
var SKIP = "color: #888";
|
|
14699
|
+
var DIM = "color: #888";
|
|
14700
|
+
var RESET = "color: inherit; font-weight: normal";
|
|
14701
|
+
function reportTestNode(node) {
|
|
14702
|
+
if (node.children) {
|
|
14703
|
+
const label = node.componentName ? `${node.title} [${node.componentName}]` : node.title;
|
|
14704
|
+
console.group(label);
|
|
14705
|
+
for (const child of node.children)
|
|
14706
|
+
reportTestNode(child);
|
|
14707
|
+
console.groupEnd();
|
|
14708
|
+
return;
|
|
14709
|
+
}
|
|
14710
|
+
const dur = node.status === "skip" ? "" : ` (${Math.round(node.durationMs)}ms)`;
|
|
14711
|
+
if (node.status === "pass") {
|
|
14712
|
+
console.log(`%c✓%c ${node.title}%c${dur}`, PASS, RESET, DIM);
|
|
14713
|
+
} else if (node.status === "skip") {
|
|
14714
|
+
console.log(`%c○ ${node.title}%c (skipped)`, SKIP, RESET);
|
|
14715
|
+
} else {
|
|
14716
|
+
console.group(`%c✗%c ${node.title}%c${dur}`, FAIL, RESET, DIM);
|
|
14717
|
+
console.error(node.error?.message ?? "(no error message)");
|
|
14718
|
+
if (node.error && (("expected" in node.error) || ("actual" in node.error))) {
|
|
14719
|
+
console.log("expected:", node.error.expected);
|
|
14720
|
+
console.log("actual: ", node.error.actual);
|
|
14721
|
+
}
|
|
14722
|
+
if (node.error?.stack)
|
|
14723
|
+
console.log(node.error.stack);
|
|
14724
|
+
console.groupEnd();
|
|
14725
|
+
}
|
|
14726
|
+
}
|
|
14727
|
+
function reportTestReportToConsole(report) {
|
|
14728
|
+
for (const m of report.modules) {
|
|
14729
|
+
const label = `tutuca tests${m.path ? ` — ${m.path}` : ""}`;
|
|
14730
|
+
console.group(label);
|
|
14731
|
+
if (m.suites.length === 0) {
|
|
14732
|
+
console.log("(no tests)");
|
|
14733
|
+
} else {
|
|
14734
|
+
for (const s of m.suites)
|
|
14735
|
+
reportTestNode(s);
|
|
14736
|
+
}
|
|
14737
|
+
const c = m.counts;
|
|
14738
|
+
const summary = `${c.pass} passed, ${c.fail} failed, ${c.skip} skipped (${c.total} total)`;
|
|
14739
|
+
if (c.fail > 0)
|
|
14740
|
+
console.error(`%c${summary}`, FAIL);
|
|
14741
|
+
else if (c.total === 0)
|
|
14742
|
+
console.log(`%c${summary}`, DIM);
|
|
14743
|
+
else
|
|
14744
|
+
console.log(`%c${summary}`, PASS);
|
|
14745
|
+
console.groupEnd();
|
|
14746
|
+
}
|
|
14747
|
+
return report;
|
|
14748
|
+
}
|
|
14749
|
+
|
|
14750
|
+
// tools/format/lint.js
|
|
14751
|
+
var UNSUPPORTED_EXPR_LABEL = {
|
|
14752
|
+
ternary: "ternary expression",
|
|
14753
|
+
comparison: "comparison",
|
|
14754
|
+
logical: "logical expression",
|
|
14755
|
+
"call-with-args": "method call with arguments"
|
|
14756
|
+
};
|
|
14757
|
+
function unsupportedExprMessage(info) {
|
|
14758
|
+
const v = JSON.stringify(info.value);
|
|
14759
|
+
const label = UNSUPPORTED_EXPR_LABEL[info.detected] ?? "expression";
|
|
14760
|
+
switch (info.role) {
|
|
14761
|
+
case "attr":
|
|
14762
|
+
return `Unsupported ${label} ${v} in dynamic attribute ':${info.attr}'`;
|
|
14763
|
+
case "directive":
|
|
14764
|
+
return `Unsupported ${label} ${v} in directive '@${info.directive}'`;
|
|
14765
|
+
case "if":
|
|
14766
|
+
return `Unsupported ${label} ${v} in '@if.${info.attr}' condition`;
|
|
14767
|
+
case "x-op":
|
|
14768
|
+
return `Unsupported ${label} ${v} in <x ${info.op}>`;
|
|
14769
|
+
default:
|
|
14770
|
+
return `Unsupported ${label} ${v}`;
|
|
14771
|
+
}
|
|
14772
|
+
}
|
|
14773
|
+
function badValueMessage(info) {
|
|
14774
|
+
const v = JSON.stringify(info.value);
|
|
14775
|
+
switch (info.role) {
|
|
14776
|
+
case "attr":
|
|
14777
|
+
return `Cannot parse value ${v} for attribute ':${info.attr}'`;
|
|
14778
|
+
case "directive":
|
|
14779
|
+
return `Cannot parse value ${v} for directive '@${info.directive}'`;
|
|
14780
|
+
case "if":
|
|
14781
|
+
return `Cannot parse condition ${v} for '@if.${info.attr}'`;
|
|
14782
|
+
case "x-op":
|
|
14783
|
+
return `Cannot parse value ${v} for <x ${info.op}>`;
|
|
14784
|
+
case "handler-name":
|
|
14785
|
+
return `Cannot parse handler name ${v}`;
|
|
14786
|
+
case "handler-arg":
|
|
14787
|
+
return `Cannot parse handler argument ${v}`;
|
|
14788
|
+
case "macro-var":
|
|
14789
|
+
return `Macro variable '^${info.name}' is not defined`;
|
|
14790
|
+
default:
|
|
14791
|
+
return `Cannot parse value ${v}`;
|
|
14792
|
+
}
|
|
14793
|
+
}
|
|
14794
|
+
function tagDisplay(tag) {
|
|
14795
|
+
return tag ? String(tag).toLowerCase() : null;
|
|
14796
|
+
}
|
|
14797
|
+
function fmtTagSuffix(info) {
|
|
14798
|
+
const t = tagDisplay(info?.tag);
|
|
14799
|
+
return t && t !== "x" ? ` on <${t}>` : "";
|
|
14800
|
+
}
|
|
14801
|
+
function fmtOriginSuffix(info) {
|
|
14802
|
+
if (!info)
|
|
14803
|
+
return "";
|
|
14804
|
+
const parts = [];
|
|
14805
|
+
if (info.originAttr) {
|
|
14806
|
+
const branch = info.branch ? `[${info.branch}]` : "";
|
|
14807
|
+
parts.push(`in ${info.originAttr}${branch}`);
|
|
14808
|
+
}
|
|
14809
|
+
if (info.handlerName) {
|
|
14810
|
+
parts.push(`handler '${info.handlerName}'${info.argIndex !== undefined ? ` arg ${info.argIndex}` : ""}`);
|
|
14811
|
+
}
|
|
14812
|
+
const t = tagDisplay(info.tag);
|
|
14813
|
+
if (t && t !== "x")
|
|
14814
|
+
parts.push(`on <${t}>`);
|
|
14815
|
+
return parts.length ? ` (${parts.join(", ")})` : "";
|
|
14816
|
+
}
|
|
14817
|
+
function fmtEventSuffix(info) {
|
|
14818
|
+
if (info?.originAttr)
|
|
14819
|
+
return ` in ${info.originAttr}`;
|
|
14820
|
+
if (info?.eventName)
|
|
14821
|
+
return ` in @on.${info.eventName}`;
|
|
14822
|
+
return "";
|
|
14823
|
+
}
|
|
14824
|
+
function lintIdToMessage(id, info) {
|
|
14825
|
+
switch (id) {
|
|
14826
|
+
case "RENDER_IT_OUTSIDE_OF_LOOP":
|
|
14827
|
+
return "<x render-it> used outside of a loop";
|
|
14828
|
+
case "UNKNOWN_EVENT_MODIFIER": {
|
|
14829
|
+
const mods = info.handler?.modifiers ?? [info.modifier];
|
|
14830
|
+
const written = `@on.${info.name}+${mods.join("+")}`;
|
|
14831
|
+
return `Unknown modifier '+${info.modifier}' in '${written}'`;
|
|
14832
|
+
}
|
|
14833
|
+
case "UNKNOWN_HANDLER_ARG_NAME":
|
|
14834
|
+
return `Unknown handler argument '${info.name}'${fmtOriginSuffix(info)}`;
|
|
14835
|
+
case "INPUT_HANDLER_NOT_IMPLEMENTED":
|
|
14836
|
+
return `Input handler '${info.name}' is not implemented${fmtEventSuffix(info)}`;
|
|
14837
|
+
case "INPUT_HANDLER_NOT_REFERENCED":
|
|
14838
|
+
return `Input handler '${info.name}' is defined but never used — remove it or wire it to an @on.* event`;
|
|
14839
|
+
case "INPUT_HANDLER_METHOD_NOT_IMPLEMENTED":
|
|
14840
|
+
return `Method '$${info.name}' is not implemented${fmtEventSuffix(info)}`;
|
|
14841
|
+
case "INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD":
|
|
14842
|
+
return `'$${info.name}' is a method reference, but '${info.name}' is defined as an input handler${fmtEventSuffix(info)}`;
|
|
14843
|
+
case "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER":
|
|
14844
|
+
return `'${info.name}' is an input handler reference, but '${info.name}' is defined as a method${fmtEventSuffix(info)}`;
|
|
14845
|
+
case "FIELD_VAL_NOT_DEFINED":
|
|
14846
|
+
return `Field '.${info.name}' is not defined${fmtOriginSuffix(info)}`;
|
|
14847
|
+
case "FIELD_VAL_IS_METHOD":
|
|
14848
|
+
return `'.${info.name}' reads a field, but '${info.name}' is defined as a method — use '$${info.name}'${fmtOriginSuffix(info)}`;
|
|
14849
|
+
case "METHOD_VAL_NOT_DEFINED":
|
|
14850
|
+
return `Method '$${info.name}' is not defined${fmtOriginSuffix(info)}`;
|
|
14851
|
+
case "METHOD_VAL_IS_FIELD":
|
|
14852
|
+
return `'$${info.name}' calls a method, but '${info.name}' is defined as a field — use '.${info.name}'${fmtOriginSuffix(info)}`;
|
|
14853
|
+
case "DUPLICATE_ATTR_DEFINITION": {
|
|
14854
|
+
const sources = info.sources?.length ? ` (${info.sources.join(", ")})` : "";
|
|
14855
|
+
const tag = info.tag ? ` on <${String(info.tag).toLowerCase()}>` : "";
|
|
14856
|
+
return `Attribute '${info.name}' is set ${info.sources?.length ?? "multiple"} times${sources}${tag}`;
|
|
14857
|
+
}
|
|
14858
|
+
case "IF_NO_BRANCH_SET":
|
|
14859
|
+
return `'@if.${info.attr}' has no '@then' or '@else' branch — add '@then="…"' or '@else="…"' (or both)${fmtTagSuffix(info)}`;
|
|
14860
|
+
case "UNKNOWN_REQUEST_NAME":
|
|
14861
|
+
return `Unknown request '!${info.name}'${fmtOriginSuffix(info)}`;
|
|
14862
|
+
case "UNKNOWN_COMPONENT_NAME":
|
|
14863
|
+
return `Unknown component '${info.name}'${fmtOriginSuffix(info)}`;
|
|
14864
|
+
case "ALT_HANDLER_NOT_DEFINED":
|
|
14865
|
+
return `Alter handler '${info.name}' is not defined${fmtOriginSuffix(info)}`;
|
|
14866
|
+
case "ALT_HANDLER_NOT_REFERENCED":
|
|
14867
|
+
return `Alter handler '${info.name}' is defined but never used — remove it or reference it from @when, @enrich-with, or @loop-with`;
|
|
14868
|
+
case "DYN_VAL_NOT_DEFINED":
|
|
14869
|
+
return `Dynamic variable '*${info.name}' is not defined${fmtOriginSuffix(info)}`;
|
|
14870
|
+
case "DYN_ALIAS_NOT_REFERENCED":
|
|
14871
|
+
return `Lookup '${info.name}' is defined but never used — remove it or reference it as '*${info.name}' in a view`;
|
|
14872
|
+
case "PROVIDE_NOT_ADDRESSABLE":
|
|
14873
|
+
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`;
|
|
14874
|
+
case "LOOKUP_BAD_SHAPE":
|
|
14875
|
+
return `Lookup '${info.name}' has an invalid shape: ${info.problem}`;
|
|
14876
|
+
case "LOOKUP_TARGET_MALFORMED":
|
|
14877
|
+
return `Lookup '${info.name}' target '${info.target}' must be 'Producer.provideName' (a string, or the 'for' of { for, default })`;
|
|
14878
|
+
case "UNKNOWN_MACRO_ARG":
|
|
14879
|
+
return `Argument '${info.name}' is not declared in macro '${info.macroName}'`;
|
|
14880
|
+
case "UNKNOWN_DIRECTIVE":
|
|
14881
|
+
return `Unknown directive '@${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
|
|
14882
|
+
case "UNKNOWN_X_OP":
|
|
14883
|
+
return `Unknown <x> op '${info.name}=${JSON.stringify(info.value)}'${fmtTagSuffix(info)}`;
|
|
14884
|
+
case "UNKNOWN_X_ATTR":
|
|
14885
|
+
return `Unknown attribute '${info.name}=${JSON.stringify(info.value)}' on <x ${info.op}>${fmtTagSuffix(info)}`;
|
|
14886
|
+
case "MAYBE_DROP_AT_PREFIX": {
|
|
14887
|
+
const written = info.value !== undefined ? `${info.name}=${JSON.stringify(info.value)}` : info.name;
|
|
14888
|
+
return `'${written}' on <x> looks like a directive but is actually an x op/attr written with a leading '@'`;
|
|
14889
|
+
}
|
|
14890
|
+
case "MAYBE_ADD_AT_PREFIX":
|
|
14891
|
+
return `'${info.name}' on <${(info.tag ?? "").toLowerCase()}> is a plain attribute, but '@${info.name}' is a directive — add the leading '@'`;
|
|
14892
|
+
case "BAD_VALUE":
|
|
14893
|
+
return `${badValueMessage(info)}${fmtTagSuffix(info)}`;
|
|
14894
|
+
case "UNSUPPORTED_EXPR_SYNTAX":
|
|
14895
|
+
return `${unsupportedExprMessage(info)}${fmtTagSuffix(info)}`;
|
|
14896
|
+
case "REDUNDANT_TEMPLATE_STRING":
|
|
14897
|
+
return `Redundant template string — '{${info.simpler}}' should be just '${info.simpler}'${fmtOriginSuffix(info)}`;
|
|
14898
|
+
case "PLACEHOLDERLESS_TEMPLATE_STRING":
|
|
14899
|
+
return `Template string has no dynamic parts — use the string literal ${info.literal} instead${fmtOriginSuffix(info)}`;
|
|
14900
|
+
case "UNKNOWN_COMPONENT_SPEC_KEY":
|
|
14901
|
+
return `Unknown component spec key '${info.key}' — value will be ignored at runtime`;
|
|
14902
|
+
case "COMP_FIELD_BAD_SHAPE":
|
|
14903
|
+
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}`;
|
|
14904
|
+
case "HTML_TAG_NAME_HAS_UPPERCASE":
|
|
14905
|
+
return `Tag <${info.raw}> will be lowercased to <${info.lowercased}>${fmtLocationSuffix(info)}`;
|
|
14906
|
+
case "HTML_SVG_TAG_WILL_LOWERCASE":
|
|
14907
|
+
return `SVG tag <${info.raw}> is not in the WHATWG case-correction list — will be lowercased to <${info.lowercased}>${fmtLocationSuffix(info)}`;
|
|
14908
|
+
case "HTML_TAG_NOT_ALLOWED_IN_PARENT":
|
|
14909
|
+
return `<${info.tag}> not allowed under <${info.parent ?? "?"}> in ${info.mode} — ${htmlActionPhrase(info.action, info.tag, info.parent)}${fmtLocationSuffix(info)}`;
|
|
14910
|
+
case "HTML_TEXT_NOT_ALLOWED_IN_PARENT":
|
|
14911
|
+
return `Non-whitespace text not allowed in ${info.mode}: ${JSON.stringify(info.snippet)}${fmtLocationSuffix(info)}`;
|
|
14912
|
+
case "HTML_VOID_ELEMENT_HAS_CLOSE_TAG":
|
|
14913
|
+
return `Void element <${info.tag}> has an explicit close tag${fmtLocationSuffix(info)}`;
|
|
14914
|
+
case "HTML_DUPLICATE_FORM":
|
|
14915
|
+
return `Nested <form> — the inner form will be dropped by the parser${fmtLocationSuffix(info)}`;
|
|
14916
|
+
case "HTML_NESTED_INTERACTIVE":
|
|
14917
|
+
return `<${info.tag}> nested inside another <${info.tag}> — adoption agency will reorder${fmtLocationSuffix(info)}`;
|
|
14918
|
+
case "HTML_MISNESTED_FORMATTING":
|
|
14919
|
+
return `Misnested formatting tag </${info.tag}> — adoption agency will reorder nodes${fmtLocationSuffix(info)}`;
|
|
14920
|
+
case "HTML_UNEXPECTED_END_TAG":
|
|
14921
|
+
return `Unexpected end tag </${info.tag}>${fmtLocationSuffix(info)}`;
|
|
14922
|
+
case "HTML_UNCLOSED_BEFORE_END":
|
|
14923
|
+
return `<${info.unclosed}> still open when </${info.tag}> was seen — implicitly closed${fmtLocationSuffix(info)}`;
|
|
14924
|
+
case "HTML_DUPLICATE_ATTRIBUTE":
|
|
14925
|
+
return `Duplicate attribute '${info.name}' — second occurrence dropped${fmtLocationSuffix(info)}`;
|
|
14926
|
+
case "HTML_ATTRIBUTES_ON_END_TAG":
|
|
14927
|
+
return `Attributes on end tag </${info.tag}> — dropped by the parser${fmtLocationSuffix(info)}`;
|
|
14928
|
+
case "HTML_SELF_CLOSING_END_TAG":
|
|
14929
|
+
return `Self-closing end tag </${info.tag}/> — trailing '/' is meaningless${fmtLocationSuffix(info)}`;
|
|
14930
|
+
case "HTML_MISSING_ATTRIBUTE_VALUE":
|
|
14931
|
+
return `Attribute '${info.name}' is missing a value${fmtLocationSuffix(info)}`;
|
|
14932
|
+
case "HTML_CDATA_IN_HTML_NAMESPACE":
|
|
14933
|
+
return `CDATA section in HTML namespace — reinterpreted as a bogus comment${fmtLocationSuffix(info)}`;
|
|
14934
|
+
case "HTML_BOGUS_COMMENT":
|
|
14935
|
+
return `Bogus comment — content dropped by the parser${fmtLocationSuffix(info)}`;
|
|
14936
|
+
case "HTML_SVG_ATTR_WILL_LOWERCASE":
|
|
14937
|
+
return `SVG attribute '${info.raw}' will be rewritten to '${info.canonical}'${fmtLocationSuffix(info)}`;
|
|
14938
|
+
case "HTML_MATHML_ATTR_WILL_LOWERCASE":
|
|
14939
|
+
return `MathML attribute '${info.raw}' will be rewritten to '${info.canonical}'${fmtLocationSuffix(info)}`;
|
|
14940
|
+
case "ASYNC_HANDLER":
|
|
14941
|
+
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)`;
|
|
14942
|
+
case "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE":
|
|
14943
|
+
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)}`;
|
|
14944
|
+
case "GLOBAL_SELECTOR_IN_SCOPED_STYLE":
|
|
14945
|
+
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)}`;
|
|
14946
|
+
case "LINT_ERROR":
|
|
14947
|
+
return info.message;
|
|
14948
|
+
default:
|
|
14949
|
+
return id;
|
|
14950
|
+
}
|
|
14951
|
+
}
|
|
14952
|
+
function suggestionToMessage(suggestion) {
|
|
14953
|
+
if (!suggestion)
|
|
14954
|
+
return null;
|
|
14955
|
+
switch (suggestion.kind) {
|
|
14956
|
+
case "replace-name":
|
|
14957
|
+
return `did you mean '${suggestion.to}'?`;
|
|
14958
|
+
case "drop-prefix":
|
|
14959
|
+
return `did you mean '${suggestion.to}'? (drop the leading '${suggestion.from.slice(0, suggestion.from.length - suggestion.to.length)}')`;
|
|
14960
|
+
case "add-prefix":
|
|
14961
|
+
return `did you mean '${suggestion.to}'? (add the leading '${suggestion.to.slice(0, suggestion.to.length - suggestion.from.length)}')`;
|
|
14962
|
+
case "remove":
|
|
14963
|
+
return `remove ${suggestion.what}`;
|
|
14964
|
+
case "rewrite":
|
|
14965
|
+
return `use '${suggestion.to}' instead of '${suggestion.from}'`;
|
|
14966
|
+
case "wrap":
|
|
14967
|
+
return `wrap it in ${suggestion.to}`;
|
|
14968
|
+
case "rephrase":
|
|
14969
|
+
return suggestion.text ?? null;
|
|
14970
|
+
default:
|
|
14971
|
+
return null;
|
|
14972
|
+
}
|
|
14973
|
+
}
|
|
14974
|
+
function fmtLocationSuffix(info) {
|
|
14975
|
+
const loc = info?.location;
|
|
14976
|
+
if (!loc)
|
|
14977
|
+
return "";
|
|
14978
|
+
return ` at line ${loc.line}, col ${loc.column}`;
|
|
14979
|
+
}
|
|
14980
|
+
function htmlActionPhrase(action, tag, parent) {
|
|
14981
|
+
switch (action) {
|
|
14982
|
+
case "ignored":
|
|
14983
|
+
return `the parser will drop this <${tag}>`;
|
|
14984
|
+
case "drop":
|
|
14985
|
+
return `the parser will drop this <${tag}>`;
|
|
14986
|
+
case "auto-close-implicit":
|
|
14987
|
+
return `the parser will close <${parent ?? "?"}> first, then place <${tag}> as a sibling`;
|
|
14988
|
+
case "foster-parent":
|
|
14989
|
+
return `the parser will move <${tag}> outside <${parent ?? "?"}> (foster-parenting)`;
|
|
14990
|
+
case "foreign-breakout":
|
|
14991
|
+
return `the parser will exit foreign content and re-process <${tag}> in HTML mode`;
|
|
14992
|
+
default:
|
|
14993
|
+
return `parser action: ${action}`;
|
|
14764
14994
|
}
|
|
14765
14995
|
}
|
|
14766
14996
|
|
|
@@ -15732,9 +15962,11 @@ export {
|
|
|
15732
15962
|
setIn$1 as setIn,
|
|
15733
15963
|
set2 as set,
|
|
15734
15964
|
runTests,
|
|
15965
|
+
resolveArgs,
|
|
15735
15966
|
reportTestReportToConsole,
|
|
15736
15967
|
removeIn,
|
|
15737
15968
|
remove,
|
|
15969
|
+
phaseOps,
|
|
15738
15970
|
mergeWith$1 as mergeWith,
|
|
15739
15971
|
mergeDeepWith$1 as mergeDeepWith,
|
|
15740
15972
|
mergeDeep$1 as mergeDeep,
|
|
@@ -15771,6 +16003,7 @@ export {
|
|
|
15771
16003
|
get2 as get,
|
|
15772
16004
|
fromJS,
|
|
15773
16005
|
docComponents,
|
|
16006
|
+
dispatchPhase,
|
|
15774
16007
|
css,
|
|
15775
16008
|
component,
|
|
15776
16009
|
compileClassesToStyleText,
|
|
@@ -15792,6 +16025,7 @@ export {
|
|
|
15792
16025
|
TestReport,
|
|
15793
16026
|
TestIndex,
|
|
15794
16027
|
Test,
|
|
16028
|
+
TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE,
|
|
15795
16029
|
Stack,
|
|
15796
16030
|
Set2 as Set,
|
|
15797
16031
|
Seq,
|
|
@@ -15836,6 +16070,7 @@ export {
|
|
|
15836
16070
|
INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD,
|
|
15837
16071
|
Map2 as IMap,
|
|
15838
16072
|
IF_NO_BRANCH_SET,
|
|
16073
|
+
GLOBAL_SELECTOR_IN_SCOPED_STYLE,
|
|
15839
16074
|
FIELD_VAL_NOT_DEFINED,
|
|
15840
16075
|
FIELD_VAL_IS_METHOD,
|
|
15841
16076
|
FIELD_CLASS,
|