@typestyles/build-runner 0.2.0 → 0.5.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/LICENSE +204 -0
- package/README.md +199 -0
- package/dist/index.cjs +521 -8
- package/dist/index.d.cts +179 -1
- package/dist/index.d.ts +179 -1
- package/dist/index.js +498 -7
- package/package.json +7 -3
package/dist/index.cjs
CHANGED
|
@@ -20,12 +20,505 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
|
|
23
|
+
DEFAULT_EXTRACT_MODULE_CANDIDATES: () => DEFAULT_EXTRACT_MODULE_CANDIDATES,
|
|
24
|
+
TYPESTYLES_IMPORT_RE: () => TYPESTYLES_IMPORT_RE,
|
|
25
|
+
VerifyTypestylesBuildError: () => VerifyTypestylesBuildError,
|
|
26
|
+
buildManifestV2: () => buildManifestV2,
|
|
27
|
+
collectAndWriteRouteCss: () => collectAndWriteRouteCss,
|
|
28
|
+
createModuleLoader: () => createModuleLoader,
|
|
29
|
+
discoverDefaultExtractModules: () => discoverDefaultExtractModules,
|
|
30
|
+
discoverNextAppRoutes: () => discoverNextAppRoutes,
|
|
31
|
+
extractNamespaces: () => extractNamespaces,
|
|
32
|
+
getRouteCss: () => getRouteCss,
|
|
33
|
+
isManifestV2: () => isManifestV2,
|
|
34
|
+
normalizeRoutePath: () => normalizeRoutePath,
|
|
35
|
+
pageRelPathToRoutePath: () => pageRelPathToRoutePath,
|
|
36
|
+
readCssFile: () => readCssFile,
|
|
37
|
+
readTypestylesManifest: () => readTypestylesManifest,
|
|
38
|
+
reportDuplicateNamespaces: () => reportDuplicateNamespaces,
|
|
39
|
+
resolveExtractMode: () => resolveExtractMode,
|
|
40
|
+
resolveExtractModules: () => resolveExtractModules,
|
|
41
|
+
runTypestylesBuild: () => runTypestylesBuild,
|
|
42
|
+
traceTypestylesModules: () => traceTypestylesModules,
|
|
43
|
+
verifyTypestylesBuild: () => verifyTypestylesBuild
|
|
24
44
|
});
|
|
25
45
|
module.exports = __toCommonJS(index_exports);
|
|
26
|
-
|
|
46
|
+
|
|
47
|
+
// src/discover.ts
|
|
27
48
|
var import_node_fs = require("fs");
|
|
28
49
|
var import_node_path = require("path");
|
|
50
|
+
var DEFAULT_EXTRACT_MODULE_BASES = [
|
|
51
|
+
"src/typestyles-entry",
|
|
52
|
+
"src/typestyles",
|
|
53
|
+
"src/styles/index",
|
|
54
|
+
"src/styles",
|
|
55
|
+
"styles/typestyles-entry",
|
|
56
|
+
"styles/typestyles"
|
|
57
|
+
];
|
|
58
|
+
var DISCOVERY_EXTENSIONS = [".ts", ".tsx", ".js", ".mjs"];
|
|
59
|
+
var DEFAULT_EXTRACT_MODULE_CANDIDATES = DEFAULT_EXTRACT_MODULE_BASES.map(
|
|
60
|
+
(base) => `${base}.ts`
|
|
61
|
+
);
|
|
62
|
+
function discoverDefaultExtractModules(root) {
|
|
63
|
+
const absRoot = (0, import_node_path.resolve)(root);
|
|
64
|
+
for (const base of DEFAULT_EXTRACT_MODULE_BASES) {
|
|
65
|
+
for (const ext of DISCOVERY_EXTENSIONS) {
|
|
66
|
+
const rel = `${base}${ext}`;
|
|
67
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.resolve)(absRoot, rel))) {
|
|
68
|
+
return [rel.replace(/\\/g, "/")];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/namespaces.ts
|
|
76
|
+
var STYLES_COMPONENT_RE = /styles\.component\(\s*['"]([^'"]+)['"]/g;
|
|
77
|
+
var STYLES_CLASS_RE = /styles\.class\(\s*['"]([^'"]+)['"]/g;
|
|
78
|
+
var TOKENS_CREATE_RE = /tokens\.create\(\s*['"]([^'"]+)['"]/g;
|
|
79
|
+
var CREATE_THEME_RE = /(?:tokens\.)?createTheme\(\s*['"]([^'"]+)['"]/g;
|
|
80
|
+
var KEYFRAMES_CREATE_RE = /keyframes\.create\(\s*['"]([^'"]+)['"]/g;
|
|
81
|
+
var GLOBAL_STYLE_RE = /global\.style\(\s*['"]([^'"]+)['"]/g;
|
|
82
|
+
var GLOBAL_FONT_FACE_RE = /global\.fontFace\(\s*['"]([^'"]+)['"]/g;
|
|
83
|
+
var TYPESTYLES_IMPORT_RE = /(?:from\s+|import\s+|require\s*\(\s*)['"]typestyles['"]/;
|
|
84
|
+
function extractNamespaces(code) {
|
|
85
|
+
const keys = [];
|
|
86
|
+
const prefixes = [];
|
|
87
|
+
for (const match of code.matchAll(STYLES_COMPONENT_RE)) {
|
|
88
|
+
prefixes.push(`.${match[1]}-`);
|
|
89
|
+
}
|
|
90
|
+
for (const match of code.matchAll(STYLES_CLASS_RE)) {
|
|
91
|
+
prefixes.push(`.${match[1]}-`);
|
|
92
|
+
}
|
|
93
|
+
for (const match of code.matchAll(TOKENS_CREATE_RE)) {
|
|
94
|
+
keys.push(`tokens:${match[1]}`);
|
|
95
|
+
}
|
|
96
|
+
for (const match of code.matchAll(CREATE_THEME_RE)) {
|
|
97
|
+
keys.push(`theme:${match[1]}`);
|
|
98
|
+
}
|
|
99
|
+
for (const match of code.matchAll(KEYFRAMES_CREATE_RE)) {
|
|
100
|
+
keys.push(`keyframes:${match[1]}`);
|
|
101
|
+
}
|
|
102
|
+
for (const match of code.matchAll(GLOBAL_STYLE_RE)) {
|
|
103
|
+
prefixes.push(match[1]);
|
|
104
|
+
}
|
|
105
|
+
for (const match of code.matchAll(GLOBAL_FONT_FACE_RE)) {
|
|
106
|
+
prefixes.push(`font-face:${match[1]}`);
|
|
107
|
+
}
|
|
108
|
+
return { keys, prefixes };
|
|
109
|
+
}
|
|
110
|
+
function reportDuplicateNamespaces(moduleNamespaces, id, prefixes, reporter) {
|
|
111
|
+
for (const [otherId, other] of moduleNamespaces) {
|
|
112
|
+
if (otherId === id) continue;
|
|
113
|
+
for (const prefix of prefixes) {
|
|
114
|
+
if (other.prefixes.includes(prefix)) {
|
|
115
|
+
const ns = prefix.slice(1, -1);
|
|
116
|
+
reporter.error(
|
|
117
|
+
`[typestyles] Style namespace "${ns}" is also used in ${otherId}. Duplicate namespaces cause class name collisions. Use a distinct name or isolate with createStyles({ scopeId: fileScopeId(import.meta) }).`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/resolve-extract.ts
|
|
125
|
+
function resolveExtractModules(root, extract) {
|
|
126
|
+
if (extract?.modules !== void 0) {
|
|
127
|
+
return extract.modules;
|
|
128
|
+
}
|
|
129
|
+
return discoverDefaultExtractModules(root);
|
|
130
|
+
}
|
|
131
|
+
function resolveExtractMode(explicitMode, resolvedModules) {
|
|
132
|
+
return explicitMode ?? (resolvedModules.length > 0 ? "build" : "runtime");
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// src/verify.ts
|
|
136
|
+
var import_node_fs2 = require("fs");
|
|
137
|
+
var import_node_path2 = require("path");
|
|
138
|
+
|
|
139
|
+
// src/manifest.ts
|
|
140
|
+
function isManifestV2(manifest) {
|
|
141
|
+
return manifest.version === 2;
|
|
142
|
+
}
|
|
143
|
+
function normalizeRoutePath(routePath) {
|
|
144
|
+
if (!routePath || routePath === "/") return "/";
|
|
145
|
+
const trimmed = routePath.replace(/\/+$/, "");
|
|
146
|
+
return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/verify.ts
|
|
150
|
+
var VerifyTypestylesBuildError = class extends Error {
|
|
151
|
+
constructor(message, code) {
|
|
152
|
+
super(`[typestyles:verify] ${message}`);
|
|
153
|
+
this.name = "VerifyTypestylesBuildError";
|
|
154
|
+
this.code = code;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
function fail(message, code) {
|
|
158
|
+
throw new VerifyTypestylesBuildError(message, code);
|
|
159
|
+
}
|
|
160
|
+
function readManifest(path) {
|
|
161
|
+
let parsed;
|
|
162
|
+
try {
|
|
163
|
+
parsed = JSON.parse((0, import_node_fs2.readFileSync)(path, "utf8"));
|
|
164
|
+
} catch {
|
|
165
|
+
fail(`Invalid JSON in ${path}.`, "manifest-invalid-json");
|
|
166
|
+
}
|
|
167
|
+
if (typeof parsed !== "object" || parsed === null || !("version" in parsed) || !("css" in parsed)) {
|
|
168
|
+
fail(`Manifest at ${path} is missing required fields.`, "manifest-invalid-shape");
|
|
169
|
+
}
|
|
170
|
+
const version = parsed.version;
|
|
171
|
+
if (version !== 1 && version !== 2) {
|
|
172
|
+
fail(`Unsupported manifest version ${String(version)}.`, "manifest-version-unsupported");
|
|
173
|
+
}
|
|
174
|
+
const manifest = parsed;
|
|
175
|
+
if (isManifestV2(manifest) && typeof manifest.routes !== "object") {
|
|
176
|
+
fail(`Manifest v2 at ${path} is missing routes.`, "manifest-invalid-shape");
|
|
177
|
+
}
|
|
178
|
+
return manifest;
|
|
179
|
+
}
|
|
180
|
+
function verifyTypestylesBuild(options) {
|
|
181
|
+
const {
|
|
182
|
+
root,
|
|
183
|
+
cssFile,
|
|
184
|
+
manifestFile,
|
|
185
|
+
manifestCssPath,
|
|
186
|
+
manifestVersion = 1,
|
|
187
|
+
minBytes,
|
|
188
|
+
requiredCssSubstrings = [],
|
|
189
|
+
minRouteEntries
|
|
190
|
+
} = options;
|
|
191
|
+
const cssPath = (0, import_node_path2.resolve)(root, cssFile);
|
|
192
|
+
if (!(0, import_node_fs2.existsSync)(cssPath)) {
|
|
193
|
+
fail(`Missing ${cssPath} \u2014 run your TypeStyles build step first.`, "css-missing");
|
|
194
|
+
}
|
|
195
|
+
const css = (0, import_node_fs2.readFileSync)(cssPath, "utf8");
|
|
196
|
+
const cssBytes = Buffer.byteLength(css, "utf8");
|
|
197
|
+
const min = minBytes ?? 1;
|
|
198
|
+
if (cssBytes < min) {
|
|
199
|
+
fail(
|
|
200
|
+
`CSS file unexpectedly small (${cssBytes} bytes, expected at least ${min}).`,
|
|
201
|
+
"css-too-small"
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
for (const substring of requiredCssSubstrings) {
|
|
205
|
+
if (!css.includes(substring)) {
|
|
206
|
+
fail(`Expected CSS to contain ${JSON.stringify(substring)}.`, "css-missing-substring");
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
const manifestRel = manifestFile === false ? void 0 : manifestFile;
|
|
210
|
+
if (!manifestRel) {
|
|
211
|
+
return { cssPath, cssBytes };
|
|
212
|
+
}
|
|
213
|
+
const manifestPath = (0, import_node_path2.resolve)(root, manifestRel);
|
|
214
|
+
if (!(0, import_node_fs2.existsSync)(manifestPath)) {
|
|
215
|
+
fail(`Missing ${manifestPath}.`, "manifest-missing");
|
|
216
|
+
}
|
|
217
|
+
const manifest = readManifest(manifestPath);
|
|
218
|
+
if (manifest.version !== manifestVersion) {
|
|
219
|
+
fail(
|
|
220
|
+
`Expected manifest version ${manifestVersion}, got ${manifest.version}.`,
|
|
221
|
+
"manifest-version-mismatch"
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
const expectedCssPath = manifestCssPath ?? cssFile;
|
|
225
|
+
if (manifest.css !== expectedCssPath) {
|
|
226
|
+
fail(
|
|
227
|
+
`Expected manifest.css ${JSON.stringify(expectedCssPath)}, got ${JSON.stringify(manifest.css)}.`,
|
|
228
|
+
"manifest-css-mismatch"
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
if (isManifestV2(manifest)) {
|
|
232
|
+
const routeCount = Object.keys(manifest.routes).length;
|
|
233
|
+
if (minRouteEntries !== void 0 && routeCount < minRouteEntries) {
|
|
234
|
+
fail(
|
|
235
|
+
`Expected at least ${minRouteEntries} route CSS entries, got ${routeCount}.`,
|
|
236
|
+
"manifest-routes-too-few"
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
for (const [routePath, entry] of Object.entries(manifest.routes)) {
|
|
240
|
+
const routeCssPath = (0, import_node_path2.resolve)(root, entry.css);
|
|
241
|
+
if (!(0, import_node_fs2.existsSync)(routeCssPath)) {
|
|
242
|
+
fail(`Missing route CSS for ${routePath} at ${routeCssPath}.`, "route-css-missing");
|
|
243
|
+
}
|
|
244
|
+
if (Buffer.byteLength((0, import_node_fs2.readFileSync)(routeCssPath, "utf8"), "utf8") < 1) {
|
|
245
|
+
fail(`Route CSS for ${routePath} is empty.`, "route-css-empty");
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
cssPath,
|
|
251
|
+
cssBytes,
|
|
252
|
+
manifestPath,
|
|
253
|
+
manifestVersion: manifest.version
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// src/next-routes.ts
|
|
258
|
+
var import_node_fs3 = require("fs");
|
|
259
|
+
var import_node_path3 = require("path");
|
|
260
|
+
var PAGE_BASENAMES = /* @__PURE__ */ new Set(["page.tsx", "page.ts", "page.jsx", "page.js"]);
|
|
261
|
+
var LAYOUT_BASENAMES = /* @__PURE__ */ new Set(["layout.tsx", "layout.ts", "layout.jsx", "layout.js"]);
|
|
262
|
+
function normalizeRelPath(root, absPath) {
|
|
263
|
+
return (0, import_node_path3.relative)(root, absPath).replace(/\\/g, "/");
|
|
264
|
+
}
|
|
265
|
+
function isRouteGroupSegment(segment) {
|
|
266
|
+
return segment.startsWith("(") && segment.endsWith(")");
|
|
267
|
+
}
|
|
268
|
+
function pageRelPathToRoutePath(pageRelPath) {
|
|
269
|
+
const dir = (0, import_node_path3.dirname)(pageRelPath).replace(/\\/g, "/");
|
|
270
|
+
if (dir === "." || dir === "") return "/";
|
|
271
|
+
const segments = dir.split("/").filter((segment) => segment.length > 0 && !isRouteGroupSegment(segment));
|
|
272
|
+
return segments.length === 0 ? "/" : `/${segments.join("/")}`;
|
|
273
|
+
}
|
|
274
|
+
function walkForPages(appAbs, currentRel, pages) {
|
|
275
|
+
const currentAbs = (0, import_node_path3.join)(appAbs, currentRel);
|
|
276
|
+
let entries;
|
|
277
|
+
try {
|
|
278
|
+
entries = (0, import_node_fs3.readdirSync)(currentAbs);
|
|
279
|
+
} catch {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
for (const entry of entries) {
|
|
283
|
+
const entryRel = currentRel ? (0, import_node_path3.join)(currentRel, entry) : entry;
|
|
284
|
+
const entryAbs = (0, import_node_path3.join)(appAbs, entryRel);
|
|
285
|
+
let stat;
|
|
286
|
+
try {
|
|
287
|
+
stat = (0, import_node_fs3.statSync)(entryAbs);
|
|
288
|
+
} catch {
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
if (stat.isDirectory()) {
|
|
292
|
+
walkForPages(appAbs, entryRel, pages);
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
if (PAGE_BASENAMES.has(entry)) {
|
|
296
|
+
pages.push(entryRel.replace(/\\/g, "/"));
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function collectLayoutChain(appAbs, pageRelPath) {
|
|
301
|
+
const layouts = [];
|
|
302
|
+
const segments = (0, import_node_path3.dirname)(pageRelPath).replace(/\\/g, "/").split("/");
|
|
303
|
+
const chainDirs = [""];
|
|
304
|
+
for (const segment of segments) {
|
|
305
|
+
if (!segment || segment === ".") continue;
|
|
306
|
+
const parent = chainDirs[chainDirs.length - 1];
|
|
307
|
+
chainDirs.push(parent ? `${parent}/${segment}` : segment);
|
|
308
|
+
}
|
|
309
|
+
for (const dir of chainDirs) {
|
|
310
|
+
const dirAbs = dir ? (0, import_node_path3.join)(appAbs, dir) : appAbs;
|
|
311
|
+
for (const layoutName of LAYOUT_BASENAMES) {
|
|
312
|
+
const layoutAbs = (0, import_node_path3.join)(dirAbs, layoutName);
|
|
313
|
+
if ((0, import_node_fs3.existsSync)(layoutAbs)) {
|
|
314
|
+
layouts.push((0, import_node_path3.join)(dir, layoutName).replace(/\\/g, "/"));
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return layouts;
|
|
320
|
+
}
|
|
321
|
+
function discoverNextAppRoutes(root, appDir = "app") {
|
|
322
|
+
const appAbs = (0, import_node_path3.resolve)(root, appDir);
|
|
323
|
+
if (!(0, import_node_fs3.existsSync)(appAbs)) return [];
|
|
324
|
+
const pageRelPaths = [];
|
|
325
|
+
walkForPages(appAbs, "", pageRelPaths);
|
|
326
|
+
return pageRelPaths.map((pageRelPath) => {
|
|
327
|
+
const pageFile = normalizeRelPath(root, (0, import_node_path3.join)(appAbs, pageRelPath));
|
|
328
|
+
const layoutFiles = collectLayoutChain(appAbs, pageRelPath).map(
|
|
329
|
+
(layoutRel) => normalizeRelPath(root, (0, import_node_path3.join)(appAbs, layoutRel))
|
|
330
|
+
);
|
|
331
|
+
return {
|
|
332
|
+
routePath: pageRelPathToRoutePath(pageRelPath),
|
|
333
|
+
pageFile,
|
|
334
|
+
layoutFiles
|
|
335
|
+
};
|
|
336
|
+
}).sort((a, b) => a.routePath.localeCompare(b.routePath));
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// src/trace-imports.ts
|
|
340
|
+
var import_esbuild = require("esbuild");
|
|
341
|
+
var import_node_fs4 = require("fs");
|
|
342
|
+
var import_node_path4 = require("path");
|
|
343
|
+
var import_node_url = require("url");
|
|
344
|
+
var EXTERNAL_PREFIXES = [
|
|
345
|
+
"react",
|
|
346
|
+
"react-dom",
|
|
347
|
+
"react/",
|
|
348
|
+
"react-dom/",
|
|
349
|
+
"next",
|
|
350
|
+
"next/",
|
|
351
|
+
"server-only",
|
|
352
|
+
"client-only",
|
|
353
|
+
"typestyles",
|
|
354
|
+
"typestyles/"
|
|
355
|
+
];
|
|
356
|
+
function isExternalBareImport(specifier) {
|
|
357
|
+
if (specifier.startsWith("node:")) return true;
|
|
358
|
+
return EXTERNAL_PREFIXES.some(
|
|
359
|
+
(prefix) => specifier === prefix || specifier.startsWith(`${prefix}/`)
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
function isExternalAssetPath(path, importer, namespace) {
|
|
363
|
+
if (path.endsWith(".css")) return true;
|
|
364
|
+
const fromCss = namespace === "css" || importer.endsWith(".css");
|
|
365
|
+
if (fromCss && path.startsWith("/") && !path.startsWith("//")) {
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
function fileImportsTypestyles(absPath) {
|
|
371
|
+
if (!(0, import_node_fs4.existsSync)(absPath)) return false;
|
|
372
|
+
try {
|
|
373
|
+
return TYPESTYLES_IMPORT_RE.test((0, import_node_fs4.readFileSync)(absPath, "utf8"));
|
|
374
|
+
} catch {
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
async function traceTypestylesModules(root, entryFiles) {
|
|
379
|
+
const absEntries = entryFiles.map((file) => (0, import_node_path4.resolve)(root, file));
|
|
380
|
+
const missing = absEntries.filter((file) => !(0, import_node_fs4.existsSync)(file));
|
|
381
|
+
if (missing.length > 0) {
|
|
382
|
+
throw new Error(
|
|
383
|
+
`[typestyles] Cannot trace imports; missing entry file(s): ${missing.join(", ")}`
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
const tsconfigPath = (0, import_node_path4.join)(root, "tsconfig.json");
|
|
387
|
+
const result = await (0, import_esbuild.build)({
|
|
388
|
+
entryPoints: absEntries,
|
|
389
|
+
bundle: true,
|
|
390
|
+
write: false,
|
|
391
|
+
outdir: root,
|
|
392
|
+
metafile: true,
|
|
393
|
+
platform: "neutral",
|
|
394
|
+
format: "esm",
|
|
395
|
+
logLevel: "silent",
|
|
396
|
+
absWorkingDir: root,
|
|
397
|
+
...(0, import_node_fs4.existsSync)(tsconfigPath) ? { tsconfig: tsconfigPath } : {},
|
|
398
|
+
plugins: [
|
|
399
|
+
{
|
|
400
|
+
name: "typestyles-trace-imports",
|
|
401
|
+
setup(build) {
|
|
402
|
+
build.onResolve({ filter: /.*/ }, (args) => {
|
|
403
|
+
if (isExternalAssetPath(args.path, args.importer, args.namespace)) {
|
|
404
|
+
return { path: args.path, external: true };
|
|
405
|
+
}
|
|
406
|
+
if (args.path.startsWith(".")) {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
if (isExternalBareImport(args.path)) {
|
|
410
|
+
return { path: args.path, external: true };
|
|
411
|
+
}
|
|
412
|
+
return null;
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
]
|
|
417
|
+
});
|
|
418
|
+
const inputs = result.metafile?.inputs ?? {};
|
|
419
|
+
const traced = /* @__PURE__ */ new Set();
|
|
420
|
+
for (const inputPath of Object.keys(inputs)) {
|
|
421
|
+
const absPath = (0, import_node_path4.resolve)(root, inputPath);
|
|
422
|
+
if (!fileImportsTypestyles(absPath)) continue;
|
|
423
|
+
traced.add(inputPath.replace(/\\/g, "/"));
|
|
424
|
+
}
|
|
425
|
+
return [...traced].sort();
|
|
426
|
+
}
|
|
427
|
+
function createModuleLoader(root, modulePath) {
|
|
428
|
+
const abs = (0, import_node_path4.resolve)(root, modulePath);
|
|
429
|
+
const href = (0, import_node_url.pathToFileURL)(abs).href;
|
|
430
|
+
return () => import(href);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// src/route-css.ts
|
|
434
|
+
var import_promises = require("fs/promises");
|
|
435
|
+
var import_node_path5 = require("path");
|
|
436
|
+
function routePathToCssFile(routePath) {
|
|
437
|
+
if (routePath === "/") return "index.css";
|
|
438
|
+
const slug = routePath.slice(1).replace(/^\[|\]$/g, "").replace(/[^\w.-]+/g, "-");
|
|
439
|
+
return `${slug || "route"}.css`;
|
|
440
|
+
}
|
|
441
|
+
function uniqueModules(...groups) {
|
|
442
|
+
return [...new Set(groups.flat())].sort();
|
|
443
|
+
}
|
|
444
|
+
async function collectAndWriteRouteCss(options) {
|
|
445
|
+
const {
|
|
446
|
+
root,
|
|
447
|
+
sharedModules,
|
|
448
|
+
appDir = "app",
|
|
449
|
+
routeCssOutDir = "app/_typestyles/routes",
|
|
450
|
+
collectCss
|
|
451
|
+
} = options;
|
|
452
|
+
const routes = discoverNextAppRoutes(root, appDir);
|
|
453
|
+
if (routes.length === 0) {
|
|
454
|
+
return { routes: {} };
|
|
455
|
+
}
|
|
456
|
+
const manifestRoutes = {};
|
|
457
|
+
for (const route of routes) {
|
|
458
|
+
const entryFiles = uniqueModules(route.layoutFiles, [route.pageFile]);
|
|
459
|
+
const routeModules = await traceTypestylesModules(root, entryFiles);
|
|
460
|
+
const modules = uniqueModules(sharedModules, routeModules);
|
|
461
|
+
const loaders = modules.map((mod) => createModuleLoader(root, mod));
|
|
462
|
+
const css = await collectCss(loaders);
|
|
463
|
+
const cssFileName = routePathToCssFile(route.routePath);
|
|
464
|
+
const cssRel = `${routeCssOutDir.replace(/\\/g, "/")}/${cssFileName}`;
|
|
465
|
+
const cssAbs = (0, import_node_path5.resolve)(root, cssRel);
|
|
466
|
+
await (0, import_promises.mkdir)((0, import_node_path5.dirname)(cssAbs), { recursive: true });
|
|
467
|
+
await (0, import_promises.writeFile)(cssAbs, css, "utf8");
|
|
468
|
+
manifestRoutes[route.routePath] = { css: cssRel };
|
|
469
|
+
}
|
|
470
|
+
return { routes: manifestRoutes };
|
|
471
|
+
}
|
|
472
|
+
function buildManifestV2(cssOutFile, routeEntries) {
|
|
473
|
+
return {
|
|
474
|
+
version: 2,
|
|
475
|
+
css: cssOutFile,
|
|
476
|
+
routes: routeEntries
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// src/route-css-read.ts
|
|
481
|
+
var import_node_fs5 = require("fs");
|
|
482
|
+
var import_node_path6 = require("path");
|
|
483
|
+
function readTypestylesManifest(root, manifestFile = "app/typestyles.manifest.json") {
|
|
484
|
+
const manifestPath = (0, import_node_path6.resolve)(root, manifestFile);
|
|
485
|
+
if (!(0, import_node_fs5.existsSync)(manifestPath)) {
|
|
486
|
+
throw new Error(`[typestyles] Missing manifest at ${manifestPath}.`);
|
|
487
|
+
}
|
|
488
|
+
let parsed;
|
|
489
|
+
try {
|
|
490
|
+
parsed = JSON.parse((0, import_node_fs5.readFileSync)(manifestPath, "utf8"));
|
|
491
|
+
} catch {
|
|
492
|
+
throw new Error(`[typestyles] Invalid JSON in ${manifestPath}.`);
|
|
493
|
+
}
|
|
494
|
+
if (typeof parsed !== "object" || parsed === null || !("version" in parsed) || !("css" in parsed)) {
|
|
495
|
+
throw new Error(`[typestyles] Manifest at ${manifestPath} is missing required fields.`);
|
|
496
|
+
}
|
|
497
|
+
return parsed;
|
|
498
|
+
}
|
|
499
|
+
function readCssFile(root, cssRelPath) {
|
|
500
|
+
const cssPath = (0, import_node_path6.resolve)(root, cssRelPath);
|
|
501
|
+
if (!(0, import_node_fs5.existsSync)(cssPath)) {
|
|
502
|
+
throw new Error(`[typestyles] Missing CSS file at ${cssPath}.`);
|
|
503
|
+
}
|
|
504
|
+
return (0, import_node_fs5.readFileSync)(cssPath, "utf8");
|
|
505
|
+
}
|
|
506
|
+
function getRouteCss(routePath, options) {
|
|
507
|
+
const manifest = readTypestylesManifest(options.root, options.manifestFile);
|
|
508
|
+
const normalized = normalizeRoutePath(routePath);
|
|
509
|
+
if (isManifestV2(manifest)) {
|
|
510
|
+
const routeEntry = manifest.routes[normalized];
|
|
511
|
+
if (routeEntry) {
|
|
512
|
+
return readCssFile(options.root, routeEntry.css);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return readCssFile(options.root, manifest.css);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// src/index.ts
|
|
519
|
+
var import_esbuild2 = require("esbuild");
|
|
520
|
+
var import_node_fs6 = require("fs");
|
|
521
|
+
var import_node_path7 = require("path");
|
|
29
522
|
var import_node_child_process = require("child_process");
|
|
30
523
|
function toImportPath(modulePath) {
|
|
31
524
|
const normalized = modulePath.replace(/\\/g, "/");
|
|
@@ -40,7 +533,7 @@ async function runTypestylesBuild({
|
|
|
40
533
|
}) {
|
|
41
534
|
if (!modules.length) return "";
|
|
42
535
|
const importLines = modules.map((mod) => `import ${JSON.stringify(toImportPath(mod))};`).join("\n");
|
|
43
|
-
const bundleResult = await (0,
|
|
536
|
+
const bundleResult = await (0, import_esbuild2.build)({
|
|
44
537
|
write: false,
|
|
45
538
|
bundle: true,
|
|
46
539
|
platform: "node",
|
|
@@ -58,12 +551,12 @@ async function runTypestylesBuild({
|
|
|
58
551
|
if (!bundledCode) {
|
|
59
552
|
throw new Error("[typestyles] Failed to produce extraction bundle.");
|
|
60
553
|
}
|
|
61
|
-
const scriptPath = (0,
|
|
554
|
+
const scriptPath = (0, import_node_path7.resolve)(root, `.typestyles-extract-${process.pid}.cjs`);
|
|
62
555
|
const script = `${bundledCode}
|
|
63
556
|
process.stdout.write(require('typestyles').getRegisteredCss());
|
|
64
557
|
`;
|
|
65
558
|
try {
|
|
66
|
-
(0,
|
|
559
|
+
(0, import_node_fs6.writeFileSync)(scriptPath, script, "utf8");
|
|
67
560
|
const result = (0, import_node_child_process.spawnSync)(process.execPath, [scriptPath], {
|
|
68
561
|
cwd: root,
|
|
69
562
|
encoding: "utf8",
|
|
@@ -80,9 +573,9 @@ ${result.stderr || result.stdout || "unknown error"}`
|
|
|
80
573
|
}
|
|
81
574
|
return result.stdout ?? "";
|
|
82
575
|
} finally {
|
|
83
|
-
if ((0,
|
|
576
|
+
if ((0, import_node_fs6.existsSync)(scriptPath)) {
|
|
84
577
|
try {
|
|
85
|
-
(0,
|
|
578
|
+
(0, import_node_fs6.unlinkSync)(scriptPath);
|
|
86
579
|
} catch {
|
|
87
580
|
}
|
|
88
581
|
}
|
|
@@ -90,5 +583,25 @@ ${result.stderr || result.stdout || "unknown error"}`
|
|
|
90
583
|
}
|
|
91
584
|
// Annotate the CommonJS export names for ESM import in node:
|
|
92
585
|
0 && (module.exports = {
|
|
93
|
-
|
|
586
|
+
DEFAULT_EXTRACT_MODULE_CANDIDATES,
|
|
587
|
+
TYPESTYLES_IMPORT_RE,
|
|
588
|
+
VerifyTypestylesBuildError,
|
|
589
|
+
buildManifestV2,
|
|
590
|
+
collectAndWriteRouteCss,
|
|
591
|
+
createModuleLoader,
|
|
592
|
+
discoverDefaultExtractModules,
|
|
593
|
+
discoverNextAppRoutes,
|
|
594
|
+
extractNamespaces,
|
|
595
|
+
getRouteCss,
|
|
596
|
+
isManifestV2,
|
|
597
|
+
normalizeRoutePath,
|
|
598
|
+
pageRelPathToRoutePath,
|
|
599
|
+
readCssFile,
|
|
600
|
+
readTypestylesManifest,
|
|
601
|
+
reportDuplicateNamespaces,
|
|
602
|
+
resolveExtractMode,
|
|
603
|
+
resolveExtractModules,
|
|
604
|
+
runTypestylesBuild,
|
|
605
|
+
traceTypestylesModules,
|
|
606
|
+
verifyTypestylesBuild
|
|
94
607
|
});
|