@dimina/compiler 1.0.17 → 1.1.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.
@@ -1,21 +1,22 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_env = require("../env-BWsUjuZE.cjs");
3
- const require_compatibility = require("../compatibility-DnN63SVV.cjs");
2
+ const require_rolldown_runtime = require("../rolldown-runtime-D6vf50IK.cjs");
3
+ const require_env = require("../env-B4U3zZUm.cjs");
4
+ const require_compatibility = require("../compatibility-CzIJUgPs.cjs");
4
5
  let node_path = require("node:path");
5
- node_path = require_env.__toESM(node_path, 1);
6
+ node_path = require_rolldown_runtime.__toESM(node_path, 1);
6
7
  let node_worker_threads = require("node:worker_threads");
7
8
  let node_fs = require("node:fs");
8
- node_fs = require_env.__toESM(node_fs, 1);
9
+ node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
9
10
  let oxc_parser = require("oxc-parser");
10
11
  let oxc_walker = require("oxc-walker");
11
12
  let magic_string = require("magic-string");
12
- magic_string = require_env.__toESM(magic_string, 1);
13
+ magic_string = require_rolldown_runtime.__toESM(magic_string, 1);
13
14
  let _vue_compiler_sfc = require("@vue/compiler-sfc");
14
15
  let cheerio = require("cheerio");
15
- cheerio = require_env.__toESM(cheerio, 1);
16
+ cheerio = require_rolldown_runtime.__toESM(cheerio, 1);
16
17
  let esbuild = require("esbuild");
17
18
  let htmlparser2 = require("htmlparser2");
18
- htmlparser2 = require_env.__toESM(htmlparser2, 1);
19
+ htmlparser2 = require_rolldown_runtime.__toESM(htmlparser2, 1);
19
20
  //#region src/common/expression-parser.js
20
21
  /**
21
22
  * 表达式解析器 - 使用 Oxc AST 解析器提取依赖
@@ -259,7 +260,10 @@ if (!node_worker_threads.isMainThread) node_worker_threads.parentPort.on("messag
259
260
  compileResCache.clear();
260
261
  wxsModuleRegistry.clear();
261
262
  wxsFilePathMap.clear();
262
- node_worker_threads.parentPort.postMessage({ success: true });
263
+ node_worker_threads.parentPort.postMessage({
264
+ success: true,
265
+ compatibilityWarnings: require_compatibility.takeCompatibilityWarnings()
266
+ });
263
267
  } catch (error) {
264
268
  compileResCache.clear();
265
269
  wxsModuleRegistry.clear();
@@ -281,17 +285,26 @@ async function compileML(pages, root, progress) {
281
285
  initWxsFilePathMap(require_env.getWorkPath());
282
286
  for (const page of pages) {
283
287
  const scriptRes = /* @__PURE__ */ new Map();
284
- buildCompileView(page, false, scriptRes, [], /* @__PURE__ */ new Set());
288
+ buildCompileView(page, false, scriptRes, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set());
285
289
  let mergeRender = "";
