@sps-woodland/codemods 8.53.12 → 8.53.13
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.
|
@@ -41,16 +41,17 @@ const jscodeshift = jscodeshiftModule.default ?? jscodeshiftModule;
|
|
|
41
41
|
// assume the mapping is "same name", some are exceptions.
|
|
42
42
|
//
|
|
43
43
|
// jsSubpath: subpath used for the bare package import, e.g.
|
|
44
|
-
// from "@sps-woodland/
|
|
44
|
+
// from "@sps-woodland/tags" -> from "@sps-woodland/core/tags"
|
|
45
45
|
// cssSubpath: subpath used when importing "<wrapperName>/style.css" — for
|
|
46
46
|
// every package this matches jsSubpath EXCEPT "buttons", whose CSS still
|
|
47
47
|
// lives under the plural "buttons" path even though the JS export is the
|
|
48
48
|
// singular "button".
|
|
49
|
+
//
|
|
50
|
+
// "cards" is deliberately NOT in this map — see CARDS_EXPORT_SUBPATH below.
|
|
49
51
|
const WRAPPER_TO_CORE = {
|
|
50
52
|
"action-bar": { jsSubpath: "action-bar", cssSubpath: "action-bar" },
|
|
51
53
|
"add-to-list": { jsSubpath: "add-to-list", cssSubpath: "add-to-list" },
|
|
52
54
|
"buttons": { jsSubpath: "button", cssSubpath: "buttons" }, // exception: singular JS, plural CSS
|
|
53
|
-
"cards": { jsSubpath: "cards", cssSubpath: "cards" },
|
|
54
55
|
"column-manager": { jsSubpath: "column-manager", cssSubpath: "column-manager" },
|
|
55
56
|
"content-row": { jsSubpath: "content-row", cssSubpath: "content-row" },
|
|
56
57
|
"content-tiles": { jsSubpath: "content-tiles", cssSubpath: "content-tiles" },
|
|
@@ -81,26 +82,83 @@ const WRAPPER_TO_CORE = {
|
|
|
81
82
|
// itself), @sps-woodland/tokens, @sps-woodland/illustrations,
|
|
82
83
|
// @sps-woodland/codemods (these ship real, independent code, not re-exports).
|
|
83
84
|
|
|
85
|
+
// "cards" is a multi-family wrapper: it re-exports three independent core
|
|
86
|
+
// families under one legacy package name (see
|
|
87
|
+
// packages/@sps-woodland/cards/src/index.ts) —
|
|
88
|
+
// export * from "@sps-woodland/core/cards";
|
|
89
|
+
// export * from "@sps-woodland/core/insight-card";
|
|
90
|
+
// export * from "@sps-woodland/core/scrollable-container";
|
|
91
|
+
// — and its style.css is a concatenation of all three families' style.css
|
|
92
|
+
// (see that package's build:css script). A single wrapper->subpath mapping
|
|
93
|
+
// would route every named import and every style.css import to just one of
|
|
94
|
+
// the three, silently dropping the other two. Route by the specific export
|
|
95
|
+
// name instead, and always expand its style.css into all three families'.
|
|
96
|
+
const CARDS_EXPORT_SUBPATH = {
|
|
97
|
+
Card: "cards",
|
|
98
|
+
CardHeader: "cards",
|
|
99
|
+
CardFooter: "cards",
|
|
100
|
+
CardTitle: "cards",
|
|
101
|
+
InsightCard: "insight-card",
|
|
102
|
+
InsightCardSet: "insight-card",
|
|
103
|
+
ScrollableContainer: "scrollable-container",
|
|
104
|
+
};
|
|
105
|
+
const CARDS_CSS_SUBPATHS = ["cards", "insight-card", "scrollable-container"];
|
|
106
|
+
|
|
84
107
|
const SCOPE = "@sps-woodland";
|
|
85
108
|
const JS_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
86
109
|
const CSS_EXTENSIONS = new Set([".css", ".scss", ".sass", ".less"]);
|
|
87
110
|
const SKIP_DIRS = new Set(["node_modules", ".git", "dist", "build", "lib", "coverage"]);
|
|
88
111
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
112
|
+
// Splits "@sps-woodland/cards/style.css" into { name: "cards", subRest:
|
|
113
|
+
// "/style.css" } (subRest is "" for a bare "@sps-woodland/<name>" import).
|
|
114
|
+
function splitScopedSpecifier(source) {
|
|
115
|
+
if (!source.startsWith(`${SCOPE}/`)) return null;
|
|
116
|
+
const rest = source.slice(SCOPE.length + 1);
|
|
92
117
|
const slashIdx = rest.indexOf("/");
|
|
93
118
|
const name = slashIdx === -1 ? rest : rest.slice(0, slashIdx);
|
|
94
|
-
const subRest = slashIdx === -1 ? "" : rest.slice(slashIdx);
|
|
119
|
+
const subRest = slashIdx === -1 ? "" : rest.slice(slashIdx);
|
|
120
|
+
return { name, subRest };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function resolveNewSource(oldSource) {
|
|
124
|
+
const parts = splitScopedSpecifier(oldSource);
|
|
125
|
+
if (!parts) return null;
|
|
95
126
|
|
|
96
|
-
const mapping = WRAPPER_TO_CORE[name];
|
|
127
|
+
const mapping = WRAPPER_TO_CORE[parts.name];
|
|
97
128
|
if (!mapping) return null; // not a known wrapper package — leave untouched
|
|
98
129
|
|
|
99
|
-
if (subRest === "") return `${SCOPE}/core/${mapping.jsSubpath}`;
|
|
100
|
-
if (subRest === "/style.css") return `${SCOPE}/core/${mapping.cssSubpath}/style.css`;
|
|
130
|
+
if (parts.subRest === "") return `${SCOPE}/core/${mapping.jsSubpath}`;
|
|
131
|
+
if (parts.subRest === "/style.css") return `${SCOPE}/core/${mapping.cssSubpath}/style.css`;
|
|
101
132
|
// Unknown deep subpath (rare) — map using the JS subpath and preserve
|
|
102
133
|
// whatever followed the package name, best-effort.
|
|
103
|
-
return `${SCOPE}/core/${mapping.jsSubpath}${subRest}`;
|
|
134
|
+
return `${SCOPE}/core/${mapping.jsSubpath}${parts.subRest}`;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// "cards" can't be resolved to a single new source string (see
|
|
138
|
+
// CARDS_EXPORT_SUBPATH above) — it needs to become several ImportDeclarations
|
|
139
|
+
// instead of having its source literal swapped in place. Returns the
|
|
140
|
+
// replacement declarations, or null if this import can't be split safely
|
|
141
|
+
// (a default/namespace import, an unrecognized named export, or a deep
|
|
142
|
+
// subpath) — callers leave those untouched and flag them for manual review.
|
|
143
|
+
function splitCardsImportDeclaration(j, node, subRest) {
|
|
144
|
+
if (subRest === "/style.css") {
|
|
145
|
+
return CARDS_CSS_SUBPATHS.map((sub) => j.importDeclaration([], j.literal(`${SCOPE}/core/${sub}/style.css`)));
|
|
146
|
+
}
|
|
147
|
+
if (subRest !== "") return null; // unrecognized deep subpath
|
|
148
|
+
|
|
149
|
+
const specifiers = node.specifiers;
|
|
150
|
+
if (specifiers.length === 0) return null; // bare side-effect import, nothing to route by
|
|
151
|
+
|
|
152
|
+
const bySubpath = new Map(); // subpath -> specifier[], insertion order
|
|
153
|
+
for (const spec of specifiers) {
|
|
154
|
+
if (spec.type !== "ImportSpecifier") return null; // default or namespace import
|
|
155
|
+
const sub = CARDS_EXPORT_SUBPATH[spec.imported.name];
|
|
156
|
+
if (!sub) return null; // not a recognized cards/insight-card/scrollable-container export
|
|
157
|
+
if (!bySubpath.has(sub)) bySubpath.set(sub, []);
|
|
158
|
+
bySubpath.get(sub).push(spec);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return [...bySubpath.entries()].map(([sub, specs]) => j.importDeclaration(specs, j.literal(`${SCOPE}/core/${sub}`)));
|
|
104
162
|
}
|
|
105
163
|
|
|
106
164
|
// Parses the file with jscodeshift (Babel/TSX parser) and rewrites only the
|
|
@@ -131,6 +189,21 @@ function transformSource(source) {
|
|
|
131
189
|
// Static: import ... from "@sps-woodland/<name>"
|
|
132
190
|
root.find(j.ImportDeclaration).forEach((p) => {
|
|
133
191
|
const node = p.node.source;
|
|
192
|
+
const value = node.value;
|
|
193
|
+
const parts = typeof value === "string" ? splitScopedSpecifier(value) : null;
|
|
194
|
+
|
|
195
|
+
if (parts && parts.name === "cards") {
|
|
196
|
+
const newDecls = splitCardsImportDeclaration(j, p.node, parts.subRest);
|
|
197
|
+
if (newDecls) {
|
|
198
|
+
const oldSource = `${SCOPE}/cards${parts.subRest}`;
|
|
199
|
+
p.replace(...newDecls);
|
|
200
|
+
changes.push({ oldSource, newSource: newDecls.map((d) => d.source.value).join(", ") });
|
|
201
|
+
} else {
|
|
202
|
+
unknown.add("cards");
|
|
203
|
+
}
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
134
207
|
maybeRewrite(node, (newValue) => {
|
|
135
208
|
node.value = newValue;
|
|
136
209
|
delete node.raw;
|
|
@@ -175,7 +248,40 @@ function transformCssSource(source) {
|
|
|
175
248
|
const changes = []; // { oldSource, newSource }
|
|
176
249
|
const unknown = new Set();
|
|
177
250
|
|
|
178
|
-
const output = source.replace(CSS_IMPORT_RE, (match, prefix, quote, name, rest) => {
|
|
251
|
+
const output = source.replace(CSS_IMPORT_RE, (match, prefix, quote, name, rest, offset, string) => {
|
|
252
|
+
if (name === "cards") {
|
|
253
|
+
if (rest !== "/style.css" && rest !== "/lib/style.css") {
|
|
254
|
+
unknown.add(`cards${rest}`);
|
|
255
|
+
return match;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// One @import can't become three without knowing what immediately
|
|
259
|
+
// follows the match (a plain ";", or url()'s ")" then ";") — a media
|
|
260
|
+
// query or anything else there would need to apply to all three
|
|
261
|
+
// splits, which we can't infer safely, so leave those for manual review.
|
|
262
|
+
const isUrl = /url\(\s*$/.test(prefix);
|
|
263
|
+
const tail = string.slice(offset + match.length);
|
|
264
|
+
if (!(isUrl ? /^\s*\)\s*;/ : /^\s*;/).test(tail)) {
|
|
265
|
+
unknown.add(`cards${rest} (unexpected trailing syntax after the @import — split into ${CARDS_CSS_SUBPATHS.length} imports manually)`);
|
|
266
|
+
return match;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const oldSource = `${SCOPE}/cards${rest}`;
|
|
270
|
+
const closeParen = isUrl ? ")" : "";
|
|
271
|
+
const statements = CARDS_CSS_SUBPATHS.map((sub, i) => {
|
|
272
|
+
const newPath = `${SCOPE}/core/${sub}/style.css`;
|
|
273
|
+
const isLast = i === CARDS_CSS_SUBPATHS.length - 1;
|
|
274
|
+
// The last split keeps whatever terminator (")" / ";" / media query)
|
|
275
|
+
// already follows the original match in the source untouched.
|
|
276
|
+
return `${prefix}${quote}${newPath}${quote}${isLast ? "" : `${closeParen};`}`;
|
|
277
|
+
});
|
|
278
|
+
changes.push({
|
|
279
|
+
oldSource,
|
|
280
|
+
newSource: CARDS_CSS_SUBPATHS.map((sub) => `${SCOPE}/core/${sub}/style.css`).join(", "),
|
|
281
|
+
});
|
|
282
|
+
return statements.join("\n");
|
|
283
|
+
}
|
|
284
|
+
|
|
179
285
|
const mapping = WRAPPER_TO_CORE[name];
|
|
180
286
|
if (!mapping) {
|
|
181
287
|
unknown.add(name);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sps-woodland/codemods",
|
|
3
3
|
"description": "SPS Woodland Design System codemods",
|
|
4
|
-
"version": "8.53.
|
|
4
|
+
"version": "8.53.13",
|
|
5
5
|
"author": "SPS Commerce",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"repository": "https://github.com/spscommerce/woodland/tree/master/packages/@sps-woodland/codemods",
|
|
Binary file
|
|
Binary file
|