elcrm 1.1.3 → 1.1.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.js
CHANGED
|
@@ -533,19 +533,112 @@ var init_form_aliases = __esm(() => {
|
|
|
533
533
|
];
|
|
534
534
|
});
|
|
535
535
|
|
|
536
|
-
// src/lib/migrate/
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
const re = new RegExp(`\\n?[ \\t]*${name.replace(/-/g, "\\-")}\\s*:[^;\\n}]+;?[ \\t]*`, "g");
|
|
536
|
+
// src/lib/migrate/css-decl.ts
|
|
537
|
+
function removeCssDecl(css, name) {
|
|
538
|
+
const re = new RegExp(`\\n?[ \\t]*${name.replace(/-/g, "\\-")}(?![\\w-])\\s*:`, "g");
|
|
540
539
|
let n = 0;
|
|
541
|
-
const
|
|
540
|
+
const ranges = [];
|
|
541
|
+
let m;
|
|
542
|
+
while ((m = re.exec(css)) !== null) {
|
|
543
|
+
const start = m.index;
|
|
544
|
+
let i = m.index + m[0].length;
|
|
545
|
+
let depth = 0;
|
|
546
|
+
while (i < css.length) {
|
|
547
|
+
const ch = css[i];
|
|
548
|
+
if (ch === "(")
|
|
549
|
+
depth++;
|
|
550
|
+
else if (ch === ")")
|
|
551
|
+
depth = Math.max(0, depth - 1);
|
|
552
|
+
else if ((ch === ";" || ch === "}") && depth === 0) {
|
|
553
|
+
if (ch === ";")
|
|
554
|
+
i++;
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
i++;
|
|
558
|
+
}
|
|
559
|
+
let s = start;
|
|
560
|
+
if (s > 0 && css[s - 1] === `
|
|
561
|
+
`)
|
|
562
|
+
s--;
|
|
563
|
+
ranges.push({ start: s, end: i });
|
|
542
564
|
n++;
|
|
543
|
-
|
|
544
|
-
|
|
565
|
+
}
|
|
566
|
+
if (!ranges.length)
|
|
567
|
+
return { next: css, n: 0 };
|
|
568
|
+
let next = css;
|
|
569
|
+
for (let r = ranges.length - 1;r >= 0; r--) {
|
|
570
|
+
const { start, end } = ranges[r];
|
|
571
|
+
next = next.slice(0, start) + next.slice(end);
|
|
572
|
+
}
|
|
545
573
|
return { next: next.replace(/\n{3,}/g, `
|
|
546
574
|
|
|
547
575
|
`), n };
|
|
548
576
|
}
|
|
577
|
+
|
|
578
|
+
// src/lib/migrate/css-sanitize.ts
|
|
579
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
580
|
+
function stripOrphanColorMix(source) {
|
|
581
|
+
let next = source;
|
|
582
|
+
let hits = 0;
|
|
583
|
+
next = next.replace(ORPHAN_MIX_BLOCK_RE, () => {
|
|
584
|
+
hits++;
|
|
585
|
+
return `
|
|
586
|
+
`;
|
|
587
|
+
});
|
|
588
|
+
const lines = next.split(/\r?\n/);
|
|
589
|
+
const kept = [];
|
|
590
|
+
for (const line of lines) {
|
|
591
|
+
if (/^[ \t]*in\s+(?:srgb|hsl|hwb|lab|lch)\s*,?\s*$/i.test(line) || /^[ \t]*transparent\s*\)\s*;?\s*$/i.test(line) || /^[ \t]*var\([^)]+\)\s*\d+%\s*,?\s*$/i.test(line)) {
|
|
592
|
+
const prev = kept[kept.length - 1] ?? "";
|
|
593
|
+
if (!/color-mix\s*\(\s*$/i.test(prev) && !/color-mix\s*\(/i.test(prev)) {
|
|
594
|
+
hits++;
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
kept.push(line);
|
|
599
|
+
}
|
|
600
|
+
next = kept.join(`
|
|
601
|
+
`).replace(/\n{3,}/g, `
|
|
602
|
+
|
|
603
|
+
`);
|
|
604
|
+
return { next, hits };
|
|
605
|
+
}
|
|
606
|
+
function lineHasOrphanColorMix(line) {
|
|
607
|
+
const t = line.trim();
|
|
608
|
+
if (!t || t.startsWith("/*") || t.startsWith("*"))
|
|
609
|
+
return false;
|
|
610
|
+
if (/^in\s+(?:srgb|hsl|hwb|lab|lch)\b/i.test(t) && !/color-mix\s*\(/i.test(t)) {
|
|
611
|
+
return true;
|
|
612
|
+
}
|
|
613
|
+
if (/^transparent\s*\)\s*;?\s*$/i.test(t))
|
|
614
|
+
return true;
|
|
615
|
+
return false;
|
|
616
|
+
}
|
|
617
|
+
async function migrateCssSanitize(cwd, dry) {
|
|
618
|
+
const changes = [];
|
|
619
|
+
const files = projectCodeRoots(cwd).flatMap((r) => walkCodeFiles(r)).filter((f) => f.endsWith(".css"));
|
|
620
|
+
for (const file of files) {
|
|
621
|
+
const raw = readFileSync9(file, "utf8");
|
|
622
|
+
const { next, hits } = stripOrphanColorMix(raw);
|
|
623
|
+
if (hits === 0 || next === raw)
|
|
624
|
+
continue;
|
|
625
|
+
if (writeIfChanged(file, next, dry) || dry) {
|
|
626
|
+
changes.push({
|
|
627
|
+
file: rel(cwd, file),
|
|
628
|
+
detail: `${hits}\xD7 \u0443\u0434\u0430\u043B\u0435\u043D\u044B \u043E\u0441\u0438\u0440\u043E\u0442\u0435\u0432\u0448\u0438\u0435 color-mix/\u0444\u0440\u0430\u0433\u043C\u0435\u043D\u0442\u044B`
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
return changes;
|
|
633
|
+
}
|
|
634
|
+
var ORPHAN_MIX_BLOCK_RE;
|
|
635
|
+
var init_css_sanitize = __esm(() => {
|
|
636
|
+
init_walk();
|
|
637
|
+
ORPHAN_MIX_BLOCK_RE = /(?:^|\n)[ \t]*(?:in\s+srgb|in\s+hsl|in\s+hwb|in\s+lab|in\s+lch)[\s\S]*?\n[ \t]*\);?[ \t]*(?=\n|$)/gi;
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
// src/lib/migrate/form-tokens.ts
|
|
641
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
549
642
|
function migrateDatePopupShadowDecl(css) {
|
|
550
643
|
let n = 0;
|
|
551
644
|
let next = css;
|
|
@@ -600,10 +693,13 @@ function rewriteFormTokens(source) {
|
|
|
600
693
|
const stillUsed = new RegExp(`var\\(\\s*${name.replace(/-/g, "\\-")}\\s*`, "i").test(next);
|
|
601
694
|
if (stillUsed)
|
|
602
695
|
continue;
|
|
603
|
-
const rem =
|
|
696
|
+
const rem = removeCssDecl(next, name);
|
|
604
697
|
next = rem.next;
|
|
605
698
|
hits += rem.n;
|
|
606
699
|
}
|
|
700
|
+
const clean = stripOrphanColorMix(next);
|
|
701
|
+
next = clean.next;
|
|
702
|
+
hits += clean.hits;
|
|
607
703
|
return { next, hits };
|
|
608
704
|
}
|
|
609
705
|
async function migrateFormTokens(cwd, dry) {
|
|
@@ -613,7 +709,7 @@ async function migrateFormTokens(cwd, dry) {
|
|
|
613
709
|
const changes = [];
|
|
614
710
|
const files = projectCodeRoots(cwd).flatMap((r) => walkCodeFiles(r)).filter((f) => f.endsWith(".css"));
|
|
615
711
|
for (const file of files) {
|
|
616
|
-
const raw =
|
|
712
|
+
const raw = readFileSync10(file, "utf8");
|
|
617
713
|
const { next, hits } = rewriteFormTokens(raw);
|
|
618
714
|
if (hits === 0 || next === raw)
|
|
619
715
|
continue;
|
|
@@ -642,6 +738,7 @@ var VAR_REPLACEMENTS, DECL_REMOVE, FORM_TOKEN_DEPRECATED, DEPRECATED_VAR_RE, DEP
|
|
|
642
738
|
var init_form_tokens = __esm(() => {
|
|
643
739
|
init_pkg();
|
|
644
740
|
init_walk();
|
|
741
|
+
init_css_sanitize();
|
|
645
742
|
VAR_REPLACEMENTS = [
|
|
646
743
|
[
|
|
647
744
|
/var\(\s*--field-note-padding-top\s*(?:,[^)]+)?\)/gi,
|
|
@@ -689,18 +786,7 @@ var init_form_tokens = __esm(() => {
|
|
|
689
786
|
});
|
|
690
787
|
|
|
691
788
|
// src/lib/migrate/components.ts
|
|
692
|
-
import { readFileSync as
|
|
693
|
-
function removeDecl2(css, name) {
|
|
694
|
-
const re = new RegExp(`\\n?[ \\t]*${name.replace(/-/g, "\\-")}\\s*:[^;\\n}]+;?[ \\t]*`, "g");
|
|
695
|
-
let n = 0;
|
|
696
|
-
const next = css.replace(re, () => {
|
|
697
|
-
n++;
|
|
698
|
-
return "";
|
|
699
|
-
});
|
|
700
|
-
return { next: next.replace(/\n{3,}/g, `
|
|
701
|
-
|
|
702
|
-
`), n };
|
|
703
|
-
}
|
|
789
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
704
790
|
function rewriteComponentsCss(source) {
|
|
705
791
|
let next = source;
|
|
706
792
|
let hits = 0;
|
|
@@ -711,10 +797,10 @@ function rewriteComponentsCss(source) {
|
|
|
711
797
|
});
|
|
712
798
|
}
|
|
713
799
|
for (const name of COMPONENTS_TOKEN_DEPRECATED) {
|
|
714
|
-
const stillUsed = new RegExp(`var\\(\\s*${name.replace(/-/g, "\\-")}\\
|
|
800
|
+
const stillUsed = new RegExp(`var\\(\\s*${name.replace(/-/g, "\\-")}(?![\\w-])`, "i").test(next);
|
|
715
801
|
if (stillUsed)
|
|
716
802
|
continue;
|
|
717
|
-
const rem =
|
|
803
|
+
const rem = removeCssDecl(next, name);
|
|
718
804
|
next = rem.next;
|
|
719
805
|
hits += rem.n;
|
|
720
806
|
}
|
|
@@ -866,13 +952,14 @@ async function migrateComponents(cwd, dry) {
|
|
|
866
952
|
const changes = [];
|
|
867
953
|
const files = projectCodeRoots(cwd).flatMap((r) => walkCodeFiles(r));
|
|
868
954
|
for (const file of files) {
|
|
869
|
-
const raw =
|
|
955
|
+
const raw = readFileSync11(file, "utf8");
|
|
870
956
|
let next = raw;
|
|
871
957
|
let hits = 0;
|
|
872
958
|
if (file.endsWith(".css")) {
|
|
873
959
|
const r = rewriteComponentsCss(raw);
|
|
874
|
-
|
|
875
|
-
|
|
960
|
+
const clean = stripOrphanColorMix(r.next);
|
|
961
|
+
next = clean.next;
|
|
962
|
+
hits = r.hits + clean.hits;
|
|
876
963
|
} else if (/\.(tsx?|jsx?|mdx?)$/.test(file)) {
|
|
877
964
|
const r = rewriteComponentsTsx(raw);
|
|
878
965
|
next = fixStackDirectionSpacing(r.next);
|
|
@@ -907,6 +994,7 @@ var VAR_REPLACEMENTS2, COMPONENTS_TOKEN_DEPRECATED, DEPRECATED_VAR_RE2, DEPRECAT
|
|
|
907
994
|
var init_components = __esm(() => {
|
|
908
995
|
init_pkg();
|
|
909
996
|
init_walk();
|
|
997
|
+
init_css_sanitize();
|
|
910
998
|
VAR_REPLACEMENTS2 = [
|
|
911
999
|
[/var\(\s*--layout-background\s*(?:,[^)]+)?\)/gi, "var(--shell-background-muted)"],
|
|
912
1000
|
[/var\(\s*--header-background\s*(?:,[^)]+)?\)/gi, "var(--shell-background)"],
|
|
@@ -955,7 +1043,14 @@ var init_components = __esm(() => {
|
|
|
955
1043
|
[/var\(\s*--item-radius\s*(?:,[^)]+)?\)/gi, "var(--shell-radius)"],
|
|
956
1044
|
[/var\(\s*--block-gap\s*(?:,[^)]+)?\)/gi, "var(--shell-gap)"],
|
|
957
1045
|
[/var\(\s*--row-gap\s*(?:,[^)]+)?\)/gi, "var(--shell-gap)"],
|
|
958
|
-
[/var\(\s*--column-gap\s*(?:,[^)]+)?\)/gi, "var(--shell-gap)"]
|
|
1046
|
+
[/var\(\s*--column-gap\s*(?:,[^)]+)?\)/gi, "var(--shell-gap)"],
|
|
1047
|
+
[/var\(\s*--page-gap\s*(?:,[^)]+)?\)/gi, "var(--shell-gap)"],
|
|
1048
|
+
[/var\(\s*--page-pad\s*(?:,[^)]+)?\)/gi, "var(--shell-padding)"],
|
|
1049
|
+
[/var\(\s*--page-pad-x\s*(?:,[^)]+)?\)/gi, "var(--shell-padding-inline)"],
|
|
1050
|
+
[/var\(\s*--page-pad-y\s*(?:,[^)]+)?\)/gi, "var(--shell-padding-block)"],
|
|
1051
|
+
[/var\(\s*--card-radius\s*(?:,[^)]+)?\)/gi, "var(--shell-radius)"],
|
|
1052
|
+
[/var\(\s*--section-description-size\s*(?:,[^)]+)?\)/gi, "0.95rem"],
|
|
1053
|
+
[/var\(\s*--section-title-size\s*(?:,[^)]+)?\)/gi, "1.5rem"]
|
|
959
1054
|
];
|
|
960
1055
|
COMPONENTS_TOKEN_DEPRECATED = [
|
|
961
1056
|
"--layout-background",
|
|
@@ -1067,10 +1162,13 @@ var init_components = __esm(() => {
|
|
|
1067
1162
|
"--empty-state-actions-margin-top",
|
|
1068
1163
|
"--radio-group-gap",
|
|
1069
1164
|
"--page-pad",
|
|
1070
|
-
"--page-
|
|
1165
|
+
"--page-pad-x",
|
|
1166
|
+
"--page-pad-y",
|
|
1167
|
+
"--page-gap",
|
|
1168
|
+
"--card-radius"
|
|
1071
1169
|
];
|
|
1072
|
-
DEPRECATED_VAR_RE2 = new RegExp(`var\\(\\s*(?:${COMPONENTS_TOKEN_DEPRECATED.map((n) => n.replace(/-/g, "\\-")).join("|")})\\
|
|
1073
|
-
DEPRECATED_DECL_RE2 = new RegExp(`(?:${COMPONENTS_TOKEN_DEPRECATED.map((n) => n.replace(/-/g, "\\-")).join("|")})\\s*:`);
|
|
1170
|
+
DEPRECATED_VAR_RE2 = new RegExp(`var\\(\\s*(?:${COMPONENTS_TOKEN_DEPRECATED.map((n) => n.replace(/-/g, "\\-")).join("|")})(?![\\w-])`, "i");
|
|
1171
|
+
DEPRECATED_DECL_RE2 = new RegExp(`(?:${COMPONENTS_TOKEN_DEPRECATED.map((n) => n.replace(/-/g, "\\-")).join("|")})(?![\\w-])\\s*:`);
|
|
1074
1172
|
});
|
|
1075
1173
|
|
|
1076
1174
|
// src/lib/migrate/front.ts
|
|
@@ -1100,6 +1198,7 @@ var init_front = __esm(() => {
|
|
|
1100
1198
|
init_form_aliases();
|
|
1101
1199
|
init_form_tokens();
|
|
1102
1200
|
init_components();
|
|
1201
|
+
init_css_sanitize();
|
|
1103
1202
|
FRONT_MIGRATIONS = {
|
|
1104
1203
|
"size-sml": migrateSizeSml,
|
|
1105
1204
|
"field-border": migrateFieldBorder,
|
|
@@ -1107,6 +1206,7 @@ var init_front = __esm(() => {
|
|
|
1107
1206
|
"form-aliases": migrateFormAliases,
|
|
1108
1207
|
"form-tokens": migrateFormTokens,
|
|
1109
1208
|
components: migrateComponents,
|
|
1209
|
+
"css-sanitize": migrateCssSanitize,
|
|
1110
1210
|
"legacy-hacks": migrateLegacyReactHack,
|
|
1111
1211
|
"socket-server": migrateSocketServer
|
|
1112
1212
|
};
|
|
@@ -1114,6 +1214,7 @@ var init_front = __esm(() => {
|
|
|
1114
1214
|
"form-aliases",
|
|
1115
1215
|
"form-tokens",
|
|
1116
1216
|
"components",
|
|
1217
|
+
"css-sanitize",
|
|
1117
1218
|
"size-sml",
|
|
1118
1219
|
"field-border",
|
|
1119
1220
|
"modal-create",
|
|
@@ -1122,7 +1223,7 @@ var init_front = __esm(() => {
|
|
|
1122
1223
|
});
|
|
1123
1224
|
|
|
1124
1225
|
// src/index.ts
|
|
1125
|
-
import { readFileSync as
|
|
1226
|
+
import { readFileSync as readFileSync21 } from "fs";
|
|
1126
1227
|
import { dirname as dirname4, join as join18 } from "path";
|
|
1127
1228
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1128
1229
|
|
|
@@ -1242,6 +1343,17 @@ function installDeps(cwd = process.cwd()) {
|
|
|
1242
1343
|
});
|
|
1243
1344
|
return r.status === 0;
|
|
1244
1345
|
}
|
|
1346
|
+
function installGlobalElcrm() {
|
|
1347
|
+
const bun = spawnSync("bun", ["--version"], { encoding: "utf8" });
|
|
1348
|
+
const cmd = bun.status === 0 ? "bun" : "npm";
|
|
1349
|
+
const args = ["i", "-g", "elcrm@latest"];
|
|
1350
|
+
console.log(`CLI: ${cmd} ${args.join(" ")}`);
|
|
1351
|
+
const r = spawnSync(cmd, args, {
|
|
1352
|
+
stdio: "inherit",
|
|
1353
|
+
env: process.env
|
|
1354
|
+
});
|
|
1355
|
+
return r.status === 0;
|
|
1356
|
+
}
|
|
1245
1357
|
|
|
1246
1358
|
// src/commands/update.ts
|
|
1247
1359
|
init_pkg();
|
|
@@ -1265,6 +1377,7 @@ var c = {
|
|
|
1265
1377
|
|
|
1266
1378
|
// src/commands/update.ts
|
|
1267
1379
|
init_front();
|
|
1380
|
+
init_css_sanitize();
|
|
1268
1381
|
|
|
1269
1382
|
// src/lib/cssSync.ts
|
|
1270
1383
|
init_form_tokens();
|
|
@@ -1272,7 +1385,7 @@ init_components();
|
|
|
1272
1385
|
import {
|
|
1273
1386
|
existsSync as existsSync6,
|
|
1274
1387
|
readdirSync as readdirSync3,
|
|
1275
|
-
readFileSync as
|
|
1388
|
+
readFileSync as readFileSync12,
|
|
1276
1389
|
statSync as statSync3,
|
|
1277
1390
|
writeFileSync as writeFileSync4
|
|
1278
1391
|
} from "fs";
|
|
@@ -1401,7 +1514,7 @@ function resolvePkgRoot(pkgName, cwd) {
|
|
|
1401
1514
|
}
|
|
1402
1515
|
function readPkgJson(dir) {
|
|
1403
1516
|
try {
|
|
1404
|
-
return JSON.parse(
|
|
1517
|
+
return JSON.parse(readFileSync12(join6(dir, "package.json"), "utf8"));
|
|
1405
1518
|
} catch {
|
|
1406
1519
|
return null;
|
|
1407
1520
|
}
|
|
@@ -1425,18 +1538,50 @@ function inspectPkgCss(pkgName, cwd) {
|
|
|
1425
1538
|
return null;
|
|
1426
1539
|
const pkg = readPkgJson(root);
|
|
1427
1540
|
const exp = pkg?.exports;
|
|
1428
|
-
const styleRel = exportPath(exp, "./style.css");
|
|
1429
|
-
const lightRel = exportPath(exp, "./light.css");
|
|
1430
|
-
const darkRel = exportPath(exp, "./dark.css");
|
|
1431
1541
|
const abs = (rel2) => rel2 ? join6(root, rel2.replace(/^\.\//, "")) : undefined;
|
|
1542
|
+
const fileIfExists = (key) => {
|
|
1543
|
+
const rel2 = exportPath(exp, key);
|
|
1544
|
+
const a = abs(rel2);
|
|
1545
|
+
return a && existsSync6(a) ? a : undefined;
|
|
1546
|
+
};
|
|
1432
1547
|
return {
|
|
1433
1548
|
name: pkgName,
|
|
1434
1549
|
root,
|
|
1435
|
-
style:
|
|
1436
|
-
light:
|
|
1437
|
-
dark:
|
|
1550
|
+
style: fileIfExists("./style.css"),
|
|
1551
|
+
light: fileIfExists("./light.css"),
|
|
1552
|
+
dark: fileIfExists("./dark.css"),
|
|
1553
|
+
tokens: fileIfExists("./tokens.css")
|
|
1438
1554
|
};
|
|
1439
1555
|
}
|
|
1556
|
+
function resolveElcrmCssImport(spec, cwd) {
|
|
1557
|
+
const bare = spec.replace(/^["']|["']$/g, "").trim();
|
|
1558
|
+
const m = bare.match(/^(@elcrm\/[^/]+)\/(.+)$/);
|
|
1559
|
+
if (!m)
|
|
1560
|
+
return null;
|
|
1561
|
+
const pkgName = m[1];
|
|
1562
|
+
const sub = m[2];
|
|
1563
|
+
const root = resolvePkgRoot(pkgName, cwd);
|
|
1564
|
+
if (!root)
|
|
1565
|
+
return null;
|
|
1566
|
+
const pkg = readPkgJson(root);
|
|
1567
|
+
const rel2 = exportPath(pkg?.exports, `./${sub}`);
|
|
1568
|
+
if (!rel2)
|
|
1569
|
+
return null;
|
|
1570
|
+
const abs = join6(root, rel2.replace(/^\.\//, ""));
|
|
1571
|
+
return existsSync6(abs) ? abs : null;
|
|
1572
|
+
}
|
|
1573
|
+
function pruneBrokenElcrmImports(css, cwd) {
|
|
1574
|
+
const removed = [];
|
|
1575
|
+
const next = css.replace(/@import\s+["'](@elcrm\/[^"']+)["']\s*;[ \t]*(?:\r?\n)?/g, (full, spec) => {
|
|
1576
|
+
if (resolveElcrmCssImport(spec, cwd))
|
|
1577
|
+
return full;
|
|
1578
|
+
removed.push(spec);
|
|
1579
|
+
return "";
|
|
1580
|
+
});
|
|
1581
|
+
return { css: next.replace(/\n{3,}/g, `
|
|
1582
|
+
|
|
1583
|
+
`), removed };
|
|
1584
|
+
}
|
|
1440
1585
|
function addDef(acc, seen, pkg, bucket, name, value) {
|
|
1441
1586
|
const key = `${bucket}:${name}`;
|
|
1442
1587
|
if (seen.has(key))
|
|
@@ -1457,7 +1602,7 @@ function collectPkgTokens(pkgName, cwd) {
|
|
|
1457
1602
|
const acc = [];
|
|
1458
1603
|
const seen = new Set;
|
|
1459
1604
|
for (const file of files) {
|
|
1460
|
-
const css =
|
|
1605
|
+
const css = readFileSync12(file, "utf8");
|
|
1461
1606
|
const kind = fileKind(file);
|
|
1462
1607
|
if (kind !== "mixed") {
|
|
1463
1608
|
for (const [name, value] of parseCustomProps(css)) {
|
|
@@ -1619,13 +1764,14 @@ function syncElcrmCss(options) {
|
|
|
1619
1764
|
"theme-dark.css": []
|
|
1620
1765
|
};
|
|
1621
1766
|
const imports = [];
|
|
1767
|
+
let removedImports = [];
|
|
1622
1768
|
const fileFor = (bucket) => bucket === "geometry" ? paths.geometry : bucket === "light" ? paths.light : paths.dark;
|
|
1623
1769
|
const labelFor = (bucket) => bucket === "geometry" ? "theme.css" : bucket === "light" ? "theme-light.css" : "theme-dark.css";
|
|
1624
1770
|
for (const bucket of ["geometry", "light", "dark"]) {
|
|
1625
1771
|
const file = fileFor(bucket);
|
|
1626
1772
|
if (!existsSync6(file))
|
|
1627
1773
|
continue;
|
|
1628
|
-
let css =
|
|
1774
|
+
let css = readFileSync12(file, "utf8");
|
|
1629
1775
|
const have = existingTokenNames(css);
|
|
1630
1776
|
const missing = allDefs.filter((d) => d.bucket === bucket && !have.has(d.name) && !TOKEN_DEPRECATED.has(d.name));
|
|
1631
1777
|
const uniq = [];
|
|
@@ -1650,15 +1796,17 @@ function syncElcrmCss(options) {
|
|
|
1650
1796
|
writeFileSync4(file, next, "utf8");
|
|
1651
1797
|
}
|
|
1652
1798
|
if (existsSync6(paths.elcrm)) {
|
|
1653
|
-
let css =
|
|
1799
|
+
let css = readFileSync12(paths.elcrm, "utf8");
|
|
1800
|
+
const pruned = pruneBrokenElcrmImports(css, options.cwd);
|
|
1801
|
+
css = pruned.css;
|
|
1802
|
+
removedImports = pruned.removed;
|
|
1654
1803
|
for (const exp of cssExports) {
|
|
1655
1804
|
const specs = [];
|
|
1656
1805
|
if (exp.light)
|
|
1657
1806
|
specs.push(`${exp.name}/light.css`);
|
|
1658
1807
|
if (exp.dark)
|
|
1659
1808
|
specs.push(`${exp.name}/dark.css`);
|
|
1660
|
-
|
|
1661
|
-
if (existsSync6(tokens))
|
|
1809
|
+
if (exp.tokens)
|
|
1662
1810
|
specs.push(`${exp.name}/tokens.css`);
|
|
1663
1811
|
for (const spec of specs) {
|
|
1664
1812
|
const r = ensureImport(css, spec);
|
|
@@ -1667,17 +1815,18 @@ function syncElcrmCss(options) {
|
|
|
1667
1815
|
imports.push(spec);
|
|
1668
1816
|
}
|
|
1669
1817
|
}
|
|
1670
|
-
if (imports.length && !options.dry)
|
|
1818
|
+
if ((imports.length || removedImports.length) && !options.dry) {
|
|
1671
1819
|
writeFileSync4(paths.elcrm, css, "utf8");
|
|
1820
|
+
}
|
|
1672
1821
|
}
|
|
1673
|
-
return { styleDir, added, imports, skippedPkgs };
|
|
1822
|
+
return { styleDir, added, imports, removedImports, skippedPkgs };
|
|
1674
1823
|
}
|
|
1675
1824
|
|
|
1676
1825
|
// src/commands/test.ts
|
|
1677
1826
|
import { resolve } from "path";
|
|
1678
1827
|
|
|
1679
1828
|
// src/lib/test/detect.ts
|
|
1680
|
-
import { existsSync as existsSync7, readdirSync as readdirSync4, readFileSync as
|
|
1829
|
+
import { existsSync as existsSync7, readdirSync as readdirSync4, readFileSync as readFileSync13, statSync as statSync4 } from "fs";
|
|
1681
1830
|
import { join as join7 } from "path";
|
|
1682
1831
|
function hasElcrmServer(pkg) {
|
|
1683
1832
|
for (const section of [
|
|
@@ -1732,17 +1881,18 @@ function readPkgAt(dir) {
|
|
|
1732
1881
|
if (!existsSync7(path))
|
|
1733
1882
|
return null;
|
|
1734
1883
|
try {
|
|
1735
|
-
return JSON.parse(
|
|
1884
|
+
return JSON.parse(readFileSync13(path, "utf8"));
|
|
1736
1885
|
} catch {
|
|
1737
1886
|
return null;
|
|
1738
1887
|
}
|
|
1739
1888
|
}
|
|
1740
1889
|
|
|
1741
1890
|
// src/lib/test/front.ts
|
|
1742
|
-
import { existsSync as existsSync8, readdirSync as readdirSync5, readFileSync as
|
|
1891
|
+
import { existsSync as existsSync8, readdirSync as readdirSync5, readFileSync as readFileSync14, statSync as statSync5 } from "fs";
|
|
1743
1892
|
import { join as join8, relative as relative2 } from "path";
|
|
1744
1893
|
init_form_tokens();
|
|
1745
1894
|
init_components();
|
|
1895
|
+
init_css_sanitize();
|
|
1746
1896
|
var SKIP = new Set(["node_modules", "dist", ".git", "coverage", ".bun"]);
|
|
1747
1897
|
function isThemeTokenFile(rel2) {
|
|
1748
1898
|
const n = rel2.replace(/\\/g, "/");
|
|
@@ -1887,7 +2037,7 @@ function collectFrontIssues(cwd, pkg) {
|
|
|
1887
2037
|
files.push(inSrc);
|
|
1888
2038
|
}
|
|
1889
2039
|
for (const file of files) {
|
|
1890
|
-
const text =
|
|
2040
|
+
const text = readFileSync14(file, "utf8");
|
|
1891
2041
|
const rel2 = relative2(cwd, file);
|
|
1892
2042
|
const skipHardColor = isLib || isThemeTokenFile(rel2) || isGeneratedIcons(rel2);
|
|
1893
2043
|
if (DEPRECATED_SOCKET_IMPORT_RE.test(text)) {
|
|
@@ -2005,6 +2155,16 @@ function collectFrontIssues(cwd, pkg) {
|
|
|
2005
2155
|
fixable: true
|
|
2006
2156
|
});
|
|
2007
2157
|
}
|
|
2158
|
+
if (lineHasOrphanColorMix(line)) {
|
|
2159
|
+
issues.push({
|
|
2160
|
+
level: "error",
|
|
2161
|
+
code: "css-orphan-mix",
|
|
2162
|
+
message: "\u043E\u0441\u0438\u0440\u043E\u0442\u0435\u0432\u0448\u0438\u0439 \u0445\u0432\u043E\u0441\u0442 color-mix (in srgb\u2026) \u2014 elcrm migrate css-sanitize",
|
|
2163
|
+
file: rel2,
|
|
2164
|
+
line: i + 1,
|
|
2165
|
+
fixable: true
|
|
2166
|
+
});
|
|
2167
|
+
}
|
|
2008
2168
|
if (/\b(Block|Row|Column)\b/.test(line) && /@elcrm\/components/.test(text) && /from\s+["']@elcrm\/components/.test(text)) {
|
|
2009
2169
|
if (/import\s*\{[^}]*\b(Block|Row|Column)\b/.test(line) || /<\/?(?:Block|Row|Column)\b/.test(line)) {
|
|
2010
2170
|
issues.push({
|
|
@@ -2044,7 +2204,7 @@ function collectFrontIssues(cwd, pkg) {
|
|
|
2044
2204
|
return issues;
|
|
2045
2205
|
}
|
|
2046
2206
|
async function runPkgScript(cwd, script) {
|
|
2047
|
-
const pkg = JSON.parse(
|
|
2207
|
+
const pkg = JSON.parse(readFileSync14(join8(cwd, "package.json"), "utf8"));
|
|
2048
2208
|
if (!pkg.scripts?.[script])
|
|
2049
2209
|
return { ran: false, ok: true };
|
|
2050
2210
|
console.log(`\u2192 bun run ${script}`);
|
|
@@ -2087,7 +2247,7 @@ function printIssues(issues, title) {
|
|
|
2087
2247
|
}
|
|
2088
2248
|
|
|
2089
2249
|
// src/lib/test/serverScan.ts
|
|
2090
|
-
import { existsSync as existsSync9, readdirSync as readdirSync6, readFileSync as
|
|
2250
|
+
import { existsSync as existsSync9, readdirSync as readdirSync6, readFileSync as readFileSync15, statSync as statSync6 } from "fs";
|
|
2091
2251
|
import { join as join9, relative as relative3 } from "path";
|
|
2092
2252
|
|
|
2093
2253
|
// src/lib/test/serverRules.ts
|
|
@@ -2489,7 +2649,7 @@ function scanServerProject(root) {
|
|
|
2489
2649
|
walkFiles2(root, root, files);
|
|
2490
2650
|
const findings = [];
|
|
2491
2651
|
for (const file of files) {
|
|
2492
|
-
const text =
|
|
2652
|
+
const text = readFileSync15(file, "utf8");
|
|
2493
2653
|
if (file.endsWith("package.json")) {
|
|
2494
2654
|
findings.push(...scanPackageJson(root, file, text));
|
|
2495
2655
|
} else {
|
|
@@ -2599,6 +2759,17 @@ elcrm test: ok`));
|
|
|
2599
2759
|
// src/commands/update.ts
|
|
2600
2760
|
async function cmdUpdate(parsed) {
|
|
2601
2761
|
const cwd = process.cwd();
|
|
2762
|
+
const dry = hasFlag(parsed, "dry");
|
|
2763
|
+
const useCore = hasFlag(parsed, "core");
|
|
2764
|
+
const noInstall = hasFlag(parsed, "no-install");
|
|
2765
|
+
const doFix = hasFlag(parsed, "fix");
|
|
2766
|
+
const doTest = hasFlag(parsed, "test");
|
|
2767
|
+
if (dry) {
|
|
2768
|
+
console.log(`${c.gray("[dry]")} bun/npm i -g elcrm@latest`);
|
|
2769
|
+
} else if (!installGlobalElcrm()) {
|
|
2770
|
+
console.error("\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0433\u043B\u043E\u0431\u0430\u043B\u044C\u043D\u044B\u0439 elcrm.");
|
|
2771
|
+
process.exit(1);
|
|
2772
|
+
}
|
|
2602
2773
|
const pkg = readPackageJson(cwd);
|
|
2603
2774
|
if (!pkg) {
|
|
2604
2775
|
console.error("package.json \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D \u0432 \u0442\u0435\u043A\u0443\u0449\u0435\u043C \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0435.");
|
|
@@ -2609,11 +2780,6 @@ async function cmdUpdate(parsed) {
|
|
|
2609
2780
|
console.log("\u0417\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u0435\u0439 @elcrm/* \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E.");
|
|
2610
2781
|
return;
|
|
2611
2782
|
}
|
|
2612
|
-
const dry = hasFlag(parsed, "dry");
|
|
2613
|
-
const useCore = hasFlag(parsed, "core");
|
|
2614
|
-
const noInstall = hasFlag(parsed, "no-install");
|
|
2615
|
-
const doFix = hasFlag(parsed, "fix");
|
|
2616
|
-
const doTest = hasFlag(parsed, "test");
|
|
2617
2783
|
const names = uniqueElcrmNames(deps);
|
|
2618
2784
|
console.log(`\u041D\u0430\u0439\u0434\u0435\u043D\u043E @elcrm/*: ${names.length}`);
|
|
2619
2785
|
let versions;
|
|
@@ -2731,9 +2897,18 @@ package.json \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D (${changed}).`);
|
|
|
2731
2897
|
if (css.imports.length) {
|
|
2732
2898
|
console.log(` ${c.green("+")} elcrm.css @import: ${css.imports.join(", ")}`);
|
|
2733
2899
|
}
|
|
2734
|
-
if (
|
|
2900
|
+
if (css.removedImports.length) {
|
|
2901
|
+
console.log(` ${c.red("\u2212")} elcrm.css \u0431\u0438\u0442\u044B\u0435 @import: ${css.removedImports.join(", ")}`);
|
|
2902
|
+
}
|
|
2903
|
+
if (added === 0 && css.imports.length === 0 && css.removedImports.length === 0) {
|
|
2735
2904
|
console.log(" \u0422\u043E\u043A\u0435\u043D\u044B \u0443\u0436\u0435 \u043D\u0430 \u043C\u0435\u0441\u0442\u0435.");
|
|
2736
2905
|
}
|
|
2906
|
+
const cleaned = await migrateCssSanitize(cwd, false);
|
|
2907
|
+
if (cleaned.length) {
|
|
2908
|
+
console.log(" css-sanitize:");
|
|
2909
|
+
for (const ch of cleaned)
|
|
2910
|
+
console.log(` ${ch.file}: ${ch.detail}`);
|
|
2911
|
+
}
|
|
2737
2912
|
} catch (e) {
|
|
2738
2913
|
console.log(` ${c.gray("css sync \u043F\u0440\u043E\u043F\u0443\u0449\u0435\u043D:")} ${e instanceof Error ? e.message : e}`);
|
|
2739
2914
|
}
|
|
@@ -2758,7 +2933,7 @@ import {
|
|
|
2758
2933
|
existsSync as existsSync11,
|
|
2759
2934
|
mkdirSync,
|
|
2760
2935
|
readdirSync as readdirSync7,
|
|
2761
|
-
readFileSync as
|
|
2936
|
+
readFileSync as readFileSync16,
|
|
2762
2937
|
statSync as statSync7,
|
|
2763
2938
|
writeFileSync as writeFileSync5
|
|
2764
2939
|
} from "fs";
|
|
@@ -2802,7 +2977,7 @@ function isEmptyDir(dir) {
|
|
|
2802
2977
|
function writePkgName(pkgPath, name) {
|
|
2803
2978
|
if (!existsSync11(pkgPath))
|
|
2804
2979
|
return;
|
|
2805
|
-
const pkg = JSON.parse(
|
|
2980
|
+
const pkg = JSON.parse(readFileSync16(pkgPath, "utf8"));
|
|
2806
2981
|
pkg.name = name;
|
|
2807
2982
|
pkg.version = pkg.version ?? "0.0.0";
|
|
2808
2983
|
writeFileSync5(pkgPath, JSON.stringify(pkg, null, 2) + `
|
|
@@ -2969,7 +3144,7 @@ async function cmdMigrate(parsed) {
|
|
|
2969
3144
|
console.log(dry ? `
|
|
2970
3145
|
--dry: ${changes.length} \u043F\u043E\u0442\u0435\u043D\u0446\u0438\u0430\u043B\u044C\u043D\u044B\u0445 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0439.` : `
|
|
2971
3146
|
\u041F\u0440\u0438\u043C\u0435\u043D\u0435\u043D\u043E: ${changes.length}.`);
|
|
2972
|
-
if (name === "front" || name === "ui" || name === "size-sml" || name === "form-tokens" || name === "components") {
|
|
3147
|
+
if (name === "front" || name === "ui" || name === "size-sml" || name === "form-tokens" || name === "components" || name === "css-sanitize") {
|
|
2973
3148
|
console.log("\u0414\u0430\u043B\u044C\u0448\u0435: elcrm css && elcrm audit");
|
|
2974
3149
|
}
|
|
2975
3150
|
}
|
|
@@ -3164,7 +3339,7 @@ import { resolve as resolve3 } from "path";
|
|
|
3164
3339
|
import {
|
|
3165
3340
|
existsSync as existsSync13,
|
|
3166
3341
|
readdirSync as readdirSync9,
|
|
3167
|
-
readFileSync as
|
|
3342
|
+
readFileSync as readFileSync18,
|
|
3168
3343
|
rmSync,
|
|
3169
3344
|
statSync as statSync8,
|
|
3170
3345
|
writeFileSync as writeFileSync7
|
|
@@ -3172,7 +3347,7 @@ import {
|
|
|
3172
3347
|
import { join as join13 } from "path";
|
|
3173
3348
|
|
|
3174
3349
|
// src/vite/concat-css.ts
|
|
3175
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
3350
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync17, writeFileSync as writeFileSync6 } from "fs";
|
|
3176
3351
|
import { join as join12 } from "path";
|
|
3177
3352
|
var SKIP_CSS = new Set([
|
|
3178
3353
|
"index.css",
|
|
@@ -3189,7 +3364,7 @@ function concatDistCss(options) {
|
|
|
3189
3364
|
...options.skip ?? []
|
|
3190
3365
|
]);
|
|
3191
3366
|
const files = readdirSync8(options.distDir).filter((f) => f.endsWith(".css") && !skip.has(f)).sort();
|
|
3192
|
-
const css = files.map((f) =>
|
|
3367
|
+
const css = files.map((f) => readFileSync17(join12(options.distDir, f), "utf8")).join(`
|
|
3193
3368
|
`);
|
|
3194
3369
|
const outPath = join12(options.distDir, outFile);
|
|
3195
3370
|
writeFileSync6(outPath, css);
|
|
@@ -3220,7 +3395,7 @@ function postbuildLib(options) {
|
|
|
3220
3395
|
const flat = join13(dist, `${name}.d.ts`);
|
|
3221
3396
|
const src = existsSync13(impl) ? impl : existsSync13(nestedIndex) ? nestedIndex : null;
|
|
3222
3397
|
if (src) {
|
|
3223
|
-
const text =
|
|
3398
|
+
const text = readFileSync18(src, "utf8").replace(/from ['"]\.\.\/([^'"]+)['"]/g, `from './$1'`);
|
|
3224
3399
|
writeFileSync7(flat, text);
|
|
3225
3400
|
console.log(`[postbuild] types \u2192 ${name}.d.ts`);
|
|
3226
3401
|
}
|
|
@@ -3239,6 +3414,7 @@ async function cmdPostbuild(parsed) {
|
|
|
3239
3414
|
|
|
3240
3415
|
// src/commands/css.ts
|
|
3241
3416
|
init_pkg();
|
|
3417
|
+
init_css_sanitize();
|
|
3242
3418
|
async function cmdCss(parsed) {
|
|
3243
3419
|
const cwd = parsed.options.dir || process.cwd();
|
|
3244
3420
|
const pkg = readPackageJson(cwd);
|
|
@@ -3272,14 +3448,28 @@ async function cmdCss(parsed) {
|
|
|
3272
3448
|
for (const spec of result.imports)
|
|
3273
3449
|
console.log(` ${c.dim(spec)}`);
|
|
3274
3450
|
}
|
|
3451
|
+
if (result.removedImports.length) {
|
|
3452
|
+
console.log(` ${c.red("\u2212")} elcrm.css \u0431\u0438\u0442\u044B\u0435 @import:`);
|
|
3453
|
+
for (const spec of result.removedImports) {
|
|
3454
|
+
console.log(` ${c.dim(spec)}`);
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3275
3457
|
if (result.skippedPkgs.length) {
|
|
3276
3458
|
console.log(` ${c.gray("\u0431\u0435\u0437 CSS-\u0442\u043E\u043A\u0435\u043D\u043E\u0432:")} ${result.skippedPkgs.join(", ")}`);
|
|
3277
3459
|
}
|
|
3278
|
-
if (total === 0 && result.imports.length === 0) {
|
|
3460
|
+
if (total === 0 && result.imports.length === 0 && result.removedImports.length === 0) {
|
|
3279
3461
|
console.log("\u0412\u0441\u0451 \u0443\u0436\u0435 \u043D\u0430 \u043C\u0435\u0441\u0442\u0435.");
|
|
3280
3462
|
} else if (dry) {
|
|
3281
3463
|
console.log("\u0417\u0430\u043F\u0438\u0441\u044C \u043D\u0435 \u0432\u044B\u043F\u043E\u043B\u043D\u044F\u043B\u0430\u0441\u044C (--dry).");
|
|
3282
3464
|
}
|
|
3465
|
+
const cleaned = await migrateCssSanitize(cwd, dry);
|
|
3466
|
+
if (cleaned.length) {
|
|
3467
|
+
console.log(dry ? `
|
|
3468
|
+
[dry] css-sanitize: ${cleaned.length} \u0444\u0430\u0439\u043B(\u043E\u0432)` : `
|
|
3469
|
+
css-sanitize: \u043F\u043E\u0447\u0438\u043D\u0435\u043D\u043E ${cleaned.length} \u0444\u0430\u0439\u043B(\u043E\u0432)`);
|
|
3470
|
+
for (const ch of cleaned)
|
|
3471
|
+
console.log(` ${ch.file}: ${ch.detail}`);
|
|
3472
|
+
}
|
|
3283
3473
|
} catch (e) {
|
|
3284
3474
|
console.error(e instanceof Error ? e.message : e);
|
|
3285
3475
|
process.exit(1);
|
|
@@ -3287,13 +3477,14 @@ async function cmdCss(parsed) {
|
|
|
3287
3477
|
}
|
|
3288
3478
|
|
|
3289
3479
|
// src/commands/audit.ts
|
|
3290
|
-
import { existsSync as existsSync14, readFileSync as
|
|
3480
|
+
import { existsSync as existsSync14, readFileSync as readFileSync19 } from "fs";
|
|
3291
3481
|
import { join as join14, relative as relative4 } from "path";
|
|
3292
3482
|
init_pkg();
|
|
3293
3483
|
init_walk();
|
|
3294
3484
|
init_front();
|
|
3295
3485
|
init_form_tokens();
|
|
3296
3486
|
init_components();
|
|
3487
|
+
init_css_sanitize();
|
|
3297
3488
|
function scan(cwd) {
|
|
3298
3489
|
const out = [];
|
|
3299
3490
|
const pkg = readPackageJson(cwd);
|
|
@@ -3324,7 +3515,7 @@ function scan(cwd) {
|
|
|
3324
3515
|
}
|
|
3325
3516
|
const files = projectCodeRoots(cwd).flatMap((r) => walkCodeFiles(r));
|
|
3326
3517
|
for (const file of files) {
|
|
3327
|
-
const text =
|
|
3518
|
+
const text = readFileSync19(file, "utf8");
|
|
3328
3519
|
const rel2 = relative4(cwd, file);
|
|
3329
3520
|
const lines = text.split(/\r?\n/);
|
|
3330
3521
|
lines.forEach((line, i) => {
|
|
@@ -3406,7 +3597,7 @@ function scan(cwd) {
|
|
|
3406
3597
|
return false;
|
|
3407
3598
|
if (/theme(-light|-dark)?\.css$/.test(f))
|
|
3408
3599
|
return false;
|
|
3409
|
-
const t =
|
|
3600
|
+
const t = readFileSync19(f, "utf8");
|
|
3410
3601
|
return t.includes("--search-border:") && t.includes("--button-secondary-bg:") && t.includes("transparent");
|
|
3411
3602
|
});
|
|
3412
3603
|
if (toolbarMarkers.length > 1) {
|
|
@@ -3426,6 +3617,21 @@ function scan(cwd) {
|
|
|
3426
3617
|
fix: "elcrm css"
|
|
3427
3618
|
});
|
|
3428
3619
|
}
|
|
3620
|
+
if (styleDir && existsSync14(join14(styleDir, "elcrm.css"))) {
|
|
3621
|
+
const elcrmCss = readFileSync19(join14(styleDir, "elcrm.css"), "utf8");
|
|
3622
|
+
for (const m of elcrmCss.matchAll(/@import\s+["'](@elcrm\/[^"']+)["']/g)) {
|
|
3623
|
+
const spec = m[1];
|
|
3624
|
+
if (!resolveElcrmCssImport(spec, cwd)) {
|
|
3625
|
+
out.push({
|
|
3626
|
+
level: "error",
|
|
3627
|
+
code: "elcrm-import-missing",
|
|
3628
|
+
message: `\u0431\u0438\u0442\u044B\u0439 @import "${spec}" \u2014 \u0444\u0430\u0439\u043B\u0430 \u043D\u0435\u0442 \u0432 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u043E\u043C \u043F\u0430\u043A\u0435\u0442\u0435`,
|
|
3629
|
+
file: relative4(cwd, join14(styleDir, "elcrm.css")),
|
|
3630
|
+
fix: "elcrm css"
|
|
3631
|
+
});
|
|
3632
|
+
}
|
|
3633
|
+
}
|
|
3634
|
+
}
|
|
3429
3635
|
const depsForm = pkg.dependencies?.["@elcrm/form"] || pkg.devDependencies?.["@elcrm/form"];
|
|
3430
3636
|
if (depsForm && styleDir) {
|
|
3431
3637
|
const themeFiles = [
|
|
@@ -3433,7 +3639,7 @@ function scan(cwd) {
|
|
|
3433
3639
|
"theme-dark.css",
|
|
3434
3640
|
"theme.css"
|
|
3435
3641
|
].map((f) => join14(styleDir, f));
|
|
3436
|
-
const themeText = themeFiles.filter(existsSync14).map((f) =>
|
|
3642
|
+
const themeText = themeFiles.filter(existsSync14).map((f) => readFileSync19(f, "utf8")).join(`
|
|
3437
3643
|
`);
|
|
3438
3644
|
if (themeText && !/--popup-shadow\s*:/.test(themeText) && /--date-popup-shadow\s*:|--select-background\s*:/.test(themeText)) {
|
|
3439
3645
|
out.push({
|
|
@@ -3455,7 +3661,7 @@ function scan(cwd) {
|
|
|
3455
3661
|
for (const file of files) {
|
|
3456
3662
|
if (!file.endsWith(".css"))
|
|
3457
3663
|
continue;
|
|
3458
|
-
const text =
|
|
3664
|
+
const text = readFileSync19(file, "utf8");
|
|
3459
3665
|
const relPath = relative4(cwd, file);
|
|
3460
3666
|
const lines = text.split(/\r?\n/);
|
|
3461
3667
|
lines.forEach((line, i) => {
|
|
@@ -3481,6 +3687,16 @@ function scan(cwd) {
|
|
|
3481
3687
|
fix: "elcrm migrate components"
|
|
3482
3688
|
});
|
|
3483
3689
|
}
|
|
3690
|
+
if (lineHasOrphanColorMix(line)) {
|
|
3691
|
+
out.push({
|
|
3692
|
+
level: "error",
|
|
3693
|
+
code: "css-orphan-mix",
|
|
3694
|
+
message: "\u0431\u0438\u0442\u044B\u0439 CSS: \u0445\u0432\u043E\u0441\u0442 color-mix \u0431\u0435\u0437 \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u0430 (in srgb / transparent))",
|
|
3695
|
+
file: relPath,
|
|
3696
|
+
line: i + 1,
|
|
3697
|
+
fix: "elcrm migrate css-sanitize"
|
|
3698
|
+
});
|
|
3699
|
+
}
|
|
3484
3700
|
});
|
|
3485
3701
|
}
|
|
3486
3702
|
return out;
|
|
@@ -3594,7 +3810,7 @@ import {
|
|
|
3594
3810
|
existsSync as existsSync15,
|
|
3595
3811
|
mkdirSync as mkdirSync2,
|
|
3596
3812
|
readdirSync as readdirSync10,
|
|
3597
|
-
readFileSync as
|
|
3813
|
+
readFileSync as readFileSync20,
|
|
3598
3814
|
writeFileSync as writeFileSync8
|
|
3599
3815
|
} from "fs";
|
|
3600
3816
|
import { dirname as dirname3, join as join15 } from "path";
|
|
@@ -3612,7 +3828,7 @@ function readBundled(relPath) {
|
|
|
3612
3828
|
if (!existsSync15(full)) {
|
|
3613
3829
|
throw new Error(`\u0428\u0430\u0431\u043B\u043E\u043D \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D: ${relPath}`);
|
|
3614
3830
|
}
|
|
3615
|
-
return
|
|
3831
|
+
return readFileSync20(full, "utf8");
|
|
3616
3832
|
}
|
|
3617
3833
|
|
|
3618
3834
|
// src/commands/docs.ts
|
|
@@ -3682,23 +3898,6 @@ async function cmdCursor(parsed) {
|
|
|
3682
3898
|
console.log(c.gray("\u0410\u0433\u0435\u043D\u0442: AGENTS.md + rules (\u0443\u0437\u043A\u0438\u0435 glob) + .cursor/docs. \u0421\u0434\u0430\u0447\u0430: elcrm test."));
|
|
3683
3899
|
}
|
|
3684
3900
|
|
|
3685
|
-
// src/commands/upd.ts
|
|
3686
|
-
import { spawnSync as spawnSync2 } from "child_process";
|
|
3687
|
-
async function cmdUpd() {
|
|
3688
|
-
const bun = spawnSync2("bun", ["--version"], { encoding: "utf8" });
|
|
3689
|
-
const cmd = bun.status === 0 ? "bun" : "npm";
|
|
3690
|
-
const args = ["i", "-g", "elcrm@latest"];
|
|
3691
|
-
console.log(`${c.cyan("\u2192")} ${cmd} ${args.join(" ")}`);
|
|
3692
|
-
const r = spawnSync2(cmd, args, {
|
|
3693
|
-
stdio: "inherit",
|
|
3694
|
-
env: process.env
|
|
3695
|
-
});
|
|
3696
|
-
if (r.status !== 0) {
|
|
3697
|
-
process.exit(r.status ?? 1);
|
|
3698
|
-
}
|
|
3699
|
-
console.log(c.green("CLI \u043E\u0431\u043D\u043E\u0432\u043B\u0451\u043D. \u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430: elcrm -v"));
|
|
3700
|
-
}
|
|
3701
|
-
|
|
3702
3901
|
// src/index.ts
|
|
3703
3902
|
function cliVersion() {
|
|
3704
3903
|
const here = dirname4(fileURLToPath2(import.meta.url));
|
|
@@ -3707,7 +3906,7 @@ function cliVersion() {
|
|
|
3707
3906
|
join18(here, "package.json")
|
|
3708
3907
|
]) {
|
|
3709
3908
|
try {
|
|
3710
|
-
const v = JSON.parse(
|
|
3909
|
+
const v = JSON.parse(readFileSync21(p, "utf8")).version;
|
|
3711
3910
|
if (typeof v === "string" && v)
|
|
3712
3911
|
return v;
|
|
3713
3912
|
} catch {}
|
|
@@ -3720,93 +3919,57 @@ function showVersion() {
|
|
|
3720
3919
|
function showHelp() {
|
|
3721
3920
|
console.log(`elcrm \u2014 CLI \u0434\u043B\u044F \u044D\u043A\u043E\u0441\u0438\u0441\u0442\u0435\u043C\u044B @elcrm/*
|
|
3722
3921
|
|
|
3723
|
-
\
|
|
3724
|
-
elcrm
|
|
3922
|
+
\u0415\u0436\u0435\u0434\u043D\u0435\u0432\u043D\u044B\u0439 \u0446\u0438\u043A\u043B:
|
|
3923
|
+
elcrm update --fix --test
|
|
3924
|
+
elcrm css
|
|
3925
|
+
elcrm docs
|
|
3926
|
+
elcrm cursor
|
|
3725
3927
|
|
|
3726
3928
|
\u041A\u043E\u043C\u0430\u043D\u0434\u044B:
|
|
3727
|
-
upd
|
|
3728
|
-
\u041E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0441\u0430\u043C CLI: bun i -g elcrm@latest (\u0431\u0435\u0437 bun \u2014 npm)
|
|
3729
|
-
|
|
3730
3929
|
update [--dry] [--core] [--no-install] [--fix] [--test]
|
|
3731
|
-
|
|
3732
|
-
\
|
|
3930
|
+
bun i -g elcrm@latest + @elcrm/* \u2192 install
|
|
3931
|
+
--fix = migrate front + sync CSS (\u0442\u043E\u043A\u0435\u043D\u044B, \u2212\u0431\u0438\u0442\u044B\u0435 @import) + css-sanitize
|
|
3932
|
+
--test = elcrm test
|
|
3733
3933
|
|
|
3734
|
-
|
|
3735
|
-
\
|
|
3736
|
-
|
|
3934
|
+
css [--dry] [--dir=\u2026]
|
|
3935
|
+
\u0422\u043E\u043A\u0435\u043D\u044B \u2192 theme*.css; elcrm.css: +\u0440\u0430\u0431\u043E\u0447\u0438\u0435 @import, \u2212\u0431\u0438\u0442\u044B\u0435 (\u043D\u0435\u0442 \u0444\u0430\u0439\u043B\u0430 \u0432 \u043F\u0430\u043A\u0435\u0442\u0435)
|
|
3936
|
+
\u0417\u0430\u0442\u0435\u043C css-sanitize (\u043E\u0441\u0438\u0440\u043E\u0442\u0435\u0432\u0448\u0438\u0439 color-mix)
|
|
3737
3937
|
|
|
3738
|
-
|
|
3739
|
-
\
|
|
3938
|
+
docs [--dry] [--keep] [--dir=\u2026] [--lib]
|
|
3939
|
+
docs/*.elCRM.md (\u0448\u043F\u0430\u0440\u0433\u0430\u043B\u043A\u0438 \u043F\u0430\u043A\u0435\u0442\u043E\u0432)
|
|
3740
3940
|
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
\
|
|
3941
|
+
cursor [--dry] [--keep] [--dir=\u2026] [--lib|-lib]
|
|
3942
|
+
.cursor/rules + .cursor/docs + AGENTS.md
|
|
3943
|
+
--lib: \u0447\u0435\u043A\u043B\u0438\u0441\u0442 \u0430\u0432\u0442\u043E\u0440\u0430 @elcrm/*
|
|
3944
|
+
|
|
3945
|
+
migrate <name> [--dry] | migrate --list
|
|
3946
|
+
front|ui = \u043F\u0430\u043A\u0435\u0442 \u043C\u0438\u0433\u0440\u0430\u0446\u0438\u0439 (aliases, tokens, components, css-sanitize, size, \u2026)
|
|
3947
|
+
\u043F\u043E \u043E\u0434\u043D\u043E\u0439: form-aliases, form-tokens, components, css-sanitize, size-sml,
|
|
3948
|
+
field-border, modal-create, legacy-hacks, socket-server
|
|
3744
3949
|
|
|
3745
|
-
|
|
3746
|
-
\
|
|
3747
|
-
|
|
3950
|
+
audit [--fix] [--dry] [--dir=\u2026]
|
|
3951
|
+
\u0421\u0442\u0430\u0440\u044B\u0435 API, \u0431\u0438\u0442\u044B\u0435 @import, orphan color-mix; --fix = migrate front
|
|
3952
|
+
\u041F\u043E\u0441\u043B\u0435 --fix \u0434\u043B\u044F imports: elcrm css
|
|
3748
3953
|
|
|
3749
3954
|
doctor [--fix]
|
|
3750
|
-
\
|
|
3955
|
+
\u0421\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u044B; \u043D\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 --fix \u2192 bunx elcrm-server update
|
|
3751
3956
|
|
|
3752
3957
|
test [dir] [--front|--server] [--no-scripts]
|
|
3753
|
-
\
|
|
3754
|
-
(workspaces \u2014 \u043A\u0430\u0436\u0434\u044B\u0439 \u043F\u0430\u043A\u0435\u0442 \u0441\u0432\u043E\u0438\u043C \u0440\u0435\u0436\u0438\u043C\u043E\u043C)
|
|
3958
|
+
\u0421\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438\u0439 \u0430\u043D\u0430\u043B\u0438\u0437 + scripts \u043F\u0440\u043E\u0435\u043A\u0442\u0430
|
|
3755
3959
|
|
|
3960
|
+
create <name> [--template app|lib|panel] [--no-install]
|
|
3961
|
+
init [--template app|lib|panel] [--force] [--no-install]
|
|
3756
3962
|
build [--client] [--url=\u2026] [--name=\u2026] [--dir=\u2026] [--folder=\u2026]
|
|
3757
|
-
\u0421\u0431\u043E\u0440\u043A\u0430 \u0438 \u0434\u0435\u043F\u043B\u043E\u0439 (\u0438\u0437 @elcrm/deploy)
|
|
3758
|
-
|
|
3759
3963
|
postbuild [--dir=./dist]
|
|
3760
|
-
\u041F\u043E\u0441\u043B\u0435 vite build lib-\u043F\u0430\u043A\u0435\u0442\u0430: \u0441\u043A\u043B\u0435\u0438\u0442\u044C CSS + \u0441\u043F\u043B\u044E\u0449\u0438\u0442\u044C .d.ts
|
|
3761
|
-
(package.json: "build": "vite build && elcrm postbuild")
|
|
3762
|
-
|
|
3763
|
-
css [--dry] [--dir=\u2026]
|
|
3764
|
-
\u0414\u0435\u0444\u043E\u043B\u0442\u043D\u044B\u0435 \u0442\u043E\u043A\u0435\u043D\u044B @elcrm/* \u2192 src/style/theme.css, theme-light/dark, elcrm.css
|
|
3765
|
-
\u0423\u0436\u0435 \u0437\u0430\u0434\u0430\u043D\u043D\u044B\u0435 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435 \u043D\u0435 \u0437\u0430\u0442\u0438\u0440\u0430\u044E\u0442\u0441\u044F, \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u0435\u0434\u043E\u0441\u0442\u0430\u044E\u0449\u0438\u0435 (\u0433\u0440\u0443\u043F\u043F\u044B \u0447\u0435\u0440\u0435\u0437 \u043F\u0443\u0441\u0442\u0443\u044E \u0441\u0442\u0440\u043E\u043A\u0443)
|
|
3766
|
-
|
|
3767
|
-
docs [--dry] [--keep] [--dir=\u2026] [--lib]
|
|
3768
|
-
docs/*.elCRM.md \u043F\u043E \u043F\u0430\u043A\u0435\u0442\u0430\u043C (cli, api, alert, button, modal, notice, \u2026)
|
|
3769
|
-
\u0441\u0435\u0440\u0432\u0435\u0440-only \u2192 SERVER, CLI, API, SOCKET; --lib \u0438\u043B\u0438 \u043F\u0430\u043A\u0435\u0442 @elcrm/* \u2192 \u0432\u0441\u0435 \u0444\u0430\u0439\u043B\u044B
|
|
3770
|
-
|
|
3771
|
-
cursor [--dry] [--keep] [--dir=\u2026] [--lib|-lib]
|
|
3772
|
-
.cursor/rules + .cursor/docs + AGENTS.md
|
|
3773
|
-
--lib: \u0447\u0435\u043A\u043B\u0438\u0441\u0442 \u0430\u0432\u0442\u043E\u0440\u0430 \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438 (\u043F\u043E\u0441\u043B\u0435 \u043F\u0440\u0430\u0432\u043E\u043A src \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C CLI-\u0448\u043F\u0430\u0440\u0433\u0430\u043B\u043A\u0438)
|
|
3774
|
-
|
|
3775
3964
|
uuid
|
|
3776
|
-
\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C UUID
|
|
3777
|
-
|
|
3778
|
-
help
|
|
3779
|
-
\u042D\u0442\u0430 \u0441\u043F\u0440\u0430\u0432\u043A\u0430
|
|
3780
3965
|
|
|
3781
|
-
\u0424\u043B\u0430\u0433\u0438:
|
|
3782
|
-
-v, --version \u0412\u0435\u0440\u0441\u0438\u044F CLI
|
|
3783
|
-
-h, --help \u0421\u043F\u0440\u0430\u0432\u043A\u0430
|
|
3966
|
+
\u0424\u043B\u0430\u0433\u0438: -v/--version, -h/--help
|
|
3784
3967
|
|
|
3785
3968
|
\u041F\u0440\u0438\u043C\u0435\u0440\u044B:
|
|
3786
|
-
elcrm
|
|
3787
|
-
elcrm
|
|
3788
|
-
elcrm update
|
|
3789
|
-
elcrm update --dry
|
|
3790
|
-
elcrm update --fix --test
|
|
3791
|
-
elcrm migrate form-aliases --dry
|
|
3792
|
-
elcrm migrate form-tokens --dry
|
|
3793
|
-
elcrm create my-app --template app
|
|
3794
|
-
elcrm init --template panel
|
|
3795
|
-
elcrm init --template lib
|
|
3796
|
-
elcrm migrate front --dry
|
|
3797
|
-
elcrm migrate size-sml
|
|
3969
|
+
elcrm update --fix --test && elcrm css && elcrm docs && elcrm cursor
|
|
3970
|
+
elcrm css # ENOENT @elcrm/\u2026/light.css \u2192 \u0441\u043D\u0438\u043C\u0435\u0442 \u0431\u0438\u0442\u044B\u0439 import
|
|
3798
3971
|
elcrm audit
|
|
3799
|
-
elcrm
|
|
3800
|
-
elcrm doctor --fix
|
|
3801
|
-
elcrm test
|
|
3802
|
-
elcrm test --server
|
|
3803
|
-
elcrm build --client --url=https://example.com/deploy
|
|
3804
|
-
elcrm postbuild
|
|
3805
|
-
elcrm css
|
|
3806
|
-
elcrm css --dry
|
|
3807
|
-
elcrm docs
|
|
3808
|
-
elcrm cursor
|
|
3809
|
-
elcrm cursor --lib
|
|
3972
|
+
elcrm migrate front --dry
|
|
3810
3973
|
`);
|
|
3811
3974
|
}
|
|
3812
3975
|
async function main() {
|
|
@@ -3823,9 +3986,6 @@ async function main() {
|
|
|
3823
3986
|
console.log("parseArgs:", JSON.stringify(parsed, null, 2));
|
|
3824
3987
|
}
|
|
3825
3988
|
switch (parsed.command) {
|
|
3826
|
-
case "upd":
|
|
3827
|
-
await cmdUpd();
|
|
3828
|
-
break;
|
|
3829
3989
|
case "update":
|
|
3830
3990
|
await cmdUpdate(parsed);
|
|
3831
3991
|
break;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "elcrm",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "CLI @elcrm/*: update
|
|
3
|
+
"version": "1.1.5",
|
|
4
|
+
"description": "CLI @elcrm/*: update --fix --test, css (prune imports), docs, cursor, migrate, audit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "MaSkal <dev@elcrm.online>",
|
|
@@ -13,7 +13,7 @@ alwaysApply: true
|
|
|
13
13
|
|
|
14
14
|
| Файл | Пакет | Делать так |
|
|
15
15
|
| ------------------------ | ---------------------- | ------------------------------------------------------- |
|
|
16
|
-
| `CLI.elCRM.md` | `elcrm` | `
|
|
16
|
+
| `CLI.elCRM.md` | `elcrm` | `update --fix --test` (CLI + пакеты), docs, cursor |
|
|
17
17
|
| `API.elCRM.md` | `@elcrm/api` | `Api.create` + `Api.query("router/method", body)` |
|
|
18
18
|
| `ALERT.elCRM.md` | `@elcrm/alert` | `<Alert.Init />`, `Alert.Send` / `Confirm` |
|
|
19
19
|
| `BUTTON.elCRM.md` | `@elcrm/button` | `<Button onSend>`, size s/m/l, не `<button>` |
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
<!--
|
|
1
|
+
<!-- Источник: elCRM.cli/templates/elcrm-docs/CLI.elCRM.md. Обновить: elcrm docs. -->
|
|
2
2
|
|
|
3
3
|
# `elcrm` CLI
|
|
4
4
|
|
|
5
|
-
Глобально: `bun i -g elcrm`
|
|
5
|
+
Глобально: `bun i -g elcrm` (нужна **свежая** версия: `elcrm -v`).
|
|
6
|
+
|
|
7
|
+
## Ежедневный цикл (запомнить эти 4)
|
|
8
|
+
|
|
9
|
+
После смены `@elcrm/*` или если «что-то сломалось» в UI/CSS:
|
|
6
10
|
|
|
7
11
|
```bash
|
|
8
12
|
elcrm update --fix --test
|
|
@@ -11,18 +15,102 @@ elcrm docs
|
|
|
11
15
|
elcrm cursor
|
|
12
16
|
```
|
|
13
17
|
|
|
14
|
-
| Команда |
|
|
18
|
+
| # | Команда | Что делает |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| 1 | `elcrm update --fix --test` | Обновляет глобальный `elcrm` + все `@elcrm/*` в `package.json` → install → **migrate front** (API/токены/css-sanitize) → внутри `--fix` ещё раз **sync CSS** → `elcrm test` |
|
|
21
|
+
| 2 | `elcrm css` | Недостающие CSS-токены → `theme.css` / `theme-light` / `theme-dark`. В `elcrm.css`: **добавляет** рабочие `@import`, **удаляет битые** (нет export/файла в установленном пакете). Затем css-sanitize |
|
|
22
|
+
| 3 | `elcrm docs` | Перезаписывает `docs/*.elCRM.md` (шпаргалки пакетов) |
|
|
23
|
+
| 4 | `elcrm cursor` | `.cursor/rules` + `.cursor/docs` + `AGENTS.md` для агента |
|
|
24
|
+
|
|
25
|
+
Не чинит само по себе: ручные баги в компонентах, сервер без `elcrm-server`, секреты. Чинит: устаревшие API после миграций, битые `@import` в `elcrm.css`, осиротевший `color-mix`, недостающие токены.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Все команды
|
|
30
|
+
|
|
31
|
+
### `update` — зависимости
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
elcrm update # latest @elcrm/* + bun i -g elcrm@latest
|
|
35
|
+
elcrm update --dry # только отчёт
|
|
36
|
+
elcrm update --core # версии как в @elcrm/core
|
|
37
|
+
elcrm update --no-install # только package.json
|
|
38
|
+
elcrm update --fix # + migrate front + sync CSS (+ prune битых @import)
|
|
39
|
+
elcrm update --test # + elcrm test (обычно вместе: --fix --test)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### `css` — стили приложения
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
elcrm css # токены + починка elcrm.css
|
|
46
|
+
elcrm css --dry
|
|
47
|
+
elcrm css --dir=./web # panel: web/
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Почему Vite ругался на `@elcrm/search/light.css`: в `elcrm.css` остался `@import`, а в **установленном** `@elcrm/search@0.1.4` нет export `./light.css`. Раньше `css` только добавлял imports — теперь **снимает** такие строки. Лечение: `elcrm css` (или `update --fix`).
|
|
51
|
+
|
|
52
|
+
### `docs` / `cursor` — шпаргалки
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
elcrm docs # docs/*.elCRM.md
|
|
56
|
+
elcrm docs --dry | --keep | --lib | --dir=…
|
|
57
|
+
elcrm cursor # .cursor/rules + .cursor/docs + AGENTS.md
|
|
58
|
+
elcrm cursor --lib # + чеклист автора @elcrm/* (правило elcrm-lib)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### `migrate` — точечные правки кода
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
elcrm migrate --list
|
|
65
|
+
elcrm migrate front # пакет (то же, что update/audit/doctor --fix):
|
|
66
|
+
# form-aliases → form-tokens → components →
|
|
67
|
+
# css-sanitize → size-sml → field-border →
|
|
68
|
+
# modal-create → socket-server
|
|
69
|
+
elcrm migrate css-sanitize # осиротевшие in srgb / transparent);
|
|
70
|
+
elcrm migrate components # Block/Row → Stack, --page-* → --shell-*
|
|
71
|
+
elcrm migrate form-tokens
|
|
72
|
+
elcrm migrate form-aliases
|
|
73
|
+
elcrm migrate size-sml # size sm|md → s|m|l
|
|
74
|
+
elcrm migrate field-border
|
|
75
|
+
elcrm migrate modal-create # Modal.Add → Create
|
|
76
|
+
elcrm migrate legacy-hacks # только по имени, не в front
|
|
77
|
+
elcrm migrate socket-server
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Флаг у всех: `--dry`.
|
|
81
|
+
|
|
82
|
+
### `audit` / `doctor` / `test` — проверки
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
elcrm audit # старые API, битые @import, orphan color-mix, …
|
|
86
|
+
elcrm audit --fix # = migrate front (+ css не вызывает — после: elcrm css)
|
|
87
|
+
elcrm doctor # стандарты проекта
|
|
88
|
+
elcrm doctor --fix # type/engines + migrate front
|
|
89
|
+
elcrm test # статический анализ + scripts проекта
|
|
90
|
+
elcrm test --front|--server|--no-scripts
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Прочее
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
elcrm create <name> [--template app|lib|panel] [--no-install]
|
|
97
|
+
elcrm init [--template …] [--force] [--no-install]
|
|
98
|
+
elcrm build --client [--url=…] [--name=…] [--dir=…] [--folder=…]
|
|
99
|
+
elcrm postbuild [--dir=./dist] # lib: склейка CSS после vite build
|
|
100
|
+
elcrm uuid
|
|
101
|
+
elcrm -v / --help
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Когда что запускать
|
|
107
|
+
|
|
108
|
+
| Ситуация | Команды |
|
|
15
109
|
| --- | --- |
|
|
16
|
-
|
|
|
17
|
-
| `
|
|
18
|
-
|
|
|
19
|
-
|
|
|
20
|
-
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
| `css [--dry]` | недостающие токены → theme*.css |
|
|
24
|
-
| `docs` / `cursor` | шпаргалки и правила агента |
|
|
25
|
-
| `cursor --lib` / `-lib` | правила автора `@elcrm/*` lib (чеклист после правок src) |
|
|
26
|
-
| `build` / `postbuild` / `uuid` | деплой клиента/api; склейка CSS lib |
|
|
27
|
-
|
|
28
|
-
Не выдумывать флаги — `elcrm --help` и `COMMANDS.md`.
|
|
110
|
+
| Обновили пакеты / «после elcrm update всё красное» | полный цикл из 4 команд сверху |
|
|
111
|
+
| Vite: `ENOENT … @elcrm/…/light.css` | `elcrm css` → при необходимости `elcrm audit` |
|
|
112
|
+
| Битый theme (`in srgb` без свойства) | `elcrm migrate css-sanitize` или `update --fix` |
|
|
113
|
+
| Агент врёт API | `elcrm docs && elcrm cursor` |
|
|
114
|
+
| Автор правит `@elcrm/*` src | чеклист: `elcrm cursor --lib`; шпаргалки править в **elCRM.cli** |
|
|
115
|
+
|
|
116
|
+
Не выдумывать флаги — `elcrm --help` и `COMMANDS.md` в репо CLI.
|