286
290
  for (const [key, value] of scriptRes.entries()) {
287
- const { code: minifiedCode } = await (0, esbuild.transform)(`modDefine('${key}', function(require, module, exports) {
291
+ const amdFormat = `modDefine('${key}', function(require, module, exports) {
288
292
  ${value}
289
- });`, {
290
- minify: true,
291
- target: ["es2020"],
292
- platform: "browser"
293
- });
294
- mergeRender += minifiedCode;
293
+ });`;
294
+ try {
295
+ const { code: minifiedCode } = await (0, esbuild.transform)(amdFormat, {
296
+ minify: true,
297
+ target: ["es2020"],
298
+ platform: "browser"
299
+ });
300
+ mergeRender += minifiedCode;
301
+ } catch (error) {
302
+ const location = error.errors?.[0]?.location;
303
+ const sourceLines = amdFormat.split("\n");
304
+ const sourceHint = location?.line ? sourceLines.slice(Math.max(0, location.line - 3), location.line + 2).map((line, index) => `${Math.max(1, location.line - 2) + index}: ${line.trim()}`).join("\n") : "";
305
+ error.message = `视图模块 ${key} 转换失败: ${error.message}${sourceHint ? `\n${sourceHint}` : ""}`;
306
+ throw error;
307
+ }
295
308
  }
296
309
  scriptRes.clear();
297
310
  const filename = `${page.path.replace(/\//g, "_")}`;
@@ -342,6 +355,17 @@ function scanWxsFiles(dir, workPath) {
342
355
  function registerWxsModule(modulePath) {
343
356
  wxsModuleRegistry.add(modulePath);
344
357
  }
358
+ function getTemplateCompilerOptions(scopeId) {
359
+ return {
360
+ prefixIdentifiers: true,
361
+ hoistStatic: false,
362
+ cacheHandlers: true,
363
+ scopeId,
364
+ mode: "function",
365
+ inline: true,
366
+ isCustomElement: (tag) => !tag.startsWith("dd-")
367
+ };
368
+ }
345
369
  /**
346
370
  * 检查是否为已注册的 wxs 模块
347
371
  * @param {string} modulePath - 模块路径
@@ -350,17 +374,10 @@ function registerWxsModule(modulePath) {
350
374
  function isRegisteredWxsModule(modulePath) {
351
375
  return wxsModuleRegistry.has(modulePath);
352
376
  }
353
- function buildCompileView(module, isComponent = false, scriptRes, depthChain = [], inheritedTemplatePaths = /* @__PURE__ */ new Set()) {
377
+ function buildCompileView(module, isComponent = false, scriptRes, activePaths = /* @__PURE__ */ new Set(), inheritedTemplatePaths = /* @__PURE__ */ new Set()) {
354
378
  const currentPath = module.path;
355
- if (depthChain.includes(currentPath)) {
356
- console.warn("[view]", `检测到循环依赖: ${[...depthChain, currentPath].join(" -> ")}`);
357
- return;
358
- }
359
- if (depthChain.length > 20) {
360
- console.warn("[view]", `检测到深度依赖: ${[...depthChain, currentPath].join(" -> ")}`);
361
- return;
362
- }
363
- depthChain = [...depthChain, currentPath];
379
+ if (activePaths.has(currentPath)) return;
380
+ activePaths.add(currentPath);
364
381
  const allScriptModules = [];
365
382
  const currentInstruction = compileModule(module, isComponent, scriptRes, { skipTemplatePaths: isComponent ? inheritedTemplatePaths : /* @__PURE__ */ new Set() });
366
383
  if (currentInstruction && currentInstruction.scriptModule) allScriptModules.push(...currentInstruction.scriptModule);
@@ -369,11 +386,8 @@ function buildCompileView(module, isComponent = false, scriptRes, depthChain = [
369
386
  if (module.usingComponents) for (const componentInfo of Object.values(module.usingComponents)) {
370
387
  const componentModule = require_env.getComponent(componentInfo);
371
388
  if (!componentModule) continue;
372
- if (componentModule.path === module.path) {
373
- console.warn("[view]", `检测到循环依赖,跳过处理: ${module.path}`);
374
- continue;
375
- }
376
- const componentInstruction = buildCompileView(componentModule, true, scriptRes, depthChain, childInheritedTemplatePaths);
389
+ if (componentModule.path === module.path) continue;
390
+ const componentInstruction = buildCompileView(componentModule, true, scriptRes, activePaths, childInheritedTemplatePaths);
377
391
  if (componentInstruction && componentInstruction.scriptModule) {
378
392
  for (const sm of componentInstruction.scriptModule) if (!allScriptModules.find((existing) => existing.path === sm.path)) allScriptModules.push(sm);
379
393
  }
@@ -382,6 +396,7 @@ function buildCompileView(module, isComponent = false, scriptRes, depthChain = [
382
396
  for (const sm of allScriptModules) if (!scriptRes.has(sm.path)) scriptRes.set(sm.path, sm.code);
383
397
  compileModuleWithAllWxs(module, scriptRes, allScriptModules);
384
398
  }
399
+ activePaths.delete(currentPath);
385
400
  return {
386
401
  scriptModule: allScriptModules,
387
402
  templateModule: currentInstruction?.templateModule || []
@@ -434,14 +449,7 @@ function compileModule(module, isComponent, scriptRes, options = {}) {
434
449
  filename: module.path,
435
450
  id: `data-v-${module.id}`,
436
451
  scoped: true,
437
- compilerOptions: {
438
- prefixIdentifiers: true,
439
- hoistStatic: false,
440
- cacheHandlers: true,
441
- scopeId: `data-v-${module.id}`,
442
- mode: "function",
443
- inline: true
444
- }
452
+ compilerOptions: getTemplateCompilerOptions(`data-v-${module.id}`)
445
453
  });
446
454
  let tplComponents = "{";
447
455
  for (const tm of compileInstruction.templateModule) {
@@ -450,14 +458,7 @@ function compileModule(module, isComponent, scriptRes, options = {}) {
450
458
  filename: tm.path,
451
459
  id: `data-v-${module.id}`,
452
460
  scoped: true,
453
- compilerOptions: {
454
- prefixIdentifiers: true,
455
- hoistStatic: false,
456
- cacheHandlers: true,
457
- scopeId: `data-v-${module.id}`,
458
- mode: "function",
459
- inline: true
460
- }
461
+ compilerOptions: getTemplateCompilerOptions(`data-v-${module.id}`)
461
462
  });
462
463
  code = insertWxsToRenderCode(code, compileInstruction.scriptModule, scriptRes, tm.path);
463
464
  tplComponents += `'${tm.path}':${code},`;
@@ -467,8 +468,12 @@ function compileModule(module, isComponent, scriptRes, options = {}) {
467
468
  const code = `Module({
468
469
  path: '${module.path}',
469
470
  id: '${module.id}',
471
+ appStyleScopeId: ${JSON.stringify(module.appStyleScopeId || null)},
472
+ sharedStyleScopeIds: ${JSON.stringify(module.sharedStyleScopeIds || [])},
473
+ styleIsolation: ${JSON.stringify(module.styleIsolation || "isolated")},
470
474
  render: ${transCode},
471
475
  usingComponents: ${JSON.stringify(module.usingComponents)},
476
+ customTabBar: ${JSON.stringify(module.customTabBar || null)},
472
477
  tplComponents: ${tplComponents},
473
478
  });`;
474
479
  const allWxsModules = collectAllWxsModules(scriptRes, /* @__PURE__ */ new Set(), compileInstruction.scriptModule || []);
@@ -619,14 +624,7 @@ function compileModuleWithAllWxs(module, scriptRes, allScriptModules) {
619
624
  filename: module.path,
620
625
  id: `data-v-${module.id}`,
621
626
  scoped: true,
622
- compilerOptions: {
623
- prefixIdentifiers: true,
624
- hoistStatic: false,
625
- cacheHandlers: true,
626
- scopeId: `data-v-${module.id}`,
627
- mode: "function",
628
- inline: true
629
- }
627
+ compilerOptions: getTemplateCompilerOptions(`data-v-${module.id}`)
630
628
  });
631
629
  let tplComponents = "{";
632
630
  for (const tm of mergedInstruction.templateModule) {
@@ -635,14 +633,7 @@ function compileModuleWithAllWxs(module, scriptRes, allScriptModules) {
635
633
  filename: tm.path,
636
634
  id: `data-v-${module.id}`,
637
635
  scoped: true,
638
- compilerOptions: {
639
- prefixIdentifiers: true,
640
- hoistStatic: false,
641
- cacheHandlers: true,
642
- scopeId: `data-v-${module.id}`,
643
- mode: "function",
644
- inline: true
645
- }
636
+ compilerOptions: getTemplateCompilerOptions(`data-v-${module.id}`)
646
637
  });
647
638
  code = insertWxsToRenderCode(code, allScriptModules, scriptRes, tm.path);
648
639
  tplComponents += `'${tm.path}':${code},`;
@@ -652,8 +643,12 @@ function compileModuleWithAllWxs(module, scriptRes, allScriptModules) {
652
643
  const code = `Module({
653
644
  path: '${module.path}',
654
645
  id: '${module.id}',
646
+ appStyleScopeId: ${JSON.stringify(module.appStyleScopeId || null)},
647
+ sharedStyleScopeIds: ${JSON.stringify(module.sharedStyleScopeIds || [])},
648
+ styleIsolation: ${JSON.stringify(module.styleIsolation || "isolated")},
655
649
  render: ${transCode},
656
650
  usingComponents: ${JSON.stringify(module.usingComponents)},
651
+ customTabBar: ${JSON.stringify(module.customTabBar || null)},
657
652
  tplComponents: ${tplComponents},
658
653
  });`;
659
654
  const cacheData = {
@@ -735,12 +730,13 @@ function toCompileTemplate(isComponent, path, components, componentPlaceholder,
735
730
  const workPath = require_env.getWorkPath();
736
731
  const fullPath = getViewPath(workPath, path);
737
732
  if (!fullPath) return { tpl: void 0 };
733
+ const sourcePath = require_env.toMiniProgramModuleId(fullPath, workPath).replace(buildExtStripRegex(require_env.getTemplateExts()), "");
738
734
  const diagnosticSource = fullPath.startsWith(workPath) ? fullPath.slice(workPath.length) : path;
739
735
  let content = require_env.getContentByPath(fullPath).trim();
740
736
  if (!content) content = "<block></block>";
741
737
  else {
742
738
  require_compatibility.checkTemplateCompatibility(content, diagnosticSource, components);
743
- if (isComponent) content = `<wrapper name="${path}">${content}</wrapper>`;
739
+ if (isComponent) content = `<component-host name="${path}">${content}</component-host>`;
744
740
  else if (cheerio.load(content, {
745
741
  xmlMode: true,
746
742
  decodeEntities: false
@@ -758,7 +754,7 @@ function toCompileTemplate(isComponent, path, components, componentPlaceholder,
758
754
  $("include").each((_, elem) => {
759
755
  const src = $(elem).attr("src");
760
756
  if (src) {
761
- const includeFullPath = require_env.getAbsolutePath(workPath, path, src);
757
+ const includeFullPath = resolveTemplateDependencyPath(workPath, sourcePath, src);
762
758
  let includePath = includeFullPath.replace(workPath, "").replace(buildExtStripRegex(require_env.getTemplateExts()), "");
763
759
  const includeDiagnosticSource = includeFullPath.startsWith(workPath) ? includeFullPath.slice(workPath.length) : includePath;
764
760
  if (!includePath.startsWith("/")) includePath = "/" + includePath;
@@ -779,13 +775,13 @@ function toCompileTemplate(isComponent, path, components, componentPlaceholder,
779
775
  } else $(elem).remove();
780
776
  } else $(elem).remove();
781
777
  });
782
- transTagTemplate($, templateModule, path, components, componentPlaceholder);
783
- transTagWxs($, scriptModule, path);
778
+ transTagTemplate($, templateModule, sourcePath, components, componentPlaceholder);
779
+ transTagWxs($, scriptModule, sourcePath);
784
780
  const importNodes = $("import");
785
781
  importNodes.each((_, elem) => {
786
782
  const src = $(elem).attr("src");
787
783
  if (src) {
788
- const importFullPath = require_env.getAbsolutePath(workPath, path, src);
784
+ const importFullPath = resolveTemplateDependencyPath(workPath, sourcePath, src);
789
785
  let importPath = importFullPath.replace(workPath, "").replace(buildExtStripRegex(require_env.getTemplateExts()), "");
790
786
  const importDiagnosticSource = importFullPath.startsWith(workPath) ? importFullPath.slice(workPath.length) : importPath;
791
787
  if (!importPath.startsWith("/")) importPath = "/" + importPath;
@@ -796,14 +792,14 @@ function toCompileTemplate(isComponent, path, components, componentPlaceholder,
796
792
  xmlMode: true,
797
793
  decodeEntities: false
798
794
  });
799
- transTagTemplate($$, templateModule, path, components, componentPlaceholder);
795
+ transTagTemplate($$, templateModule, importPath, components, componentPlaceholder);
800
796
  transTagWxs($$, scriptModule, importPath);
801
797
  processIncludedFileWxsDependencies(importContent, importPath, scriptModule, components, processedPaths);
802
798
  }
803
799
  }
804
800
  });
805
801
  importNodes.remove();
806
- transAsses($, $("image"), path);
802
+ transAsses($, $("image"), sourcePath);
807
803
  const res = [];
808
804
  transHtmlTag($.html(), res, components, componentPlaceholder);
809
805
  return {
@@ -838,6 +834,72 @@ function transAsses($, imageNodes, path) {
838
834
  if (!imgSrc.startsWith("{{")) $(elem).attr("src", require_env.collectAssets(require_env.getWorkPath(), path, imgSrc, require_env.getTargetPath(), require_env.getAppId()));
839
835
  });
840
836
  }
837
+ var DIMINA_SLOT_GROUP_TAG = "dimina-slot-group";
838
+ var DIMINA_FOR_SCOPE_TAG = "dimina-for-scope";
839
+ function getDirectiveAttributeNames(attrs, suffixes) {
840
+ return Object.keys(attrs || {}).filter((name) => suffixes.some((suffix) => name.endsWith(suffix)));
841
+ }
842
+ function hasForAndIf(attrs) {
843
+ return getDirectiveAttributeNames(attrs, [":for", ":for-items"]).length > 0 && getDirectiveAttributeNames(attrs, [":if"]).length > 0;
844
+ }
845
+ function groupDuplicateNamedSlots($, components) {
846
+ const slotHosts = $("*").toArray().filter((element) => {
847
+ const tag = element.tagName;
848
+ return tag === "component" || Boolean(components?.[tag]);
849
+ });
850
+ for (const host of slotHosts) {
851
+ const groups = /* @__PURE__ */ new Map();
852
+ for (const child of $(host).children().toArray()) {
853
+ const slotName = child.attribs?.slot;
854
+ if (!slotName) continue;
855
+ const group = groups.get(slotName) || [];
856
+ group.push(child);
857
+ groups.set(slotName, group);
858
+ }
859
+ for (const [slotName, nodes] of groups) {
860
+ if (nodes.length === 1 && !hasForAndIf(nodes[0].attribs)) continue;
861
+ const wrapper = $(`<${DIMINA_SLOT_GROUP_TAG}></${DIMINA_SLOT_GROUP_TAG}>`);
862
+ wrapper.attr("name", slotName);
863
+ $(nodes[0]).before(wrapper);
864
+ for (const node of nodes) {
865
+ $(node).removeAttr("slot");
866
+ wrapper.append(node);
867
+ }
868
+ }
869
+ }
870
+ }
871
+ function wrapForIfScopes($) {
872
+ const nodes = $("*").toArray();
873
+ for (const node of nodes) {
874
+ if (node.tagName === DIMINA_FOR_SCOPE_TAG || !hasForAndIf(node.attribs)) continue;
875
+ const attrsToMove = getDirectiveAttributeNames(node.attribs, [
876
+ ":for",
877
+ ":for-items",
878
+ ":for-item",
879
+ ":for-index",
880
+ ":key"
881
+ ]);
882
+ const wrapper = $(`<${DIMINA_FOR_SCOPE_TAG}></${DIMINA_FOR_SCOPE_TAG}>`);
883
+ for (const name of attrsToMove) {
884
+ wrapper.attr(name, node.attribs[name]);
885
+ $(node).removeAttr(name);
886
+ }
887
+ $(node).before(wrapper);
888
+ wrapper.append(node);
889
+ }
890
+ }
891
+ function normalizeTemplateSyntax(html, components) {
892
+ const $ = cheerio.load(html, {
893
+ xmlMode: true,
894
+ decodeEntities: false,
895
+ _useHtmlParser2: true,
896
+ lowerCaseTags: false,
897
+ lowerCaseAttributeNames: false
898
+ });
899
+ groupDuplicateNamedSlots($, components);
900
+ wrapForIfScopes($);
901
+ return $.html();
902
+ }
841
903
  function transHtmlTag(html, res, components, componentPlaceholder) {
842
904
  const attrsList = [];
843
905
  const parser = new htmlparser2.Parser({
@@ -865,7 +927,7 @@ function transHtmlTag(html, res, components, componentPlaceholder) {
865
927
  console.error(error);
866
928
  }
867
929
  }, { xmlMode: true });
868
- parser.write(html);
930
+ parser.write(normalizeTemplateSyntax(html, components));
869
931
  parser.end();
870
932
  }
871
933
  /**
@@ -875,11 +937,15 @@ function transHtmlTag(html, res, components, componentPlaceholder) {
875
937
  function transTag(opts) {
876
938
  const { isStart, tag, attrs, components } = opts;
877
939
  let res;
878
- if (tag === "slot") res = tag;
940
+ if (tag === DIMINA_SLOT_GROUP_TAG) {
941
+ if (isStart) return `<template ${generateSlotDirective(attrs.name)}>`;
942
+ return "</template>";
943
+ } else if (tag === DIMINA_FOR_SCOPE_TAG) res = "template";
944
+ else if (tag === "slot") res = tag;
879
945
  else if (components && components[tag]) res = `dd-${tag}`;
880
946
  else if (tag === "component" || tag === "canvas") res = tag;
881
- else if (!require_env.tagWhiteList.includes(tag)) res = "dd-text";
882
- else res = `dd-${tag}`;
947
+ else if (require_env.tagWhiteList.includes(tag)) res = `dd-${tag}`;
948
+ else res = tag;
883
949
  let tagRes;
884
950
  const propsAry = isStart ? getProps(attrs, tag, components) : [];
885
951
  const multipleSlots = attrs?.slot;
@@ -924,7 +990,17 @@ function generateSlotDirective(slotValue) {
924
990
  */
925
991
  function getProps(attrs, tag, components) {
926
992
  const attrsList = [];
993
+ const isCustomComponent = Boolean(components && components[tag]);
927
994
  const propBindings = {};
995
+ const hasEventBindings = Object.keys(attrs).some((name) => /^(?:capture-)?(?:bind|catch)(?::)?.+/.test(name));
996
+ if (tag === "page-meta") attrsList.push({
997
+ name: "dimina-rpx-unit",
998
+ value: "vw"
999
+ });
1000
+ if (hasEventBindings) attrsList.push({
1001
+ name: "v-c-event-node",
1002
+ value: components && components[tag] ? "'component'" : "'node'"
1003
+ });
928
1004
  Object.entries(attrs).forEach(([name, value]) => {
929
1005
  if (name.endsWith(":if")) attrsList.push({
930
1006
  name: "v-if",
@@ -948,11 +1024,20 @@ function getProps(attrs, tag, components) {
948
1024
  name: ":key",
949
1025
  value: tranValue
950
1026
  });
951
- } else if (name === "style") attrsList.push({
952
- name: "v-c-style",
953
- value: require_env.transformRpx(parseSafeBraceExp(value))
954
- });
955
- else if (name === "class") {
1027
+ } else if (name === "style") {
1028
+ const parsedStyle = parseSafeBraceExp(value);
1029
+ attrsList.push({
1030
+ name: "v-c-style",
1031
+ value: require_env.transformRpx(parsedStyle)
1032
+ });
1033
+ if (isCustomComponent) {
1034
+ attrsList.push({
1035
+ name: ":dimina-wxml-style",
1036
+ value: parsedStyle
1037
+ });
1038
+ if (isWrappedByBraces(value) && parsedStyle) propBindings.style = parsedStyle;
1039
+ }
1040
+ } else if (name === "class") {
956
1041
  if (isWrappedByBraces(value)) attrsList.push({
957
1042
  name: ":class",
958
1043
  value: parseClassRules(value)
@@ -1004,7 +1089,7 @@ function getProps(attrs, tag, components) {
1004
1089
  });
1005
1090
  else if (isWrappedByBraces(value)) {
1006
1091
  const pVal = tag === "template" && name === "data" ? parseTemplateDataExp(value) : parseSafeBraceExp(value);
1007
- if (components && components[tag]) {
1092
+ if (isCustomComponent) {
1008
1093
  if (pVal && typeof pVal === "string") propBindings[name] = pVal;
1009
1094
  }
1010
1095
  attrsList.push({
@@ -1023,7 +1108,7 @@ function getProps(attrs, tag, components) {
1023
1108
  else if (/\$\{[^}]*\}/.test(value)) propsRes.push(`:${name}="\`${value}\`"`);
1024
1109
  else propsRes.push(`${name}="${escapeQuotes(value)}"`);
1025
1110
  });
1026
- if (components && components[tag] && Object.keys(propBindings).length > 0) try {
1111
+ if (isCustomComponent && Object.keys(propBindings).length > 0) try {
1027
1112
  const validBindings = {};
1028
1113
  for (const [key, value] of Object.entries(propBindings)) if (value !== void 0 && value !== null && typeof value === "string") validBindings[key] = value;
1029
1114
  if (Object.keys(validBindings).length > 0) {
@@ -1095,6 +1180,20 @@ function getViewPath(workPath, src) {
1095
1180
  }
1096
1181
  }
1097
1182
  /**
1183
+ * 解析 import/include 的模板文件路径。
1184
+ * 微信允许省略 .wxml;显式扩展名保持原样,无扩展名时按当前模板类型优先级补全。
1185
+ */
1186
+ function resolveTemplateDependencyPath(workPath, ownerPath, src) {
1187
+ const resolvedPath = require_env.getAbsolutePath(workPath, ownerPath, src);
1188
+ if (node_fs.default.existsSync(resolvedPath) && node_fs.default.statSync(resolvedPath).isFile()) return resolvedPath;
1189
+ if (node_path.default.extname(resolvedPath)) return resolvedPath;
1190
+ for (const ext of require_env.getTemplateExts()) {
1191
+ const candidate = `${resolvedPath}${ext}`;
1192
+ if (node_fs.default.existsSync(candidate) && node_fs.default.statSync(candidate).isFile()) return candidate;
1193
+ }
1194
+ return resolvedPath;
1195
+ }
1196
+ /**
1098
1197
  * 将字符串内部的双引号进行替换
1099
1198
  * @param {*} input
1100
1199
  */
@@ -1135,7 +1234,7 @@ function splitWithBraces(str) {
1135
1234
  function parseClassRules(cssRule) {
1136
1235
  let list = splitWithBraces(cssRule);
1137
1236
  list = list.map((item) => {
1138
- return parseBraceExp(item);
1237
+ return parseSafeBraceExp(item);
1139
1238
  });
1140
1239
  if (list.length === 1) return list.pop();
1141
1240
  return `[${list.join(",")}]`;
@@ -1163,11 +1262,16 @@ function getForIndexName(attrs) {
1163
1262
  * @param {*} attrs
1164
1263
  */
1165
1264
  function parseForExp(exp, attrs) {
1166
- return `(${getForItemName(attrs)}, ${getForIndexName(attrs)}) in ${parseBraceExp(exp)}`;
1265
+ return `(${getForItemName(attrs)}, ${getForIndexName(attrs)}) in ${parseSafeBraceExp(exp)}`;
1167
1266
  }
1168
1267
  var braceRegex = /(\{\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\}\})|([^{}]+)/g;
1169
1268
  var noBraceRegex = /\{\{((?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*)\}\}/;
1170
1269
  var ternaryRegex = /[^?]+\?.+:.+/;
1270
+ var RESERVED_TEMPLATE_CONTEXT_ALIASES = /* @__PURE__ */ new Map([["class", "__dimina_reserved_class"]]);
1271
+ var RESERVED_TEMPLATE_CONTEXT_NAMES = new Map([...RESERVED_TEMPLATE_CONTEXT_ALIASES].map(([name, alias]) => [alias, name]));
1272
+ function encodeReservedTemplateContextIdentifier(expression) {
1273
+ return RESERVED_TEMPLATE_CONTEXT_ALIASES.get(expression) || expression;
1274
+ }
1171
1275
  /**
1172
1276
  * 解析 {{}} 表达式的值
1173
1277
  * @param {*} exp
@@ -1179,7 +1283,7 @@ function parseBraceExp(exp) {
1179
1283
  if (result[1]) {
1180
1284
  const matchResult = result[1].match(noBraceRegex);
1181
1285
  if (matchResult) {
1182
- const statement = matchResult[1].trim();
1286
+ const statement = encodeReservedTemplateContextIdentifier(matchResult[1].trim());
1183
1287
  if (ternaryRegex.test(statement)) group.push(`(${statement})`);
1184
1288
  else group.push(statement);
1185
1289
  }
@@ -1195,8 +1299,8 @@ function parseBraceExp(exp) {
1195
1299
  */
1196
1300
  function parseTemplateDataExp(exp) {
1197
1301
  const matchResult = exp.trim().match(/^\{\{([\s\S]*)\}\}$/);
1198
- if (matchResult) return `{${matchResult[1].trim()}}`;
1199
- return `{${parseBraceExp(exp)}}`;
1302
+ if (matchResult) return addOptionalChaining(`{${matchResult[1].trim()}}`);
1303
+ return `{${parseSafeBraceExp(exp)}}`;
1200
1304
  }
1201
1305
  function transTagWxs($, scriptModule, filePath) {
1202
1306
  const wxsNodes = $(require_env.getViewScriptTags().join(","));
@@ -1336,8 +1440,7 @@ function insertWxsToRenderCode(code, scriptModule, scriptRes, filename = "render
1336
1440
  });
1337
1441
  declarations.push(`const ${localIdentifier} = require(${JSON.stringify(requireModuleName)});`);
1338
1442
  }
1339
- if (wxsBindings.length === 0) return getProgramCode(code, ast);
1340
- if (renderBody?.type === "BlockStatement") codeReplacements.push({
1443
+ if (wxsBindings.length > 0 && renderBody?.type === "BlockStatement") codeReplacements.push({
1341
1444
  type: "insert",
1342
1445
  start: renderBody.start + 1,
1343
1446
  end: renderBody.start + 1,
@@ -1345,6 +1448,15 @@ function insertWxsToRenderCode(code, scriptModule, scriptRes, filename = "render
1345
1448
  });
1346
1449
  (0, oxc_walker.walk)(ast, { enter(node) {
1347
1450
  if (node.type === "MemberExpression" && node.object?.type === "Identifier" && node.object.name === "_ctx" && !node.computed && node.property?.type === "Identifier") {
1451
+ const reservedName = RESERVED_TEMPLATE_CONTEXT_NAMES.get(node.property.name);
1452
+ if (reservedName) {
1453
+ codeReplacements.push({
1454
+ start: node.property.start,
1455
+ end: node.property.end,
1456
+ value: reservedName
1457
+ });
1458
+ return;
1459
+ }
1348
1460
  const replacement = wxsBindings.find((item) => item.templatePropertyName === node.property.name);
1349
1461
  if (replacement) codeReplacements.push({
1350
1462
  start: node.start,
@@ -1353,6 +1465,7 @@ function insertWxsToRenderCode(code, scriptModule, scriptRes, filename = "render
1353
1465
  });
1354
1466
  }
1355
1467
  } });
1468
+ if (codeReplacements.length === 0) return getProgramCode(code, ast);
1356
1469
  const transformed = applyCodeReplacements(code, codeReplacements);
1357
1470
  return getProgramCode(transformed, parseJs(transformed, filename));
1358
1471
  }
@@ -1362,6 +1475,7 @@ exports.generateSlotDirective = generateSlotDirective;
1362
1475
  exports.generateVModelTemplate = generateVModelTemplate;
1363
1476
  exports.initWxsFilePathMap = initWxsFilePathMap;
1364
1477
  exports.loadWxsModule = loadWxsModule;
1478
+ exports.normalizeTemplateSyntax = normalizeTemplateSyntax;
1365
1479
  exports.parseBraceExp = parseBraceExp;
1366
1480
  exports.parseClassRules = parseClassRules;
1367
1481
  exports.parseKeyExpression = parseKeyExpression;