@cmssy/cli 12.12.0 → 12.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/init/eslint.config.mjs +3 -0
- package/dist/index.js +353 -46
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -603,14 +603,281 @@ function runAddBlock(options, deps) {
|
|
|
603
603
|
|
|
604
604
|
// src/init.ts
|
|
605
605
|
import {
|
|
606
|
-
copyFileSync,
|
|
607
|
-
existsSync as
|
|
606
|
+
copyFileSync as copyFileSync2,
|
|
607
|
+
existsSync as existsSync4,
|
|
608
608
|
mkdirSync as mkdirSync2,
|
|
609
|
-
readFileSync as
|
|
610
|
-
writeFileSync as
|
|
609
|
+
readFileSync as readFileSync4,
|
|
610
|
+
writeFileSync as writeFileSync3
|
|
611
611
|
} from "fs";
|
|
612
|
-
import { dirname as dirname2, join as
|
|
612
|
+
import { dirname as dirname2, join as join4, resolve as resolve2 } from "path";
|
|
613
613
|
import { fileURLToPath } from "url";
|
|
614
|
+
|
|
615
|
+
// src/eslint-config.ts
|
|
616
|
+
import { copyFileSync, existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
617
|
+
import { join as join3 } from "path";
|
|
618
|
+
var ESLINT_PLUGIN = "@cmssy/eslint-plugin";
|
|
619
|
+
var ESLINT_CONFIG_FILE = "eslint.config.mjs";
|
|
620
|
+
var ESLINT_PURPOSE = "the two wiring mistakes no build catches: server config pulled into a client bundle, and a provider the /cmssy-edit route never gets";
|
|
621
|
+
var FLAT_CONFIGS = [
|
|
622
|
+
"eslint.config.js",
|
|
623
|
+
"eslint.config.mjs",
|
|
624
|
+
"eslint.config.cjs",
|
|
625
|
+
"eslint.config.ts",
|
|
626
|
+
"eslint.config.mts",
|
|
627
|
+
"eslint.config.cts"
|
|
628
|
+
];
|
|
629
|
+
var LEGACY_CONFIGS = [
|
|
630
|
+
".eslintrc.js",
|
|
631
|
+
".eslintrc.cjs",
|
|
632
|
+
".eslintrc.mjs",
|
|
633
|
+
".eslintrc.json",
|
|
634
|
+
".eslintrc.yml",
|
|
635
|
+
".eslintrc.yaml",
|
|
636
|
+
".eslintrc"
|
|
637
|
+
];
|
|
638
|
+
var SPREAD = "...cmssy.configs.recommended";
|
|
639
|
+
var IMPORT_LINE = `import cmssy from "${ESLINT_PLUGIN}";`;
|
|
640
|
+
var STANDALONE_SNIPPET = `${IMPORT_LINE}
|
|
641
|
+
export default [...cmssy.configs.standalone];`;
|
|
642
|
+
var APPEND_SNIPPET = `${IMPORT_LINE}
|
|
643
|
+
export default [...yourConfig, ${SPREAD}];`;
|
|
644
|
+
var REQUIRE_SNIPPET = `const cmssy = require("${ESLINT_PLUGIN}");
|
|
645
|
+
module.exports = [...yourConfig, ${SPREAD}];`;
|
|
646
|
+
var INLINE_STANDALONE = `an ${ESLINT_CONFIG_FILE} of \`${IMPORT_LINE} export default [...cmssy.configs.standalone];\``;
|
|
647
|
+
var BUILDERS = /* @__PURE__ */ new Set([
|
|
648
|
+
"config",
|
|
649
|
+
"defineConfig",
|
|
650
|
+
"defineFlatConfig",
|
|
651
|
+
"tseslint.config"
|
|
652
|
+
]);
|
|
653
|
+
var WIRED = /(?:import|require)[\s\S]{0,200}?["']@cmssy\/eslint-plugin["']/;
|
|
654
|
+
var RULES = "cmssy/edit-route-provider-parity and cmssy/no-server-config-in-client";
|
|
655
|
+
function describeExpression(expression) {
|
|
656
|
+
const stack = [];
|
|
657
|
+
const pairs = { ")": "(", "]": "[", "}": "{" };
|
|
658
|
+
let closed = -1;
|
|
659
|
+
for (let i = 0; i < expression.length; i += 1) {
|
|
660
|
+
const char = expression[i];
|
|
661
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
662
|
+
i += 1;
|
|
663
|
+
while (i < expression.length && expression[i] !== char) {
|
|
664
|
+
if (expression[i] === "\\") i += 1;
|
|
665
|
+
i += 1;
|
|
666
|
+
}
|
|
667
|
+
if (i >= expression.length) return { balanced: false, single: false };
|
|
668
|
+
continue;
|
|
669
|
+
}
|
|
670
|
+
if (char === "/" && expression[i + 1] === "/") {
|
|
671
|
+
while (i < expression.length && expression[i] !== "\n") i += 1;
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
if (char === "/" && expression[i + 1] === "*") {
|
|
675
|
+
i += 2;
|
|
676
|
+
while (i < expression.length && !(expression[i] === "*" && expression[i + 1] === "/")) {
|
|
677
|
+
i += 1;
|
|
678
|
+
}
|
|
679
|
+
if (i >= expression.length) return { balanced: false, single: false };
|
|
680
|
+
i += 1;
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
if (char === "(" || char === "[" || char === "{") {
|
|
684
|
+
stack.push(char);
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
if (char === ")" || char === "]" || char === "}") {
|
|
688
|
+
if (stack.pop() !== pairs[char])
|
|
689
|
+
return { balanced: false, single: false };
|
|
690
|
+
if (stack.length === 0) closed = i;
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
if (char === ";" && stack.length === 0) {
|
|
694
|
+
return { balanced: false, single: false };
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
return {
|
|
698
|
+
balanced: stack.length === 0,
|
|
699
|
+
single: closed === expression.length - 1
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
function indentOf(inner) {
|
|
703
|
+
return /\n([ \t]+)\S/.exec(inner)?.[1] ?? " ";
|
|
704
|
+
}
|
|
705
|
+
function appendItem(inner) {
|
|
706
|
+
if (inner.trim() === "") return `
|
|
707
|
+
${SPREAD},
|
|
708
|
+
`;
|
|
709
|
+
if (!inner.includes("\n")) {
|
|
710
|
+
return `${inner.replace(/,\s*$/, "")}, ${SPREAD}`;
|
|
711
|
+
}
|
|
712
|
+
const body = inner.replace(/\s+$/, "");
|
|
713
|
+
const close = /\n([ \t]*)$/.exec(inner);
|
|
714
|
+
const item = `${body}${body.endsWith(",") ? "" : ","}
|
|
715
|
+
${indentOf(inner)}${SPREAD}`;
|
|
716
|
+
return close ? `${item},
|
|
717
|
+
${close[1]}` : item;
|
|
718
|
+
}
|
|
719
|
+
function patchExpression(expression) {
|
|
720
|
+
const shape = describeExpression(expression);
|
|
721
|
+
if (!shape.balanced) return null;
|
|
722
|
+
if (expression.startsWith("[") && expression.endsWith("]") && shape.single) {
|
|
723
|
+
return `[${appendItem(expression.slice(1, -1))}]`;
|
|
724
|
+
}
|
|
725
|
+
const call = /^([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\(([\s\S]*)\)$/.exec(
|
|
726
|
+
expression
|
|
727
|
+
);
|
|
728
|
+
if (call && shape.single && BUILDERS.has(call[1])) {
|
|
729
|
+
const args = call[2];
|
|
730
|
+
const only = args.trim();
|
|
731
|
+
if (only.startsWith("[") && only.endsWith("]")) {
|
|
732
|
+
const inner = patchExpression(only);
|
|
733
|
+
if (inner) return `${call[1]}(${inner})`;
|
|
734
|
+
}
|
|
735
|
+
return `${call[1]}(${appendItem(args)})`;
|
|
736
|
+
}
|
|
737
|
+
return `[...${expression}, ${SPREAD}]`;
|
|
738
|
+
}
|
|
739
|
+
function insertImport(source) {
|
|
740
|
+
const lines = source.split("\n");
|
|
741
|
+
let at = 0;
|
|
742
|
+
let block = false;
|
|
743
|
+
for (; at < lines.length; at += 1) {
|
|
744
|
+
const line = lines[at].trim();
|
|
745
|
+
if (block) {
|
|
746
|
+
if (line.includes("*/")) block = false;
|
|
747
|
+
continue;
|
|
748
|
+
}
|
|
749
|
+
if (line === "" || line.startsWith("//") || line.startsWith("#!")) continue;
|
|
750
|
+
if (line.startsWith("/*")) {
|
|
751
|
+
block = !line.includes("*/");
|
|
752
|
+
continue;
|
|
753
|
+
}
|
|
754
|
+
break;
|
|
755
|
+
}
|
|
756
|
+
const next = lines[at] ?? "";
|
|
757
|
+
const spacer = next.trim() === "" || next.startsWith("import ") ? [] : [""];
|
|
758
|
+
lines.splice(at, 0, IMPORT_LINE, ...spacer);
|
|
759
|
+
return lines.join("\n");
|
|
760
|
+
}
|
|
761
|
+
function patchFlatConfig(source) {
|
|
762
|
+
const exports = [...source.matchAll(/^export default\b/gm)];
|
|
763
|
+
const last = exports.at(-1);
|
|
764
|
+
if (last?.index === void 0) return null;
|
|
765
|
+
const head = source.slice(0, last.index);
|
|
766
|
+
const expression = source.slice(last.index + "export default".length).trim().replace(/;$/, "").trimEnd();
|
|
767
|
+
if (expression === "") return null;
|
|
768
|
+
const patched = patchExpression(expression);
|
|
769
|
+
if (!patched) return null;
|
|
770
|
+
const result = insertImport(`${head}export default ${patched};
|
|
771
|
+
`);
|
|
772
|
+
if (!result.includes(SPREAD)) return null;
|
|
773
|
+
return result;
|
|
774
|
+
}
|
|
775
|
+
function withoutComments(source) {
|
|
776
|
+
let out = "";
|
|
777
|
+
for (let i = 0; i < source.length; i += 1) {
|
|
778
|
+
const char = source[i];
|
|
779
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
780
|
+
out += char;
|
|
781
|
+
i += 1;
|
|
782
|
+
while (i < source.length && source[i] !== char) {
|
|
783
|
+
if (source[i] === "\\") {
|
|
784
|
+
out += source[i];
|
|
785
|
+
i += 1;
|
|
786
|
+
}
|
|
787
|
+
out += source[i] ?? "";
|
|
788
|
+
i += 1;
|
|
789
|
+
}
|
|
790
|
+
out += source[i] ?? "";
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
793
|
+
if (char === "/" && source[i + 1] === "/") {
|
|
794
|
+
while (i < source.length && source[i] !== "\n") i += 1;
|
|
795
|
+
out += "\n";
|
|
796
|
+
continue;
|
|
797
|
+
}
|
|
798
|
+
if (char === "/" && source[i + 1] === "*") {
|
|
799
|
+
i += 2;
|
|
800
|
+
while (i < source.length && !(source[i] === "*" && source[i + 1] === "/")) {
|
|
801
|
+
i += 1;
|
|
802
|
+
}
|
|
803
|
+
i += 1;
|
|
804
|
+
continue;
|
|
805
|
+
}
|
|
806
|
+
out += char;
|
|
807
|
+
}
|
|
808
|
+
return out;
|
|
809
|
+
}
|
|
810
|
+
function findFile(root, names) {
|
|
811
|
+
return names.find((name) => existsSync3(join3(root, name)));
|
|
812
|
+
}
|
|
813
|
+
function wireEslintConfig(root, pkg, asset) {
|
|
814
|
+
const flat = findFile(root, FLAT_CONFIGS);
|
|
815
|
+
const legacy = findFile(root, LEGACY_CONFIGS);
|
|
816
|
+
const installed = pkg.dependencies?.eslint !== void 0 || pkg.devDependencies?.eslint !== void 0;
|
|
817
|
+
if (!flat && legacy) {
|
|
818
|
+
return {
|
|
819
|
+
dependency: true,
|
|
820
|
+
notes: [
|
|
821
|
+
{
|
|
822
|
+
status: "fail",
|
|
823
|
+
message: `${legacy} is the legacy eslintrc format, so ${RULES} were not wired`,
|
|
824
|
+
fix: `migrate to flat config (an eslint.config.mjs) and add:
|
|
825
|
+
${STANDALONE_SNIPPET}`
|
|
826
|
+
}
|
|
827
|
+
]
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
if (!flat && !installed) {
|
|
831
|
+
return {
|
|
832
|
+
dependency: false,
|
|
833
|
+
notes: [
|
|
834
|
+
{
|
|
835
|
+
status: "unknown",
|
|
836
|
+
message: `this app has no eslint, so ${RULES} were not wired - they are the only check for a provider the editor route never gets; install eslint and rerun, or write ${INLINE_STANDALONE} yourself`
|
|
837
|
+
}
|
|
838
|
+
]
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
if (!flat) {
|
|
842
|
+
copyFileSync(asset, join3(root, ESLINT_CONFIG_FILE));
|
|
843
|
+
return { written: ESLINT_CONFIG_FILE, dependency: true, notes: [] };
|
|
844
|
+
}
|
|
845
|
+
const source = readFileSync3(join3(root, flat), "utf8");
|
|
846
|
+
if (WIRED.test(withoutComments(source))) {
|
|
847
|
+
return { dependency: true, notes: [] };
|
|
848
|
+
}
|
|
849
|
+
if (flat.endsWith(".cjs") || /\bmodule\.exports\b/.test(source)) {
|
|
850
|
+
return {
|
|
851
|
+
dependency: true,
|
|
852
|
+
notes: [
|
|
853
|
+
{
|
|
854
|
+
status: "fail",
|
|
855
|
+
message: `${flat} is CommonJS, so ${RULES} were not wired - it was left untouched`,
|
|
856
|
+
fix: `add them yourself:
|
|
857
|
+
${REQUIRE_SNIPPET}`
|
|
858
|
+
}
|
|
859
|
+
]
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
const patched = patchFlatConfig(source);
|
|
863
|
+
if (!patched) {
|
|
864
|
+
return {
|
|
865
|
+
dependency: true,
|
|
866
|
+
notes: [
|
|
867
|
+
{
|
|
868
|
+
status: "fail",
|
|
869
|
+
message: `${flat} has no default export this can extend, so ${RULES} were not wired - it was left untouched`,
|
|
870
|
+
fix: `add them yourself:
|
|
871
|
+
${APPEND_SNIPPET}`
|
|
872
|
+
}
|
|
873
|
+
]
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
writeFileSync2(join3(root, flat), patched);
|
|
877
|
+
return { patched: flat, dependency: true, notes: [] };
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// src/init.ts
|
|
614
881
|
var ASSETS_DIR = fileURLToPath(new URL("../assets/init", import.meta.url));
|
|
615
882
|
var CLI_PACKAGE_JSON = fileURLToPath(
|
|
616
883
|
new URL("../package.json", import.meta.url)
|
|
@@ -635,40 +902,53 @@ function frameworkFiles(framework, root) {
|
|
|
635
902
|
return files;
|
|
636
903
|
}
|
|
637
904
|
function cliVersion() {
|
|
638
|
-
const pkg = JSON.parse(
|
|
905
|
+
const pkg = JSON.parse(readFileSync4(CLI_PACKAGE_JSON, "utf8"));
|
|
639
906
|
return pkg.version;
|
|
640
907
|
}
|
|
641
|
-
function
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
(name) => present[name] === void 0
|
|
908
|
+
function sortedEntries(entries) {
|
|
909
|
+
return Object.fromEntries(
|
|
910
|
+
Object.entries(entries).sort(([a], [b]) => a.localeCompare(b))
|
|
645
911
|
);
|
|
646
|
-
|
|
912
|
+
}
|
|
913
|
+
function addDependencies(root, pkg, framework, development) {
|
|
914
|
+
const present = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
915
|
+
const absent = (name) => present[name] === void 0;
|
|
916
|
+
const missing = framework.dependencies.filter(absent);
|
|
917
|
+
const missingDev = development.filter(absent);
|
|
918
|
+
if (missing.length === 0 && missingDev.length === 0) return [];
|
|
647
919
|
const range = `^${cliVersion()}`;
|
|
648
|
-
const
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
920
|
+
const pinned = (names) => Object.fromEntries(names.map((name) => [name, range]));
|
|
921
|
+
if (missing.length > 0) {
|
|
922
|
+
pkg.dependencies = sortedEntries({
|
|
923
|
+
...pkg.dependencies,
|
|
924
|
+
...pinned(missing)
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
if (missingDev.length > 0) {
|
|
928
|
+
pkg.devDependencies = sortedEntries({
|
|
929
|
+
...pkg.devDependencies,
|
|
930
|
+
...pinned(missingDev)
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
writeFileSync3(
|
|
934
|
+
join4(root, "package.json"),
|
|
655
935
|
`${JSON.stringify(pkg, null, 2)}
|
|
656
936
|
`
|
|
657
937
|
);
|
|
658
|
-
return missing.map((name) => `${name}@${range}`);
|
|
938
|
+
return [...missing, ...missingDev].map((name) => `${name}@${range}`);
|
|
659
939
|
}
|
|
660
940
|
function detectInstallCommand(root) {
|
|
661
|
-
if (
|
|
941
|
+
if (existsSync4(join4(root, "pnpm-lock.yaml")) || existsSync4(join4(root, "pnpm-workspace.yaml"))) {
|
|
662
942
|
return "pnpm install";
|
|
663
943
|
}
|
|
664
|
-
if (
|
|
665
|
-
if (
|
|
944
|
+
if (existsSync4(join4(root, "yarn.lock"))) return "yarn";
|
|
945
|
+
if (existsSync4(join4(root, "bun.lock")) || existsSync4(join4(root, "bun.lockb"))) {
|
|
666
946
|
return "bun install";
|
|
667
947
|
}
|
|
668
948
|
return "npm install";
|
|
669
949
|
}
|
|
670
950
|
function existingFile(root, base) {
|
|
671
|
-
return ["tsx", "ts", "jsx", "js"].map((extension) => `${base}.${extension}`).find((candidate) =>
|
|
951
|
+
return ["tsx", "ts", "jsx", "js"].map((extension) => `${base}.${extension}`).find((candidate) => existsSync4(join4(root, candidate)));
|
|
672
952
|
}
|
|
673
953
|
function frameworkNotes(framework, root, skipped) {
|
|
674
954
|
const notes = [];
|
|
@@ -703,7 +983,7 @@ function frameworkNotes(framework, root, skipped) {
|
|
|
703
983
|
status: "unknown",
|
|
704
984
|
message: "the cmssy wiring needs the React integration and a server adapter - run: npx astro add react node"
|
|
705
985
|
});
|
|
706
|
-
if (
|
|
986
|
+
if (existsSync4(join4(root, "src/pages/index.astro"))) {
|
|
707
987
|
notes.push({
|
|
708
988
|
status: "unknown",
|
|
709
989
|
message: "src/pages/index.astro shadows the cmssy catch-all for / - delete it and the cmssy page serves /"
|
|
@@ -728,7 +1008,7 @@ function runInit(options, deps) {
|
|
|
728
1008
|
const { log } = deps;
|
|
729
1009
|
try {
|
|
730
1010
|
const root = resolve2(deps.cwd, options.dir ?? ".");
|
|
731
|
-
if (!
|
|
1011
|
+
if (!existsSync4(root)) {
|
|
732
1012
|
throw new CliError(
|
|
733
1013
|
`${root} does not exist`,
|
|
734
1014
|
"pass --dir with the app's directory, or run cmssy init inside it"
|
|
@@ -745,8 +1025,8 @@ function runInit(options, deps) {
|
|
|
745
1025
|
const written = [];
|
|
746
1026
|
const skipped = [];
|
|
747
1027
|
for (const file of frameworkFiles(framework, root)) {
|
|
748
|
-
const target =
|
|
749
|
-
if (
|
|
1028
|
+
const target = join4(root, file.target);
|
|
1029
|
+
if (existsSync4(target) && !options.force) {
|
|
750
1030
|
skipped.push(file.target);
|
|
751
1031
|
log(
|
|
752
1032
|
formatResult({
|
|
@@ -757,12 +1037,36 @@ function runInit(options, deps) {
|
|
|
757
1037
|
continue;
|
|
758
1038
|
}
|
|
759
1039
|
mkdirSync2(dirname2(target), { recursive: true });
|
|
760
|
-
|
|
1040
|
+
copyFileSync2(join4(ASSETS_DIR, framework.name, file.asset), target);
|
|
761
1041
|
written.push(file.target);
|
|
762
1042
|
log(formatResult({ status: "ok", message: `wrote ${file.target}` }));
|
|
763
1043
|
log(` ${file.purpose}`);
|
|
764
1044
|
}
|
|
765
|
-
const
|
|
1045
|
+
const eslint = wireEslintConfig(
|
|
1046
|
+
root,
|
|
1047
|
+
pkg,
|
|
1048
|
+
join4(ASSETS_DIR, ESLINT_CONFIG_FILE)
|
|
1049
|
+
);
|
|
1050
|
+
if (eslint.written) {
|
|
1051
|
+
written.push(eslint.written);
|
|
1052
|
+
log(formatResult({ status: "ok", message: `wrote ${eslint.written}` }));
|
|
1053
|
+
log(` ${ESLINT_PURPOSE}`);
|
|
1054
|
+
}
|
|
1055
|
+
if (eslint.patched) {
|
|
1056
|
+
log(
|
|
1057
|
+
formatResult({
|
|
1058
|
+
status: "ok",
|
|
1059
|
+
message: `wired ${ESLINT_PLUGIN} into ${eslint.patched}`
|
|
1060
|
+
})
|
|
1061
|
+
);
|
|
1062
|
+
log(` ${ESLINT_PURPOSE}`);
|
|
1063
|
+
}
|
|
1064
|
+
const added = addDependencies(
|
|
1065
|
+
root,
|
|
1066
|
+
pkg,
|
|
1067
|
+
framework,
|
|
1068
|
+
eslint.dependency ? [ESLINT_PLUGIN] : []
|
|
1069
|
+
);
|
|
766
1070
|
if (added.length > 0) {
|
|
767
1071
|
log(
|
|
768
1072
|
formatResult({
|
|
@@ -771,7 +1075,10 @@ function runInit(options, deps) {
|
|
|
771
1075
|
})
|
|
772
1076
|
);
|
|
773
1077
|
}
|
|
774
|
-
for (const note of
|
|
1078
|
+
for (const note of [
|
|
1079
|
+
...frameworkNotes(framework, root, skipped),
|
|
1080
|
+
...eslint.notes
|
|
1081
|
+
]) {
|
|
775
1082
|
log(formatResult(note));
|
|
776
1083
|
}
|
|
777
1084
|
log("");
|
|
@@ -814,8 +1121,8 @@ function runInit(options, deps) {
|
|
|
814
1121
|
}
|
|
815
1122
|
|
|
816
1123
|
// src/link.ts
|
|
817
|
-
import { existsSync as
|
|
818
|
-
import { join as
|
|
1124
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
1125
|
+
import { join as join6 } from "path";
|
|
819
1126
|
import {
|
|
820
1127
|
buildEditorUrl,
|
|
821
1128
|
checkDraftSecret,
|
|
@@ -823,8 +1130,8 @@ import {
|
|
|
823
1130
|
} from "@cmssy/core/preflight";
|
|
824
1131
|
|
|
825
1132
|
// src/env-load.ts
|
|
826
|
-
import { existsSync as
|
|
827
|
-
import { join as
|
|
1133
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
1134
|
+
import { join as join5 } from "path";
|
|
828
1135
|
|
|
829
1136
|
// src/env-file.ts
|
|
830
1137
|
function parseEnvFile(content) {
|
|
@@ -863,9 +1170,9 @@ function applyEnv(vars, env) {
|
|
|
863
1170
|
var ENV_FILES = [".env.local", ".env"];
|
|
864
1171
|
function loadEnvFiles(cwd, env) {
|
|
865
1172
|
for (const file of ENV_FILES) {
|
|
866
|
-
const path =
|
|
867
|
-
if (!
|
|
868
|
-
applyEnv(parseEnvFile(
|
|
1173
|
+
const path = join5(cwd, file);
|
|
1174
|
+
if (!existsSync5(path)) continue;
|
|
1175
|
+
applyEnv(parseEnvFile(readFileSync5(path, "utf8")), env);
|
|
869
1176
|
}
|
|
870
1177
|
}
|
|
871
1178
|
|
|
@@ -1042,9 +1349,9 @@ function resolvePreviewUrl(options) {
|
|
|
1042
1349
|
return origin;
|
|
1043
1350
|
}
|
|
1044
1351
|
function writeEnvLocal(cwd, updates) {
|
|
1045
|
-
const path =
|
|
1046
|
-
const existing =
|
|
1047
|
-
|
|
1352
|
+
const path = join6(cwd, ".env.local");
|
|
1353
|
+
const existing = existsSync6(path) ? readFileSync6(path, "utf8") : null;
|
|
1354
|
+
writeFileSync4(path, mergeEnvContent(existing, updates));
|
|
1048
1355
|
}
|
|
1049
1356
|
async function runLink(options, deps) {
|
|
1050
1357
|
const { cwd, env, log } = deps;
|
|
@@ -1158,7 +1465,7 @@ async function runLink(options, deps) {
|
|
|
1158
1465
|
}
|
|
1159
1466
|
|
|
1160
1467
|
// src/types-command.ts
|
|
1161
|
-
import { mkdirSync as mkdirSync3, readFileSync as
|
|
1468
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync7, readdirSync, writeFileSync as writeFileSync5 } from "fs";
|
|
1162
1469
|
import { dirname as dirname3, relative, resolve as resolvePath } from "path";
|
|
1163
1470
|
import { DEFAULT_CMSSY_API_URL } from "@cmssy/core";
|
|
1164
1471
|
|
|
@@ -1502,7 +1809,7 @@ function existingOperationNames(cwd, skipPath) {
|
|
|
1502
1809
|
if (full === skipPath) continue;
|
|
1503
1810
|
let source;
|
|
1504
1811
|
try {
|
|
1505
|
-
source =
|
|
1812
|
+
source = readFileSync7(full, "utf8");
|
|
1506
1813
|
} catch {
|
|
1507
1814
|
continue;
|
|
1508
1815
|
}
|
|
@@ -1522,7 +1829,7 @@ function syncOperations(options, deps) {
|
|
|
1522
1829
|
const source = generateOperationsFile();
|
|
1523
1830
|
let previous = null;
|
|
1524
1831
|
try {
|
|
1525
|
-
previous =
|
|
1832
|
+
previous = readFileSync7(outPath, "utf8");
|
|
1526
1833
|
} catch {
|
|
1527
1834
|
previous = null;
|
|
1528
1835
|
}
|
|
@@ -1550,7 +1857,7 @@ function syncOperations(options, deps) {
|
|
|
1550
1857
|
}
|
|
1551
1858
|
try {
|
|
1552
1859
|
mkdirSync3(dirname3(outPath), { recursive: true });
|
|
1553
|
-
|
|
1860
|
+
writeFileSync5(outPath, source);
|
|
1554
1861
|
} catch (error) {
|
|
1555
1862
|
throw new CliError(
|
|
1556
1863
|
`could not write ${shown}: ${error.message}`,
|
|
@@ -1597,7 +1904,7 @@ async function runTypes(options, deps) {
|
|
|
1597
1904
|
const source = generateModelTypes(models, { workspace });
|
|
1598
1905
|
let previous = null;
|
|
1599
1906
|
try {
|
|
1600
|
-
previous =
|
|
1907
|
+
previous = readFileSync7(outPath, "utf8");
|
|
1601
1908
|
} catch {
|
|
1602
1909
|
previous = null;
|
|
1603
1910
|
}
|
|
@@ -1616,7 +1923,7 @@ async function runTypes(options, deps) {
|
|
|
1616
1923
|
return 1;
|
|
1617
1924
|
}
|
|
1618
1925
|
mkdirSync3(dirname3(outPath), { recursive: true });
|
|
1619
|
-
|
|
1926
|
+
writeFileSync5(outPath, source);
|
|
1620
1927
|
const fieldCount = models.reduce(
|
|
1621
1928
|
(total, model) => total + model.fields.length,
|
|
1622
1929
|
0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmssy/cli",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.13.0",
|
|
4
4
|
"description": "The cmssy CLI: `cmssy init` wires cmssy into an existing Next.js, Astro or React Router app; `cmssy link` connects it to a workspace and verifies the editor wiring.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cmssy",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"assets"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@cmssy/core": "12.
|
|
30
|
+
"@cmssy/core": "12.13.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^20.0.0",
|