tutuca 0.9.34 → 0.9.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -8
- package/dist/tutuca-cli.js +149 -261
- package/dist/tutuca-dev.js +103 -177
- package/dist/tutuca-dev.min.js +3 -3
- package/dist/tutuca-extra.js +77 -131
- package/dist/tutuca-extra.min.js +3 -3
- package/dist/tutuca.js +77 -131
- package/dist/tutuca.min.js +3 -3
- package/package.json +2 -2
- package/skill/SKILL.md +19 -9
- package/skill/cli.md +12 -10
- package/skill/core.md +69 -34
package/dist/tutuca-cli.js
CHANGED
|
@@ -118,16 +118,6 @@ class RenderBatch {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
class DoctorReport {
|
|
122
|
-
constructor({ lint, renders }) {
|
|
123
|
-
this.lint = lint;
|
|
124
|
-
this.renders = renders;
|
|
125
|
-
}
|
|
126
|
-
get ok() {
|
|
127
|
-
return !this.lint.hasErrors && !this.renders.hasErrors;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
121
|
// tools/core/module.js
|
|
132
122
|
class Example {
|
|
133
123
|
constructor({ title, description = null, value, view = "main", componentName = null }) {
|
|
@@ -456,6 +446,30 @@ function docComponents(normalized, { name = null } = {}) {
|
|
|
456
446
|
}
|
|
457
447
|
var init_docs = () => {};
|
|
458
448
|
|
|
449
|
+
// tools/core/list.js
|
|
450
|
+
function summarize(comp) {
|
|
451
|
+
const meta = comp.Class.getMetaClass();
|
|
452
|
+
const fields = [];
|
|
453
|
+
for (const fieldName in meta.fields) {
|
|
454
|
+
const f = meta.fields[fieldName];
|
|
455
|
+
fields.push({ name: fieldName, type: f.type });
|
|
456
|
+
}
|
|
457
|
+
return new ComponentSummary({
|
|
458
|
+
name: comp.name,
|
|
459
|
+
views: Object.keys(comp.views ?? {}),
|
|
460
|
+
fields
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
function listComponents(normalized, { name = null } = {}) {
|
|
464
|
+
const comps = normalized.components;
|
|
465
|
+
const picked = name === null ? comps : comps.filter((c) => c.name === name);
|
|
466
|
+
return new ComponentList({ items: picked.map(summarize) });
|
|
467
|
+
}
|
|
468
|
+
function listExamples(normalized) {
|
|
469
|
+
return new ExampleIndex({ sections: normalized.sections });
|
|
470
|
+
}
|
|
471
|
+
var init_list = () => {};
|
|
472
|
+
|
|
459
473
|
// src/path.js
|
|
460
474
|
class Step {
|
|
461
475
|
lookup(_v, dval = null) {
|
|
@@ -708,7 +722,7 @@ class ValParser {
|
|
|
708
722
|
}
|
|
709
723
|
allowFieldOnly() {
|
|
710
724
|
this.okField = true;
|
|
711
|
-
this.okBind = this.
|
|
725
|
+
this.okBind = this.okDyn = this.okType = this.okRequest = false;
|
|
712
726
|
this.okName = this.okConst = this.okStrTpl = this.okSeqAccess = false;
|
|
713
727
|
}
|
|
714
728
|
_parseSeqAccess(s, px) {
|
|
@@ -749,8 +763,6 @@ class ValParser {
|
|
|
749
763
|
return this.okDyn ? parseDyn(s.slice(1), px) : null;
|
|
750
764
|
case 46:
|
|
751
765
|
return this.okField ? parseField(s.slice(1), px) : null;
|
|
752
|
-
case 36:
|
|
753
|
-
return this.okComputed ? parseComp(s.slice(1), px) : null;
|
|
754
766
|
case 33:
|
|
755
767
|
return this.okRequest ? parseReq(s.slice(1), px) : null;
|
|
756
768
|
}
|
|
@@ -767,17 +779,16 @@ class ValParser {
|
|
|
767
779
|
}
|
|
768
780
|
parseDynamic(s, px) {
|
|
769
781
|
this.allowFieldOnly();
|
|
770
|
-
this.okComputed = true;
|
|
771
782
|
return this.parse(s, px);
|
|
772
783
|
}
|
|
773
784
|
parseEach(s, px) {
|
|
774
785
|
this.allowFieldOnly();
|
|
775
|
-
this.
|
|
786
|
+
this.okDyn = true;
|
|
776
787
|
return this.parse(s, px);
|
|
777
788
|
}
|
|
778
789
|
allowHandlerArg() {
|
|
779
790
|
this.allowFieldOnly();
|
|
780
|
-
this.okBind = this.
|
|
791
|
+
this.okBind = this.okDyn = this.okType = this.okRequest = true;
|
|
781
792
|
this.okName = this.okConst = true;
|
|
782
793
|
}
|
|
783
794
|
parseHandlerArg(s, px) {
|
|
@@ -806,12 +817,12 @@ class ValParser {
|
|
|
806
817
|
}
|
|
807
818
|
parseCondValue(s, px) {
|
|
808
819
|
this.allowFieldOnly();
|
|
809
|
-
this.okBind = this.
|
|
820
|
+
this.okBind = this.okDyn = this.okConst = true;
|
|
810
821
|
return this.parse(s, px);
|
|
811
822
|
}
|
|
812
823
|
parseText(s, px) {
|
|
813
824
|
this.allowFieldOnly();
|
|
814
|
-
this.okBind = this.
|
|
825
|
+
this.okBind = this.okDyn = this.okConst = this.okStrTpl = true;
|
|
815
826
|
return this.parse(s, px);
|
|
816
827
|
}
|
|
817
828
|
parseRender(s, px) {
|
|
@@ -853,10 +864,10 @@ function getValSubType(s) {
|
|
|
853
864
|
return open === 1 && close === 1 ? VAL_SUB_TYPE_SEQ_ACCESS : VAL_SUB_TYPE_INVALID;
|
|
854
865
|
return -1;
|
|
855
866
|
}
|
|
856
|
-
var VALID_VAL_ID_RE, isValidValId = (name) => VALID_VAL_ID_RE.test(name), VALID_FLOAT_RE, STR_TPL_SPLIT_RE, parseStrTemplate = (v, px) => StrTplVal.parse(v, px), parseConst = (v, _) => new ConstVal(v), parseName = (v, _) => isValidValId(v) ? new NameVal(v) : null, parseType = (v, _) => isValidValId(v) ? new TypeVal(v) : null, parseBind = (v, _) => isValidValId(v) ? new BindVal(v) : null, parseDyn = (v, _) => isValidValId(v) ? new DynVal(v) : null, parseField = (v, _) => isValidValId(v) ? new FieldVal(v) : null,
|
|
867
|
+
var VALID_VAL_ID_RE, isValidValId = (name) => VALID_VAL_ID_RE.test(name), VALID_FLOAT_RE, STR_TPL_SPLIT_RE, parseStrTemplate = (v, px) => StrTplVal.parse(v, px), parseConst = (v, _) => new ConstVal(v), parseName = (v, _) => isValidValId(v) ? new NameVal(v) : null, parseType = (v, _) => isValidValId(v) ? new TypeVal(v) : null, parseBind = (v, _) => isValidValId(v) ? new BindVal(v) : null, parseDyn = (v, _) => isValidValId(v) ? new DynVal(v) : null, parseField = (v, _) => isValidValId(v) ? new FieldVal(v) : null, parseReq = (v, _) => isValidValId(v) ? new RequestVal(v) : null, ConstVal, VarVal, StrTplVal, NameVal, InputHandlerNameVal, AlterHandlerNameVal, mk404Handler = (type, name) => function(...args) {
|
|
857
868
|
console.warn("handler not found", { type, name, args }, this);
|
|
858
869
|
return this;
|
|
859
|
-
}, TypeVal, RequestVal, RawFieldVal, RenderVal, RenderNameVal, BindVal, DynVal, FieldVal,
|
|
870
|
+
}, TypeVal, RequestVal, RawFieldVal, RenderVal, RenderNameVal, BindVal, DynVal, FieldVal, SeqAccessVal, VAL_SUB_TYPE_STRING_TEMPLATE = 0, VAL_SUB_TYPE_SEQ_ACCESS = 1, VAL_SUB_TYPE_INVALID = 2, VAL_SUB_TYPE_CONST_STRING = 3, vp;
|
|
860
871
|
var init_value = __esm(() => {
|
|
861
872
|
init_path();
|
|
862
873
|
VALID_VAL_ID_RE = /^[a-zA-Z][a-zA-Z0-9_]*$/;
|
|
@@ -995,14 +1006,6 @@ var init_value = __esm(() => {
|
|
|
995
1006
|
return `.${this.name}`;
|
|
996
1007
|
}
|
|
997
1008
|
};
|
|
998
|
-
ComputedVal = class ComputedVal extends RenderNameVal {
|
|
999
|
-
eval(stack) {
|
|
1000
|
-
return stack.lookupComputed(this.name);
|
|
1001
|
-
}
|
|
1002
|
-
toString() {
|
|
1003
|
-
return `$${this.name}`;
|
|
1004
|
-
}
|
|
1005
|
-
};
|
|
1006
1009
|
SeqAccessVal = class SeqAccessVal extends RenderVal {
|
|
1007
1010
|
constructor(seqVal, keyVal) {
|
|
1008
1011
|
super();
|
|
@@ -1969,111 +1972,11 @@ var init_anode = __esm(() => {
|
|
|
1969
1972
|
};
|
|
1970
1973
|
});
|
|
1971
1974
|
|
|
1972
|
-
// src/cache.js
|
|
1973
|
-
class NullDomCache {
|
|
1974
|
-
get(_keys, _cacheKey) {}
|
|
1975
|
-
set(_keys, _cacheKey, _v) {}
|
|
1976
|
-
evict() {
|
|
1977
|
-
return { hit: 0, miss: 0, badKey: 0 };
|
|
1978
|
-
}
|
|
1979
|
-
}
|
|
1980
|
-
|
|
1981
|
-
class WeakMapDomCache {
|
|
1982
|
-
constructor() {
|
|
1983
|
-
this.hit = this.miss = this.badKey = 0;
|
|
1984
|
-
this.keysByLen = new Map;
|
|
1985
|
-
}
|
|
1986
|
-
_returnValue(r) {
|
|
1987
|
-
if (r === undefined)
|
|
1988
|
-
this.miss += 1;
|
|
1989
|
-
else
|
|
1990
|
-
this.hit += 1;
|
|
1991
|
-
return r;
|
|
1992
|
-
}
|
|
1993
|
-
get(keys, cacheKey) {
|
|
1994
|
-
const len = keys.length;
|
|
1995
|
-
let cur = this.keysByLen.get(len);
|
|
1996
|
-
if (!cur)
|
|
1997
|
-
return this._returnValue(undefined);
|
|
1998
|
-
for (let i = 0;i < len - 1; i++) {
|
|
1999
|
-
cur = cur.get(keys[i]);
|
|
2000
|
-
if (!cur)
|
|
2001
|
-
return this._returnValue(undefined);
|
|
2002
|
-
}
|
|
2003
|
-
return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
|
|
2004
|
-
}
|
|
2005
|
-
set(keys, cacheKey, v) {
|
|
2006
|
-
const len = keys.length;
|
|
2007
|
-
let cur = this.keysByLen.get(len);
|
|
2008
|
-
if (!cur) {
|
|
2009
|
-
cur = new WeakMap;
|
|
2010
|
-
this.keysByLen.set(len, cur);
|
|
2011
|
-
}
|
|
2012
|
-
for (let i = 0;i < len - 1; i++) {
|
|
2013
|
-
const key = keys[i];
|
|
2014
|
-
let next = cur.get(key);
|
|
2015
|
-
if (!next) {
|
|
2016
|
-
if (typeof key !== "object") {
|
|
2017
|
-
this.badKey += 1;
|
|
2018
|
-
return;
|
|
2019
|
-
}
|
|
2020
|
-
next = new WeakMap;
|
|
2021
|
-
cur.set(key, next);
|
|
2022
|
-
}
|
|
2023
|
-
cur = next;
|
|
2024
|
-
}
|
|
2025
|
-
const lastKey = keys[len - 1];
|
|
2026
|
-
const leaf = cur.get(lastKey);
|
|
2027
|
-
if (leaf)
|
|
2028
|
-
leaf[cacheKey] = v;
|
|
2029
|
-
else if (typeof lastKey === "object")
|
|
2030
|
-
cur.set(lastKey, { [cacheKey]: v });
|
|
2031
|
-
else
|
|
2032
|
-
this.badKey += 1;
|
|
2033
|
-
}
|
|
2034
|
-
evict() {
|
|
2035
|
-
const { hit, miss, badKey } = this;
|
|
2036
|
-
this.hit = this.miss = this.badKey = 0;
|
|
2037
|
-
this.keysByLen = new Map;
|
|
2038
|
-
return { hit, miss, badKey };
|
|
2039
|
-
}
|
|
2040
|
-
}
|
|
2041
|
-
|
|
2042
|
-
class NullComputedCache {
|
|
2043
|
-
getKey(v, _key, fn) {
|
|
2044
|
-
return fn.call(v);
|
|
2045
|
-
}
|
|
2046
|
-
}
|
|
2047
|
-
|
|
2048
|
-
class WeakMapComputedCache {
|
|
2049
|
-
constructor() {
|
|
2050
|
-
this.map = new WeakMap;
|
|
2051
|
-
}
|
|
2052
|
-
getKey(v, key, fn) {
|
|
2053
|
-
const cur = this.map.get(v);
|
|
2054
|
-
if (cur) {
|
|
2055
|
-
const curValue = cur[key];
|
|
2056
|
-
if (curValue !== undefined)
|
|
2057
|
-
return curValue;
|
|
2058
|
-
const newValue2 = fn.call(v) ?? null;
|
|
2059
|
-
cur[key] = newValue2;
|
|
2060
|
-
return newValue2;
|
|
2061
|
-
}
|
|
2062
|
-
const newValue = fn.call(v) ?? null;
|
|
2063
|
-
this.map.set(v, { [key]: newValue });
|
|
2064
|
-
return newValue;
|
|
2065
|
-
}
|
|
2066
|
-
}
|
|
2067
|
-
|
|
2068
1975
|
// src/components.js
|
|
2069
1976
|
class Components {
|
|
2070
1977
|
constructor() {
|
|
2071
1978
|
this.getComponentSymbol = Symbol("getComponent");
|
|
2072
1979
|
this.byId = new Map;
|
|
2073
|
-
this.computedCache = new WeakMapComputedCache;
|
|
2074
|
-
}
|
|
2075
|
-
setNullComputedCache() {
|
|
2076
|
-
this.computedCache = new NullComputedCache;
|
|
2077
1980
|
}
|
|
2078
1981
|
registerComponent(comp) {
|
|
2079
1982
|
comp.Class.prototype[this.getComponentSymbol] = () => comp;
|
|
@@ -2096,10 +1999,6 @@ class Components {
|
|
|
2096
1999
|
const comp = this.getCompFor(v);
|
|
2097
2000
|
return comp ? comp.scope.lookupRequest(name) : null;
|
|
2098
2001
|
}
|
|
2099
|
-
lookupComputed(v, name) {
|
|
2100
|
-
const fn = this.getHandlerFor(v, name, "computed");
|
|
2101
|
-
return fn ? this.computedCache.getKey(v, name, fn) : null;
|
|
2102
|
-
}
|
|
2103
2002
|
compileStyles() {
|
|
2104
2003
|
const styles = [];
|
|
2105
2004
|
for (const comp of this.byId.values())
|
|
@@ -2172,23 +2071,21 @@ function checkComponent(Comp, lx = new LintContext) {
|
|
|
2172
2071
|
return lx.push({ componentName: Comp.name }, () => {
|
|
2173
2072
|
const referencedAlters = new Set;
|
|
2174
2073
|
const referencedInputs = new Set;
|
|
2175
|
-
const referencedComputed = new Set;
|
|
2176
2074
|
checkEventHandlersHaveImpls(lx, Comp, referencedInputs);
|
|
2177
|
-
checkConsistentAttrs(lx, Comp, referencedAlters
|
|
2075
|
+
checkConsistentAttrs(lx, Comp, referencedAlters);
|
|
2178
2076
|
for (const name in Comp.views) {
|
|
2179
|
-
lx.push({ viewName: name }, () => checkView(lx, Comp.views[name], Comp, referencedAlters
|
|
2077
|
+
lx.push({ viewName: name }, () => checkView(lx, Comp.views[name], Comp, referencedAlters));
|
|
2180
2078
|
}
|
|
2181
2079
|
checkUnreferencedAlterHandlers(lx, Comp, referencedAlters);
|
|
2182
2080
|
checkUnreferencedInputHandlers(lx, Comp, referencedInputs);
|
|
2183
|
-
checkUnreferencedComputed(lx, Comp, referencedComputed);
|
|
2184
2081
|
return lx;
|
|
2185
2082
|
});
|
|
2186
2083
|
}
|
|
2187
|
-
function checkView(lx, view, Comp, referencedAlters
|
|
2084
|
+
function checkView(lx, view, Comp, referencedAlters) {
|
|
2188
2085
|
checkParseIssues(lx, view);
|
|
2189
2086
|
checkRenderItInLoop(lx, view);
|
|
2190
2087
|
checkEventModifiers(lx, view);
|
|
2191
|
-
checkKnownHandlerNames(lx, view, Comp, referencedAlters
|
|
2088
|
+
checkKnownHandlerNames(lx, view, Comp, referencedAlters);
|
|
2192
2089
|
checkMacroCallArgs(lx, view, Comp);
|
|
2193
2090
|
}
|
|
2194
2091
|
function checkParseIssues(lx, view) {
|
|
@@ -2289,8 +2186,8 @@ function checkEventModifiers(lx, view) {
|
|
|
2289
2186
|
function isKnownHandlerName(name) {
|
|
2290
2187
|
return KNOWN_HANDLER_NAMES.has(name);
|
|
2291
2188
|
}
|
|
2292
|
-
function checkKnownHandlerNames(lx, view, Comp, referencedAlters
|
|
2293
|
-
const {
|
|
2189
|
+
function checkKnownHandlerNames(lx, view, Comp, referencedAlters) {
|
|
2190
|
+
const { scope, alter, Class } = Comp;
|
|
2294
2191
|
const { prototype: proto } = Class;
|
|
2295
2192
|
const { fields } = Class.getMetaClass();
|
|
2296
2193
|
for (const event of view.ctx.events) {
|
|
@@ -2304,7 +2201,10 @@ function checkKnownHandlerNames(lx, view, Comp, referencedAlters, referencedComp
|
|
|
2304
2201
|
originAttr: `@on.${eventName}`
|
|
2305
2202
|
};
|
|
2306
2203
|
for (let i = 0;i < args.length; i++) {
|
|
2307
|
-
checkConsistentAttrVal(lx, args[i], fields, proto,
|
|
2204
|
+
checkConsistentAttrVal(lx, args[i], fields, proto, scope, alter, referencedAlters, false, {
|
|
2205
|
+
...errCtx,
|
|
2206
|
+
argIndex: i
|
|
2207
|
+
});
|
|
2308
2208
|
}
|
|
2309
2209
|
}
|
|
2310
2210
|
}
|
|
@@ -2367,22 +2267,16 @@ function checkEventHandlersHaveImpls(lx, Comp, referencedInputs) {
|
|
|
2367
2267
|
});
|
|
2368
2268
|
}
|
|
2369
2269
|
}
|
|
2370
|
-
function checkConsistentAttrVal(lx, val, fields, proto,
|
|
2270
|
+
function checkConsistentAttrVal(lx, val, fields, proto, scope, alter, referencedAlters, skipNameVal = false, errCtx = null) {
|
|
2371
2271
|
const valName = val?.constructor.name;
|
|
2372
2272
|
if (valName === "FieldVal" || valName === "RawFieldVal") {
|
|
2373
2273
|
const { name } = val;
|
|
2374
2274
|
if (fields[name] === undefined && proto[name] === undefined) {
|
|
2375
2275
|
lx.error(FIELD_VAL_NOT_DEFINED, { ...errCtx, val, name });
|
|
2376
2276
|
}
|
|
2377
|
-
} else if (valName === "ComputedVal") {
|
|
2378
|
-
const { name } = val;
|
|
2379
|
-
referencedComputed?.add(name);
|
|
2380
|
-
if (computed[name] === undefined) {
|
|
2381
|
-
lx.error(COMPUTED_VAL_NOT_DEFINED, { ...errCtx, val, name });
|
|
2382
|
-
}
|
|
2383
2277
|
} else if (valName === "SeqAccessVal") {
|
|
2384
|
-
checkConsistentAttrVal(lx, val.seqVal, fields, proto,
|
|
2385
|
-
checkConsistentAttrVal(lx, val.keyVal, fields, proto,
|
|
2278
|
+
checkConsistentAttrVal(lx, val.seqVal, fields, proto, scope, alter, referencedAlters, skipNameVal, errCtx);
|
|
2279
|
+
checkConsistentAttrVal(lx, val.keyVal, fields, proto, scope, alter, referencedAlters, skipNameVal, errCtx);
|
|
2386
2280
|
} else if (valName === "RequestVal") {
|
|
2387
2281
|
if (scope.lookupRequest(val.name) === null) {
|
|
2388
2282
|
lx.error(UNKNOWN_REQUEST_NAME, { ...errCtx, name: val.name });
|
|
@@ -2397,7 +2291,7 @@ function checkConsistentAttrVal(lx, val, fields, proto, computed, scope, alter,
|
|
|
2397
2291
|
}
|
|
2398
2292
|
} else if (valName === "StrTplVal") {
|
|
2399
2293
|
for (const subVal of val.vals) {
|
|
2400
|
-
checkConsistentAttrVal(lx, subVal, fields, proto,
|
|
2294
|
+
checkConsistentAttrVal(lx, subVal, fields, proto, scope, alter, referencedAlters, skipNameVal, errCtx);
|
|
2401
2295
|
}
|
|
2402
2296
|
} else if (valName === "AlterHandlerNameVal") {
|
|
2403
2297
|
referencedAlters?.add(val.name);
|
|
@@ -2429,8 +2323,8 @@ function attrOriginAttr(attr) {
|
|
|
2429
2323
|
return "@dangerouslysetinnerhtml";
|
|
2430
2324
|
return `:${attr.name}`;
|
|
2431
2325
|
}
|
|
2432
|
-
function checkConsistentAttrs(lx, Comp, referencedAlters
|
|
2433
|
-
const {
|
|
2326
|
+
function checkConsistentAttrs(lx, Comp, referencedAlters) {
|
|
2327
|
+
const { scope, views, alter, Class } = Comp;
|
|
2434
2328
|
const { prototype: proto } = Class;
|
|
2435
2329
|
const { fields } = Class.getMetaClass();
|
|
2436
2330
|
for (const viewName in views) {
|
|
@@ -2460,10 +2354,10 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedComputed) {
|
|
|
2460
2354
|
["@else", attr.elseVal]
|
|
2461
2355
|
];
|
|
2462
2356
|
for (const [branch, subVal] of branches) {
|
|
2463
|
-
checkConsistentAttrVal(lx, subVal, fields, proto,
|
|
2357
|
+
checkConsistentAttrVal(lx, subVal, fields, proto, scope, alter, referencedAlters, isMacroCall, { tag, originAttr: `@if.${attr.name}`, branch });
|
|
2464
2358
|
}
|
|
2465
2359
|
} else if (attr?.val !== undefined) {
|
|
2466
|
-
checkConsistentAttrVal(lx, attr.val, fields, proto,
|
|
2360
|
+
checkConsistentAttrVal(lx, attr.val, fields, proto, scope, alter, referencedAlters, isMacroCall, { tag, originAttr: attrOriginAttr(attr) });
|
|
2467
2361
|
}
|
|
2468
2362
|
}
|
|
2469
2363
|
for (const [name, sources] of sourcesByName) {
|
|
@@ -2476,19 +2370,19 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedComputed) {
|
|
|
2476
2370
|
for (const w of wrapperAttrs) {
|
|
2477
2371
|
if (w.name === "each") {
|
|
2478
2372
|
if (w.whenVal)
|
|
2479
|
-
checkConsistentAttrVal(lx, w.whenVal, fields, proto,
|
|
2373
|
+
checkConsistentAttrVal(lx, w.whenVal, fields, proto, scope, alter, referencedAlters, false, { tag, originAttr: "@when" });
|
|
2480
2374
|
if (w.enrichWithVal)
|
|
2481
|
-
checkConsistentAttrVal(lx, w.enrichWithVal, fields, proto,
|
|
2375
|
+
checkConsistentAttrVal(lx, w.enrichWithVal, fields, proto, scope, alter, referencedAlters, false, { tag, originAttr: "@enrich-with" });
|
|
2482
2376
|
if (w.loopWithVal)
|
|
2483
|
-
checkConsistentAttrVal(lx, w.loopWithVal, fields, proto,
|
|
2377
|
+
checkConsistentAttrVal(lx, w.loopWithVal, fields, proto, scope, alter, referencedAlters, false, { tag, originAttr: "@loop-with" });
|
|
2484
2378
|
} else {
|
|
2485
2379
|
const originAttr = w.name === "scope" ? "@enrich-with" : `@${w.name}`;
|
|
2486
|
-
checkConsistentAttrVal(lx, w.val, fields, proto,
|
|
2380
|
+
checkConsistentAttrVal(lx, w.val, fields, proto, scope, alter, referencedAlters, false, { tag, originAttr });
|
|
2487
2381
|
}
|
|
2488
2382
|
}
|
|
2489
2383
|
}
|
|
2490
2384
|
if (textChild) {
|
|
2491
|
-
checkConsistentAttrVal(lx, textChild, fields, proto,
|
|
2385
|
+
checkConsistentAttrVal(lx, textChild, fields, proto, scope, alter, referencedAlters, false, { tag, originAttr: "@text" });
|
|
2492
2386
|
}
|
|
2493
2387
|
}
|
|
2494
2388
|
for (const node of view.ctx.nodes) {
|
|
@@ -2497,14 +2391,14 @@ function checkConsistentAttrs(lx, Comp, referencedAlters, referencedComputed) {
|
|
|
2497
2391
|
continue;
|
|
2498
2392
|
const baseCtx = nodeCtxForNode(nodeKind);
|
|
2499
2393
|
if (node.val) {
|
|
2500
|
-
checkConsistentAttrVal(lx, node.val, fields, proto,
|
|
2394
|
+
checkConsistentAttrVal(lx, node.val, fields, proto, scope, alter, referencedAlters, false, baseCtx);
|
|
2501
2395
|
}
|
|
2502
2396
|
if (nodeKind === "RenderEachNode") {
|
|
2503
2397
|
const iter = node.iterInfo;
|
|
2504
2398
|
if (iter.whenVal)
|
|
2505
|
-
checkConsistentAttrVal(lx, iter.whenVal, fields, proto,
|
|
2399
|
+
checkConsistentAttrVal(lx, iter.whenVal, fields, proto, scope, alter, referencedAlters, false, { originAttr: "<x render-each when>" });
|
|
2506
2400
|
if (iter.loopWithVal)
|
|
2507
|
-
checkConsistentAttrVal(lx, iter.loopWithVal, fields, proto,
|
|
2401
|
+
checkConsistentAttrVal(lx, iter.loopWithVal, fields, proto, scope, alter, referencedAlters, false, { originAttr: "<x render-each loop-with>" });
|
|
2508
2402
|
}
|
|
2509
2403
|
}
|
|
2510
2404
|
});
|
|
@@ -2524,13 +2418,6 @@ function checkUnreferencedInputHandlers(lx, Comp, referencedInputs) {
|
|
|
2524
2418
|
}
|
|
2525
2419
|
}
|
|
2526
2420
|
}
|
|
2527
|
-
function checkUnreferencedComputed(lx, Comp, referencedComputed) {
|
|
2528
|
-
for (const name in Comp.computed) {
|
|
2529
|
-
if (!referencedComputed.has(name)) {
|
|
2530
|
-
lx.hint(COMPUTED_NOT_REFERENCED, { name });
|
|
2531
|
-
}
|
|
2532
|
-
}
|
|
2533
|
-
}
|
|
2534
2421
|
|
|
2535
2422
|
class LintContext {
|
|
2536
2423
|
constructor() {
|
|
@@ -2559,7 +2446,7 @@ class LintContext {
|
|
|
2559
2446
|
this.reports.push({ id, info, level, context: { ...this.frame } });
|
|
2560
2447
|
}
|
|
2561
2448
|
}
|
|
2562
|
-
var ALT_HANDLER_NOT_DEFINED = "ALT_HANDLER_NOT_DEFINED", ALT_HANDLER_NOT_REFERENCED = "ALT_HANDLER_NOT_REFERENCED", RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP", UNKNOWN_EVENT_MODIFIER = "UNKNOWN_EVENT_MODIFIER", UNKNOWN_HANDLER_ARG_NAME = "UNKNOWN_HANDLER_ARG_NAME", INPUT_HANDLER_NOT_IMPLEMENTED = "INPUT_HANDLER_NOT_IMPLEMENTED", INPUT_HANDLER_NOT_REFERENCED = "INPUT_HANDLER_NOT_REFERENCED", INPUT_HANDLER_METHOD_NOT_IMPLEMENTED = "INPUT_HANDLER_METHOD_NOT_IMPLEMENTED", INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD = "INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD", INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER = "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER", FIELD_VAL_NOT_DEFINED = "FIELD_VAL_NOT_DEFINED",
|
|
2449
|
+
var ALT_HANDLER_NOT_DEFINED = "ALT_HANDLER_NOT_DEFINED", ALT_HANDLER_NOT_REFERENCED = "ALT_HANDLER_NOT_REFERENCED", RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP", UNKNOWN_EVENT_MODIFIER = "UNKNOWN_EVENT_MODIFIER", UNKNOWN_HANDLER_ARG_NAME = "UNKNOWN_HANDLER_ARG_NAME", INPUT_HANDLER_NOT_IMPLEMENTED = "INPUT_HANDLER_NOT_IMPLEMENTED", INPUT_HANDLER_NOT_REFERENCED = "INPUT_HANDLER_NOT_REFERENCED", INPUT_HANDLER_METHOD_NOT_IMPLEMENTED = "INPUT_HANDLER_METHOD_NOT_IMPLEMENTED", INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD = "INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD", INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER = "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER", FIELD_VAL_NOT_DEFINED = "FIELD_VAL_NOT_DEFINED", DUPLICATE_ATTR_DEFINITION = "DUPLICATE_ATTR_DEFINITION", IF_NO_BRANCH_SET = "IF_NO_BRANCH_SET", UNKNOWN_REQUEST_NAME = "UNKNOWN_REQUEST_NAME", UNKNOWN_COMPONENT_NAME = "UNKNOWN_COMPONENT_NAME", UNKNOWN_MACRO_ARG = "UNKNOWN_MACRO_ARG", UNKNOWN_DIRECTIVE = "UNKNOWN_DIRECTIVE", UNKNOWN_X_OP = "UNKNOWN_X_OP", UNKNOWN_X_ATTR = "UNKNOWN_X_ATTR", MAYBE_DROP_AT_PREFIX = "MAYBE_DROP_AT_PREFIX", BAD_VALUE = "BAD_VALUE", PARSE_ISSUE_KIND_TO_LINT_ID, X_KNOWN_OP_NAMES, X_KNOWN_ATTR_NAMES, AT_PREFIX_HINT_KNOWN_BY_KIND, LEVEL_WARN = "warn", LEVEL_ERROR = "error", LEVEL_HINT = "hint", NO_WRAPPERS, KNOWN_HANDLER_NAMES, NODE_KIND_TO_CTX, LintParseContext;
|
|
2563
2450
|
var init_lint_check = __esm(() => {
|
|
2564
2451
|
init_anode();
|
|
2565
2452
|
PARSE_ISSUE_KIND_TO_LINT_ID = {
|
|
@@ -2771,10 +2658,6 @@ class Stack {
|
|
|
2771
2658
|
lookupName(name) {
|
|
2772
2659
|
return this.ctx.lookupName(name);
|
|
2773
2660
|
}
|
|
2774
|
-
lookupComputed(name) {
|
|
2775
|
-
const node = this.binds[0].isFrame ? this.binds[0] : this.binds[1][0];
|
|
2776
|
-
return this.comps.lookupComputed(node.it, name);
|
|
2777
|
-
}
|
|
2778
2661
|
getHandlerFor(name, key) {
|
|
2779
2662
|
return this.comps.getHandlerFor(this.it, name, key);
|
|
2780
2663
|
}
|
|
@@ -3623,12 +3506,10 @@ class App {
|
|
|
3623
3506
|
this.render();
|
|
3624
3507
|
});
|
|
3625
3508
|
injectCss("tutuca-app", this.comps.compileStyles(), opts?.head ?? document.head);
|
|
3626
|
-
if (opts?.noCache)
|
|
3509
|
+
if (opts?.noCache)
|
|
3627
3510
|
this.renderer.setNullCache();
|
|
3628
|
-
|
|
3629
|
-
} else {
|
|
3511
|
+
else
|
|
3630
3512
|
this.startCacheEvictionInterval();
|
|
3631
|
-
}
|
|
3632
3513
|
this.render();
|
|
3633
3514
|
}
|
|
3634
3515
|
stop() {
|
|
@@ -7946,6 +7827,76 @@ var init_immutable = __esm(() => {
|
|
|
7946
7827
|
initCollectionConversions();
|
|
7947
7828
|
});
|
|
7948
7829
|
|
|
7830
|
+
// src/cache.js
|
|
7831
|
+
class NullDomCache {
|
|
7832
|
+
get(_keys, _cacheKey) {}
|
|
7833
|
+
set(_keys, _cacheKey, _v) {}
|
|
7834
|
+
evict() {
|
|
7835
|
+
return { hit: 0, miss: 0, badKey: 0 };
|
|
7836
|
+
}
|
|
7837
|
+
}
|
|
7838
|
+
|
|
7839
|
+
class WeakMapDomCache {
|
|
7840
|
+
constructor() {
|
|
7841
|
+
this.hit = this.miss = this.badKey = 0;
|
|
7842
|
+
this.keysByLen = new Map;
|
|
7843
|
+
}
|
|
7844
|
+
_returnValue(r) {
|
|
7845
|
+
if (r === undefined)
|
|
7846
|
+
this.miss += 1;
|
|
7847
|
+
else
|
|
7848
|
+
this.hit += 1;
|
|
7849
|
+
return r;
|
|
7850
|
+
}
|
|
7851
|
+
get(keys, cacheKey) {
|
|
7852
|
+
const len = keys.length;
|
|
7853
|
+
let cur = this.keysByLen.get(len);
|
|
7854
|
+
if (!cur)
|
|
7855
|
+
return this._returnValue(undefined);
|
|
7856
|
+
for (let i = 0;i < len - 1; i++) {
|
|
7857
|
+
cur = cur.get(keys[i]);
|
|
7858
|
+
if (!cur)
|
|
7859
|
+
return this._returnValue(undefined);
|
|
7860
|
+
}
|
|
7861
|
+
return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
|
|
7862
|
+
}
|
|
7863
|
+
set(keys, cacheKey, v) {
|
|
7864
|
+
const len = keys.length;
|
|
7865
|
+
let cur = this.keysByLen.get(len);
|
|
7866
|
+
if (!cur) {
|
|
7867
|
+
cur = new WeakMap;
|
|
7868
|
+
this.keysByLen.set(len, cur);
|
|
7869
|
+
}
|
|
7870
|
+
for (let i = 0;i < len - 1; i++) {
|
|
7871
|
+
const key = keys[i];
|
|
7872
|
+
let next = cur.get(key);
|
|
7873
|
+
if (!next) {
|
|
7874
|
+
if (typeof key !== "object") {
|
|
7875
|
+
this.badKey += 1;
|
|
7876
|
+
return;
|
|
7877
|
+
}
|
|
7878
|
+
next = new WeakMap;
|
|
7879
|
+
cur.set(key, next);
|
|
7880
|
+
}
|
|
7881
|
+
cur = next;
|
|
7882
|
+
}
|
|
7883
|
+
const lastKey = keys[len - 1];
|
|
7884
|
+
const leaf = cur.get(lastKey);
|
|
7885
|
+
if (leaf)
|
|
7886
|
+
leaf[cacheKey] = v;
|
|
7887
|
+
else if (typeof lastKey === "object")
|
|
7888
|
+
cur.set(lastKey, { [cacheKey]: v });
|
|
7889
|
+
else
|
|
7890
|
+
this.badKey += 1;
|
|
7891
|
+
}
|
|
7892
|
+
evict() {
|
|
7893
|
+
const { hit, miss, badKey } = this;
|
|
7894
|
+
this.hit = this.miss = this.badKey = 0;
|
|
7895
|
+
this.keysByLen = new Map;
|
|
7896
|
+
return { hit, miss, badKey };
|
|
7897
|
+
}
|
|
7898
|
+
}
|
|
7899
|
+
|
|
7949
7900
|
// src/renderer.js
|
|
7950
7901
|
class Renderer {
|
|
7951
7902
|
constructor(comps) {
|
|
@@ -8150,6 +8101,8 @@ function renderExamples(normalized, env, { name = null, title = null, view = nul
|
|
|
8150
8101
|
error
|
|
8151
8102
|
}));
|
|
8152
8103
|
}
|
|
8104
|
+
if (items.length === 0)
|
|
8105
|
+
continue;
|
|
8153
8106
|
sections.push(new RenderedSection({
|
|
8154
8107
|
title: section.title,
|
|
8155
8108
|
description: section.description,
|
|
@@ -8162,43 +8115,6 @@ var init_render2 = __esm(() => {
|
|
|
8162
8115
|
init_render();
|
|
8163
8116
|
});
|
|
8164
8117
|
|
|
8165
|
-
// tools/core/doctor.js
|
|
8166
|
-
function runDoctor(normalized, env) {
|
|
8167
|
-
const lint = lintComponents(normalized, {
|
|
8168
|
-
LintParseContextClass: env.LintParseContext
|
|
8169
|
-
});
|
|
8170
|
-
const renders = renderExamples(normalized, env);
|
|
8171
|
-
return new DoctorReport({ lint, renders });
|
|
8172
|
-
}
|
|
8173
|
-
var init_doctor = __esm(() => {
|
|
8174
|
-
init_lint();
|
|
8175
|
-
init_render2();
|
|
8176
|
-
});
|
|
8177
|
-
|
|
8178
|
-
// tools/core/list.js
|
|
8179
|
-
function summarize(comp) {
|
|
8180
|
-
const meta = comp.Class.getMetaClass();
|
|
8181
|
-
const fields = [];
|
|
8182
|
-
for (const fieldName in meta.fields) {
|
|
8183
|
-
const f = meta.fields[fieldName];
|
|
8184
|
-
fields.push({ name: fieldName, type: f.type });
|
|
8185
|
-
}
|
|
8186
|
-
return new ComponentSummary({
|
|
8187
|
-
name: comp.name,
|
|
8188
|
-
views: Object.keys(comp.views ?? {}),
|
|
8189
|
-
fields
|
|
8190
|
-
});
|
|
8191
|
-
}
|
|
8192
|
-
function listComponents(normalized, { name = null } = {}) {
|
|
8193
|
-
const comps = normalized.components;
|
|
8194
|
-
const picked = name === null ? comps : comps.filter((c) => c.name === name);
|
|
8195
|
-
return new ComponentList({ items: picked.map(summarize) });
|
|
8196
|
-
}
|
|
8197
|
-
function listExamples(normalized) {
|
|
8198
|
-
return new ExampleIndex({ sections: normalized.sections });
|
|
8199
|
-
}
|
|
8200
|
-
var init_list = () => {};
|
|
8201
|
-
|
|
8202
8118
|
// tools/cli/commands/_registry.js
|
|
8203
8119
|
var exports__registry = {};
|
|
8204
8120
|
__export(exports__registry, {
|
|
@@ -8208,7 +8124,6 @@ var COMMANDS;
|
|
|
8208
8124
|
var init__registry = __esm(() => {
|
|
8209
8125
|
init_describe();
|
|
8210
8126
|
init_docs();
|
|
8211
|
-
init_doctor();
|
|
8212
8127
|
init_list();
|
|
8213
8128
|
init_lint();
|
|
8214
8129
|
init_render2();
|
|
@@ -8257,19 +8172,6 @@ var init__registry = __esm(() => {
|
|
|
8257
8172
|
view: values.view ?? null
|
|
8258
8173
|
}),
|
|
8259
8174
|
exitOn: (result) => result.hasErrors ? 3 : 0
|
|
8260
|
-
},
|
|
8261
|
-
doctor: {
|
|
8262
|
-
describe: "Run lint + render as a smoke test over the module.",
|
|
8263
|
-
defaultFormat: "cli",
|
|
8264
|
-
needsEnv: true,
|
|
8265
|
-
run: (normalized, _parsed, env) => runDoctor(normalized, env),
|
|
8266
|
-
exitOn: (result) => {
|
|
8267
|
-
if (result.lint.hasErrors)
|
|
8268
|
-
return 2;
|
|
8269
|
-
if (result.renders.hasErrors)
|
|
8270
|
-
return 3;
|
|
8271
|
-
return 0;
|
|
8272
|
-
}
|
|
8273
8175
|
}
|
|
8274
8176
|
};
|
|
8275
8177
|
});
|
|
@@ -8396,7 +8298,7 @@ MODULE CONVENTION
|
|
|
8396
8298
|
export function getComponents() // required for all module commands
|
|
8397
8299
|
-> Component[] // results of tutuca's component()
|
|
8398
8300
|
|
|
8399
|
-
export function getExamples() // required for render
|
|
8301
|
+
export function getExamples() // required for render
|
|
8400
8302
|
-> Section | Section[] // single section or an array
|
|
8401
8303
|
where Section = { title: string, description?: string,
|
|
8402
8304
|
items: Example[] }
|
|
@@ -8441,10 +8343,6 @@ COMMANDS (require <module-path>)
|
|
|
8441
8343
|
--view <v> override the example's view name
|
|
8442
8344
|
Exits 3 if any render crashes.
|
|
8443
8345
|
|
|
8444
|
-
doctor
|
|
8445
|
-
lint + render in one pass, producing a combined report. The smoke
|
|
8446
|
-
test invocation for CI. Exits 2 on lint errors, 3 on render crashes.
|
|
8447
|
-
|
|
8448
8346
|
COMMANDS (no module required)
|
|
8449
8347
|
help [command]
|
|
8450
8348
|
Without [command]: prints this full reference.
|
|
@@ -8458,8 +8356,8 @@ COMMANDS (no module required)
|
|
|
8458
8356
|
GLOBAL FLAGS
|
|
8459
8357
|
-f, --format <cli|md|json|html>
|
|
8460
8358
|
Output format. Defaults per command:
|
|
8461
|
-
info, list, examples, lint
|
|
8462
|
-
docs, render
|
|
8359
|
+
info, list, examples, lint -> cli
|
|
8360
|
+
docs, render -> md
|
|
8463
8361
|
html is only supported by render.
|
|
8464
8362
|
json is supported by every command and serializes the result
|
|
8465
8363
|
class directly — useful for piping into other tools or agents.
|
|
@@ -8493,8 +8391,9 @@ EXAMPLES
|
|
|
8493
8391
|
# Render a single example
|
|
8494
8392
|
tutuca ./src/components.js render Button --title "Disabled state"
|
|
8495
8393
|
|
|
8496
|
-
#
|
|
8497
|
-
tutuca ./src/components.js
|
|
8394
|
+
# Post-edit verification: lint, then render the example you changed
|
|
8395
|
+
tutuca ./src/components.js lint
|
|
8396
|
+
tutuca ./src/components.js render --title "Disabled state"
|
|
8498
8397
|
`;
|
|
8499
8398
|
async function run2(argv) {
|
|
8500
8399
|
const target = argv?.[0];
|
|
@@ -8532,9 +8431,16 @@ import { parseArgs as parseArgs2 } from "node:util";
|
|
|
8532
8431
|
// tools/cli/env.js
|
|
8533
8432
|
init_anode();
|
|
8534
8433
|
init_lint_check();
|
|
8535
|
-
import { JSDOM } from "jsdom";
|
|
8434
|
+
import { JSDOM, VirtualConsole } from "jsdom";
|
|
8536
8435
|
async function createNodeEnv() {
|
|
8537
|
-
const
|
|
8436
|
+
const virtualConsole = new VirtualConsole;
|
|
8437
|
+
virtualConsole.forwardTo(console, { jsdomErrors: "none" });
|
|
8438
|
+
virtualConsole.on("jsdomError", (err) => {
|
|
8439
|
+
if (err?.message?.includes("Could not parse CSS stylesheet"))
|
|
8440
|
+
return;
|
|
8441
|
+
console.error(err.message);
|
|
8442
|
+
});
|
|
8443
|
+
const dom = new JSDOM("<!DOCTYPE html><html><head></head><body></body></html>", { virtualConsole });
|
|
8538
8444
|
const { document: document2, Text, Comment } = dom.window;
|
|
8539
8445
|
globalThis.document = document2;
|
|
8540
8446
|
|
|
@@ -8664,10 +8570,6 @@ function lintIdToMessage(id, info) {
|
|
|
8664
8570
|
return `'${info.name}' exists as method — use with '.' prefix${fmtEventSuffix(info)}`;
|
|
8665
8571
|
case "FIELD_VAL_NOT_DEFINED":
|
|
8666
8572
|
return `Field '.${info.name}' is not defined${fmtOriginSuffix(info)}`;
|
|
8667
|
-
case "COMPUTED_VAL_NOT_DEFINED":
|
|
8668
|
-
return `Computed property '$${info.name}' is not defined${fmtOriginSuffix(info)}`;
|
|
8669
|
-
case "COMPUTED_NOT_REFERENCED":
|
|
8670
|
-
return `Computed property '$${info.name}' is defined but not referenced`;
|
|
8671
8573
|
case "DUPLICATE_ATTR_DEFINITION": {
|
|
8672
8574
|
const sources = info.sources?.length ? ` (${info.sources.join(", ")})` : "";
|
|
8673
8575
|
const tag = info.tag ? ` on <${String(info.tag).toLowerCase()}>` : "";
|
|
@@ -8809,26 +8711,13 @@ function fmtRenderBatch(batch) {
|
|
|
8809
8711
|
return lines.join(`
|
|
8810
8712
|
`);
|
|
8811
8713
|
}
|
|
8812
|
-
function fmtDoctor(rep) {
|
|
8813
|
-
const lines = [];
|
|
8814
|
-
lines.push("== lint ==");
|
|
8815
|
-
lines.push(fmtLintReport(rep.lint));
|
|
8816
|
-
lines.push("");
|
|
8817
|
-
lines.push("== renders ==");
|
|
8818
|
-
lines.push(fmtRenderBatch(rep.renders));
|
|
8819
|
-
lines.push("");
|
|
8820
|
-
lines.push(`Result: ${rep.ok ? "OK" : "FAIL"}`);
|
|
8821
|
-
return lines.join(`
|
|
8822
|
-
`);
|
|
8823
|
-
}
|
|
8824
8714
|
var { supports, format } = makeFormatter("cli", {
|
|
8825
8715
|
ModuleInfo: fmtModuleInfo,
|
|
8826
8716
|
ComponentList: fmtComponentList,
|
|
8827
8717
|
ExampleIndex: fmtExampleIndex,
|
|
8828
8718
|
ComponentDocs: fmtComponentDocs,
|
|
8829
8719
|
LintReport: fmtLintReport,
|
|
8830
|
-
RenderBatch: fmtRenderBatch
|
|
8831
|
-
DoctorReport: fmtDoctor
|
|
8720
|
+
RenderBatch: fmtRenderBatch
|
|
8832
8721
|
});
|
|
8833
8722
|
|
|
8834
8723
|
// tools/format/md.js
|
|
@@ -9004,8 +8893,7 @@ var { supports: supports3, format: format3 } = makeFormatter("json", {
|
|
|
9004
8893
|
ExampleIndex: fmtJson,
|
|
9005
8894
|
ComponentDocs: fmtJson,
|
|
9006
8895
|
LintReport: fmtJson,
|
|
9007
|
-
RenderBatch: fmtJson
|
|
9008
|
-
DoctorReport: fmtJson
|
|
8896
|
+
RenderBatch: fmtJson
|
|
9009
8897
|
});
|
|
9010
8898
|
|
|
9011
8899
|
// tools/format/html.js
|