@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.
- package/README.md +23 -0
- package/dist/bin/index.cjs +17 -15
- package/dist/bin/index.js +13 -11
- package/dist/{compatibility-DlYbbw0F.cjs → compatibility-CzIJUgPs.cjs} +99 -4
- package/dist/{compatibility-C_zWVjYl.js → compatibility-DdxfVhcK.js} +94 -4
- package/dist/core/logic-compiler.cjs +16 -18
- package/dist/core/logic-compiler.js +13 -16
- package/dist/core/style-compiler.cjs +62 -61
- package/dist/core/style-compiler.js +53 -53
- package/dist/core/view-compiler.cjs +232 -111
- package/dist/core/view-compiler.js +224 -107
- package/dist/{env-Dmnqp9bD.cjs → env-B4U3zZUm.cjs} +297 -65
- package/dist/{env-p9Az8lv5.js → env-OH3--qg8.js} +250 -28
- package/dist/index.cjs +124 -32
- package/dist/index.js +119 -28
- package/dist/rolldown-runtime-D6vf50IK.cjs +28 -0
- package/package.json +15 -11
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as checkTemplateCompatibility } from "../compatibility-
|
|
1
|
+
import { C as tagWhiteList, T as toMiniProgramModuleId, a as getComponent, b as getAbsolutePath, d as getTargetPath, f as getTemplateExts, g as resetStoreInfo, h as getWorkPath, m as getViewScriptTags, n as getAppId, o as getContentByPath, p as getViewScriptExts, w as transformRpx, y as collectAssets } from "../env-OH3--qg8.js";
|
|
2
|
+
import { r as takeCompatibilityWarnings, t as checkTemplateCompatibility } from "../compatibility-DdxfVhcK.js";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { isMainThread, parentPort } from "node:worker_threads";
|
|
5
5
|
import fs from "node:fs";
|
|
@@ -14,7 +14,7 @@ import * as htmlparser2 from "htmlparser2";
|
|
|
14
14
|
/**
|
|
15
15
|
* 表达式解析器 - 使用 Oxc AST 解析器提取依赖
|
|
16
16
|
*/
|
|
17
|
-
var KEYWORDS = new Set([
|
|
17
|
+
var KEYWORDS = /* @__PURE__ */ new Set([
|
|
18
18
|
"true",
|
|
19
19
|
"false",
|
|
20
20
|
"null",
|
|
@@ -123,7 +123,19 @@ function parseBindings(bindings) {
|
|
|
123
123
|
}
|
|
124
124
|
//#endregion
|
|
125
125
|
//#region src/core/view-compiler.js
|
|
126
|
-
|
|
126
|
+
/**
|
|
127
|
+
* 根据扩展名列表生成匹配尾部扩展名的正则,如 ['.wxs', '.qds'] -> /(\.wxs|\.qds)$/
|
|
128
|
+
*/
|
|
129
|
+
function buildExtStripRegex(exts) {
|
|
130
|
+
const alt = exts.map((e) => e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
131
|
+
return new RegExp(`(${alt})$`);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 移除视图脚本文件路径末尾的扩展名,支持 .wxs 和自定义扩展名
|
|
135
|
+
*/
|
|
136
|
+
function stripViewScriptExt(p) {
|
|
137
|
+
return p.replace(buildExtStripRegex(getViewScriptExts()), "");
|
|
138
|
+
}
|
|
127
139
|
/**
|
|
128
140
|
* 解析 JavaScript 代码
|
|
129
141
|
* @param {string} code
|
|
@@ -241,7 +253,10 @@ if (!isMainThread) parentPort.on("message", async ({ pages, storeInfo }) => {
|
|
|
241
253
|
compileResCache.clear();
|
|
242
254
|
wxsModuleRegistry.clear();
|
|
243
255
|
wxsFilePathMap.clear();
|
|
244
|
-
parentPort.postMessage({
|
|
256
|
+
parentPort.postMessage({
|
|
257
|
+
success: true,
|
|
258
|
+
compatibilityWarnings: takeCompatibilityWarnings()
|
|
259
|
+
});
|
|
245
260
|
} catch (error) {
|
|
246
261
|
compileResCache.clear();
|
|
247
262
|
wxsModuleRegistry.clear();
|
|
@@ -263,17 +278,26 @@ async function compileML(pages, root, progress) {
|
|
|
263
278
|
initWxsFilePathMap(getWorkPath());
|
|
264
279
|
for (const page of pages) {
|
|
265
280
|
const scriptRes = /* @__PURE__ */ new Map();
|
|
266
|
-
buildCompileView(page, false, scriptRes,
|
|
281
|
+
buildCompileView(page, false, scriptRes, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set());
|
|
267
282
|
let mergeRender = "";
|
|
268
283
|
for (const [key, value] of scriptRes.entries()) {
|
|
269
|
-
const
|
|
284
|
+
const amdFormat = `modDefine('${key}', function(require, module, exports) {
|
|
270
285
|
${value}
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
286
|
+
});`;
|
|
287
|
+
try {
|
|
288
|
+
const { code: minifiedCode } = await transform(amdFormat, {
|
|
289
|
+
minify: true,
|
|
290
|
+
target: ["es2020"],
|
|
291
|
+
platform: "browser"
|
|
292
|
+
});
|
|
293
|
+
mergeRender += minifiedCode;
|
|
294
|
+
} catch (error) {
|
|
295
|
+
const location = error.errors?.[0]?.location;
|
|
296
|
+
const sourceLines = amdFormat.split("\n");
|
|
297
|
+
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") : "";
|
|
298
|
+
error.message = `视图模块 ${key} 转换失败: ${error.message}${sourceHint ? `\n${sourceHint}` : ""}`;
|
|
299
|
+
throw error;
|
|
300
|
+
}
|
|
277
301
|
}
|
|
278
302
|
scriptRes.clear();
|
|
279
303
|
const filename = `${page.path.replace(/\//g, "_")}`;
|
|
@@ -310,8 +334,8 @@ function scanWxsFiles(dir, workPath) {
|
|
|
310
334
|
const fullPath = path.join(dir, item);
|
|
311
335
|
const stat = fs.statSync(fullPath);
|
|
312
336
|
if (stat.isDirectory()) scanWxsFiles(fullPath, workPath);
|
|
313
|
-
else if (stat.isFile() && item.endsWith(
|
|
314
|
-
const moduleName = fullPath.replace(workPath, "")
|
|
337
|
+
else if (stat.isFile() && getViewScriptExts().some((ext) => item.endsWith(ext))) {
|
|
338
|
+
const moduleName = stripViewScriptExt(fullPath.replace(workPath, "")).replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
|
|
315
339
|
wxsFilePathMap.set(moduleName, fullPath);
|
|
316
340
|
}
|
|
317
341
|
}
|
|
@@ -324,6 +348,17 @@ function scanWxsFiles(dir, workPath) {
|
|
|
324
348
|
function registerWxsModule(modulePath) {
|
|
325
349
|
wxsModuleRegistry.add(modulePath);
|
|
326
350
|
}
|
|
351
|
+
function getTemplateCompilerOptions(scopeId) {
|
|
352
|
+
return {
|
|
353
|
+
prefixIdentifiers: true,
|
|
354
|
+
hoistStatic: false,
|
|
355
|
+
cacheHandlers: true,
|
|
356
|
+
scopeId,
|
|
357
|
+
mode: "function",
|
|
358
|
+
inline: true,
|
|
359
|
+
isCustomElement: (tag) => !tag.startsWith("dd-")
|
|
360
|
+
};
|
|
361
|
+
}
|
|
327
362
|
/**
|
|
328
363
|
* 检查是否为已注册的 wxs 模块
|
|
329
364
|
* @param {string} modulePath - 模块路径
|
|
@@ -332,17 +367,10 @@ function registerWxsModule(modulePath) {
|
|
|
332
367
|
function isRegisteredWxsModule(modulePath) {
|
|
333
368
|
return wxsModuleRegistry.has(modulePath);
|
|
334
369
|
}
|
|
335
|
-
function buildCompileView(module, isComponent = false, scriptRes,
|
|
370
|
+
function buildCompileView(module, isComponent = false, scriptRes, activePaths = /* @__PURE__ */ new Set(), inheritedTemplatePaths = /* @__PURE__ */ new Set()) {
|
|
336
371
|
const currentPath = module.path;
|
|
337
|
-
if (
|
|
338
|
-
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
if (depthChain.length > 20) {
|
|
342
|
-
console.warn("[view]", `检测到深度依赖: ${[...depthChain, currentPath].join(" -> ")}`);
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
depthChain = [...depthChain, currentPath];
|
|
372
|
+
if (activePaths.has(currentPath)) return;
|
|
373
|
+
activePaths.add(currentPath);
|
|
346
374
|
const allScriptModules = [];
|
|
347
375
|
const currentInstruction = compileModule(module, isComponent, scriptRes, { skipTemplatePaths: isComponent ? inheritedTemplatePaths : /* @__PURE__ */ new Set() });
|
|
348
376
|
if (currentInstruction && currentInstruction.scriptModule) allScriptModules.push(...currentInstruction.scriptModule);
|
|
@@ -351,11 +379,8 @@ function buildCompileView(module, isComponent = false, scriptRes, depthChain = [
|
|
|
351
379
|
if (module.usingComponents) for (const componentInfo of Object.values(module.usingComponents)) {
|
|
352
380
|
const componentModule = getComponent(componentInfo);
|
|
353
381
|
if (!componentModule) continue;
|
|
354
|
-
if (componentModule.path === module.path)
|
|
355
|
-
|
|
356
|
-
continue;
|
|
357
|
-
}
|
|
358
|
-
const componentInstruction = buildCompileView(componentModule, true, scriptRes, depthChain, childInheritedTemplatePaths);
|
|
382
|
+
if (componentModule.path === module.path) continue;
|
|
383
|
+
const componentInstruction = buildCompileView(componentModule, true, scriptRes, activePaths, childInheritedTemplatePaths);
|
|
359
384
|
if (componentInstruction && componentInstruction.scriptModule) {
|
|
360
385
|
for (const sm of componentInstruction.scriptModule) if (!allScriptModules.find((existing) => existing.path === sm.path)) allScriptModules.push(sm);
|
|
361
386
|
}
|
|
@@ -364,6 +389,7 @@ function buildCompileView(module, isComponent = false, scriptRes, depthChain = [
|
|
|
364
389
|
for (const sm of allScriptModules) if (!scriptRes.has(sm.path)) scriptRes.set(sm.path, sm.code);
|
|
365
390
|
compileModuleWithAllWxs(module, scriptRes, allScriptModules);
|
|
366
391
|
}
|
|
392
|
+
activePaths.delete(currentPath);
|
|
367
393
|
return {
|
|
368
394
|
scriptModule: allScriptModules,
|
|
369
395
|
templateModule: currentInstruction?.templateModule || []
|
|
@@ -416,14 +442,7 @@ function compileModule(module, isComponent, scriptRes, options = {}) {
|
|
|
416
442
|
filename: module.path,
|
|
417
443
|
id: `data-v-${module.id}`,
|
|
418
444
|
scoped: true,
|
|
419
|
-
compilerOptions: {
|
|
420
|
-
prefixIdentifiers: true,
|
|
421
|
-
hoistStatic: false,
|
|
422
|
-
cacheHandlers: true,
|
|
423
|
-
scopeId: `data-v-${module.id}`,
|
|
424
|
-
mode: "function",
|
|
425
|
-
inline: true
|
|
426
|
-
}
|
|
445
|
+
compilerOptions: getTemplateCompilerOptions(`data-v-${module.id}`)
|
|
427
446
|
});
|
|
428
447
|
let tplComponents = "{";
|
|
429
448
|
for (const tm of compileInstruction.templateModule) {
|
|
@@ -432,14 +451,7 @@ function compileModule(module, isComponent, scriptRes, options = {}) {
|
|
|
432
451
|
filename: tm.path,
|
|
433
452
|
id: `data-v-${module.id}`,
|
|
434
453
|
scoped: true,
|
|
435
|
-
compilerOptions: {
|
|
436
|
-
prefixIdentifiers: true,
|
|
437
|
-
hoistStatic: false,
|
|
438
|
-
cacheHandlers: true,
|
|
439
|
-
scopeId: `data-v-${module.id}`,
|
|
440
|
-
mode: "function",
|
|
441
|
-
inline: true
|
|
442
|
-
}
|
|
454
|
+
compilerOptions: getTemplateCompilerOptions(`data-v-${module.id}`)
|
|
443
455
|
});
|
|
444
456
|
code = insertWxsToRenderCode(code, compileInstruction.scriptModule, scriptRes, tm.path);
|
|
445
457
|
tplComponents += `'${tm.path}':${code},`;
|
|
@@ -449,8 +461,12 @@ function compileModule(module, isComponent, scriptRes, options = {}) {
|
|
|
449
461
|
const code = `Module({
|
|
450
462
|
path: '${module.path}',
|
|
451
463
|
id: '${module.id}',
|
|
464
|
+
appStyleScopeId: ${JSON.stringify(module.appStyleScopeId || null)},
|
|
465
|
+
sharedStyleScopeIds: ${JSON.stringify(module.sharedStyleScopeIds || [])},
|
|
466
|
+
styleIsolation: ${JSON.stringify(module.styleIsolation || "isolated")},
|
|
452
467
|
render: ${transCode},
|
|
453
468
|
usingComponents: ${JSON.stringify(module.usingComponents)},
|
|
469
|
+
customTabBar: ${JSON.stringify(module.customTabBar || null)},
|
|
454
470
|
tplComponents: ${tplComponents},
|
|
455
471
|
});`;
|
|
456
472
|
const allWxsModules = collectAllWxsModules(scriptRes, /* @__PURE__ */ new Set(), compileInstruction.scriptModule || []);
|
|
@@ -523,7 +539,7 @@ function processWxsContent(wxsContent, wxsFilePath, scriptModule, workPath, file
|
|
|
523
539
|
if (filePath && filePath.includes("/miniprogram_npm/")) {
|
|
524
540
|
const currentWxsDir = path.dirname(wxsFilePath);
|
|
525
541
|
resolvedWxsPath = path.resolve(currentWxsDir, requirePath);
|
|
526
|
-
const moduleName = resolvedWxsPath.replace(workPath, "")
|
|
542
|
+
const moduleName = stripViewScriptExt(resolvedWxsPath.replace(workPath, "")).replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
|
|
527
543
|
processWxsDependency(resolvedWxsPath, moduleName, scriptModule, workPath, filePath);
|
|
528
544
|
replacements.push({
|
|
529
545
|
start: node.arguments[0].start,
|
|
@@ -533,7 +549,7 @@ function processWxsContent(wxsContent, wxsFilePath, scriptModule, workPath, file
|
|
|
533
549
|
} else {
|
|
534
550
|
const currentWxsDir = path.dirname(wxsFilePath);
|
|
535
551
|
resolvedWxsPath = path.resolve(currentWxsDir, requirePath);
|
|
536
|
-
const depModuleName = resolvedWxsPath.replace(workPath, "")
|
|
552
|
+
const depModuleName = stripViewScriptExt(resolvedWxsPath.replace(workPath, "")).replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
|
|
537
553
|
processWxsDependency(resolvedWxsPath, depModuleName, scriptModule, workPath, filePath);
|
|
538
554
|
replacements.push({
|
|
539
555
|
start: node.arguments[0].start,
|
|
@@ -601,14 +617,7 @@ function compileModuleWithAllWxs(module, scriptRes, allScriptModules) {
|
|
|
601
617
|
filename: module.path,
|
|
602
618
|
id: `data-v-${module.id}`,
|
|
603
619
|
scoped: true,
|
|
604
|
-
compilerOptions: {
|
|
605
|
-
prefixIdentifiers: true,
|
|
606
|
-
hoistStatic: false,
|
|
607
|
-
cacheHandlers: true,
|
|
608
|
-
scopeId: `data-v-${module.id}`,
|
|
609
|
-
mode: "function",
|
|
610
|
-
inline: true
|
|
611
|
-
}
|
|
620
|
+
compilerOptions: getTemplateCompilerOptions(`data-v-${module.id}`)
|
|
612
621
|
});
|
|
613
622
|
let tplComponents = "{";
|
|
614
623
|
for (const tm of mergedInstruction.templateModule) {
|
|
@@ -617,14 +626,7 @@ function compileModuleWithAllWxs(module, scriptRes, allScriptModules) {
|
|
|
617
626
|
filename: tm.path,
|
|
618
627
|
id: `data-v-${module.id}`,
|
|
619
628
|
scoped: true,
|
|
620
|
-
compilerOptions: {
|
|
621
|
-
prefixIdentifiers: true,
|
|
622
|
-
hoistStatic: false,
|
|
623
|
-
cacheHandlers: true,
|
|
624
|
-
scopeId: `data-v-${module.id}`,
|
|
625
|
-
mode: "function",
|
|
626
|
-
inline: true
|
|
627
|
-
}
|
|
629
|
+
compilerOptions: getTemplateCompilerOptions(`data-v-${module.id}`)
|
|
628
630
|
});
|
|
629
631
|
code = insertWxsToRenderCode(code, allScriptModules, scriptRes, tm.path);
|
|
630
632
|
tplComponents += `'${tm.path}':${code},`;
|
|
@@ -634,8 +636,12 @@ function compileModuleWithAllWxs(module, scriptRes, allScriptModules) {
|
|
|
634
636
|
const code = `Module({
|
|
635
637
|
path: '${module.path}',
|
|
636
638
|
id: '${module.id}',
|
|
639
|
+
appStyleScopeId: ${JSON.stringify(module.appStyleScopeId || null)},
|
|
640
|
+
sharedStyleScopeIds: ${JSON.stringify(module.sharedStyleScopeIds || [])},
|
|
641
|
+
styleIsolation: ${JSON.stringify(module.styleIsolation || "isolated")},
|
|
637
642
|
render: ${transCode},
|
|
638
643
|
usingComponents: ${JSON.stringify(module.usingComponents)},
|
|
644
|
+
customTabBar: ${JSON.stringify(module.customTabBar || null)},
|
|
639
645
|
tplComponents: ${tplComponents},
|
|
640
646
|
});`;
|
|
641
647
|
const cacheData = {
|
|
@@ -717,12 +723,13 @@ function toCompileTemplate(isComponent, path, components, componentPlaceholder,
|
|
|
717
723
|
const workPath = getWorkPath();
|
|
718
724
|
const fullPath = getViewPath(workPath, path);
|
|
719
725
|
if (!fullPath) return { tpl: void 0 };
|
|
726
|
+
const sourcePath = toMiniProgramModuleId(fullPath, workPath).replace(buildExtStripRegex(getTemplateExts()), "");
|
|
720
727
|
const diagnosticSource = fullPath.startsWith(workPath) ? fullPath.slice(workPath.length) : path;
|
|
721
728
|
let content = getContentByPath(fullPath).trim();
|
|
722
729
|
if (!content) content = "<block></block>";
|
|
723
730
|
else {
|
|
724
731
|
checkTemplateCompatibility(content, diagnosticSource, components);
|
|
725
|
-
if (isComponent) content = `<
|
|
732
|
+
if (isComponent) content = `<component-host name="${path}">${content}</component-host>`;
|
|
726
733
|
else if (cheerio.load(content, {
|
|
727
734
|
xmlMode: true,
|
|
728
735
|
decodeEntities: false
|
|
@@ -740,8 +747,8 @@ function toCompileTemplate(isComponent, path, components, componentPlaceholder,
|
|
|
740
747
|
$("include").each((_, elem) => {
|
|
741
748
|
const src = $(elem).attr("src");
|
|
742
749
|
if (src) {
|
|
743
|
-
const includeFullPath =
|
|
744
|
-
let includePath = includeFullPath.replace(workPath, "").replace(
|
|
750
|
+
const includeFullPath = resolveTemplateDependencyPath(workPath, sourcePath, src);
|
|
751
|
+
let includePath = includeFullPath.replace(workPath, "").replace(buildExtStripRegex(getTemplateExts()), "");
|
|
745
752
|
const includeDiagnosticSource = includeFullPath.startsWith(workPath) ? includeFullPath.slice(workPath.length) : includePath;
|
|
746
753
|
if (!includePath.startsWith("/")) includePath = "/" + includePath;
|
|
747
754
|
const includeContent = getContentByPath(includeFullPath).trim();
|
|
@@ -755,21 +762,20 @@ function toCompileTemplate(isComponent, path, components, componentPlaceholder,
|
|
|
755
762
|
transTagWxs($includeContent, scriptModule, includePath);
|
|
756
763
|
processIncludedFileWxsDependencies(includeContent, includePath, scriptModule, components, processedPaths);
|
|
757
764
|
$includeContent("template").remove();
|
|
758
|
-
$includeContent("
|
|
759
|
-
$includeContent("dds").remove();
|
|
765
|
+
$includeContent(getViewScriptTags().join(",")).remove();
|
|
760
766
|
const processedContent = processIncludeConditionalAttrs($, elem, $includeContent.html());
|
|
761
767
|
$(elem).replaceWith(processedContent);
|
|
762
768
|
} else $(elem).remove();
|
|
763
769
|
} else $(elem).remove();
|
|
764
770
|
});
|
|
765
|
-
transTagTemplate($, templateModule,
|
|
766
|
-
transTagWxs($, scriptModule,
|
|
771
|
+
transTagTemplate($, templateModule, sourcePath, components, componentPlaceholder);
|
|
772
|
+
transTagWxs($, scriptModule, sourcePath);
|
|
767
773
|
const importNodes = $("import");
|
|
768
774
|
importNodes.each((_, elem) => {
|
|
769
775
|
const src = $(elem).attr("src");
|
|
770
776
|
if (src) {
|
|
771
|
-
const importFullPath =
|
|
772
|
-
let importPath = importFullPath.replace(workPath, "").replace(
|
|
777
|
+
const importFullPath = resolveTemplateDependencyPath(workPath, sourcePath, src);
|
|
778
|
+
let importPath = importFullPath.replace(workPath, "").replace(buildExtStripRegex(getTemplateExts()), "");
|
|
773
779
|
const importDiagnosticSource = importFullPath.startsWith(workPath) ? importFullPath.slice(workPath.length) : importPath;
|
|
774
780
|
if (!importPath.startsWith("/")) importPath = "/" + importPath;
|
|
775
781
|
const importContent = getContentByPath(importFullPath).trim();
|
|
@@ -779,14 +785,14 @@ function toCompileTemplate(isComponent, path, components, componentPlaceholder,
|
|
|
779
785
|
xmlMode: true,
|
|
780
786
|
decodeEntities: false
|
|
781
787
|
});
|
|
782
|
-
transTagTemplate($$, templateModule,
|
|
788
|
+
transTagTemplate($$, templateModule, importPath, components, componentPlaceholder);
|
|
783
789
|
transTagWxs($$, scriptModule, importPath);
|
|
784
790
|
processIncludedFileWxsDependencies(importContent, importPath, scriptModule, components, processedPaths);
|
|
785
791
|
}
|
|
786
792
|
}
|
|
787
793
|
});
|
|
788
794
|
importNodes.remove();
|
|
789
|
-
transAsses($, $("image"),
|
|
795
|
+
transAsses($, $("image"), sourcePath);
|
|
790
796
|
const res = [];
|
|
791
797
|
transHtmlTag($.html(), res, components, componentPlaceholder);
|
|
792
798
|
return {
|
|
@@ -804,8 +810,7 @@ function transTagTemplate($, templateModule, path, components, componentPlacehol
|
|
|
804
810
|
const templateContent = $(elem);
|
|
805
811
|
templateContent.find("import").remove();
|
|
806
812
|
templateContent.find("include").remove();
|
|
807
|
-
templateContent.find("
|
|
808
|
-
templateContent.find("dds").remove();
|
|
813
|
+
templateContent.find(getViewScriptTags().join(",")).remove();
|
|
809
814
|
transAsses($, templateContent.find("image"), path);
|
|
810
815
|
const res = [];
|
|
811
816
|
transHtmlTag(templateContent.html(), res, components, componentPlaceholder);
|
|
@@ -822,6 +827,72 @@ function transAsses($, imageNodes, path) {
|
|
|
822
827
|
if (!imgSrc.startsWith("{{")) $(elem).attr("src", collectAssets(getWorkPath(), path, imgSrc, getTargetPath(), getAppId()));
|
|
823
828
|
});
|
|
824
829
|
}
|
|
830
|
+
var DIMINA_SLOT_GROUP_TAG = "dimina-slot-group";
|
|
831
|
+
var DIMINA_FOR_SCOPE_TAG = "dimina-for-scope";
|
|
832
|
+
function getDirectiveAttributeNames(attrs, suffixes) {
|
|
833
|
+
return Object.keys(attrs || {}).filter((name) => suffixes.some((suffix) => name.endsWith(suffix)));
|
|
834
|
+
}
|
|
835
|
+
function hasForAndIf(attrs) {
|
|
836
|
+
return getDirectiveAttributeNames(attrs, [":for", ":for-items"]).length > 0 && getDirectiveAttributeNames(attrs, [":if"]).length > 0;
|
|
837
|
+
}
|
|
838
|
+
function groupDuplicateNamedSlots($, components) {
|
|
839
|
+
const slotHosts = $("*").toArray().filter((element) => {
|
|
840
|
+
const tag = element.tagName;
|
|
841
|
+
return tag === "component" || Boolean(components?.[tag]);
|
|
842
|
+
});
|
|
843
|
+
for (const host of slotHosts) {
|
|
844
|
+
const groups = /* @__PURE__ */ new Map();
|
|
845
|
+
for (const child of $(host).children().toArray()) {
|
|
846
|
+
const slotName = child.attribs?.slot;
|
|
847
|
+
if (!slotName) continue;
|
|
848
|
+
const group = groups.get(slotName) || [];
|
|
849
|
+
group.push(child);
|
|
850
|
+
groups.set(slotName, group);
|
|
851
|
+
}
|
|
852
|
+
for (const [slotName, nodes] of groups) {
|
|
853
|
+
if (nodes.length === 1 && !hasForAndIf(nodes[0].attribs)) continue;
|
|
854
|
+
const wrapper = $(`<${DIMINA_SLOT_GROUP_TAG}></${DIMINA_SLOT_GROUP_TAG}>`);
|
|
855
|
+
wrapper.attr("name", slotName);
|
|
856
|
+
$(nodes[0]).before(wrapper);
|
|
857
|
+
for (const node of nodes) {
|
|
858
|
+
$(node).removeAttr("slot");
|
|
859
|
+
wrapper.append(node);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
function wrapForIfScopes($) {
|
|
865
|
+
const nodes = $("*").toArray();
|
|
866
|
+
for (const node of nodes) {
|
|
867
|
+
if (node.tagName === DIMINA_FOR_SCOPE_TAG || !hasForAndIf(node.attribs)) continue;
|
|
868
|
+
const attrsToMove = getDirectiveAttributeNames(node.attribs, [
|
|
869
|
+
":for",
|
|
870
|
+
":for-items",
|
|
871
|
+
":for-item",
|
|
872
|
+
":for-index",
|
|
873
|
+
":key"
|
|
874
|
+
]);
|
|
875
|
+
const wrapper = $(`<${DIMINA_FOR_SCOPE_TAG}></${DIMINA_FOR_SCOPE_TAG}>`);
|
|
876
|
+
for (const name of attrsToMove) {
|
|
877
|
+
wrapper.attr(name, node.attribs[name]);
|
|
878
|
+
$(node).removeAttr(name);
|
|
879
|
+
}
|
|
880
|
+
$(node).before(wrapper);
|
|
881
|
+
wrapper.append(node);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
function normalizeTemplateSyntax(html, components) {
|
|
885
|
+
const $ = cheerio.load(html, {
|
|
886
|
+
xmlMode: true,
|
|
887
|
+
decodeEntities: false,
|
|
888
|
+
_useHtmlParser2: true,
|
|
889
|
+
lowerCaseTags: false,
|
|
890
|
+
lowerCaseAttributeNames: false
|
|
891
|
+
});
|
|
892
|
+
groupDuplicateNamedSlots($, components);
|
|
893
|
+
wrapForIfScopes($);
|
|
894
|
+
return $.html();
|
|
895
|
+
}
|
|
825
896
|
function transHtmlTag(html, res, components, componentPlaceholder) {
|
|
826
897
|
const attrsList = [];
|
|
827
898
|
const parser = new htmlparser2.Parser({
|
|
@@ -849,7 +920,7 @@ function transHtmlTag(html, res, components, componentPlaceholder) {
|
|
|
849
920
|
console.error(error);
|
|
850
921
|
}
|
|
851
922
|
}, { xmlMode: true });
|
|
852
|
-
parser.write(html);
|
|
923
|
+
parser.write(normalizeTemplateSyntax(html, components));
|
|
853
924
|
parser.end();
|
|
854
925
|
}
|
|
855
926
|
/**
|
|
@@ -859,11 +930,15 @@ function transHtmlTag(html, res, components, componentPlaceholder) {
|
|
|
859
930
|
function transTag(opts) {
|
|
860
931
|
const { isStart, tag, attrs, components } = opts;
|
|
861
932
|
let res;
|
|
862
|
-
if (tag ===
|
|
933
|
+
if (tag === DIMINA_SLOT_GROUP_TAG) {
|
|
934
|
+
if (isStart) return `<template ${generateSlotDirective(attrs.name)}>`;
|
|
935
|
+
return "</template>";
|
|
936
|
+
} else if (tag === DIMINA_FOR_SCOPE_TAG) res = "template";
|
|
937
|
+
else if (tag === "slot") res = tag;
|
|
863
938
|
else if (components && components[tag]) res = `dd-${tag}`;
|
|
864
939
|
else if (tag === "component" || tag === "canvas") res = tag;
|
|
865
|
-
else if (
|
|
866
|
-
else res =
|
|
940
|
+
else if (tagWhiteList.includes(tag)) res = `dd-${tag}`;
|
|
941
|
+
else res = tag;
|
|
867
942
|
let tagRes;
|
|
868
943
|
const propsAry = isStart ? getProps(attrs, tag, components) : [];
|
|
869
944
|
const multipleSlots = attrs?.slot;
|
|
@@ -908,7 +983,17 @@ function generateSlotDirective(slotValue) {
|
|
|
908
983
|
*/
|
|
909
984
|
function getProps(attrs, tag, components) {
|
|
910
985
|
const attrsList = [];
|
|
986
|
+
const isCustomComponent = Boolean(components && components[tag]);
|
|
911
987
|
const propBindings = {};
|
|
988
|
+
const hasEventBindings = Object.keys(attrs).some((name) => /^(?:capture-)?(?:bind|catch)(?::)?.+/.test(name));
|
|
989
|
+
if (tag === "page-meta") attrsList.push({
|
|
990
|
+
name: "dimina-rpx-unit",
|
|
991
|
+
value: "vw"
|
|
992
|
+
});
|
|
993
|
+
if (hasEventBindings) attrsList.push({
|
|
994
|
+
name: "v-c-event-node",
|
|
995
|
+
value: components && components[tag] ? "'component'" : "'node'"
|
|
996
|
+
});
|
|
912
997
|
Object.entries(attrs).forEach(([name, value]) => {
|
|
913
998
|
if (name.endsWith(":if")) attrsList.push({
|
|
914
999
|
name: "v-if",
|
|
@@ -932,11 +1017,20 @@ function getProps(attrs, tag, components) {
|
|
|
932
1017
|
name: ":key",
|
|
933
1018
|
value: tranValue
|
|
934
1019
|
});
|
|
935
|
-
} else if (name === "style")
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1020
|
+
} else if (name === "style") {
|
|
1021
|
+
const parsedStyle = parseSafeBraceExp(value);
|
|
1022
|
+
attrsList.push({
|
|
1023
|
+
name: "v-c-style",
|
|
1024
|
+
value: transformRpx(parsedStyle)
|
|
1025
|
+
});
|
|
1026
|
+
if (isCustomComponent) {
|
|
1027
|
+
attrsList.push({
|
|
1028
|
+
name: ":dimina-wxml-style",
|
|
1029
|
+
value: parsedStyle
|
|
1030
|
+
});
|
|
1031
|
+
if (isWrappedByBraces(value) && parsedStyle) propBindings.style = parsedStyle;
|
|
1032
|
+
}
|
|
1033
|
+
} else if (name === "class") {
|
|
940
1034
|
if (isWrappedByBraces(value)) attrsList.push({
|
|
941
1035
|
name: ":class",
|
|
942
1036
|
value: parseClassRules(value)
|
|
@@ -988,7 +1082,7 @@ function getProps(attrs, tag, components) {
|
|
|
988
1082
|
});
|
|
989
1083
|
else if (isWrappedByBraces(value)) {
|
|
990
1084
|
const pVal = tag === "template" && name === "data" ? parseTemplateDataExp(value) : parseSafeBraceExp(value);
|
|
991
|
-
if (
|
|
1085
|
+
if (isCustomComponent) {
|
|
992
1086
|
if (pVal && typeof pVal === "string") propBindings[name] = pVal;
|
|
993
1087
|
}
|
|
994
1088
|
attrsList.push({
|
|
@@ -1007,7 +1101,7 @@ function getProps(attrs, tag, components) {
|
|
|
1007
1101
|
else if (/\$\{[^}]*\}/.test(value)) propsRes.push(`:${name}="\`${value}\`"`);
|
|
1008
1102
|
else propsRes.push(`${name}="${escapeQuotes(value)}"`);
|
|
1009
1103
|
});
|
|
1010
|
-
if (
|
|
1104
|
+
if (isCustomComponent && Object.keys(propBindings).length > 0) try {
|
|
1011
1105
|
const validBindings = {};
|
|
1012
1106
|
for (const [key, value] of Object.entries(propBindings)) if (value !== void 0 && value !== null && typeof value === "string") validBindings[key] = value;
|
|
1013
1107
|
if (Object.keys(validBindings).length > 0) {
|
|
@@ -1071,7 +1165,7 @@ function parseKeyExpression(exp, itemName = "item", indexName = "index") {
|
|
|
1071
1165
|
*/
|
|
1072
1166
|
function getViewPath(workPath, src) {
|
|
1073
1167
|
const aSrc = src.startsWith("/") ? src : `/${src}`;
|
|
1074
|
-
for (const mlType of
|
|
1168
|
+
for (const mlType of getTemplateExts()) {
|
|
1075
1169
|
const mlFullPath = `${workPath}${aSrc}${mlType}`;
|
|
1076
1170
|
if (fs.existsSync(mlFullPath)) return mlFullPath;
|
|
1077
1171
|
const indexMlFullPath = `${workPath}${aSrc}/index${mlType}`;
|
|
@@ -1079,6 +1173,20 @@ function getViewPath(workPath, src) {
|
|
|
1079
1173
|
}
|
|
1080
1174
|
}
|
|
1081
1175
|
/**
|
|
1176
|
+
* 解析 import/include 的模板文件路径。
|
|
1177
|
+
* 微信允许省略 .wxml;显式扩展名保持原样,无扩展名时按当前模板类型优先级补全。
|
|
1178
|
+
*/
|
|
1179
|
+
function resolveTemplateDependencyPath(workPath, ownerPath, src) {
|
|
1180
|
+
const resolvedPath = getAbsolutePath(workPath, ownerPath, src);
|
|
1181
|
+
if (fs.existsSync(resolvedPath) && fs.statSync(resolvedPath).isFile()) return resolvedPath;
|
|
1182
|
+
if (path.extname(resolvedPath)) return resolvedPath;
|
|
1183
|
+
for (const ext of getTemplateExts()) {
|
|
1184
|
+
const candidate = `${resolvedPath}${ext}`;
|
|
1185
|
+
if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) return candidate;
|
|
1186
|
+
}
|
|
1187
|
+
return resolvedPath;
|
|
1188
|
+
}
|
|
1189
|
+
/**
|
|
1082
1190
|
* 将字符串内部的双引号进行替换
|
|
1083
1191
|
* @param {*} input
|
|
1084
1192
|
*/
|
|
@@ -1119,7 +1227,7 @@ function splitWithBraces(str) {
|
|
|
1119
1227
|
function parseClassRules(cssRule) {
|
|
1120
1228
|
let list = splitWithBraces(cssRule);
|
|
1121
1229
|
list = list.map((item) => {
|
|
1122
|
-
return
|
|
1230
|
+
return parseSafeBraceExp(item);
|
|
1123
1231
|
});
|
|
1124
1232
|
if (list.length === 1) return list.pop();
|
|
1125
1233
|
return `[${list.join(",")}]`;
|
|
@@ -1147,11 +1255,16 @@ function getForIndexName(attrs) {
|
|
|
1147
1255
|
* @param {*} attrs
|
|
1148
1256
|
*/
|
|
1149
1257
|
function parseForExp(exp, attrs) {
|
|
1150
|
-
return `(${getForItemName(attrs)}, ${getForIndexName(attrs)}) in ${
|
|
1258
|
+
return `(${getForItemName(attrs)}, ${getForIndexName(attrs)}) in ${parseSafeBraceExp(exp)}`;
|
|
1151
1259
|
}
|
|
1152
1260
|
var braceRegex = /(\{\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\}\})|([^{}]+)/g;
|
|
1153
1261
|
var noBraceRegex = /\{\{((?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*)\}\}/;
|
|
1154
1262
|
var ternaryRegex = /[^?]+\?.+:.+/;
|
|
1263
|
+
var RESERVED_TEMPLATE_CONTEXT_ALIASES = /* @__PURE__ */ new Map([["class", "__dimina_reserved_class"]]);
|
|
1264
|
+
var RESERVED_TEMPLATE_CONTEXT_NAMES = new Map([...RESERVED_TEMPLATE_CONTEXT_ALIASES].map(([name, alias]) => [alias, name]));
|
|
1265
|
+
function encodeReservedTemplateContextIdentifier(expression) {
|
|
1266
|
+
return RESERVED_TEMPLATE_CONTEXT_ALIASES.get(expression) || expression;
|
|
1267
|
+
}
|
|
1155
1268
|
/**
|
|
1156
1269
|
* 解析 {{}} 表达式的值
|
|
1157
1270
|
* @param {*} exp
|
|
@@ -1163,7 +1276,7 @@ function parseBraceExp(exp) {
|
|
|
1163
1276
|
if (result[1]) {
|
|
1164
1277
|
const matchResult = result[1].match(noBraceRegex);
|
|
1165
1278
|
if (matchResult) {
|
|
1166
|
-
const statement = matchResult[1].trim();
|
|
1279
|
+
const statement = encodeReservedTemplateContextIdentifier(matchResult[1].trim());
|
|
1167
1280
|
if (ternaryRegex.test(statement)) group.push(`(${statement})`);
|
|
1168
1281
|
else group.push(statement);
|
|
1169
1282
|
}
|
|
@@ -1179,12 +1292,11 @@ function parseBraceExp(exp) {
|
|
|
1179
1292
|
*/
|
|
1180
1293
|
function parseTemplateDataExp(exp) {
|
|
1181
1294
|
const matchResult = exp.trim().match(/^\{\{([\s\S]*)\}\}$/);
|
|
1182
|
-
if (matchResult) return `{${matchResult[1].trim()}}
|
|
1183
|
-
return `{${
|
|
1295
|
+
if (matchResult) return addOptionalChaining(`{${matchResult[1].trim()}}`);
|
|
1296
|
+
return `{${parseSafeBraceExp(exp)}}`;
|
|
1184
1297
|
}
|
|
1185
1298
|
function transTagWxs($, scriptModule, filePath) {
|
|
1186
|
-
|
|
1187
|
-
if (wxsNodes.length === 0) wxsNodes = $("dds");
|
|
1299
|
+
const wxsNodes = $(getViewScriptTags().join(","));
|
|
1188
1300
|
wxsNodes.each((_, elem) => {
|
|
1189
1301
|
const smName = $(elem).attr("module");
|
|
1190
1302
|
if (smName) {
|
|
@@ -1200,7 +1312,7 @@ function transTagWxs($, scriptModule, filePath) {
|
|
|
1200
1312
|
wxsFilePath = path.resolve(componentFullPath, src);
|
|
1201
1313
|
} else wxsFilePath = getAbsolutePath(workPath, filePath, src);
|
|
1202
1314
|
if (wxsFilePath) {
|
|
1203
|
-
uniqueModuleName = wxsFilePath.replace(workPath, "")
|
|
1315
|
+
uniqueModuleName = stripViewScriptExt(wxsFilePath.replace(workPath, "")).replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
|
|
1204
1316
|
cacheKey = wxsFilePath;
|
|
1205
1317
|
}
|
|
1206
1318
|
}
|
|
@@ -1248,7 +1360,7 @@ function collectAllWxsModules(scriptRes, collectedPaths = /* @__PURE__ */ new Se
|
|
|
1248
1360
|
});
|
|
1249
1361
|
const dependencies = extractWxsDependencies(moduleCode);
|
|
1250
1362
|
for (const depPath of dependencies) if (!collectedPaths.has(depPath)) if (scriptRes.has(depPath)) {
|
|
1251
|
-
const depModules = collectAllWxsModules(new Map([[depPath, scriptRes.get(depPath)]]), collectedPaths, scriptModule);
|
|
1363
|
+
const depModules = collectAllWxsModules(/* @__PURE__ */ new Map([[depPath, scriptRes.get(depPath)]]), collectedPaths, scriptModule);
|
|
1252
1364
|
allWxsModules.push(...depModules);
|
|
1253
1365
|
} else {
|
|
1254
1366
|
const loaded = loadWxsModule(depPath, workPath, scriptModule);
|
|
@@ -1256,7 +1368,7 @@ function collectAllWxsModules(scriptRes, collectedPaths = /* @__PURE__ */ new Se
|
|
|
1256
1368
|
scriptRes.set(depPath, loaded.code);
|
|
1257
1369
|
allWxsModules.push(loaded);
|
|
1258
1370
|
collectedPaths.add(depPath);
|
|
1259
|
-
const depModules = collectAllWxsModules(new Map([[depPath, loaded.code]]), collectedPaths, scriptModule);
|
|
1371
|
+
const depModules = collectAllWxsModules(/* @__PURE__ */ new Map([[depPath, loaded.code]]), collectedPaths, scriptModule);
|
|
1260
1372
|
allWxsModules.push(...depModules);
|
|
1261
1373
|
}
|
|
1262
1374
|
}
|
|
@@ -1272,12 +1384,8 @@ function collectAllWxsModules(scriptRes, collectedPaths = /* @__PURE__ */ new Se
|
|
|
1272
1384
|
* @returns {Object|null} 加载的模块对象或 null
|
|
1273
1385
|
*/
|
|
1274
1386
|
function loadWxsModule(modulePath, workPath, scriptModule) {
|
|
1275
|
-
if (!modulePath.startsWith("miniprogram_npm__") || !modulePath.includes("_wxs_")) return null;
|
|
1276
1387
|
const wxsFilePath = wxsFilePathMap.get(modulePath);
|
|
1277
|
-
if (!wxsFilePath)
|
|
1278
|
-
console.warn(`[view] 无法找到 wxs 模块文件: ${modulePath}`);
|
|
1279
|
-
return null;
|
|
1280
|
-
}
|
|
1388
|
+
if (!wxsFilePath) return null;
|
|
1281
1389
|
try {
|
|
1282
1390
|
const wxsContent = getContentByPath(wxsFilePath).trim();
|
|
1283
1391
|
if (!wxsContent) return null;
|
|
@@ -1325,8 +1433,7 @@ function insertWxsToRenderCode(code, scriptModule, scriptRes, filename = "render
|
|
|
1325
1433
|
});
|
|
1326
1434
|
declarations.push(`const ${localIdentifier} = require(${JSON.stringify(requireModuleName)});`);
|
|
1327
1435
|
}
|
|
1328
|
-
if (wxsBindings.length
|
|
1329
|
-
if (renderBody?.type === "BlockStatement") codeReplacements.push({
|
|
1436
|
+
if (wxsBindings.length > 0 && renderBody?.type === "BlockStatement") codeReplacements.push({
|
|
1330
1437
|
type: "insert",
|
|
1331
1438
|
start: renderBody.start + 1,
|
|
1332
1439
|
end: renderBody.start + 1,
|
|
@@ -1334,6 +1441,15 @@ function insertWxsToRenderCode(code, scriptModule, scriptRes, filename = "render
|
|
|
1334
1441
|
});
|
|
1335
1442
|
walk(ast, { enter(node) {
|
|
1336
1443
|
if (node.type === "MemberExpression" && node.object?.type === "Identifier" && node.object.name === "_ctx" && !node.computed && node.property?.type === "Identifier") {
|
|
1444
|
+
const reservedName = RESERVED_TEMPLATE_CONTEXT_NAMES.get(node.property.name);
|
|
1445
|
+
if (reservedName) {
|
|
1446
|
+
codeReplacements.push({
|
|
1447
|
+
start: node.property.start,
|
|
1448
|
+
end: node.property.end,
|
|
1449
|
+
value: reservedName
|
|
1450
|
+
});
|
|
1451
|
+
return;
|
|
1452
|
+
}
|
|
1337
1453
|
const replacement = wxsBindings.find((item) => item.templatePropertyName === node.property.name);
|
|
1338
1454
|
if (replacement) codeReplacements.push({
|
|
1339
1455
|
start: node.start,
|
|
@@ -1342,8 +1458,9 @@ function insertWxsToRenderCode(code, scriptModule, scriptRes, filename = "render
|
|
|
1342
1458
|
});
|
|
1343
1459
|
}
|
|
1344
1460
|
} });
|
|
1461
|
+
if (codeReplacements.length === 0) return getProgramCode(code, ast);
|
|
1345
1462
|
const transformed = applyCodeReplacements(code, codeReplacements);
|
|
1346
1463
|
return getProgramCode(transformed, parseJs(transformed, filename));
|
|
1347
1464
|
}
|
|
1348
1465
|
//#endregion
|
|
1349
|
-
export { compileML, generateSlotDirective, generateVModelTemplate, parseBraceExp, parseClassRules, parseKeyExpression, parseTemplateDataExp, processIncludeConditionalAttrs, processWxsContent, splitWithBraces };
|
|
1466
|
+
export { compileML, generateSlotDirective, generateVModelTemplate, initWxsFilePathMap, loadWxsModule, normalizeTemplateSyntax, parseBraceExp, parseClassRules, parseKeyExpression, parseTemplateDataExp, processIncludeConditionalAttrs, processWxsContent, splitWithBraces };
|