@weapp-vite/miniprogram-automator 1.2.23 → 1.4.0
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 +96 -0
- package/dist/index.d.mts +76 -8
- package/dist/index.mjs +996 -212
- package/dist/{launch-CSjvON-f.mjs → launch-ElaGbFxh.mjs} +2373 -621
- package/dist/operation.d.mts +64 -0
- package/dist/operation.mjs +233 -0
- package/package.json +15 -4
|
@@ -8,7 +8,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
8
8
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
9
9
|
var __getProtoOf = Object.getPrototypeOf;
|
|
10
10
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
11
|
-
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
11
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod, mod.exports), cb = null), mod.exports);
|
|
12
12
|
var __exportAll = (all, no_symbols) => {
|
|
13
13
|
let target = {};
|
|
14
14
|
for (var name in all) __defProp(target, name, {
|
|
@@ -58,6 +58,41 @@ function createAppInstance(definition) {
|
|
|
58
58
|
return instance;
|
|
59
59
|
}
|
|
60
60
|
//#endregion
|
|
61
|
+
//#region ../../mpcore/packages/simulator/src/host/attachmentBindingUpdates.ts
|
|
62
|
+
const bindingUpdates = /* @__PURE__ */ new WeakMap();
|
|
63
|
+
const instanceScopes = /* @__PURE__ */ new WeakMap();
|
|
64
|
+
/** 实例经渲染上下文归属页面,不扩展公开 renderer context 的参数契约。 */
|
|
65
|
+
function bindAttachmentBindingScope(instance, scope) {
|
|
66
|
+
instanceScopes.set(instance, instanceScopes.get(scope) ?? scope);
|
|
67
|
+
}
|
|
68
|
+
/** 仅在挂载回调内同步逻辑绑定,不接管视图提交和 setData 回调。 */
|
|
69
|
+
function runWithAttachmentBindingUpdates(scope, update, callback, value) {
|
|
70
|
+
const previous = bindingUpdates.get(scope);
|
|
71
|
+
const state = previous ?? {
|
|
72
|
+
revision: 0,
|
|
73
|
+
update
|
|
74
|
+
};
|
|
75
|
+
const previousUpdate = state.update;
|
|
76
|
+
state.update = update;
|
|
77
|
+
bindingUpdates.set(scope, state);
|
|
78
|
+
try {
|
|
79
|
+
return callback(value);
|
|
80
|
+
} finally {
|
|
81
|
+
if (previous) state.update = previousUpdate;
|
|
82
|
+
else bindingUpdates.delete(scope);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function getAttachmentBindingRevision(instance) {
|
|
86
|
+
return bindingUpdates.get(instanceScopes.get(instance) ?? instance);
|
|
87
|
+
}
|
|
88
|
+
function synchronizeAttachmentBindings(instance) {
|
|
89
|
+
const state = bindingUpdates.get(instanceScopes.get(instance) ?? instance);
|
|
90
|
+
if (state) {
|
|
91
|
+
state.revision++;
|
|
92
|
+
state.update();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
61
96
|
//#region ../../mpcore/packages/simulator/src/runtime/componentInstance/shared.ts
|
|
62
97
|
const ARRAY_INDEX_PATH_RE$1 = /\[(\d+)\]/g;
|
|
63
98
|
const ARRAY_INDEX_SEGMENT_RE$1 = /^\d+$/;
|
|
@@ -128,11 +163,14 @@ function runPropertyObservers(definition, instance, changedKeys, previousPropert
|
|
|
128
163
|
const changedRoots = new Set(changedKeys.map((key) => parseDataPath$1(key)[0]));
|
|
129
164
|
for (const changedKey of Object.keys(propOptions)) {
|
|
130
165
|
if (!changedRoots.has(changedKey)) continue;
|
|
166
|
+
const value = instance.properties[changedKey];
|
|
167
|
+
if ((value === null || typeof value !== "object") && Object.hasOwn(previousProperties, changedKey) && Object.is(value, previousProperties[changedKey])) continue;
|
|
131
168
|
const option = propOptions[changedKey];
|
|
132
169
|
if (!option || typeof option !== "object" || Array.isArray(option)) continue;
|
|
133
170
|
const observer = typeof option.observer === "string" ? instance[option.observer] : option.observer;
|
|
134
171
|
if (typeof observer !== "function") continue;
|
|
135
|
-
|
|
172
|
+
const changedPath = parseDataPath$1(changedKeys.find((key) => parseDataPath$1(key)[0] === changedKey)).map((segment) => isArrayIndexSegment$1(segment) ? Number(segment) : segment);
|
|
173
|
+
observer.call(instance, value, previousProperties[changedKey], changedPath);
|
|
136
174
|
}
|
|
137
175
|
}
|
|
138
176
|
function normalizeObserverPattern(pattern) {
|
|
@@ -343,7 +381,6 @@ function resolveInitialProperties(definition, properties) {
|
|
|
343
381
|
if (option && typeof option === "object" && !Array.isArray(option) && "value" in option) resolved[key] = resolvePropertyDefaultValue(option, definition);
|
|
344
382
|
else resolved[key] = cloneValue$1(resolveDefaultValueByType(normalizePropertyType(option)));
|
|
345
383
|
}
|
|
346
|
-
for (const [key, value] of Object.entries(properties)) if (!(key in resolved)) resolved[key] = value;
|
|
347
384
|
return resolved;
|
|
348
385
|
}
|
|
349
386
|
//#endregion
|
|
@@ -743,7 +780,7 @@ const basename = function(p, extension) {
|
|
|
743
780
|
}
|
|
744
781
|
return extension && lastSegment.endsWith(extension) ? lastSegment.slice(0, -extension.length) : lastSegment;
|
|
745
782
|
};
|
|
746
|
-
const parse$
|
|
783
|
+
const parse$3 = function(p) {
|
|
747
784
|
const root = _PATH_ROOT_RE.exec(p)?.[0]?.replace(/\\/g, "/") || "";
|
|
748
785
|
const base = basename(p);
|
|
749
786
|
const extension = extname(base);
|
|
@@ -769,7 +806,7 @@ const _path = {
|
|
|
769
806
|
matchesGlob,
|
|
770
807
|
normalize,
|
|
771
808
|
normalizeString,
|
|
772
|
-
parse: parse$
|
|
809
|
+
parse: parse$3,
|
|
773
810
|
relative,
|
|
774
811
|
resolve,
|
|
775
812
|
sep: "/",
|
|
@@ -804,11 +841,11 @@ const opposite = {
|
|
|
804
841
|
function definitions(instance) {
|
|
805
842
|
return Object.entries(instance.__definition__?.relations ?? {});
|
|
806
843
|
}
|
|
807
|
-
function includesBehavior(behaviors, target) {
|
|
808
|
-
return Array.isArray(behaviors) && behaviors.some((behavior) => behavior === target || behavior && typeof behavior === "object" && includesBehavior(behavior.behaviors, target));
|
|
844
|
+
function includesBehavior$1(behaviors, target) {
|
|
845
|
+
return Array.isArray(behaviors) && behaviors.some((behavior) => behavior === target || behavior && typeof behavior === "object" && includesBehavior$1(behavior.behaviors, target));
|
|
809
846
|
}
|
|
810
847
|
function matches(source, key, relation, target) {
|
|
811
|
-
if (relation.target) return includesBehavior(target.__definition__?.behaviors, relation.target);
|
|
848
|
+
if (relation.target) return includesBehavior$1(target.__definition__?.behaviors, relation.target);
|
|
812
849
|
const targetPath = key.startsWith("/") ? key.slice(1) : posix.join(posix.dirname(String(source.is)), key);
|
|
813
850
|
return posix.normalize(targetPath) === target.is;
|
|
814
851
|
}
|
|
@@ -882,29 +919,24 @@ function detachComponentRelations(instances) {
|
|
|
882
919
|
//#region ../../mpcore/packages/simulator/src/runtime/componentInstance/index.ts
|
|
883
920
|
function createComponentInstance(options) {
|
|
884
921
|
const definition = normalizeComponentDefinition(options.definition);
|
|
885
|
-
const inputProperties = resolveInitialProperties(definition, options.properties ?? {});
|
|
886
922
|
const data = {
|
|
887
923
|
...resolveInitialData$1(definition),
|
|
888
|
-
...
|
|
924
|
+
...resolveInitialProperties(definition, options.properties ?? {})
|
|
889
925
|
};
|
|
890
926
|
const instance = {
|
|
891
927
|
__definition__: definition,
|
|
892
928
|
data,
|
|
893
929
|
__propertySnapshots__: {},
|
|
894
|
-
properties:
|
|
895
|
-
...data,
|
|
896
|
-
...inputProperties
|
|
897
|
-
},
|
|
930
|
+
properties: data,
|
|
898
931
|
getRelationNodes(key) {
|
|
899
932
|
return getComponentRelationNodes(instance, key);
|
|
900
933
|
},
|
|
901
934
|
setData(patch, callback) {
|
|
902
935
|
const changedKeys = Object.keys(patch);
|
|
903
|
-
const
|
|
904
|
-
const propertyKeys = dataKeys.filter((key) => Object.hasOwn(definition.properties ?? {}, key));
|
|
936
|
+
const propertyKeys = [...new Set(changedKeys.map((key) => parseDataPath$1(key)[0]))].filter((key) => Object.hasOwn(definition.properties ?? {}, key));
|
|
905
937
|
const previousProperties = Object.fromEntries(propertyKeys.map((key) => [key, cloneValue$1(instance.properties[key])]));
|
|
906
938
|
for (const [key, value] of Object.entries(patch)) assignByPath$1(instance.data, key, value);
|
|
907
|
-
|
|
939
|
+
synchronizeAttachmentBindings(instance);
|
|
908
940
|
runComponentObservers(definition, instance, changedKeys, previousProperties);
|
|
909
941
|
if (options.requestRender) options.requestRender(callback);
|
|
910
942
|
else callback?.();
|
|
@@ -946,8 +978,11 @@ const componentPageInstances = /* @__PURE__ */ new WeakSet();
|
|
|
946
978
|
function isComponentPageAttaching(instance) {
|
|
947
979
|
return attachingInstances.has(instance);
|
|
948
980
|
}
|
|
949
|
-
function registerComponentPageAttachment(definition,
|
|
950
|
-
definitionAttachments.set(definition,
|
|
981
|
+
function registerComponentPageAttachment(definition, created, attached) {
|
|
982
|
+
definitionAttachments.set(definition, {
|
|
983
|
+
created,
|
|
984
|
+
attached
|
|
985
|
+
});
|
|
951
986
|
}
|
|
952
987
|
function bindComponentPageAttachment(instance, definition) {
|
|
953
988
|
const attach = definitionAttachments.get(definition);
|
|
@@ -958,13 +993,14 @@ function bindComponentPageAttachment(instance, definition) {
|
|
|
958
993
|
if (typeof options?.styleIsolation === "string") instanceStyleIsolation.set(instance, options.styleIsolation);
|
|
959
994
|
}
|
|
960
995
|
}
|
|
961
|
-
function attachComponentPage(instance) {
|
|
996
|
+
function attachComponentPage(instance, updateBindings) {
|
|
962
997
|
const attach = instanceAttachments.get(instance);
|
|
963
998
|
if (!attach) return false;
|
|
964
999
|
instanceAttachments.delete(instance);
|
|
965
1000
|
attachingInstances.add(instance);
|
|
966
1001
|
try {
|
|
967
|
-
attach.
|
|
1002
|
+
attach.created(instance);
|
|
1003
|
+
runWithAttachmentBindingUpdates(instance, updateBindings, attach.attached, instance);
|
|
968
1004
|
} finally {
|
|
969
1005
|
attachingInstances.delete(instance);
|
|
970
1006
|
}
|
|
@@ -1114,6 +1150,7 @@ function createPageInstance(route, definition, options = {}, pageState = {}) {
|
|
|
1114
1150
|
const rootKey = parseDataPath(key)[0];
|
|
1115
1151
|
if (rootKey) instance.properties[rootKey] = instance.data[rootKey];
|
|
1116
1152
|
}
|
|
1153
|
+
synchronizeAttachmentBindings(instance);
|
|
1117
1154
|
if (pageState.requestRender) pageState.requestRender(callback);
|
|
1118
1155
|
else callback?.();
|
|
1119
1156
|
}
|
|
@@ -1126,6 +1163,287 @@ function createPageInstance(route, definition, options = {}, pageState = {}) {
|
|
|
1126
1163
|
return instance;
|
|
1127
1164
|
}
|
|
1128
1165
|
//#endregion
|
|
1166
|
+
//#region ../../mpcore/packages/simulator/src/view/eventBindingParser.ts
|
|
1167
|
+
const LEGACY_EVENT_NAME_RE = /^\w+$/;
|
|
1168
|
+
const EVENT_BINDING_PREFIXES = [
|
|
1169
|
+
{
|
|
1170
|
+
prefix: "capture-bind:",
|
|
1171
|
+
priority: 0,
|
|
1172
|
+
stopAfter: false,
|
|
1173
|
+
phase: "capture"
|
|
1174
|
+
},
|
|
1175
|
+
{
|
|
1176
|
+
prefix: "capture-catch:",
|
|
1177
|
+
priority: 0,
|
|
1178
|
+
stopAfter: true,
|
|
1179
|
+
phase: "capture"
|
|
1180
|
+
},
|
|
1181
|
+
{
|
|
1182
|
+
prefix: "capture-bind",
|
|
1183
|
+
priority: 1,
|
|
1184
|
+
stopAfter: false,
|
|
1185
|
+
phase: "capture"
|
|
1186
|
+
},
|
|
1187
|
+
{
|
|
1188
|
+
prefix: "capture-catch",
|
|
1189
|
+
priority: 1,
|
|
1190
|
+
stopAfter: true,
|
|
1191
|
+
phase: "capture"
|
|
1192
|
+
},
|
|
1193
|
+
{
|
|
1194
|
+
prefix: "bind:",
|
|
1195
|
+
priority: 0,
|
|
1196
|
+
stopAfter: false,
|
|
1197
|
+
phase: "bubble"
|
|
1198
|
+
},
|
|
1199
|
+
{
|
|
1200
|
+
prefix: "catch:",
|
|
1201
|
+
priority: 0,
|
|
1202
|
+
stopAfter: true,
|
|
1203
|
+
phase: "bubble"
|
|
1204
|
+
},
|
|
1205
|
+
{
|
|
1206
|
+
prefix: "bind",
|
|
1207
|
+
priority: 1,
|
|
1208
|
+
stopAfter: false,
|
|
1209
|
+
phase: "bubble"
|
|
1210
|
+
},
|
|
1211
|
+
{
|
|
1212
|
+
prefix: "catch",
|
|
1213
|
+
priority: 1,
|
|
1214
|
+
stopAfter: true,
|
|
1215
|
+
phase: "bubble"
|
|
1216
|
+
}
|
|
1217
|
+
];
|
|
1218
|
+
function parseEventBinding(attributeName, method) {
|
|
1219
|
+
const definition = EVENT_BINDING_PREFIXES.find((item) => attributeName.startsWith(item.prefix));
|
|
1220
|
+
if (!definition) return null;
|
|
1221
|
+
const eventName = attributeName.slice(definition.prefix.length);
|
|
1222
|
+
if (!eventName || !definition.prefix.endsWith(":") && !LEGACY_EVENT_NAME_RE.test(eventName)) return null;
|
|
1223
|
+
return {
|
|
1224
|
+
eventName,
|
|
1225
|
+
method,
|
|
1226
|
+
phase: definition.phase,
|
|
1227
|
+
priority: definition.priority,
|
|
1228
|
+
stopAfter: definition.stopAfter
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1231
|
+
function collectEventBindings(attributes = {}, includeCapture = true) {
|
|
1232
|
+
const eventBindings = /* @__PURE__ */ new Map();
|
|
1233
|
+
let captureEventBindings;
|
|
1234
|
+
const priorities = /* @__PURE__ */ new Map();
|
|
1235
|
+
for (const [attributeName, method] of Object.entries(attributes)) {
|
|
1236
|
+
const candidate = parseEventBinding(attributeName, method);
|
|
1237
|
+
if (!candidate || !includeCapture && candidate.phase === "capture") continue;
|
|
1238
|
+
const eventPriorities = priorities.get(candidate.eventName) ?? {};
|
|
1239
|
+
if (candidate.priority < (eventPriorities[candidate.phase] ?? -1)) continue;
|
|
1240
|
+
(candidate.phase === "bubble" ? eventBindings : captureEventBindings ??= /* @__PURE__ */ new Map()).set(candidate.eventName, {
|
|
1241
|
+
method: candidate.method,
|
|
1242
|
+
stopAfter: candidate.stopAfter
|
|
1243
|
+
});
|
|
1244
|
+
eventPriorities[candidate.phase] = candidate.priority;
|
|
1245
|
+
priorities.set(candidate.eventName, eventPriorities);
|
|
1246
|
+
}
|
|
1247
|
+
return {
|
|
1248
|
+
eventBindings,
|
|
1249
|
+
captureEventBindings
|
|
1250
|
+
};
|
|
1251
|
+
}
|
|
1252
|
+
/** 单事件查询只保留命中的绑定,原生交互不构造整张事件表。 */
|
|
1253
|
+
function resolveEventBindingPhases(attributes, eventName, includeCapture = true) {
|
|
1254
|
+
if (!attributes) return null;
|
|
1255
|
+
let bindings = null;
|
|
1256
|
+
let bubblePriority = -1;
|
|
1257
|
+
let capturePriority = -1;
|
|
1258
|
+
for (const [attributeName, method] of Object.entries(attributes)) {
|
|
1259
|
+
const candidate = parseEventBinding(attributeName, method);
|
|
1260
|
+
if (!candidate || candidate.eventName !== eventName || !includeCapture && candidate.phase === "capture") continue;
|
|
1261
|
+
const priority = candidate.phase === "bubble" ? bubblePriority : capturePriority;
|
|
1262
|
+
if (candidate.priority < priority) continue;
|
|
1263
|
+
bindings ??= {};
|
|
1264
|
+
bindings[candidate.phase] = {
|
|
1265
|
+
method: candidate.method,
|
|
1266
|
+
stopAfter: candidate.stopAfter
|
|
1267
|
+
};
|
|
1268
|
+
if (candidate.phase === "bubble") bubblePriority = candidate.priority;
|
|
1269
|
+
else capturePriority = candidate.priority;
|
|
1270
|
+
}
|
|
1271
|
+
return bindings;
|
|
1272
|
+
}
|
|
1273
|
+
//#endregion
|
|
1274
|
+
//#region ../../mpcore/packages/simulator/src/view/nodeDataset.ts
|
|
1275
|
+
const DATASET_NAME_RE = /-([a-z])/g;
|
|
1276
|
+
function isDatasetAttribute(attributeName) {
|
|
1277
|
+
return attributeName.startsWith("data-") && !attributeName.startsWith("data-sim-");
|
|
1278
|
+
}
|
|
1279
|
+
function toDatasetKey(attributeName) {
|
|
1280
|
+
return attributeName.slice(5).replace(DATASET_NAME_RE, (_match, char) => char.toUpperCase());
|
|
1281
|
+
}
|
|
1282
|
+
function collectNodeDataset(node) {
|
|
1283
|
+
if (node.dataset) return { ...node.dataset };
|
|
1284
|
+
const dataset = {};
|
|
1285
|
+
for (const [key, value] of Object.entries(node.attribs ?? {})) if (isDatasetAttribute(key)) dataset[toDatasetKey(key)] = value;
|
|
1286
|
+
return dataset;
|
|
1287
|
+
}
|
|
1288
|
+
//#endregion
|
|
1289
|
+
//#region ../../mpcore/packages/simulator/src/view/componentEvent.ts
|
|
1290
|
+
const eventNodes = /* @__PURE__ */ new WeakMap();
|
|
1291
|
+
/** 原生默认行为读取声明所有者与原始属性,避免组件根折叠覆盖宿主边界。 */
|
|
1292
|
+
function getNativeNodeOwner(node) {
|
|
1293
|
+
const entry = eventNodes.get(node);
|
|
1294
|
+
return entry ? {
|
|
1295
|
+
scopeId: entry.scope.getScopeId(),
|
|
1296
|
+
target: entry.target
|
|
1297
|
+
} : void 0;
|
|
1298
|
+
}
|
|
1299
|
+
/** 原生冒泡包含折叠的宿主绑定;catch 只截断其后的绑定和祖先。 */
|
|
1300
|
+
function visitNativeNodeEventBindings(node, eventName, visit) {
|
|
1301
|
+
const collect = (entry) => {
|
|
1302
|
+
const binding = entry.bindings ? entry.bindings.eventBindings?.get(eventName) : resolveEventBindingPhases(entry.target.attribs, eventName, false)?.bubble;
|
|
1303
|
+
if (binding) visit(entry.scope.getScopeId(), entry.target, binding);
|
|
1304
|
+
return binding?.stopAfter ?? false;
|
|
1305
|
+
};
|
|
1306
|
+
const entry = eventNodes.get(node);
|
|
1307
|
+
if (!entry) {
|
|
1308
|
+
const binding = resolveEventBindingPhases(node.attribs, eventName, false)?.bubble;
|
|
1309
|
+
if (binding) visit(node.attribs?.["data-sim-scope"] ?? null, node, binding);
|
|
1310
|
+
return binding?.stopAfter ?? false;
|
|
1311
|
+
}
|
|
1312
|
+
if (collect(entry)) return true;
|
|
1313
|
+
for (const host of entry.hosts ?? []) if (collect(eventNodes.get(host))) return true;
|
|
1314
|
+
return false;
|
|
1315
|
+
}
|
|
1316
|
+
/** 在构造子树之前建立父链,created/observer 中的事件也能访问声明树。 */
|
|
1317
|
+
function registerComponentEventNode(node, scope, parent) {
|
|
1318
|
+
node.parent = parent ?? null;
|
|
1319
|
+
eventNodes.set(node, {
|
|
1320
|
+
scope,
|
|
1321
|
+
target: node
|
|
1322
|
+
});
|
|
1323
|
+
}
|
|
1324
|
+
/** 宿主与作用域共享同一份分阶段绑定,eventBindings 仍是原有的冒泡存储。 */
|
|
1325
|
+
function bindComponentEventHost(node) {
|
|
1326
|
+
const bindings = collectEventBindings(node.attribs);
|
|
1327
|
+
eventNodes.get(node).bindings = bindings;
|
|
1328
|
+
return bindings;
|
|
1329
|
+
}
|
|
1330
|
+
/** 渲染会把宿主折叠进模板根;事件仍保留两层独立的绑定和声明所有者。 */
|
|
1331
|
+
function mergeComponentEventRoot(root, host) {
|
|
1332
|
+
const entry = eventNodes.get(root);
|
|
1333
|
+
if (entry.target === root) entry.target = {
|
|
1334
|
+
attribs: root.attribs,
|
|
1335
|
+
dataset: root.dataset
|
|
1336
|
+
};
|
|
1337
|
+
entry.hosts ??= [];
|
|
1338
|
+
entry.hosts.push(host);
|
|
1339
|
+
root.parent = host.parent;
|
|
1340
|
+
}
|
|
1341
|
+
/** 按渲染完成后的实际宿主父链排序;输入只包含本轮存活的组件作用域。 */
|
|
1342
|
+
function orderComponentAttachmentScopes(scopeIds, componentScopes) {
|
|
1343
|
+
const hostScopes = /* @__PURE__ */ new Map();
|
|
1344
|
+
for (const scopeId of scopeIds) hostScopes.set(componentScopes.get(scopeId).hostNode, scopeId);
|
|
1345
|
+
const ordered = [];
|
|
1346
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1347
|
+
const visit = (node) => {
|
|
1348
|
+
if (!node || visited.has(node)) return;
|
|
1349
|
+
visited.add(node);
|
|
1350
|
+
visit(node.parent);
|
|
1351
|
+
const hosts = eventNodes.get(node)?.hosts;
|
|
1352
|
+
if (hosts) for (let index = hosts.length - 1; index >= 0; index--) visit(hosts[index]);
|
|
1353
|
+
const scopeId = hostScopes.get(node);
|
|
1354
|
+
if (scopeId !== void 0) ordered.push(scopeId);
|
|
1355
|
+
};
|
|
1356
|
+
for (const host of hostScopes.keys()) visit(host);
|
|
1357
|
+
return ordered;
|
|
1358
|
+
}
|
|
1359
|
+
function buildComponentTrigger(componentScopeId, context) {
|
|
1360
|
+
return (instance, eventName, detail, triggerOptions) => {
|
|
1361
|
+
const originScope = context.componentScopes.get(componentScopeId);
|
|
1362
|
+
const origin = originScope?.hostNode;
|
|
1363
|
+
if (!originScope || !origin) return;
|
|
1364
|
+
const bubbles = triggerOptions?.bubbles ?? false;
|
|
1365
|
+
const capturePhase = triggerOptions?.capturePhase ?? false;
|
|
1366
|
+
const composed = triggerOptions?.composed ?? false;
|
|
1367
|
+
const target = {
|
|
1368
|
+
dataset: originScope.dataset ?? collectNodeDataset(origin),
|
|
1369
|
+
id: originScope.hostId ?? ""
|
|
1370
|
+
};
|
|
1371
|
+
const mark = instance.__lastInteractionEvent__?.mark;
|
|
1372
|
+
const listeners = [];
|
|
1373
|
+
const collect = (entry, isOrigin) => {
|
|
1374
|
+
if (!composed && entry.scope.getScopeId() !== originScope.listenerScopeId) return false;
|
|
1375
|
+
const bindings = entry.bindings ? {
|
|
1376
|
+
bubble: entry.bindings.eventBindings?.get(eventName),
|
|
1377
|
+
capture: entry.bindings.captureEventBindings?.get(eventName)
|
|
1378
|
+
} : resolveEventBindingPhases(entry.target.attribs, eventName);
|
|
1379
|
+
if (bindings?.bubble || bindings?.capture) listeners.push({
|
|
1380
|
+
scope: entry.scope,
|
|
1381
|
+
bindings,
|
|
1382
|
+
currentTarget: isOrigin ? target : {
|
|
1383
|
+
dataset: collectNodeDataset(entry.target),
|
|
1384
|
+
id: entry.target.attribs?.id ?? ""
|
|
1385
|
+
},
|
|
1386
|
+
origin: isOrigin
|
|
1387
|
+
});
|
|
1388
|
+
return true;
|
|
1389
|
+
};
|
|
1390
|
+
let current = origin;
|
|
1391
|
+
while (current) {
|
|
1392
|
+
const entry = eventNodes.get(current);
|
|
1393
|
+
if (entry) {
|
|
1394
|
+
if (!collect(entry, current === origin)) break;
|
|
1395
|
+
let crossedBoundary = false;
|
|
1396
|
+
for (const host of entry.hosts ?? []) if (!collect(eventNodes.get(host), false)) {
|
|
1397
|
+
crossedBoundary = true;
|
|
1398
|
+
break;
|
|
1399
|
+
}
|
|
1400
|
+
if (crossedBoundary) break;
|
|
1401
|
+
}
|
|
1402
|
+
if (!bubbles && !capturePhase) break;
|
|
1403
|
+
current = current.parent;
|
|
1404
|
+
}
|
|
1405
|
+
const handlers = [];
|
|
1406
|
+
let stopped = false;
|
|
1407
|
+
if (capturePhase) for (let index = listeners.length - 1; index >= 0; index--) {
|
|
1408
|
+
const listener = listeners[index];
|
|
1409
|
+
const binding = listener.bindings.capture;
|
|
1410
|
+
if (binding) {
|
|
1411
|
+
handlers.push({
|
|
1412
|
+
scope: listener.scope,
|
|
1413
|
+
binding,
|
|
1414
|
+
currentTarget: listener.currentTarget
|
|
1415
|
+
});
|
|
1416
|
+
if (binding.stopAfter) {
|
|
1417
|
+
stopped = true;
|
|
1418
|
+
break;
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
if (!stopped) for (const listener of listeners) {
|
|
1423
|
+
if (!bubbles && !listener.origin) continue;
|
|
1424
|
+
const binding = listener.bindings.bubble;
|
|
1425
|
+
if (binding) {
|
|
1426
|
+
handlers.push({
|
|
1427
|
+
scope: listener.scope,
|
|
1428
|
+
binding,
|
|
1429
|
+
currentTarget: listener.currentTarget
|
|
1430
|
+
});
|
|
1431
|
+
if (binding.stopAfter) break;
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
for (const { scope, binding, currentTarget } of handlers) scope.getMethod(binding.method)?.({
|
|
1435
|
+
bubbles,
|
|
1436
|
+
capturePhase,
|
|
1437
|
+
composed,
|
|
1438
|
+
currentTarget,
|
|
1439
|
+
detail,
|
|
1440
|
+
mark,
|
|
1441
|
+
target,
|
|
1442
|
+
type: eventName
|
|
1443
|
+
});
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
//#endregion
|
|
1129
1447
|
//#region ../../mpcore/packages/simulator/src/view/conditionalChildren.ts
|
|
1130
1448
|
function selectConditionalChildren(children, evaluate) {
|
|
1131
1449
|
const selected = [];
|
|
@@ -1181,11 +1499,77 @@ function customTabBarHostScope() {
|
|
|
1181
1499
|
};
|
|
1182
1500
|
}
|
|
1183
1501
|
//#endregion
|
|
1502
|
+
//#region ../../mpcore/packages/simulator/src/view/inspectionTree.ts
|
|
1503
|
+
const inspectionChildren = /* @__PURE__ */ new WeakMap();
|
|
1504
|
+
const inspectionParents = /* @__PURE__ */ new WeakMap();
|
|
1505
|
+
const emptyChildren = [];
|
|
1506
|
+
function getInspectionChildren(node) {
|
|
1507
|
+
return inspectionChildren.get(node) ?? node.children ?? emptyChildren;
|
|
1508
|
+
}
|
|
1509
|
+
function getInspectionParent(node) {
|
|
1510
|
+
return inspectionParents.get(node) ?? node.parent ?? null;
|
|
1511
|
+
}
|
|
1512
|
+
function collectRenderedNodes(node, nodes) {
|
|
1513
|
+
if (nodes.has(node)) return;
|
|
1514
|
+
nodes.add(node);
|
|
1515
|
+
for (const child of node.children ?? emptyChildren) collectRenderedNodes(child, nodes);
|
|
1516
|
+
}
|
|
1517
|
+
/** 原生检查器保留未投影声明;可见 DOM、WXML 和事件父链不因此增加节点。 */
|
|
1518
|
+
function registerInspectionTrees(root, pass, scopes) {
|
|
1519
|
+
if (!pass.hasUnprojectedSlots) return;
|
|
1520
|
+
const rendered = /* @__PURE__ */ new Set();
|
|
1521
|
+
collectRenderedNodes(root, rendered);
|
|
1522
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
1523
|
+
for (const [entries, group] of pass.slotDeclarations) {
|
|
1524
|
+
if (scopes.get(group.scopeId)?.hostNode !== group.parent) continue;
|
|
1525
|
+
const host = pass.componentRoots.get(group.scopeId);
|
|
1526
|
+
if (!host) continue;
|
|
1527
|
+
for (const entry of entries) for (const node of pass.renderedSlots.get(entry) ?? emptyChildren) candidates.set(node, host);
|
|
1528
|
+
}
|
|
1529
|
+
const nested = /* @__PURE__ */ new Set();
|
|
1530
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1531
|
+
const indexChildren = (node) => {
|
|
1532
|
+
if (visited.has(node)) return;
|
|
1533
|
+
visited.add(node);
|
|
1534
|
+
for (const child of node.children ?? emptyChildren) {
|
|
1535
|
+
nested.add(child);
|
|
1536
|
+
if (!rendered.has(child)) inspectionParents.set(child, node);
|
|
1537
|
+
indexChildren(child);
|
|
1538
|
+
}
|
|
1539
|
+
};
|
|
1540
|
+
for (const node of candidates.keys()) indexChildren(node);
|
|
1541
|
+
for (const [node, host] of candidates) {
|
|
1542
|
+
if (rendered.has(node) || nested.has(node) || node === host) continue;
|
|
1543
|
+
let children = inspectionChildren.get(host);
|
|
1544
|
+
if (!children) {
|
|
1545
|
+
children = [...host.children ?? emptyChildren];
|
|
1546
|
+
inspectionChildren.set(host, children);
|
|
1547
|
+
}
|
|
1548
|
+
children.push(node);
|
|
1549
|
+
inspectionParents.set(node, host);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
//#endregion
|
|
1184
1553
|
//#region ../../mpcore/packages/simulator/src/view/loopEntries.ts
|
|
1554
|
+
const LOOP_SCOPE_ESCAPE_RE = /[^\w-]/g;
|
|
1555
|
+
function escapeScopeCodeUnit(character) {
|
|
1556
|
+
return `~${character.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
|
1557
|
+
}
|
|
1558
|
+
function encodeLoopCoordinate(value) {
|
|
1559
|
+
return value.replace(LOOP_SCOPE_ESCAPE_RE, escapeScopeCodeUnit);
|
|
1560
|
+
}
|
|
1185
1561
|
function resolveLoopEntries(value) {
|
|
1186
1562
|
if (Array.isArray(value)) return value.map((item, index) => [index, item]);
|
|
1187
1563
|
return value !== null && typeof value === "object" ? Object.entries(value) : [];
|
|
1188
1564
|
}
|
|
1565
|
+
function resolveLoopInstanceSuffix(item, index, key, occurrences) {
|
|
1566
|
+
if (!key || !occurrences) return `:for-${encodeLoopCoordinate(String(index))}`;
|
|
1567
|
+
const value = key === "*this" ? item : item?.[key];
|
|
1568
|
+
const normalized = encodeLoopCoordinate(String(value ?? ""));
|
|
1569
|
+
const occurrence = occurrences.get(normalized) ?? 0;
|
|
1570
|
+
occurrences.set(normalized, occurrence + 1);
|
|
1571
|
+
return `:key-${normalized}${occurrence ? `:duplicate-${occurrence}` : ""}`;
|
|
1572
|
+
}
|
|
1189
1573
|
//#endregion
|
|
1190
1574
|
//#region ../../mpcore/packages/simulator/src/view/renderedTree.ts
|
|
1191
1575
|
/** 在循环展开和组件替换完成后,让父节点关系指向本次渲染树。 */
|
|
@@ -1194,7 +1578,45 @@ function linkRenderedParents(root, parent = null) {
|
|
|
1194
1578
|
for (const child of root.children ?? []) linkRenderedParents(child, root);
|
|
1195
1579
|
}
|
|
1196
1580
|
//#endregion
|
|
1197
|
-
//#region ../../
|
|
1581
|
+
//#region ../../mpcore/packages/simulator/src/view/renderPass.ts
|
|
1582
|
+
const initializedPages = /* @__PURE__ */ new WeakMap();
|
|
1583
|
+
function createRenderPass(propertyUpdate = false, parent) {
|
|
1584
|
+
return {
|
|
1585
|
+
seenComponentScopes: /* @__PURE__ */ new Set(),
|
|
1586
|
+
componentRoots: /* @__PURE__ */ new Map(),
|
|
1587
|
+
slotDeclarations: /* @__PURE__ */ new Map(),
|
|
1588
|
+
renderedSlots: /* @__PURE__ */ new Map(),
|
|
1589
|
+
hasUnprojectedSlots: false,
|
|
1590
|
+
propertyUpdate,
|
|
1591
|
+
bindingUpdate: parent?.bindingUpdate,
|
|
1592
|
+
bindingRevision: parent?.bindingUpdate?.revision ?? 0
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1595
|
+
function createPageRenderPass(page, cache) {
|
|
1596
|
+
const pass = createRenderPass(initializedPages.get(cache)?.has(page) ?? false);
|
|
1597
|
+
pass.bindingUpdate = getAttachmentBindingRevision(page);
|
|
1598
|
+
pass.bindingRevision = pass.bindingUpdate?.revision ?? 0;
|
|
1599
|
+
return pass;
|
|
1600
|
+
}
|
|
1601
|
+
function isRenderPassStale(pass) {
|
|
1602
|
+
return pass.bindingUpdate !== void 0 && pass.bindingUpdate.revision !== pass.bindingRevision;
|
|
1603
|
+
}
|
|
1604
|
+
function markPageTreeConstructed(page, cache) {
|
|
1605
|
+
let pages = initializedPages.get(cache);
|
|
1606
|
+
if (!pages) {
|
|
1607
|
+
pages = /* @__PURE__ */ new WeakSet();
|
|
1608
|
+
initializedPages.set(cache, pages);
|
|
1609
|
+
}
|
|
1610
|
+
pages.add(page);
|
|
1611
|
+
}
|
|
1612
|
+
function registerSlotDeclarations(pass, slots, parent, scopeId) {
|
|
1613
|
+
for (const entries of slots.values()) if (!pass.slotDeclarations.has(entries)) pass.slotDeclarations.set(entries, {
|
|
1614
|
+
parent,
|
|
1615
|
+
scopeId
|
|
1616
|
+
});
|
|
1617
|
+
}
|
|
1618
|
+
//#endregion
|
|
1619
|
+
//#region ../../node_modules/.pnpm/@babel+parser@8.0.7/node_modules/@babel/parser/lib/index.js
|
|
1198
1620
|
var Position = class {
|
|
1199
1621
|
constructor(line, col, index) {
|
|
1200
1622
|
this.line = void 0;
|
|
@@ -9263,7 +9685,11 @@ var StatementParser = class extends ExpressionParser {
|
|
|
9263
9685
|
if (isDeclaration) node.id = this.parseFunctionId(requireId);
|
|
9264
9686
|
this.scope.enter(514);
|
|
9265
9687
|
this.prodParam.enter(functionFlags(isAsync, node.generator));
|
|
9266
|
-
if (!isDeclaration
|
|
9688
|
+
if (!isDeclaration && tokenIsIdentifier(this.state.type)) {
|
|
9689
|
+
this.expressionScope.enter(newExpressionScope());
|
|
9690
|
+
node.id = this.parseFunctionId();
|
|
9691
|
+
this.expressionScope.exit();
|
|
9692
|
+
}
|
|
9267
9693
|
this.parseFunctionParams(node, false);
|
|
9268
9694
|
this.parseFunctionBodyAndFinish(node, isDeclaration ? "FunctionDeclaration" : "FunctionExpression");
|
|
9269
9695
|
this.prodParam.exit();
|
|
@@ -12596,6 +13022,29 @@ var Parser$1 = class extends StatementParser {
|
|
|
12596
13022
|
return result;
|
|
12597
13023
|
}
|
|
12598
13024
|
};
|
|
13025
|
+
function parse$2(input, options) {
|
|
13026
|
+
if (options?.sourceType === "unambiguous") {
|
|
13027
|
+
options = { ...options };
|
|
13028
|
+
try {
|
|
13029
|
+
options.sourceType = "module";
|
|
13030
|
+
const parser = getParser(options, input);
|
|
13031
|
+
const ast = parser.parse();
|
|
13032
|
+
if (parser.sawUnambiguousESM) return ast;
|
|
13033
|
+
if (parser.ambiguousScriptDifferentAst) try {
|
|
13034
|
+
options.sourceType = "script";
|
|
13035
|
+
return getParser(options, input).parse();
|
|
13036
|
+
} catch {}
|
|
13037
|
+
else ast.program.sourceType = "script";
|
|
13038
|
+
return ast;
|
|
13039
|
+
} catch (moduleError) {
|
|
13040
|
+
try {
|
|
13041
|
+
options.sourceType = "script";
|
|
13042
|
+
return getParser(options, input).parse();
|
|
13043
|
+
} catch {}
|
|
13044
|
+
throw moduleError;
|
|
13045
|
+
}
|
|
13046
|
+
} else return getParser(options, input).parse();
|
|
13047
|
+
}
|
|
12599
13048
|
function parseExpression(input, options) {
|
|
12600
13049
|
const parser = getParser(options, input);
|
|
12601
13050
|
if (parser.options.strictMode) parser.state.strict = true;
|
|
@@ -12913,7 +13362,8 @@ function isComponentAttached(instance) {
|
|
|
12913
13362
|
return attachmentStates.get(instance) === "attached";
|
|
12914
13363
|
}
|
|
12915
13364
|
function hasPendingComponentAttachments(instances) {
|
|
12916
|
-
|
|
13365
|
+
for (const instance of instances) if (attachmentStates.get(instance) === "attaching") return true;
|
|
13366
|
+
return false;
|
|
12917
13367
|
}
|
|
12918
13368
|
function flushComponentReady(instances, ready) {
|
|
12919
13369
|
const all = [...instances];
|
|
@@ -12923,19 +13373,71 @@ function flushComponentReady(instances, ready) {
|
|
|
12923
13373
|
for (const instance of pending) ready(instance);
|
|
12924
13374
|
return pending.length > 0;
|
|
12925
13375
|
}
|
|
12926
|
-
function flushComponentAttachments(
|
|
12927
|
-
const pending =
|
|
12928
|
-
for (const
|
|
13376
|
+
function flushComponentAttachments(componentCache, scopeIds, attach) {
|
|
13377
|
+
const pending = /* @__PURE__ */ new Map();
|
|
13378
|
+
for (const scopeId of scopeIds) {
|
|
13379
|
+
const instance = componentCache.get(scopeId);
|
|
13380
|
+
if (!instance) continue;
|
|
13381
|
+
const state = attachmentStates.get(instance);
|
|
13382
|
+
if (state === "attaching") return false;
|
|
13383
|
+
if (!state) pending.set(scopeId, instance);
|
|
13384
|
+
}
|
|
13385
|
+
for (const instance of pending.values()) attachmentStates.set(instance, "attaching");
|
|
12929
13386
|
try {
|
|
12930
|
-
for (const instance of pending)
|
|
12931
|
-
|
|
12932
|
-
|
|
12933
|
-
|
|
13387
|
+
for (const [scopeId, instance] of pending) {
|
|
13388
|
+
if (componentCache.get(scopeId) !== instance) return "restart";
|
|
13389
|
+
let restart;
|
|
13390
|
+
try {
|
|
13391
|
+
restart = attach(instance);
|
|
13392
|
+
} finally {
|
|
13393
|
+
attachmentStates.set(instance, "attached");
|
|
13394
|
+
}
|
|
13395
|
+
if (restart) return "restart";
|
|
12934
13396
|
}
|
|
12935
13397
|
} finally {
|
|
12936
|
-
for (const instance of pending) if (attachmentStates.get(instance) === "attaching") attachmentStates.delete(instance);
|
|
13398
|
+
for (const instance of pending.values()) if (attachmentStates.get(instance) === "attaching") attachmentStates.delete(instance);
|
|
12937
13399
|
}
|
|
12938
|
-
return pending.
|
|
13400
|
+
return pending.size > 0 ? "attached" : false;
|
|
13401
|
+
}
|
|
13402
|
+
//#endregion
|
|
13403
|
+
//#region ../../mpcore/packages/simulator/src/runtime/componentInstance/construction.ts
|
|
13404
|
+
const constructionStates = /* @__PURE__ */ new WeakMap();
|
|
13405
|
+
const constructingInstances = /* @__PURE__ */ new WeakSet();
|
|
13406
|
+
function isComponentConstructing(instance) {
|
|
13407
|
+
return instance !== void 0 && constructingInstances.has(instance);
|
|
13408
|
+
}
|
|
13409
|
+
function hasPendingComponentConstruction(componentCache) {
|
|
13410
|
+
return constructionStates.has(componentCache);
|
|
13411
|
+
}
|
|
13412
|
+
function beginComponentConstruction(componentCache, scopeId, instance) {
|
|
13413
|
+
let state = constructionStates.get(componentCache);
|
|
13414
|
+
if (!state) {
|
|
13415
|
+
state = {
|
|
13416
|
+
depth: 0,
|
|
13417
|
+
created: /* @__PURE__ */ new Map()
|
|
13418
|
+
};
|
|
13419
|
+
constructionStates.set(componentCache, state);
|
|
13420
|
+
}
|
|
13421
|
+
state.depth++;
|
|
13422
|
+
state.created.set(scopeId, instance);
|
|
13423
|
+
constructingInstances.add(instance);
|
|
13424
|
+
}
|
|
13425
|
+
function discardComponentConstruction(componentCache, componentScopes, scopeId) {
|
|
13426
|
+
const state = constructionStates.get(componentCache);
|
|
13427
|
+
const prefix = `${scopeId}/`;
|
|
13428
|
+
for (const [createdScopeId, instance] of state.created) {
|
|
13429
|
+
if (createdScopeId !== scopeId && !createdScopeId.startsWith(prefix)) continue;
|
|
13430
|
+
if (componentCache.get(createdScopeId) === instance) {
|
|
13431
|
+
componentCache.delete(createdScopeId);
|
|
13432
|
+
componentScopes.delete(createdScopeId);
|
|
13433
|
+
}
|
|
13434
|
+
state.created.delete(createdScopeId);
|
|
13435
|
+
}
|
|
13436
|
+
}
|
|
13437
|
+
function finishComponentConstruction(componentCache, instance) {
|
|
13438
|
+
constructingInstances.delete(instance);
|
|
13439
|
+
const state = constructionStates.get(componentCache);
|
|
13440
|
+
if (--state.depth === 0) constructionStates.delete(componentCache);
|
|
12939
13441
|
}
|
|
12940
13442
|
//#endregion
|
|
12941
13443
|
//#region ../../mpcore/packages/simulator/src/runtime/componentInstance/discardedReady.ts
|
|
@@ -12958,6 +13460,61 @@ function flushDiscardedComponentReady(cache, pageScopeId, ready) {
|
|
|
12958
13460
|
if (!pending.size) discardedReady.delete(cache);
|
|
12959
13461
|
}
|
|
12960
13462
|
//#endregion
|
|
13463
|
+
//#region ../../mpcore/packages/simulator/src/runtime/componentInstance/propertyBindings.ts
|
|
13464
|
+
const consumedPageChanges = /* @__PURE__ */ new WeakMap();
|
|
13465
|
+
function syncComponentProperties(instance, definition, nextProperties, bindingExpressions, changedPageKeys, beforeObservers) {
|
|
13466
|
+
const freshPageChanges = changedPageKeys.length > 0 && consumedPageChanges.get(instance) !== changedPageKeys;
|
|
13467
|
+
if (freshPageChanges) consumedPageChanges.set(instance, changedPageKeys);
|
|
13468
|
+
const changedRootKeys = [];
|
|
13469
|
+
const previousProperties = {};
|
|
13470
|
+
for (const [key, value] of Object.entries(nextProperties)) {
|
|
13471
|
+
if (!Object.hasOwn(definition.properties ?? {}, key)) continue;
|
|
13472
|
+
const nextValue = normalizeComponentPropertyValue(definition, key, value);
|
|
13473
|
+
const bindingExpression = bindingExpressions[key];
|
|
13474
|
+
const bindingAffected = freshPageChanges && !!bindingExpression && changedPageKeys.some((changedKey) => {
|
|
13475
|
+
return changedKey === bindingExpression || changedKey.startsWith(`${bindingExpression}.`) || changedKey.startsWith(`${bindingExpression}[`);
|
|
13476
|
+
});
|
|
13477
|
+
const previousSnapshot = instance.__propertySnapshots?.[key];
|
|
13478
|
+
if (hasComponentPropertyValueChanged(instance.properties[key], previousSnapshot, nextValue, bindingAffected)) {
|
|
13479
|
+
previousProperties[key] = instance.properties[key];
|
|
13480
|
+
const deliveredValue = cloneValue$1(nextValue);
|
|
13481
|
+
instance.properties[key] = deliveredValue;
|
|
13482
|
+
changedRootKeys.push(key);
|
|
13483
|
+
}
|
|
13484
|
+
instance.__propertySnapshots ??= {};
|
|
13485
|
+
instance.__propertySnapshots[key] = cloneValue$1(nextValue);
|
|
13486
|
+
}
|
|
13487
|
+
if (changedRootKeys.length === 0) return;
|
|
13488
|
+
beforeObservers?.(instance, "properties");
|
|
13489
|
+
runComponentObservers(definition, instance, changedRootKeys, previousProperties);
|
|
13490
|
+
}
|
|
13491
|
+
//#endregion
|
|
13492
|
+
//#region ../../mpcore/packages/simulator/src/runtime/componentInstance/reconcileRemoved.ts
|
|
13493
|
+
/** 用户卸载钩子失败也要完成关系与缓存收尾,避免下一次渲染重复卸载同一实例。 */
|
|
13494
|
+
function reconcileRemovedComponents(cache, scopes, activeScopeIds, pageScopeId) {
|
|
13495
|
+
const removed = [...cache].filter(([scopeId]) => scopeId.startsWith(`${pageScopeId}/`) && !activeScopeIds.has(scopeId));
|
|
13496
|
+
let failure;
|
|
13497
|
+
for (const [scopeId, instance] of removed) try {
|
|
13498
|
+
if (isComponentAttached(instance)) runComponentLifecycle(instance, "detached");
|
|
13499
|
+
else scheduleDiscardedComponentReady(cache, scopeId, instance);
|
|
13500
|
+
} catch (error) {
|
|
13501
|
+
failure ??= { error };
|
|
13502
|
+
}
|
|
13503
|
+
let relationsChanged = false;
|
|
13504
|
+
try {
|
|
13505
|
+
relationsChanged = syncComponentRelations(cache, activeScopeIds, pageScopeId);
|
|
13506
|
+
} catch (error) {
|
|
13507
|
+
failure ??= { error };
|
|
13508
|
+
} finally {
|
|
13509
|
+
for (const [scopeId] of removed) {
|
|
13510
|
+
cache.delete(scopeId);
|
|
13511
|
+
scopes.delete(scopeId);
|
|
13512
|
+
}
|
|
13513
|
+
}
|
|
13514
|
+
if (failure) throw failure.error;
|
|
13515
|
+
return relationsChanged;
|
|
13516
|
+
}
|
|
13517
|
+
//#endregion
|
|
12961
13518
|
//#region ../../mpcore/packages/simulator/src/runtime/pageLifecycle.ts
|
|
12962
13519
|
const loadingPages = /* @__PURE__ */ new WeakSet();
|
|
12963
13520
|
function isPageBeforeReady(page) {
|
|
@@ -13047,97 +13604,9 @@ function createPluginArtifactSource(fallback, miniprogramRootPath, plugins) {
|
|
|
13047
13604
|
};
|
|
13048
13605
|
}
|
|
13049
13606
|
//#endregion
|
|
13050
|
-
//#region
|
|
13051
|
-
|
|
13052
|
-
|
|
13053
|
-
return attributeName.startsWith("data-") && !attributeName.startsWith("data-sim-");
|
|
13054
|
-
}
|
|
13055
|
-
function toDatasetKey(attributeName) {
|
|
13056
|
-
return attributeName.slice(5).replace(DATASET_NAME_RE, (_match, char) => char.toUpperCase());
|
|
13057
|
-
}
|
|
13058
|
-
function collectNodeDataset(node) {
|
|
13059
|
-
if (node.dataset) return { ...node.dataset };
|
|
13060
|
-
const dataset = {};
|
|
13061
|
-
for (const [key, value] of Object.entries(node.attribs ?? {})) if (isDatasetAttribute(key)) dataset[toDatasetKey(key)] = value;
|
|
13062
|
-
return dataset;
|
|
13063
|
-
}
|
|
13064
|
-
//#endregion
|
|
13065
|
-
//#region ../../mpcore/packages/simulator/src/view/eventBinding.ts
|
|
13066
|
-
const LEGACY_EVENT_NAME_RE = /^\w+$/;
|
|
13067
|
-
const EVENT_BINDING_PREFIXES = [
|
|
13068
|
-
{
|
|
13069
|
-
prefix: "bind:",
|
|
13070
|
-
priority: 0,
|
|
13071
|
-
stopAfter: false
|
|
13072
|
-
},
|
|
13073
|
-
{
|
|
13074
|
-
prefix: "catch:",
|
|
13075
|
-
priority: 0,
|
|
13076
|
-
stopAfter: true
|
|
13077
|
-
},
|
|
13078
|
-
{
|
|
13079
|
-
prefix: "bind",
|
|
13080
|
-
priority: 1,
|
|
13081
|
-
stopAfter: false
|
|
13082
|
-
},
|
|
13083
|
-
{
|
|
13084
|
-
prefix: "catch",
|
|
13085
|
-
priority: 1,
|
|
13086
|
-
stopAfter: true
|
|
13087
|
-
}
|
|
13088
|
-
];
|
|
13089
|
-
function parseEventBinding(attributeName, method) {
|
|
13090
|
-
const definition = EVENT_BINDING_PREFIXES.find((item) => attributeName.startsWith(item.prefix));
|
|
13091
|
-
if (!definition) return null;
|
|
13092
|
-
const eventName = attributeName.slice(definition.prefix.length);
|
|
13093
|
-
if (!eventName || !definition.prefix.endsWith(":") && !LEGACY_EVENT_NAME_RE.test(eventName)) return null;
|
|
13094
|
-
return {
|
|
13095
|
-
eventName,
|
|
13096
|
-
method,
|
|
13097
|
-
priority: definition.priority,
|
|
13098
|
-
stopAfter: definition.stopAfter
|
|
13099
|
-
};
|
|
13100
|
-
}
|
|
13101
|
-
function collectMiniProgramEventBindings(attributes = {}) {
|
|
13102
|
-
const bindings = /* @__PURE__ */ new Map();
|
|
13103
|
-
const priorities = /* @__PURE__ */ new Map();
|
|
13104
|
-
for (const [attributeName, method] of Object.entries(attributes)) {
|
|
13105
|
-
const candidate = parseEventBinding(attributeName, method);
|
|
13106
|
-
if (!candidate || candidate.priority < (priorities.get(candidate.eventName) ?? -1)) continue;
|
|
13107
|
-
bindings.set(candidate.eventName, {
|
|
13108
|
-
method: candidate.method,
|
|
13109
|
-
stopAfter: candidate.stopAfter
|
|
13110
|
-
});
|
|
13111
|
-
priorities.set(candidate.eventName, candidate.priority);
|
|
13112
|
-
}
|
|
13113
|
-
return bindings;
|
|
13114
|
-
}
|
|
13115
|
-
function resolveMiniProgramEventBinding(attributes, eventName) {
|
|
13116
|
-
return collectMiniProgramEventBindings(attributes).get(eventName) ?? null;
|
|
13117
|
-
}
|
|
13118
|
-
/** 冒泡时保留原始 target,currentTarget 则属于当前执行绑定的节点。 */
|
|
13119
|
-
function createMiniProgramEventPayload(node, eventName, event, origin = node) {
|
|
13120
|
-
const dataset = collectNodeDataset(node);
|
|
13121
|
-
const nodeId = node.attribs?.id ?? "";
|
|
13122
|
-
const isOrigin = node === origin;
|
|
13123
|
-
return {
|
|
13124
|
-
bubbles: false,
|
|
13125
|
-
capturePhase: false,
|
|
13126
|
-
composed: false,
|
|
13127
|
-
currentTarget: {
|
|
13128
|
-
dataset: isOrigin ? event.currentTarget?.dataset ?? event.dataset ?? dataset : dataset,
|
|
13129
|
-
id: isOrigin ? event.currentTarget?.id ?? event.id ?? nodeId : nodeId
|
|
13130
|
-
},
|
|
13131
|
-
detail: event.detail,
|
|
13132
|
-
mark: event.mark,
|
|
13133
|
-
target: {
|
|
13134
|
-
dataset: event.target?.dataset ?? event.dataset ?? (isOrigin ? dataset : collectNodeDataset(origin)),
|
|
13135
|
-
id: event.target?.id ?? event.id ?? origin.attribs?.id ?? ""
|
|
13136
|
-
},
|
|
13137
|
-
timeStamp: Date.now(),
|
|
13138
|
-
type: eventName
|
|
13139
|
-
};
|
|
13140
|
-
}
|
|
13607
|
+
//#region ../../@weapp-core/constants/dist/index.js
|
|
13608
|
+
/** 无头测试后端不支持所请求的自动化协议。 */
|
|
13609
|
+
const HEADLESS_PROTOCOL_UNSUPPORTED = "HEADLESS_PROTOCOL_UNSUPPORTED";
|
|
13141
13610
|
const WEVU_NATIVE_INSTANCE_KEY = "__wevuNativeInstance";
|
|
13142
13611
|
/** 宿主值为 1 时,实现带 routeEventId 的路由阶段契约;不代表微信 SDK 版本。 */
|
|
13143
13612
|
const WEVU_ROUTE_EVENT_CONTRACT_KEY = "__wevuRouteEventContract";
|
|
@@ -13251,66 +13720,155 @@ function resolveMiniProgramComponent(ownerFilePath, request, miniprogramRootPath
|
|
|
13251
13720
|
return npmPath ? relative(miniprogramRootPath, npmPath).slice(0, -3) : localPath;
|
|
13252
13721
|
}
|
|
13253
13722
|
//#endregion
|
|
13254
|
-
//#region ../../mpcore/packages/simulator/src/view/
|
|
13255
|
-
|
|
13256
|
-
|
|
13257
|
-
const
|
|
13258
|
-
|
|
13259
|
-
|
|
13260
|
-
|
|
13261
|
-
if (existing) return existing;
|
|
13262
|
-
const state = createTemplateRenderState(node);
|
|
13263
|
-
const wxsModules = Object.create(null);
|
|
13264
|
-
const ownDefinitions = new Map(state.definitions);
|
|
13265
|
-
const document = {
|
|
13266
|
-
state,
|
|
13267
|
-
exports: ownDefinitions
|
|
13268
|
-
};
|
|
13269
|
-
documents.set(owner, document);
|
|
13270
|
-
const visit = (child) => {
|
|
13271
|
-
if (child.name === "wxs" && loadWxs) {
|
|
13272
|
-
const name = child.attribs?.module;
|
|
13273
|
-
if (!name || !/^[a-z_$][\w$]*$/i.test(name) || [
|
|
13274
|
-
"__proto__",
|
|
13275
|
-
"constructor",
|
|
13276
|
-
"prototype"
|
|
13277
|
-
].includes(name)) throw new Error(`Invalid WXS module name in ${owner}: ${String(name)}`);
|
|
13278
|
-
if (Object.hasOwn(wxsModules, name)) throw new Error(`Duplicate WXS module in ${owner}: ${name}`);
|
|
13279
|
-
wxsModules[name] = loadWxs(owner, child);
|
|
13280
|
-
return;
|
|
13281
|
-
}
|
|
13282
|
-
if (child.name === "import" && child.attribs?.src) {
|
|
13283
|
-
const source = child.attribs.src;
|
|
13284
|
-
const imported = loadImport(owner, source.endsWith(".wxml") ? source : `${source}.wxml`);
|
|
13285
|
-
const importedDocument = collect(imported.root, imported.filePath);
|
|
13286
|
-
for (const [name, definition] of importedDocument.exports) state.definitions.set(name, definition);
|
|
13287
|
-
}
|
|
13288
|
-
for (const nested of child.children ?? []) visit(nested);
|
|
13289
|
-
};
|
|
13290
|
-
visit(node);
|
|
13291
|
-
if (Object.keys(wxsModules).length) state.wxsModules = wxsModules;
|
|
13292
|
-
for (const [name, definition] of ownDefinitions) {
|
|
13293
|
-
state.definitions.set(name, definition);
|
|
13294
|
-
definitionScopes.set(definition, state.definitions);
|
|
13295
|
-
if (state.wxsModules) definitionWxsScopes.set(definition, state.wxsModules);
|
|
13296
|
-
}
|
|
13297
|
-
state.definitionScopes = definitionScopes;
|
|
13298
|
-
state.definitionWxsScopes = definitionWxsScopes;
|
|
13299
|
-
return document;
|
|
13723
|
+
//#region ../../mpcore/packages/simulator/src/view/nodeEvents.ts
|
|
13724
|
+
/** 正确字段优先;复制触点,避免处理器修改调用者持有的数据。 */
|
|
13725
|
+
function readTouchEventPayload(event) {
|
|
13726
|
+
const changedTouches = event.changedTouches ?? event.changeTouches;
|
|
13727
|
+
return {
|
|
13728
|
+
...event.touches === void 0 ? {} : { touches: event.touches.map((touch) => ({ ...touch })) },
|
|
13729
|
+
...changedTouches === void 0 ? {} : { changedTouches: changedTouches.map((touch) => ({ ...touch })) }
|
|
13300
13730
|
};
|
|
13301
|
-
return collect(root, filePath).state;
|
|
13302
13731
|
}
|
|
13303
13732
|
//#endregion
|
|
13304
|
-
//#region ../../mpcore/packages/simulator/src/view/
|
|
13305
|
-
function
|
|
13306
|
-
|
|
13307
|
-
|
|
13308
|
-
|
|
13309
|
-
|
|
13310
|
-
|
|
13311
|
-
|
|
13733
|
+
//#region ../../mpcore/packages/simulator/src/view/eventBinding.ts
|
|
13734
|
+
function resolveMiniProgramEventBinding(attributes, eventName) {
|
|
13735
|
+
return resolveEventBindingPhases(attributes, eventName, false)?.bubble ?? null;
|
|
13736
|
+
}
|
|
13737
|
+
/** 冒泡时保留原始 target,currentTarget 则属于当前执行绑定的节点。 */
|
|
13738
|
+
function createMiniProgramEventPayload(node, eventName, event, origin = node) {
|
|
13739
|
+
const dataset = collectNodeDataset(node);
|
|
13740
|
+
const nodeId = node.attribs?.id ?? "";
|
|
13741
|
+
const isOrigin = node === origin;
|
|
13742
|
+
return {
|
|
13743
|
+
...readTouchEventPayload(event),
|
|
13744
|
+
bubbles: false,
|
|
13745
|
+
capturePhase: false,
|
|
13746
|
+
composed: false,
|
|
13747
|
+
currentTarget: {
|
|
13748
|
+
dataset: isOrigin ? event.currentTarget?.dataset ?? event.dataset ?? dataset : dataset,
|
|
13749
|
+
id: isOrigin ? event.currentTarget?.id ?? event.id ?? nodeId : nodeId
|
|
13750
|
+
},
|
|
13751
|
+
detail: event.detail,
|
|
13752
|
+
mark: event.mark,
|
|
13753
|
+
target: {
|
|
13754
|
+
dataset: event.target?.dataset ?? event.dataset ?? (isOrigin ? dataset : collectNodeDataset(origin)),
|
|
13755
|
+
id: event.target?.id ?? event.id ?? origin.attribs?.id ?? ""
|
|
13756
|
+
},
|
|
13757
|
+
timeStamp: Date.now(),
|
|
13758
|
+
type: eventName
|
|
13759
|
+
};
|
|
13760
|
+
}
|
|
13761
|
+
//#endregion
|
|
13762
|
+
//#region ../../mpcore/packages/simulator/src/view/nativeForm.ts
|
|
13763
|
+
const pickerValues = /* @__PURE__ */ new WeakMap();
|
|
13764
|
+
/** 保存 picker 的原始数组属性,不能从渲染后的逗号字符串反推选项值。 */
|
|
13765
|
+
function setNativePickerValue(node, value) {
|
|
13766
|
+
if (node.name === "picker") pickerValues.set(node, value);
|
|
13767
|
+
}
|
|
13768
|
+
function includesBehavior(definition, name, visited = /* @__PURE__ */ new Set()) {
|
|
13769
|
+
if (visited.has(definition)) return false;
|
|
13770
|
+
visited.add(definition);
|
|
13771
|
+
return Array.isArray(definition.behaviors) && definition.behaviors.some((behavior) => behavior === name || behavior !== null && typeof behavior === "object" && includesBehavior(behavior, name, visited));
|
|
13772
|
+
}
|
|
13773
|
+
function nativeOwner(node) {
|
|
13774
|
+
return getNativeNodeOwner(node) ?? {
|
|
13775
|
+
scopeId: node.attribs?.["data-sim-scope"] ?? null,
|
|
13776
|
+
target: node
|
|
13777
|
+
};
|
|
13778
|
+
}
|
|
13779
|
+
function participatingScopes(formScope, pageScope, resolveComponent) {
|
|
13780
|
+
const scopes = /* @__PURE__ */ new Set([null, pageScope]);
|
|
13781
|
+
let current = formScope;
|
|
13782
|
+
while (current && !scopes.has(current)) {
|
|
13783
|
+
scopes.add(current);
|
|
13784
|
+
current = resolveComponent?.(current)?.ownerScopeId ?? null;
|
|
13312
13785
|
}
|
|
13313
|
-
return
|
|
13786
|
+
return scopes;
|
|
13787
|
+
}
|
|
13788
|
+
function participates(scopeId, formScopes, behavior, resolveComponent) {
|
|
13789
|
+
const visited = /* @__PURE__ */ new Set();
|
|
13790
|
+
while (!formScopes.has(scopeId)) {
|
|
13791
|
+
if (!scopeId || visited.has(scopeId)) return false;
|
|
13792
|
+
visited.add(scopeId);
|
|
13793
|
+
const component = resolveComponent?.(scopeId);
|
|
13794
|
+
if (!component || !includesBehavior(component.definition, behavior)) return false;
|
|
13795
|
+
scopeId = component.ownerScopeId;
|
|
13796
|
+
}
|
|
13797
|
+
return true;
|
|
13798
|
+
}
|
|
13799
|
+
function checked(attributes, name) {
|
|
13800
|
+
const value = attributes?.[name];
|
|
13801
|
+
return value !== void 0 && value !== "false" && value !== "0";
|
|
13802
|
+
}
|
|
13803
|
+
function choiceValues(group, pageScope, resolveComponent) {
|
|
13804
|
+
const values = [];
|
|
13805
|
+
const scopes = participatingScopes(nativeOwner(group).scopeId, pageScope, resolveComponent);
|
|
13806
|
+
const choice = group.name === "radio-group" ? "radio" : "checkbox";
|
|
13807
|
+
const visit = (node) => {
|
|
13808
|
+
if (node.name === "form" || node.name === "radio-group" || node.name === "checkbox-group") return;
|
|
13809
|
+
if (node.name === choice) {
|
|
13810
|
+
const owner = nativeOwner(node);
|
|
13811
|
+
if (checked(owner.target.attribs, "checked") && participates(owner.scopeId, scopes, "wx://form-field-group", resolveComponent)) values.push(owner.target.attribs?.value ?? "");
|
|
13812
|
+
}
|
|
13813
|
+
for (const child of node.children ?? []) visit(child);
|
|
13814
|
+
};
|
|
13815
|
+
for (const child of group.children ?? []) visit(child);
|
|
13816
|
+
return values;
|
|
13817
|
+
}
|
|
13818
|
+
function collectFormValues(form, scopes, pageScope, resolveComponent) {
|
|
13819
|
+
const values = Object.create(null);
|
|
13820
|
+
const visit = (node) => {
|
|
13821
|
+
if (node.name === "form") return;
|
|
13822
|
+
const owner = nativeOwner(node);
|
|
13823
|
+
const attributes = owner.target.attribs;
|
|
13824
|
+
const name = attributes?.name;
|
|
13825
|
+
if (attributes && name && participates(owner.scopeId, scopes, "wx://form-field-group", resolveComponent)) switch (node.name) {
|
|
13826
|
+
case "input":
|
|
13827
|
+
case "textarea":
|
|
13828
|
+
values[name] = attributes.value ?? "";
|
|
13829
|
+
break;
|
|
13830
|
+
case "switch":
|
|
13831
|
+
values[name] = checked(attributes, "checked");
|
|
13832
|
+
break;
|
|
13833
|
+
case "slider":
|
|
13834
|
+
values[name] = Number(attributes.value ?? 0);
|
|
13835
|
+
break;
|
|
13836
|
+
case "picker": {
|
|
13837
|
+
const mode = attributes.mode ?? "selector";
|
|
13838
|
+
if (mode === "multiSelector" || mode === "region") {
|
|
13839
|
+
const value = pickerValues.get(node);
|
|
13840
|
+
values[name] = Array.isArray(value) ? value.slice() : [];
|
|
13841
|
+
} else values[name] = mode === "selector" ? Number(attributes.value ?? 0) : attributes.value ?? "";
|
|
13842
|
+
break;
|
|
13843
|
+
}
|
|
13844
|
+
case "radio-group":
|
|
13845
|
+
values[name] = choiceValues(node, pageScope, resolveComponent)[0] ?? "";
|
|
13846
|
+
break;
|
|
13847
|
+
case "checkbox-group": values[name] = choiceValues(node, pageScope, resolveComponent);
|
|
13848
|
+
}
|
|
13849
|
+
for (const child of node.children ?? []) visit(child);
|
|
13850
|
+
};
|
|
13851
|
+
for (const child of form.children ?? []) visit(child);
|
|
13852
|
+
return values;
|
|
13853
|
+
}
|
|
13854
|
+
/** 先固定提交目标、字段值和方法所有者,再允许 tap 回调改变组件树。 */
|
|
13855
|
+
function prepareNativeFormSubmit(button, pageScope, event, resolveMethod, resolveComponent) {
|
|
13856
|
+
const owner = nativeOwner(button);
|
|
13857
|
+
if (owner.target.attribs?.["form-type"] !== "submit" || checked(owner.target.attribs, "disabled")) return;
|
|
13858
|
+
let form = button.parent;
|
|
13859
|
+
while (form && form.name !== "form") form = form.parent;
|
|
13860
|
+
if (!form) return;
|
|
13861
|
+
const formOwner = nativeOwner(form);
|
|
13862
|
+
const scopes = participatingScopes(formOwner.scopeId, pageScope, resolveComponent);
|
|
13863
|
+
if (!participates(owner.scopeId, scopes, "wx://form-field-button", resolveComponent)) return;
|
|
13864
|
+
const binding = resolveMiniProgramEventBinding(formOwner.target.attribs, "submit");
|
|
13865
|
+
return {
|
|
13866
|
+
call: binding?.method ? resolveMethod(formOwner.scopeId, binding.method) : void 0,
|
|
13867
|
+
event: createMiniProgramEventPayload(formOwner.target, "submit", {
|
|
13868
|
+
detail: { value: collectFormValues(form, scopes, pageScope, resolveComponent) },
|
|
13869
|
+
mark: event.mark
|
|
13870
|
+
})
|
|
13871
|
+
};
|
|
13314
13872
|
}
|
|
13315
13873
|
//#endregion
|
|
13316
13874
|
//#region ../../node_modules/.pnpm/entities@8.1.0/node_modules/entities/dist/decode-codepoint.js
|
|
@@ -16359,7 +16917,7 @@ const attributeEscapeRegex = /["&\u{A0}]/gu;
|
|
|
16359
16917
|
* following {@link https://html.spec.whatwg.org/multipage/parsing.html#escapingString}.
|
|
16360
16918
|
* @param data String to escape.
|
|
16361
16919
|
*/
|
|
16362
|
-
function escapeAttribute$
|
|
16920
|
+
function escapeAttribute$2(data) {
|
|
16363
16921
|
return escapeWithRegex(attributeEscapeRegex, data);
|
|
16364
16922
|
}
|
|
16365
16923
|
const textEscapeRegex = /[&<>\u{A0}]/gu;
|
|
@@ -16471,7 +17029,7 @@ function replaceQuotes(value) {
|
|
|
16471
17029
|
*/
|
|
16472
17030
|
function formatAttributes(attributes, options, xmlMode) {
|
|
16473
17031
|
if (!attributes) return "";
|
|
16474
|
-
const encode = (options.encodeEntities ?? options.decodeEntities) === false ? replaceQuotes : xmlMode || options.encodeEntities !== "utf8" ? encodeXML : escapeAttribute$
|
|
17032
|
+
const encode = (options.encodeEntities ?? options.decodeEntities) === false ? replaceQuotes : xmlMode || options.encodeEntities !== "utf8" ? encodeXML : escapeAttribute$2;
|
|
16475
17033
|
const isForeign = xmlMode === "foreign";
|
|
16476
17034
|
const showEmpty = !!(options.emptyAttrs ?? xmlMode);
|
|
16477
17035
|
let result = "";
|
|
@@ -17086,6 +17644,344 @@ function parseDocument(data, options) {
|
|
|
17086
17644
|
return handler.root;
|
|
17087
17645
|
}
|
|
17088
17646
|
//#endregion
|
|
17647
|
+
//#region ../../@weapp-core/shared/dist/rich-text.js
|
|
17648
|
+
const ALLOWED_TAGS = /* @__PURE__ */ new Set([
|
|
17649
|
+
"a",
|
|
17650
|
+
"abbr",
|
|
17651
|
+
"address",
|
|
17652
|
+
"article",
|
|
17653
|
+
"aside",
|
|
17654
|
+
"b",
|
|
17655
|
+
"bdi",
|
|
17656
|
+
"bdo",
|
|
17657
|
+
"big",
|
|
17658
|
+
"blockquote",
|
|
17659
|
+
"br",
|
|
17660
|
+
"caption",
|
|
17661
|
+
"center",
|
|
17662
|
+
"cite",
|
|
17663
|
+
"code",
|
|
17664
|
+
"col",
|
|
17665
|
+
"colgroup",
|
|
17666
|
+
"dd",
|
|
17667
|
+
"del",
|
|
17668
|
+
"div",
|
|
17669
|
+
"dl",
|
|
17670
|
+
"dt",
|
|
17671
|
+
"em",
|
|
17672
|
+
"fieldset",
|
|
17673
|
+
"font",
|
|
17674
|
+
"h1",
|
|
17675
|
+
"h2",
|
|
17676
|
+
"h3",
|
|
17677
|
+
"h4",
|
|
17678
|
+
"h5",
|
|
17679
|
+
"h6",
|
|
17680
|
+
"header",
|
|
17681
|
+
"hr",
|
|
17682
|
+
"i",
|
|
17683
|
+
"img",
|
|
17684
|
+
"ins",
|
|
17685
|
+
"label",
|
|
17686
|
+
"legend",
|
|
17687
|
+
"li",
|
|
17688
|
+
"mark",
|
|
17689
|
+
"ol",
|
|
17690
|
+
"p",
|
|
17691
|
+
"pre",
|
|
17692
|
+
"q",
|
|
17693
|
+
"rt",
|
|
17694
|
+
"ruby",
|
|
17695
|
+
"s",
|
|
17696
|
+
"section",
|
|
17697
|
+
"small",
|
|
17698
|
+
"span",
|
|
17699
|
+
"strong",
|
|
17700
|
+
"sub",
|
|
17701
|
+
"sup",
|
|
17702
|
+
"table",
|
|
17703
|
+
"tbody",
|
|
17704
|
+
"td",
|
|
17705
|
+
"tfoot",
|
|
17706
|
+
"th",
|
|
17707
|
+
"thead",
|
|
17708
|
+
"tr",
|
|
17709
|
+
"tt",
|
|
17710
|
+
"u",
|
|
17711
|
+
"ul"
|
|
17712
|
+
]);
|
|
17713
|
+
const ALLOWED_ATTRIBUTES = /* @__PURE__ */ new Set([
|
|
17714
|
+
"abbr",
|
|
17715
|
+
"align",
|
|
17716
|
+
"alt",
|
|
17717
|
+
"axis",
|
|
17718
|
+
"bgcolor",
|
|
17719
|
+
"border",
|
|
17720
|
+
"cellpadding",
|
|
17721
|
+
"cellspacing",
|
|
17722
|
+
"class",
|
|
17723
|
+
"colspan",
|
|
17724
|
+
"dir",
|
|
17725
|
+
"height",
|
|
17726
|
+
"href",
|
|
17727
|
+
"id",
|
|
17728
|
+
"lang",
|
|
17729
|
+
"rowspan",
|
|
17730
|
+
"scope",
|
|
17731
|
+
"span",
|
|
17732
|
+
"start",
|
|
17733
|
+
"style",
|
|
17734
|
+
"summary",
|
|
17735
|
+
"target",
|
|
17736
|
+
"title",
|
|
17737
|
+
"type",
|
|
17738
|
+
"valign",
|
|
17739
|
+
"width"
|
|
17740
|
+
]);
|
|
17741
|
+
const URL_ATTRIBUTES = /* @__PURE__ */ new Set(["href", "src"]);
|
|
17742
|
+
const ALLOWED_STYLE_PROPERTIES = /* @__PURE__ */ new Set([
|
|
17743
|
+
"background",
|
|
17744
|
+
"background-color",
|
|
17745
|
+
"border",
|
|
17746
|
+
"border-bottom",
|
|
17747
|
+
"border-color",
|
|
17748
|
+
"border-left",
|
|
17749
|
+
"border-radius",
|
|
17750
|
+
"border-right",
|
|
17751
|
+
"border-style",
|
|
17752
|
+
"border-top",
|
|
17753
|
+
"border-width",
|
|
17754
|
+
"color",
|
|
17755
|
+
"display",
|
|
17756
|
+
"font-family",
|
|
17757
|
+
"font-size",
|
|
17758
|
+
"font-style",
|
|
17759
|
+
"font-weight",
|
|
17760
|
+
"height",
|
|
17761
|
+
"letter-spacing",
|
|
17762
|
+
"line-height",
|
|
17763
|
+
"margin",
|
|
17764
|
+
"margin-bottom",
|
|
17765
|
+
"margin-left",
|
|
17766
|
+
"margin-right",
|
|
17767
|
+
"margin-top",
|
|
17768
|
+
"max-height",
|
|
17769
|
+
"max-width",
|
|
17770
|
+
"min-height",
|
|
17771
|
+
"min-width",
|
|
17772
|
+
"opacity",
|
|
17773
|
+
"overflow",
|
|
17774
|
+
"padding",
|
|
17775
|
+
"padding-bottom",
|
|
17776
|
+
"padding-left",
|
|
17777
|
+
"padding-right",
|
|
17778
|
+
"padding-top",
|
|
17779
|
+
"text-align",
|
|
17780
|
+
"text-decoration",
|
|
17781
|
+
"text-indent",
|
|
17782
|
+
"text-overflow",
|
|
17783
|
+
"text-transform",
|
|
17784
|
+
"vertical-align",
|
|
17785
|
+
"white-space",
|
|
17786
|
+
"width",
|
|
17787
|
+
"word-break",
|
|
17788
|
+
"word-wrap"
|
|
17789
|
+
]);
|
|
17790
|
+
function isRecord(value) {
|
|
17791
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
17792
|
+
}
|
|
17793
|
+
function isSafeUrl(value, attribute) {
|
|
17794
|
+
const normalized = Array.from(value).filter((character) => character.charCodeAt(0) > 32).join("").toLowerCase();
|
|
17795
|
+
if (!normalized || normalized.startsWith("#") || normalized.startsWith("/") || normalized.startsWith("./") || normalized.startsWith("../")) return true;
|
|
17796
|
+
if (/^(?:https?:|mailto:|tel:)/.test(normalized)) return true;
|
|
17797
|
+
return attribute === "src" && /^data:image\/(?:gif|jpe?g|png|webp);base64,/.test(normalized);
|
|
17798
|
+
}
|
|
17799
|
+
function isSafeStyleValue(value) {
|
|
17800
|
+
const normalized = value.toLowerCase().replace(/\s+/g, "");
|
|
17801
|
+
return !normalized.includes("url(") && !normalized.includes("expression(") && !normalized.includes("javascript:") && !normalized.includes("behavior:") && !normalized.includes("-moz-binding");
|
|
17802
|
+
}
|
|
17803
|
+
function sanitizeRichTextStyle(value) {
|
|
17804
|
+
const source = isRecord(value) ? Object.entries(value).map(([property, propertyValue]) => `${property}:${String(propertyValue)}`).join(";") : String(value ?? "");
|
|
17805
|
+
const declarations = [];
|
|
17806
|
+
for (const declaration of source.split(";")) {
|
|
17807
|
+
const separator = declaration.indexOf(":");
|
|
17808
|
+
if (separator <= 0) continue;
|
|
17809
|
+
const property = declaration.slice(0, separator).trim().toLowerCase();
|
|
17810
|
+
const propertyValue = declaration.slice(separator + 1).trim();
|
|
17811
|
+
if (ALLOWED_STYLE_PROPERTIES.has(property) && propertyValue && isSafeStyleValue(propertyValue)) declarations.push(`${property}: ${propertyValue}`);
|
|
17812
|
+
}
|
|
17813
|
+
return declarations.join("; ");
|
|
17814
|
+
}
|
|
17815
|
+
function sanitizeRichTextAttributes(value, tagName) {
|
|
17816
|
+
if (!isRecord(value)) return {};
|
|
17817
|
+
const attributes = {};
|
|
17818
|
+
for (const [rawName, rawValue] of Object.entries(value)) {
|
|
17819
|
+
const name = rawName.trim().toLowerCase();
|
|
17820
|
+
if (name.startsWith("on") || name === "srcdoc") continue;
|
|
17821
|
+
if (!ALLOWED_ATTRIBUTES.has(name) && name !== "src" && !name.startsWith("aria-") && !name.startsWith("data-")) continue;
|
|
17822
|
+
if (name === "src" && tagName !== "img") continue;
|
|
17823
|
+
const serialized = name === "style" ? sanitizeRichTextStyle(rawValue) : String(rawValue ?? "");
|
|
17824
|
+
if (!serialized || URL_ATTRIBUTES.has(name) && !isSafeUrl(serialized, name)) continue;
|
|
17825
|
+
attributes[name] = serialized;
|
|
17826
|
+
}
|
|
17827
|
+
if (tagName === "a") attributes.rel = "noopener noreferrer";
|
|
17828
|
+
return attributes;
|
|
17829
|
+
}
|
|
17830
|
+
function convertSourceNode(value) {
|
|
17831
|
+
if (!isRecord(value)) return [];
|
|
17832
|
+
if (value.type === "text" || !value.name && typeof value.text === "string") return [{
|
|
17833
|
+
type: "text",
|
|
17834
|
+
text: String(value.text ?? "")
|
|
17835
|
+
}];
|
|
17836
|
+
const children = Array.isArray(value.children) ? value.children.flatMap(convertSourceNode) : [];
|
|
17837
|
+
const name = String(value.name ?? "").toLowerCase();
|
|
17838
|
+
if (!ALLOWED_TAGS.has(name)) return children;
|
|
17839
|
+
return [{
|
|
17840
|
+
type: "element",
|
|
17841
|
+
name,
|
|
17842
|
+
attrs: sanitizeRichTextAttributes(value.attrs, name),
|
|
17843
|
+
children
|
|
17844
|
+
}];
|
|
17845
|
+
}
|
|
17846
|
+
function convertParsedNode(node) {
|
|
17847
|
+
if (node.type === "text") return [{
|
|
17848
|
+
type: "text",
|
|
17849
|
+
text: node.data
|
|
17850
|
+
}];
|
|
17851
|
+
if (node.type !== "tag") return [];
|
|
17852
|
+
const element = node;
|
|
17853
|
+
const children = element.children.flatMap(convertParsedNode);
|
|
17854
|
+
const name = element.name.toLowerCase();
|
|
17855
|
+
if (!ALLOWED_TAGS.has(name)) return children;
|
|
17856
|
+
return [{
|
|
17857
|
+
type: "element",
|
|
17858
|
+
name,
|
|
17859
|
+
attrs: sanitizeRichTextAttributes(element.attribs, name),
|
|
17860
|
+
children
|
|
17861
|
+
}];
|
|
17862
|
+
}
|
|
17863
|
+
function normalizeRichTextNodes(value) {
|
|
17864
|
+
if (typeof value === "string") return parseDocument(value, {
|
|
17865
|
+
decodeEntities: true,
|
|
17866
|
+
lowerCaseAttributeNames: true,
|
|
17867
|
+
lowerCaseTags: true
|
|
17868
|
+
}).children.flatMap(convertParsedNode);
|
|
17869
|
+
return (Array.isArray(value) ? value : [value]).flatMap(convertSourceNode);
|
|
17870
|
+
}
|
|
17871
|
+
//#endregion
|
|
17872
|
+
//#region ../../mpcore/packages/simulator/src/view/richText.ts
|
|
17873
|
+
function materializeNode(node) {
|
|
17874
|
+
if (node.type === "text") return {
|
|
17875
|
+
type: "text",
|
|
17876
|
+
data: node.text
|
|
17877
|
+
};
|
|
17878
|
+
for (const name of Object.keys(node.attrs)) if (name.startsWith("data-sim-")) delete node.attrs[name];
|
|
17879
|
+
return {
|
|
17880
|
+
type: "tag",
|
|
17881
|
+
name: node.name,
|
|
17882
|
+
attribs: node.attrs,
|
|
17883
|
+
children: node.children.map(materializeNode)
|
|
17884
|
+
};
|
|
17885
|
+
}
|
|
17886
|
+
/** 富文本直接成为已渲染节点,不能再进入 WXML 表达式或组件处理流程。 */
|
|
17887
|
+
function renderRichTextNodes(value) {
|
|
17888
|
+
return normalizeRichTextNodes(value).map(materializeNode);
|
|
17889
|
+
}
|
|
17890
|
+
//#endregion
|
|
17891
|
+
//#region ../../mpcore/packages/simulator/src/view/templateIncludes.ts
|
|
17892
|
+
/** 展开 include 的可渲染内容,并保留嵌套引用的来源文件。 */
|
|
17893
|
+
function expandTemplateIncludes(root, filePath, loadTemplate) {
|
|
17894
|
+
const owners = /* @__PURE__ */ new WeakMap();
|
|
17895
|
+
const expand = (node, owner, stack, included = false) => {
|
|
17896
|
+
if (included && (isTemplateDefinition(node) || node.name === "wxs")) return;
|
|
17897
|
+
owners.set(node, owner);
|
|
17898
|
+
if (node.name === "include" && node.attribs?.src) {
|
|
17899
|
+
const source = node.attribs.src;
|
|
17900
|
+
const loaded = loadTemplate(owner, source.endsWith(".wxml") ? source : `${source}.wxml`);
|
|
17901
|
+
if (stack.includes(loaded.filePath)) throw new Error("Circular WXML include is not supported");
|
|
17902
|
+
const { src: _src, ...attributes } = node.attribs;
|
|
17903
|
+
node.name = "block";
|
|
17904
|
+
node.attribs = attributes;
|
|
17905
|
+
node.children = (loaded.root.children ?? []).flatMap((child) => {
|
|
17906
|
+
const expanded = expand(child, loaded.filePath, [...stack, loaded.filePath], true);
|
|
17907
|
+
return expanded ? [expanded] : [];
|
|
17908
|
+
});
|
|
17909
|
+
return node;
|
|
17910
|
+
}
|
|
17911
|
+
node.children = node.children?.flatMap((child) => {
|
|
17912
|
+
const expanded = expand(child, owner, stack, included);
|
|
17913
|
+
return expanded ? [expanded] : [];
|
|
17914
|
+
});
|
|
17915
|
+
return node;
|
|
17916
|
+
};
|
|
17917
|
+
expand(root, filePath, [filePath]);
|
|
17918
|
+
return owners;
|
|
17919
|
+
}
|
|
17920
|
+
//#endregion
|
|
17921
|
+
//#region ../../mpcore/packages/simulator/src/view/templateImports.ts
|
|
17922
|
+
function createImportedTemplateState(root, filePath, loadImport, loadWxs) {
|
|
17923
|
+
const documents = /* @__PURE__ */ new Map();
|
|
17924
|
+
const definitionScopes = /* @__PURE__ */ new Map();
|
|
17925
|
+
const definitionWxsScopes = /* @__PURE__ */ new Map();
|
|
17926
|
+
const collect = (node, owner) => {
|
|
17927
|
+
const existing = documents.get(owner);
|
|
17928
|
+
if (existing) return existing;
|
|
17929
|
+
const owners = expandTemplateIncludes(node, owner, loadImport);
|
|
17930
|
+
const state = createTemplateRenderState(node);
|
|
17931
|
+
const wxsModules = Object.create(null);
|
|
17932
|
+
const ownDefinitions = new Map(state.definitions);
|
|
17933
|
+
const document = {
|
|
17934
|
+
state,
|
|
17935
|
+
exports: ownDefinitions
|
|
17936
|
+
};
|
|
17937
|
+
documents.set(owner, document);
|
|
17938
|
+
const visit = (child) => {
|
|
17939
|
+
const sourceOwner = owners.get(child) ?? owner;
|
|
17940
|
+
if (child.name === "wxs" && loadWxs) {
|
|
17941
|
+
const name = child.attribs?.module;
|
|
17942
|
+
if (!name || !/^[a-z_$][\w$]*$/i.test(name) || [
|
|
17943
|
+
"__proto__",
|
|
17944
|
+
"constructor",
|
|
17945
|
+
"prototype"
|
|
17946
|
+
].includes(name)) throw new Error(`Invalid WXS module name in ${owner}: ${String(name)}`);
|
|
17947
|
+
if (Object.hasOwn(wxsModules, name)) throw new Error(`Duplicate WXS module in ${owner}: ${name}`);
|
|
17948
|
+
wxsModules[name] = loadWxs(sourceOwner, child);
|
|
17949
|
+
return;
|
|
17950
|
+
}
|
|
17951
|
+
if (child.name === "import" && child.attribs?.src) {
|
|
17952
|
+
const source = child.attribs.src;
|
|
17953
|
+
const imported = loadImport(sourceOwner, source.endsWith(".wxml") ? source : `${source}.wxml`);
|
|
17954
|
+
const importedDocument = collect(imported.root, imported.filePath);
|
|
17955
|
+
for (const [name, definition] of importedDocument.exports) state.definitions.set(name, definition);
|
|
17956
|
+
}
|
|
17957
|
+
for (const nested of child.children ?? []) visit(nested);
|
|
17958
|
+
};
|
|
17959
|
+
visit(node);
|
|
17960
|
+
if (Object.keys(wxsModules).length) state.wxsModules = wxsModules;
|
|
17961
|
+
for (const [name, definition] of ownDefinitions) {
|
|
17962
|
+
state.definitions.set(name, definition);
|
|
17963
|
+
definitionScopes.set(definition, state.definitions);
|
|
17964
|
+
if (state.wxsModules) definitionWxsScopes.set(definition, state.wxsModules);
|
|
17965
|
+
}
|
|
17966
|
+
state.definitionScopes = definitionScopes;
|
|
17967
|
+
state.definitionWxsScopes = definitionWxsScopes;
|
|
17968
|
+
return document;
|
|
17969
|
+
};
|
|
17970
|
+
return collect(root, filePath).state;
|
|
17971
|
+
}
|
|
17972
|
+
//#endregion
|
|
17973
|
+
//#region ../../mpcore/packages/simulator/src/view/templateText.ts
|
|
17974
|
+
function interpolateTemplateText(input, data, emptyNull = false) {
|
|
17975
|
+
let output = "";
|
|
17976
|
+
let offset = 0;
|
|
17977
|
+
for (const range of templateInterpolations(input)) {
|
|
17978
|
+
const value = resolveTemplateExpression(data, range.expression);
|
|
17979
|
+
output += input.slice(offset, range.start) + (value === void 0 || emptyNull && value === null ? "" : String(value));
|
|
17980
|
+
offset = range.end;
|
|
17981
|
+
}
|
|
17982
|
+
return output + input.slice(offset);
|
|
17983
|
+
}
|
|
17984
|
+
//#endregion
|
|
17089
17985
|
//#region ../../mpcore/packages/simulator/src/view/templateAttributes.ts
|
|
17090
17986
|
function decodeAttribute(raw, quote) {
|
|
17091
17987
|
const source = raw.replaceAll(`\\${quote}`, quote);
|
|
@@ -17140,17 +18036,18 @@ function maskTemplateAttributes(source) {
|
|
|
17140
18036
|
const INLINE_WXS_RE = /<wxs\b([^>]*)(?<!\/)>([\s\S]*?)<\/wxs\s*>/g;
|
|
17141
18037
|
function parseWxsTemplateDocument(templateSource) {
|
|
17142
18038
|
const scripts = [];
|
|
17143
|
-
const
|
|
18039
|
+
const source = templateSource.replace(INLINE_WXS_RE, (_match, attributes, script) => {
|
|
17144
18040
|
return `<wxs data-sim-wxs="${scripts.push(script) - 1}"${attributes}>wxs-source</wxs>`;
|
|
17145
|
-
})
|
|
18041
|
+
});
|
|
18042
|
+
const masked = maskTemplateAttributes(source);
|
|
17146
18043
|
const document = parseDocument(`<page>${masked.source}</page>`, {
|
|
17147
|
-
xmlMode:
|
|
18044
|
+
xmlMode: true,
|
|
17148
18045
|
decodeEntities: false,
|
|
17149
18046
|
lowerCaseAttributeNames: false,
|
|
17150
18047
|
lowerCaseTags: false,
|
|
17151
18048
|
recognizeSelfClosing: true
|
|
17152
18049
|
});
|
|
17153
|
-
if (!scripts.length && !masked.attributes.size) return document;
|
|
18050
|
+
if (!scripts.length && !masked.attributes.size && !/[\r\n]/.test(source)) return document;
|
|
17154
18051
|
const hasAttributes = masked.attributes.size > 0;
|
|
17155
18052
|
const restore = (node) => {
|
|
17156
18053
|
if (hasAttributes && node.attribs) {
|
|
@@ -17159,7 +18056,9 @@ function parseWxsTemplateDocument(templateSource) {
|
|
|
17159
18056
|
if (node.name === "wxs" && Object.hasOwn(node.attribs ?? {}, "data-sim-wxs")) {
|
|
17160
18057
|
node.children[0].data = scripts[Number(node.attribs["data-sim-wxs"])];
|
|
17161
18058
|
delete node.attribs["data-sim-wxs"];
|
|
18059
|
+
return;
|
|
17162
18060
|
}
|
|
18061
|
+
if (node.children) node.children = node.children.filter((child) => child.type !== "text" || !/^[\t\r\n ]+$/.test(child.data ?? "") || !/[\r\n]/.test(child.data ?? ""));
|
|
17163
18062
|
for (const child of node.children ?? []) restore(child);
|
|
17164
18063
|
};
|
|
17165
18064
|
restore(document);
|
|
@@ -17200,7 +18099,7 @@ function collectDataset(node, source) {
|
|
|
17200
18099
|
function escapeText$2(text) {
|
|
17201
18100
|
return text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
17202
18101
|
}
|
|
17203
|
-
function escapeAttribute$
|
|
18102
|
+
function escapeAttribute$1(value) {
|
|
17204
18103
|
return escapeText$2(value).replaceAll("\"", """);
|
|
17205
18104
|
}
|
|
17206
18105
|
function cloneNode(node) {
|
|
@@ -17245,7 +18144,7 @@ function serializeDomNode$1(node) {
|
|
|
17245
18144
|
if (node.type === "root") return (node.children ?? []).map(serializeDomNode$1).join("");
|
|
17246
18145
|
const tagName = node.name ?? "";
|
|
17247
18146
|
if (!tagName) return (node.children ?? []).map(serializeDomNode$1).join("");
|
|
17248
|
-
return `<${tagName}${Object.entries(node.attribs ?? {}).map(([key, value]) => ` ${key}="${escapeAttribute$
|
|
18147
|
+
return `<${tagName}${Object.entries(node.attribs ?? {}).map(([key, value]) => ` ${key}="${escapeAttribute$1(value)}"`).join("")}>${(node.children ?? []).map(serializeDomNode$1).join("")}</${tagName}>`;
|
|
17249
18148
|
}
|
|
17250
18149
|
function isTagNode(node) {
|
|
17251
18150
|
return node.type === "tag" && typeof node.name === "string";
|
|
@@ -17264,7 +18163,7 @@ function resolveComponentAttributeValue(value, scope) {
|
|
|
17264
18163
|
}
|
|
17265
18164
|
return interpolateTemplate$1(value, wxsScopeData(scope));
|
|
17266
18165
|
}
|
|
17267
|
-
function applyNodeBindings(node, scope) {
|
|
18166
|
+
function applyNodeBindings(node, scope, richText = false) {
|
|
17268
18167
|
if (!isTagNode(node)) {
|
|
17269
18168
|
if (node.type === "text" && typeof node.data === "string") node.data = interpolateTemplateText(node.data, wxsScopeData(scope));
|
|
17270
18169
|
return;
|
|
@@ -17272,6 +18171,7 @@ function applyNodeBindings(node, scope) {
|
|
|
17272
18171
|
node.attribs ??= {};
|
|
17273
18172
|
node.attribs["data-sim-scope"] = scope.getScopeId();
|
|
17274
18173
|
for (const key of STRUCTURAL_ATTRS) delete node.attribs[key];
|
|
18174
|
+
if (richText) node.children = [];
|
|
17275
18175
|
let dataset;
|
|
17276
18176
|
for (const [key, value] of Object.entries({ ...node.attribs })) {
|
|
17277
18177
|
if (EVENT_BINDING_ATTRS.includes(key)) {
|
|
@@ -17279,6 +18179,8 @@ function applyNodeBindings(node, scope) {
|
|
|
17279
18179
|
continue;
|
|
17280
18180
|
}
|
|
17281
18181
|
const resolvedValue = typeof value === "string" ? resolveAttributeValue(value, scope) : value;
|
|
18182
|
+
if (key === "value") setNativePickerValue(node, resolvedValue);
|
|
18183
|
+
if (richText && key === "nodes") node.children = renderRichTextNodes(resolvedValue);
|
|
17282
18184
|
node.attribs[key] = String(resolvedValue ?? "");
|
|
17283
18185
|
if (isDatasetAttribute(key)) {
|
|
17284
18186
|
dataset ??= {};
|
|
@@ -17305,8 +18207,7 @@ function createLoopScope(scope, itemName, indexName, item, index) {
|
|
|
17305
18207
|
//#endregion
|
|
17306
18208
|
//#region ../../mpcore/packages/simulator/src/runtime/render/component.ts
|
|
17307
18209
|
function resolveComponentRegistryEntry(context, ownerJsonPath, ownerFilePath, alias, genericComponentBasePath) {
|
|
17308
|
-
const
|
|
17309
|
-
const componentBasePath = genericComponentBasePath ?? usingComponents.get(alias);
|
|
18210
|
+
const componentBasePath = genericComponentBasePath ?? resolveUsingComponent(context, ownerJsonPath, ownerFilePath, alias);
|
|
17310
18211
|
if (!componentBasePath) return null;
|
|
17311
18212
|
const filePath = `${componentBasePath}.js`;
|
|
17312
18213
|
const templatePath = `${componentBasePath}.wxml`;
|
|
@@ -17327,30 +18228,25 @@ function readComponentConfig(artifactSource, jsonPath) {
|
|
|
17327
18228
|
return {};
|
|
17328
18229
|
}
|
|
17329
18230
|
}
|
|
17330
|
-
function
|
|
18231
|
+
function resolveUsingComponent(context, ownerJsonPath, ownerFilePath, alias) {
|
|
17331
18232
|
try {
|
|
17332
18233
|
const usingComponents = readComponentConfig(context.artifactSource, ownerJsonPath).usingComponents;
|
|
17333
|
-
if (!usingComponents || typeof usingComponents !== "object" || Array.isArray(usingComponents)) return
|
|
17334
|
-
const
|
|
17335
|
-
|
|
17336
|
-
|
|
17337
|
-
const basePath = resolvePluginRequest(context.project.plugins, rawPath, "publicComponent")?.resourcePath ?? resolveMiniProgramComponent(ownerFilePath, rawPath, context.project.miniprogramRootPath, (candidate) => context.artifactSource.readText(candidate) !== void 0);
|
|
17338
|
-
resolved.set(alias, basePath.replace(LEADING_SLASH_RE$4, ""));
|
|
17339
|
-
}
|
|
17340
|
-
return resolved;
|
|
18234
|
+
if (!usingComponents || typeof usingComponents !== "object" || Array.isArray(usingComponents)) return;
|
|
18235
|
+
const rawPath = usingComponents[alias];
|
|
18236
|
+
if (typeof rawPath !== "string") return;
|
|
18237
|
+
return (resolvePluginRequest(context.project.plugins, rawPath, "publicComponent")?.resourcePath ?? resolveMiniProgramComponent(ownerFilePath, rawPath, context.project.miniprogramRootPath, (candidate) => context.artifactSource.has(candidate))).replace(LEADING_SLASH_RE$4, "");
|
|
17341
18238
|
} catch {
|
|
17342
|
-
return
|
|
18239
|
+
return;
|
|
17343
18240
|
}
|
|
17344
18241
|
}
|
|
17345
18242
|
function resolveComponentGenerics(context, hostNode, ownerJsonPath, ownerFilePath, componentFilePath, ownerGenerics) {
|
|
17346
18243
|
const componentJsonPath = path.resolve(context.project.miniprogramRootPath, `${componentFilePath.replace(JS_FILE_RE, "")}.json`);
|
|
17347
18244
|
const componentGenerics = readComponentConfig(context.artifactSource, componentJsonPath).componentGenerics;
|
|
17348
18245
|
if (!componentGenerics || typeof componentGenerics !== "object" || Array.isArray(componentGenerics)) return;
|
|
17349
|
-
const ownerComponents = resolveUsingComponents(context, ownerJsonPath, ownerFilePath);
|
|
17350
18246
|
const resolved = /* @__PURE__ */ new Map();
|
|
17351
18247
|
for (const [genericName, definition] of Object.entries(componentGenerics)) {
|
|
17352
18248
|
const selectedAlias = hostNode.attribs?.[`generic:${genericName}`];
|
|
17353
|
-
const selectedPath = selectedAlias ? ownerGenerics?.get(selectedAlias) ??
|
|
18249
|
+
const selectedPath = selectedAlias ? ownerGenerics?.get(selectedAlias) ?? resolveUsingComponent(context, ownerJsonPath, ownerFilePath, selectedAlias) : void 0;
|
|
17354
18250
|
if (selectedPath) {
|
|
17355
18251
|
resolved.set(genericName, selectedPath);
|
|
17356
18252
|
continue;
|
|
@@ -17362,67 +18258,6 @@ function resolveComponentGenerics(context, hostNode, ownerJsonPath, ownerFilePat
|
|
|
17362
18258
|
}
|
|
17363
18259
|
return resolved.size > 0 ? resolved : void 0;
|
|
17364
18260
|
}
|
|
17365
|
-
function collectComponentEventBindings(hostNode) {
|
|
17366
|
-
return collectMiniProgramEventBindings(hostNode.attribs);
|
|
17367
|
-
}
|
|
17368
|
-
function buildComponentTrigger(componentScopeId, context, hostNode) {
|
|
17369
|
-
const hostDataset = collectDataset(hostNode);
|
|
17370
|
-
const hostId = hostNode.attribs?.id ?? "";
|
|
17371
|
-
return (instance, eventName, detail, triggerOptions) => {
|
|
17372
|
-
const originScope = context.componentScopes.get(componentScopeId);
|
|
17373
|
-
const interactionMark = instance.__lastInteractionEvent__?.mark;
|
|
17374
|
-
const target = {
|
|
17375
|
-
dataset: originScope?.dataset ?? hostDataset,
|
|
17376
|
-
id: originScope?.hostId ?? hostId
|
|
17377
|
-
};
|
|
17378
|
-
let currentScopeId = componentScopeId;
|
|
17379
|
-
while (currentScopeId) {
|
|
17380
|
-
const currentScope = context.componentScopes.get(currentScopeId);
|
|
17381
|
-
const binding = currentScope?.eventBindings?.get(eventName);
|
|
17382
|
-
const listenerScope = currentScope?.listenerScopeId ? context.componentScopes.get(currentScope.listenerScopeId) : null;
|
|
17383
|
-
const handler = binding && listenerScope ? listenerScope.getMethod(binding.method) : void 0;
|
|
17384
|
-
if (handler) handler({
|
|
17385
|
-
bubbles: triggerOptions?.bubbles ?? false,
|
|
17386
|
-
capturePhase: false,
|
|
17387
|
-
composed: triggerOptions?.composed ?? false,
|
|
17388
|
-
currentTarget: {
|
|
17389
|
-
dataset: currentScope?.dataset ?? hostDataset,
|
|
17390
|
-
id: currentScope?.hostId ?? hostId
|
|
17391
|
-
},
|
|
17392
|
-
detail,
|
|
17393
|
-
mark: interactionMark,
|
|
17394
|
-
target,
|
|
17395
|
-
type: eventName
|
|
17396
|
-
});
|
|
17397
|
-
if (binding?.stopAfter) break;
|
|
17398
|
-
if (!triggerOptions?.bubbles || !triggerOptions?.composed) break;
|
|
17399
|
-
currentScopeId = currentScope?.ownerScopeId;
|
|
17400
|
-
}
|
|
17401
|
-
};
|
|
17402
|
-
}
|
|
17403
|
-
function syncComponentProperties(instance, definition, nextProperties, bindingExpressions, changedPageKeys) {
|
|
17404
|
-
const changedRootKeys = [];
|
|
17405
|
-
const previousProperties = {};
|
|
17406
|
-
for (const [key, value] of Object.entries(nextProperties)) {
|
|
17407
|
-
const nextValue = normalizeComponentPropertyValue(definition, key, value);
|
|
17408
|
-
const bindingExpression = bindingExpressions[key];
|
|
17409
|
-
const bindingAffected = !!bindingExpression && changedPageKeys.some((changedKey) => {
|
|
17410
|
-
return changedKey === bindingExpression || changedKey.startsWith(`${bindingExpression}.`) || changedKey.startsWith(`${bindingExpression}[`);
|
|
17411
|
-
});
|
|
17412
|
-
const previousSnapshot = instance.__propertySnapshots?.[key];
|
|
17413
|
-
if (hasComponentPropertyValueChanged(instance.properties[key], previousSnapshot, nextValue, bindingAffected)) {
|
|
17414
|
-
previousProperties[key] = instance.properties[key];
|
|
17415
|
-
const deliveredValue = cloneValue$1(nextValue);
|
|
17416
|
-
instance.properties[key] = deliveredValue;
|
|
17417
|
-
if (Object.hasOwn(definition.properties ?? {}, key)) instance.data[key] = deliveredValue;
|
|
17418
|
-
changedRootKeys.push(key);
|
|
17419
|
-
}
|
|
17420
|
-
instance.__propertySnapshots ??= {};
|
|
17421
|
-
instance.__propertySnapshots[key] = cloneValue$1(nextValue);
|
|
17422
|
-
}
|
|
17423
|
-
if (changedRootKeys.length === 0) return;
|
|
17424
|
-
runComponentObservers(definition, instance, changedRootKeys, previousProperties);
|
|
17425
|
-
}
|
|
17426
18261
|
function createComponentScope(clonedNode, scope, componentScopeId, componentInstance, genericComponents, slots) {
|
|
17427
18262
|
const ownerScopeId = scope.getScopeId().includes("/") ? scope.getScopeId() : void 0;
|
|
17428
18263
|
return {
|
|
@@ -17430,7 +18265,7 @@ function createComponentScope(clonedNode, scope, componentScopeId, componentInst
|
|
|
17430
18265
|
classList: String(clonedNode.attribs?.class ?? "").split(CLASS_SPLIT_RE).map((item) => item.trim()).filter(Boolean),
|
|
17431
18266
|
data: { ...componentInstance.data },
|
|
17432
18267
|
dataset: collectDataset(clonedNode, wxsScopeData(scope)),
|
|
17433
|
-
|
|
18268
|
+
...bindComponentEventHost(clonedNode),
|
|
17434
18269
|
getMethod: (methodName) => {
|
|
17435
18270
|
const method = componentInstance?.[methodName];
|
|
17436
18271
|
return typeof method === "function" ? method.bind(componentInstance) : void 0;
|
|
@@ -17438,6 +18273,7 @@ function createComponentScope(clonedNode, scope, componentScopeId, componentInst
|
|
|
17438
18273
|
getScopeId: () => componentScopeId,
|
|
17439
18274
|
genericComponents,
|
|
17440
18275
|
hostId: typeof clonedNode.attribs?.id === "string" ? clonedNode.attribs.id : void 0,
|
|
18276
|
+
hostNode: clonedNode,
|
|
17441
18277
|
id: typeof clonedNode.attribs?.id === "string" ? clonedNode.attribs.id : void 0,
|
|
17442
18278
|
listenerScopeId: scope.getScopeId(),
|
|
17443
18279
|
ownerScopeId,
|
|
@@ -17460,13 +18296,13 @@ function resolveComponentProperties(clonedNode, scope, definition) {
|
|
|
17460
18296
|
bindingExpressions
|
|
17461
18297
|
};
|
|
17462
18298
|
}
|
|
17463
|
-
function createRuntimeComponentInstance(componentScopeId, context,
|
|
17464
|
-
const
|
|
17465
|
-
const componentInstance = createComponentInstance({
|
|
18299
|
+
function createRuntimeComponentInstance(componentScopeId, context, componentEntry, nextProperties, ownerScopeId, renderTemplate, bindEventsBeforeProperties = false) {
|
|
18300
|
+
const instanceOptions = {
|
|
17466
18301
|
definition: componentEntry.definition,
|
|
17467
|
-
requestRender: (callback) => context.session.requestRender(callback)
|
|
17468
|
-
|
|
17469
|
-
|
|
18302
|
+
requestRender: (callback) => context.session.requestRender(callback)
|
|
18303
|
+
};
|
|
18304
|
+
const componentInstance = createComponentInstance(instanceOptions);
|
|
18305
|
+
bindAttachmentBindingScope(componentInstance, context);
|
|
17470
18306
|
setSelectorQueryScopeId(componentInstance, componentScopeId);
|
|
17471
18307
|
componentInstance.is = componentEntry.filePath.replace(JS_FILE_RE, "");
|
|
17472
18308
|
componentInstance.createIntersectionObserver = (options) => context.session.createIntersectionObserver(componentInstance, options);
|
|
@@ -17474,19 +18310,29 @@ function createRuntimeComponentInstance(componentScopeId, context, clonedNode, c
|
|
|
17474
18310
|
componentInstance.createSelectorQuery = () => context.moduleLoader.wx.createSelectorQuery().in(componentInstance);
|
|
17475
18311
|
componentInstance.selectComponent = (selector) => resolveNativeComponentSelection(context.session.selectComponentWithin(componentScopeId, selector));
|
|
17476
18312
|
componentInstance.selectAllComponents = (selector) => context.session.selectAllComponentsWithin(componentScopeId, selector).map(resolveNativeComponentSelection);
|
|
17477
|
-
componentInstance.selectOwnerComponent = () => ownerScopeId ? context.componentCache.get(ownerScopeId)
|
|
18313
|
+
componentInstance.selectOwnerComponent = () => ownerScopeId ? resolveNativeComponentSelection(context.componentCache.get(ownerScopeId)) : null;
|
|
18314
|
+
beginComponentConstruction(context.componentCache, componentScopeId, componentInstance);
|
|
17478
18315
|
context.componentCache.set(componentScopeId, componentInstance);
|
|
17479
|
-
|
|
17480
|
-
|
|
17481
|
-
|
|
17482
|
-
|
|
17483
|
-
|
|
18316
|
+
try {
|
|
18317
|
+
renderTemplate?.(componentInstance, "defaults");
|
|
18318
|
+
runComponentLifecycle(componentInstance, "created");
|
|
18319
|
+
if (bindEventsBeforeProperties) instanceOptions.triggerEvent = buildComponentTrigger(componentScopeId, context);
|
|
18320
|
+
componentInstance.__propertySnapshots = Object.fromEntries(Object.entries(componentInstance.properties).map(([key, propertyValue]) => [key, cloneValue$1(propertyValue)]));
|
|
18321
|
+
syncComponentProperties(componentInstance, componentInstance.__definition__ ?? componentEntry.definition, nextProperties, {}, [], renderTemplate);
|
|
18322
|
+
if (!bindEventsBeforeProperties) instanceOptions.triggerEvent = buildComponentTrigger(componentScopeId, context);
|
|
18323
|
+
return componentInstance;
|
|
18324
|
+
} catch (error) {
|
|
18325
|
+
discardComponentConstruction(context.componentCache, context.componentScopes, componentScopeId);
|
|
18326
|
+
throw error;
|
|
18327
|
+
} finally {
|
|
18328
|
+
finishComponentConstruction(context.componentCache, componentInstance);
|
|
18329
|
+
}
|
|
17484
18330
|
}
|
|
17485
|
-
function renderRuntimeComponentTemplate(context, componentEntry, renderNodeTree, componentScope, componentScopeId,
|
|
18331
|
+
function renderRuntimeComponentTemplate(context, componentEntry, renderNodeTree, componentScope, componentScopeId, renderPass) {
|
|
17486
18332
|
const componentDocument = parseTemplateDocument(readTemplateSource(context.artifactSource, componentEntry.absoluteTemplatePath));
|
|
17487
18333
|
const componentRoot = (componentDocument.children ?? [])[0] ?? componentDocument;
|
|
17488
18334
|
const templateRenderState = prepareTemplateRenderState(context.artifactSource, componentRoot, componentEntry.absoluteTemplatePath, context.project.miniprogramRootPath, getRuntimeWxsLoader(context.moduleLoader, context.artifactSource));
|
|
17489
|
-
return renderNodeTree(componentRoot, componentScope, context, path.resolve(context.project.miniprogramRootPath, `${componentEntry.filePath.replace(JS_FILE_RE, "")}.json`), componentEntry.filePath, componentScopeId,
|
|
18335
|
+
return renderNodeTree(componentRoot, componentScope, context, path.resolve(context.project.miniprogramRootPath, `${componentEntry.filePath.replace(JS_FILE_RE, "")}.json`), componentEntry.filePath, componentScopeId, renderPass, templateRenderState, componentScope.hostNode);
|
|
17490
18336
|
}
|
|
17491
18337
|
//#endregion
|
|
17492
18338
|
//#region ../../mpcore/packages/simulator/src/runtime/render/index.ts
|
|
@@ -17500,24 +18346,33 @@ function expandNodeByFor(node, scope) {
|
|
|
17500
18346
|
const items = resolveLoopEntries(resolveRawValueByPath$1(wxsScopeData(scope), forExpression));
|
|
17501
18347
|
const itemName = node.attribs?.["wx:for-item"]?.trim() || "item";
|
|
17502
18348
|
const indexName = node.attribs?.["wx:for-index"]?.trim() || "index";
|
|
18349
|
+
const key = node.attribs?.["wx:key"]?.trim();
|
|
18350
|
+
const keyOccurrences = key ? /* @__PURE__ */ new Map() : void 0;
|
|
17503
18351
|
return items.map(([index, item]) => ({
|
|
17504
18352
|
node: cloneNode(node),
|
|
17505
18353
|
scope: createLoopScope(scope, itemName, indexName, item, index),
|
|
17506
|
-
instanceSuffix:
|
|
18354
|
+
instanceSuffix: resolveLoopInstanceSuffix(item, index, key, keyOccurrences)
|
|
17507
18355
|
}));
|
|
17508
18356
|
}
|
|
17509
|
-
function renderNodeVariants(node, scope, context, ownerJsonPath, ownerFilePath, instancePath,
|
|
17510
|
-
|
|
18357
|
+
function renderNodeVariants(node, scope, context, ownerJsonPath, ownerFilePath, instancePath, renderPass, templateRenderState, parent) {
|
|
18358
|
+
const nodes = [];
|
|
18359
|
+
if (isRenderPassStale(renderPass)) return nodes;
|
|
18360
|
+
for (const { node: expandedNode, scope: expandedScope, instanceSuffix } of expandNodeByFor(node, scope)) {
|
|
18361
|
+
if (isRenderPassStale(renderPass)) break;
|
|
18362
|
+
nodes.push(renderNodeTree(expandedNode, expandedScope, context, ownerJsonPath, ownerFilePath, `${instancePath}${instanceSuffix}`, renderPass, templateRenderState, parent));
|
|
18363
|
+
}
|
|
18364
|
+
return nodes;
|
|
17511
18365
|
}
|
|
17512
|
-
function renderChildren(children, scope, context, ownerJsonPath, ownerFilePath, instancePath,
|
|
18366
|
+
function renderChildren(children, scope, context, ownerJsonPath, ownerFilePath, instancePath, renderPass, templateRenderState, parent) {
|
|
17513
18367
|
const renderedChildren = [];
|
|
17514
18368
|
for (const { node: child, index } of selectConditionalChildren(children, (node) => evaluateConditionalBranch(node, scope))) {
|
|
18369
|
+
if (isRenderPassStale(renderPass)) break;
|
|
17515
18370
|
if (!isTagNode(child)) {
|
|
17516
|
-
renderedChildren.push(...renderNodeVariants(child, scope, context, ownerJsonPath, ownerFilePath, `${instancePath}/node-${index}`,
|
|
18371
|
+
renderedChildren.push(...renderNodeVariants(child, scope, context, ownerJsonPath, ownerFilePath, `${instancePath}/node-${index}`, renderPass, templateRenderState, parent));
|
|
17517
18372
|
continue;
|
|
17518
18373
|
}
|
|
17519
18374
|
if (isTemplateDefinition(child) || child.name === "import" || child.name === "wxs") continue;
|
|
17520
|
-
renderedChildren.push(...renderNodeVariants(child, scope, context, ownerJsonPath, ownerFilePath, `${instancePath}/node-${index}`,
|
|
18375
|
+
renderedChildren.push(...renderNodeVariants(child, scope, context, ownerJsonPath, ownerFilePath, `${instancePath}/node-${index}`, renderPass, templateRenderState, parent));
|
|
17521
18376
|
}
|
|
17522
18377
|
return renderedChildren;
|
|
17523
18378
|
}
|
|
@@ -17549,22 +18404,38 @@ function collectComponentSlots(componentNode, scope, ownerJsonPath, ownerFilePat
|
|
|
17549
18404
|
}
|
|
17550
18405
|
return slots;
|
|
17551
18406
|
}
|
|
17552
|
-
function
|
|
18407
|
+
function reconcileSlotDeclarations(context, renderPass) {
|
|
18408
|
+
for (const [entries, { parent, scopeId }] of renderPass.slotDeclarations) {
|
|
18409
|
+
if (isRenderPassStale(renderPass)) return;
|
|
18410
|
+
if (isComponentConstructing(context.componentCache.get(scopeId))) continue;
|
|
18411
|
+
for (const { index } of selectConditionalChildren(entries.map((entry) => entry.node), (node, index) => evaluateConditionalBranch(node, entries[index].scope))) {
|
|
18412
|
+
if (isRenderPassStale(renderPass)) return;
|
|
18413
|
+
const entry = entries[index];
|
|
18414
|
+
if (renderPass.renderedSlots.has(entry)) continue;
|
|
18415
|
+
const nodes = renderNodeVariants(entry.node, entry.scope, context, entry.ownerJsonPath, entry.ownerFilePath, entry.instancePath, renderPass, entry.templateRenderState, parent);
|
|
18416
|
+
renderPass.renderedSlots.set(entry, nodes);
|
|
18417
|
+
renderPass.hasUnprojectedSlots ||= nodes.length > 0;
|
|
18418
|
+
}
|
|
18419
|
+
}
|
|
18420
|
+
}
|
|
18421
|
+
function renderNodeTree(node, scope, context, ownerJsonPath, ownerFilePath, instancePath, renderPass, templateRenderState, parent) {
|
|
18422
|
+
if (isRenderPassStale(renderPass)) return node;
|
|
17553
18423
|
if (scope.wxs !== templateRenderState.wxsModules) scope = {
|
|
17554
18424
|
...scope,
|
|
17555
18425
|
wxs: templateRenderState.wxsModules
|
|
17556
18426
|
};
|
|
17557
18427
|
const clonedNode = cloneNode(node);
|
|
18428
|
+
registerComponentEventNode(clonedNode, scope, parent);
|
|
17558
18429
|
if (!isTagNode(clonedNode)) {
|
|
17559
18430
|
applyNodeBindings(clonedNode, scope);
|
|
17560
18431
|
return clonedNode;
|
|
17561
18432
|
}
|
|
17562
|
-
if (isTemplateDefinition(clonedNode))
|
|
17563
|
-
|
|
17564
|
-
|
|
17565
|
-
|
|
17566
|
-
|
|
17567
|
-
}
|
|
18433
|
+
if (isTemplateDefinition(clonedNode)) {
|
|
18434
|
+
clonedNode.name = "block";
|
|
18435
|
+
clonedNode.attribs = {};
|
|
18436
|
+
clonedNode.children = [];
|
|
18437
|
+
return clonedNode;
|
|
18438
|
+
}
|
|
17568
18439
|
const templateName = resolveTemplateCall(clonedNode, wxsScopeData(scope));
|
|
17569
18440
|
if (templateName) {
|
|
17570
18441
|
const definition = templateRenderState.definitions.get(templateName);
|
|
@@ -17573,39 +18444,42 @@ function renderNodeTree(node, scope, context, ownerJsonPath, ownerFilePath, inst
|
|
|
17573
18444
|
data: resolveTemplateData(clonedNode, wxsScopeData(scope)),
|
|
17574
18445
|
wxs: definition && templateRenderState.definitionWxsScopes?.get(definition)
|
|
17575
18446
|
};
|
|
17576
|
-
|
|
18447
|
+
clonedNode.name = "block";
|
|
18448
|
+
clonedNode.attribs = {
|
|
18449
|
+
"data-sim-node": instancePath,
|
|
18450
|
+
"data-sim-scope": scope.getScopeId()
|
|
18451
|
+
};
|
|
18452
|
+
clonedNode.children = definition && !templateRenderState.stack.includes(templateName) ? renderChildren(definition.children ?? [], templateScope, context, ownerJsonPath, ownerFilePath, `${instancePath}/template-${templateName}`, renderPass, {
|
|
17577
18453
|
definitions: templateRenderState.definitionScopes?.get(definition) ?? templateRenderState.definitions,
|
|
17578
18454
|
definitionScopes: templateRenderState.definitionScopes,
|
|
17579
18455
|
definitionWxsScopes: templateRenderState.definitionWxsScopes,
|
|
17580
18456
|
wxsModules: templateScope.wxs,
|
|
17581
18457
|
stack: [...templateRenderState.stack, templateName]
|
|
17582
|
-
}) : [];
|
|
17583
|
-
return
|
|
17584
|
-
type: "tag",
|
|
17585
|
-
name: "block",
|
|
17586
|
-
attribs: {
|
|
17587
|
-
"data-sim-node": instancePath,
|
|
17588
|
-
"data-sim-scope": scope.getScopeId()
|
|
17589
|
-
},
|
|
17590
|
-
children
|
|
17591
|
-
};
|
|
18458
|
+
}, clonedNode) : [];
|
|
18459
|
+
return clonedNode;
|
|
17592
18460
|
}
|
|
17593
18461
|
if (clonedNode.name === "slot") {
|
|
17594
18462
|
const slotName = clonedNode.attribs?.name?.trim() || "default";
|
|
17595
18463
|
const projected = scope.slots?.get(slotName) ?? [];
|
|
17596
|
-
const
|
|
17597
|
-
|
|
17598
|
-
|
|
17599
|
-
|
|
17600
|
-
|
|
17601
|
-
|
|
17602
|
-
name: "block",
|
|
17603
|
-
attribs: {
|
|
17604
|
-
"data-sim-node": instancePath,
|
|
17605
|
-
"data-sim-scope": scope.getScopeId()
|
|
17606
|
-
},
|
|
17607
|
-
children
|
|
18464
|
+
const fallbackChildren = clonedNode.children ?? [];
|
|
18465
|
+
bindComponentEventHost(clonedNode);
|
|
18466
|
+
clonedNode.name = "block";
|
|
18467
|
+
clonedNode.attribs = {
|
|
18468
|
+
"data-sim-node": instancePath,
|
|
18469
|
+
"data-sim-scope": scope.getScopeId()
|
|
17608
18470
|
};
|
|
18471
|
+
const slotOwner = scope.getScopeId();
|
|
18472
|
+
if (projected.length && slotOwner && isComponentConstructing(context.componentCache.get(slotOwner))) {
|
|
18473
|
+
clonedNode.children = [];
|
|
18474
|
+
return clonedNode;
|
|
18475
|
+
}
|
|
18476
|
+
clonedNode.children = projected.length ? selectConditionalChildren(projected.map((entry) => entry.node), (node, index) => evaluateConditionalBranch(node, projected[index].scope)).flatMap(({ index }) => {
|
|
18477
|
+
const entry = projected[index];
|
|
18478
|
+
const nodes = renderNodeVariants(entry.node, entry.scope, context, entry.ownerJsonPath, entry.ownerFilePath, entry.instancePath, renderPass, entry.templateRenderState, clonedNode);
|
|
18479
|
+
renderPass.renderedSlots.set(entry, nodes);
|
|
18480
|
+
return nodes;
|
|
18481
|
+
}) : renderChildren(fallbackChildren, scope, context, ownerJsonPath, ownerFilePath, `${instancePath}/slot-fallback-${slotName}`, renderPass, templateRenderState, clonedNode);
|
|
18482
|
+
return clonedNode;
|
|
17609
18483
|
}
|
|
17610
18484
|
const componentEntry = resolveComponentRegistryEntry(context, ownerJsonPath, ownerFilePath, clonedNode.name, scope.genericComponents?.get(clonedNode.name));
|
|
17611
18485
|
if (componentEntry) {
|
|
@@ -17614,19 +18488,31 @@ function renderNodeTree(node, scope, context, ownerJsonPath, ownerFilePath, inst
|
|
|
17614
18488
|
const { nextProperties, bindingExpressions } = resolveComponentProperties(clonedNode, scope, componentEntry.definition);
|
|
17615
18489
|
const genericComponents = resolveComponentGenerics(context, clonedNode, ownerJsonPath, ownerFilePath, componentEntry.filePath, scope.genericComponents);
|
|
17616
18490
|
const slots = collectComponentSlots(clonedNode, scope, ownerJsonPath, ownerFilePath, componentScopeId, templateRenderState);
|
|
18491
|
+
registerSlotDeclarations(renderPass, slots, clonedNode, componentScopeId);
|
|
18492
|
+
applyNodeBindings(clonedNode, scope);
|
|
18493
|
+
const reconcilePrivateTemplate = (instance, phase) => {
|
|
18494
|
+
let bindingPass;
|
|
18495
|
+
do {
|
|
18496
|
+
const bindingScope = createComponentScope(clonedNode, scope, componentScopeId, instance, genericComponents, slots);
|
|
18497
|
+
context.componentScopes.set(componentScopeId, bindingScope);
|
|
18498
|
+
bindingPass = createRenderPass(phase === "properties", renderPass);
|
|
18499
|
+
renderRuntimeComponentTemplate(context, componentEntry, renderNodeTree, bindingScope, componentScopeId, bindingPass);
|
|
18500
|
+
reconcileSlotDeclarations(context, bindingPass);
|
|
18501
|
+
} while (isRenderPassStale(bindingPass));
|
|
18502
|
+
};
|
|
17617
18503
|
let componentInstance = context.componentCache.get(componentScopeId);
|
|
17618
|
-
if (!componentInstance) componentInstance = createRuntimeComponentInstance(componentScopeId, context,
|
|
17619
|
-
|
|
17620
|
-
context.componentScopes.set(componentScopeId,
|
|
17621
|
-
|
|
17622
|
-
}
|
|
17623
|
-
|
|
17624
|
-
seenComponentScopes.add(componentScopeId);
|
|
18504
|
+
if (!componentInstance) componentInstance = createRuntimeComponentInstance(componentScopeId, context, componentEntry, nextProperties, ownerScopeId, reconcilePrivateTemplate, renderPass.propertyUpdate);
|
|
18505
|
+
else {
|
|
18506
|
+
context.componentScopes.set(componentScopeId, createComponentScope(clonedNode, scope, componentScopeId, componentInstance, genericComponents, slots));
|
|
18507
|
+
syncComponentProperties(componentInstance, componentInstance.__definition__ ?? componentEntry.definition, nextProperties, bindingExpressions, context.changedPageKeys, reconcilePrivateTemplate);
|
|
18508
|
+
}
|
|
18509
|
+
if (isRenderPassStale(renderPass)) return clonedNode;
|
|
18510
|
+
renderPass.seenComponentScopes.add(componentScopeId);
|
|
17625
18511
|
const componentScope = createComponentScope(clonedNode, scope, componentScopeId, componentInstance, genericComponents, slots);
|
|
17626
18512
|
context.componentScopes.set(componentScopeId, componentScope);
|
|
17627
|
-
const renderedComponentRoot = renderRuntimeComponentTemplate(context, componentEntry, renderNodeTree, componentScope, componentScopeId,
|
|
18513
|
+
const renderedComponentRoot = renderRuntimeComponentTemplate(context, componentEntry, renderNodeTree, componentScope, componentScopeId, renderPass);
|
|
18514
|
+
mergeComponentEventRoot(renderedComponentRoot, clonedNode);
|
|
17628
18515
|
if (renderedComponentRoot.attribs) {
|
|
17629
|
-
applyNodeBindings(clonedNode, scope);
|
|
17630
18516
|
renderedComponentRoot.attribs = {
|
|
17631
18517
|
...clonedNode.attribs,
|
|
17632
18518
|
...renderedComponentRoot.attribs
|
|
@@ -17639,66 +18525,94 @@ function renderNodeTree(node, scope, context, ownerJsonPath, ownerFilePath, inst
|
|
|
17639
18525
|
renderedComponentRoot.attribs["data-sim-node"] = instancePath;
|
|
17640
18526
|
renderedComponentRoot.attribs["data-sim-scope"] = componentScopeId;
|
|
17641
18527
|
}
|
|
18528
|
+
renderPass.componentRoots.set(componentScopeId, renderedComponentRoot);
|
|
17642
18529
|
return renderedComponentRoot;
|
|
17643
18530
|
}
|
|
17644
|
-
|
|
18531
|
+
const richText = clonedNode.name === "rich-text";
|
|
18532
|
+
applyNodeBindings(clonedNode, scope, richText);
|
|
17645
18533
|
clonedNode.attribs["data-sim-node"] = instancePath;
|
|
17646
|
-
|
|
18534
|
+
if (richText) return clonedNode;
|
|
18535
|
+
clonedNode.children = renderChildren(clonedNode.children ?? [], scope, context, ownerJsonPath, ownerFilePath, `${instancePath}/${clonedNode.name}`, renderPass, templateRenderState, clonedNode);
|
|
17647
18536
|
return clonedNode;
|
|
17648
18537
|
}
|
|
18538
|
+
function reconcileRuntimePageTree(context, page, bindingsOnly = false) {
|
|
18539
|
+
for (;;) {
|
|
18540
|
+
bindAttachmentBindingScope(context, page);
|
|
18541
|
+
if (page.__lastChangedKeys__) context.changedPageKeys = page.__lastChangedKeys__;
|
|
18542
|
+
const route = page.route.replace(LEADING_SLASH_RE$4, "");
|
|
18543
|
+
const resourcePath = context.project.routes.find((item) => item.route === route)?.resourcePath ?? route;
|
|
18544
|
+
const templatePath = path.resolve(context.project.miniprogramRootPath, `${resourcePath}.wxml`);
|
|
18545
|
+
const document = parseTemplateDocument(readTemplateSource(context.artifactSource, templatePath));
|
|
18546
|
+
const pageScopeId = `page:${route}`;
|
|
18547
|
+
const pageScope = {
|
|
18548
|
+
data: page.data,
|
|
18549
|
+
getMethod: (methodName) => {
|
|
18550
|
+
const method = page[methodName];
|
|
18551
|
+
return typeof method === "function" ? method.bind(page) : void 0;
|
|
18552
|
+
},
|
|
18553
|
+
getScopeId: () => pageScopeId,
|
|
18554
|
+
id: "page-root"
|
|
18555
|
+
};
|
|
18556
|
+
for (const scopeId of context.componentScopes.keys()) if (scopeId === pageScopeId || scopeId.startsWith(`${pageScopeId}/`)) context.componentScopes.delete(scopeId);
|
|
18557
|
+
context.componentScopes.set(pageScopeId, pageScope);
|
|
18558
|
+
const renderPass = createPageRenderPass(page, context.componentCache);
|
|
18559
|
+
const root = (document.children ?? [])[0] ?? document;
|
|
18560
|
+
const templateRenderState = prepareTemplateRenderState(context.artifactSource, root, templatePath, context.project.miniprogramRootPath, getRuntimeWxsLoader(context.moduleLoader, context.artifactSource));
|
|
18561
|
+
const renderedRoot = renderNodeTree(root, pageScope, context, path.resolve(context.project.miniprogramRootPath, `${resourcePath}.json`), `${resourcePath}.js`, pageScopeId, renderPass, templateRenderState);
|
|
18562
|
+
const roots = [renderedRoot];
|
|
18563
|
+
if (hasCustomTabBar(context.project.appConfig, route)) roots.push(renderNodeTree({
|
|
18564
|
+
type: "tag",
|
|
18565
|
+
name: "custom-tab-bar",
|
|
18566
|
+
attribs: {},
|
|
18567
|
+
children: []
|
|
18568
|
+
}, customTabBarHostScope(), context, path.resolve(context.project.miniprogramRootPath, "app.json"), "app.js", pageScopeId, renderPass, templateRenderState));
|
|
18569
|
+
reconcileSlotDeclarations(context, renderPass);
|
|
18570
|
+
if (isRenderPassStale(renderPass)) continue;
|
|
18571
|
+
markPageTreeConstructed(page, context.componentCache);
|
|
18572
|
+
const treeRoot = roots.length > 1 ? {
|
|
18573
|
+
type: "root",
|
|
18574
|
+
children: roots
|
|
18575
|
+
} : renderedRoot;
|
|
18576
|
+
linkRenderedParents(treeRoot);
|
|
18577
|
+
registerInspectionTrees(treeRoot, renderPass, context.componentScopes);
|
|
18578
|
+
if (bindingsOnly) return {
|
|
18579
|
+
root: treeRoot,
|
|
18580
|
+
roots
|
|
18581
|
+
};
|
|
18582
|
+
let bindingsRefreshed = false;
|
|
18583
|
+
const updateBindings = () => {
|
|
18584
|
+
bindingsRefreshed = true;
|
|
18585
|
+
if (hasPendingComponentConstruction(context.componentCache)) return;
|
|
18586
|
+
reconcileRuntimePageTree(context, page, true);
|
|
18587
|
+
};
|
|
18588
|
+
const pageAttached = attachComponentPage(page, updateBindings);
|
|
18589
|
+
if (bindingsRefreshed) continue;
|
|
18590
|
+
const pageAttaching = isComponentPageAttaching(page);
|
|
18591
|
+
const scopeIds = orderComponentAttachmentScopes(renderPass.seenComponentScopes, context.componentScopes);
|
|
18592
|
+
const instances = scopeIds.map((scopeId) => context.componentCache.get(scopeId));
|
|
18593
|
+
const attached = !pageAttaching && runWithAttachmentBindingUpdates(page, updateBindings, (scopes) => flushComponentAttachments(context.componentCache, scopes, (instance) => {
|
|
18594
|
+
runComponentLifecycle(instance, "attached");
|
|
18595
|
+
return bindingsRefreshed;
|
|
18596
|
+
}), scopeIds);
|
|
18597
|
+
if (attached === "restart") continue;
|
|
18598
|
+
const canFinalize = !pageAttaching && !hasPendingComponentAttachments(instances);
|
|
18599
|
+
const relationsChanged = canFinalize && reconcileRemovedComponents(context.componentCache, context.componentScopes, renderPass.seenComponentScopes, pageScopeId);
|
|
18600
|
+
if (pageAttached || attached || relationsChanged) continue;
|
|
18601
|
+
if (canFinalize && !isPageBeforeReady(page)) flushDiscardedComponentReady(context.componentCache, pageScopeId, (instance) => runComponentLifecycle(instance, "ready"));
|
|
18602
|
+
if (canFinalize && !isPageBeforeReady(page) && flushComponentReady(instances, (instance) => {
|
|
18603
|
+
runComponentLifecycle(instance, "ready");
|
|
18604
|
+
if (instance !== context.componentCache.get(customTabBarScopeId(route))) instance.__definition__?.pageLifetimes?.show?.call(instance);
|
|
18605
|
+
})) continue;
|
|
18606
|
+
return {
|
|
18607
|
+
root: treeRoot,
|
|
18608
|
+
roots
|
|
18609
|
+
};
|
|
18610
|
+
}
|
|
18611
|
+
}
|
|
17649
18612
|
function renderRuntimePageTree(context, page) {
|
|
17650
|
-
const
|
|
17651
|
-
const resourcePath = context.project.routes.find((item) => item.route === route)?.resourcePath ?? route;
|
|
17652
|
-
const templatePath = path.resolve(context.project.miniprogramRootPath, `${resourcePath}.wxml`);
|
|
17653
|
-
const document = parseTemplateDocument(readTemplateSource(context.artifactSource, templatePath));
|
|
17654
|
-
const pageScopeId = `page:${route}`;
|
|
17655
|
-
const pageScope = {
|
|
17656
|
-
data: page.data,
|
|
17657
|
-
getMethod: (methodName) => {
|
|
17658
|
-
const method = page[methodName];
|
|
17659
|
-
return typeof method === "function" ? method.bind(page) : void 0;
|
|
17660
|
-
},
|
|
17661
|
-
getScopeId: () => pageScopeId,
|
|
17662
|
-
id: "page-root"
|
|
17663
|
-
};
|
|
17664
|
-
for (const scopeId of context.componentScopes.keys()) if (scopeId === pageScopeId || scopeId.startsWith(`${pageScopeId}/`)) context.componentScopes.delete(scopeId);
|
|
17665
|
-
context.componentScopes.set(pageScopeId, pageScope);
|
|
17666
|
-
const seenComponentScopes = /* @__PURE__ */ new Set();
|
|
17667
|
-
const root = (document.children ?? [])[0] ?? document;
|
|
17668
|
-
const templateRenderState = prepareTemplateRenderState(context.artifactSource, root, templatePath, context.project.miniprogramRootPath, getRuntimeWxsLoader(context.moduleLoader, context.artifactSource));
|
|
17669
|
-
const renderedRoot = renderNodeTree(root, pageScope, context, path.resolve(context.project.miniprogramRootPath, `${resourcePath}.json`), `${resourcePath}.js`, pageScopeId, seenComponentScopes, templateRenderState);
|
|
17670
|
-
const roots = [renderedRoot];
|
|
17671
|
-
if (hasCustomTabBar(context.project.appConfig, route)) roots.push(renderNodeTree({
|
|
17672
|
-
type: "tag",
|
|
17673
|
-
name: "custom-tab-bar",
|
|
17674
|
-
attribs: {},
|
|
17675
|
-
children: []
|
|
17676
|
-
}, customTabBarHostScope(), context, path.resolve(context.project.miniprogramRootPath, "app.json"), "app.js", pageScopeId, seenComponentScopes, templateRenderState));
|
|
17677
|
-
const pageAttached = attachComponentPage(page);
|
|
17678
|
-
const pageAttaching = isComponentPageAttaching(page);
|
|
17679
|
-
const attached = !pageAttaching && flushComponentAttachments([...seenComponentScopes].map((scopeId) => context.componentCache.get(scopeId)), (instance) => runComponentLifecycle(instance, "attached"));
|
|
17680
|
-
const removed = [...context.componentCache].filter(([scopeId]) => scopeId.startsWith(`${pageScopeId}/`) && !seenComponentScopes.has(scopeId));
|
|
17681
|
-
for (const [scopeId, instance] of removed) if (isComponentAttached(instance)) runComponentLifecycle(instance, "detached");
|
|
17682
|
-
else scheduleDiscardedComponentReady(context.componentCache, scopeId, instance);
|
|
17683
|
-
const instances = [...seenComponentScopes].map((scopeId) => context.componentCache.get(scopeId));
|
|
17684
|
-
const relationsChanged = !pageAttaching && !hasPendingComponentAttachments(instances) && syncComponentRelations(context.componentCache, seenComponentScopes, pageScopeId);
|
|
17685
|
-
for (const [scopeId] of removed) {
|
|
17686
|
-
context.componentCache.delete(scopeId);
|
|
17687
|
-
context.componentScopes.delete(scopeId);
|
|
17688
|
-
}
|
|
17689
|
-
if (pageAttached || attached || relationsChanged) return renderRuntimePageTree(context, page);
|
|
17690
|
-
if (!isPageBeforeReady(page)) flushDiscardedComponentReady(context.componentCache, pageScopeId, (instance) => runComponentLifecycle(instance, "ready"));
|
|
17691
|
-
if (!isPageBeforeReady(page) && flushComponentReady(instances, (instance) => {
|
|
17692
|
-
runComponentLifecycle(instance, "ready");
|
|
17693
|
-
if (instance !== context.componentCache.get(customTabBarScopeId(route))) instance.__definition__?.pageLifetimes?.show?.call(instance);
|
|
17694
|
-
})) return renderRuntimePageTree(context, page);
|
|
17695
|
-
const treeRoot = roots.length > 1 ? {
|
|
17696
|
-
type: "root",
|
|
17697
|
-
children: roots
|
|
17698
|
-
} : renderedRoot;
|
|
17699
|
-
linkRenderedParents(treeRoot);
|
|
18613
|
+
const { root, roots } = reconcileRuntimePageTree(context, page);
|
|
17700
18614
|
return {
|
|
17701
|
-
root
|
|
18615
|
+
root,
|
|
17702
18616
|
wxml: roots.map(serializeDomNode$1).join("")
|
|
17703
18617
|
};
|
|
17704
18618
|
}
|
|
@@ -17722,15 +18636,23 @@ function createDuplicateRegistrationError(kind, id) {
|
|
|
17722
18636
|
function callDefinitionMethod(instance, method, args) {
|
|
17723
18637
|
if (typeof method === "function") return method.apply(instance, args);
|
|
17724
18638
|
}
|
|
18639
|
+
function composeDefinitionMethods(primary, secondary) {
|
|
18640
|
+
if (typeof primary !== "function" || typeof secondary !== "function" || primary === secondary) return primary ?? secondary;
|
|
18641
|
+
return function composedDefinitionMethod(...args) {
|
|
18642
|
+
const result = primary.apply(this, args);
|
|
18643
|
+
secondary.apply(this, args);
|
|
18644
|
+
return result;
|
|
18645
|
+
};
|
|
18646
|
+
}
|
|
17725
18647
|
function normalizeComponentPageDefinition(definition) {
|
|
17726
18648
|
const { lifetimes = {}, methods = {}, pageLifetimes = {}, ...rest } = definition;
|
|
17727
18649
|
const created = lifetimes.created ?? rest.created;
|
|
17728
18650
|
const attached = lifetimes.attached ?? rest.attached;
|
|
17729
|
-
const ready = lifetimes.ready ?? rest.ready
|
|
18651
|
+
const ready = composeDefinitionMethods(lifetimes.ready ?? rest.ready, methods.onReady ?? rest.onReady);
|
|
17730
18652
|
const detached = lifetimes.detached ?? rest.detached ?? methods.onUnload ?? rest.onUnload;
|
|
17731
18653
|
const load = methods.onLoad ?? rest.onLoad;
|
|
17732
|
-
const show = pageLifetimes.show
|
|
17733
|
-
const hide = pageLifetimes.hide
|
|
18654
|
+
const show = typeof pageLifetimes.show === "function" ? composeDefinitionMethods(pageLifetimes.show, methods.onShow) : methods.onShow ?? rest.onShow;
|
|
18655
|
+
const hide = typeof pageLifetimes.hide === "function" ? composeDefinitionMethods(pageLifetimes.hide, methods.onHide) : methods.onHide ?? rest.onHide;
|
|
17734
18656
|
const resize = pageLifetimes.resize ?? methods.onResize ?? rest.onResize;
|
|
17735
18657
|
const routeDone = pageLifetimes.routeDone ?? methods.onRouteDone ?? rest.onRouteDone;
|
|
17736
18658
|
const pageDefinition = {
|
|
@@ -17758,10 +18680,7 @@ function normalizeComponentPageDefinition(definition) {
|
|
|
17758
18680
|
return callDefinitionMethod(this, routeDone, args);
|
|
17759
18681
|
}
|
|
17760
18682
|
};
|
|
17761
|
-
registerComponentPageAttachment(pageDefinition,
|
|
17762
|
-
callDefinitionMethod(this, created, []);
|
|
17763
|
-
callDefinitionMethod(this, attached, []);
|
|
17764
|
-
});
|
|
18683
|
+
registerComponentPageAttachment(pageDefinition, (instance) => callDefinitionMethod(instance, created, []), (instance) => callDefinitionMethod(instance, attached, []));
|
|
17765
18684
|
return pageDefinition;
|
|
17766
18685
|
}
|
|
17767
18686
|
function createHostRegistries() {
|
|
@@ -17952,7 +18871,7 @@ function resolveCapabilityValue(source, schema) {
|
|
|
17952
18871
|
}
|
|
17953
18872
|
return current;
|
|
17954
18873
|
}
|
|
17955
|
-
function createHeadlessWx(driver, runtimeConsole = console) {
|
|
18874
|
+
function createHeadlessWx(driver, runtimeConsole = console, workers) {
|
|
17956
18875
|
const eventBus = createHeadlessUniEventBus();
|
|
17957
18876
|
const rpx2px = (value) => {
|
|
17958
18877
|
const width = driver.getWindowInfoSync().windowWidth;
|
|
@@ -17960,6 +18879,10 @@ function createHeadlessWx(driver, runtimeConsole = console) {
|
|
|
17960
18879
|
};
|
|
17961
18880
|
const capabilityTree = {
|
|
17962
18881
|
canIUse: true,
|
|
18882
|
+
...workers ? {
|
|
18883
|
+
createWorker: true,
|
|
18884
|
+
preDownloadSubpackage: true
|
|
18885
|
+
} : {},
|
|
17963
18886
|
canvasToTempFilePath: true,
|
|
17964
18887
|
chooseImage: { return: {
|
|
17965
18888
|
errMsg: true,
|
|
@@ -18217,6 +19140,14 @@ function createHeadlessWx(driver, runtimeConsole = console) {
|
|
|
18217
19140
|
...eventBus,
|
|
18218
19141
|
[WEVU_ROUTE_EVENT_CONTRACT_KEY]: 1,
|
|
18219
19142
|
[WEVU_PAGE_SCROLL_EVENT_CONTRACT_KEY]: 1,
|
|
19143
|
+
createWorker: (script) => {
|
|
19144
|
+
if (!workers) throw new Error("Worker host is unavailable");
|
|
19145
|
+
return workers.createWorker(script);
|
|
19146
|
+
},
|
|
19147
|
+
preDownloadSubpackage: (option) => {
|
|
19148
|
+
if (!workers) throw new Error("Worker host is unavailable");
|
|
19149
|
+
workers.preDownloadSubpackage(option);
|
|
19150
|
+
},
|
|
18220
19151
|
canIUse: (schema) => typeof schema === "string" && schema.trim() !== "" && resolveCapabilityValue(capabilityTree, schema.trim()) != null,
|
|
18221
19152
|
canvasToTempFilePath: (option) => invokeWxApi(() => driver.canvasToTempFilePath(option), option),
|
|
18222
19153
|
chooseImage: (option) => invokeWxApi(() => driver.chooseImage(option ?? {}), option),
|
|
@@ -18340,9 +19271,7 @@ function createHeadlessWx(driver, runtimeConsole = console) {
|
|
|
18340
19271
|
navigateBack: (option) => runNavigationApi(driver, option, (deferred) => invokeWxApi(() => {
|
|
18341
19272
|
driver.navigateBack(deferred);
|
|
18342
19273
|
}, deferred)),
|
|
18343
|
-
navigateTo: (option) => runNavigationApi(driver, option, (deferred) =>
|
|
18344
|
-
driver.navigateTo(deferred);
|
|
18345
|
-
}, deferred)),
|
|
19274
|
+
navigateTo: (option) => runNavigationApi(driver, option, (deferred) => driver.navigateTo(deferred)),
|
|
18346
19275
|
nextTick: (callback) => driver.nextTick(callback),
|
|
18347
19276
|
offBeforeAppRoute: (listener) => driver.offBeforeAppRoute(listener),
|
|
18348
19277
|
offBeforePageUnload: (listener) => driver.offBeforePageUnload(listener),
|
|
@@ -18453,7 +19382,13 @@ function invokePreparedNavigationApi(prepare, option) {
|
|
|
18453
19382
|
//#region ../../mpcore/packages/simulator/src/kernel/artifactSource.ts
|
|
18454
19383
|
function createFileSystemArtifactSource() {
|
|
18455
19384
|
return {
|
|
18456
|
-
has
|
|
19385
|
+
has(filePath) {
|
|
19386
|
+
try {
|
|
19387
|
+
return fs.statSync(filePath).isFile();
|
|
19388
|
+
} catch {
|
|
19389
|
+
return false;
|
|
19390
|
+
}
|
|
19391
|
+
},
|
|
18457
19392
|
readText(filePath) {
|
|
18458
19393
|
try {
|
|
18459
19394
|
return fs.readFileSync(filePath, "utf8");
|
|
@@ -18598,6 +19533,62 @@ var RuntimeKernel = class {
|
|
|
18598
19533
|
}
|
|
18599
19534
|
};
|
|
18600
19535
|
//#endregion
|
|
19536
|
+
//#region ../../mpcore/packages/simulator/src/kernel/renderQueue.ts
|
|
19537
|
+
/** 两类宿主共享提交、错误诊断与等待回调边界,失败批次不自动重试。 */
|
|
19538
|
+
var RuntimeRenderQueue = class {
|
|
19539
|
+
options;
|
|
19540
|
+
closed = false;
|
|
19541
|
+
pending = false;
|
|
19542
|
+
running = false;
|
|
19543
|
+
callbacks = [];
|
|
19544
|
+
constructor(options) {
|
|
19545
|
+
this.options = options;
|
|
19546
|
+
}
|
|
19547
|
+
close() {
|
|
19548
|
+
this.closed = true;
|
|
19549
|
+
this.pending = false;
|
|
19550
|
+
this.callbacks.length = 0;
|
|
19551
|
+
}
|
|
19552
|
+
request(callback) {
|
|
19553
|
+
if (this.isClosed()) return;
|
|
19554
|
+
if (callback) this.callbacks.push(callback);
|
|
19555
|
+
if (this.pending) return;
|
|
19556
|
+
this.pending = true;
|
|
19557
|
+
if (this.running) return;
|
|
19558
|
+
Promise.resolve().then(async () => {
|
|
19559
|
+
if (this.isClosed()) return;
|
|
19560
|
+
this.pending = false;
|
|
19561
|
+
this.running = true;
|
|
19562
|
+
const callbacks = this.callbacks.splice(0);
|
|
19563
|
+
try {
|
|
19564
|
+
const rendered = this.options.render();
|
|
19565
|
+
if (rendered && typeof rendered.then === "function") await rendered;
|
|
19566
|
+
} catch (error) {
|
|
19567
|
+
this.options.onError(error);
|
|
19568
|
+
callbacks.push(...this.callbacks.splice(0));
|
|
19569
|
+
this.pending = false;
|
|
19570
|
+
} finally {
|
|
19571
|
+
for (const callback of callbacks) {
|
|
19572
|
+
if (this.isClosed()) break;
|
|
19573
|
+
try {
|
|
19574
|
+
callback();
|
|
19575
|
+
} catch (error) {
|
|
19576
|
+
this.options.onError(error);
|
|
19577
|
+
}
|
|
19578
|
+
}
|
|
19579
|
+
this.running = false;
|
|
19580
|
+
if (this.pending && !this.isClosed()) {
|
|
19581
|
+
this.pending = false;
|
|
19582
|
+
this.request();
|
|
19583
|
+
}
|
|
19584
|
+
}
|
|
19585
|
+
});
|
|
19586
|
+
}
|
|
19587
|
+
isClosed() {
|
|
19588
|
+
return this.closed || this.options.isClosed();
|
|
19589
|
+
}
|
|
19590
|
+
};
|
|
19591
|
+
//#endregion
|
|
18601
19592
|
//#region ../../mpcore/packages/simulator/src/project/resolveRoutes.ts
|
|
18602
19593
|
const LEADING_SLASH_RE$3 = /^\/+/;
|
|
18603
19594
|
const TRAILING_SLASH_RE$1 = /\/+$/;
|
|
@@ -18798,6 +19789,22 @@ function loadProject(projectPath) {
|
|
|
18798
19789
|
});
|
|
18799
19790
|
}
|
|
18800
19791
|
//#endregion
|
|
19792
|
+
//#region ../../mpcore/packages/simulator/src/view/nodeSerialization.ts
|
|
19793
|
+
function escapeText$1(text) {
|
|
19794
|
+
return text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
19795
|
+
}
|
|
19796
|
+
function serializeNode(node) {
|
|
19797
|
+
if (node.type === "text") return escapeText$1(node.data ?? "");
|
|
19798
|
+
if (node.type !== "tag") return (node.children ?? []).map(serializeNode).join("");
|
|
19799
|
+
if (node.name === "page") return (node.children ?? []).filter((child) => !(child.type === "tag" && (child.name === "import" || child.name === "wxs"))).map(serializeNode).join("");
|
|
19800
|
+
const attrs = Object.entries(node.attribs ?? {}).filter(([key]) => !key.startsWith("data-sim-")).map(([key, value]) => ` ${key}="${escapeText$1(value).replaceAll("\"", """)}"`).join("");
|
|
19801
|
+
return `<${node.name ?? ""}${attrs}>${(node.children ?? []).map(serializeNode).join("")}</${node.name ?? ""}>`;
|
|
19802
|
+
}
|
|
19803
|
+
function collectNodeText$1(node) {
|
|
19804
|
+
if (node.type === "text") return node.data ?? "";
|
|
19805
|
+
return (node.children ?? []).map(collectNodeText$1).join("");
|
|
19806
|
+
}
|
|
19807
|
+
//#endregion
|
|
18801
19808
|
//#region ../../node_modules/.pnpm/boolbase@2.0.0/node_modules/boolbase/dist/index.js
|
|
18802
19809
|
function trueFunc() {
|
|
18803
19810
|
return true;
|
|
@@ -20224,23 +21231,31 @@ function appendNextSiblings(element, adapter) {
|
|
|
20224
21231
|
const selectAll = getSelectorFunction((query, elements, options) => query === falseFunc || !elements || elements.length === 0 ? [] : findAll(query, elements, options));
|
|
20225
21232
|
//#endregion
|
|
20226
21233
|
//#region ../../mpcore/packages/simulator/src/view/selectors.ts
|
|
20227
|
-
|
|
20228
|
-
|
|
20229
|
-
|
|
20230
|
-
|
|
20231
|
-
|
|
20232
|
-
|
|
20233
|
-
|
|
20234
|
-
|
|
20235
|
-
|
|
20236
|
-
|
|
20237
|
-
|
|
20238
|
-
|
|
20239
|
-
|
|
20240
|
-
|
|
20241
|
-
|
|
20242
|
-
|
|
20243
|
-
|
|
21234
|
+
function createAdapter(getChildren, getParent) {
|
|
21235
|
+
const adapter = {
|
|
21236
|
+
isTag: (node) => node.type === "tag",
|
|
21237
|
+
getAttributeValue: (node, name) => node.attribs?.[name],
|
|
21238
|
+
getChildren,
|
|
21239
|
+
getName: (node) => node.name ?? "",
|
|
21240
|
+
getParent,
|
|
21241
|
+
getSiblings: (node) => {
|
|
21242
|
+
const parent = getParent(node);
|
|
21243
|
+
return parent ? getChildren(parent) : [node];
|
|
21244
|
+
},
|
|
21245
|
+
getText: (node) => node.type === "text" ? node.data ?? "" : getChildren(node).map((child) => adapter.getText(child)).join(""),
|
|
21246
|
+
hasAttrib: (node, name) => Object.hasOwn(node.attribs ?? {}, name),
|
|
21247
|
+
removeSubsets: (nodes) => {
|
|
21248
|
+
const unique = new Set(nodes);
|
|
21249
|
+
return [...unique].filter((node) => {
|
|
21250
|
+
for (let parent = getParent(node); parent; parent = getParent(parent)) if (unique.has(parent)) return false;
|
|
21251
|
+
return true;
|
|
21252
|
+
});
|
|
21253
|
+
}
|
|
21254
|
+
};
|
|
21255
|
+
return adapter;
|
|
21256
|
+
}
|
|
21257
|
+
const renderedAdapter = createAdapter((node) => node.children ?? [], (node) => node.parent ?? null);
|
|
21258
|
+
const inspectionAdapter = createAdapter(getInspectionChildren, getInspectionParent);
|
|
20244
21259
|
function resolveComponentTags(selectors) {
|
|
20245
21260
|
return selectors.map((group) => group.map((token) => {
|
|
20246
21261
|
if (token.type === SelectorType.Pseudo && Array.isArray(token.data)) return {
|
|
@@ -20263,7 +21278,7 @@ function resolveComponentTags(selectors) {
|
|
|
20263
21278
|
};
|
|
20264
21279
|
}));
|
|
20265
21280
|
}
|
|
20266
|
-
function
|
|
21281
|
+
function queryWithAdapter(root, selector, adapter) {
|
|
20267
21282
|
const parsed = parse$1(selector);
|
|
20268
21283
|
const query = resolveComponentTags(parsed);
|
|
20269
21284
|
const includesPageRoot = root.type === "tag" && root.name === "page" && parsed.some((group) => group.some((token) => token.type === SelectorType.Tag && token.name === "page"));
|
|
@@ -20272,12 +21287,18 @@ function querySelectorAll(root, selector) {
|
|
|
20272
21287
|
cacheResults: false
|
|
20273
21288
|
});
|
|
20274
21289
|
}
|
|
21290
|
+
function querySelectorAll(root, selector) {
|
|
21291
|
+
return queryWithAdapter(root, selector, renderedAdapter);
|
|
21292
|
+
}
|
|
21293
|
+
function queryInspectionSelectorAll(root, selector) {
|
|
21294
|
+
return queryWithAdapter(root, selector, inspectionAdapter);
|
|
21295
|
+
}
|
|
20275
21296
|
//#endregion
|
|
20276
21297
|
//#region ../../node_modules/.pnpm/whynot@5.0.0/node_modules/whynot/dist/whynot.umd.cjs
|
|
20277
|
-
var require_whynot_umd = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
21298
|
+
var require_whynot_umd = /* @__PURE__ */ __commonJSMin(((exports, module, this$4) => {
|
|
20278
21299
|
(function(t, s) {
|
|
20279
21300
|
"object" == typeof exports && "undefined" != typeof module ? s(exports) : "function" == typeof define && define.amd ? define(["exports"], s) : s((t = "undefined" != typeof globalThis ? globalThis : t || self).whynot = {});
|
|
20280
|
-
})(
|
|
21301
|
+
})(this$4, (function(t) {
|
|
20281
21302
|
"use strict";
|
|
20282
21303
|
function s(t, s, i, r) {
|
|
20283
21304
|
const n = {
|
|
@@ -20625,10 +21646,10 @@ var require_whynot_umd = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
20625
21646
|
}));
|
|
20626
21647
|
//#endregion
|
|
20627
21648
|
//#region ../../node_modules/.pnpm/xspattern@3.1.0/node_modules/xspattern/dist/xspattern.umd.cjs
|
|
20628
|
-
var require_xspattern_umd = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
21649
|
+
var require_xspattern_umd = /* @__PURE__ */ __commonJSMin(((exports, module, this$3) => {
|
|
20629
21650
|
(function(A, B) {
|
|
20630
21651
|
"object" == typeof exports && "undefined" != typeof module ? B(exports, require_whynot_umd()) : "function" == typeof define && define.amd ? define(["exports", "whynot"], B) : B((A = "undefined" != typeof globalThis ? globalThis : A || self).xspattern = {}, A.whynot);
|
|
20631
|
-
})(
|
|
21652
|
+
})(this$3, (function(A, B) {
|
|
20632
21653
|
"use strict";
|
|
20633
21654
|
function a(A) {
|
|
20634
21655
|
return (B) => B === A;
|
|
@@ -21925,10 +22946,10 @@ var require_xspattern_umd = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
21925
22946
|
}));
|
|
21926
22947
|
//#endregion
|
|
21927
22948
|
//#region ../../node_modules/.pnpm/prsc@4.0.0/node_modules/prsc/dist/prsc.umd.cjs
|
|
21928
|
-
var require_prsc_umd = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
22949
|
+
var require_prsc_umd = /* @__PURE__ */ __commonJSMin(((exports, module, this$2) => {
|
|
21929
22950
|
(function(n, t) {
|
|
21930
22951
|
"object" == typeof exports && "undefined" != typeof module ? t(exports) : "function" == typeof define && define.amd ? define(["exports"], t) : t((n = "undefined" != typeof globalThis ? globalThis : n || self).prsc = {});
|
|
21931
|
-
})(
|
|
22952
|
+
})(this$2, (function(n) {
|
|
21932
22953
|
"use strict";
|
|
21933
22954
|
function t(n, t) {
|
|
21934
22955
|
return {
|
|
@@ -22171,12 +23192,12 @@ var require_prsc_umd = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
22171
23192
|
}));
|
|
22172
23193
|
//#endregion
|
|
22173
23194
|
//#region ../../mpcore/packages/simulator/src/view/xpath.ts
|
|
22174
|
-
var import_fontoxpath = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
23195
|
+
var import_fontoxpath = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module, this$1) => {
|
|
22175
23196
|
(function(root, factory) {
|
|
22176
23197
|
if (typeof define === "function" && define.amd) define(["xspattern", "prsc"], factory);
|
|
22177
23198
|
else if (typeof exports === "object") module.exports = factory(require_xspattern_umd(), require_prsc_umd());
|
|
22178
23199
|
else root.fontoxpath = factory(root.xspattern, root.prsc);
|
|
22179
|
-
})(
|
|
23200
|
+
})(this$1, function(xspattern, prsc) {
|
|
22180
23201
|
return (function(xspattern, prsc) {
|
|
22181
23202
|
const VERSION = "3.34.0";
|
|
22182
23203
|
const fontoxpathGlobal = {};
|
|
@@ -38019,7 +39040,10 @@ var import_fontoxpath = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin((
|
|
|
38019
39040
|
});
|
|
38020
39041
|
})))(), 1);
|
|
38021
39042
|
const xpathEngine = Reflect.get(import_fontoxpath, "default") ?? import_fontoxpath;
|
|
38022
|
-
function
|
|
39043
|
+
function getRenderedChildren(node) {
|
|
39044
|
+
return node.children ?? [];
|
|
39045
|
+
}
|
|
39046
|
+
function wrapNode(source, getChildren, parent = null) {
|
|
38023
39047
|
const node = {
|
|
38024
39048
|
attributes: [],
|
|
38025
39049
|
children: [],
|
|
@@ -38042,7 +39066,7 @@ function wrapNode(source, parent = null) {
|
|
|
38042
39066
|
prefix: null,
|
|
38043
39067
|
value
|
|
38044
39068
|
}));
|
|
38045
|
-
node.children = (source
|
|
39069
|
+
node.children = getChildren(source).map((child) => wrapNode(child, getChildren, node));
|
|
38046
39070
|
return node;
|
|
38047
39071
|
}
|
|
38048
39072
|
function sibling(node, offset) {
|
|
@@ -38062,40 +39086,28 @@ const domFacade = {
|
|
|
38062
39086
|
getParentNode: (node) => node.parent,
|
|
38063
39087
|
getPreviousSibling: (node) => sibling(node, -1)
|
|
38064
39088
|
};
|
|
38065
|
-
function
|
|
39089
|
+
function queryElements(root, expression, getChildren) {
|
|
38066
39090
|
if (!expression.trim()) throw new Error("XPath must be a non-empty expression in headless testing runtime.");
|
|
38067
39091
|
const document = wrapNode(root.type === "root" ? root : {
|
|
38068
39092
|
type: "root",
|
|
38069
39093
|
children: [root]
|
|
38070
|
-
});
|
|
39094
|
+
}, getChildren);
|
|
38071
39095
|
return xpathEngine.evaluateXPathToNodes(expression, document, domFacade).filter((node) => node.nodeType === 1).map((node) => node.source);
|
|
38072
39096
|
}
|
|
39097
|
+
function queryXPathElements(root, expression) {
|
|
39098
|
+
return queryElements(root, expression, getRenderedChildren);
|
|
39099
|
+
}
|
|
39100
|
+
function queryInspectionXPathElements(root, expression) {
|
|
39101
|
+
return queryElements(root, expression, getInspectionChildren);
|
|
39102
|
+
}
|
|
38073
39103
|
//#endregion
|
|
38074
39104
|
//#region ../../mpcore/packages/simulator/src/view/nodeHandle.ts
|
|
38075
|
-
function escapeText$1(text) {
|
|
38076
|
-
return text.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
38077
|
-
}
|
|
38078
39105
|
function createValueEventDetail(value, detail) {
|
|
38079
39106
|
return {
|
|
38080
39107
|
value,
|
|
38081
39108
|
...detail ?? {}
|
|
38082
39109
|
};
|
|
38083
39110
|
}
|
|
38084
|
-
function escapeAttribute$1(value) {
|
|
38085
|
-
return escapeText$1(value).replaceAll("\"", """);
|
|
38086
|
-
}
|
|
38087
|
-
function serializeNode(node) {
|
|
38088
|
-
if (node.type === "text") return escapeText$1(node.data ?? "");
|
|
38089
|
-
if (node.type !== "tag") return (node.children ?? []).map(serializeNode).join("");
|
|
38090
|
-
if (node.name === "page") return (node.children ?? []).filter((child) => !(child.type === "tag" && (child.name === "import" || child.name === "wxs"))).map(serializeNode).join("");
|
|
38091
|
-
const attrs = Object.entries(node.attribs ?? {}).filter(([key]) => !key.startsWith("data-sim-")).map(([key, value]) => ` ${key}="${escapeAttribute$1(value)}"`).join("");
|
|
38092
|
-
const children = (node.children ?? []).map(serializeNode).join("");
|
|
38093
|
-
return `<${node.name ?? ""}${attrs}>${children}</${node.name ?? ""}>`;
|
|
38094
|
-
}
|
|
38095
|
-
function collectText(node) {
|
|
38096
|
-
if (node.type === "text") return node.data ?? "";
|
|
38097
|
-
return (node.children ?? []).map(collectText).join("");
|
|
38098
|
-
}
|
|
38099
39111
|
function resolvePageScopeId$1(scopeId) {
|
|
38100
39112
|
if (!scopeId) return null;
|
|
38101
39113
|
const pagePathIndex = scopeId.indexOf("/page/");
|
|
@@ -38116,7 +39128,7 @@ var HeadlessTestingNodeHandle = class HeadlessTestingNodeHandle {
|
|
|
38116
39128
|
this.interactions?.assertActive?.();
|
|
38117
39129
|
}
|
|
38118
39130
|
query(selector) {
|
|
38119
|
-
const nodes = querySelectorAll(this.node, selector);
|
|
39131
|
+
const nodes = (this.interactions?.projectionOnly ? querySelectorAll : queryInspectionSelectorAll)(this.node, selector);
|
|
38120
39132
|
const scope = this.node.attribs?.["data-sim-scope"];
|
|
38121
39133
|
if (!scope || !this.interactions) return nodes;
|
|
38122
39134
|
return nodes.filter((node) => {
|
|
@@ -38135,7 +39147,7 @@ var HeadlessTestingNodeHandle = class HeadlessTestingNodeHandle {
|
|
|
38135
39147
|
}
|
|
38136
39148
|
async getElementsByXpath(expression) {
|
|
38137
39149
|
this.assertActive();
|
|
38138
|
-
return queryXPathElements(this.node, expression).map((node) => new HeadlessTestingNodeHandle(node, this.interactions));
|
|
39150
|
+
return (this.interactions?.projectionOnly ? queryXPathElements : queryInspectionXPathElements)(this.node, expression).map((node) => new HeadlessTestingNodeHandle(node, this.interactions));
|
|
38139
39151
|
}
|
|
38140
39152
|
async attr(name) {
|
|
38141
39153
|
this.assertActive();
|
|
@@ -38173,7 +39185,7 @@ var HeadlessTestingNodeHandle = class HeadlessTestingNodeHandle {
|
|
|
38173
39185
|
}
|
|
38174
39186
|
async text() {
|
|
38175
39187
|
this.assertActive();
|
|
38176
|
-
return
|
|
39188
|
+
return collectNodeText$1(this.node);
|
|
38177
39189
|
}
|
|
38178
39190
|
async tagName() {
|
|
38179
39191
|
this.assertActive();
|
|
@@ -38185,10 +39197,23 @@ var HeadlessTestingNodeHandle = class HeadlessTestingNodeHandle {
|
|
|
38185
39197
|
const normalizedEventName = eventName.trim();
|
|
38186
39198
|
if (!normalizedEventName) throw new Error("Event name must be a non-empty string in headless testing runtime.");
|
|
38187
39199
|
let handlerResults;
|
|
38188
|
-
|
|
38189
|
-
|
|
38190
|
-
|
|
38191
|
-
|
|
39200
|
+
let nativeHandled;
|
|
39201
|
+
try {
|
|
39202
|
+
nativeHandled = this.interactions.dispatchNativeEvent?.(this.node, normalizedEventName, event, normalizedEventName === "tap" ? (result) => {
|
|
39203
|
+
handlerResults ??= [];
|
|
39204
|
+
handlerResults.push(result);
|
|
39205
|
+
} : void 0);
|
|
39206
|
+
} catch (error) {
|
|
39207
|
+
let failures;
|
|
39208
|
+
if (handlerResults) {
|
|
39209
|
+
for (const result of await Promise.allSettled(handlerResults)) if (result.status === "rejected") {
|
|
39210
|
+
failures ??= [error];
|
|
39211
|
+
failures.push(result.reason);
|
|
39212
|
+
}
|
|
39213
|
+
}
|
|
39214
|
+
if (failures) throw new AggregateError(failures, "Native interaction handlers failed", { cause: error });
|
|
39215
|
+
throw error;
|
|
39216
|
+
}
|
|
38192
39217
|
if (normalizedEventName === "tap" && nativeHandled) return handlerResults ? (await Promise.all(handlerResults))[0] : void 0;
|
|
38193
39218
|
const binding = resolveMiniProgramEventBinding(this.node.attribs, normalizedEventName);
|
|
38194
39219
|
if (!binding?.method) {
|
|
@@ -38200,6 +39225,20 @@ var HeadlessTestingNodeHandle = class HeadlessTestingNodeHandle {
|
|
|
38200
39225
|
async tap(event = {}) {
|
|
38201
39226
|
return await this.trigger("tap", event);
|
|
38202
39227
|
}
|
|
39228
|
+
async touchstart(event = {}) {
|
|
39229
|
+
return await this.trigger("touchstart", event);
|
|
39230
|
+
}
|
|
39231
|
+
async touchmove(event = {}) {
|
|
39232
|
+
return await this.trigger("touchmove", event);
|
|
39233
|
+
}
|
|
39234
|
+
async touchend(event = {}) {
|
|
39235
|
+
return await this.trigger("touchend", event);
|
|
39236
|
+
}
|
|
39237
|
+
async dispatchEvent({ eventName, $: selector, ...event }) {
|
|
39238
|
+
const target = selector ? await this.$(selector) : this;
|
|
39239
|
+
if (!target) throw new Error(`No node matching "${selector}" was found for dispatchEvent in headless testing runtime.`);
|
|
39240
|
+
return await target.trigger(eventName, event);
|
|
39241
|
+
}
|
|
38203
39242
|
async input(value, event = {}) {
|
|
38204
39243
|
return await this.trigger("input", {
|
|
38205
39244
|
...event,
|
|
@@ -38252,16 +39291,20 @@ function isMustacheOnly(value) {
|
|
|
38252
39291
|
return trimmed.startsWith("{{") && trimmed.endsWith("}}") && !trimmed.includes("{{", 2);
|
|
38253
39292
|
}
|
|
38254
39293
|
function visitDom(node, visitor) {
|
|
38255
|
-
visitor(node);
|
|
39294
|
+
if (visitor(node) === false) return;
|
|
38256
39295
|
for (const child of node.children ?? []) visitDom(child, visitor);
|
|
38257
39296
|
}
|
|
38258
39297
|
function interpolateDomTree(root, data) {
|
|
38259
39298
|
visitDom(root, (node) => {
|
|
39299
|
+
const richText = node.type === "tag" && node.name === "rich-text";
|
|
39300
|
+
if (richText) node.children = [];
|
|
38260
39301
|
if (typeof node.data === "string") node.data = interpolateTemplateText(node.data, data);
|
|
38261
39302
|
if (node.attribs) {
|
|
38262
39303
|
let dataset;
|
|
38263
39304
|
for (const [key, value] of Object.entries(node.attribs)) {
|
|
38264
39305
|
const resolvedValue = isMustacheOnly(value) ? resolveRawValueByPath(data, value.trim().slice(2, -2)) : interpolateTemplate(value, data);
|
|
39306
|
+
if (key === "value") setNativePickerValue(node, resolvedValue);
|
|
39307
|
+
if (richText && key === "nodes") node.children = renderRichTextNodes(resolvedValue);
|
|
38265
39308
|
node.attribs[key] = String(resolvedValue ?? "");
|
|
38266
39309
|
if (isDatasetAttribute(key)) {
|
|
38267
39310
|
dataset ??= {};
|
|
@@ -38270,6 +39313,7 @@ function interpolateDomTree(root, data) {
|
|
|
38270
39313
|
}
|
|
38271
39314
|
node.dataset = dataset;
|
|
38272
39315
|
}
|
|
39316
|
+
if (richText) return false;
|
|
38273
39317
|
});
|
|
38274
39318
|
}
|
|
38275
39319
|
function escapeText(text) {
|
|
@@ -38291,11 +39335,12 @@ function renderPageTree(project, page) {
|
|
|
38291
39335
|
const templateSource = project.artifactSource.readText(templatePath);
|
|
38292
39336
|
if (templateSource == null) throw new Error(`Missing template in headless runtime: ${templatePath}`);
|
|
38293
39337
|
const document = parseDocument(`<page>${templateSource}</page>`, {
|
|
38294
|
-
xmlMode:
|
|
39338
|
+
xmlMode: true,
|
|
38295
39339
|
decodeEntities: false,
|
|
38296
39340
|
recognizeSelfClosing: true
|
|
38297
39341
|
});
|
|
38298
39342
|
interpolateDomTree(document, page.data);
|
|
39343
|
+
linkRenderedParents(document);
|
|
38299
39344
|
return {
|
|
38300
39345
|
root: document,
|
|
38301
39346
|
wxml: serializeDomNode((document.children ?? [])[0] ?? document)
|
|
@@ -38466,7 +39511,7 @@ function getNativeScrollOffset(page, node) {
|
|
|
38466
39511
|
};
|
|
38467
39512
|
}
|
|
38468
39513
|
/** 原生交互更新宿主状态,导航仍交给统一 wx 路由入口。 */
|
|
38469
|
-
function dispatchNativeNodeEvent(page, node, eventName, event, wx, resolveMethod, onHandlerResult) {
|
|
39514
|
+
function dispatchNativeNodeEvent(page, node, eventName, event, wx, resolveMethod, onHandlerResult, resolveComponent) {
|
|
38470
39515
|
if (eventName === "scroll" && node.name === "scroll-view") {
|
|
38471
39516
|
const detail = event.detail;
|
|
38472
39517
|
const state = pageScrollViews.get(page)?.get(nodeKey(node));
|
|
@@ -38480,30 +39525,42 @@ function dispatchNativeNodeEvent(page, node, eventName, event, wx, resolveMethod
|
|
|
38480
39525
|
if (eventName !== "tap") return false;
|
|
38481
39526
|
let current = node;
|
|
38482
39527
|
let navigator;
|
|
39528
|
+
let button;
|
|
39529
|
+
const origin = getNativeNodeOwner(node)?.target ?? node;
|
|
38483
39530
|
let handlers;
|
|
38484
39531
|
let handled = false;
|
|
38485
|
-
|
|
38486
|
-
if (
|
|
38487
|
-
|
|
38488
|
-
if (binding?.method) {
|
|
38489
|
-
const call = resolveMethod(current.attribs?.["data-sim-scope"] ?? null, binding.method);
|
|
39532
|
+
const collectHandler = (scopeId, target, binding) => {
|
|
39533
|
+
if (binding.method) {
|
|
39534
|
+
const call = resolveMethod(scopeId, binding.method);
|
|
38490
39535
|
handlers ??= [];
|
|
38491
39536
|
handlers.push({
|
|
38492
|
-
|
|
39537
|
+
event: createMiniProgramEventPayload(target, "tap", event, origin),
|
|
38493
39538
|
call
|
|
38494
39539
|
});
|
|
38495
39540
|
handled = true;
|
|
38496
39541
|
}
|
|
38497
|
-
|
|
39542
|
+
};
|
|
39543
|
+
while (current) {
|
|
39544
|
+
if (!navigator && current.name === "navigator") navigator = current;
|
|
39545
|
+
if (!button && current.name === "button") button = current;
|
|
39546
|
+
if (visitNativeNodeEventBindings(current, "tap", collectHandler)) {
|
|
38498
39547
|
handled = true;
|
|
38499
39548
|
break;
|
|
38500
39549
|
}
|
|
38501
39550
|
current = current.parent;
|
|
38502
39551
|
}
|
|
39552
|
+
const submit = button ? prepareNativeFormSubmit(button, `page:${page.route}`, event, resolveMethod, resolveComponent) : void 0;
|
|
38503
39553
|
if (handlers) for (const handler of handlers) {
|
|
38504
|
-
const result = handler.call(
|
|
39554
|
+
const result = handler.call(handler.event);
|
|
38505
39555
|
onHandlerResult?.(result);
|
|
38506
39556
|
}
|
|
39557
|
+
if (submit) {
|
|
39558
|
+
handled = true;
|
|
39559
|
+
if (submit.call) {
|
|
39560
|
+
const result = submit.call(submit.event);
|
|
39561
|
+
onHandlerResult?.(result);
|
|
39562
|
+
}
|
|
39563
|
+
}
|
|
38507
39564
|
if (!navigator) return handled;
|
|
38508
39565
|
const openType = navigator.attribs?.["open-type"] ?? "navigate";
|
|
38509
39566
|
const url = navigator.attribs?.url ?? "";
|
|
@@ -39288,6 +40345,64 @@ function createHeadlessMediaQueryObserver(driver, onDisconnect) {
|
|
|
39288
40345
|
};
|
|
39289
40346
|
}
|
|
39290
40347
|
//#endregion
|
|
40348
|
+
//#region ../../mpcore/packages/simulator/src/view/templateRegistration.ts
|
|
40349
|
+
/** 编译模板及递归依赖共用全局注册图,图外原生模板继续实时读取。 */
|
|
40350
|
+
function createTemplateRegistration(source, projectRoot, compiledTemplatePaths = []) {
|
|
40351
|
+
const root = normalize(projectRoot);
|
|
40352
|
+
const normalizeTemplatePath = (filePath) => {
|
|
40353
|
+
const normalized = normalize(filePath);
|
|
40354
|
+
const local = relative(root, normalized);
|
|
40355
|
+
if (!normalized.endsWith(".wxml") || isAbsolute(local) || local === ".." || local.startsWith("../")) throw new TypeError("Compiled template paths must stay inside the mini-program root and end in .wxml.");
|
|
40356
|
+
return normalized;
|
|
40357
|
+
};
|
|
40358
|
+
const resolveRelativeTemplatePath = (filePath) => {
|
|
40359
|
+
const local = normalize(filePath);
|
|
40360
|
+
if (isAbsolute(local) || local === ".." || local.startsWith("../")) throw new TypeError("Compiled template paths must stay inside the mini-program root and end in .wxml.");
|
|
40361
|
+
return normalizeTemplatePath(join(root, local));
|
|
40362
|
+
};
|
|
40363
|
+
const entries = [...new Set(compiledTemplatePaths.map((filePath) => {
|
|
40364
|
+
if (typeof filePath !== "string" || !filePath || isAbsolute(filePath)) throw new TypeError("Compiled template paths must be project-relative WXML paths.");
|
|
40365
|
+
return resolveRelativeTemplatePath(filePath);
|
|
40366
|
+
}))];
|
|
40367
|
+
let registered = /* @__PURE__ */ new Map();
|
|
40368
|
+
function readSnapshot() {
|
|
40369
|
+
const snapshot = /* @__PURE__ */ new Map();
|
|
40370
|
+
const collect = (filePath) => {
|
|
40371
|
+
filePath = normalizeTemplatePath(filePath);
|
|
40372
|
+
if (snapshot.has(filePath)) return;
|
|
40373
|
+
const content = source.readText(filePath);
|
|
40374
|
+
if (content === void 0) throw new Error(`Missing compiled template during host registration: ${relative(root, filePath)}`);
|
|
40375
|
+
snapshot.set(filePath, content);
|
|
40376
|
+
const visit = (node) => {
|
|
40377
|
+
const request = node.attribs?.src;
|
|
40378
|
+
if ((node.name === "include" || node.name === "import") && request) {
|
|
40379
|
+
const target = (request.endsWith(".wxml") ? request : `${request}.wxml`).replaceAll("\\", "/");
|
|
40380
|
+
if (isAbsolute(target) && !target.startsWith("/")) throw new TypeError("Compiled template paths must stay inside the mini-program root and end in .wxml.");
|
|
40381
|
+
collect(resolveRelativeTemplatePath(target.startsWith("/") ? target.slice(1) : join(relative(root, dirname(filePath)), target)));
|
|
40382
|
+
}
|
|
40383
|
+
for (const child of node.children ?? []) visit(child);
|
|
40384
|
+
};
|
|
40385
|
+
visit(parseWxsTemplateDocument(content));
|
|
40386
|
+
};
|
|
40387
|
+
for (const filePath of entries) collect(filePath);
|
|
40388
|
+
return snapshot;
|
|
40389
|
+
}
|
|
40390
|
+
function reload() {
|
|
40391
|
+
const snapshot = readSnapshot();
|
|
40392
|
+
const changed = snapshot.size !== registered.size || [...snapshot].some(([filePath, content]) => registered.get(filePath) !== content);
|
|
40393
|
+
registered = snapshot;
|
|
40394
|
+
return changed;
|
|
40395
|
+
}
|
|
40396
|
+
reload();
|
|
40397
|
+
return {
|
|
40398
|
+
artifactSource: {
|
|
40399
|
+
has: (filePath) => registered.has(normalize(filePath)) || source.has(filePath),
|
|
40400
|
+
readText: (filePath) => registered.get(normalize(filePath)) ?? source.readText(filePath)
|
|
40401
|
+
},
|
|
40402
|
+
reload
|
|
40403
|
+
};
|
|
40404
|
+
}
|
|
40405
|
+
//#endregion
|
|
39291
40406
|
//#region ../../mpcore/packages/simulator/src/view/videoContext.ts
|
|
39292
40407
|
function createEventPayload(node, eventName, detail) {
|
|
39293
40408
|
const dataset = collectNodeDataset(node);
|
|
@@ -39416,6 +40531,490 @@ var HeadlessAppLifecycle = class {
|
|
|
39416
40531
|
}
|
|
39417
40532
|
};
|
|
39418
40533
|
//#endregion
|
|
40534
|
+
//#region ../../mpcore/packages/simulator/src/runtime/workerHost.ts
|
|
40535
|
+
/** 两种 simulator 共用消息与生命周期;每个 worker 独立模块缓存、全局对象及计时器。 */
|
|
40536
|
+
function createWorkerHost(options) {
|
|
40537
|
+
const active = /* @__PURE__ */ new Set();
|
|
40538
|
+
let closed = false;
|
|
40539
|
+
const configuredRoot = () => {
|
|
40540
|
+
return JSON.parse(options.read(join(options.root, "app.json")) ?? "{}").workers;
|
|
40541
|
+
};
|
|
40542
|
+
return {
|
|
40543
|
+
apis: {
|
|
40544
|
+
preDownloadSubpackage(option) {
|
|
40545
|
+
const config = configuredRoot();
|
|
40546
|
+
if (option.packageType !== "workers" || typeof config !== "object" || !config.isSubpackage) {
|
|
40547
|
+
const error = /* @__PURE__ */ new Error("preDownloadSubpackage:fail workers subpackage is not configured");
|
|
40548
|
+
option.fail?.(error);
|
|
40549
|
+
option.complete?.();
|
|
40550
|
+
return;
|
|
40551
|
+
}
|
|
40552
|
+
const result = { errMsg: "preDownloadSubpackage:ok" };
|
|
40553
|
+
option.success?.(result);
|
|
40554
|
+
option.complete?.(result);
|
|
40555
|
+
},
|
|
40556
|
+
createWorker(scriptPath) {
|
|
40557
|
+
if (closed) throw new Error("createWorker:fail runtime has closed");
|
|
40558
|
+
const config = configuredRoot();
|
|
40559
|
+
const directory = typeof config === "string" ? config : config?.path;
|
|
40560
|
+
if (!directory || typeof scriptPath !== "string" || !scriptPath.endsWith(".js")) throw new Error("createWorker:fail invalid worker path");
|
|
40561
|
+
const root = normalize(join(options.root, directory));
|
|
40562
|
+
const entry = normalize(join(options.root, scriptPath));
|
|
40563
|
+
const inside = (file) => file.startsWith(`${root}/`);
|
|
40564
|
+
if (!inside(entry) || options.read(entry) === void 0) throw new Error("createWorker:fail worker entry is outside the configured directory or missing");
|
|
40565
|
+
const messages = /* @__PURE__ */ new Set();
|
|
40566
|
+
const incoming = /* @__PURE__ */ new Set();
|
|
40567
|
+
const errors = /* @__PURE__ */ new Set();
|
|
40568
|
+
const cache = /* @__PURE__ */ new Map();
|
|
40569
|
+
let terminated = false;
|
|
40570
|
+
const scheduler = new RuntimeScheduler((error) => {
|
|
40571
|
+
const value = { message: error instanceof Error ? error.message : String(error) };
|
|
40572
|
+
if (errors.size) for (const listener of errors) listener(value);
|
|
40573
|
+
else options.console.error(value.message);
|
|
40574
|
+
});
|
|
40575
|
+
const post = (listeners, message) => {
|
|
40576
|
+
if (terminated) return;
|
|
40577
|
+
const copy = structuredClone(message);
|
|
40578
|
+
scheduler.setTimeout(() => {
|
|
40579
|
+
for (const listener of [...listeners]) {
|
|
40580
|
+
if (terminated) break;
|
|
40581
|
+
listener(copy);
|
|
40582
|
+
}
|
|
40583
|
+
}, 0);
|
|
40584
|
+
};
|
|
40585
|
+
const globals = {
|
|
40586
|
+
wx: void 0,
|
|
40587
|
+
App: void 0,
|
|
40588
|
+
Page: void 0,
|
|
40589
|
+
Component: void 0,
|
|
40590
|
+
getApp: void 0,
|
|
40591
|
+
console: options.console,
|
|
40592
|
+
worker: {
|
|
40593
|
+
onMessage: (listener) => incoming.add(listener),
|
|
40594
|
+
postMessage: (message) => post(messages, message)
|
|
40595
|
+
},
|
|
40596
|
+
setTimeout: scheduler.setTimeout.bind(scheduler),
|
|
40597
|
+
clearTimeout: scheduler.clearTimeout.bind(scheduler),
|
|
40598
|
+
setInterval: scheduler.setInterval.bind(scheduler),
|
|
40599
|
+
clearInterval: scheduler.clearInterval.bind(scheduler)
|
|
40600
|
+
};
|
|
40601
|
+
globals.globalThis = globals;
|
|
40602
|
+
const execute = options.createExecutor(globals);
|
|
40603
|
+
const load = (file) => {
|
|
40604
|
+
if (terminated) return;
|
|
40605
|
+
if (!inside(file)) throw new Error("Worker require cannot leave its configured directory");
|
|
40606
|
+
if (cache.has(file)) return cache.get(file).exports;
|
|
40607
|
+
const source = options.read(file);
|
|
40608
|
+
if (source === void 0) throw new Error(`Missing worker module: ${file}`);
|
|
40609
|
+
if (file.endsWith(".json")) return JSON.parse(source);
|
|
40610
|
+
const module = { exports: {} };
|
|
40611
|
+
cache.set(file, module);
|
|
40612
|
+
const require = Object.assign((request) => {
|
|
40613
|
+
const target = resolveMiniProgramModule(file, request, root, (candidate) => options.read(candidate) !== void 0);
|
|
40614
|
+
if (!target) throw new Error(`Cannot resolve worker module: ${request}`);
|
|
40615
|
+
return load(target);
|
|
40616
|
+
}, { async: (request) => Promise.resolve().then(() => require(request)) });
|
|
40617
|
+
try {
|
|
40618
|
+
execute(source, file, module, require);
|
|
40619
|
+
} catch (error) {
|
|
40620
|
+
cache.delete(file);
|
|
40621
|
+
throw error;
|
|
40622
|
+
}
|
|
40623
|
+
return module.exports;
|
|
40624
|
+
};
|
|
40625
|
+
const worker = {
|
|
40626
|
+
onMessage: (listener) => {
|
|
40627
|
+
messages.add(listener);
|
|
40628
|
+
},
|
|
40629
|
+
offMessage: (listener) => {
|
|
40630
|
+
if (listener) messages.delete(listener);
|
|
40631
|
+
else messages.clear();
|
|
40632
|
+
},
|
|
40633
|
+
postMessage: (message) => post(incoming, message),
|
|
40634
|
+
onError: (listener) => {
|
|
40635
|
+
errors.add(listener);
|
|
40636
|
+
},
|
|
40637
|
+
offError: (listener) => {
|
|
40638
|
+
if (listener) errors.delete(listener);
|
|
40639
|
+
else errors.clear();
|
|
40640
|
+
},
|
|
40641
|
+
terminate() {
|
|
40642
|
+
if (terminated) return;
|
|
40643
|
+
terminated = true;
|
|
40644
|
+
scheduler.close();
|
|
40645
|
+
messages.clear();
|
|
40646
|
+
incoming.clear();
|
|
40647
|
+
errors.clear();
|
|
40648
|
+
cache.clear();
|
|
40649
|
+
active.delete(worker);
|
|
40650
|
+
}
|
|
40651
|
+
};
|
|
40652
|
+
active.add(worker);
|
|
40653
|
+
scheduler.setTimeout(() => load(entry), 0);
|
|
40654
|
+
return worker;
|
|
40655
|
+
}
|
|
40656
|
+
},
|
|
40657
|
+
close() {
|
|
40658
|
+
closed = true;
|
|
40659
|
+
for (const worker of active) worker.terminate();
|
|
40660
|
+
}
|
|
40661
|
+
};
|
|
40662
|
+
}
|
|
40663
|
+
//#endregion
|
|
40664
|
+
//#region ../../mpcore/packages/simulator/src/runtime/moduleSyntax/ast.ts
|
|
40665
|
+
function isSyntaxNode(value) {
|
|
40666
|
+
return value !== null && typeof value === "object" && "type" in value && typeof value.type === "string";
|
|
40667
|
+
}
|
|
40668
|
+
function childNodes(node) {
|
|
40669
|
+
const children = [];
|
|
40670
|
+
for (const [key, value] of Object.entries(node)) for (const child of Array.isArray(value) ? value : [value]) if (isSyntaxNode(child)) children.push({
|
|
40671
|
+
key,
|
|
40672
|
+
node: child
|
|
40673
|
+
});
|
|
40674
|
+
return children;
|
|
40675
|
+
}
|
|
40676
|
+
function patternIdentifiers(node) {
|
|
40677
|
+
if (node.type === "Identifier") return [node];
|
|
40678
|
+
const keys = node.type === "ObjectPattern" ? ["properties"] : node.type === "ObjectProperty" ? ["value"] : node.type === "AssignmentPattern" ? ["left"] : node.type === "RestElement" ? ["argument"] : ["elements"];
|
|
40679
|
+
return childNodes(node).filter((child) => keys.includes(child.key)).flatMap((child) => patternIdentifiers(child.node));
|
|
40680
|
+
}
|
|
40681
|
+
function createUniqueName(root) {
|
|
40682
|
+
const used = /* @__PURE__ */ new Set();
|
|
40683
|
+
const visit = (node) => {
|
|
40684
|
+
if (node.type === "Identifier" && typeof node.name === "string") used.add(node.name);
|
|
40685
|
+
childNodes(node).forEach((child) => visit(child.node));
|
|
40686
|
+
};
|
|
40687
|
+
visit(root);
|
|
40688
|
+
let index = 0;
|
|
40689
|
+
return () => {
|
|
40690
|
+
let name;
|
|
40691
|
+
do
|
|
40692
|
+
name = `__mpcoreEsm${index++}`;
|
|
40693
|
+
while (used.has(name));
|
|
40694
|
+
used.add(name);
|
|
40695
|
+
return name;
|
|
40696
|
+
};
|
|
40697
|
+
}
|
|
40698
|
+
function applySourceEdits(source, edits) {
|
|
40699
|
+
for (const edit of edits.toSorted((left, right) => right.start - left.start || right.end - left.end)) source = source.slice(0, edit.start) + edit.content + source.slice(edit.end);
|
|
40700
|
+
return source;
|
|
40701
|
+
}
|
|
40702
|
+
//#endregion
|
|
40703
|
+
//#region ../../mpcore/packages/simulator/src/runtime/moduleSyntax/bindings.ts
|
|
40704
|
+
const functionTypes = /* @__PURE__ */ new Set([
|
|
40705
|
+
"FunctionDeclaration",
|
|
40706
|
+
"FunctionExpression",
|
|
40707
|
+
"ArrowFunctionExpression",
|
|
40708
|
+
"ObjectMethod",
|
|
40709
|
+
"ClassMethod",
|
|
40710
|
+
"ClassPrivateMethod"
|
|
40711
|
+
]);
|
|
40712
|
+
const blockTypes = /* @__PURE__ */ new Set([
|
|
40713
|
+
"BlockStatement",
|
|
40714
|
+
"CatchClause",
|
|
40715
|
+
"ForStatement",
|
|
40716
|
+
"ForInStatement",
|
|
40717
|
+
"ForOfStatement",
|
|
40718
|
+
"SwitchStatement",
|
|
40719
|
+
"StaticBlock"
|
|
40720
|
+
]);
|
|
40721
|
+
/** 按词法作用域改写导入引用;声明、键名及同名局部变量保持原样。 */
|
|
40722
|
+
function rewriteImportReferences(root, imports, bindingName) {
|
|
40723
|
+
const scopes = /* @__PURE__ */ new WeakMap();
|
|
40724
|
+
const declarations = /* @__PURE__ */ new WeakSet();
|
|
40725
|
+
const moduleScope = {
|
|
40726
|
+
bindings: /* @__PURE__ */ new Set(),
|
|
40727
|
+
variable: true,
|
|
40728
|
+
functionDepth: 0
|
|
40729
|
+
};
|
|
40730
|
+
const declare = (pattern, scope) => {
|
|
40731
|
+
if (!isSyntaxNode(pattern)) return;
|
|
40732
|
+
for (const identifier of patternIdentifiers(pattern)) {
|
|
40733
|
+
scope.bindings.add(String(identifier.name));
|
|
40734
|
+
declarations.add(identifier);
|
|
40735
|
+
}
|
|
40736
|
+
};
|
|
40737
|
+
const visit = (node, inherited, parent, key) => {
|
|
40738
|
+
let scope = inherited;
|
|
40739
|
+
if (functionTypes.has(node.type)) {
|
|
40740
|
+
if (node.type === "FunctionDeclaration") declare(node.id, inherited);
|
|
40741
|
+
scope = {
|
|
40742
|
+
parent: inherited,
|
|
40743
|
+
bindings: /* @__PURE__ */ new Set(),
|
|
40744
|
+
variable: false,
|
|
40745
|
+
functionDepth: inherited.functionDepth + 1
|
|
40746
|
+
};
|
|
40747
|
+
declare(node.id, scope);
|
|
40748
|
+
if (Array.isArray(node.params)) node.params.forEach((parameter) => declare(parameter, scope));
|
|
40749
|
+
} else if (node.type === "ClassDeclaration" || node.type === "ClassExpression") {
|
|
40750
|
+
if (node.type === "ClassDeclaration") declare(node.id, inherited);
|
|
40751
|
+
scope = {
|
|
40752
|
+
parent: inherited,
|
|
40753
|
+
bindings: /* @__PURE__ */ new Set(),
|
|
40754
|
+
variable: false,
|
|
40755
|
+
functionDepth: inherited.functionDepth
|
|
40756
|
+
};
|
|
40757
|
+
declare(node.id, scope);
|
|
40758
|
+
} else if (blockTypes.has(node.type)) {
|
|
40759
|
+
scope = {
|
|
40760
|
+
parent: inherited,
|
|
40761
|
+
bindings: /* @__PURE__ */ new Set(),
|
|
40762
|
+
variable: node.type === "StaticBlock" || key === "body" && !!parent && functionTypes.has(parent.type),
|
|
40763
|
+
functionDepth: inherited.functionDepth
|
|
40764
|
+
};
|
|
40765
|
+
if (node.type === "CatchClause") declare(node.param, scope);
|
|
40766
|
+
}
|
|
40767
|
+
scopes.set(node, scope);
|
|
40768
|
+
if (node.type === "VariableDeclaration") {
|
|
40769
|
+
let owner = scope;
|
|
40770
|
+
while (node.kind === "var" && !owner.variable && owner.parent) owner = owner.parent;
|
|
40771
|
+
for (const child of childNodes(node)) declare(child.node.id, owner);
|
|
40772
|
+
}
|
|
40773
|
+
if (node.type === "ImportDeclaration") {
|
|
40774
|
+
for (const child of childNodes(node)) if (child.key === "specifiers") declare(child.node.local, moduleScope);
|
|
40775
|
+
return;
|
|
40776
|
+
}
|
|
40777
|
+
if (node.type === "ImportExpression" || node.type === "CallExpression" && isSyntaxNode(node.callee) && node.callee.type === "Import") throw new SyntaxError("Dynamic import is not supported by the synchronous mini-program module loader.");
|
|
40778
|
+
if (node.type === "MetaProperty" && isSyntaxNode(node.meta) && node.meta.name === "import") throw new SyntaxError("import.meta is not supported by the synchronous mini-program module loader.");
|
|
40779
|
+
if (scope.functionDepth === 0 && (node.type === "AwaitExpression" || node.type === "ForOfStatement" && node.await)) throw new SyntaxError("Top-level await is not supported by the synchronous mini-program module loader.");
|
|
40780
|
+
if (scope.functionDepth === 0 && node.type === "ReturnStatement") throw new SyntaxError("Top-level return is not valid in a mini-program ES module.");
|
|
40781
|
+
for (const child of childNodes(node)) {
|
|
40782
|
+
const computedMethodKey = functionTypes.has(node.type) && child.key === "key";
|
|
40783
|
+
const switchDiscriminant = node.type === "SwitchStatement" && child.key === "discriminant";
|
|
40784
|
+
visit(child.node, computedMethodKey || switchDiscriminant ? inherited : scope, node, child.key);
|
|
40785
|
+
}
|
|
40786
|
+
};
|
|
40787
|
+
visit(root, moduleScope);
|
|
40788
|
+
const edits = [];
|
|
40789
|
+
const rewrite = (node, parent, key) => {
|
|
40790
|
+
if (node.type === "ImportDeclaration" || node.type === "ExportAllDeclaration" || node.type === "ExportNamedDeclaration" && !node.declaration) return;
|
|
40791
|
+
if (node.type === "Identifier" && !declarations.has(node) && imports.has(String(node.name))) {
|
|
40792
|
+
const property = parent && key === "key" && !parent.computed && [
|
|
40793
|
+
"ObjectProperty",
|
|
40794
|
+
"ObjectMethod",
|
|
40795
|
+
"ClassMethod",
|
|
40796
|
+
"ClassPrivateMethod",
|
|
40797
|
+
"ClassProperty"
|
|
40798
|
+
].includes(parent.type);
|
|
40799
|
+
const member = parent && key === "property" && !parent.computed && ["MemberExpression", "OptionalMemberExpression"].includes(parent.type);
|
|
40800
|
+
const label = key === "label" || parent?.type === "PrivateName" || parent?.type === "MetaProperty";
|
|
40801
|
+
let owner = scopes.get(node);
|
|
40802
|
+
while (owner && !owner.bindings.has(String(node.name))) owner = owner.parent;
|
|
40803
|
+
if (!property && !member && !label && owner === moduleScope) {
|
|
40804
|
+
let content = `${bindingName}[${JSON.stringify(node.name)}]`;
|
|
40805
|
+
if (parent && (key === "callee" && ["CallExpression", "OptionalCallExpression"].includes(parent.type) || key === "tag" && parent.type === "TaggedTemplateExpression")) content = `(0, ${content})`;
|
|
40806
|
+
if (parent?.type === "ObjectProperty" && parent.shorthand && key === "value") content = `${node.name}: ${content}`;
|
|
40807
|
+
edits.push({
|
|
40808
|
+
start: node.start,
|
|
40809
|
+
end: node.end,
|
|
40810
|
+
content
|
|
40811
|
+
});
|
|
40812
|
+
}
|
|
40813
|
+
}
|
|
40814
|
+
childNodes(node).forEach((child) => rewrite(child.node, node, child.key));
|
|
40815
|
+
};
|
|
40816
|
+
rewrite(root);
|
|
40817
|
+
return edits;
|
|
40818
|
+
}
|
|
40819
|
+
//#endregion
|
|
40820
|
+
//#region ../../mpcore/packages/simulator/src/runtime/moduleSyntax/index.ts
|
|
40821
|
+
function position(node, edge) {
|
|
40822
|
+
const value = node[edge];
|
|
40823
|
+
if (typeof value !== "number") throw new SyntaxError("Missing source range in mini-program module syntax.");
|
|
40824
|
+
return value;
|
|
40825
|
+
}
|
|
40826
|
+
function identifierName(node) {
|
|
40827
|
+
return node.type === "Identifier" ? String(node.name) : String(node.value);
|
|
40828
|
+
}
|
|
40829
|
+
/** 同步转换静态 ESM;CJS 保留原字节,Node 与浏览器共享导入和导出语义。 */
|
|
40830
|
+
function transformMiniProgramModule(source) {
|
|
40831
|
+
if (!/\b(?:import|export)\b/.test(source)) return source;
|
|
40832
|
+
const ast = parse$2(source, {
|
|
40833
|
+
sourceType: "unambiguous",
|
|
40834
|
+
allowReturnOutsideFunction: true,
|
|
40835
|
+
tokens: true
|
|
40836
|
+
});
|
|
40837
|
+
const moduleNodes = ast.program.body.filter((node) => [
|
|
40838
|
+
"ImportDeclaration",
|
|
40839
|
+
"ExportNamedDeclaration",
|
|
40840
|
+
"ExportDefaultDeclaration",
|
|
40841
|
+
"ExportAllDeclaration"
|
|
40842
|
+
].includes(node.type));
|
|
40843
|
+
if (moduleNodes.length === 0) return source;
|
|
40844
|
+
const root = ast.program;
|
|
40845
|
+
const fresh = createUniqueName(root);
|
|
40846
|
+
const moduleName = fresh();
|
|
40847
|
+
const requireName = fresh();
|
|
40848
|
+
const objectName = fresh();
|
|
40849
|
+
const bindingsName = fresh();
|
|
40850
|
+
const dependencies = /* @__PURE__ */ new Map();
|
|
40851
|
+
const imports = /* @__PURE__ */ new Map();
|
|
40852
|
+
const exports = /* @__PURE__ */ new Map();
|
|
40853
|
+
const hoistedDefaultNames = [];
|
|
40854
|
+
const starExports = [];
|
|
40855
|
+
const edits = [];
|
|
40856
|
+
const dependency = (request) => {
|
|
40857
|
+
let name = dependencies.get(request);
|
|
40858
|
+
if (!name) {
|
|
40859
|
+
name = fresh();
|
|
40860
|
+
dependencies.set(request, name);
|
|
40861
|
+
}
|
|
40862
|
+
return name;
|
|
40863
|
+
};
|
|
40864
|
+
const remove = (node) => edits.push({
|
|
40865
|
+
start: position(node, "start"),
|
|
40866
|
+
end: position(node, "end"),
|
|
40867
|
+
content: ""
|
|
40868
|
+
});
|
|
40869
|
+
const own = (object, key) => `${objectName}.prototype.hasOwnProperty.call(${object}, ${key})`;
|
|
40870
|
+
for (const node of moduleNodes) {
|
|
40871
|
+
if ("attributes" in node && node.attributes?.length) throw new SyntaxError("Import attributes are not supported by the synchronous mini-program module loader.");
|
|
40872
|
+
if (node.type === "ImportDeclaration") {
|
|
40873
|
+
if (node.phase) throw new SyntaxError("Import phases are not supported by the synchronous mini-program module loader.");
|
|
40874
|
+
const namespace = dependency(node.source.value);
|
|
40875
|
+
for (const specifier of node.specifiers) {
|
|
40876
|
+
const binding = specifier.type === "ImportNamespaceSpecifier" ? namespace : specifier.type === "ImportDefaultSpecifier" ? `${namespace} != null && ${own(namespace, "\"default\"")} ? ${namespace}.default : ${namespace}` : `${namespace}[${JSON.stringify(identifierName(specifier.imported))}]`;
|
|
40877
|
+
imports.set(specifier.local.name, binding);
|
|
40878
|
+
}
|
|
40879
|
+
remove(node);
|
|
40880
|
+
} else if (node.type === "ExportNamedDeclaration") {
|
|
40881
|
+
if (node.declaration) {
|
|
40882
|
+
edits.push({
|
|
40883
|
+
start: position(node, "start"),
|
|
40884
|
+
end: position(node.declaration, "start"),
|
|
40885
|
+
content: ""
|
|
40886
|
+
});
|
|
40887
|
+
const patterns = node.declaration.type === "VariableDeclaration" ? node.declaration.declarations.map((declaration) => declaration.id) : "id" in node.declaration && node.declaration.id ? [node.declaration.id] : [];
|
|
40888
|
+
for (const pattern of patterns) for (const identifier of patternIdentifiers(pattern)) exports.set(String(identifier.name), String(identifier.name));
|
|
40889
|
+
} else {
|
|
40890
|
+
const namespace = node.source ? dependency(node.source.value) : void 0;
|
|
40891
|
+
for (const specifier of node.specifiers) {
|
|
40892
|
+
const exported = identifierName(specifier.exported);
|
|
40893
|
+
if (specifier.type === "ExportNamespaceSpecifier" && namespace) exports.set(exported, namespace);
|
|
40894
|
+
else if (specifier.type === "ExportSpecifier") {
|
|
40895
|
+
const local = identifierName(specifier.local);
|
|
40896
|
+
exports.set(exported, namespace ? `${namespace}[${JSON.stringify(local)}]` : local);
|
|
40897
|
+
} else throw new SyntaxError(`Unsupported mini-program export specifier: ${specifier.type}.`);
|
|
40898
|
+
}
|
|
40899
|
+
remove(node);
|
|
40900
|
+
}
|
|
40901
|
+
} else if (node.type === "ExportAllDeclaration") {
|
|
40902
|
+
starExports.push(dependency(node.source.value));
|
|
40903
|
+
remove(node);
|
|
40904
|
+
} else if (node.type === "ExportDefaultDeclaration") {
|
|
40905
|
+
const declaration = node.declaration;
|
|
40906
|
+
const defaultToken = ast.tokens?.find((token) => token.start > position(node, "start") && token.end <= position(declaration, "start") && token.type.label === "default");
|
|
40907
|
+
if (!defaultToken) throw new SyntaxError("Missing default export token in mini-program module syntax.");
|
|
40908
|
+
if (declaration.type === "FunctionDeclaration" && !declaration.id) {
|
|
40909
|
+
const name = fresh();
|
|
40910
|
+
const keyword = ast.tokens?.find((token) => token.start >= position(declaration, "start") && token.type.label === "function");
|
|
40911
|
+
const nameToken = declaration.generator ? ast.tokens?.find((token) => token.start >= (keyword?.end ?? position(declaration, "start")) && token.type.label === "*") : keyword;
|
|
40912
|
+
if (!nameToken) throw new SyntaxError("Missing default function token in mini-program module syntax.");
|
|
40913
|
+
exports.set("default", name);
|
|
40914
|
+
hoistedDefaultNames.push(name);
|
|
40915
|
+
edits.push({
|
|
40916
|
+
start: position(node, "start"),
|
|
40917
|
+
end: defaultToken.end,
|
|
40918
|
+
content: ""
|
|
40919
|
+
});
|
|
40920
|
+
edits.push({
|
|
40921
|
+
start: nameToken.end,
|
|
40922
|
+
end: nameToken.end,
|
|
40923
|
+
content: ` ${name}`
|
|
40924
|
+
});
|
|
40925
|
+
} else if ((declaration.type === "FunctionDeclaration" || declaration.type === "ClassDeclaration") && declaration.id) {
|
|
40926
|
+
exports.set("default", declaration.id.name);
|
|
40927
|
+
edits.push({
|
|
40928
|
+
start: position(node, "start"),
|
|
40929
|
+
end: defaultToken.end,
|
|
40930
|
+
content: ""
|
|
40931
|
+
});
|
|
40932
|
+
} else {
|
|
40933
|
+
const name = fresh();
|
|
40934
|
+
exports.set("default", name);
|
|
40935
|
+
edits.push({
|
|
40936
|
+
start: position(node, "start"),
|
|
40937
|
+
end: defaultToken.end,
|
|
40938
|
+
content: `const ${name} = `
|
|
40939
|
+
});
|
|
40940
|
+
edits.push({
|
|
40941
|
+
start: position(node, "end"),
|
|
40942
|
+
end: position(node, "end"),
|
|
40943
|
+
content: ";"
|
|
40944
|
+
});
|
|
40945
|
+
}
|
|
40946
|
+
}
|
|
40947
|
+
}
|
|
40948
|
+
edits.push(...rewriteImportReferences(root, new Set(imports.keys()), bindingsName));
|
|
40949
|
+
const declarations = [
|
|
40950
|
+
dependencies.size ? `let ${[...dependencies.values()].join(", ")};` : "",
|
|
40951
|
+
`const ${bindingsName} = ${objectName}.create(null);`,
|
|
40952
|
+
...[...imports].map(([name, expression]) => `${objectName}.defineProperty(${bindingsName}, ${JSON.stringify(name)}, { get: () => (${expression}) });`),
|
|
40953
|
+
...[...exports].map(([name, expression]) => {
|
|
40954
|
+
const value = imports.has(expression) ? `${bindingsName}[${JSON.stringify(expression)}]` : expression;
|
|
40955
|
+
return `${objectName}.defineProperty(${moduleName}.exports, ${JSON.stringify(name)}, { enumerable: true, get: () => ${value} });`;
|
|
40956
|
+
}),
|
|
40957
|
+
...hoistedDefaultNames.map((name) => `${objectName}.defineProperty(${name}, 'name', { value: 'default', configurable: true });`),
|
|
40958
|
+
...[...dependencies].map(([request, namespace]) => `${namespace} = ${requireName}(${JSON.stringify(request)});`)
|
|
40959
|
+
];
|
|
40960
|
+
if (starExports.length) {
|
|
40961
|
+
const owners = fresh();
|
|
40962
|
+
const namespace = fresh();
|
|
40963
|
+
const key = fresh();
|
|
40964
|
+
declarations.push(`
|
|
40965
|
+
const ${owners} = ${objectName}.create(null);
|
|
40966
|
+
for (const ${namespace} of [${starExports.join(", ")}]) {
|
|
40967
|
+
for (const ${key} of ${objectName}.keys(${namespace})) {
|
|
40968
|
+
if (${key} === 'default' || ${own(`${moduleName}.exports`, key)}) continue;
|
|
40969
|
+
${owners}[${key}] = ${own(owners, key)} && ${owners}[${key}] !== ${namespace} ? null : ${namespace};
|
|
40970
|
+
}
|
|
40971
|
+
}
|
|
40972
|
+
for (const ${key} of ${objectName}.keys(${owners})) {
|
|
40973
|
+
if (${owners}[${key}] !== null) ${objectName}.defineProperty(${moduleName}.exports, ${key}, { enumerable: true, get: () => ${owners}[${key}][${key}] });
|
|
40974
|
+
}
|
|
40975
|
+
`);
|
|
40976
|
+
}
|
|
40977
|
+
return `(function(${moduleName}, ${requireName}, ${objectName}) {\n"use strict";\n${declarations.join("\n")}\n${applySourceEdits(source, edits)}\n${objectName}.preventExtensions(${moduleName}.exports);\n}).call(undefined, module, require, Object);`;
|
|
40978
|
+
}
|
|
40979
|
+
//#endregion
|
|
40980
|
+
//#region ../../mpcore/packages/simulator/src/runtime/pageDefinitionReload.ts
|
|
40981
|
+
/** 定义更新只解析已有路由,不触发普通导航的启动或 page-not-found 生命周期。 */
|
|
40982
|
+
function resolvePageDefinitionReloadRoute(project, route) {
|
|
40983
|
+
if (typeof route !== "string" || !route.trim() || /[?#]/.test(route)) throw new TypeError("Page definition reload requires a route path without query or hash.");
|
|
40984
|
+
const normalized = route.trim().replace(/^\/+/, "");
|
|
40985
|
+
const record = project.routes.find((record) => record.route === normalized);
|
|
40986
|
+
if (!record) throw new Error(`Unknown page definition reload route: ${route}`);
|
|
40987
|
+
return record;
|
|
40988
|
+
}
|
|
40989
|
+
function restoreMap(target, snapshot) {
|
|
40990
|
+
target.clear();
|
|
40991
|
+
for (const [key, value] of snapshot) target.set(key, value);
|
|
40992
|
+
}
|
|
40993
|
+
/** 仅替换目标 entry;失败恢复缓存和注册表,保留未变依赖的对象身份。 */
|
|
40994
|
+
function reloadPageModuleDefinition(options) {
|
|
40995
|
+
const { filePath, route, source, cache, registries } = options;
|
|
40996
|
+
const previous = cache.get(filePath);
|
|
40997
|
+
if (!previous || !registries.pages.has(route)) throw new Error(`Cannot reload a page definition before it is loaded: ${route}`);
|
|
40998
|
+
if (source === void 0) throw new Error(`Missing page script for definition reload: ${route}`);
|
|
40999
|
+
if (source === previous.source) return false;
|
|
41000
|
+
const modules = new Map(cache);
|
|
41001
|
+
const pages = new Map(registries.pages);
|
|
41002
|
+
const components = new Map(registries.components);
|
|
41003
|
+
const app = registries.appDefinition;
|
|
41004
|
+
cache.delete(filePath);
|
|
41005
|
+
registries.pages.delete(route);
|
|
41006
|
+
try {
|
|
41007
|
+
options.execute();
|
|
41008
|
+
return true;
|
|
41009
|
+
} catch (error) {
|
|
41010
|
+
restoreMap(cache, modules);
|
|
41011
|
+
restoreMap(registries.pages, pages);
|
|
41012
|
+
restoreMap(registries.components, components);
|
|
41013
|
+
registries.appDefinition = app;
|
|
41014
|
+
throw error;
|
|
41015
|
+
}
|
|
41016
|
+
}
|
|
41017
|
+
//#endregion
|
|
39419
41018
|
//#region ../../mpcore/packages/simulator/src/runtime/runtimeGlobals.ts
|
|
39420
41019
|
const MINI_PROGRAM_UNAVAILABLE_GLOBAL_NAMES = [
|
|
39421
41020
|
"window",
|
|
@@ -39459,108 +41058,12 @@ function createMiniProgramRuntimeGlobals(availableGlobals, overrides) {
|
|
|
39459
41058
|
}
|
|
39460
41059
|
//#endregion
|
|
39461
41060
|
//#region ../../mpcore/packages/simulator/src/runtime/moduleLoader.ts
|
|
39462
|
-
const ESM_IMPORT_LINE_RE = /^[ \t]*import[^\n]*$/gm;
|
|
39463
|
-
const ESM_EXPORT_LIST_RE = /^[ \t]*export[ \t]*\{([^}\n]+)\}[ \t]*;?$/gm;
|
|
39464
|
-
const ESM_EXPORT_DECLARATION_RE = /\bexport\s+(const|let|var|function|class)\s+([A-Za-z_$][\w$]*)/g;
|
|
39465
|
-
const ESM_EXPORT_DEFAULT_DECLARATION_RE = /\bexport\s+default\s+(function|class)\s+([A-Za-z_$][\w$]*)/g;
|
|
39466
|
-
function isImportWhitespace(value) {
|
|
39467
|
-
return value === " " || value === " ";
|
|
39468
|
-
}
|
|
39469
|
-
function parseEsmImportLine(line) {
|
|
39470
|
-
let statement = line.trim().slice(6).trim();
|
|
39471
|
-
if (statement.endsWith(";")) statement = statement.slice(0, -1).trimEnd();
|
|
39472
|
-
if (statement.startsWith("\"") || statement.startsWith("'")) {
|
|
39473
|
-
const quote = statement[0];
|
|
39474
|
-
if (statement.endsWith(quote) && statement.length > 1) return {
|
|
39475
|
-
request: statement.slice(1, -1),
|
|
39476
|
-
sideEffect: true
|
|
39477
|
-
};
|
|
39478
|
-
return;
|
|
39479
|
-
}
|
|
39480
|
-
let fromIndex = statement.indexOf("from");
|
|
39481
|
-
while (fromIndex >= 0) {
|
|
39482
|
-
if (isImportWhitespace(statement[fromIndex - 1]) && isImportWhitespace(statement[fromIndex + 4])) break;
|
|
39483
|
-
fromIndex = statement.indexOf("from", fromIndex + 4);
|
|
39484
|
-
}
|
|
39485
|
-
if (fromIndex < 0) return;
|
|
39486
|
-
const specifier = statement.slice(0, fromIndex).trim();
|
|
39487
|
-
const requestLiteral = statement.slice(fromIndex + 4).trim();
|
|
39488
|
-
const quote = requestLiteral[0];
|
|
39489
|
-
if (!specifier || quote !== "\"" && quote !== "'" || requestLiteral.length < 2 || !requestLiteral.endsWith(quote)) return;
|
|
39490
|
-
return {
|
|
39491
|
-
request: requestLiteral.slice(1, -1),
|
|
39492
|
-
sideEffect: false,
|
|
39493
|
-
specifier
|
|
39494
|
-
};
|
|
39495
|
-
}
|
|
39496
|
-
function createEsmImportBindings(specifier, request, index) {
|
|
39497
|
-
const namespaceName = `__headlessEsmImport${index}`;
|
|
39498
|
-
const statements = [`const ${namespaceName} = require(${JSON.stringify(request)});`];
|
|
39499
|
-
const normalizedSpecifier = specifier.trim();
|
|
39500
|
-
if (normalizedSpecifier.startsWith("{") && normalizedSpecifier.endsWith("}")) {
|
|
39501
|
-
const entries = normalizedSpecifier.slice(1, -1).split(",");
|
|
39502
|
-
for (const entry of entries) {
|
|
39503
|
-
const [importedName, localName] = entry.trim().split(/\s+as\s+/);
|
|
39504
|
-
if (!importedName) continue;
|
|
39505
|
-
const bindingName = localName || importedName;
|
|
39506
|
-
statements.push(`const ${bindingName} = ${namespaceName}[${JSON.stringify(importedName)}];`);
|
|
39507
|
-
}
|
|
39508
|
-
return statements.join("\n");
|
|
39509
|
-
}
|
|
39510
|
-
if (normalizedSpecifier.startsWith("* as ")) {
|
|
39511
|
-
const bindingName = normalizedSpecifier.slice(5).trim();
|
|
39512
|
-
statements.push(`const ${bindingName} = ${namespaceName};`);
|
|
39513
|
-
return statements.join("\n");
|
|
39514
|
-
}
|
|
39515
|
-
const [defaultName, namedPart] = normalizedSpecifier.split(/\s*,\s*/, 2);
|
|
39516
|
-
if (defaultName) statements.push(`const ${defaultName.trim()} = ${namespaceName}.default ?? ${namespaceName};`);
|
|
39517
|
-
if (namedPart?.startsWith("{") && namedPart.endsWith("}")) statements.push(createEsmImportBindings(namedPart, request, index).split("\n").slice(1).join("\n"));
|
|
39518
|
-
return statements.join("\n");
|
|
39519
|
-
}
|
|
39520
|
-
function transformEsmToCommonJs(source) {
|
|
39521
|
-
if (!/^\s*(?:import|export)\b/m.test(source)) return source;
|
|
39522
|
-
let importIndex = 0;
|
|
39523
|
-
const exportedNames = [];
|
|
39524
|
-
let transformed = source.replace(ESM_IMPORT_LINE_RE, (line) => {
|
|
39525
|
-
const parsed = parseEsmImportLine(line);
|
|
39526
|
-
if (!parsed) return line;
|
|
39527
|
-
if (parsed.sideEffect) return `require(${JSON.stringify(parsed.request)});`;
|
|
39528
|
-
return createEsmImportBindings(parsed.specifier, parsed.request, importIndex++);
|
|
39529
|
-
});
|
|
39530
|
-
transformed = transformed.replace(ESM_EXPORT_LIST_RE, (_match, entries) => {
|
|
39531
|
-
for (const entry of entries.split(",")) {
|
|
39532
|
-
const [local, exported] = entry.trim().split(/\s+as\s+/);
|
|
39533
|
-
if (local) exportedNames.push({
|
|
39534
|
-
exported: exported || local,
|
|
39535
|
-
local
|
|
39536
|
-
});
|
|
39537
|
-
}
|
|
39538
|
-
return "";
|
|
39539
|
-
});
|
|
39540
|
-
transformed = transformed.replace(ESM_EXPORT_DEFAULT_DECLARATION_RE, (_match, kind, local) => {
|
|
39541
|
-
exportedNames.push({
|
|
39542
|
-
exported: "default",
|
|
39543
|
-
local
|
|
39544
|
-
});
|
|
39545
|
-
return `${kind} ${local}`;
|
|
39546
|
-
});
|
|
39547
|
-
transformed = transformed.replace(ESM_EXPORT_DECLARATION_RE, (_match, kind, local) => {
|
|
39548
|
-
exportedNames.push({
|
|
39549
|
-
exported: local,
|
|
39550
|
-
local
|
|
39551
|
-
});
|
|
39552
|
-
return `${kind} ${local}`;
|
|
39553
|
-
});
|
|
39554
|
-
transformed = transformed.replace(/\bexport\s+default\s+/g, "module.exports.default = ");
|
|
39555
|
-
if (exportedNames.length > 0) transformed += `\n${exportedNames.map(({ exported, local }) => `module.exports[${JSON.stringify(exported)}] = ${local};`).join("\n")}`;
|
|
39556
|
-
return transformed;
|
|
39557
|
-
}
|
|
39558
41061
|
function createRequireNotFoundError(request, importer) {
|
|
39559
41062
|
return /* @__PURE__ */ new Error(`Cannot resolve require("${request}") from ${normalize(importer)} in headless runtime.`);
|
|
39560
41063
|
}
|
|
39561
|
-
function createExecutionContext(registries, getCurrentPages, getApp, wxDriver, kernel, globals, onConsole) {
|
|
41064
|
+
function createExecutionContext(registries, getCurrentPages, getApp, wxDriver, kernel, globals, onConsole, workers) {
|
|
39562
41065
|
const runtimeConsole = kernel.diagnostics.createConsole(console, onConsole);
|
|
39563
|
-
const wx = createHeadlessWx(wxDriver, runtimeConsole);
|
|
41066
|
+
const wx = createHeadlessWx(wxDriver, runtimeConsole, workers);
|
|
39564
41067
|
return createMiniProgramRuntimeGlobals({
|
|
39565
41068
|
App(definition) {
|
|
39566
41069
|
return registerAppDefinition(registries, definition);
|
|
@@ -39593,8 +41096,19 @@ function createExecutionContext(registries, getCurrentPages, getApp, wxDriver, k
|
|
|
39593
41096
|
}, globals);
|
|
39594
41097
|
}
|
|
39595
41098
|
function createModuleLoader(registries, getCurrentPages, getApp, wxDriver, options) {
|
|
41099
|
+
const workers = createWorkerHost({
|
|
41100
|
+
root: options.miniprogramRootPath,
|
|
41101
|
+
read: (file) => options.artifactSource.readText(file),
|
|
41102
|
+
console: options.kernel.diagnostics.createConsole(console, options.onConsole),
|
|
41103
|
+
createExecutor(globals) {
|
|
41104
|
+
const realm = vm.createContext(globals);
|
|
41105
|
+
return (source, file, module, require) => {
|
|
41106
|
+
new vm.Script(`(function(module, exports, require) {${source}\n})`, { filename: file }).runInContext(realm)(module, module.exports, require);
|
|
41107
|
+
};
|
|
41108
|
+
}
|
|
41109
|
+
});
|
|
39596
41110
|
const moduleCache = /* @__PURE__ */ new Map();
|
|
39597
|
-
const executionContext = createExecutionContext(registries, getCurrentPages, getApp, wxDriver, options.kernel, options.globals ?? {}, options.onConsole);
|
|
41111
|
+
const executionContext = createExecutionContext(registries, getCurrentPages, getApp, wxDriver, options.kernel, options.globals ?? {}, options.onConsole, workers.apis);
|
|
39598
41112
|
executionContext.globalThis = executionContext;
|
|
39599
41113
|
function executeModule(filePath, loadContext) {
|
|
39600
41114
|
const resolvedPath = path.resolve(filePath);
|
|
@@ -39603,6 +41117,7 @@ function createModuleLoader(registries, getCurrentPages, getApp, wxDriver, optio
|
|
|
39603
41117
|
const source = options.artifactSource.readText(resolvedPath);
|
|
39604
41118
|
if (source == null) throw new TypeError(`Missing module in headless runtime: ${normalize(resolvedPath)}`);
|
|
39605
41119
|
const module = {
|
|
41120
|
+
source,
|
|
39606
41121
|
componentDefinitions: [],
|
|
39607
41122
|
exports: {}
|
|
39608
41123
|
};
|
|
@@ -39612,7 +41127,7 @@ function createModuleLoader(registries, getCurrentPages, getApp, wxDriver, optio
|
|
|
39612
41127
|
const previousLoadContext = registries.currentLoadContext;
|
|
39613
41128
|
registries.currentLoadContext = loadContext;
|
|
39614
41129
|
const localRequire = ((request) => {
|
|
39615
|
-
const requiredPath = resolveMiniProgramModule(resolvedPath, request, options.miniprogramRootPath, (candidate) => options.artifactSource.
|
|
41130
|
+
const requiredPath = resolveMiniProgramModule(resolvedPath, request, options.miniprogramRootPath, (candidate) => options.artifactSource.has(candidate));
|
|
39616
41131
|
if (!requiredPath) throw createRequireNotFoundError(request, resolvedPath);
|
|
39617
41132
|
if (requiredPath.endsWith(".json")) {
|
|
39618
41133
|
const content = options.artifactSource.readText(requiredPath);
|
|
@@ -39625,7 +41140,7 @@ function createModuleLoader(registries, getCurrentPages, getApp, wxDriver, optio
|
|
|
39625
41140
|
});
|
|
39626
41141
|
localRequire.async = (request) => Promise.resolve().then(() => localRequire(request));
|
|
39627
41142
|
try {
|
|
39628
|
-
new vm.Script(`(function (exports, module, require, __filename, __dirname) { ${
|
|
41143
|
+
new vm.Script(`(function (exports, module, require, __filename, __dirname) { ${transformMiniProgramModule(source)}\n})`, { filename: resolvedPath }).runInNewContext(executionContext)(module.exports, module, localRequire, resolvedPath, path.dirname(resolvedPath));
|
|
39629
41144
|
const registeredDefinitions = [...registries.components.values()].filter((definition) => !registeredDefinitionsBefore.has(definition));
|
|
39630
41145
|
module.componentDefinitions = [.../* @__PURE__ */ new Set([
|
|
39631
41146
|
...requiredComponentDefinitions,
|
|
@@ -39653,6 +41168,7 @@ function createModuleLoader(registries, getCurrentPages, getApp, wxDriver, optio
|
|
|
39653
41168
|
return callback(...args);
|
|
39654
41169
|
},
|
|
39655
41170
|
close() {
|
|
41171
|
+
workers.close();
|
|
39656
41172
|
moduleCache.clear();
|
|
39657
41173
|
closeRuntimeWxsLoader(loader);
|
|
39658
41174
|
},
|
|
@@ -39671,6 +41187,17 @@ function createModuleLoader(registries, getCurrentPages, getApp, wxDriver, optio
|
|
|
39671
41187
|
if (!definition) throw new Error(`Page() was not registered for route "${route}" while executing ${normalize(filePath)}.`);
|
|
39672
41188
|
return definition;
|
|
39673
41189
|
},
|
|
41190
|
+
reloadPageModule(filePath, route) {
|
|
41191
|
+
const resolvedPath = path.resolve(filePath);
|
|
41192
|
+
return reloadPageModuleDefinition({
|
|
41193
|
+
filePath: resolvedPath,
|
|
41194
|
+
route,
|
|
41195
|
+
source: options.artifactSource.readText(resolvedPath),
|
|
41196
|
+
cache: moduleCache,
|
|
41197
|
+
registries,
|
|
41198
|
+
execute: () => loader.executePageModule(resolvedPath, route)
|
|
41199
|
+
});
|
|
41200
|
+
},
|
|
39674
41201
|
executeComponentModule(filePath, id) {
|
|
39675
41202
|
const loadedModule = executeModule(filePath, {
|
|
39676
41203
|
kind: "component",
|
|
@@ -39707,6 +41234,7 @@ var HeadlessRouteEvents = class {
|
|
|
39707
41234
|
nextRouteId = 0;
|
|
39708
41235
|
nextWebviewId = 0;
|
|
39709
41236
|
activeEvent;
|
|
41237
|
+
activeState;
|
|
39710
41238
|
constructor(requestRender, isCurrentPage) {
|
|
39711
41239
|
this.requestRender = requestRender;
|
|
39712
41240
|
this.isCurrentPage = isCurrentPage;
|
|
@@ -39718,6 +41246,7 @@ var HeadlessRouteEvents = class {
|
|
|
39718
41246
|
this.bus.$off(name, listener);
|
|
39719
41247
|
}
|
|
39720
41248
|
begin(path, query, openType, renderer, page) {
|
|
41249
|
+
this.cancel(this.activeState, /* @__PURE__ */ new Error("navigateTo:fail navigation was superseded"));
|
|
39721
41250
|
const previous = page ? this.pages.get(page) : void 0;
|
|
39722
41251
|
const event = {
|
|
39723
41252
|
path,
|
|
@@ -39734,12 +41263,28 @@ var HeadlessRouteEvents = class {
|
|
|
39734
41263
|
}
|
|
39735
41264
|
attach(page, event) {
|
|
39736
41265
|
const state = this.pages.get(page);
|
|
39737
|
-
|
|
41266
|
+
const next = {
|
|
39738
41267
|
webviewId: event.webviewId,
|
|
39739
41268
|
ready: state?.ready ?? false,
|
|
39740
41269
|
event,
|
|
39741
|
-
committed: false
|
|
39742
|
-
|
|
41270
|
+
committed: false,
|
|
41271
|
+
completed: false
|
|
41272
|
+
};
|
|
41273
|
+
this.pages.set(page, next);
|
|
41274
|
+
if (this.activeEvent === event) this.activeState = next;
|
|
41275
|
+
}
|
|
41276
|
+
/** 原生 navigateTo 的回调属于本次路由记录,不能以当前页面或提交栈代替完成。 */
|
|
41277
|
+
navigateTo(operation, callbacks) {
|
|
41278
|
+
let state;
|
|
41279
|
+
try {
|
|
41280
|
+
state = this.pages.get(operation());
|
|
41281
|
+
} catch (error) {
|
|
41282
|
+
this.settle(callbacks, error);
|
|
41283
|
+
return;
|
|
41284
|
+
}
|
|
41285
|
+
if (!state || state.canceled) this.settle(callbacks, state?.canceled ?? /* @__PURE__ */ new Error("navigateTo:fail target page was unloaded"));
|
|
41286
|
+
else if (state.completed) this.settle(callbacks);
|
|
41287
|
+
else state.callbacks = callbacks;
|
|
39743
41288
|
}
|
|
39744
41289
|
commit(page, event) {
|
|
39745
41290
|
const state = this.pages.get(page);
|
|
@@ -39756,10 +41301,40 @@ var HeadlessRouteEvents = class {
|
|
|
39756
41301
|
}
|
|
39757
41302
|
complete(page, state) {
|
|
39758
41303
|
this.requestRender(() => {
|
|
39759
|
-
if (this.pages.get(page) !== state || this.activeEvent !== state.event || !this.isCurrentPage(page)) return;
|
|
39760
|
-
|
|
41304
|
+
if (state.completed || state.canceled || this.pages.get(page) !== state || this.activeEvent !== state.event || !this.isCurrentPage(page)) return;
|
|
41305
|
+
state.completed = true;
|
|
41306
|
+
const callbacks = state.callbacks;
|
|
41307
|
+
state.callbacks = void 0;
|
|
41308
|
+
try {
|
|
41309
|
+
const event = state.event;
|
|
41310
|
+
this.bus.$emit("appRouteDone", {
|
|
41311
|
+
path: event.path,
|
|
41312
|
+
query: { ...event.query },
|
|
41313
|
+
openType: event.openType,
|
|
41314
|
+
webviewId: event.webviewId,
|
|
41315
|
+
routeEventId: event.routeEventId,
|
|
41316
|
+
timeStamp: event.timeStamp
|
|
41317
|
+
});
|
|
41318
|
+
} finally {
|
|
41319
|
+
this.settle(callbacks);
|
|
41320
|
+
}
|
|
39761
41321
|
});
|
|
39762
41322
|
}
|
|
41323
|
+
settle(callbacks, error) {
|
|
41324
|
+
try {
|
|
41325
|
+
if (error) callbacks?.fail?.(error);
|
|
41326
|
+
else callbacks?.success?.();
|
|
41327
|
+
} finally {
|
|
41328
|
+
callbacks?.complete?.();
|
|
41329
|
+
}
|
|
41330
|
+
}
|
|
41331
|
+
cancel(state, error) {
|
|
41332
|
+
if (!state || state.completed || state.canceled) return;
|
|
41333
|
+
state.canceled = error;
|
|
41334
|
+
const callbacks = state.callbacks;
|
|
41335
|
+
state.callbacks = void 0;
|
|
41336
|
+
this.settle(callbacks, error);
|
|
41337
|
+
}
|
|
39763
41338
|
beforeUnload(page, event) {
|
|
39764
41339
|
const state = this.pages.get(page);
|
|
39765
41340
|
if (event && state) this.bus.$emit("beforePageUnload", {
|
|
@@ -39770,9 +41345,12 @@ var HeadlessRouteEvents = class {
|
|
|
39770
41345
|
webviewId: state.webviewId,
|
|
39771
41346
|
page
|
|
39772
41347
|
});
|
|
41348
|
+
this.cancel(state, /* @__PURE__ */ new Error("navigateTo:fail target page was unloaded"));
|
|
39773
41349
|
this.pages.delete(page);
|
|
39774
41350
|
}
|
|
39775
41351
|
close() {
|
|
41352
|
+
this.cancel(this.activeState, /* @__PURE__ */ new Error("navigateTo:fail runtime session closed"));
|
|
41353
|
+
this.activeState = void 0;
|
|
39776
41354
|
this.activeEvent = void 0;
|
|
39777
41355
|
this.bus.$off();
|
|
39778
41356
|
}
|
|
@@ -41620,6 +43198,7 @@ var HeadlessSession = class {
|
|
|
41620
43198
|
appInstance = null;
|
|
41621
43199
|
appLifecycle = new HeadlessAppLifecycle();
|
|
41622
43200
|
moduleLoader;
|
|
43201
|
+
templateRegistration;
|
|
41623
43202
|
routeEvents = new HeadlessRouteEvents((callback) => this.requestRender(callback), (page) => this.currentPageInstance === page && !this.kernel.isClosed);
|
|
41624
43203
|
eventListeners = /* @__PURE__ */ new Map();
|
|
41625
43204
|
registries;
|
|
@@ -41628,8 +43207,13 @@ var HeadlessSession = class {
|
|
|
41628
43207
|
componentCache = /* @__PURE__ */ new Map();
|
|
41629
43208
|
componentScopes = /* @__PURE__ */ new Map();
|
|
41630
43209
|
selectorQueryScopeSnapshots = /* @__PURE__ */ new WeakMap();
|
|
41631
|
-
|
|
41632
|
-
|
|
43210
|
+
renderQueue = new RuntimeRenderQueue({
|
|
43211
|
+
isClosed: () => this.kernel.isClosed,
|
|
43212
|
+
onError: (error) => this.kernel.diagnostics.record("exception", [error]),
|
|
43213
|
+
render: () => {
|
|
43214
|
+
if (this.currentPageInstance) this.renderCurrentPage();
|
|
43215
|
+
}
|
|
43216
|
+
});
|
|
41633
43217
|
tabBarRoutes;
|
|
41634
43218
|
tabPages = /* @__PURE__ */ new Map();
|
|
41635
43219
|
tabBarItems = /* @__PURE__ */ new Map();
|
|
@@ -41648,6 +43232,7 @@ var HeadlessSession = class {
|
|
|
41648
43232
|
constructor(options) {
|
|
41649
43233
|
if (!options.project && !options.projectPath) throw new Error("Headless runtime requires projectPath or project.");
|
|
41650
43234
|
this.project = options.project ?? loadProject(options.projectPath);
|
|
43235
|
+
this.templateRegistration = createTemplateRegistration(this.project.artifactSource, this.project.miniprogramRootPath, options.compiledTemplatePaths);
|
|
41651
43236
|
this.wxState = createHeadlessWxState(this.kernel.scheduler, {
|
|
41652
43237
|
strictMocks: options.strictHostMocks,
|
|
41653
43238
|
readPackageFile: createPackageAssetReader((relative) => this.project.artifactSource.readText(path.join(this.project.miniprogramRootPath, relative)))
|
|
@@ -41701,7 +43286,7 @@ var HeadlessSession = class {
|
|
|
41701
43286
|
getMenuButtonBoundingClientRect: () => deriveMenuButtonBoundingClientRect(this.systemInfo),
|
|
41702
43287
|
getNetworkType: () => this.wxState.getNetworkType(),
|
|
41703
43288
|
navigateBack: (option) => this.navigateBack(option?.delta),
|
|
41704
|
-
navigateTo: (option) => this.navigateTo(option.url),
|
|
43289
|
+
navigateTo: (option) => this.routeEvents.navigateTo(() => this.navigateTo(option.url), option),
|
|
41705
43290
|
pageScrollTo: (option) => this.pageScrollTo(option),
|
|
41706
43291
|
openDocument: (option) => this.wxState.openDocument(option),
|
|
41707
43292
|
clearStorageSync: () => this.wxState.clearStorageSync(),
|
|
@@ -41785,8 +43370,7 @@ var HeadlessSession = class {
|
|
|
41785
43370
|
failure = { error };
|
|
41786
43371
|
}
|
|
41787
43372
|
this.canvasContexts.clear();
|
|
41788
|
-
this.
|
|
41789
|
-
this.renderRequestPending = false;
|
|
43373
|
+
this.renderQueue.close();
|
|
41790
43374
|
this.appLifecycle.close();
|
|
41791
43375
|
this.routeEvents.close();
|
|
41792
43376
|
this.wxState.close();
|
|
@@ -41836,6 +43420,23 @@ var HeadlessSession = class {
|
|
|
41836
43420
|
this.assertActive();
|
|
41837
43421
|
return this.pages.slice();
|
|
41838
43422
|
}
|
|
43423
|
+
/** 显式重载已变更的页面 entry,保留 App 与依赖缓存;调用者随后自行导航。 */
|
|
43424
|
+
reloadPageDefinition(route) {
|
|
43425
|
+
this.assertActive();
|
|
43426
|
+
const record = resolvePageDefinitionReloadRoute(this.project, route);
|
|
43427
|
+
const filePath = path.resolve(this.project.miniprogramRootPath, `${record.resourcePath ?? record.route}.js`);
|
|
43428
|
+
return this.moduleLoader.reloadPageModule(filePath, record.route);
|
|
43429
|
+
}
|
|
43430
|
+
/** 显式提交编译模板及其 import/include 依赖;不重载脚本、不导航或替换实例。 */
|
|
43431
|
+
reloadTemplates() {
|
|
43432
|
+
this.assertActive();
|
|
43433
|
+
const changed = this.templateRegistration.reload();
|
|
43434
|
+
if (changed) {
|
|
43435
|
+
closeRuntimeWxsLoader(this.moduleLoader);
|
|
43436
|
+
this.requestRender();
|
|
43437
|
+
}
|
|
43438
|
+
return changed;
|
|
43439
|
+
}
|
|
41839
43440
|
getWx() {
|
|
41840
43441
|
this.assertActive();
|
|
41841
43442
|
return this.moduleLoader.wx;
|
|
@@ -41891,7 +43492,7 @@ var HeadlessSession = class {
|
|
|
41891
43492
|
const current = this.requireCurrentPage("renderCurrentPage()");
|
|
41892
43493
|
const rendered = renderRuntimePageTree({
|
|
41893
43494
|
changedPageKeys: current.__lastChangedKeys__ ?? [],
|
|
41894
|
-
artifactSource: this.
|
|
43495
|
+
artifactSource: this.templateRegistration.artifactSource,
|
|
41895
43496
|
componentCache: this.componentCache,
|
|
41896
43497
|
componentScopes: this.componentScopes,
|
|
41897
43498
|
moduleLoader: this.moduleLoader,
|
|
@@ -41921,20 +43522,18 @@ var HeadlessSession = class {
|
|
|
41921
43522
|
dispatchNativeNodeEvent(node, eventName, event, onHandlerResult) {
|
|
41922
43523
|
const current = this.requireCurrentPage("dispatchNativeNodeEvent()");
|
|
41923
43524
|
if (eventName === "tap") this.renderCurrentPage();
|
|
41924
|
-
return dispatchNativeNodeEvent(current, node, eventName, event, this.moduleLoader.wx, (scopeId, method) => this.resolveScopeMethod(current, scopeId, method), onHandlerResult)
|
|
43525
|
+
return dispatchNativeNodeEvent(current, node, eventName, event, this.moduleLoader.wx, (scopeId, method) => this.resolveScopeMethod(current, scopeId, method), onHandlerResult, (scopeId) => {
|
|
43526
|
+
const instance = this.componentCache.get(scopeId);
|
|
43527
|
+
const scope = this.componentScopes.get(scopeId);
|
|
43528
|
+
return instance?.__definition__ && scope ? {
|
|
43529
|
+
definition: instance.__definition__,
|
|
43530
|
+
ownerScopeId: scope.ownerScopeId ?? null
|
|
43531
|
+
} : void 0;
|
|
43532
|
+
});
|
|
41925
43533
|
}
|
|
41926
43534
|
requestRender(callback) {
|
|
41927
43535
|
this.assertActive();
|
|
41928
|
-
|
|
41929
|
-
if (this.renderRequestPending) return;
|
|
41930
|
-
this.renderRequestPending = true;
|
|
41931
|
-
Promise.resolve().then(() => {
|
|
41932
|
-
if (this.kernel.isClosed) return;
|
|
41933
|
-
this.renderRequestPending = false;
|
|
41934
|
-
const callbacks = this.renderRequestCallbacks.splice(0);
|
|
41935
|
-
if (this.currentPageInstance) this.renderCurrentPage();
|
|
41936
|
-
callbacks.forEach((cb) => cb());
|
|
41937
|
-
});
|
|
43536
|
+
this.renderQueue.request(callback);
|
|
41938
43537
|
}
|
|
41939
43538
|
getScopeSnapshot(scopeId) {
|
|
41940
43539
|
const scope = this.componentScopes.get(scopeId);
|
|
@@ -42016,19 +43615,19 @@ var HeadlessSession = class {
|
|
|
42016
43615
|
return this.wxState.getShareMenu();
|
|
42017
43616
|
}
|
|
42018
43617
|
selectComponent(selector) {
|
|
42019
|
-
this.renderCurrentPage();
|
|
43618
|
+
if (!hasPendingComponentConstruction(this.componentCache)) this.renderCurrentPage();
|
|
42020
43619
|
return this.selectComponentsWithin(null, selector)[0] ?? null;
|
|
42021
43620
|
}
|
|
42022
43621
|
selectAllComponents(selector) {
|
|
42023
|
-
this.renderCurrentPage();
|
|
43622
|
+
if (!hasPendingComponentConstruction(this.componentCache)) this.renderCurrentPage();
|
|
42024
43623
|
return this.selectComponentsWithin(null, selector);
|
|
42025
43624
|
}
|
|
42026
43625
|
selectComponentWithin(scopeId, selector) {
|
|
42027
|
-
this.renderCurrentPage();
|
|
43626
|
+
if (!hasPendingComponentConstruction(this.componentCache)) this.renderCurrentPage();
|
|
42028
43627
|
return this.selectComponentsWithin(scopeId, selector)[0] ?? null;
|
|
42029
43628
|
}
|
|
42030
43629
|
selectAllComponentsWithin(scopeId, selector) {
|
|
42031
|
-
this.renderCurrentPage();
|
|
43630
|
+
if (!hasPendingComponentConstruction(this.componentCache)) this.renderCurrentPage();
|
|
42032
43631
|
return this.selectComponentsWithin(scopeId, selector);
|
|
42033
43632
|
}
|
|
42034
43633
|
selectOwnerComponent(scopeId) {
|
|
@@ -42768,6 +44367,7 @@ function createPageRootNodeHandle(options) {
|
|
|
42768
44367
|
const tree = session?.getCurrentPages().includes(page) ? session.renderCurrentPage() : renderPageTree(project, page);
|
|
42769
44368
|
return new HeadlessTestingNodeHandle(tree.root.type === "root" && !options.includeHostRoots ? tree.root.children?.[0] ?? tree.root : tree.root, {
|
|
42770
44369
|
assertActive: options.assertActive,
|
|
44370
|
+
projectionOnly: options.projectionOnly,
|
|
42771
44371
|
dispatchNativeEvent: (node, eventName, event, onHandlerResult) => session?.getCurrentPages().at(-1) === page ? session.dispatchNativeNodeEvent(node, eventName, event, onHandlerResult) : false,
|
|
42772
44372
|
callMethod: (scopeId, methodName, event) => {
|
|
42773
44373
|
if (session?.getCurrentPages().includes(page)) return session.callScopeMethod(scopeId, methodName, event);
|
|
@@ -43130,7 +44730,18 @@ var HeadlessTestingPageHandle = class {
|
|
|
43130
44730
|
renderedAccess() {
|
|
43131
44731
|
return {
|
|
43132
44732
|
assertActive: () => this.assertActive(),
|
|
43133
|
-
findAll: async (selector) =>
|
|
44733
|
+
findAll: async (selector) => {
|
|
44734
|
+
this.assertActive();
|
|
44735
|
+
const root = createPageRootNodeHandle({
|
|
44736
|
+
assertActive: () => this.assertActive(),
|
|
44737
|
+
createPageHandle: () => this,
|
|
44738
|
+
page: this.page,
|
|
44739
|
+
project: this.project,
|
|
44740
|
+
projectionOnly: true,
|
|
44741
|
+
session: this.session
|
|
44742
|
+
});
|
|
44743
|
+
return selector === "page" ? [root] : await root.$$(selector);
|
|
44744
|
+
},
|
|
43134
44745
|
waitFor: async (ms) => await this.waitFor(ms),
|
|
43135
44746
|
wxml: async () => await this.wxml()
|
|
43136
44747
|
};
|
|
@@ -43147,6 +44758,133 @@ var HeadlessTestingPageHandle = class {
|
|
|
43147
44758
|
}
|
|
43148
44759
|
};
|
|
43149
44760
|
//#endregion
|
|
44761
|
+
//#region ../../mpcore/packages/simulator/src/testing/sessionHandle/protocol.ts
|
|
44762
|
+
/** 无头协议只公布已有运行时语义;不把宿主缺失能力伪装为调试器结果。 */
|
|
44763
|
+
var HeadlessTestingProtocolUnsupportedError = class extends Error {
|
|
44764
|
+
method;
|
|
44765
|
+
code = HEADLESS_PROTOCOL_UNSUPPORTED;
|
|
44766
|
+
constructor(method) {
|
|
44767
|
+
super(`Protocol method ${method} is not supported by the headless testing runtime.`);
|
|
44768
|
+
this.method = method;
|
|
44769
|
+
this.name = "HeadlessTestingProtocolUnsupportedError";
|
|
44770
|
+
}
|
|
44771
|
+
};
|
|
44772
|
+
function requireString(params, name) {
|
|
44773
|
+
const value = params[name];
|
|
44774
|
+
if (typeof value !== "string" || !value.trim()) throw new TypeError(`Protocol parameter ${name} must be a non-empty string.`);
|
|
44775
|
+
return value;
|
|
44776
|
+
}
|
|
44777
|
+
function readArgs(params) {
|
|
44778
|
+
if (params.args === void 0) return [];
|
|
44779
|
+
if (!Array.isArray(params.args)) throw new TypeError("Protocol parameter args must be an array.");
|
|
44780
|
+
return cloneProtocolValue(params.args);
|
|
44781
|
+
}
|
|
44782
|
+
function pageSnapshot(page) {
|
|
44783
|
+
return {
|
|
44784
|
+
pageId: page.pageId,
|
|
44785
|
+
path: page.path,
|
|
44786
|
+
query: page.query
|
|
44787
|
+
};
|
|
44788
|
+
}
|
|
44789
|
+
async function dispatch(target, method, params) {
|
|
44790
|
+
switch (method) {
|
|
44791
|
+
case "Tool.getInfo": return await target.toolInfo();
|
|
44792
|
+
case "App.getCurrentPage": {
|
|
44793
|
+
const page = await target.currentPage();
|
|
44794
|
+
return page ? pageSnapshot(page) : null;
|
|
44795
|
+
}
|
|
44796
|
+
case "App.getPageStack": return { pageStack: (await target.getCurrentPages()).map(pageSnapshot) };
|
|
44797
|
+
case "App.callFunction": return { result: cloneProtocolValue(await target.evaluateWithOptions(requireString(params, "functionDeclaration"), {}, ...readArgs(params))) };
|
|
44798
|
+
case "App.callWxMethod": return { result: cloneProtocolValue(await target.callWxMethodWithOptions(requireString(params, "method"), {}, ...readArgs(params))) };
|
|
44799
|
+
default: throw new HeadlessTestingProtocolUnsupportedError(method);
|
|
44800
|
+
}
|
|
44801
|
+
}
|
|
44802
|
+
async function sendHeadlessTestingProtocol(target, method, params, options) {
|
|
44803
|
+
let rejectClosed;
|
|
44804
|
+
const closed = new Promise((_resolve, reject) => {
|
|
44805
|
+
rejectClosed = reject;
|
|
44806
|
+
});
|
|
44807
|
+
const onClose = () => rejectClosed(/* @__PURE__ */ new Error(`The headless testing session closed before protocol method ${method} completed.`));
|
|
44808
|
+
target.on("close", onClose);
|
|
44809
|
+
try {
|
|
44810
|
+
return await runWithTimeout(() => Promise.race([dispatch(target, method, params), closed]), options.timeout, `Timed out executing protocol method ${method} in headless testing runtime.`);
|
|
44811
|
+
} finally {
|
|
44812
|
+
target.off("close", onClose);
|
|
44813
|
+
}
|
|
44814
|
+
}
|
|
44815
|
+
//#endregion
|
|
44816
|
+
//#region ../../mpcore/packages/simulator/src/testing/sessionHandle/cdp.ts
|
|
44817
|
+
/** 保留官方调用形状;当前后端的 enable 会明确报告不支持。 */
|
|
44818
|
+
function createHeadlessTestingCDP(target, assertActive) {
|
|
44819
|
+
let enabling;
|
|
44820
|
+
const enable = (options) => {
|
|
44821
|
+
enabling ??= target.send("App.CDPEnable", {}, options).catch((error) => {
|
|
44822
|
+
enabling = void 0;
|
|
44823
|
+
throw error;
|
|
44824
|
+
});
|
|
44825
|
+
return enabling;
|
|
44826
|
+
};
|
|
44827
|
+
return {
|
|
44828
|
+
enable,
|
|
44829
|
+
async sendCommand(domain, method, params = {}, options) {
|
|
44830
|
+
await enable(options);
|
|
44831
|
+
return await target.send("App.CDPCommand", {
|
|
44832
|
+
domain,
|
|
44833
|
+
method,
|
|
44834
|
+
params
|
|
44835
|
+
}, options);
|
|
44836
|
+
},
|
|
44837
|
+
async listProtocol(options) {
|
|
44838
|
+
await enable(options);
|
|
44839
|
+
return await target.send("App.CDPListProtocol", {}, options);
|
|
44840
|
+
},
|
|
44841
|
+
onEvent() {
|
|
44842
|
+
assertActive();
|
|
44843
|
+
throw new HeadlessTestingProtocolUnsupportedError("App.CDPEvent");
|
|
44844
|
+
}
|
|
44845
|
+
};
|
|
44846
|
+
}
|
|
44847
|
+
//#endregion
|
|
44848
|
+
//#region ../../mpcore/packages/simulator/src/testing/sessionHandle/navigation.ts
|
|
44849
|
+
/** 所有测试句柄通过同一个 wx 导航边界等待成功、失败或关闭通知。 */
|
|
44850
|
+
var HeadlessTestingNavigation = class {
|
|
44851
|
+
session;
|
|
44852
|
+
pending = /* @__PURE__ */ new Set();
|
|
44853
|
+
constructor(session) {
|
|
44854
|
+
this.session = session;
|
|
44855
|
+
session.on("close", () => {
|
|
44856
|
+
for (const reject of this.pending) reject(/* @__PURE__ */ new Error("The headless testing session closed before navigation completed."));
|
|
44857
|
+
this.pending.clear();
|
|
44858
|
+
});
|
|
44859
|
+
}
|
|
44860
|
+
invoke(methodName, options) {
|
|
44861
|
+
return new Promise((resolve, reject) => {
|
|
44862
|
+
const rejectNavigation = (error) => {
|
|
44863
|
+
this.pending.delete(rejectNavigation);
|
|
44864
|
+
reject(error);
|
|
44865
|
+
};
|
|
44866
|
+
this.pending.add(rejectNavigation);
|
|
44867
|
+
try {
|
|
44868
|
+
this.session.callWxMethod(methodName, {
|
|
44869
|
+
...options,
|
|
44870
|
+
success: () => {
|
|
44871
|
+
this.pending.delete(rejectNavigation);
|
|
44872
|
+
resolve();
|
|
44873
|
+
},
|
|
44874
|
+
fail: (error) => {
|
|
44875
|
+
const details = error && typeof error === "object" ? error : void 0;
|
|
44876
|
+
const reason = typeof details?.errMsg === "string" ? details.errMsg : typeof details?.message === "string" ? details.message : String(error);
|
|
44877
|
+
const target = options.url ? ` route "${options.url}"` : "";
|
|
44878
|
+
rejectNavigation(new Error(`Failed to ${methodName}${target} through the headless wx runtime: ${reason}`, { cause: error }));
|
|
44879
|
+
}
|
|
44880
|
+
});
|
|
44881
|
+
} catch (error) {
|
|
44882
|
+
rejectNavigation(error);
|
|
44883
|
+
}
|
|
44884
|
+
});
|
|
44885
|
+
}
|
|
44886
|
+
};
|
|
44887
|
+
//#endregion
|
|
43150
44888
|
//#region ../../mpcore/packages/simulator/src/testing/sessionHandle/scope.ts
|
|
43151
44889
|
var HeadlessTestingScopeHandle = class HeadlessTestingScopeHandle {
|
|
43152
44890
|
scopeId;
|
|
@@ -43208,16 +44946,41 @@ var HeadlessTestingScopeHandle = class HeadlessTestingScopeHandle {
|
|
|
43208
44946
|
var HeadlessTestingSessionHandle = class {
|
|
43209
44947
|
project;
|
|
43210
44948
|
session;
|
|
43211
|
-
|
|
44949
|
+
navigation;
|
|
44950
|
+
disconnection;
|
|
44951
|
+
cdp;
|
|
43212
44952
|
constructor(project, session) {
|
|
43213
44953
|
this.project = project;
|
|
43214
44954
|
this.session = session;
|
|
43215
|
-
this.
|
|
43216
|
-
for (const reject of this.pendingNavigations) reject(/* @__PURE__ */ new Error("The headless testing session closed before navigation completed."));
|
|
43217
|
-
});
|
|
44955
|
+
this.navigation = new HeadlessTestingNavigation(session);
|
|
43218
44956
|
}
|
|
43219
|
-
|
|
43220
|
-
this.
|
|
44957
|
+
close() {
|
|
44958
|
+
return this.disconnect();
|
|
44959
|
+
}
|
|
44960
|
+
/** 先保存共享结果,再同步开始关闭,覆盖关闭监听器内的重入调用。 */
|
|
44961
|
+
disconnect() {
|
|
44962
|
+
if (!this.disconnection) {
|
|
44963
|
+
let resolve;
|
|
44964
|
+
let reject;
|
|
44965
|
+
this.disconnection = new Promise((accept, fail) => {
|
|
44966
|
+
resolve = accept;
|
|
44967
|
+
reject = fail;
|
|
44968
|
+
});
|
|
44969
|
+
try {
|
|
44970
|
+
this.session.close();
|
|
44971
|
+
resolve();
|
|
44972
|
+
} catch (error) {
|
|
44973
|
+
reject(error);
|
|
44974
|
+
}
|
|
44975
|
+
}
|
|
44976
|
+
return this.disconnection;
|
|
44977
|
+
}
|
|
44978
|
+
async send(method, params = {}, options = {}) {
|
|
44979
|
+
this.session.assertActive();
|
|
44980
|
+
return await sendHeadlessTestingProtocol(this, method, params, options);
|
|
44981
|
+
}
|
|
44982
|
+
CDP() {
|
|
44983
|
+
return this.cdp ??= createHeadlessTestingCDP(this, () => this.session.assertActive());
|
|
43221
44984
|
}
|
|
43222
44985
|
async toolInfo() {
|
|
43223
44986
|
return { version: "mpcore-simulator" };
|
|
@@ -43256,6 +45019,10 @@ var HeadlessTestingSessionHandle = class {
|
|
|
43256
45019
|
const normalizedMethodName = normalizeNonEmptyInput(methodName, "wx method name");
|
|
43257
45020
|
return await runWithTimeout(() => this.session.callWxMethod(normalizedMethodName, ...args), options.timeout, `Timed out calling wx.${normalizedMethodName} in headless testing runtime.`);
|
|
43258
45021
|
}
|
|
45022
|
+
/** 返回与 DevTools automator 兼容的运行时系统信息。 */
|
|
45023
|
+
async systemInfo() {
|
|
45024
|
+
return await this.callWxMethod("getSystemInfoSync");
|
|
45025
|
+
}
|
|
43259
45026
|
async scopeSnapshot(scopeId) {
|
|
43260
45027
|
const normalizedScopeId = normalizeNonEmptyInput(scopeId, "Scope id");
|
|
43261
45028
|
return this.session.getScopeSnapshot(normalizedScopeId);
|
|
@@ -43283,23 +45050,31 @@ var HeadlessTestingSessionHandle = class {
|
|
|
43283
45050
|
}, `Timed out waiting for ${normalizedCount} component(s) matching "${normalizedSelector}" in headless testing runtime.`, options);
|
|
43284
45051
|
}
|
|
43285
45052
|
async reLaunch(route) {
|
|
43286
|
-
await this.
|
|
45053
|
+
await this.navigation.invoke("reLaunch", { url: route });
|
|
43287
45054
|
return await this.requireCurrentPage("reLaunch", route);
|
|
43288
45055
|
}
|
|
45056
|
+
/** 只更新页面定义;不隐式导航,也不替换当前页面或应用实例。 */
|
|
45057
|
+
async reloadPageDefinition(route) {
|
|
45058
|
+
return this.session.reloadPageDefinition(route);
|
|
45059
|
+
}
|
|
45060
|
+
/** 显式提交宿主编译模板;不隐式重载脚本或导航。 */
|
|
45061
|
+
async reloadTemplates() {
|
|
45062
|
+
return this.session.reloadTemplates();
|
|
45063
|
+
}
|
|
43289
45064
|
async navigateTo(route) {
|
|
43290
|
-
await this.
|
|
45065
|
+
await this.navigation.invoke("navigateTo", { url: route });
|
|
43291
45066
|
return await this.requireCurrentPage("navigateTo", route);
|
|
43292
45067
|
}
|
|
43293
45068
|
async redirectTo(route) {
|
|
43294
|
-
await this.
|
|
45069
|
+
await this.navigation.invoke("redirectTo", { url: route });
|
|
43295
45070
|
return await this.requireCurrentPage("redirectTo", route);
|
|
43296
45071
|
}
|
|
43297
45072
|
async navigateBack(delta = 1) {
|
|
43298
|
-
await this.
|
|
45073
|
+
await this.navigation.invoke("navigateBack", { delta });
|
|
43299
45074
|
return await this.currentPage();
|
|
43300
45075
|
}
|
|
43301
45076
|
async switchTab(route) {
|
|
43302
|
-
await this.
|
|
45077
|
+
await this.navigation.invoke("switchTab", { url: route });
|
|
43303
45078
|
return await this.requireCurrentPage("switchTab", route);
|
|
43304
45079
|
}
|
|
43305
45080
|
async waitForCurrentPage(route, options = {}) {
|
|
@@ -43335,32 +45110,6 @@ var HeadlessTestingSessionHandle = class {
|
|
|
43335
45110
|
async triggerRouteDone(options) {
|
|
43336
45111
|
this.session.triggerRouteDone(options);
|
|
43337
45112
|
}
|
|
43338
|
-
invokeNavigation(methodName, options) {
|
|
43339
|
-
return new Promise((resolve, reject) => {
|
|
43340
|
-
const rejectNavigation = (error) => {
|
|
43341
|
-
this.pendingNavigations.delete(rejectNavigation);
|
|
43342
|
-
reject(error);
|
|
43343
|
-
};
|
|
43344
|
-
this.pendingNavigations.add(rejectNavigation);
|
|
43345
|
-
try {
|
|
43346
|
-
this.session.callWxMethod(methodName, {
|
|
43347
|
-
...options,
|
|
43348
|
-
success: () => {
|
|
43349
|
-
this.pendingNavigations.delete(rejectNavigation);
|
|
43350
|
-
resolve();
|
|
43351
|
-
},
|
|
43352
|
-
fail: (error) => {
|
|
43353
|
-
const details = error && typeof error === "object" ? error : void 0;
|
|
43354
|
-
const reason = typeof details?.errMsg === "string" ? details.errMsg : typeof details?.message === "string" ? details.message : String(error);
|
|
43355
|
-
const target = options.url ? ` route "${options.url}"` : "";
|
|
43356
|
-
rejectNavigation(new Error(`Failed to ${methodName}${target} through the headless wx runtime: ${reason}`, { cause: error }));
|
|
43357
|
-
}
|
|
43358
|
-
});
|
|
43359
|
-
} catch (error) {
|
|
43360
|
-
rejectNavigation(error);
|
|
43361
|
-
}
|
|
43362
|
-
});
|
|
43363
|
-
}
|
|
43364
45113
|
async requireCurrentPage(methodName, route) {
|
|
43365
45114
|
const page = await this.currentPage();
|
|
43366
45115
|
if (!page) throw new Error(`Failed to ${methodName} route "${route}" through the headless wx runtime.`);
|
|
@@ -43379,7 +45128,10 @@ function resolveInitialRoute(session) {
|
|
|
43379
45128
|
return session.project.routes[0]?.route ?? null;
|
|
43380
45129
|
}
|
|
43381
45130
|
async function launch(options) {
|
|
43382
|
-
const session = createHeadlessSession({
|
|
45131
|
+
const session = createHeadlessSession({
|
|
45132
|
+
compiledTemplatePaths: options.compiledTemplatePaths,
|
|
45133
|
+
projectPath: options.projectPath
|
|
45134
|
+
});
|
|
43383
45135
|
const handle = new HeadlessTestingSessionHandle(session.project, session);
|
|
43384
45136
|
try {
|
|
43385
45137
|
await options.onSessionCreated?.(handle);
|