@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.
Files changed (2) hide show
  1. package/dist/index.cjs +524 -432
  2. 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 = /\/\/[^\n]*|\/\*(?!\*)[\s\S]*?\*\//g;
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.1",
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
- return {
1228
- cmd,
1229
- files: null,
1230
- modList,
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 !isInvalid && results.every((r) => r) ? results : null;
1420
+ return results;
1240
1421
  }
1241
- async function implementModules(module2, fileGroup, file, config, mods) {
1242
- if (!mods)
1243
- mods = await getModuleUsage(module2, fileGroup, file, config);
1244
- if (!mods)
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
- for (const mod of mods) {
1252
- if (!mod)
1253
- return null;
1254
- if (!mod.cmd)
1255
- return null;
1256
- switch (mod.cmd) {
1257
- case "export":
1258
- const thisPath = file.isIndex ? file.path : `${file.path}/${file.name}`;
1259
- if (!module2[thisPath])
1260
- module2[thisPath] = {};
1261
- Object.entries(mod.modList).forEach(([_, value]) => {
1262
- module2[thisPath][value.as] = value.value;
1263
- });
1264
- break;
1265
- case "include":
1266
- let toReplace = "";
1267
- if (!mod.files) {
1268
- if (!mod.modList)
1269
- return null;
1270
- const modEntries = Object.entries(mod.modList);
1271
- const modLen = modEntries.length;
1272
- const modIterator = modEntries.entries();
1273
- for (const [idx, [_, include]] of modIterator) {
1274
- if (idx > 0)
1275
- switch (include.value.type) {
1276
- case "object":
1277
- case "method":
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
- break;
1306
- case "import":
1307
- const cmdMatches = [...file.content.matchAll(contentModRegex)];
1308
- const shortCmdMatches = [...file.content.matchAll(contentModShortRegex)];
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
- for (const match of shortCmdMatches) {
1349
- const { mod: contentMod } = match.groups;
1350
- if (!contentMod) {
1351
- 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...`);
1352
- return null;
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
- for (const [idx, pair] of pairs.entries()) {
1398
- if (idx === 0)
1399
- res = res.slice(0, -1) + `,
1400
- `;
1401
- res += `${insertTabs(tabLevel, config.tabType)}${pair[0]}: ${pair[1]}${idx < pairs.length - 1 ? "," : ""}
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
- res += insertTabs(tabCnt, config.tabType) + "}";
1405
- file.content = file.content.replace(match[0], res);
1406
- }
1407
- break;
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 mods;
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scaffscript/core",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/undervolta/scaffscript"