@codefast/cli 0.3.7-canary.0 → 0.3.13-canary.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/README.md +178 -262
- package/dist/analyze-DvtJ3j9m.mjs +92 -0
- package/dist/arrange-Bbh62DrU.mjs +107 -0
- package/dist/arrange-BqP2DI3w.mjs +8 -0
- package/dist/ast-helpers-MDRYuIAk.mjs +115 -0
- package/dist/bin.mjs +8 -0
- package/dist/caught-unknown-message-CRhkDWO7.mjs +20 -0
- package/dist/collectors-cn-BS8TTQ8O.mjs +61 -0
- package/dist/collectors-jsx-D9tL2ZPM.mjs +20 -0
- package/dist/collectors-tv-D2PXZaRt.mjs +170 -0
- package/dist/colors-BjdkCfGK.mjs +12 -0
- package/dist/commands/arrange.mjs +2 -0
- package/dist/commands/mirror.mjs +2 -0
- package/dist/commands/mirror.test.mjs +48 -0
- package/dist/commands/tag.mjs +2 -0
- package/dist/config-DVia_f9a.mjs +3 -0
- package/dist/config-reporter-SCcWDZc1.mjs +10 -0
- package/dist/constants-AtPhF-Ct.mjs +169 -0
- package/dist/constants-Bq5wdyLC.mjs +8 -0
- package/dist/dirent-list-BSDeRG5i.mjs +14 -0
- package/dist/engine-CcWEHSCq.mjs +287 -0
- package/dist/engine-DRTdkc5u.mjs +236 -0
- package/dist/errors-CFH4w6ic.mjs +15 -0
- package/dist/errors-CpU1ogfA.mjs +19 -0
- package/dist/formatters-DGE8jJ53.mjs +52 -0
- package/dist/group-file-ClW7XdD6.mjs +113 -0
- package/dist/grouping-c1grpCQT.mjs +235 -0
- package/dist/imports-DSVq1xhB.mjs +54 -0
- package/dist/lib/arrange/application/analyze.mjs +2 -0
- package/dist/lib/arrange/application/analyze.test.mjs +171 -0
- package/dist/lib/arrange/application/group-file.mjs +2 -0
- package/dist/lib/arrange/application/group-file.test.mjs +273 -0
- package/dist/lib/arrange/application/run-target.mjs +2 -0
- package/dist/lib/arrange/application/run-target.test.mjs +97 -0
- package/dist/lib/arrange/domain/ast/ast-helpers.mjs +2 -0
- package/dist/lib/arrange/domain/ast/ast-helpers.test.mjs +148 -0
- package/dist/lib/arrange/domain/ast/collectors-cn.mjs +2 -0
- package/dist/lib/arrange/domain/ast/collectors-cn.test.mjs +58 -0
- package/dist/lib/arrange/domain/ast/collectors-jsx.mjs +2 -0
- package/dist/lib/arrange/domain/ast/collectors-jsx.test.mjs +20 -0
- package/dist/lib/arrange/domain/ast/collectors-tv.mjs +2 -0
- package/dist/lib/arrange/domain/ast/collectors-tv.test.mjs +145 -0
- package/dist/lib/arrange/domain/ast/targets.mjs +2 -0
- package/dist/lib/arrange/domain/ast/targets.test.mjs +50 -0
- package/dist/lib/arrange/domain/constants.mjs +2 -0
- package/dist/lib/arrange/domain/errors.mjs +2 -0
- package/dist/lib/arrange/domain/grouping.mjs +2 -0
- package/dist/lib/arrange/domain/grouping.test.mjs +186 -0
- package/dist/lib/arrange/domain/imports.mjs +2 -0
- package/dist/lib/arrange/domain/imports.test.mjs +48 -0
- package/dist/lib/arrange/domain/tokenizer.mjs +2 -0
- package/dist/lib/arrange/domain/tokenizer.test.mjs +165 -0
- package/dist/lib/arrange/domain/types.mjs +1 -0
- package/dist/lib/arrange/index.mjs +16 -0
- package/dist/lib/arrange/infra/walk.mjs +2 -0
- package/dist/lib/arrange/infra/walk.test.mjs +50 -0
- package/dist/lib/arrange/presentation/formatters.mjs +2 -0
- package/dist/lib/arrange/presentation/formatters.test.mjs +73 -0
- package/dist/lib/arrange/presentation/report.mjs +2 -0
- package/dist/lib/config/domain/schema.mjs +2 -0
- package/dist/lib/config/index.mjs +4 -0
- package/dist/lib/config/infra/loader.mjs +2 -0
- package/dist/lib/config/infra/loader.test.mjs +116 -0
- package/dist/lib/infra/caught-unknown-message.mjs +2 -0
- package/dist/lib/infra/config-reporter.mjs +2 -0
- package/dist/lib/infra/fs-contract.mjs +1 -0
- package/dist/lib/infra/node-io.mjs +2 -0
- package/dist/lib/infra/workspace/repo-root.mjs +2 -0
- package/dist/lib/infra/workspace/repo-root.test.mjs +45 -0
- package/dist/lib/mirror/application/engine.mjs +2 -0
- package/dist/lib/mirror/application/sync.mjs +2 -0
- package/dist/lib/mirror/application/sync.test.mjs +482 -0
- package/dist/lib/mirror/domain/constants.mjs +2 -0
- package/dist/lib/mirror/domain/errors.mjs +2 -0
- package/dist/lib/mirror/domain/types.mjs +1 -0
- package/dist/lib/mirror/index.mjs +3 -0
- package/dist/lib/mirror/infra/dirent-list.mjs +2 -0
- package/dist/lib/mirror/infra/dirent-list.test.mjs +18 -0
- package/dist/lib/mirror/infra/package-filter.mjs +2 -0
- package/dist/lib/mirror/infra/package-filter.test.mjs +32 -0
- package/dist/lib/mirror/infra/path-normalizer.mjs +2 -0
- package/dist/lib/mirror/infra/update-pkg.mjs +2 -0
- package/dist/lib/mirror/infra/workspace-packages.mjs +2 -0
- package/dist/lib/mirror/infra/workspace-packages.test.mjs +167 -0
- package/dist/lib/mirror/presentation/reporter.mjs +2 -0
- package/dist/lib/tag/application/engine.mjs +2 -0
- package/dist/lib/tag/application/engine.test.mjs +159 -0
- package/dist/lib/tag/domain/types.mjs +1 -0
- package/dist/lib/tag/index.mjs +5 -0
- package/dist/lib/tag/infra/target-resolver.mjs +2 -0
- package/dist/lib/tag/presentation/colors.mjs +2 -0
- package/dist/lib/tag/presentation/tag-presenter.mjs +2 -0
- package/dist/lib/tag/presentation/tag-presenter.test.mjs +29 -0
- package/dist/loader-DpN-zl5g.mjs +78 -0
- package/dist/mirror-CbGiLXKT.mjs +2 -0
- package/dist/mirror-DqJE3ejL.mjs +66 -0
- package/dist/node-io-DFRbHO6m.mjs +30 -0
- package/dist/package-filter-C_8ryqvz.mjs +26 -0
- package/dist/path-normalizer-D4ceBO3l.mjs +7 -0
- package/dist/program-DR-H4tH3.mjs +34 -0
- package/dist/program.mjs +2 -0
- package/dist/repo-root-HmtIEm6J.mjs +22 -0
- package/dist/report-DYxvw34T.mjs +24 -0
- package/dist/reporter-CwIe_tAM.mjs +108 -0
- package/dist/run-target-CJWrqNT4.mjs +65 -0
- package/dist/schema-Or8RAARd.mjs +25 -0
- package/dist/sync-e1Sp-shi.mjs +157 -0
- package/dist/tag-Cd9JujU5.mjs +2 -0
- package/dist/tag-hEKVZ_-7.mjs +58 -0
- package/dist/tag-presenter-Cs66UBsH.mjs +63 -0
- package/dist/target-resolver-CR3FXMTy.mjs +170 -0
- package/dist/targets-pCTslnFh.mjs +106 -0
- package/dist/tokenizer-CeZx73Zu.mjs +216 -0
- package/dist/update-pkg-CnGfjWBy.mjs +37 -0
- package/dist/walk-DjgQn66n.mjs +33 -0
- package/dist/workspace-packages-K2NYTHJq.mjs +159 -0
- package/package.json +42 -53
- package/CHANGELOG.md +0 -15
- package/dist/cjs/index.cjs +0 -2
- package/dist/cjs/src/index.d.ts +0 -3
- package/dist/cjs/src/index.d.ts.map +0 -1
- package/dist/esm/index.js +0 -2
- package/dist/esm/src/index.d.ts +0 -3
- package/dist/esm/src/index.d.ts.map +0 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { n as ensureCnImport, t as cnModuleSpecifierForFile } from "../../../imports-DSVq1xhB.mjs";
|
|
2
|
+
import "../../../arrange-BqP2DI3w.mjs";
|
|
3
|
+
//#region src/lib/arrange/domain/imports.test.ts
|
|
4
|
+
describe("cnModuleSpecifierForFile", () => {
|
|
5
|
+
it("documents that default module specifier is stable across file paths", () => {
|
|
6
|
+
expect(cnModuleSpecifierForFile("/repo/packages/ui/src/components/a.tsx")).toBe("@codefast/tailwind-variants");
|
|
7
|
+
expect(cnModuleSpecifierForFile("/repo/packages/cli/src/lib/a.ts")).toBe("@codefast/tailwind-variants");
|
|
8
|
+
});
|
|
9
|
+
it("documents that explicit override always takes precedence", () => {
|
|
10
|
+
expect(cnModuleSpecifierForFile("/repo/packages/ui/src/components/a.tsx", "clsx")).toBe("clsx");
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
describe("ensureCnImport", () => {
|
|
14
|
+
it("does not change source when cn is imported as default binding", () => {
|
|
15
|
+
const source = "import cn from \"@codefast/tailwind-variants\";\nconst x = 1;\n";
|
|
16
|
+
expect(ensureCnImport(source, "/repo/x.ts")).toBe(source);
|
|
17
|
+
});
|
|
18
|
+
it("does not change source when cn already imported", () => {
|
|
19
|
+
const source = "import { cn, tv } from \"@codefast/tailwind-variants\";\nconst x = 1;\n";
|
|
20
|
+
expect(ensureCnImport(source, "/repo/x.ts")).toBe(source);
|
|
21
|
+
});
|
|
22
|
+
it("injects cn into an existing named import from matching module", () => {
|
|
23
|
+
const out = ensureCnImport("import { tv } from \"clsx\";\nconst x = 1;\n", "/repo/x.ts", "clsx");
|
|
24
|
+
expect(out).toContain("import { cn, tv } from \"clsx\";");
|
|
25
|
+
});
|
|
26
|
+
it("inserts after use client directive", () => {
|
|
27
|
+
const out = ensureCnImport("\"use client\";\n\nexport const x = 1;\n", "/repo/x.tsx");
|
|
28
|
+
expect(out.startsWith("\"use client\";\n\nimport { cn }")).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
it("inserts before first import when no matching import exists", () => {
|
|
31
|
+
const out = ensureCnImport("import { tv } from \"clsx\";\nconst x = 1;\n", "/repo/x.ts");
|
|
32
|
+
expect(out.indexOf("import { cn } from \"@codefast/tailwind-variants\";")).toBe(0);
|
|
33
|
+
});
|
|
34
|
+
it("inserts at file start when there are no imports", () => {
|
|
35
|
+
const out = ensureCnImport("const x = 1;\n", "/repo/x.ts");
|
|
36
|
+
expect(out.startsWith("import { cn } from \"@codefast/tailwind-variants\";\n")).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
it("respects module override when adding new import", () => {
|
|
39
|
+
const out = ensureCnImport("const x = 1;\n", "/repo/x.ts", "clsx");
|
|
40
|
+
expect(out.startsWith("import { cn } from \"clsx\";\n")).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
it("keeps existing legacy tailwind-variants import unchanged (backward compat)", () => {
|
|
43
|
+
const source = "import { cn, tv } from \"tailwind-variants\";\nconst x = 1;\n";
|
|
44
|
+
expect(ensureCnImport(source, "/repo/x.ts")).toBe(source);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
//#endregion
|
|
48
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as compositeSecondaryOrder, c as selectorKey, d as tokenizeClassString, i as classifyToken, l as stateKey, n as bucketsMergeCompatible, o as indexOfFirstVariantColon, r as classifyBareUtility, s as isArbitraryParentSelectorStateToken, t as bucketsCompatible, u as stripVariants } from "../../../tokenizer-CeZx73Zu.mjs";
|
|
2
|
+
export { bucketsCompatible, bucketsMergeCompatible, classifyBareUtility, classifyToken, compositeSecondaryOrder, indexOfFirstVariantColon, isArbitraryParentSelectorStateToken, selectorKey, stateKey, stripVariants, tokenizeClassString };
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { c as selectorKey, d as tokenizeClassString, i as classifyToken, l as stateKey, n as bucketsMergeCompatible, o as indexOfFirstVariantColon, t as bucketsCompatible, u as stripVariants } from "../../../tokenizer-CeZx73Zu.mjs";
|
|
2
|
+
import "../../../arrange-BqP2DI3w.mjs";
|
|
3
|
+
//#region src/lib/arrange/domain/tokenizer.test.ts
|
|
4
|
+
describe("tokenizeClassString", () => {
|
|
5
|
+
it("trims and splits on whitespace runs", () => {
|
|
6
|
+
expect(tokenizeClassString(" flex gap-2 ")).toEqual(["flex", "gap-2"]);
|
|
7
|
+
});
|
|
8
|
+
it("returns empty for whitespace-only input", () => {
|
|
9
|
+
expect(tokenizeClassString(" \n ")).toEqual([]);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
describe("bucketsMergeCompatible", () => {
|
|
13
|
+
it.each([
|
|
14
|
+
[
|
|
15
|
+
"state",
|
|
16
|
+
"state",
|
|
17
|
+
false
|
|
18
|
+
],
|
|
19
|
+
[
|
|
20
|
+
"starting",
|
|
21
|
+
"starting",
|
|
22
|
+
false
|
|
23
|
+
],
|
|
24
|
+
[
|
|
25
|
+
"layout",
|
|
26
|
+
"sizing",
|
|
27
|
+
true
|
|
28
|
+
],
|
|
29
|
+
[
|
|
30
|
+
"shape",
|
|
31
|
+
"shadow",
|
|
32
|
+
true
|
|
33
|
+
],
|
|
34
|
+
[
|
|
35
|
+
"layout",
|
|
36
|
+
"state",
|
|
37
|
+
false
|
|
38
|
+
],
|
|
39
|
+
[
|
|
40
|
+
"arbitrary",
|
|
41
|
+
"arbitrary",
|
|
42
|
+
false
|
|
43
|
+
],
|
|
44
|
+
[
|
|
45
|
+
"arbitrary",
|
|
46
|
+
"state",
|
|
47
|
+
false
|
|
48
|
+
],
|
|
49
|
+
[
|
|
50
|
+
"selector",
|
|
51
|
+
"selector",
|
|
52
|
+
false
|
|
53
|
+
],
|
|
54
|
+
[
|
|
55
|
+
"layout",
|
|
56
|
+
"selector",
|
|
57
|
+
false
|
|
58
|
+
],
|
|
59
|
+
[
|
|
60
|
+
"selector",
|
|
61
|
+
"state",
|
|
62
|
+
false
|
|
63
|
+
]
|
|
64
|
+
])("merge compatibility %s + %s -> %s", (a, b, expected) => {
|
|
65
|
+
expect(bucketsMergeCompatible(a, b)).toBe(expected);
|
|
66
|
+
expect(bucketsMergeCompatible(b, a)).toBe(expected);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe("bucketsCompatible", () => {
|
|
70
|
+
it.each([
|
|
71
|
+
[
|
|
72
|
+
"layout",
|
|
73
|
+
"layout",
|
|
74
|
+
true
|
|
75
|
+
],
|
|
76
|
+
[
|
|
77
|
+
"layout",
|
|
78
|
+
"sizing",
|
|
79
|
+
true
|
|
80
|
+
],
|
|
81
|
+
[
|
|
82
|
+
"shape",
|
|
83
|
+
"shadow",
|
|
84
|
+
true
|
|
85
|
+
],
|
|
86
|
+
[
|
|
87
|
+
"layout",
|
|
88
|
+
"state",
|
|
89
|
+
false
|
|
90
|
+
],
|
|
91
|
+
[
|
|
92
|
+
"arbitrary",
|
|
93
|
+
"state",
|
|
94
|
+
false
|
|
95
|
+
],
|
|
96
|
+
[
|
|
97
|
+
"layout",
|
|
98
|
+
"selector",
|
|
99
|
+
false
|
|
100
|
+
]
|
|
101
|
+
])("compatibility %s + %s -> %s", (a, b, expected) => {
|
|
102
|
+
expect(bucketsCompatible(a, b)).toBe(expected);
|
|
103
|
+
expect(bucketsCompatible(b, a)).toBe(expected);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe("stateKey", () => {
|
|
107
|
+
it("uses the full variant stack for unique keys", () => {
|
|
108
|
+
expect(stateKey("@md/field-group:[&>*]:w-auto")).not.toBe(stateKey("@md/field-group:[&>[data-slot=field-label]]:flex-auto"));
|
|
109
|
+
});
|
|
110
|
+
it("normalizes bracketed data variant stems", () => {
|
|
111
|
+
expect(stateKey("data-[state=open]:opacity-100")).toBe("data-[state=open]");
|
|
112
|
+
expect(stateKey("in-data-[slot=tooltip-content]:bg-background/20")).toBe("in-data-[slot=tooltip-content]");
|
|
113
|
+
});
|
|
114
|
+
it("keeps distinct keys for in-data-side-* stems", () => {
|
|
115
|
+
expect(stateKey("in-data-side-right:cursor-e-resize")).toBe("in-data-side-right");
|
|
116
|
+
expect(stateKey("in-data-side-left:cursor-w-resize")).not.toBe(stateKey("in-data-side-right:cursor-e-resize"));
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe("indexOfFirstVariantColon + stripVariants", () => {
|
|
120
|
+
it("ignores colons inside square brackets", () => {
|
|
121
|
+
const tok = "[&_a:hover]:text-red-500";
|
|
122
|
+
expect(indexOfFirstVariantColon(tok)).toBe(11);
|
|
123
|
+
expect(stripVariants(tok)).toBe("text-red-500");
|
|
124
|
+
});
|
|
125
|
+
it("strips stacked variant prefixes", () => {
|
|
126
|
+
expect(stripVariants("@min-[600px]:@max-[900px]:hidden")).toBe("hidden");
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe("classifyToken", () => {
|
|
130
|
+
it.each([
|
|
131
|
+
["flex", "layout"],
|
|
132
|
+
["w-4", "sizing"],
|
|
133
|
+
["px-3", "spacing"],
|
|
134
|
+
["rounded-md", "shape"],
|
|
135
|
+
["text-sm", "typography"],
|
|
136
|
+
["transition", "motion"],
|
|
137
|
+
["outline-hidden", "shadow"],
|
|
138
|
+
["focus-visible:outline-hidden", "state"],
|
|
139
|
+
["hover:opacity-80", "state"],
|
|
140
|
+
["[&_svg]:size-4", "selector"],
|
|
141
|
+
["*:rounded", "selector"],
|
|
142
|
+
["**:text-sm", "selector"],
|
|
143
|
+
["has-[img]:bg-muted", "selector"],
|
|
144
|
+
["in-[.popover]:opacity-100", "selector"],
|
|
145
|
+
["group-[.is-published]:block", "selector"],
|
|
146
|
+
["peer-[.is-dirty]:peer-required:block", "selector"],
|
|
147
|
+
["not-[.prose]:mt-4", "selector"],
|
|
148
|
+
["starting:opacity-0", "starting"],
|
|
149
|
+
["cursor-default", "behavior"],
|
|
150
|
+
["@container/sidebar", "existence"],
|
|
151
|
+
["@md/sidebar:w-full", "state"]
|
|
152
|
+
])("classifies %s -> %s", (token, bucket) => {
|
|
153
|
+
expect(classifyToken(token)).toBe(bucket);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
describe("selectorKey", () => {
|
|
157
|
+
it("merges shadcn svg size guard with plain [&_svg] utilities", () => {
|
|
158
|
+
expect(selectorKey("[&_svg]:pointer-events-none")).toBe(selectorKey("[&_svg:not([class*='size-'])]:size-6"));
|
|
159
|
+
});
|
|
160
|
+
it("still splits unrelated arbitrary parent selectors", () => {
|
|
161
|
+
expect(selectorKey("[&_svg]:size-4")).not.toBe(selectorKey("[&>*]:block"));
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
//#endregion
|
|
165
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { i as DEFAULT_ARRANGE_TARGET, o as LONG_STRING_TOKEN_THRESHOLD, p as MAX_STRIP_VARIANT_PASSES } from "../../constants-AtPhF-Ct.mjs";
|
|
2
|
+
import { c as selectorKey, d as tokenizeClassString, i as classifyToken, l as stateKey, n as bucketsMergeCompatible, o as indexOfFirstVariantColon, t as bucketsCompatible, u as stripVariants } from "../../tokenizer-CeZx73Zu.mjs";
|
|
3
|
+
import { a as mergeCnUnconditionalLiteralPoolForTest, r as forEachStringLiteralInClassExpression } from "../../collectors-cn-BS8TTQ8O.mjs";
|
|
4
|
+
import { a as isCnOrTvIdentifier, i as indentOfLineContaining, l as unwrapCnInsideTvCallReplacement, n as applyEditsDescending, o as lineOf, r as buildKnownCnTvBindings, s as moduleLooksLikeCnTvReexport, t as KNOWN_CN_TV_MODULES } from "../../ast-helpers-MDRYuIAk.mjs";
|
|
5
|
+
import { n as walkTsxFiles, t as DEFAULT_SKIP_DIRS } from "../../walk-DjgQn66n.mjs";
|
|
6
|
+
import { t as analyzeDirectory } from "../../analyze-DvtJ3j9m.mjs";
|
|
7
|
+
import { t as printAnalyzeReport } from "../../report-DYxvw34T.mjs";
|
|
8
|
+
import { a as suggestCnGroups, i as mergeSingletons, n as capGroups, o as summarizeGroupBucketLabels, r as mergeEaseTimingIntoFollowingAnimatedState, t as areCnTailwindPartitionsEquivalent } from "../../grouping-c1grpCQT.mjs";
|
|
9
|
+
import { a as formatJsxCnAttributeValue, i as formatCnCall, n as formatArray, r as formatCnArguments, t as escapeTsStringLiteralContent } from "../../formatters-DGE8jJ53.mjs";
|
|
10
|
+
import { n as ensureCnImport, t as cnModuleSpecifierForFile } from "../../imports-DSVq1xhB.mjs";
|
|
11
|
+
import { t as groupFile } from "../../group-file-ClW7XdD6.mjs";
|
|
12
|
+
import { n as ArrangeErrorCode, t as ArrangeError } from "../../errors-CpU1ogfA.mjs";
|
|
13
|
+
import { n as runOnTarget, t as runArrangeSync } from "../../run-target-CJWrqNT4.mjs";
|
|
14
|
+
import { n as createNodeCliLogger, t as createNodeCliFs } from "../../node-io-DFRbHO6m.mjs";
|
|
15
|
+
import "../../arrange-BqP2DI3w.mjs";
|
|
16
|
+
export { ArrangeError, ArrangeErrorCode, DEFAULT_ARRANGE_TARGET, DEFAULT_SKIP_DIRS, KNOWN_CN_TV_MODULES, LONG_STRING_TOKEN_THRESHOLD, MAX_STRIP_VARIANT_PASSES, analyzeDirectory, applyEditsDescending, areCnTailwindPartitionsEquivalent, bucketsCompatible, bucketsMergeCompatible, buildKnownCnTvBindings, capGroups, classifyToken, cnModuleSpecifierForFile, createNodeCliFs, createNodeCliLogger, ensureCnImport, escapeTsStringLiteralContent, forEachStringLiteralInClassExpression, formatArray, formatCnArguments, formatCnCall, formatJsxCnAttributeValue, groupFile, indentOfLineContaining, indexOfFirstVariantColon, isCnOrTvIdentifier, lineOf, mergeCnUnconditionalLiteralPoolForTest, mergeEaseTimingIntoFollowingAnimatedState, mergeSingletons, moduleLooksLikeCnTvReexport, printAnalyzeReport, runArrangeSync, runOnTarget, selectorKey, stateKey, stripVariants, suggestCnGroups, summarizeGroupBucketLabels, tokenizeClassString, unwrapCnInsideTvCallReplacement, walkTsxFiles };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { n as walkTsxFiles, t as DEFAULT_SKIP_DIRS } from "../../../walk-DjgQn66n.mjs";
|
|
2
|
+
import { t as createNodeCliFs } from "../../../node-io-DFRbHO6m.mjs";
|
|
3
|
+
import "../../../arrange-BqP2DI3w.mjs";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import os from "node:os";
|
|
7
|
+
//#region src/lib/arrange/infra/walk.test.ts
|
|
8
|
+
const arrangeFs = createNodeCliFs();
|
|
9
|
+
describe("DEFAULT_SKIP_DIRS", () => {
|
|
10
|
+
it("contains common generated directories", () => {
|
|
11
|
+
expect(DEFAULT_SKIP_DIRS.has("node_modules")).toBe(true);
|
|
12
|
+
expect(DEFAULT_SKIP_DIRS.has(".git")).toBe(true);
|
|
13
|
+
expect(DEFAULT_SKIP_DIRS.has("dist")).toBe(true);
|
|
14
|
+
expect(DEFAULT_SKIP_DIRS.has(".turbo")).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
describe("walkTsxFiles", () => {
|
|
18
|
+
it("collects .ts/.tsx, skips .d.ts and nested skipped directories", () => {
|
|
19
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "arr-walk-"));
|
|
20
|
+
try {
|
|
21
|
+
fs.mkdirSync(path.join(dir, "a", "node_modules", "x"), { recursive: true });
|
|
22
|
+
fs.mkdirSync(path.join(dir, ".git", "hooks"), { recursive: true });
|
|
23
|
+
fs.writeFileSync(path.join(dir, "root.ts"), "", "utf8");
|
|
24
|
+
fs.writeFileSync(path.join(dir, "root.tsx"), "", "utf8");
|
|
25
|
+
fs.writeFileSync(path.join(dir, "types.d.ts"), "", "utf8");
|
|
26
|
+
fs.writeFileSync(path.join(dir, "a", "node_modules", "x", "ignored.tsx"), "", "utf8");
|
|
27
|
+
fs.writeFileSync(path.join(dir, ".git", "hooks", "ignored.ts"), "", "utf8");
|
|
28
|
+
const rel = walkTsxFiles(dir, arrangeFs).map((p) => path.relative(dir, p).split(path.sep).join("/")).sort();
|
|
29
|
+
expect(rel).toEqual(["root.ts", "root.tsx"]);
|
|
30
|
+
} finally {
|
|
31
|
+
fs.rmSync(dir, {
|
|
32
|
+
recursive: true,
|
|
33
|
+
force: true
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
it("returns empty array for empty directory", () => {
|
|
38
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "arr-walk-empty-"));
|
|
39
|
+
try {
|
|
40
|
+
expect(walkTsxFiles(dir, arrangeFs)).toEqual([]);
|
|
41
|
+
} finally {
|
|
42
|
+
fs.rmSync(dir, {
|
|
43
|
+
recursive: true,
|
|
44
|
+
force: true
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
//#endregion
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as formatJsxCnAttributeValue, i as formatCnCall, n as formatArray, r as formatCnArguments, t as escapeTsStringLiteralContent } from "../../../formatters-DGE8jJ53.mjs";
|
|
2
|
+
export { escapeTsStringLiteralContent, formatArray, formatCnArguments, formatCnCall, formatJsxCnAttributeValue };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { a as formatJsxCnAttributeValue, i as formatCnCall, n as formatArray, r as formatCnArguments, t as escapeTsStringLiteralContent } from "../../../formatters-DGE8jJ53.mjs";
|
|
2
|
+
import "../../../arrange-BqP2DI3w.mjs";
|
|
3
|
+
//#region src/lib/arrange/presentation/formatters.test.ts
|
|
4
|
+
describe("escapeTsStringLiteralContent", () => {
|
|
5
|
+
it("escapes backslashes and quotes", () => {
|
|
6
|
+
expect(escapeTsStringLiteralContent(String.raw`x\"y`)).toBe(String.raw`x\\\"y`);
|
|
7
|
+
});
|
|
8
|
+
it("keeps plain strings unchanged", () => {
|
|
9
|
+
expect(escapeTsStringLiteralContent("plain")).toBe("plain");
|
|
10
|
+
});
|
|
11
|
+
it("handles empty strings", () => {
|
|
12
|
+
expect(escapeTsStringLiteralContent("")).toBe("");
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
describe("formatCnArguments", () => {
|
|
16
|
+
it("renders indented args without wrapping cn()", () => {
|
|
17
|
+
expect(formatCnArguments(["flex gap-2", "text-sm"], { indent: " " })).toBe([" \"flex gap-2\",", " \"text-sm\""].join("\n"));
|
|
18
|
+
});
|
|
19
|
+
it("adds comma on last group when commaAfterLastGroup=true", () => {
|
|
20
|
+
expect(formatCnArguments(["a", "b"], { commaAfterLastGroup: true })).toBe([" \"a\",", " \"b\","].join("\n"));
|
|
21
|
+
});
|
|
22
|
+
it("appends trailing className line when requested", () => {
|
|
23
|
+
expect(formatCnArguments(["a", "b"], { trailingClassName: true })).toBe([
|
|
24
|
+
" \"a\",",
|
|
25
|
+
" \"b\",",
|
|
26
|
+
" className,"
|
|
27
|
+
].join("\n"));
|
|
28
|
+
});
|
|
29
|
+
it("escapes literals", () => {
|
|
30
|
+
expect(formatCnArguments(["x\"y"])).toBe(" \"x\\\"y\"");
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe("formatCnCall", () => {
|
|
34
|
+
it("omits trailing comma for single group", () => {
|
|
35
|
+
expect(formatCnCall(["only"])).toBe([
|
|
36
|
+
"cn(",
|
|
37
|
+
" \"only\"",
|
|
38
|
+
")"
|
|
39
|
+
].join("\n"));
|
|
40
|
+
});
|
|
41
|
+
it("renders multiline cn() with trailing commas for multi-arg", () => {
|
|
42
|
+
expect(formatCnCall(["a", "b"])).toBe([
|
|
43
|
+
"cn(",
|
|
44
|
+
" \"a\",",
|
|
45
|
+
" \"b\",",
|
|
46
|
+
")"
|
|
47
|
+
].join("\n"));
|
|
48
|
+
});
|
|
49
|
+
it("supports trailing className", () => {
|
|
50
|
+
expect(formatCnCall(["a", "b"], { trailingClassName: true })).toContain("className,");
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe("formatArray", () => {
|
|
54
|
+
it("renders multiline string array", () => {
|
|
55
|
+
expect(formatArray(["a", "b"])).toBe([
|
|
56
|
+
"[",
|
|
57
|
+
" \"a\",",
|
|
58
|
+
" \"b\",",
|
|
59
|
+
"]"
|
|
60
|
+
].join("\n"));
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
describe("formatJsxCnAttributeValue", () => {
|
|
64
|
+
it("formats className={cn(...)} with source-derived indentation", () => {
|
|
65
|
+
const source = `export function F() {\n return <div className="x" />;\n}`;
|
|
66
|
+
const out = formatJsxCnAttributeValue(["flex gap-2", "text-sm"], source, source.indexOf("\""));
|
|
67
|
+
expect(out.startsWith("{cn(")).toBe(true);
|
|
68
|
+
expect(out.endsWith(")}")).toBe(true);
|
|
69
|
+
expect(out).toContain("\"flex gap-2\",");
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
//#endregion
|
|
73
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as mirrorConfigSchema, i as hookSchema, n as codefastConfigSchema, r as codefastTagConfigSchema, t as codefastArrangeConfigSchema } from "../../../schema-Or8RAARd.mjs";
|
|
2
|
+
export { codefastArrangeConfigSchema, codefastConfigSchema, codefastTagConfigSchema, hookSchema, mirrorConfigSchema };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { a as mirrorConfigSchema, i as hookSchema, n as codefastConfigSchema, r as codefastTagConfigSchema, t as codefastArrangeConfigSchema } from "../../schema-Or8RAARd.mjs";
|
|
2
|
+
import { n as resetConfigLoaderCacheForTests, t as loadConfig } from "../../loader-DpN-zl5g.mjs";
|
|
3
|
+
import "../../config-DVia_f9a.mjs";
|
|
4
|
+
export { codefastArrangeConfigSchema, codefastConfigSchema, codefastTagConfigSchema, hookSchema, loadConfig, mirrorConfigSchema, resetConfigLoaderCacheForTests };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { n as resetConfigLoaderCacheForTests, t as loadConfig } from "../../../loader-DpN-zl5g.mjs";
|
|
2
|
+
import { t as createNodeCliFs } from "../../../node-io-DFRbHO6m.mjs";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
//#region src/lib/config/infra/loader.test.ts
|
|
7
|
+
describe("loadConfig", () => {
|
|
8
|
+
const cliFs = createNodeCliFs();
|
|
9
|
+
async function withCwd(cwd, fn) {
|
|
10
|
+
const prev = process.cwd();
|
|
11
|
+
process.chdir(cwd);
|
|
12
|
+
resetConfigLoaderCacheForTests();
|
|
13
|
+
try {
|
|
14
|
+
return await fn();
|
|
15
|
+
} finally {
|
|
16
|
+
process.chdir(prev);
|
|
17
|
+
resetConfigLoaderCacheForTests();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
it("loads mirror + lifecycle hooks from codefast.config.cjs", async () => {
|
|
21
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "codefast-config-hooks-"));
|
|
22
|
+
try {
|
|
23
|
+
fs.writeFileSync(path.join(root, "codefast.config.cjs"), [
|
|
24
|
+
"module.exports = {",
|
|
25
|
+
" mirror: { skipPackages: [\"@acme/private\"] },",
|
|
26
|
+
" tag: { onAfterWrite: async ({ files }) => {",
|
|
27
|
+
" if (files.length === 0) return;",
|
|
28
|
+
" } },",
|
|
29
|
+
" arrange: { onAfterWrite: ({ files }) => files.length },",
|
|
30
|
+
"};",
|
|
31
|
+
""
|
|
32
|
+
].join("\n"), "utf8");
|
|
33
|
+
await withCwd(root, async () => {
|
|
34
|
+
const { config, warnings } = await loadConfig(cliFs);
|
|
35
|
+
expect(warnings).toEqual([]);
|
|
36
|
+
expect(config.mirror).toEqual({ skipPackages: ["@acme/private"] });
|
|
37
|
+
expect(typeof config.tag?.onAfterWrite).toBe("function");
|
|
38
|
+
expect(typeof config.arrange?.onAfterWrite).toBe("function");
|
|
39
|
+
});
|
|
40
|
+
} finally {
|
|
41
|
+
fs.rmSync(root, {
|
|
42
|
+
recursive: true,
|
|
43
|
+
force: true
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
it("requires mirror config to be nested under the mirror key", async () => {
|
|
48
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "codefast-config-mirror-top-"));
|
|
49
|
+
try {
|
|
50
|
+
fs.writeFileSync(path.join(root, "codefast.config.json"), JSON.stringify({ skipPackages: ["@acme/legacy"] }), "utf8");
|
|
51
|
+
await withCwd(root, async () => {
|
|
52
|
+
await expect(loadConfig(cliFs)).rejects.toThrow("Invalid config schema");
|
|
53
|
+
await expect(loadConfig(cliFs)).rejects.toThrow("Unrecognized key: \"skipPackages\"");
|
|
54
|
+
});
|
|
55
|
+
} finally {
|
|
56
|
+
fs.rmSync(root, {
|
|
57
|
+
recursive: true,
|
|
58
|
+
force: true
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
it("throws schema validation errors for invalid hook values", async () => {
|
|
63
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "codefast-config-invalid-hook-"));
|
|
64
|
+
try {
|
|
65
|
+
fs.writeFileSync(path.join(root, "codefast.config.json"), JSON.stringify({
|
|
66
|
+
tag: { onAfterWrite: "not-a-function" },
|
|
67
|
+
arrange: { onAfterWrite: 123 }
|
|
68
|
+
}), "utf8");
|
|
69
|
+
await withCwd(root, async () => {
|
|
70
|
+
await expect(loadConfig(cliFs)).rejects.toThrow("Invalid config schema");
|
|
71
|
+
await expect(loadConfig(cliFs)).rejects.toThrow("tag.onAfterWrite");
|
|
72
|
+
});
|
|
73
|
+
} finally {
|
|
74
|
+
fs.rmSync(root, {
|
|
75
|
+
recursive: true,
|
|
76
|
+
force: true
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
it("resolves config with upward search from process.cwd()", async () => {
|
|
81
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "codefast-config-upward-"));
|
|
82
|
+
const nested = path.join(root, "packages", "ui", "src");
|
|
83
|
+
try {
|
|
84
|
+
fs.mkdirSync(nested, { recursive: true });
|
|
85
|
+
fs.writeFileSync(path.join(root, "codefast.config.json"), JSON.stringify({ mirror: { skipPackages: ["@acme/infra"] } }), "utf8");
|
|
86
|
+
await withCwd(nested, async () => {
|
|
87
|
+
const { config } = await loadConfig(cliFs);
|
|
88
|
+
expect(config.mirror).toEqual({ skipPackages: ["@acme/infra"] });
|
|
89
|
+
});
|
|
90
|
+
} finally {
|
|
91
|
+
fs.rmSync(root, {
|
|
92
|
+
recursive: true,
|
|
93
|
+
force: true
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
it("uses singleton cache within one process", async () => {
|
|
98
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), "codefast-config-cache-"));
|
|
99
|
+
try {
|
|
100
|
+
fs.writeFileSync(path.join(root, "codefast.config.json"), JSON.stringify({ mirror: { skipPackages: ["@acme/one"] } }), "utf8");
|
|
101
|
+
await withCwd(root, async () => {
|
|
102
|
+
const first = await loadConfig(cliFs);
|
|
103
|
+
fs.writeFileSync(path.join(root, "codefast.config.json"), JSON.stringify({ mirror: { skipPackages: ["@acme/two"] } }), "utf8");
|
|
104
|
+
const second = await loadConfig(cliFs);
|
|
105
|
+
expect(second.config.mirror).toEqual(first.config.mirror);
|
|
106
|
+
});
|
|
107
|
+
} finally {
|
|
108
|
+
fs.rmSync(root, {
|
|
109
|
+
recursive: true,
|
|
110
|
+
force: true
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
//#endregion
|
|
116
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { t as findRepoRoot } from "../../../repo-root-HmtIEm6J.mjs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
//#region src/lib/infra/workspace/repo-root.test.ts
|
|
4
|
+
function makeFs(existsSync) {
|
|
5
|
+
return {
|
|
6
|
+
existsSync,
|
|
7
|
+
statSync: () => ({
|
|
8
|
+
isDirectory: () => true,
|
|
9
|
+
isFile: () => false
|
|
10
|
+
}),
|
|
11
|
+
readFileSync: () => "",
|
|
12
|
+
writeFileSync: () => void 0,
|
|
13
|
+
readdirSync: () => [],
|
|
14
|
+
readFile: async () => "",
|
|
15
|
+
writeFile: async () => void 0,
|
|
16
|
+
readdir: async () => [],
|
|
17
|
+
rename: async () => void 0,
|
|
18
|
+
unlink: async () => void 0
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
describe("findRepoRoot", () => {
|
|
22
|
+
it("returns the nearest ancestor containing pnpm-workspace.yaml", () => {
|
|
23
|
+
const root = "/tmp/repo";
|
|
24
|
+
const marker = path.join(root, "pnpm-workspace.yaml");
|
|
25
|
+
const cwdSpy = jest.spyOn(process, "cwd").mockReturnValue("/tmp/repo/packages/cli");
|
|
26
|
+
try {
|
|
27
|
+
const fs = makeFs((targetPath) => targetPath === marker);
|
|
28
|
+
expect(findRepoRoot(fs)).toBe(root);
|
|
29
|
+
} finally {
|
|
30
|
+
cwdSpy.mockRestore();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
it("includes searched candidate paths when root cannot be resolved", () => {
|
|
34
|
+
const cwdSpy = jest.spyOn(process, "cwd").mockReturnValue("/tmp/no-repo");
|
|
35
|
+
try {
|
|
36
|
+
const fs = makeFs(() => false);
|
|
37
|
+
expect(() => findRepoRoot(fs)).toThrow(/Searched from:/);
|
|
38
|
+
expect(() => findRepoRoot(fs)).toThrow(/\/tmp\/no-repo/);
|
|
39
|
+
} finally {
|
|
40
|
+
cwdSpy.mockRestore();
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
//#endregion
|
|
45
|
+
export {};
|