pug-site-core 3.0.0 → 3.0.2
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/lib/ai/aiPanel.js +0 -722
- package/lib/ai/aiRouter.js +586 -258
- package/lib/generate.js +417 -342
- package/lib/utils.js +1 -7
- package/package.json +2 -2
package/lib/generate.js
CHANGED
|
@@ -56,7 +56,11 @@ export async function compilePagesPugToFn(pugPath) {
|
|
|
56
56
|
10, // 限制并发数为10
|
|
57
57
|
async (fileName) => {
|
|
58
58
|
const filePath = paths.resolveRoot(paths.template.pages, fileName);
|
|
59
|
-
const funName = fileName
|
|
59
|
+
const funName = fileName
|
|
60
|
+
.split(pathSymbol)
|
|
61
|
+
.join("_")
|
|
62
|
+
.slice(0, -4)
|
|
63
|
+
.replace(/[-]/g, "_");
|
|
60
64
|
|
|
61
65
|
// 读取并编译pug文件
|
|
62
66
|
const pugValue = await fse.readFile(filePath, "utf8");
|
|
@@ -146,7 +150,9 @@ export async function generateGetDataFn() {
|
|
|
146
150
|
// 为每个页面注入数据获取函数
|
|
147
151
|
await async.each(pagesPugFilePathArr, async (fileName) => {
|
|
148
152
|
const funName =
|
|
149
|
-
"get_" +
|
|
153
|
+
"get_" +
|
|
154
|
+
fileName.split(pathSymbol).join("_").slice(0, -4).replace(/[-]/g, "_") +
|
|
155
|
+
"_data";
|
|
150
156
|
|
|
151
157
|
// 使用正则表达式检查特定的数据获取函数是否存在
|
|
152
158
|
const dataFnRegex = new RegExp(
|
|
@@ -246,7 +252,7 @@ export async function fetchDataToJsonFile(args) {
|
|
|
246
252
|
// 创建一个全局任务队列控制整体并发数
|
|
247
253
|
const queue = async.queue(async (task) => {
|
|
248
254
|
await task();
|
|
249
|
-
}, fetchDataConcurrencyLimit ||
|
|
255
|
+
}, fetchDataConcurrencyLimit || 3);
|
|
250
256
|
|
|
251
257
|
// 收集所有需要执行的任务
|
|
252
258
|
const allTasks = [];
|
|
@@ -334,7 +340,9 @@ export async function fetchDataToJsonFile(args) {
|
|
|
334
340
|
// 处理模板页面数据
|
|
335
341
|
for (const fileName of pugFilePathList) {
|
|
336
342
|
let funName =
|
|
337
|
-
"get_" +
|
|
343
|
+
"get_" +
|
|
344
|
+
fileName.split(pathSymbol).join("_").slice(0, -4).replace(/[-]/g, "_") +
|
|
345
|
+
"_data";
|
|
338
346
|
|
|
339
347
|
let jsonFilePath = fileName.slice(0, -4).split(pathSymbol);
|
|
340
348
|
if (!getData[funName] || typeof getData[funName] !== "function") {
|
|
@@ -481,246 +489,285 @@ export async function buildFn() {
|
|
|
481
489
|
console.log("打包完成花费:", (Date.now() - starTime) / 1000, "s");
|
|
482
490
|
}
|
|
483
491
|
|
|
484
|
-
//html文件打包
|
|
492
|
+
//html文件打包
|
|
485
493
|
export async function buildStatic() {
|
|
486
494
|
let jsonDataPath = paths.resolveRoot("jsonData");
|
|
487
495
|
|
|
488
|
-
if (!fse.pathExistsSync(jsonDataPath)) {
|
|
489
|
-
return Promise.reject(
|
|
490
|
-
new Error(jsonDataPath + "目录不存在请先执行npm run getData生成数据!")
|
|
491
|
-
);
|
|
492
|
-
}
|
|
493
496
|
console.log("开始打包...");
|
|
494
497
|
let starTime = Date.now();
|
|
495
498
|
let distOutputPath = paths.resolveRoot(config.staticOutput);
|
|
496
|
-
await fse.remove(distOutputPath);
|
|
497
|
-
await sleep(0);
|
|
498
|
-
await fse.copy(paths.public, distOutputPath);
|
|
499
499
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
500
|
+
/**
|
|
501
|
+
* 构建HTML文件路径
|
|
502
|
+
* @param {string} lang - 语言代码
|
|
503
|
+
* @param {string} outputPath - 输出路径
|
|
504
|
+
* @param {string} fileName - 文件名(可选)
|
|
505
|
+
* @returns {string} 完整的HTML文件路径
|
|
506
|
+
*/
|
|
507
|
+
function buildHtmlPath(lang, outputPath, fileName = null) {
|
|
508
|
+
let htmlPath
|
|
509
|
+
try {
|
|
510
|
+
if (fileName) {
|
|
511
|
+
htmlPath = paths.resolveRoot(
|
|
512
|
+
distOutputPath,
|
|
513
|
+
lang,
|
|
514
|
+
outputPath.replace(
|
|
515
|
+
outputPath.split("/").pop().replace(/\..*$/, ""),
|
|
516
|
+
fileName.replace(/\..*$/, "")
|
|
517
|
+
)
|
|
518
|
+
);
|
|
519
|
+
} else {
|
|
520
|
+
htmlPath = paths.resolveRoot(distOutputPath, lang, outputPath);
|
|
521
|
+
}
|
|
522
|
+
console.log(htmlPath);
|
|
523
|
+
return htmlPath;
|
|
524
|
+
} catch (error) {
|
|
525
|
+
throw new Error(`构建HTML路径失败 [lang: ${lang}, outputPath: ${outputPath}, fileName: ${fileName}]: ${error.message}`);
|
|
516
526
|
}
|
|
517
|
-
|
|
527
|
+
}
|
|
518
528
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
529
|
+
/**
|
|
530
|
+
* 生成HTML内容
|
|
531
|
+
*/
|
|
532
|
+
function generateHtml(pagesPugToFn, funName, data, pagePath, commonData) {
|
|
533
|
+
try {
|
|
534
|
+
if (!pagesPugToFn[funName]) {
|
|
535
|
+
throw new Error(`模板函数 ${funName} 不存在`);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return pagesPugToFn[funName]({
|
|
539
|
+
data,
|
|
540
|
+
_pagePath: pagePath,
|
|
541
|
+
common: commonData,
|
|
542
|
+
});
|
|
543
|
+
} catch (error) {
|
|
544
|
+
throw new Error(`生成HTML失败 [funName: ${funName}, pagePath: ${pagePath}]: ${error.message}`);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
522
547
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
548
|
+
/**
|
|
549
|
+
* 处理数组数据的HTML输出
|
|
550
|
+
*/
|
|
551
|
+
async function processArrayData(pagesPugToFn, data, obj, funName, pagePath, commonData, lang) {
|
|
552
|
+
try {
|
|
553
|
+
const name = obj.outPutHtmlPath.split("/").pop().replace(/\..*$/, "");
|
|
554
|
+
const regex = /^\[.+\]$/;
|
|
555
|
+
|
|
556
|
+
if (regex.test(name)) {
|
|
557
|
+
const property = name.slice(1, -1);
|
|
558
|
+
|
|
559
|
+
await async.eachLimit(data, 64, async (dataItem, index) => {
|
|
560
|
+
try {
|
|
561
|
+
const fileName = dataItem[property];
|
|
562
|
+
if (!fileName) {
|
|
563
|
+
throw new Error(
|
|
564
|
+
`数据项索引 ${index} 中缺少属性 ${property} 或值为空`
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
const htmlPath = buildHtmlPath(lang, obj.outPutHtmlPath, fileName);
|
|
569
|
+
const html = generateHtml(pagesPugToFn, funName, dataItem, pagePath, commonData);
|
|
570
|
+
await fse.outputFile(htmlPath, html);
|
|
571
|
+
} catch (error) {
|
|
572
|
+
throw new Error(`处理数组数据项失败 [index: ${index}, property: ${property}]: ${error.message}`);
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
} else {
|
|
576
|
+
const htmlPath = buildHtmlPath(lang, obj.outPutHtmlPath);
|
|
577
|
+
const html = generateHtml(pagesPugToFn, funName, data, pagePath, commonData);
|
|
578
|
+
await fse.outputFile(htmlPath, html);
|
|
579
|
+
}
|
|
580
|
+
} catch (error) {
|
|
581
|
+
throw new Error(`处理数组数据失败 [lang: ${lang}, getDataFn: ${obj.getDataFn}]: ${error.message}`);
|
|
531
582
|
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* 处理对象数据的HTML输出
|
|
587
|
+
*/
|
|
588
|
+
async function processObjectData(pagesPugToFn, data, obj, funName, pagePath, commonData, lang) {
|
|
589
|
+
try {
|
|
590
|
+
const htmlPath = buildHtmlPath(lang, obj.outPutHtmlPath);
|
|
591
|
+
const html = generateHtml(pagesPugToFn, funName, data, pagePath, commonData);
|
|
592
|
+
await fse.outputFile(htmlPath, html);
|
|
593
|
+
} catch (error) {
|
|
594
|
+
throw new Error(`处理对象数据失败 [lang: ${lang}, getDataFn: ${obj.getDataFn}]: ${error.message}`);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* 处理自定义HTML构建
|
|
600
|
+
*/
|
|
601
|
+
async function processCustomBuildHtml(pagesPugToFn, lang, getData, commonData, dealWithEndFunName) {
|
|
602
|
+
if (!config.customBuildHtml?.length) return;
|
|
603
|
+
|
|
604
|
+
await async.eachLimit(config.customBuildHtml, 3, async (obj) => {
|
|
605
|
+
try {
|
|
606
|
+
// 检查语言过滤
|
|
607
|
+
if (obj.includeLang?.length > 0 && !obj.includeLang.includes(lang)) {
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// 获取数据
|
|
612
|
+
if (!getData[obj.getDataFn] || typeof getData[obj.getDataFn] !== 'function') {
|
|
613
|
+
throw new Error(`数据获取函数 ${obj.getDataFn} 不存在或不是函数`);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const data = await getData[obj.getDataFn](lang);
|
|
617
|
+
|
|
618
|
+
// 处理路径和函数名
|
|
619
|
+
obj.inputPugPath = obj.inputPugPath.replace(/^\//, "");
|
|
620
|
+
const funName = obj.inputPugPath.split("/").join("_").slice(0, -4);
|
|
621
|
+
dealWithEndFunName.set(funName, 1);
|
|
622
|
+
const pagePath = obj.inputPugPath.replaceAll("/", pathSymbol);
|
|
623
|
+
|
|
624
|
+
// 根据数据类型处理
|
|
625
|
+
if (Array.isArray(data)) {
|
|
626
|
+
await processArrayData(pagesPugToFn, data, obj, funName, pagePath, commonData, lang);
|
|
627
|
+
} else if (typeof data === "object" && data !== null) {
|
|
628
|
+
await processObjectData(pagesPugToFn, data, obj, funName, pagePath, commonData, lang);
|
|
629
|
+
} else {
|
|
630
|
+
throw new Error(`数据类型不支持: ${typeof data}`);
|
|
631
|
+
}
|
|
632
|
+
} catch (error) {
|
|
633
|
+
throw new Error(`处理自定义HTML构建失败 [lang: ${lang}, config: ${JSON.stringify(obj)}]: ${error.message}`);
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* 处理页面JSON文件
|
|
640
|
+
*/
|
|
641
|
+
async function processPageJsonFiles(pagesPugToFn, lang, langDataPath, commonData, dealWithEndFunName) {
|
|
642
|
+
try {
|
|
643
|
+
const pagesAllJsonFileName = (
|
|
644
|
+
await fse.readdir(langDataPath, { recursive: true })
|
|
645
|
+
).filter((fileName) => fileName.endsWith(".json"));
|
|
646
|
+
|
|
647
|
+
await async.eachLimit(pagesAllJsonFileName, 64, async (jsonFileName) => {
|
|
648
|
+
try {
|
|
649
|
+
const data = await fse.readJSON(paths.resolveRoot(langDataPath, jsonFileName));
|
|
650
|
+
const pugTemplate = data._template;
|
|
651
|
+
|
|
652
|
+
if (!pugTemplate) {
|
|
550
653
|
return;
|
|
551
654
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
if (
|
|
556
|
-
|
|
655
|
+
|
|
656
|
+
const funName = pugTemplate.split(pathSymbol).join("_").slice(0, -4);
|
|
657
|
+
|
|
658
|
+
if (dealWithEndFunName.has(funName)) {
|
|
659
|
+
return;
|
|
557
660
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
if (Array.isArray(data)) {
|
|
580
|
-
let name = outPutPath.split(pathSymbol).pop().replace(/\..*$/, "");
|
|
581
|
-
const regex = /^\[.+\]$/;
|
|
582
|
-
if (regex.test(name)) {
|
|
583
|
-
let property = name.slice(1, -1);
|
|
584
|
-
for (let index = 0; index < data.length; index++) {
|
|
585
|
-
const dataItem = data[index];
|
|
586
|
-
let fileName = dataItem[property];
|
|
587
|
-
if (
|
|
588
|
-
fileName === null ||
|
|
589
|
-
fileName === undefined ||
|
|
590
|
-
fileName === ""
|
|
591
|
-
) {
|
|
592
|
-
return Promise.reject(
|
|
593
|
-
new Error(
|
|
594
|
-
dataFn +
|
|
595
|
-
"获取的数据中期望以" +
|
|
596
|
-
property +
|
|
597
|
-
`命名但是${index}下标中对象${property}属性为:${fileName}`
|
|
598
|
-
)
|
|
599
|
-
);
|
|
600
|
-
}
|
|
601
|
-
htmlPath = paths.resolveRoot.join(
|
|
602
|
-
distOutputPath,
|
|
603
|
-
lang,
|
|
604
|
-
devicePrefix,
|
|
605
|
-
outPutPath.replace(name, fileName)
|
|
606
|
-
);
|
|
607
|
-
html = pug.compileFile(pugPath, {
|
|
608
|
-
basedir: paths.template.root,
|
|
609
|
-
compileDebug: true,
|
|
610
|
-
filters: getCompilePugFilter(),
|
|
611
|
-
})({
|
|
612
|
-
data: dataItem,
|
|
613
|
-
_pagePath: obj.pugPath,
|
|
614
|
-
common: commonData,
|
|
615
|
-
});
|
|
616
|
-
fse.ensureFileSync(htmlPath);
|
|
617
|
-
await fse.writeFile(htmlPath, html);
|
|
618
|
-
}
|
|
619
|
-
} else {
|
|
620
|
-
htmlPath = paths.resolveRoot(
|
|
621
|
-
paths.template.root,
|
|
622
|
-
lang,
|
|
623
|
-
devicePrefix,
|
|
624
|
-
outPutPath
|
|
625
|
-
);
|
|
626
|
-
html = pug.compileFile(pugPath, {
|
|
627
|
-
basedir: paths.template.root,
|
|
628
|
-
compileDebug: true,
|
|
629
|
-
filters: getCompilePugFilter(),
|
|
630
|
-
})({
|
|
631
|
-
data,
|
|
632
|
-
_pagePath: obj.pugPath,
|
|
633
|
-
common: commonData,
|
|
634
|
-
});
|
|
635
|
-
fse.ensureFileSync(htmlPath);
|
|
636
|
-
await fse.writeFile(htmlPath, html);
|
|
637
|
-
}
|
|
638
|
-
} else if (typeof data === "object") {
|
|
639
|
-
htmlPath = paths.resolveRoot(
|
|
640
|
-
distOutputPath,
|
|
641
|
-
lang,
|
|
642
|
-
devicePrefix,
|
|
643
|
-
outPutPath
|
|
644
|
-
);
|
|
645
|
-
html = pug.compileFile(pugPath, {
|
|
646
|
-
basedir: paths.template.root,
|
|
647
|
-
compileDebug: true,
|
|
648
|
-
filters: getCompilePugFilter(),
|
|
649
|
-
})({
|
|
650
|
-
data,
|
|
651
|
-
_pagePath: obj.pugPath,
|
|
652
|
-
common: commonData,
|
|
653
|
-
});
|
|
654
|
-
fse.ensureFileSync(htmlPath);
|
|
655
|
-
await fse.writeFile(htmlPath, html);
|
|
656
|
-
}
|
|
657
|
-
});
|
|
661
|
+
|
|
662
|
+
const html = generateHtml(pagesPugToFn, funName, data, pugTemplate, commonData);
|
|
663
|
+
|
|
664
|
+
// 构建输出路径
|
|
665
|
+
let finalPugTemplate = pugTemplate;
|
|
666
|
+
if (data.page_name) {
|
|
667
|
+
finalPugTemplate =
|
|
668
|
+
pugTemplate.split(pathSymbol).slice(0, -1).join(pathSymbol) +
|
|
669
|
+
pathSymbol +
|
|
670
|
+
data.page_name;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
const htmlPath = paths.resolveRoot(
|
|
674
|
+
distOutputPath,
|
|
675
|
+
lang,
|
|
676
|
+
finalPugTemplate.replace(/\..*$/, ".html")
|
|
677
|
+
);
|
|
678
|
+
console.log(htmlPath);
|
|
679
|
+
await fse.outputFile(htmlPath, html);
|
|
680
|
+
} catch (error) {
|
|
681
|
+
throw new Error(`处理JSON文件失败 [file: ${jsonFileName}]: ${error.message}`);
|
|
658
682
|
}
|
|
659
683
|
});
|
|
684
|
+
} catch (error) {
|
|
685
|
+
throw new Error(`处理页面JSON文件失败 [lang: ${lang}]: ${error.message}`);
|
|
660
686
|
}
|
|
687
|
+
}
|
|
661
688
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
recursive: true,
|
|
665
|
-
})
|
|
666
|
-
).filter((fileName) => fileName.endsWith(".json"));
|
|
667
|
-
await async.eachLimit(pagesAllJsonFileName, 64, async (jsonFileName) => {
|
|
668
|
-
let data = await fse.readJSON(paths.resolveRoot(langDataPath, jsonFileName));
|
|
669
|
-
let pugTemplateArr = data._template;
|
|
670
|
-
if (!pugTemplateArr) {
|
|
671
|
-
return;
|
|
672
|
-
}
|
|
673
|
-
let flag = false;
|
|
689
|
+
try {
|
|
690
|
+
const getData = await import(paths.getData);
|
|
674
691
|
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
692
|
+
// 清理并准备输出目录
|
|
693
|
+
await fse.remove(distOutputPath);
|
|
694
|
+
await sleep(0);
|
|
695
|
+
await fse.copy(paths.public, distOutputPath);
|
|
696
|
+
|
|
697
|
+
// 复制静态资源
|
|
698
|
+
await fse.copy(
|
|
699
|
+
paths.template.static,
|
|
700
|
+
paths.resolveRoot(distOutputPath, "static"),
|
|
701
|
+
{
|
|
702
|
+
filter: (src, dest) => {
|
|
703
|
+
//根目录必须要返回true
|
|
704
|
+
if (src.endsWith("static")) {
|
|
705
|
+
return true;
|
|
706
|
+
}
|
|
707
|
+
if (config.buildStaticDirArr && config.buildStaticDirArr.length > 0) {
|
|
708
|
+
return !!config.buildStaticDirArr.find((item) => {
|
|
709
|
+
return src.startsWith(paths.resolveRoot(paths.template.static, item));
|
|
710
|
+
});
|
|
690
711
|
}
|
|
691
712
|
return true;
|
|
692
|
-
}
|
|
713
|
+
},
|
|
693
714
|
}
|
|
715
|
+
);
|
|
694
716
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
717
|
+
// 编译PUG模板
|
|
718
|
+
await compilePagesPugToFn();
|
|
719
|
+
const PagesPugToFn = await import(paths.pagesPugFn);
|
|
720
|
+
|
|
721
|
+
// 处理每种语言
|
|
722
|
+
await async.eachSeries(config.languageList, async (lang) => {
|
|
723
|
+
try {
|
|
724
|
+
console.log("开始处理语言:", lang);
|
|
725
|
+
const langDataPath = paths.resolveRoot(jsonDataPath, lang);
|
|
726
|
+
|
|
727
|
+
// 读取公共数据
|
|
728
|
+
let commonData;
|
|
729
|
+
try {
|
|
730
|
+
commonData = await fse.readJSON(
|
|
731
|
+
paths.resolveRoot("jsonData", lang, "_common.json")
|
|
732
|
+
);
|
|
733
|
+
commonData = _.merge(commonData, config.commonData);
|
|
734
|
+
} catch (error) {
|
|
735
|
+
throw new Error(`读取公共数据失败: ${error.message}`);
|
|
710
736
|
}
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
);
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
737
|
+
|
|
738
|
+
const dealWithEndFunName = new Map();
|
|
739
|
+
|
|
740
|
+
// 处理自定义HTML构建
|
|
741
|
+
await processCustomBuildHtml(PagesPugToFn, lang, getData, commonData, dealWithEndFunName);
|
|
742
|
+
|
|
743
|
+
// 处理页面JSON文件
|
|
744
|
+
await processPageJsonFiles(PagesPugToFn, lang, langDataPath, commonData, dealWithEndFunName);
|
|
745
|
+
|
|
746
|
+
console.log("处理语言:", lang, "完成");
|
|
747
|
+
} catch (error) {
|
|
748
|
+
throw new Error(`处理语言 ${lang} 失败: ${error.message}`);
|
|
749
|
+
}
|
|
721
750
|
});
|
|
722
|
-
|
|
723
|
-
|
|
751
|
+
|
|
752
|
+
// 混淆JavaScript文件(如果配置了)
|
|
753
|
+
if (config.obfuscateJavaScript) {
|
|
754
|
+
console.log("开始混淆js文件...");
|
|
755
|
+
const startTime = Date.now();
|
|
756
|
+
try {
|
|
757
|
+
await obfuscateJavaScript(paths.resolveRoot(distOutputPath, "static"));
|
|
758
|
+
const costTime = (Date.now() - startTime) / 1000;
|
|
759
|
+
console.log("混淆js文件耗时:", costTime, "s");
|
|
760
|
+
} catch (error) {
|
|
761
|
+
throw new Error(`混淆JavaScript文件失败: ${error.message}`);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
console.log("打包完成花费:", (Date.now() - starTime) / 1000, "s");
|
|
766
|
+
|
|
767
|
+
} catch (error) {
|
|
768
|
+
console.error("HTML文件打包失败:", error);
|
|
769
|
+
throw error;
|
|
770
|
+
}
|
|
724
771
|
}
|
|
725
772
|
|
|
726
773
|
/**
|
|
@@ -730,26 +777,26 @@ export async function buildStatic() {
|
|
|
730
777
|
*/
|
|
731
778
|
export async function createDebugTemplate() {
|
|
732
779
|
try {
|
|
733
|
-
console.log(
|
|
734
|
-
|
|
780
|
+
console.log("开始创建调试模板目录...");
|
|
781
|
+
|
|
735
782
|
const sourceDir = paths.template.root;
|
|
736
783
|
const targetDir = paths.template.debug;
|
|
737
|
-
|
|
784
|
+
|
|
738
785
|
// 删除已存在的调试目录
|
|
739
786
|
if (await fse.pathExists(targetDir)) {
|
|
740
787
|
await fse.remove(targetDir);
|
|
741
|
-
console.log(
|
|
788
|
+
console.log("已删除现有的调试目录");
|
|
742
789
|
}
|
|
743
|
-
|
|
790
|
+
|
|
744
791
|
// 复制整个 template 目录到 template-debug
|
|
745
792
|
await fse.copy(sourceDir, targetDir);
|
|
746
793
|
console.log(`已复制 ${sourceDir} 到 ${targetDir}`);
|
|
747
794
|
|
|
748
795
|
let languageData = (await import(paths.languageData)).default.us;
|
|
749
|
-
|
|
796
|
+
|
|
750
797
|
// 缓存语言路径检查结果,避免重复计算
|
|
751
798
|
const langPathCache = new Map();
|
|
752
|
-
|
|
799
|
+
|
|
753
800
|
/**
|
|
754
801
|
* 检查属性路径是否在languageData的us对象中存在
|
|
755
802
|
* @param {string} langPath - 属性路径,例如 "Store.about"
|
|
@@ -760,21 +807,21 @@ export async function createDebugTemplate() {
|
|
|
760
807
|
if (langPathCache.has(langPath)) {
|
|
761
808
|
return langPathCache.get(langPath);
|
|
762
809
|
}
|
|
763
|
-
|
|
810
|
+
|
|
764
811
|
try {
|
|
765
|
-
const keys = langPath.split(
|
|
812
|
+
const keys = langPath.split(".");
|
|
766
813
|
let current = languageData;
|
|
767
|
-
|
|
814
|
+
|
|
768
815
|
for (const key of keys) {
|
|
769
|
-
if (current && typeof current ===
|
|
816
|
+
if (current && typeof current === "object" && key in current) {
|
|
770
817
|
current = current[key];
|
|
771
818
|
} else {
|
|
772
819
|
langPathCache.set(langPath, false);
|
|
773
820
|
return false;
|
|
774
821
|
}
|
|
775
822
|
}
|
|
776
|
-
|
|
777
|
-
const isValid = typeof current ===
|
|
823
|
+
|
|
824
|
+
const isValid = typeof current === "string";
|
|
778
825
|
langPathCache.set(langPath, isValid);
|
|
779
826
|
return isValid;
|
|
780
827
|
} catch (error) {
|
|
@@ -782,7 +829,7 @@ export async function createDebugTemplate() {
|
|
|
782
829
|
return false;
|
|
783
830
|
}
|
|
784
831
|
}
|
|
785
|
-
|
|
832
|
+
|
|
786
833
|
/**
|
|
787
834
|
* 检查是否是动态内容
|
|
788
835
|
* @param {string} code - 代码内容
|
|
@@ -795,13 +842,13 @@ export async function createDebugTemplate() {
|
|
|
795
842
|
/\b(data|item|index|info|common\.siteConfig)\b/,
|
|
796
843
|
/[+\-*/%]/,
|
|
797
844
|
/\brandom\b|\bfloor\b|\bceil\b|\bround\b/,
|
|
798
|
-
/\.\w+\(/,
|
|
799
|
-
/\$\{[^}]*[+\-*/%.][^}]*\}
|
|
845
|
+
/\.\w+\(/, // 方法调用
|
|
846
|
+
/\$\{[^}]*[+\-*/%.][^}]*\}/, // 模板字符串中的计算
|
|
800
847
|
];
|
|
801
|
-
|
|
802
|
-
return dynamicPatterns.some(pattern => pattern.test(code));
|
|
848
|
+
|
|
849
|
+
return dynamicPatterns.some((pattern) => pattern.test(code));
|
|
803
850
|
}
|
|
804
|
-
|
|
851
|
+
|
|
805
852
|
/**
|
|
806
853
|
* 提取Pug节点中的common.lang引用
|
|
807
854
|
* @param {string} code - 代码内容
|
|
@@ -813,22 +860,22 @@ export async function createDebugTemplate() {
|
|
|
813
860
|
if (langMatch) {
|
|
814
861
|
return langMatch[1];
|
|
815
862
|
}
|
|
816
|
-
|
|
863
|
+
|
|
817
864
|
// 匹配 ${common.lang.xxx}
|
|
818
865
|
const templateLangMatch = code.match(/\$\{common\.lang\.([^}]+)\}/);
|
|
819
866
|
if (templateLangMatch) {
|
|
820
867
|
return templateLangMatch[1];
|
|
821
868
|
}
|
|
822
|
-
|
|
869
|
+
|
|
823
870
|
// 匹配带反引号的模板字符串 `${common.lang.xxx}`
|
|
824
871
|
const backquoteLangMatch = code.match(/`.*\$\{common\.lang\.([^}]+)\}.*`/);
|
|
825
872
|
if (backquoteLangMatch) {
|
|
826
873
|
return backquoteLangMatch[1];
|
|
827
874
|
}
|
|
828
|
-
|
|
875
|
+
|
|
829
876
|
return null;
|
|
830
877
|
}
|
|
831
|
-
|
|
878
|
+
|
|
832
879
|
/**
|
|
833
880
|
* 使用 pug-parser 和 pug-walk 分析 pug 文件中的标签
|
|
834
881
|
* @param {string} pugContent - pug 文件内容
|
|
@@ -839,45 +886,47 @@ export async function createDebugTemplate() {
|
|
|
839
886
|
try {
|
|
840
887
|
const tokens = pugLexer(pugContent, { filename });
|
|
841
888
|
const ast = pugParser(tokens, { filename, src: pugContent });
|
|
842
|
-
|
|
889
|
+
|
|
843
890
|
const lineTagMap = new Map();
|
|
844
|
-
|
|
891
|
+
|
|
845
892
|
pugWalk(ast, function before(node) {
|
|
846
|
-
if (node.type ===
|
|
893
|
+
if (node.type === "Tag" && node.line) {
|
|
847
894
|
const tagInfo = {
|
|
848
895
|
tagName: node.name,
|
|
849
896
|
line: node.line,
|
|
850
897
|
isEditable: false,
|
|
851
898
|
editableValue: "true",
|
|
852
|
-
textContent:
|
|
853
|
-
langPath:
|
|
899
|
+
textContent: "",
|
|
900
|
+
langPath: "",
|
|
854
901
|
hasStaticText: false,
|
|
855
|
-
hasLangText: false
|
|
902
|
+
hasLangText: false,
|
|
856
903
|
};
|
|
857
|
-
|
|
904
|
+
|
|
858
905
|
// 分析标签的子节点来确定文本内容
|
|
859
906
|
if (node.block && node.block.nodes) {
|
|
860
907
|
for (const child of node.block.nodes) {
|
|
861
908
|
// 处理Text节点(静态文本)
|
|
862
|
-
if (child.type ===
|
|
909
|
+
if (child.type === "Text" && child.val && child.val.trim()) {
|
|
863
910
|
// 检查是否在同一行还有其他动态内容
|
|
864
|
-
const hasOtherDynamicNodes = node.block.nodes.some(
|
|
865
|
-
sibling
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
911
|
+
const hasOtherDynamicNodes = node.block.nodes.some(
|
|
912
|
+
(sibling) =>
|
|
913
|
+
sibling !== child &&
|
|
914
|
+
sibling.line === child.line &&
|
|
915
|
+
(sibling.type === "Code" ||
|
|
916
|
+
sibling.type === "InterpolatedTag") &&
|
|
917
|
+
sibling.val &&
|
|
918
|
+
isDynamicContent(sibling.val)
|
|
870
919
|
);
|
|
871
|
-
|
|
920
|
+
|
|
872
921
|
if (!hasOtherDynamicNodes) {
|
|
873
922
|
tagInfo.hasStaticText = true;
|
|
874
923
|
tagInfo.textContent = child.val.trim();
|
|
875
924
|
tagInfo.isEditable = true;
|
|
876
925
|
}
|
|
877
926
|
}
|
|
878
|
-
|
|
927
|
+
|
|
879
928
|
// 处理Code节点(插值表达式和代码块)
|
|
880
|
-
if (child.type ===
|
|
929
|
+
if (child.type === "Code" && child.val) {
|
|
881
930
|
const langPath = extractLangPath(child.val);
|
|
882
931
|
if (langPath && !isDynamicContent(child.val)) {
|
|
883
932
|
if (checkLangPathExists(langPath)) {
|
|
@@ -885,14 +934,14 @@ export async function createDebugTemplate() {
|
|
|
885
934
|
tagInfo.langPath = langPath;
|
|
886
935
|
tagInfo.isEditable = true;
|
|
887
936
|
// 转换为 [us][key1][key2] 格式
|
|
888
|
-
const pathParts = langPath.split(
|
|
889
|
-
tagInfo.editableValue = `us,${pathParts.join(
|
|
937
|
+
const pathParts = langPath.split(".");
|
|
938
|
+
tagInfo.editableValue = `us,${pathParts.join(",")}`;
|
|
890
939
|
}
|
|
891
940
|
}
|
|
892
941
|
}
|
|
893
942
|
}
|
|
894
943
|
}
|
|
895
|
-
|
|
944
|
+
|
|
896
945
|
// 检查节点本身是否有代码内容(对于!=语法)
|
|
897
946
|
if (node.code && node.code.val) {
|
|
898
947
|
const langPath = extractLangPath(node.code.val);
|
|
@@ -902,12 +951,12 @@ export async function createDebugTemplate() {
|
|
|
902
951
|
tagInfo.langPath = langPath;
|
|
903
952
|
tagInfo.isEditable = true;
|
|
904
953
|
// 转换为 us,key1,key2 格式
|
|
905
|
-
const pathParts = langPath.split(
|
|
906
|
-
tagInfo.editableValue = `us,${pathParts.join(
|
|
954
|
+
const pathParts = langPath.split(".");
|
|
955
|
+
tagInfo.editableValue = `us,${pathParts.join(",")}`;
|
|
907
956
|
}
|
|
908
957
|
}
|
|
909
958
|
}
|
|
910
|
-
|
|
959
|
+
|
|
911
960
|
// 将标签信息添加到行映射中
|
|
912
961
|
if (!lineTagMap.has(node.line)) {
|
|
913
962
|
lineTagMap.set(node.line, []);
|
|
@@ -915,14 +964,14 @@ export async function createDebugTemplate() {
|
|
|
915
964
|
lineTagMap.get(node.line).push(tagInfo);
|
|
916
965
|
}
|
|
917
966
|
});
|
|
918
|
-
|
|
967
|
+
|
|
919
968
|
return lineTagMap;
|
|
920
969
|
} catch (error) {
|
|
921
970
|
console.error(`分析 pug 文件 ${filename} 时出错:`, error);
|
|
922
971
|
return new Map();
|
|
923
972
|
}
|
|
924
973
|
}
|
|
925
|
-
|
|
974
|
+
|
|
926
975
|
/**
|
|
927
976
|
* 为 pug 文件内容添加调试属性
|
|
928
977
|
* @param {string} pugContent - pug 文件内容
|
|
@@ -932,129 +981,150 @@ export async function createDebugTemplate() {
|
|
|
932
981
|
*/
|
|
933
982
|
function addDebugAttributesToPug(pugContent, relativePath, filename) {
|
|
934
983
|
try {
|
|
935
|
-
const lines = pugContent.split(
|
|
984
|
+
const lines = pugContent.split("\n");
|
|
936
985
|
const lineTagMap = analyzeTagsFromPug(pugContent, filename);
|
|
937
|
-
|
|
986
|
+
|
|
938
987
|
// 定义不需要添加调试属性的标签
|
|
939
988
|
const excludeTags = new Set([
|
|
940
|
-
|
|
941
|
-
|
|
989
|
+
"head",
|
|
990
|
+
"title",
|
|
991
|
+
"meta",
|
|
992
|
+
"link",
|
|
993
|
+
"html",
|
|
994
|
+
"style",
|
|
995
|
+
"script",
|
|
996
|
+
"base",
|
|
997
|
+
"noscript",
|
|
998
|
+
"template",
|
|
942
999
|
]);
|
|
943
|
-
|
|
1000
|
+
|
|
944
1001
|
// 处理每一行
|
|
945
1002
|
const processedLines = lines.map((line, index) => {
|
|
946
1003
|
const lineNumber = index + 1;
|
|
947
1004
|
const tagsInLine = lineTagMap.get(lineNumber);
|
|
948
|
-
|
|
1005
|
+
|
|
949
1006
|
if (!tagsInLine || tagsInLine.length === 0) {
|
|
950
1007
|
return line;
|
|
951
1008
|
}
|
|
952
|
-
|
|
1009
|
+
|
|
953
1010
|
// 过滤掉不需要处理的标签
|
|
954
|
-
const visibleTags = tagsInLine.filter(
|
|
955
|
-
|
|
1011
|
+
const visibleTags = tagsInLine.filter(
|
|
1012
|
+
(tag) => !excludeTags.has(tag.tagName.toLowerCase())
|
|
1013
|
+
);
|
|
1014
|
+
|
|
956
1015
|
if (visibleTags.length === 0) {
|
|
957
1016
|
return line;
|
|
958
1017
|
}
|
|
959
|
-
|
|
1018
|
+
|
|
960
1019
|
// 对于每个标签,添加调试属性
|
|
961
1020
|
let processedLine = line;
|
|
962
|
-
|
|
1021
|
+
|
|
963
1022
|
// 只处理第一个标签,避免处理插值表达式中的内容
|
|
964
1023
|
const mainTag = visibleTags[0];
|
|
965
|
-
|
|
1024
|
+
|
|
966
1025
|
if (mainTag) {
|
|
967
1026
|
// 构建调试属性
|
|
968
1027
|
const debugAttrs = [
|
|
969
1028
|
`data-debug-file="${relativePath}"`,
|
|
970
|
-
`data-debug-line="${lineNumber}"
|
|
1029
|
+
`data-debug-line="${lineNumber}"`,
|
|
971
1030
|
];
|
|
972
|
-
|
|
1031
|
+
|
|
973
1032
|
// 只有可编辑的元素才添加 data-debug-editable 属性
|
|
974
1033
|
if (mainTag.isEditable) {
|
|
975
1034
|
debugAttrs.push(`data-debug-editable="${mainTag.editableValue}"`);
|
|
976
1035
|
}
|
|
977
|
-
|
|
978
|
-
const debugAttrsString = debugAttrs.join(
|
|
979
|
-
|
|
1036
|
+
|
|
1037
|
+
const debugAttrsString = debugAttrs.join(", ");
|
|
1038
|
+
|
|
980
1039
|
// 简化的标签处理逻辑
|
|
981
1040
|
const trimmedLine = line.trim();
|
|
982
|
-
|
|
1041
|
+
|
|
983
1042
|
// 处理隐式 div(.class 或 #id 语法)
|
|
984
|
-
if (trimmedLine.startsWith(
|
|
1043
|
+
if (trimmedLine.startsWith(".") || trimmedLine.startsWith("#")) {
|
|
985
1044
|
const indent = line.match(/^\s*/)[0];
|
|
986
|
-
|
|
1045
|
+
|
|
987
1046
|
// 找到选择器结束的位置
|
|
988
1047
|
let selectorEndIndex = 1;
|
|
989
|
-
while (
|
|
1048
|
+
while (
|
|
1049
|
+
selectorEndIndex < trimmedLine.length &&
|
|
1050
|
+
/[\w-]/.test(trimmedLine[selectorEndIndex])
|
|
1051
|
+
) {
|
|
990
1052
|
selectorEndIndex++;
|
|
991
1053
|
}
|
|
992
|
-
|
|
1054
|
+
|
|
993
1055
|
// 检查是否已经有属性括号
|
|
994
1056
|
const afterSelector = trimmedLine.substring(selectorEndIndex);
|
|
995
|
-
const parenIndex = afterSelector.indexOf(
|
|
996
|
-
|
|
1057
|
+
const parenIndex = afterSelector.indexOf("(");
|
|
1058
|
+
|
|
997
1059
|
if (parenIndex !== -1) {
|
|
998
1060
|
// 已经有属性括号
|
|
999
|
-
const beforeParen = trimmedLine.substring(
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1061
|
+
const beforeParen = trimmedLine.substring(
|
|
1062
|
+
0,
|
|
1063
|
+
selectorEndIndex + parenIndex + 1
|
|
1064
|
+
);
|
|
1065
|
+
const afterFirstParen = trimmedLine.substring(
|
|
1066
|
+
selectorEndIndex + parenIndex + 1
|
|
1067
|
+
);
|
|
1068
|
+
const lastParenIndex = afterFirstParen.lastIndexOf(")");
|
|
1069
|
+
|
|
1003
1070
|
if (lastParenIndex !== -1) {
|
|
1004
1071
|
const existingAttrs = afterFirstParen.substring(0, lastParenIndex);
|
|
1005
1072
|
const afterLastParen = afterFirstParen.substring(lastParenIndex);
|
|
1006
|
-
|
|
1007
|
-
const separator = existingAttrs.trim() ?
|
|
1073
|
+
|
|
1074
|
+
const separator = existingAttrs.trim() ? ", " : "";
|
|
1008
1075
|
processedLine = `${indent}${beforeParen}${existingAttrs}${separator}${debugAttrsString}${afterLastParen}`;
|
|
1009
1076
|
}
|
|
1010
1077
|
} else {
|
|
1011
1078
|
// 没有属性括号,在选择器后添加
|
|
1012
1079
|
const selector = trimmedLine.substring(0, selectorEndIndex);
|
|
1013
1080
|
const afterAttrs = trimmedLine.substring(selectorEndIndex);
|
|
1014
|
-
|
|
1081
|
+
|
|
1015
1082
|
processedLine = `${indent}${selector}(${debugAttrsString})${afterAttrs}`;
|
|
1016
1083
|
}
|
|
1017
1084
|
}
|
|
1018
1085
|
// 处理普通标签
|
|
1019
1086
|
else if (trimmedLine.startsWith(mainTag.tagName)) {
|
|
1020
1087
|
const indent = line.match(/^\s*/)[0];
|
|
1021
|
-
|
|
1088
|
+
|
|
1022
1089
|
// 找到标签名和修饰符的结束位置
|
|
1023
1090
|
const tagEndIndex = findTagEnd(mainTag.tagName, trimmedLine);
|
|
1024
1091
|
const afterTag = trimmedLine.substring(tagEndIndex);
|
|
1025
|
-
|
|
1026
|
-
if (afterTag.startsWith(
|
|
1092
|
+
|
|
1093
|
+
if (afterTag.startsWith("(")) {
|
|
1027
1094
|
// 已经有属性括号,需要找到正确的结束位置
|
|
1028
1095
|
const parenEnd = findMatchingParen(trimmedLine, tagEndIndex);
|
|
1029
|
-
|
|
1096
|
+
|
|
1030
1097
|
if (parenEnd !== -1) {
|
|
1031
1098
|
const tagWithModifiers = trimmedLine.substring(0, tagEndIndex);
|
|
1032
|
-
const existingAttrs = trimmedLine.substring(
|
|
1099
|
+
const existingAttrs = trimmedLine.substring(
|
|
1100
|
+
tagEndIndex + 1,
|
|
1101
|
+
parenEnd
|
|
1102
|
+
);
|
|
1033
1103
|
const remaining = trimmedLine.substring(parenEnd + 1);
|
|
1034
|
-
|
|
1035
|
-
const separator = existingAttrs.trim() ?
|
|
1104
|
+
|
|
1105
|
+
const separator = existingAttrs.trim() ? ", " : "";
|
|
1036
1106
|
processedLine = `${indent}${tagWithModifiers}(${existingAttrs}${separator}${debugAttrsString})${remaining}`;
|
|
1037
1107
|
}
|
|
1038
1108
|
} else {
|
|
1039
1109
|
// 没有属性括号,添加新的属性括号
|
|
1040
1110
|
const tagWithModifiers = trimmedLine.substring(0, tagEndIndex);
|
|
1041
1111
|
const remaining = trimmedLine.substring(tagEndIndex);
|
|
1042
|
-
|
|
1112
|
+
|
|
1043
1113
|
processedLine = `${indent}${tagWithModifiers}(${debugAttrsString})${remaining}`;
|
|
1044
1114
|
}
|
|
1045
1115
|
}
|
|
1046
1116
|
}
|
|
1047
|
-
|
|
1117
|
+
|
|
1048
1118
|
return processedLine;
|
|
1049
1119
|
});
|
|
1050
|
-
|
|
1051
|
-
return processedLines.join(
|
|
1120
|
+
|
|
1121
|
+
return processedLines.join("\n");
|
|
1052
1122
|
} catch (error) {
|
|
1053
1123
|
console.error(`处理 pug 文件 ${filename} 时出错:`, error);
|
|
1054
1124
|
return pugContent;
|
|
1055
1125
|
}
|
|
1056
1126
|
}
|
|
1057
|
-
|
|
1127
|
+
|
|
1058
1128
|
/**
|
|
1059
1129
|
* 找到标签名和修饰符的结束位置
|
|
1060
1130
|
* @param {string} tagName - 标签名
|
|
@@ -1063,11 +1133,11 @@ export async function createDebugTemplate() {
|
|
|
1063
1133
|
*/
|
|
1064
1134
|
function findTagEnd(tagName, line) {
|
|
1065
1135
|
let index = tagName.length;
|
|
1066
|
-
|
|
1136
|
+
|
|
1067
1137
|
// 跳过类名和ID修饰符
|
|
1068
1138
|
while (index < line.length) {
|
|
1069
1139
|
const char = line[index];
|
|
1070
|
-
if (char ===
|
|
1140
|
+
if (char === "." || char === "#") {
|
|
1071
1141
|
index++;
|
|
1072
1142
|
while (index < line.length && /[\w-]/.test(line[index])) {
|
|
1073
1143
|
index++;
|
|
@@ -1076,10 +1146,10 @@ export async function createDebugTemplate() {
|
|
|
1076
1146
|
break;
|
|
1077
1147
|
}
|
|
1078
1148
|
}
|
|
1079
|
-
|
|
1149
|
+
|
|
1080
1150
|
return index;
|
|
1081
1151
|
}
|
|
1082
|
-
|
|
1152
|
+
|
|
1083
1153
|
/**
|
|
1084
1154
|
* 找到匹配的右括号
|
|
1085
1155
|
* @param {string} str - 字符串
|
|
@@ -1090,22 +1160,22 @@ export async function createDebugTemplate() {
|
|
|
1090
1160
|
let depth = 0;
|
|
1091
1161
|
let i = start;
|
|
1092
1162
|
let inString = false;
|
|
1093
|
-
let stringChar =
|
|
1094
|
-
|
|
1163
|
+
let stringChar = "";
|
|
1164
|
+
|
|
1095
1165
|
while (i < str.length) {
|
|
1096
1166
|
const char = str[i];
|
|
1097
|
-
|
|
1167
|
+
|
|
1098
1168
|
// 处理字符串内容,避免字符串中的括号影响匹配
|
|
1099
|
-
if (!inString && (char === '"' || char === "'" || char ===
|
|
1169
|
+
if (!inString && (char === '"' || char === "'" || char === "`")) {
|
|
1100
1170
|
inString = true;
|
|
1101
1171
|
stringChar = char;
|
|
1102
|
-
} else if (inString && char === stringChar && str[i-1] !==
|
|
1172
|
+
} else if (inString && char === stringChar && str[i - 1] !== "\\") {
|
|
1103
1173
|
inString = false;
|
|
1104
|
-
stringChar =
|
|
1174
|
+
stringChar = "";
|
|
1105
1175
|
} else if (!inString) {
|
|
1106
|
-
if (char ===
|
|
1176
|
+
if (char === "(") {
|
|
1107
1177
|
depth++;
|
|
1108
|
-
} else if (char ===
|
|
1178
|
+
} else if (char === ")") {
|
|
1109
1179
|
depth--;
|
|
1110
1180
|
if (depth === 0) {
|
|
1111
1181
|
return i;
|
|
@@ -1114,10 +1184,10 @@ export async function createDebugTemplate() {
|
|
|
1114
1184
|
}
|
|
1115
1185
|
i++;
|
|
1116
1186
|
}
|
|
1117
|
-
|
|
1187
|
+
|
|
1118
1188
|
return -1; // 没有找到匹配的括号
|
|
1119
1189
|
}
|
|
1120
|
-
|
|
1190
|
+
|
|
1121
1191
|
/**
|
|
1122
1192
|
* 递归处理目录中的所有 pug 文件
|
|
1123
1193
|
* @param {string} dir - 目录路径
|
|
@@ -1126,27 +1196,33 @@ export async function createDebugTemplate() {
|
|
|
1126
1196
|
async function processPugFilesInDirectory(dir, baseDir) {
|
|
1127
1197
|
try {
|
|
1128
1198
|
const files = await fse.readdir(dir);
|
|
1129
|
-
|
|
1199
|
+
|
|
1130
1200
|
for (const file of files) {
|
|
1131
1201
|
const fullPath = path.join(dir, file);
|
|
1132
1202
|
const stats = await fse.stat(fullPath);
|
|
1133
|
-
|
|
1203
|
+
|
|
1134
1204
|
if (stats.isDirectory()) {
|
|
1135
1205
|
// 递归处理子目录
|
|
1136
1206
|
await processPugFilesInDirectory(fullPath, baseDir);
|
|
1137
|
-
} else if (file.endsWith(
|
|
1207
|
+
} else if (file.endsWith(".pug")) {
|
|
1138
1208
|
// 处理 pug 文件
|
|
1139
1209
|
try {
|
|
1140
|
-
const relativePath = path
|
|
1141
|
-
|
|
1142
|
-
|
|
1210
|
+
const relativePath = path
|
|
1211
|
+
.relative(baseDir, fullPath)
|
|
1212
|
+
.replace(/\\/g, "/");
|
|
1213
|
+
const pugContent = await fse.readFile(fullPath, "utf8");
|
|
1214
|
+
|
|
1143
1215
|
console.log(`正在处理: ${relativePath}`);
|
|
1144
|
-
|
|
1145
|
-
const processedContent = addDebugAttributesToPug(
|
|
1146
|
-
|
|
1216
|
+
|
|
1217
|
+
const processedContent = addDebugAttributesToPug(
|
|
1218
|
+
pugContent,
|
|
1219
|
+
relativePath,
|
|
1220
|
+
file
|
|
1221
|
+
);
|
|
1222
|
+
|
|
1147
1223
|
// 写回处理后的内容
|
|
1148
|
-
await fse.writeFile(fullPath, processedContent,
|
|
1149
|
-
|
|
1224
|
+
await fse.writeFile(fullPath, processedContent, "utf8");
|
|
1225
|
+
|
|
1150
1226
|
console.log(`已处理: ${relativePath}`);
|
|
1151
1227
|
} catch (error) {
|
|
1152
1228
|
console.error(`处理文件 ${fullPath} 时出错:`, error);
|
|
@@ -1157,16 +1233,15 @@ export async function createDebugTemplate() {
|
|
|
1157
1233
|
console.error(`处理目录 ${dir} 时出错:`, error);
|
|
1158
1234
|
}
|
|
1159
1235
|
}
|
|
1160
|
-
|
|
1236
|
+
|
|
1161
1237
|
// 开始处理调试目录中的所有 pug 文件
|
|
1162
|
-
console.log(
|
|
1238
|
+
console.log("开始为 pug 文件添加调试属性...");
|
|
1163
1239
|
await processPugFilesInDirectory(targetDir, targetDir);
|
|
1164
|
-
|
|
1165
|
-
console.log(
|
|
1240
|
+
|
|
1241
|
+
console.log("调试模板目录创建完成!");
|
|
1166
1242
|
console.log(`调试模板位置: ${targetDir}`);
|
|
1167
|
-
|
|
1168
1243
|
} catch (error) {
|
|
1169
|
-
console.error(
|
|
1244
|
+
console.error("创建调试模板时出错:", error);
|
|
1170
1245
|
throw error;
|
|
1171
1246
|
}
|
|
1172
|
-
}
|
|
1247
|
+
}
|