@scaffscript/core 0.2.3 → 0.2.5
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/dist/index.cjs +524 -432
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -314,7 +314,7 @@ async function getScaffConfig() {
|
|
|
314
314
|
};
|
|
315
315
|
}
|
|
316
316
|
// src/parser/regex.ts
|
|
317
|
-
var commentRegex =
|
|
317
|
+
var commentRegex = /(?<!\/)\/\/(?!\/)[^\n]*|\/\*(?!\*)[\s\S]*?\*\//g;
|
|
318
318
|
var implRegex = /impl\s+(?<name>[\w+]+)\s+\{\s+(?<body>[.\s\S]+?)\}/g;
|
|
319
319
|
var implHeaderRegex = /impl\s+(?<name>\w+)\s*\{/g;
|
|
320
320
|
var fnParamsRegex = /\((?<params>[^)]*)\)/g;
|
|
@@ -344,7 +344,7 @@ function getTabLevels(str, tabType) {
|
|
|
344
344
|
// package.json
|
|
345
345
|
var package_default = {
|
|
346
346
|
name: "@scaffscript/core",
|
|
347
|
-
version: "0.2.
|
|
347
|
+
version: "0.2.3",
|
|
348
348
|
repository: {
|
|
349
349
|
type: "git",
|
|
350
350
|
url: "https://github.com/undervolta/scaffscript"
|
|
@@ -516,6 +516,353 @@ async function readAndSplitFiles(files, config) {
|
|
|
516
516
|
}
|
|
517
517
|
return res;
|
|
518
518
|
}
|
|
519
|
+
// src/parser/import-module.ts
|
|
520
|
+
function countTabsBeforeSubstring(str, sub, tabChar) {
|
|
521
|
+
const idx = str.indexOf(sub);
|
|
522
|
+
if (idx === -1)
|
|
523
|
+
return -1;
|
|
524
|
+
const lineStart = str.lastIndexOf(`
|
|
525
|
+
`, idx - 1) + 1;
|
|
526
|
+
const segment = str.slice(lineStart, idx);
|
|
527
|
+
let count = 0;
|
|
528
|
+
for (const ch of segment) {
|
|
529
|
+
if (ch === tabChar)
|
|
530
|
+
count++;
|
|
531
|
+
else
|
|
532
|
+
break;
|
|
533
|
+
}
|
|
534
|
+
return count;
|
|
535
|
+
}
|
|
536
|
+
function resolveImportPath(filePath, importPath, config) {
|
|
537
|
+
if (!config.path)
|
|
538
|
+
return resolvePath(`${filePath}/${importPath}`);
|
|
539
|
+
const useWildcard = Object.keys(config.path).filter((k) => k.endsWith("*")).find((k) => importPath.startsWith(k.slice(0, -1)));
|
|
540
|
+
if (useWildcard) {
|
|
541
|
+
const pathAlias = config.path[useWildcard]?.replace("*", "");
|
|
542
|
+
const dynPath = importPath.replace(useWildcard.slice(0, -2), "");
|
|
543
|
+
if (!pathAlias) {
|
|
544
|
+
log.error(`Path \x1B[33m${importPath}\x1B[0m not found in path aliases. Aborting...`);
|
|
545
|
+
return "";
|
|
546
|
+
}
|
|
547
|
+
if (pathAlias.startsWith("~")) {
|
|
548
|
+
return resolvePath(`${config.source}/${pathAlias.replace("~/", "").replace("~", "")}${dynPath}`);
|
|
549
|
+
}
|
|
550
|
+
return resolvePath(`${filePath}/${pathAlias}${dynPath}`);
|
|
551
|
+
} else if (config.path[importPath]) {
|
|
552
|
+
const pathAlias = config.path[importPath];
|
|
553
|
+
if (pathAlias.startsWith("~")) {
|
|
554
|
+
return resolvePath(`${config.source}/${pathAlias.replace("~/", "").replace("~", "")}`);
|
|
555
|
+
}
|
|
556
|
+
return resolvePath(`${filePath}/${pathAlias}`);
|
|
557
|
+
}
|
|
558
|
+
return resolvePath(`${filePath}/${importPath}`);
|
|
559
|
+
}
|
|
560
|
+
async function getModuleUsage(module2, fileGroup, file, config) {
|
|
561
|
+
const matches = [...file.content.matchAll(modControlRegex)].filter((match) => match.groups.cmd !== "export");
|
|
562
|
+
const limit = 10;
|
|
563
|
+
const results = [];
|
|
564
|
+
let isInvalid = false;
|
|
565
|
+
for (let i = 0;i < matches.length; i += limit) {
|
|
566
|
+
const batch = matches.slice(i, i + limit);
|
|
567
|
+
const res = await Promise.all(batch.map(async (match) => {
|
|
568
|
+
const { cmd, mod, path: path3 } = match.groups;
|
|
569
|
+
const res2 = {
|
|
570
|
+
cmd: null,
|
|
571
|
+
files: null,
|
|
572
|
+
modList: null,
|
|
573
|
+
targetPath: null,
|
|
574
|
+
targetStr: ""
|
|
575
|
+
};
|
|
576
|
+
if (!(cmd && mod && path3)) {
|
|
577
|
+
log.error(`Invalid module control statement: \x1B[34m${cmd} ${mod} from ${path3}\x1B[0m in \x1B[33m${file.name}\x1B[0m from \x1B[32m${file.path}\x1B[0m. Aborting...`);
|
|
578
|
+
isInvalid = true;
|
|
579
|
+
return null;
|
|
580
|
+
}
|
|
581
|
+
const fromPath = normalizePath(resolveImportPath(file.path, path3.slice(1, -1), config));
|
|
582
|
+
const modList = {};
|
|
583
|
+
const alias = {};
|
|
584
|
+
if (!module2[fromPath]) {
|
|
585
|
+
if (cmd === "include" && mod.startsWith("{") && (mod.includes('"') || mod.includes("'"))) {
|
|
586
|
+
const files = mod.slice(1, -1).split(",").map((m) => m.trim());
|
|
587
|
+
const filePaths = [];
|
|
588
|
+
for (const f of files) {
|
|
589
|
+
const filePath = normalizePath(resolvePath(`${file.path}/${f.slice(1, -1)}`));
|
|
590
|
+
const targetFile = fileGroup.normal.find((fl) => {
|
|
591
|
+
let targetFile2 = `${fl.path}/${fl.name}`;
|
|
592
|
+
let currFile = filePath;
|
|
593
|
+
if (!targetFile2.endsWith(".gml"))
|
|
594
|
+
targetFile2 += ".gml";
|
|
595
|
+
if (!currFile.endsWith(".gml"))
|
|
596
|
+
currFile += ".gml";
|
|
597
|
+
return targetFile2 === currFile;
|
|
598
|
+
});
|
|
599
|
+
if (targetFile)
|
|
600
|
+
filePaths.push(targetFile);
|
|
601
|
+
else if (await fileExists(filePath))
|
|
602
|
+
filePaths.push(filePath);
|
|
603
|
+
else {
|
|
604
|
+
if (config.onNotFound === "error") {
|
|
605
|
+
log.error(`File \x1B[33m${f.slice(1, -1)}\x1B[0m from \x1B[32m${file.path}\x1B[0m not found. Aborting...`);
|
|
606
|
+
isInvalid = true;
|
|
607
|
+
return null;
|
|
608
|
+
} else
|
|
609
|
+
log.warn(`File \x1B[33m${f.slice(1, -1)}\x1B[0m from \x1B[32m${file.path}\x1B[0m not found. Skipping this file...`);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return {
|
|
613
|
+
cmd,
|
|
614
|
+
files: filePaths,
|
|
615
|
+
modList,
|
|
616
|
+
targetPath: fromPath,
|
|
617
|
+
targetStr: match[0]
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
log.error(`Path \x1B[33m${fromPath}\x1B[0m doesn't have any exported modules. Aborting...`);
|
|
621
|
+
isInvalid = true;
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
624
|
+
if (mod === "*" || mod.startsWith("{") && mod.endsWith("}")) {
|
|
625
|
+
const targetMods = mod === "*" ? null : mod.slice(1, -1).split(",").map((m) => {
|
|
626
|
+
const split = m.split(":");
|
|
627
|
+
const key = split[0].trim();
|
|
628
|
+
if (split.length === 1)
|
|
629
|
+
alias[key] = key;
|
|
630
|
+
else
|
|
631
|
+
alias[key] = split[1].trim();
|
|
632
|
+
if (!module2[fromPath]) {
|
|
633
|
+
if (config.onNotFound === "error") {
|
|
634
|
+
log.error(`Path \x1B[33m${fromPath}\x1B[0m doesn't have any exported modules. Aborting...`);
|
|
635
|
+
isInvalid = true;
|
|
636
|
+
} else
|
|
637
|
+
log.warn(`Path \x1B[33m${fromPath}\x1B[0m doesn't have any exported modules. Skipping this module...`);
|
|
638
|
+
return null;
|
|
639
|
+
}
|
|
640
|
+
if (!module2[fromPath][key]) {
|
|
641
|
+
if (config.onNotFound === "error") {
|
|
642
|
+
log.error(`Module \x1B[33m${key}\x1B[0m from \x1B[32m${fromPath}\x1B[0m not found. Aborting...`);
|
|
643
|
+
isInvalid = true;
|
|
644
|
+
} else
|
|
645
|
+
log.warn(`Module \x1B[33m${key}\x1B[0m from \x1B[32m${fromPath}\x1B[0m not found. Skipping this module...`);
|
|
646
|
+
return null;
|
|
647
|
+
}
|
|
648
|
+
return key;
|
|
649
|
+
}).filter(Boolean);
|
|
650
|
+
Object.entries(module2[fromPath]).forEach(([key, value]) => {
|
|
651
|
+
if (mod === "*")
|
|
652
|
+
modList[key] = { name: key, as: key, value, usingAlias: false };
|
|
653
|
+
else if (targetMods.includes(key)) {
|
|
654
|
+
const usingAlias = key in alias && alias[key] !== key;
|
|
655
|
+
modList[alias[key] ?? key] = {
|
|
656
|
+
name: key,
|
|
657
|
+
as: alias[key] ?? key,
|
|
658
|
+
value,
|
|
659
|
+
usingAlias
|
|
660
|
+
};
|
|
661
|
+
if (usingAlias) {
|
|
662
|
+
if (!module2[fromPath])
|
|
663
|
+
module2[fromPath] = {};
|
|
664
|
+
module2[fromPath][`@${alias[key]}`] = value;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
} else {
|
|
669
|
+
if (!module2[fromPath][mod]) {
|
|
670
|
+
if (config.onNotFound === "error") {
|
|
671
|
+
log.error(`Module \x1B[33m${mod}\x1B[0m from \x1B[32m${fromPath}\x1B[0m not found. Aborting...`);
|
|
672
|
+
isInvalid = true;
|
|
673
|
+
} else
|
|
674
|
+
log.warn(`Module \x1B[33m${mod}\x1B[0m from \x1B[32m${fromPath}\x1B[0m not found. Skipping this module...`);
|
|
675
|
+
return res2;
|
|
676
|
+
}
|
|
677
|
+
modList[mod] = {
|
|
678
|
+
name: mod,
|
|
679
|
+
as: mod,
|
|
680
|
+
value: module2[fromPath][mod],
|
|
681
|
+
usingAlias: false
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
return {
|
|
685
|
+
cmd,
|
|
686
|
+
files: null,
|
|
687
|
+
modList,
|
|
688
|
+
targetPath: fromPath,
|
|
689
|
+
targetStr: match[0]
|
|
690
|
+
};
|
|
691
|
+
}));
|
|
692
|
+
if (isInvalid)
|
|
693
|
+
break;
|
|
694
|
+
results.push(...res);
|
|
695
|
+
}
|
|
696
|
+
return !isInvalid && results.every((r) => r) ? results : null;
|
|
697
|
+
}
|
|
698
|
+
async function implementModules(module2, fileGroup, file, config, mods) {
|
|
699
|
+
if (!mods)
|
|
700
|
+
mods = await getModuleUsage(module2, fileGroup, file, config);
|
|
701
|
+
if (!mods)
|
|
702
|
+
return null;
|
|
703
|
+
const toRemove = [...file.content.matchAll(modControlRegex)];
|
|
704
|
+
for (const rm of toRemove) {
|
|
705
|
+
if (rm.groups?.cmd !== "include")
|
|
706
|
+
file.content = file.content.replace(rm[0], "");
|
|
707
|
+
}
|
|
708
|
+
for (const mod of mods) {
|
|
709
|
+
if (!mod)
|
|
710
|
+
return null;
|
|
711
|
+
if (!mod.cmd)
|
|
712
|
+
return null;
|
|
713
|
+
switch (mod.cmd) {
|
|
714
|
+
case "include":
|
|
715
|
+
let toReplace = "";
|
|
716
|
+
if (!mod.files) {
|
|
717
|
+
if (!mod.modList)
|
|
718
|
+
return null;
|
|
719
|
+
const modEntries = Object.entries(mod.modList);
|
|
720
|
+
const modLen = modEntries.length;
|
|
721
|
+
const modIterator = modEntries.entries();
|
|
722
|
+
for (const [idx, [_, include]] of modIterator) {
|
|
723
|
+
if (idx > 0)
|
|
724
|
+
switch (include.value.type) {
|
|
725
|
+
case "object":
|
|
726
|
+
case "method":
|
|
727
|
+
case "array":
|
|
728
|
+
case "enum":
|
|
729
|
+
toReplace += `
|
|
730
|
+
`;
|
|
731
|
+
break;
|
|
732
|
+
}
|
|
733
|
+
toReplace += include.value.parsedStr + `
|
|
734
|
+
`;
|
|
735
|
+
if (idx === modLen - 1)
|
|
736
|
+
toReplace += `
|
|
737
|
+
`;
|
|
738
|
+
}
|
|
739
|
+
file.content = file.content.replace(mod.targetStr, toReplace);
|
|
740
|
+
} else {
|
|
741
|
+
for (const fileOrPath of mod.files) {
|
|
742
|
+
if (typeof fileOrPath === "string") {
|
|
743
|
+
const content = await fsRuntime.readText(fileOrPath);
|
|
744
|
+
toReplace += content + `
|
|
745
|
+
|
|
746
|
+
`;
|
|
747
|
+
} else
|
|
748
|
+
toReplace += fileOrPath.content + `
|
|
749
|
+
|
|
750
|
+
`;
|
|
751
|
+
}
|
|
752
|
+
file.content = file.content.replace(mod.targetStr, toReplace);
|
|
753
|
+
}
|
|
754
|
+
break;
|
|
755
|
+
case "import":
|
|
756
|
+
const cmdMatches = [...file.content.matchAll(contentModRegex)];
|
|
757
|
+
const shortCmdMatches = [
|
|
758
|
+
...file.content.matchAll(contentModShortRegex)
|
|
759
|
+
];
|
|
760
|
+
const useMatches = [...file.content.matchAll(useModRegex)];
|
|
761
|
+
for (const match of cmdMatches) {
|
|
762
|
+
const { cmd: contentCmd, mod: contentMod } = match.groups;
|
|
763
|
+
if (!contentCmd || !contentMod) {
|
|
764
|
+
log.error(`Invalid content module statement: \x1B[34m${contentCmd} ${contentMod}\x1B[0m in \x1B[33m${file.name}\x1B[0m from \x1B[32m${file.path}\x1B[0m. Aborting...`);
|
|
765
|
+
return null;
|
|
766
|
+
}
|
|
767
|
+
if (!(`@${contentMod}` in mod.modList) && !(contentMod in mod.modList))
|
|
768
|
+
continue;
|
|
769
|
+
if (config.debugLevel >= 1)
|
|
770
|
+
log.debug(`Content module statement found: \x1B[34m${contentCmd} ${contentMod}\x1B[0m in \x1B[33m${file.name === "" ? "index" : file.name}\x1B[0m from \x1B[32m${file.path}\x1B[0m.`);
|
|
771
|
+
let parsedStr = "";
|
|
772
|
+
switch (contentCmd) {
|
|
773
|
+
case "content":
|
|
774
|
+
const tabChar = config.tabType === "1t" ? "\t" : config.tabType === "2s" ? " " : " ";
|
|
775
|
+
const tabCnt = countTabsBeforeSubstring(file.content, match[0], tabChar);
|
|
776
|
+
parsedStr = module2[mod.targetPath][`@${contentMod}` in module2[mod.targetPath] ? `@${contentMod}` : contentMod].parsedStr;
|
|
777
|
+
if (tabCnt > 0) {
|
|
778
|
+
const tabLevels = getTabLevels(parsedStr, config.tabType).map((l) => l + tabCnt);
|
|
779
|
+
file.content = file.content.replace(match[0], parsedStr.split(`
|
|
780
|
+
`).map((l, i) => tabLevels[i] ? insertTabs(tabLevels[i], config.tabType) + l : l).join(`
|
|
781
|
+
`));
|
|
782
|
+
} else
|
|
783
|
+
file.content = file.content.replace(match[0], parsedStr);
|
|
784
|
+
break;
|
|
785
|
+
case "nameof":
|
|
786
|
+
parsedStr = module2[mod.targetPath][`@${contentMod}` in module2[mod.targetPath] ? `@${contentMod}` : contentMod].name;
|
|
787
|
+
file.content = file.content.replace(`@nameof ${contentMod}`, parsedStr);
|
|
788
|
+
break;
|
|
789
|
+
case "typeof":
|
|
790
|
+
parsedStr = module2[mod.targetPath][`@${contentMod}` in module2[mod.targetPath] ? `@${contentMod}` : contentMod].type;
|
|
791
|
+
file.content = file.content.replace(`@typeof ${contentMod}`, `"${parsedStr}"`);
|
|
792
|
+
break;
|
|
793
|
+
case "valueof":
|
|
794
|
+
parsedStr = module2[mod.targetPath][`@${contentMod}` in module2[mod.targetPath] ? `@${contentMod}` : contentMod].value;
|
|
795
|
+
file.content = file.content.replace(`@valueof ${contentMod}`, parsedStr);
|
|
796
|
+
break;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
for (const match of shortCmdMatches) {
|
|
800
|
+
const { mod: contentMod } = match.groups;
|
|
801
|
+
if (!contentMod) {
|
|
802
|
+
log.error(`Invalid content module statement: \x1B[34m@:${contentMod}\x1B[0m in \x1B[33m${file.name}\x1B[0m from \x1B[32m${file.path}\x1B[0m. Aborting...`);
|
|
803
|
+
return null;
|
|
804
|
+
}
|
|
805
|
+
if (config.debugLevel >= 1)
|
|
806
|
+
log.debug(`Valueof module statement found: \x1B[34m${contentMod}\x1B[0m in \x1B[33m${file.name}\x1B[0m from \x1B[32m${file.path}\x1B[0m.`);
|
|
807
|
+
if (!(`@${contentMod}` in mod.modList) && !(contentMod in mod.modList))
|
|
808
|
+
continue;
|
|
809
|
+
const parsedStr = module2[mod.targetPath][`@${contentMod}` in module2[mod.targetPath] ? `@${contentMod}` : contentMod].value;
|
|
810
|
+
file.content = file.content.replace(`@:${contentMod}`, parsedStr);
|
|
811
|
+
}
|
|
812
|
+
for (const match of useMatches) {
|
|
813
|
+
const { mod: contentMod, body } = match.groups;
|
|
814
|
+
if (!contentMod || !body) {
|
|
815
|
+
log.error(`Invalid content module statement: \x1B[34m@use ${contentMod} ${body}\x1B[0m in \x1B[33m${file.name}\x1B[0m from \x1B[32m${file.path}\x1B[0m. Aborting...`);
|
|
816
|
+
return null;
|
|
817
|
+
}
|
|
818
|
+
if (!(`@${contentMod}` in mod.modList) && !(contentMod in mod.modList))
|
|
819
|
+
continue;
|
|
820
|
+
if (config.debugLevel >= 1)
|
|
821
|
+
log.debug(`Use module statement found: \x1B[34m@use ${contentMod} ${body}\x1B[0m in \x1B[33m${file.name}\x1B[0m from \x1B[32m${file.path}\x1B[0m.`);
|
|
822
|
+
const lines = body.slice(1, -1).split(`
|
|
823
|
+
`).filter(Boolean);
|
|
824
|
+
const pairs = lines.map((l) => l.split(":").map((p) => {
|
|
825
|
+
const delimIdx = p.lastIndexOf(",");
|
|
826
|
+
return p.slice(0, delimIdx === -1 ? undefined : delimIdx).trim();
|
|
827
|
+
}));
|
|
828
|
+
const tabChar = config.tabType === "1t" ? "\t" : config.tabType === "2s" ? " " : " ";
|
|
829
|
+
const tabCnt = countTabsBeforeSubstring(file.content.slice(file.content.lastIndexOf(`
|
|
830
|
+
`, match.index), match.index + match[0].length), "@", tabChar);
|
|
831
|
+
const tabLevels = getTabLevels(body, config.tabType).map((l) => l + tabCnt);
|
|
832
|
+
const currMod = module2[mod.targetPath][`@${contentMod}` in module2[mod.targetPath] ? `@${contentMod}` : contentMod];
|
|
833
|
+
const modMember = Object.entries(currMod.member);
|
|
834
|
+
const tabLevel = tabCnt + tabLevels[Math.min(1, tabLevels.length - 1)];
|
|
835
|
+
let res = `{
|
|
836
|
+
`;
|
|
837
|
+
for (const [idx, [mName, mVal]] of modMember.entries()) {
|
|
838
|
+
const pairIdx = pairs.findIndex((p) => p[0] === mName);
|
|
839
|
+
const pair = pairIdx > -1 ? pairs[pairIdx] : null;
|
|
840
|
+
const value = pair ? pair.length === 2 ? pair[1] : mVal.value : mVal.value;
|
|
841
|
+
if (value) {
|
|
842
|
+
res += `${insertTabs(tabLevel, config.tabType)}${mName}: ${value}${idx < modMember.length - 2 ? "," : ""}
|
|
843
|
+
`;
|
|
844
|
+
}
|
|
845
|
+
if (pairIdx > -1)
|
|
846
|
+
swapAndPop(pairs, pairIdx);
|
|
847
|
+
}
|
|
848
|
+
for (const [idx, pair] of pairs.entries()) {
|
|
849
|
+
if (idx === 0)
|
|
850
|
+
res = res.slice(0, -1) + `,
|
|
851
|
+
`;
|
|
852
|
+
res += `${insertTabs(tabLevel, config.tabType)}${pair[0]}: ${pair[1]}${idx < pairs.length - 1 ? "," : ""}
|
|
853
|
+
`;
|
|
854
|
+
}
|
|
855
|
+
res += insertTabs(tabCnt, config.tabType) + "}";
|
|
856
|
+
file.content = file.content.replace(match[0], res);
|
|
857
|
+
}
|
|
858
|
+
break;
|
|
859
|
+
}
|
|
860
|
+
file.content = file.content.trim() + `
|
|
861
|
+
`;
|
|
862
|
+
}
|
|
863
|
+
return mods;
|
|
864
|
+
}
|
|
865
|
+
|
|
519
866
|
// src/parser/export-module.ts
|
|
520
867
|
function inferType(value) {
|
|
521
868
|
value = value.trim();
|
|
@@ -940,7 +1287,91 @@ ${insertTabs(1, config.tabType)}${classBody}
|
|
|
940
1287
|
retryLen = retryList.length;
|
|
941
1288
|
retryCount++;
|
|
942
1289
|
}
|
|
943
|
-
return module2;
|
|
1290
|
+
return module2;
|
|
1291
|
+
}
|
|
1292
|
+
function reexportModule(module2, file, config) {
|
|
1293
|
+
const reexportMatches = [...file.content.matchAll(modControlRegex)].filter((match) => match.groups?.cmd === "export");
|
|
1294
|
+
if (!reexportMatches.length)
|
|
1295
|
+
return false;
|
|
1296
|
+
for (const match of reexportMatches) {
|
|
1297
|
+
const { cmd, mod, path: path3 } = match.groups;
|
|
1298
|
+
if (!(cmd && mod && path3)) {
|
|
1299
|
+
log.error(`Invalid module control statement: \x1B[34m${cmd} ${mod} from ${path3}\x1B[0m in \x1B[33m${file.name}\x1B[0m from \x1B[32m${file.path}\x1B[0m. Aborting...`);
|
|
1300
|
+
return false;
|
|
1301
|
+
}
|
|
1302
|
+
const fromPath = normalizePath(resolveImportPath(file.path, path3.slice(1, -1), config));
|
|
1303
|
+
const thisPath = file.isIndex ? file.path : `${file.path}/${file.name}`;
|
|
1304
|
+
const alias = {};
|
|
1305
|
+
if (mod === "*" || mod.startsWith("{") && mod.endsWith("}")) {
|
|
1306
|
+
const targetMods = mod === "*" ? null : mod.slice(1, -1).split(",").map((m) => {
|
|
1307
|
+
const split = m.split(":");
|
|
1308
|
+
const key = split[0].trim();
|
|
1309
|
+
if (split.length === 1)
|
|
1310
|
+
alias[key] = key;
|
|
1311
|
+
else
|
|
1312
|
+
alias[key] = split[1].trim();
|
|
1313
|
+
if (!module2[fromPath]) {
|
|
1314
|
+
if (config.onNotFound === "error") {
|
|
1315
|
+
log.error(`Path \x1B[33m${fromPath}\x1B[0m doesn't have any exported modules. Aborting...`);
|
|
1316
|
+
return false;
|
|
1317
|
+
} else
|
|
1318
|
+
log.warn(`Path \x1B[33m${fromPath}\x1B[0m doesn't have any exported modules. Skipping this module...`);
|
|
1319
|
+
return false;
|
|
1320
|
+
}
|
|
1321
|
+
if (!module2[fromPath][key]) {
|
|
1322
|
+
if (config.onNotFound === "error") {
|
|
1323
|
+
log.error(`Module \x1B[33m${key}\x1B[0m from \x1B[32m${fromPath}\x1B[0m not found. Aborting...`);
|
|
1324
|
+
return false;
|
|
1325
|
+
} else
|
|
1326
|
+
log.warn(`Module \x1B[33m${key}\x1B[0m from \x1B[32m${fromPath}\x1B[0m not found. Skipping this module...`);
|
|
1327
|
+
return false;
|
|
1328
|
+
}
|
|
1329
|
+
return key;
|
|
1330
|
+
}).filter(Boolean);
|
|
1331
|
+
if (!module2[fromPath]) {
|
|
1332
|
+
if (config.onNotFound === "error") {
|
|
1333
|
+
log.error(`Path \x1B[33m${fromPath}\x1B[0m doesn't have any exported modules. Aborting...`);
|
|
1334
|
+
return false;
|
|
1335
|
+
} else
|
|
1336
|
+
log.warn(`Path \x1B[33m${fromPath}\x1B[0m doesn't have any exported modules. Skipping this module...`);
|
|
1337
|
+
return false;
|
|
1338
|
+
}
|
|
1339
|
+
Object.entries(module2[fromPath]).forEach(([key, value]) => {
|
|
1340
|
+
if (!module2[thisPath])
|
|
1341
|
+
module2[thisPath] = {};
|
|
1342
|
+
if (mod === "*")
|
|
1343
|
+
module2[thisPath][key] = value;
|
|
1344
|
+
else if (targetMods.includes(key)) {
|
|
1345
|
+
const usingAlias = key in alias && alias[key] !== key;
|
|
1346
|
+
if (usingAlias)
|
|
1347
|
+
module2[thisPath][`@${alias[key]}`] = value;
|
|
1348
|
+
else
|
|
1349
|
+
module2[thisPath][key] = value;
|
|
1350
|
+
}
|
|
1351
|
+
});
|
|
1352
|
+
} else {
|
|
1353
|
+
if (!module2[fromPath]) {
|
|
1354
|
+
if (config.onNotFound === "error") {
|
|
1355
|
+
log.error(`Path \x1B[33m${fromPath}\x1B[0m doesn't have any exported modules. Aborting...`);
|
|
1356
|
+
return false;
|
|
1357
|
+
} else
|
|
1358
|
+
log.warn(`Path \x1B[33m${fromPath}\x1B[0m doesn't have any exported modules. Skipping this module...`);
|
|
1359
|
+
return false;
|
|
1360
|
+
}
|
|
1361
|
+
if (!module2[fromPath][mod]) {
|
|
1362
|
+
if (config.onNotFound === "error") {
|
|
1363
|
+
log.error(`Module \x1B[33m${mod}\x1B[0m from \x1B[32m${fromPath}\x1B[0m not found. Aborting...`);
|
|
1364
|
+
return false;
|
|
1365
|
+
} else
|
|
1366
|
+
log.warn(`Module \x1B[33m${mod}\x1B[0m from \x1B[32m${fromPath}\x1B[0m not found. Skipping this module...`);
|
|
1367
|
+
return false;
|
|
1368
|
+
}
|
|
1369
|
+
if (!module2[thisPath])
|
|
1370
|
+
module2[thisPath] = {};
|
|
1371
|
+
module2[thisPath][mod] = module2[fromPath][mod];
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
return true;
|
|
944
1375
|
}
|
|
945
1376
|
// src/parser/class-implement.ts
|
|
946
1377
|
function convertArrowFn(str) {
|
|
@@ -965,451 +1396,109 @@ function parseHeader(str, regex = implHeaderRegex) {
|
|
|
965
1396
|
let i = start;
|
|
966
1397
|
for (;i < str.length; i++) {
|
|
967
1398
|
const char = str[i];
|
|
968
|
-
if (inString) {
|
|
969
|
-
if (char === stringChar && (i === 0 || str[i - 1] !== "\\")) {
|
|
970
|
-
inString = false;
|
|
971
|
-
}
|
|
972
|
-
} else {
|
|
973
|
-
if (char === '"' || char === "'") {
|
|
974
|
-
inString = true;
|
|
975
|
-
stringChar = char;
|
|
976
|
-
} else if (char === "{") {
|
|
977
|
-
braceCount++;
|
|
978
|
-
} else if (char === "}") {
|
|
979
|
-
braceCount--;
|
|
980
|
-
if (braceCount === 0)
|
|
981
|
-
break;
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
const body = str.slice(start, i);
|
|
986
|
-
results.push({ name, body });
|
|
987
|
-
regex.lastIndex = i + 1;
|
|
988
|
-
}
|
|
989
|
-
return results;
|
|
990
|
-
}
|
|
991
|
-
function implementClass(module2, fileGroup, config) {
|
|
992
|
-
if (fileGroup.generate.length == 0 && fileGroup.scaff.length == 0) {
|
|
993
|
-
log.warn("No files to implement classes from.");
|
|
994
|
-
return false;
|
|
995
|
-
}
|
|
996
|
-
const toImpl = [];
|
|
997
|
-
for (const file of fileGroup.scaff) {
|
|
998
|
-
if (file.childs.length > 0)
|
|
999
|
-
file.childs.forEach((child) => toImpl.push({ parent: file, file: child }));
|
|
1000
|
-
}
|
|
1001
|
-
for (const file of fileGroup.generate) {
|
|
1002
|
-
if (file.childs.length > 0)
|
|
1003
|
-
file.childs.forEach((child) => toImpl.push({ parent: file, file: child }));
|
|
1004
|
-
}
|
|
1005
|
-
for (const fileImpl of toImpl) {
|
|
1006
|
-
const filePath = fileImpl.parent.isIndex ? fileImpl.parent.path : `${fileImpl.parent.path}/${fileImpl.parent.name}`;
|
|
1007
|
-
const match = parseHeader(fileImpl.file.content);
|
|
1008
|
-
const classNames = [];
|
|
1009
|
-
for (const [mIdx, m] of match.entries()) {
|
|
1010
|
-
const { name: className } = m;
|
|
1011
|
-
let { body } = m;
|
|
1012
|
-
body = convertClassMethods(body);
|
|
1013
|
-
body = convertArrowFn(body);
|
|
1014
|
-
if (!className || !body)
|
|
1015
|
-
continue;
|
|
1016
|
-
classNames.push(className);
|
|
1017
|
-
if (!module2[filePath] || !module2[filePath][className]) {
|
|
1018
|
-
let newFilePath = null;
|
|
1019
|
-
for (const file of fileGroup.scaff) {
|
|
1020
|
-
if (file.content.includes(`class ${className} {`)) {
|
|
1021
|
-
newFilePath = file.isIndex ? file.path : `${file.path}/${file.name}`;
|
|
1022
|
-
break;
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
if (!newFilePath) {
|
|
1026
|
-
for (const file of fileGroup.generate) {
|
|
1027
|
-
if (file.content.includes(`class ${className} {`)) {
|
|
1028
|
-
newFilePath = file.isIndex ? file.path : `${file.path}/${file.name}`;
|
|
1029
|
-
break;
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
if (!newFilePath) {
|
|
1034
|
-
if (config.onNotFound === "error") {
|
|
1035
|
-
log.error(`Class \x1B[33m${className}\x1B[0m not found for file \x1B[34m${fileImpl.file.name}\x1B[0m. Aborting...`);
|
|
1036
|
-
return false;
|
|
1037
|
-
} else {
|
|
1038
|
-
log.warn(`Class \x1B[33m${className}\x1B[0m not found for file \x1B[34m${fileImpl.file.name}\x1B[0m. Skipping this class...`);
|
|
1039
|
-
continue;
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
const classCloseBracket = module2[newFilePath][className].parsedStr.lastIndexOf("}");
|
|
1043
|
-
module2[newFilePath][className].parsedStr = module2[newFilePath][className].parsedStr.slice(0, classCloseBracket) + `${body.replace(`
|
|
1044
|
-
`, "")}` + (mIdx < match.length - 1 ? `
|
|
1045
|
-
|
|
1046
|
-
` : `
|
|
1047
|
-
}
|
|
1048
|
-
`);
|
|
1049
|
-
if (mIdx === match.length - 1) {
|
|
1050
|
-
for (const name of classNames) {
|
|
1051
|
-
if (!module2[filePath] || !module2[filePath][name])
|
|
1052
|
-
continue;
|
|
1053
|
-
module2[filePath][name].parsedStr += `}
|
|
1054
|
-
`;
|
|
1055
|
-
}
|
|
1056
|
-
} else
|
|
1057
|
-
classNames.splice(classNames.indexOf(className), 1);
|
|
1058
|
-
continue;
|
|
1059
|
-
} else {
|
|
1060
|
-
const classCloseBracket = module2[filePath][className].parsedStr.lastIndexOf("}");
|
|
1061
|
-
module2[filePath][className].parsedStr = module2[filePath][className].parsedStr.slice(0, classCloseBracket) + `${body.replace(`
|
|
1062
|
-
`, "")}` + (mIdx < match.length - 1 ? `
|
|
1063
|
-
|
|
1064
|
-
` : `
|
|
1065
|
-
}
|
|
1066
|
-
`);
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
return true;
|
|
1071
|
-
}
|
|
1072
|
-
// src/parser/import-module.ts
|
|
1073
|
-
function countTabsBeforeSubstring(str, sub, tabChar) {
|
|
1074
|
-
const idx = str.indexOf(sub);
|
|
1075
|
-
if (idx === -1)
|
|
1076
|
-
return -1;
|
|
1077
|
-
const lineStart = str.lastIndexOf(`
|
|
1078
|
-
`, idx - 1) + 1;
|
|
1079
|
-
const segment = str.slice(lineStart, idx);
|
|
1080
|
-
let count = 0;
|
|
1081
|
-
for (const ch of segment) {
|
|
1082
|
-
if (ch === tabChar)
|
|
1083
|
-
count++;
|
|
1084
|
-
else
|
|
1085
|
-
break;
|
|
1086
|
-
}
|
|
1087
|
-
return count;
|
|
1088
|
-
}
|
|
1089
|
-
function resolveImportPath(filePath, importPath, config) {
|
|
1090
|
-
if (!config.path)
|
|
1091
|
-
return resolvePath(`${filePath}/${importPath}`);
|
|
1092
|
-
const useWildcard = Object.keys(config.path).filter((k) => k.endsWith("*")).find((k) => importPath.startsWith(k.slice(0, -1)));
|
|
1093
|
-
if (useWildcard) {
|
|
1094
|
-
const pathAlias = config.path[useWildcard]?.replace("*", "");
|
|
1095
|
-
const dynPath = importPath.replace(useWildcard.slice(0, -2), "");
|
|
1096
|
-
if (!pathAlias) {
|
|
1097
|
-
log.error(`Path \x1B[33m${importPath}\x1B[0m not found in path aliases. Aborting...`);
|
|
1098
|
-
return "";
|
|
1099
|
-
}
|
|
1100
|
-
if (pathAlias.startsWith("~")) {
|
|
1101
|
-
return resolvePath(`${config.source}/${pathAlias.replace("~/", "").replace("~", "")}${dynPath}`);
|
|
1102
|
-
}
|
|
1103
|
-
return resolvePath(`${filePath}/${pathAlias}${dynPath}`);
|
|
1104
|
-
} else if (config.path[importPath]) {
|
|
1105
|
-
const pathAlias = config.path[importPath];
|
|
1106
|
-
if (pathAlias.startsWith("~")) {
|
|
1107
|
-
return resolvePath(`${config.source}/${pathAlias.replace("~/", "").replace("~", "")}`);
|
|
1108
|
-
}
|
|
1109
|
-
return resolvePath(`${filePath}/${pathAlias}`);
|
|
1110
|
-
}
|
|
1111
|
-
return resolvePath(`${filePath}/${importPath}`);
|
|
1112
|
-
}
|
|
1113
|
-
async function getModuleUsage(module2, fileGroup, file, config) {
|
|
1114
|
-
const matches = [...file.content.matchAll(modControlRegex)];
|
|
1115
|
-
const limit = 10;
|
|
1116
|
-
const results = [];
|
|
1117
|
-
let isInvalid = false;
|
|
1118
|
-
for (let i = 0;i < matches.length; i += limit) {
|
|
1119
|
-
const batch = matches.slice(i, i + limit);
|
|
1120
|
-
const res = await Promise.all(batch.map(async (match) => {
|
|
1121
|
-
const { cmd, mod, path: path3 } = match.groups;
|
|
1122
|
-
const res2 = {
|
|
1123
|
-
cmd: null,
|
|
1124
|
-
files: null,
|
|
1125
|
-
modList: null,
|
|
1126
|
-
targetPath: null,
|
|
1127
|
-
targetStr: ""
|
|
1128
|
-
};
|
|
1129
|
-
if (!(cmd && mod && path3)) {
|
|
1130
|
-
log.error(`Invalid module control statement: \x1B[34m${cmd} ${mod} from ${path3}\x1B[0m in \x1B[33m${file.name}\x1B[0m from \x1B[32m${file.path}\x1B[0m. Aborting...`);
|
|
1131
|
-
isInvalid = true;
|
|
1132
|
-
return null;
|
|
1133
|
-
}
|
|
1134
|
-
const fromPath = normalizePath(resolveImportPath(file.path, path3.slice(1, -1), config));
|
|
1135
|
-
const modList = {};
|
|
1136
|
-
const alias = {};
|
|
1137
|
-
if (!module2[fromPath]) {
|
|
1138
|
-
if (cmd === "include" && (mod.startsWith("{") && (mod.includes('"') || mod.includes("'")))) {
|
|
1139
|
-
const files = mod.slice(1, -1).split(",").map((m) => m.trim());
|
|
1140
|
-
const filePaths = [];
|
|
1141
|
-
for (const f of files) {
|
|
1142
|
-
const filePath = normalizePath(resolvePath(`${file.path}/${f.slice(1, -1)}`));
|
|
1143
|
-
const targetFile = fileGroup.normal.find((fl) => {
|
|
1144
|
-
let targetFile2 = `${fl.path}/${fl.name}`;
|
|
1145
|
-
let currFile = filePath;
|
|
1146
|
-
if (!targetFile2.endsWith(".gml"))
|
|
1147
|
-
targetFile2 += ".gml";
|
|
1148
|
-
if (!currFile.endsWith(".gml"))
|
|
1149
|
-
currFile += ".gml";
|
|
1150
|
-
return targetFile2 === currFile;
|
|
1151
|
-
});
|
|
1152
|
-
if (targetFile)
|
|
1153
|
-
filePaths.push(targetFile);
|
|
1154
|
-
else if (await fileExists(filePath))
|
|
1155
|
-
filePaths.push(filePath);
|
|
1156
|
-
else {
|
|
1157
|
-
if (config.onNotFound === "error") {
|
|
1158
|
-
log.error(`File \x1B[33m${f.slice(1, -1)}\x1B[0m from \x1B[32m${file.path}\x1B[0m not found. Aborting...`);
|
|
1159
|
-
isInvalid = true;
|
|
1160
|
-
return null;
|
|
1161
|
-
} else
|
|
1162
|
-
log.warn(`File \x1B[33m${f.slice(1, -1)}\x1B[0m from \x1B[32m${file.path}\x1B[0m not found. Skipping this file...`);
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
return {
|
|
1166
|
-
cmd,
|
|
1167
|
-
files: filePaths,
|
|
1168
|
-
modList,
|
|
1169
|
-
targetPath: fromPath,
|
|
1170
|
-
targetStr: match[0]
|
|
1171
|
-
};
|
|
1172
|
-
}
|
|
1173
|
-
log.error(`Path \x1B[33m${fromPath}\x1B[0m doesn't have any exported modules. Aborting...`);
|
|
1174
|
-
isInvalid = true;
|
|
1175
|
-
return null;
|
|
1176
|
-
}
|
|
1177
|
-
if (mod === "*" || mod.startsWith("{") && mod.endsWith("}")) {
|
|
1178
|
-
const targetMods = mod === "*" ? null : mod.slice(1, -1).split(",").map((m) => {
|
|
1179
|
-
const split = m.split(":");
|
|
1180
|
-
const key = split[0].trim();
|
|
1181
|
-
if (split.length === 1)
|
|
1182
|
-
alias[key] = key;
|
|
1183
|
-
else
|
|
1184
|
-
alias[key] = split[1].trim();
|
|
1185
|
-
if (!module2[fromPath]) {
|
|
1186
|
-
if (config.onNotFound === "error") {
|
|
1187
|
-
log.error(`Path \x1B[33m${fromPath}\x1B[0m doesn't have any exported modules. Aborting...`);
|
|
1188
|
-
isInvalid = true;
|
|
1189
|
-
} else
|
|
1190
|
-
log.warn(`Path \x1B[33m${fromPath}\x1B[0m doesn't have any exported modules. Skipping this module...`);
|
|
1191
|
-
return null;
|
|
1192
|
-
}
|
|
1193
|
-
if (!module2[fromPath][key]) {
|
|
1194
|
-
if (config.onNotFound === "error") {
|
|
1195
|
-
log.error(`Module \x1B[33m${key}\x1B[0m from \x1B[32m${fromPath}\x1B[0m not found. Aborting...`);
|
|
1196
|
-
isInvalid = true;
|
|
1197
|
-
} else
|
|
1198
|
-
log.warn(`Module \x1B[33m${key}\x1B[0m from \x1B[32m${fromPath}\x1B[0m not found. Skipping this module...`);
|
|
1199
|
-
return null;
|
|
1200
|
-
}
|
|
1201
|
-
return key;
|
|
1202
|
-
}).filter(Boolean);
|
|
1203
|
-
Object.entries(module2[fromPath]).forEach(([key, value]) => {
|
|
1204
|
-
if (mod === "*")
|
|
1205
|
-
modList[key] = { name: key, as: key, value, usingAlias: false };
|
|
1206
|
-
else if (targetMods.includes(key)) {
|
|
1207
|
-
const usingAlias = key in alias && alias[key] !== key;
|
|
1208
|
-
modList[alias[key] ?? key] = { name: key, as: alias[key] ?? key, value, usingAlias };
|
|
1209
|
-
if (usingAlias) {
|
|
1210
|
-
if (!module2[fromPath])
|
|
1211
|
-
module2[fromPath] = {};
|
|
1212
|
-
module2[fromPath][`@${alias[key]}`] = value;
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
});
|
|
1216
|
-
} else {
|
|
1217
|
-
if (!module2[fromPath][mod]) {
|
|
1218
|
-
if (config.onNotFound === "error") {
|
|
1219
|
-
log.error(`Module \x1B[33m${mod}\x1B[0m from \x1B[32m${fromPath}\x1B[0m not found. Aborting...`);
|
|
1220
|
-
isInvalid = true;
|
|
1221
|
-
} else
|
|
1222
|
-
log.warn(`Module \x1B[33m${mod}\x1B[0m from \x1B[32m${fromPath}\x1B[0m not found. Skipping this module...`);
|
|
1223
|
-
return res2;
|
|
1399
|
+
if (inString) {
|
|
1400
|
+
if (char === stringChar && (i === 0 || str[i - 1] !== "\\")) {
|
|
1401
|
+
inString = false;
|
|
1402
|
+
}
|
|
1403
|
+
} else {
|
|
1404
|
+
if (char === '"' || char === "'") {
|
|
1405
|
+
inString = true;
|
|
1406
|
+
stringChar = char;
|
|
1407
|
+
} else if (char === "{") {
|
|
1408
|
+
braceCount++;
|
|
1409
|
+
} else if (char === "}") {
|
|
1410
|
+
braceCount--;
|
|
1411
|
+
if (braceCount === 0)
|
|
1412
|
+
break;
|
|
1224
1413
|
}
|
|
1225
|
-
modList[mod] = { name: mod, as: mod, value: module2[fromPath][mod], usingAlias: false };
|
|
1226
1414
|
}
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
targetPath: fromPath,
|
|
1232
|
-
targetStr: match[0]
|
|
1233
|
-
};
|
|
1234
|
-
}));
|
|
1235
|
-
if (isInvalid)
|
|
1236
|
-
break;
|
|
1237
|
-
results.push(...res);
|
|
1415
|
+
}
|
|
1416
|
+
const body = str.slice(start, i);
|
|
1417
|
+
results.push({ name, body });
|
|
1418
|
+
regex.lastIndex = i + 1;
|
|
1238
1419
|
}
|
|
1239
|
-
return
|
|
1420
|
+
return results;
|
|
1240
1421
|
}
|
|
1241
|
-
|
|
1242
|
-
if (
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
return null;
|
|
1246
|
-
const toRemove = [...file.content.matchAll(modControlRegex)];
|
|
1247
|
-
for (const rm of toRemove) {
|
|
1248
|
-
if (rm.groups?.cmd !== "include")
|
|
1249
|
-
file.content = file.content.replace(rm[0], "");
|
|
1422
|
+
function implementClass(module2, fileGroup, config) {
|
|
1423
|
+
if (fileGroup.generate.length == 0 && fileGroup.scaff.length == 0) {
|
|
1424
|
+
log.warn("No files to implement classes from.");
|
|
1425
|
+
return false;
|
|
1250
1426
|
}
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
case "array":
|
|
1279
|
-
case "enum":
|
|
1280
|
-
toReplace += `
|
|
1281
|
-
`;
|
|
1282
|
-
break;
|
|
1283
|
-
}
|
|
1284
|
-
toReplace += include.value.parsedStr + `
|
|
1285
|
-
`;
|
|
1286
|
-
if (idx === modLen - 1)
|
|
1287
|
-
toReplace += `
|
|
1288
|
-
`;
|
|
1289
|
-
}
|
|
1290
|
-
file.content = file.content.replace(mod.targetStr, toReplace);
|
|
1291
|
-
} else {
|
|
1292
|
-
for (const fileOrPath of mod.files) {
|
|
1293
|
-
if (typeof fileOrPath === "string") {
|
|
1294
|
-
const content = await fsRuntime.readText(fileOrPath);
|
|
1295
|
-
toReplace += content + `
|
|
1296
|
-
|
|
1297
|
-
`;
|
|
1298
|
-
} else
|
|
1299
|
-
toReplace += fileOrPath.content + `
|
|
1300
|
-
|
|
1301
|
-
`;
|
|
1427
|
+
const toImpl = [];
|
|
1428
|
+
for (const file of fileGroup.scaff) {
|
|
1429
|
+
if (file.childs.length > 0)
|
|
1430
|
+
file.childs.forEach((child) => toImpl.push({ parent: file, file: child }));
|
|
1431
|
+
}
|
|
1432
|
+
for (const file of fileGroup.generate) {
|
|
1433
|
+
if (file.childs.length > 0)
|
|
1434
|
+
file.childs.forEach((child) => toImpl.push({ parent: file, file: child }));
|
|
1435
|
+
}
|
|
1436
|
+
for (const fileImpl of toImpl) {
|
|
1437
|
+
const filePath = fileImpl.parent.isIndex ? fileImpl.parent.path : `${fileImpl.parent.path}/${fileImpl.parent.name}`;
|
|
1438
|
+
const match = parseHeader(fileImpl.file.content);
|
|
1439
|
+
const classNames = [];
|
|
1440
|
+
for (const [mIdx, m] of match.entries()) {
|
|
1441
|
+
const { name: className } = m;
|
|
1442
|
+
let { body } = m;
|
|
1443
|
+
body = convertClassMethods(body);
|
|
1444
|
+
body = convertArrowFn(body);
|
|
1445
|
+
if (!className || !body)
|
|
1446
|
+
continue;
|
|
1447
|
+
classNames.push(className);
|
|
1448
|
+
if (!module2[filePath] || !module2[filePath][className]) {
|
|
1449
|
+
let newFilePath = null;
|
|
1450
|
+
for (const file of fileGroup.scaff) {
|
|
1451
|
+
if (file.content.includes(`class ${className} {`)) {
|
|
1452
|
+
newFilePath = file.isIndex ? file.path : `${file.path}/${file.name}`;
|
|
1453
|
+
break;
|
|
1302
1454
|
}
|
|
1303
|
-
file.content = file.content.replace(mod.targetStr, toReplace);
|
|
1304
1455
|
}
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
const useMatches = [...file.content.matchAll(useModRegex)];
|
|
1310
|
-
for (const match of cmdMatches) {
|
|
1311
|
-
const { cmd: contentCmd, mod: contentMod } = match.groups;
|
|
1312
|
-
if (!contentCmd || !contentMod) {
|
|
1313
|
-
log.error(`Invalid content module statement: \x1B[34m${contentCmd} ${contentMod}\x1B[0m in \x1B[33m${file.name}\x1B[0m from \x1B[32m${file.path}\x1B[0m. Aborting...`);
|
|
1314
|
-
return null;
|
|
1315
|
-
}
|
|
1316
|
-
if (!(`@${contentMod}` in mod.modList) && !(contentMod in mod.modList))
|
|
1317
|
-
continue;
|
|
1318
|
-
if (config.debugLevel >= 1)
|
|
1319
|
-
log.debug(`Content module statement found: \x1B[34m${contentCmd} ${contentMod}\x1B[0m in \x1B[33m${file.name === "" ? "index" : file.name}\x1B[0m from \x1B[32m${file.path}\x1B[0m.`);
|
|
1320
|
-
let parsedStr = "";
|
|
1321
|
-
switch (contentCmd) {
|
|
1322
|
-
case "content":
|
|
1323
|
-
const tabChar = config.tabType === "1t" ? "\t" : config.tabType === "2s" ? " " : " ";
|
|
1324
|
-
const tabCnt = countTabsBeforeSubstring(file.content, match[0], tabChar);
|
|
1325
|
-
parsedStr = module2[mod.targetPath][`@${contentMod}` in module2[mod.targetPath] ? `@${contentMod}` : contentMod].parsedStr;
|
|
1326
|
-
if (tabCnt > 0) {
|
|
1327
|
-
const tabLevels = getTabLevels(parsedStr, config.tabType).map((l) => l + tabCnt);
|
|
1328
|
-
file.content = file.content.replace(match[0], parsedStr.split(`
|
|
1329
|
-
`).map((l, i) => tabLevels[i] ? insertTabs(tabLevels[i], config.tabType) + l : l).join(`
|
|
1330
|
-
`));
|
|
1331
|
-
} else
|
|
1332
|
-
file.content = file.content.replace(match[0], parsedStr);
|
|
1333
|
-
break;
|
|
1334
|
-
case "nameof":
|
|
1335
|
-
parsedStr = module2[mod.targetPath][`@${contentMod}` in module2[mod.targetPath] ? `@${contentMod}` : contentMod].name;
|
|
1336
|
-
file.content = file.content.replace(`@nameof ${contentMod}`, parsedStr);
|
|
1337
|
-
break;
|
|
1338
|
-
case "typeof":
|
|
1339
|
-
parsedStr = module2[mod.targetPath][`@${contentMod}` in module2[mod.targetPath] ? `@${contentMod}` : contentMod].type;
|
|
1340
|
-
file.content = file.content.replace(`@typeof ${contentMod}`, `"${parsedStr}"`);
|
|
1341
|
-
break;
|
|
1342
|
-
case "valueof":
|
|
1343
|
-
parsedStr = module2[mod.targetPath][`@${contentMod}` in module2[mod.targetPath] ? `@${contentMod}` : contentMod].value;
|
|
1344
|
-
file.content = file.content.replace(`@valueof ${contentMod}`, parsedStr);
|
|
1456
|
+
if (!newFilePath) {
|
|
1457
|
+
for (const file of fileGroup.generate) {
|
|
1458
|
+
if (file.content.includes(`class ${className} {`)) {
|
|
1459
|
+
newFilePath = file.isIndex ? file.path : `${file.path}/${file.name}`;
|
|
1345
1460
|
break;
|
|
1461
|
+
}
|
|
1346
1462
|
}
|
|
1347
1463
|
}
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
if (config.debugLevel >= 1)
|
|
1355
|
-
log.debug(`Valueof module statement found: \x1B[34m${contentMod}\x1B[0m in \x1B[33m${file.name}\x1B[0m from \x1B[32m${file.path}\x1B[0m.`);
|
|
1356
|
-
if (!(`@${contentMod}` in mod.modList) && !(contentMod in mod.modList))
|
|
1357
|
-
continue;
|
|
1358
|
-
const parsedStr = module2[mod.targetPath][`@${contentMod}` in module2[mod.targetPath] ? `@${contentMod}` : contentMod].value;
|
|
1359
|
-
file.content = file.content.replace(`@:${contentMod}`, parsedStr);
|
|
1360
|
-
}
|
|
1361
|
-
for (const match of useMatches) {
|
|
1362
|
-
const { mod: contentMod, body } = match.groups;
|
|
1363
|
-
if (!contentMod || !body) {
|
|
1364
|
-
log.error(`Invalid content module statement: \x1B[34m@use ${contentMod} ${body}\x1B[0m in \x1B[33m${file.name}\x1B[0m from \x1B[32m${file.path}\x1B[0m. Aborting...`);
|
|
1365
|
-
return null;
|
|
1366
|
-
}
|
|
1367
|
-
if (!(`@${contentMod}` in mod.modList) && !(contentMod in mod.modList))
|
|
1464
|
+
if (!newFilePath) {
|
|
1465
|
+
if (config.onNotFound === "error") {
|
|
1466
|
+
log.error(`Class \x1B[33m${className}\x1B[0m not found for file \x1B[34m${fileImpl.file.name}\x1B[0m. Aborting...`);
|
|
1467
|
+
return false;
|
|
1468
|
+
} else {
|
|
1469
|
+
log.warn(`Class \x1B[33m${className}\x1B[0m not found for file \x1B[34m${fileImpl.file.name}\x1B[0m. Skipping this class...`);
|
|
1368
1470
|
continue;
|
|
1369
|
-
if (config.debugLevel >= 1)
|
|
1370
|
-
log.debug(`Use module statement found: \x1B[34m@use ${contentMod} ${body}\x1B[0m in \x1B[33m${file.name}\x1B[0m from \x1B[32m${file.path}\x1B[0m.`);
|
|
1371
|
-
const lines = body.slice(1, -1).split(`
|
|
1372
|
-
`).filter(Boolean);
|
|
1373
|
-
const pairs = lines.map((l) => l.split(":").map((p) => {
|
|
1374
|
-
const delimIdx = p.lastIndexOf(",");
|
|
1375
|
-
return p.slice(0, delimIdx === -1 ? undefined : delimIdx).trim();
|
|
1376
|
-
}));
|
|
1377
|
-
const tabChar = config.tabType === "1t" ? "\t" : config.tabType === "2s" ? " " : " ";
|
|
1378
|
-
const tabCnt = countTabsBeforeSubstring(file.content.slice(file.content.lastIndexOf(`
|
|
1379
|
-
`, match.index), match.index + match[0].length), "@", tabChar);
|
|
1380
|
-
const tabLevels = getTabLevels(body, config.tabType).map((l) => l + tabCnt);
|
|
1381
|
-
const currMod = module2[mod.targetPath][`@${contentMod}` in module2[mod.targetPath] ? `@${contentMod}` : contentMod];
|
|
1382
|
-
const modMember = Object.entries(currMod.member);
|
|
1383
|
-
const tabLevel = tabCnt + tabLevels[Math.min(1, tabLevels.length - 1)];
|
|
1384
|
-
let res = `{
|
|
1385
|
-
`;
|
|
1386
|
-
for (const [idx, [mName, mVal]] of modMember.entries()) {
|
|
1387
|
-
const pairIdx = pairs.findIndex((p) => p[0] === mName);
|
|
1388
|
-
const pair = pairIdx > -1 ? pairs[pairIdx] : null;
|
|
1389
|
-
const value = pair ? pair.length === 2 ? pair[1] : mVal.value : mVal.value;
|
|
1390
|
-
if (value) {
|
|
1391
|
-
res += `${insertTabs(tabLevel, config.tabType)}${mName}: ${value}${idx < modMember.length - 2 ? "," : ""}
|
|
1392
|
-
`;
|
|
1393
|
-
}
|
|
1394
|
-
if (pairIdx > -1)
|
|
1395
|
-
swapAndPop(pairs, pairIdx);
|
|
1396
1471
|
}
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1472
|
+
}
|
|
1473
|
+
const classCloseBracket = module2[newFilePath][className].parsedStr.lastIndexOf("}");
|
|
1474
|
+
module2[newFilePath][className].parsedStr = module2[newFilePath][className].parsedStr.slice(0, classCloseBracket) + `${body.replace(`
|
|
1475
|
+
`, "")}` + (mIdx < match.length - 1 ? `
|
|
1476
|
+
|
|
1477
|
+
` : `
|
|
1478
|
+
}
|
|
1479
|
+
`);
|
|
1480
|
+
if (mIdx === match.length - 1) {
|
|
1481
|
+
for (const name of classNames) {
|
|
1482
|
+
if (!module2[filePath] || !module2[filePath][name])
|
|
1483
|
+
continue;
|
|
1484
|
+
module2[filePath][name].parsedStr += `}
|
|
1402
1485
|
`;
|
|
1403
1486
|
}
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1487
|
+
} else
|
|
1488
|
+
classNames.splice(classNames.indexOf(className), 1);
|
|
1489
|
+
continue;
|
|
1490
|
+
} else {
|
|
1491
|
+
const classCloseBracket = module2[filePath][className].parsedStr.lastIndexOf("}");
|
|
1492
|
+
module2[filePath][className].parsedStr = module2[filePath][className].parsedStr.slice(0, classCloseBracket) + `${body.replace(`
|
|
1493
|
+
`, "")}` + (mIdx < match.length - 1 ? `
|
|
1494
|
+
|
|
1495
|
+
` : `
|
|
1496
|
+
}
|
|
1497
|
+
`);
|
|
1498
|
+
}
|
|
1408
1499
|
}
|
|
1409
|
-
file.content = file.content.trim() + `
|
|
1410
|
-
`;
|
|
1411
1500
|
}
|
|
1412
|
-
return
|
|
1501
|
+
return true;
|
|
1413
1502
|
}
|
|
1414
1503
|
// types/gm-event.ts
|
|
1415
1504
|
var EVENT = {
|
|
@@ -2370,6 +2459,9 @@ async function main() {
|
|
|
2370
2459
|
return;
|
|
2371
2460
|
log.debug("Classes implemented successfully.");
|
|
2372
2461
|
log.debug("Implementing modules...");
|
|
2462
|
+
for (const file of files) {
|
|
2463
|
+
reexportModule(module2, file, config);
|
|
2464
|
+
}
|
|
2373
2465
|
const implMods = [];
|
|
2374
2466
|
for (const file of files) {
|
|
2375
2467
|
const mod = await implementModules(module2, fileGroup, file, config);
|