@dimina/compiler 1.0.16 → 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,26 +1,27 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_env = require("../env-Dmnqp9bD.cjs");
3
- const require_compatibility = require("../compatibility-DlYbbw0F.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 解析器提取依赖
22
23
  */
23
- var KEYWORDS = new Set([
24
+ var KEYWORDS = /* @__PURE__ */ new Set([
24
25
  "true",
25
26
  "false",
26
27
  "null",
@@ -129,7 +130,19 @@ function parseBindings(bindings) {
129
130
  }
130
131
  //#endregion
131
132
  //#region src/core/view-compiler.js
132
- var fileType = [".wxml", ".ddml"];
133
+ /**
134
+ * 根据扩展名列表生成匹配尾部扩展名的正则,如 ['.wxs', '.qds'] -> /(\.wxs|\.qds)$/
135
+ */
136
+ function buildExtStripRegex(exts) {
137
+ const alt = exts.map((e) => e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
138
+ return new RegExp(`(${alt})$`);
139
+ }
140
+ /**
141
+ * 移除视图脚本文件路径末尾的扩展名,支持 .wxs 和自定义扩展名
142
+ */
143
+ function stripViewScriptExt(p) {
144
+ return p.replace(buildExtStripRegex(require_env.getViewScriptExts()), "");
145
+ }
133
146
  /**
134
147
  * 解析 JavaScript 代码
135
148
  * @param {string} code
@@ -247,7 +260,10 @@ if (!node_worker_threads.isMainThread) node_worker_threads.parentPort.on("messag
247
260
  compileResCache.clear();
248
261
  wxsModuleRegistry.clear();
249
262
  wxsFilePathMap.clear();
250
- node_worker_threads.parentPort.postMessage({ success: true });
263
+ node_worker_threads.parentPort.postMessage({
264
+ success: true,
265
+ compatibilityWarnings: require_compatibility.takeCompatibilityWarnings()
266
+ });
251
267
  } catch (error) {
252
268
  compileResCache.clear();
253
269
  wxsModuleRegistry.clear();
@@ -269,17 +285,26 @@ async function compileML(pages, root, progress) {
269
285
  initWxsFilePathMap(require_env.getWorkPath());
270
286
  for (const page of pages) {
271
287
  const scriptRes = /* @__PURE__ */ new Map();
272
- buildCompileView(page, false, scriptRes, [], /* @__PURE__ */ new Set());
288
+ buildCompileView(page, false, scriptRes, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set());
273
289
  let mergeRender = "";
274
290
  for (const [key, value] of scriptRes.entries()) {
275
- const { code: minifiedCode } = await (0, esbuild.transform)(`modDefine('${key}', function(require, module, exports) {
291
+ const amdFormat = `modDefine('${key}', function(require, module, exports) {
276
292
  ${value}
277
- });`, {
278
- minify: true,
279
- target: ["es2020"],
280
- platform: "browser"
281
- });
282
- 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
+ }
283
308
  }
284
309
  scriptRes.clear();
285
310
  const filename = `${page.path.replace(/\//g, "_")}`;
@@ -316,8 +341,8 @@ function scanWxsFiles(dir, workPath) {
316
341
  const fullPath = node_path.default.join(dir, item);
317
342
  const stat = node_fs.default.statSync(fullPath);
318
343
  if (stat.isDirectory()) scanWxsFiles(fullPath, workPath);
319
- else if (stat.isFile() && item.endsWith(".wxs")) {
320
- const moduleName = fullPath.replace(workPath, "").replace(/\.wxs$/, "").replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
344
+ else if (stat.isFile() && require_env.getViewScriptExts().some((ext) => item.endsWith(ext))) {
345
+ const moduleName = stripViewScriptExt(fullPath.replace(workPath, "")).replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
321
346
  wxsFilePathMap.set(moduleName, fullPath);
322
347
  }
323
348
  }
@@ -330,6 +355,17 @@ function scanWxsFiles(dir, workPath) {
330
355
  function registerWxsModule(modulePath) {
331
356
  wxsModuleRegistry.add(modulePath);
332
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
+ }
333
369
  /**
334
370
  * 检查是否为已注册的 wxs 模块
335
371
  * @param {string} modulePath - 模块路径
@@ -338,17 +374,10 @@ function registerWxsModule(modulePath) {
338
374
  function isRegisteredWxsModule(modulePath) {
339
375
  return wxsModuleRegistry.has(modulePath);
340
376
  }
341
- 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()) {
342
378
  const currentPath = module.path;
343
- if (depthChain.includes(currentPath)) {
344
- console.warn("[view]", `检测到循环依赖: ${[...depthChain, currentPath].join(" -> ")}`);
345
- return;
346
- }
347
- if (depthChain.length > 20) {
348
- console.warn("[view]", `检测到深度依赖: ${[...depthChain, currentPath].join(" -> ")}`);
349
- return;
350
- }
351
- depthChain = [...depthChain, currentPath];
379
+ if (activePaths.has(currentPath)) return;
380
+ activePaths.add(currentPath);
352
381
  const allScriptModules = [];
353
382
  const currentInstruction = compileModule(module, isComponent, scriptRes, { skipTemplatePaths: isComponent ? inheritedTemplatePaths : /* @__PURE__ */ new Set() });
354
383
  if (currentInstruction && currentInstruction.scriptModule) allScriptModules.push(...currentInstruction.scriptModule);
@@ -357,11 +386,8 @@ function buildCompileView(module, isComponent = false, scriptRes, depthChain = [
357
386
  if (module.usingComponents) for (const componentInfo of Object.values(module.usingComponents)) {
358
387
  const componentModule = require_env.getComponent(componentInfo);
359
388
  if (!componentModule) continue;
360
- if (componentModule.path === module.path) {
361
- console.warn("[view]", `检测到循环依赖,跳过处理: ${module.path}`);
362
- continue;
363
- }
364
- const componentInstruction = buildCompileView(componentModule, true, scriptRes, depthChain, childInheritedTemplatePaths);
389
+ if (componentModule.path === module.path) continue;
390
+ const componentInstruction = buildCompileView(componentModule, true, scriptRes, activePaths, childInheritedTemplatePaths);
365
391
  if (componentInstruction && componentInstruction.scriptModule) {
366
392
  for (const sm of componentInstruction.scriptModule) if (!allScriptModules.find((existing) => existing.path === sm.path)) allScriptModules.push(sm);
367
393
  }
@@ -370,6 +396,7 @@ function buildCompileView(module, isComponent = false, scriptRes, depthChain = [
370
396
  for (const sm of allScriptModules) if (!scriptRes.has(sm.path)) scriptRes.set(sm.path, sm.code);
371
397
  compileModuleWithAllWxs(module, scriptRes, allScriptModules);
372
398
  }
399
+ activePaths.delete(currentPath);
373
400
  return {
374
401
  scriptModule: allScriptModules,
375
402
  templateModule: currentInstruction?.templateModule || []
@@ -422,14 +449,7 @@ function compileModule(module, isComponent, scriptRes, options = {}) {
422
449
  filename: module.path,
423
450
  id: `data-v-${module.id}`,
424
451
  scoped: true,
425
- compilerOptions: {
426
- prefixIdentifiers: true,
427
- hoistStatic: false,
428
- cacheHandlers: true,
429
- scopeId: `data-v-${module.id}`,
430
- mode: "function",
431
- inline: true
432
- }
452
+ compilerOptions: getTemplateCompilerOptions(`data-v-${module.id}`)
433
453
  });
434
454
  let tplComponents = "{";
435
455
  for (const tm of compileInstruction.templateModule) {
@@ -438,14 +458,7 @@ function compileModule(module, isComponent, scriptRes, options = {}) {
438
458
  filename: tm.path,
439
459
  id: `data-v-${module.id}`,
440
460
  scoped: true,
441
- compilerOptions: {
442
- prefixIdentifiers: true,
443
- hoistStatic: false,
444
- cacheHandlers: true,
445
- scopeId: `data-v-${module.id}`,
446
- mode: "function",
447
- inline: true
448
- }
461
+ compilerOptions: getTemplateCompilerOptions(`data-v-${module.id}`)
449
462
  });
450
463
  code = insertWxsToRenderCode(code, compileInstruction.scriptModule, scriptRes, tm.path);
451
464
  tplComponents += `'${tm.path}':${code},`;
@@ -455,8 +468,12 @@ function compileModule(module, isComponent, scriptRes, options = {}) {
455
468
  const code = `Module({
456
469
  path: '${module.path}',
457
470
  id: '${module.id}',
471
+ appStyleScopeId: ${JSON.stringify(module.appStyleScopeId || null)},
472
+ sharedStyleScopeIds: ${JSON.stringify(module.sharedStyleScopeIds || [])},
473
+ styleIsolation: ${JSON.stringify(module.styleIsolation || "isolated")},
458
474
  render: ${transCode},
459
475
  usingComponents: ${JSON.stringify(module.usingComponents)},
476
+ customTabBar: ${JSON.stringify(module.customTabBar || null)},
460
477
  tplComponents: ${tplComponents},
461
478
  });`;
462
479
  const allWxsModules = collectAllWxsModules(scriptRes, /* @__PURE__ */ new Set(), compileInstruction.scriptModule || []);
@@ -529,7 +546,7 @@ function processWxsContent(wxsContent, wxsFilePath, scriptModule, workPath, file
529
546
  if (filePath && filePath.includes("/miniprogram_npm/")) {
530
547
  const currentWxsDir = node_path.default.dirname(wxsFilePath);
531
548
  resolvedWxsPath = node_path.default.resolve(currentWxsDir, requirePath);
532
- const moduleName = resolvedWxsPath.replace(workPath, "").replace(/\.wxs$/, "").replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
549
+ const moduleName = stripViewScriptExt(resolvedWxsPath.replace(workPath, "")).replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
533
550
  processWxsDependency(resolvedWxsPath, moduleName, scriptModule, workPath, filePath);
534
551
  replacements.push({
535
552
  start: node.arguments[0].start,
@@ -539,7 +556,7 @@ function processWxsContent(wxsContent, wxsFilePath, scriptModule, workPath, file
539
556
  } else {
540
557
  const currentWxsDir = node_path.default.dirname(wxsFilePath);
541
558
  resolvedWxsPath = node_path.default.resolve(currentWxsDir, requirePath);
542
- const depModuleName = resolvedWxsPath.replace(workPath, "").replace(/\.wxs$/, "").replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
559
+ const depModuleName = stripViewScriptExt(resolvedWxsPath.replace(workPath, "")).replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
543
560
  processWxsDependency(resolvedWxsPath, depModuleName, scriptModule, workPath, filePath);
544
561
  replacements.push({
545
562
  start: node.arguments[0].start,
@@ -607,14 +624,7 @@ function compileModuleWithAllWxs(module, scriptRes, allScriptModules) {
607
624
  filename: module.path,
608
625
  id: `data-v-${module.id}`,
609
626
  scoped: true,
610
- compilerOptions: {
611
- prefixIdentifiers: true,
612
- hoistStatic: false,
613
- cacheHandlers: true,
614
- scopeId: `data-v-${module.id}`,
615
- mode: "function",
616
- inline: true
617
- }
627
+ compilerOptions: getTemplateCompilerOptions(`data-v-${module.id}`)
618
628
  });
619
629
  let tplComponents = "{";
620
630
  for (const tm of mergedInstruction.templateModule) {
@@ -623,14 +633,7 @@ function compileModuleWithAllWxs(module, scriptRes, allScriptModules) {
623
633
  filename: tm.path,
624
634
  id: `data-v-${module.id}`,
625
635
  scoped: true,
626
- compilerOptions: {
627
- prefixIdentifiers: true,
628
- hoistStatic: false,
629
- cacheHandlers: true,
630
- scopeId: `data-v-${module.id}`,
631
- mode: "function",
632
- inline: true
633
- }
636
+ compilerOptions: getTemplateCompilerOptions(`data-v-${module.id}`)
634
637
  });
635
638
  code = insertWxsToRenderCode(code, allScriptModules, scriptRes, tm.path);
636
639
  tplComponents += `'${tm.path}':${code},`;
@@ -640,8 +643,12 @@ function compileModuleWithAllWxs(module, scriptRes, allScriptModules) {
640
643
  const code = `Module({
641
644
  path: '${module.path}',
642
645
  id: '${module.id}',
646
+ appStyleScopeId: ${JSON.stringify(module.appStyleScopeId || null)},
647
+ sharedStyleScopeIds: ${JSON.stringify(module.sharedStyleScopeIds || [])},
648
+ styleIsolation: ${JSON.stringify(module.styleIsolation || "isolated")},
643
649
  render: ${transCode},
644
650
  usingComponents: ${JSON.stringify(module.usingComponents)},
651
+ customTabBar: ${JSON.stringify(module.customTabBar || null)},
645
652
  tplComponents: ${tplComponents},
646
653
  });`;
647
654
  const cacheData = {
@@ -723,12 +730,13 @@ function toCompileTemplate(isComponent, path, components, componentPlaceholder,
723
730
  const workPath = require_env.getWorkPath();
724
731
  const fullPath = getViewPath(workPath, path);
725
732
  if (!fullPath) return { tpl: void 0 };
733
+ const sourcePath = require_env.toMiniProgramModuleId(fullPath, workPath).replace(buildExtStripRegex(require_env.getTemplateExts()), "");
726
734
  const diagnosticSource = fullPath.startsWith(workPath) ? fullPath.slice(workPath.length) : path;
727
735
  let content = require_env.getContentByPath(fullPath).trim();
728
736
  if (!content) content = "<block></block>";
729
737
  else {
730
738
  require_compatibility.checkTemplateCompatibility(content, diagnosticSource, components);
731
- if (isComponent) content = `<wrapper name="${path}">${content}</wrapper>`;
739
+ if (isComponent) content = `<component-host name="${path}">${content}</component-host>`;
732
740
  else if (cheerio.load(content, {
733
741
  xmlMode: true,
734
742
  decodeEntities: false
@@ -746,8 +754,8 @@ function toCompileTemplate(isComponent, path, components, componentPlaceholder,
746
754
  $("include").each((_, elem) => {
747
755
  const src = $(elem).attr("src");
748
756
  if (src) {
749
- const includeFullPath = require_env.getAbsolutePath(workPath, path, src);
750
- let includePath = includeFullPath.replace(workPath, "").replace(/\.(wxml|ddml)$/, "");
757
+ const includeFullPath = resolveTemplateDependencyPath(workPath, sourcePath, src);
758
+ let includePath = includeFullPath.replace(workPath, "").replace(buildExtStripRegex(require_env.getTemplateExts()), "");
751
759
  const includeDiagnosticSource = includeFullPath.startsWith(workPath) ? includeFullPath.slice(workPath.length) : includePath;
752
760
  if (!includePath.startsWith("/")) includePath = "/" + includePath;
753
761
  const includeContent = require_env.getContentByPath(includeFullPath).trim();
@@ -761,21 +769,20 @@ function toCompileTemplate(isComponent, path, components, componentPlaceholder,
761
769
  transTagWxs($includeContent, scriptModule, includePath);
762
770
  processIncludedFileWxsDependencies(includeContent, includePath, scriptModule, components, processedPaths);
763
771
  $includeContent("template").remove();
764
- $includeContent("wxs").remove();
765
- $includeContent("dds").remove();
772
+ $includeContent(require_env.getViewScriptTags().join(",")).remove();
766
773
  const processedContent = processIncludeConditionalAttrs($, elem, $includeContent.html());
767
774
  $(elem).replaceWith(processedContent);
768
775
  } else $(elem).remove();
769
776
  } else $(elem).remove();
770
777
  });
771
- transTagTemplate($, templateModule, path, components, componentPlaceholder);
772
- transTagWxs($, scriptModule, path);
778
+ transTagTemplate($, templateModule, sourcePath, components, componentPlaceholder);
779
+ transTagWxs($, scriptModule, sourcePath);
773
780
  const importNodes = $("import");
774
781
  importNodes.each((_, elem) => {
775
782
  const src = $(elem).attr("src");
776
783
  if (src) {
777
- const importFullPath = require_env.getAbsolutePath(workPath, path, src);
778
- let importPath = importFullPath.replace(workPath, "").replace(/\.(wxml|ddml)$/, "");
784
+ const importFullPath = resolveTemplateDependencyPath(workPath, sourcePath, src);
785
+ let importPath = importFullPath.replace(workPath, "").replace(buildExtStripRegex(require_env.getTemplateExts()), "");
779
786
  const importDiagnosticSource = importFullPath.startsWith(workPath) ? importFullPath.slice(workPath.length) : importPath;
780
787
  if (!importPath.startsWith("/")) importPath = "/" + importPath;
781
788
  const importContent = require_env.getContentByPath(importFullPath).trim();
@@ -785,14 +792,14 @@ function toCompileTemplate(isComponent, path, components, componentPlaceholder,
785
792
  xmlMode: true,
786
793
  decodeEntities: false
787
794
  });
788
- transTagTemplate($$, templateModule, path, components, componentPlaceholder);
795
+ transTagTemplate($$, templateModule, importPath, components, componentPlaceholder);
789
796
  transTagWxs($$, scriptModule, importPath);
790
797
  processIncludedFileWxsDependencies(importContent, importPath, scriptModule, components, processedPaths);
791
798
  }
792
799
  }
793
800
  });
794
801
  importNodes.remove();
795
- transAsses($, $("image"), path);
802
+ transAsses($, $("image"), sourcePath);
796
803
  const res = [];
797
804
  transHtmlTag($.html(), res, components, componentPlaceholder);
798
805
  return {
@@ -810,8 +817,7 @@ function transTagTemplate($, templateModule, path, components, componentPlacehol
810
817
  const templateContent = $(elem);
811
818
  templateContent.find("import").remove();
812
819
  templateContent.find("include").remove();
813
- templateContent.find("wxs").remove();
814
- templateContent.find("dds").remove();
820
+ templateContent.find(require_env.getViewScriptTags().join(",")).remove();
815
821
  transAsses($, templateContent.find("image"), path);
816
822
  const res = [];
817
823
  transHtmlTag(templateContent.html(), res, components, componentPlaceholder);
@@ -828,6 +834,72 @@ function transAsses($, imageNodes, path) {
828
834
  if (!imgSrc.startsWith("{{")) $(elem).attr("src", require_env.collectAssets(require_env.getWorkPath(), path, imgSrc, require_env.getTargetPath(), require_env.getAppId()));
829
835
  });
830
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
+ }
831
903
  function transHtmlTag(html, res, components, componentPlaceholder) {
832
904
  const attrsList = [];
833
905
  const parser = new htmlparser2.Parser({
@@ -855,7 +927,7 @@ function transHtmlTag(html, res, components, componentPlaceholder) {
855
927
  console.error(error);
856
928
  }
857
929
  }, { xmlMode: true });
858
- parser.write(html);
930
+ parser.write(normalizeTemplateSyntax(html, components));
859
931
  parser.end();
860
932
  }
861
933
  /**
@@ -865,11 +937,15 @@ function transHtmlTag(html, res, components, componentPlaceholder) {
865
937
  function transTag(opts) {
866
938
  const { isStart, tag, attrs, components } = opts;
867
939
  let res;
868
- 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;
869
945
  else if (components && components[tag]) res = `dd-${tag}`;
870
946
  else if (tag === "component" || tag === "canvas") res = tag;
871
- else if (!require_env.tagWhiteList.includes(tag)) res = "dd-text";
872
- else res = `dd-${tag}`;
947
+ else if (require_env.tagWhiteList.includes(tag)) res = `dd-${tag}`;
948
+ else res = tag;
873
949
  let tagRes;
874
950
  const propsAry = isStart ? getProps(attrs, tag, components) : [];
875
951
  const multipleSlots = attrs?.slot;
@@ -914,7 +990,17 @@ function generateSlotDirective(slotValue) {
914
990
  */
915
991
  function getProps(attrs, tag, components) {
916
992
  const attrsList = [];
993
+ const isCustomComponent = Boolean(components && components[tag]);
917
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
+ });
918
1004
  Object.entries(attrs).forEach(([name, value]) => {
919
1005
  if (name.endsWith(":if")) attrsList.push({
920
1006
  name: "v-if",
@@ -938,11 +1024,20 @@ function getProps(attrs, tag, components) {
938
1024
  name: ":key",
939
1025
  value: tranValue
940
1026
  });
941
- } else if (name === "style") attrsList.push({
942
- name: "v-c-style",
943
- value: require_env.transformRpx(parseSafeBraceExp(value))
944
- });
945
- 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") {
946
1041
  if (isWrappedByBraces(value)) attrsList.push({
947
1042
  name: ":class",
948
1043
  value: parseClassRules(value)
@@ -994,7 +1089,7 @@ function getProps(attrs, tag, components) {
994
1089
  });
995
1090
  else if (isWrappedByBraces(value)) {
996
1091
  const pVal = tag === "template" && name === "data" ? parseTemplateDataExp(value) : parseSafeBraceExp(value);
997
- if (components && components[tag]) {
1092
+ if (isCustomComponent) {
998
1093
  if (pVal && typeof pVal === "string") propBindings[name] = pVal;
999
1094
  }
1000
1095
  attrsList.push({
@@ -1013,7 +1108,7 @@ function getProps(attrs, tag, components) {
1013
1108
  else if (/\$\{[^}]*\}/.test(value)) propsRes.push(`:${name}="\`${value}\`"`);
1014
1109
  else propsRes.push(`${name}="${escapeQuotes(value)}"`);
1015
1110
  });
1016
- if (components && components[tag] && Object.keys(propBindings).length > 0) try {
1111
+ if (isCustomComponent && Object.keys(propBindings).length > 0) try {
1017
1112
  const validBindings = {};
1018
1113
  for (const [key, value] of Object.entries(propBindings)) if (value !== void 0 && value !== null && typeof value === "string") validBindings[key] = value;
1019
1114
  if (Object.keys(validBindings).length > 0) {
@@ -1077,7 +1172,7 @@ function parseKeyExpression(exp, itemName = "item", indexName = "index") {
1077
1172
  */
1078
1173
  function getViewPath(workPath, src) {
1079
1174
  const aSrc = src.startsWith("/") ? src : `/${src}`;
1080
- for (const mlType of fileType) {
1175
+ for (const mlType of require_env.getTemplateExts()) {
1081
1176
  const mlFullPath = `${workPath}${aSrc}${mlType}`;
1082
1177
  if (node_fs.default.existsSync(mlFullPath)) return mlFullPath;
1083
1178
  const indexMlFullPath = `${workPath}${aSrc}/index${mlType}`;
@@ -1085,6 +1180,20 @@ function getViewPath(workPath, src) {
1085
1180
  }
1086
1181
  }
1087
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
+ /**
1088
1197
  * 将字符串内部的双引号进行替换
1089
1198
  * @param {*} input
1090
1199
  */
@@ -1125,7 +1234,7 @@ function splitWithBraces(str) {
1125
1234
  function parseClassRules(cssRule) {
1126
1235
  let list = splitWithBraces(cssRule);
1127
1236
  list = list.map((item) => {
1128
- return parseBraceExp(item);
1237
+ return parseSafeBraceExp(item);
1129
1238
  });
1130
1239
  if (list.length === 1) return list.pop();
1131
1240
  return `[${list.join(",")}]`;
@@ -1153,11 +1262,16 @@ function getForIndexName(attrs) {
1153
1262
  * @param {*} attrs
1154
1263
  */
1155
1264
  function parseForExp(exp, attrs) {
1156
- return `(${getForItemName(attrs)}, ${getForIndexName(attrs)}) in ${parseBraceExp(exp)}`;
1265
+ return `(${getForItemName(attrs)}, ${getForIndexName(attrs)}) in ${parseSafeBraceExp(exp)}`;
1157
1266
  }
1158
1267
  var braceRegex = /(\{\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\}\})|([^{}]+)/g;
1159
1268
  var noBraceRegex = /\{\{((?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*)\}\}/;
1160
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
+ }
1161
1275
  /**
1162
1276
  * 解析 {{}} 表达式的值
1163
1277
  * @param {*} exp
@@ -1169,7 +1283,7 @@ function parseBraceExp(exp) {
1169
1283
  if (result[1]) {
1170
1284
  const matchResult = result[1].match(noBraceRegex);
1171
1285
  if (matchResult) {
1172
- const statement = matchResult[1].trim();
1286
+ const statement = encodeReservedTemplateContextIdentifier(matchResult[1].trim());
1173
1287
  if (ternaryRegex.test(statement)) group.push(`(${statement})`);
1174
1288
  else group.push(statement);
1175
1289
  }
@@ -1185,12 +1299,11 @@ function parseBraceExp(exp) {
1185
1299
  */
1186
1300
  function parseTemplateDataExp(exp) {
1187
1301
  const matchResult = exp.trim().match(/^\{\{([\s\S]*)\}\}$/);
1188
- if (matchResult) return `{${matchResult[1].trim()}}`;
1189
- return `{${parseBraceExp(exp)}}`;
1302
+ if (matchResult) return addOptionalChaining(`{${matchResult[1].trim()}}`);
1303
+ return `{${parseSafeBraceExp(exp)}}`;
1190
1304
  }
1191
1305
  function transTagWxs($, scriptModule, filePath) {
1192
- let wxsNodes = $("wxs");
1193
- if (wxsNodes.length === 0) wxsNodes = $("dds");
1306
+ const wxsNodes = $(require_env.getViewScriptTags().join(","));
1194
1307
  wxsNodes.each((_, elem) => {
1195
1308
  const smName = $(elem).attr("module");
1196
1309
  if (smName) {
@@ -1206,7 +1319,7 @@ function transTagWxs($, scriptModule, filePath) {
1206
1319
  wxsFilePath = node_path.default.resolve(componentFullPath, src);
1207
1320
  } else wxsFilePath = require_env.getAbsolutePath(workPath, filePath, src);
1208
1321
  if (wxsFilePath) {
1209
- uniqueModuleName = wxsFilePath.replace(workPath, "").replace(/\.wxs$/, "").replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
1322
+ uniqueModuleName = stripViewScriptExt(wxsFilePath.replace(workPath, "")).replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
1210
1323
  cacheKey = wxsFilePath;
1211
1324
  }
1212
1325
  }
@@ -1254,7 +1367,7 @@ function collectAllWxsModules(scriptRes, collectedPaths = /* @__PURE__ */ new Se
1254
1367
  });
1255
1368
  const dependencies = extractWxsDependencies(moduleCode);
1256
1369
  for (const depPath of dependencies) if (!collectedPaths.has(depPath)) if (scriptRes.has(depPath)) {
1257
- const depModules = collectAllWxsModules(new Map([[depPath, scriptRes.get(depPath)]]), collectedPaths, scriptModule);
1370
+ const depModules = collectAllWxsModules(/* @__PURE__ */ new Map([[depPath, scriptRes.get(depPath)]]), collectedPaths, scriptModule);
1258
1371
  allWxsModules.push(...depModules);
1259
1372
  } else {
1260
1373
  const loaded = loadWxsModule(depPath, workPath, scriptModule);
@@ -1262,7 +1375,7 @@ function collectAllWxsModules(scriptRes, collectedPaths = /* @__PURE__ */ new Se
1262
1375
  scriptRes.set(depPath, loaded.code);
1263
1376
  allWxsModules.push(loaded);
1264
1377
  collectedPaths.add(depPath);
1265
- const depModules = collectAllWxsModules(new Map([[depPath, loaded.code]]), collectedPaths, scriptModule);
1378
+ const depModules = collectAllWxsModules(/* @__PURE__ */ new Map([[depPath, loaded.code]]), collectedPaths, scriptModule);
1266
1379
  allWxsModules.push(...depModules);
1267
1380
  }
1268
1381
  }
@@ -1278,12 +1391,8 @@ function collectAllWxsModules(scriptRes, collectedPaths = /* @__PURE__ */ new Se
1278
1391
  * @returns {Object|null} 加载的模块对象或 null
1279
1392
  */
1280
1393
  function loadWxsModule(modulePath, workPath, scriptModule) {
1281
- if (!modulePath.startsWith("miniprogram_npm__") || !modulePath.includes("_wxs_")) return null;
1282
1394
  const wxsFilePath = wxsFilePathMap.get(modulePath);
1283
- if (!wxsFilePath) {
1284
- console.warn(`[view] 无法找到 wxs 模块文件: ${modulePath}`);
1285
- return null;
1286
- }
1395
+ if (!wxsFilePath) return null;
1287
1396
  try {
1288
1397
  const wxsContent = require_env.getContentByPath(wxsFilePath).trim();
1289
1398
  if (!wxsContent) return null;
@@ -1331,8 +1440,7 @@ function insertWxsToRenderCode(code, scriptModule, scriptRes, filename = "render
1331
1440
  });
1332
1441
  declarations.push(`const ${localIdentifier} = require(${JSON.stringify(requireModuleName)});`);
1333
1442
  }
1334
- if (wxsBindings.length === 0) return getProgramCode(code, ast);
1335
- if (renderBody?.type === "BlockStatement") codeReplacements.push({
1443
+ if (wxsBindings.length > 0 && renderBody?.type === "BlockStatement") codeReplacements.push({
1336
1444
  type: "insert",
1337
1445
  start: renderBody.start + 1,
1338
1446
  end: renderBody.start + 1,
@@ -1340,6 +1448,15 @@ function insertWxsToRenderCode(code, scriptModule, scriptRes, filename = "render
1340
1448
  });
1341
1449
  (0, oxc_walker.walk)(ast, { enter(node) {
1342
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
+ }
1343
1460
  const replacement = wxsBindings.find((item) => item.templatePropertyName === node.property.name);
1344
1461
  if (replacement) codeReplacements.push({
1345
1462
  start: node.start,
@@ -1348,6 +1465,7 @@ function insertWxsToRenderCode(code, scriptModule, scriptRes, filename = "render
1348
1465
  });
1349
1466
  }
1350
1467
  } });
1468
+ if (codeReplacements.length === 0) return getProgramCode(code, ast);
1351
1469
  const transformed = applyCodeReplacements(code, codeReplacements);
1352
1470
  return getProgramCode(transformed, parseJs(transformed, filename));
1353
1471
  }
@@ -1355,6 +1473,9 @@ function insertWxsToRenderCode(code, scriptModule, scriptRes, filename = "render
1355
1473
  exports.compileML = compileML;
1356
1474
  exports.generateSlotDirective = generateSlotDirective;
1357
1475
  exports.generateVModelTemplate = generateVModelTemplate;
1476
+ exports.initWxsFilePathMap = initWxsFilePathMap;
1477
+ exports.loadWxsModule = loadWxsModule;
1478
+ exports.normalizeTemplateSyntax = normalizeTemplateSyntax;
1358
1479
  exports.parseBraceExp = parseBraceExp;
1359
1480
  exports.parseClassRules = parseClassRules;
1360
1481
  exports.parseKeyExpression = parseKeyExpression;