sculpted 0.3.2 → 0.3.4
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 +4 -2
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +1 -1
- package/dist/{patcher-DQgKdozw.mjs → patcher-nj9VhRT-.mjs} +131 -11
- package/dist/{runtime-C1gUOAc9.d.mts → runtime-C5jlEq5d.d.mts} +1 -1
- package/dist/runtime.d.mts +1 -1
- package/dist/runtime.mjs +5017 -19
- package/dist/{sourceSyntax-U2iybN9L.d.mts → sourceSyntax-BpjcDJyk.d.mts} +1 -1
- package/dist/tsrx.d.mts +1 -1
- package/dist/{types-CdByW0ji.d.mts → types-BWXru9cn.d.mts} +12 -1
- package/dist/ui.d.mts +7 -2
- package/dist/ui.mjs +392 -128
- package/dist/vite.d.mts +1 -1
- package/dist/vite.mjs +553 -186
- package/docs/source-writeback.md +4 -2
- package/docs/vite-plugin.md +11 -2
- package/examples/vite-preact-pandacss/package.json +1 -1
- package/examples/vite-preact-pandacss/postcss.config.cjs +2 -2
- package/examples/vite-preact-pandacss/src/BatchFixtures.tsx +77 -0
- package/examples/vite-preact-pandacss/src/index.css +6 -1
- package/examples/vite-preact-pandacss/src/main.tsx +2 -0
- package/examples/vite-preact-pandacss/vite.config.ts +5 -5
- package/examples/vite-react-pandacss/package.json +1 -1
- package/examples/vite-react-pandacss/src/BatchFixtures.tsx +77 -0
- package/examples/vite-react-pandacss/src/index.css +6 -1
- package/examples/vite-react-pandacss/src/main.tsx +2 -0
- package/package.json +20 -19
package/dist/vite.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { _ as markerClassForEditId, a as DEFAULT_JSX_SOURCE_ATTRIBUTE, c as DEFAULT_OPEN_SOURCE_ENDPOINT, d as DEFAULT_TOKEN_WRITEBACK_ENDPOINT, f as DEFAULT_WRITEBACK_ENDPOINT, l as DEFAULT_SOURCE_ATTRIBUTE, p as SCULPTED_EVENTS, r as DEFAULT_EDIT_ID_ATTRIBUTE, t as DEFAULT_COMPONENT_ATTRIBUTE, u as DEFAULT_STYLE_MODULE_ENDPOINT } from "./protocol-D5heR2QM.mjs";
|
|
2
|
-
import { S as
|
|
2
|
+
import { S as parsePandaSource, _ as createStaticCssPatch, a as createStyleModuleSourcePatch, b as hashSource, c as resolveProjectPath, d as toRelativeProjectPath$1, f as trustedManifestFilePath, g as createStaticCssBatchPatch, h as verifyProjectWritePath, i as createStyleModuleDetachPatch, l as safeProjectSourcePath, m as verifyProjectExistingPath, n as componentStyleModulePaths, o as readComponentStyleModule, p as trustedTokenSourceFilePath, r as createStyleModuleAttachPatch, s as normalizePath$1, t as createTokenConfigPatch, u as stripViteQuery, v as createInlineCssSourcePatch, w as resolveSourceParserAdapter, y as analyzePandaCssSource } from "./patcher-nj9VhRT-.mjs";
|
|
3
3
|
import ts from "typescript";
|
|
4
4
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
5
|
-
import { loadConfigAndCreateContext } from "@pandacss/node";
|
|
6
5
|
import { dirname } from "node:path";
|
|
6
|
+
import { loadConfigAndCreateContext } from "@pandacss/node";
|
|
7
7
|
//#region src/vite/constants.ts
|
|
8
8
|
const DEFAULT_EXCLUDE = ["node_modules/**", "styled-system/**"];
|
|
9
9
|
const DEFAULT_RUNTIME_BOOTSTRAP_ENDPOINT = "/@sculpted/runtime";
|
|
@@ -21,6 +21,61 @@ const DEFAULT_PANDA_CONFIG_FILES = [
|
|
|
21
21
|
];
|
|
22
22
|
//#endregion
|
|
23
23
|
//#region src/vite/editorProperties.ts
|
|
24
|
+
const EDITOR_PROPERTY_COMMONNESS = {
|
|
25
|
+
display: 2.2,
|
|
26
|
+
color: 2.1,
|
|
27
|
+
background: 2,
|
|
28
|
+
backgroundColor: 2,
|
|
29
|
+
padding: 2,
|
|
30
|
+
paddingX: 1.9,
|
|
31
|
+
paddingY: 1.9,
|
|
32
|
+
paddingTop: 1.8,
|
|
33
|
+
paddingRight: 1.8,
|
|
34
|
+
paddingBottom: 1.8,
|
|
35
|
+
paddingLeft: 1.8,
|
|
36
|
+
margin: 1.9,
|
|
37
|
+
marginX: 1.8,
|
|
38
|
+
marginY: 1.8,
|
|
39
|
+
marginTop: 1.7,
|
|
40
|
+
marginRight: 1.7,
|
|
41
|
+
marginBottom: 1.7,
|
|
42
|
+
marginLeft: 1.7,
|
|
43
|
+
width: 1.9,
|
|
44
|
+
height: 1.8,
|
|
45
|
+
borderRadius: 1.8,
|
|
46
|
+
gap: 1.8,
|
|
47
|
+
fontSize: 1.8,
|
|
48
|
+
fontWeight: 1.7,
|
|
49
|
+
lineHeight: 1.7,
|
|
50
|
+
position: 1.7,
|
|
51
|
+
opacity: 1.7,
|
|
52
|
+
border: 1.6,
|
|
53
|
+
boxShadow: 1.5,
|
|
54
|
+
alignItems: 1.5,
|
|
55
|
+
justifyContent: 1.5,
|
|
56
|
+
flexDirection: 1.4,
|
|
57
|
+
overflow: 1.4,
|
|
58
|
+
cursor: 1.3,
|
|
59
|
+
transform: 1.3,
|
|
60
|
+
maxWidth: 1.3,
|
|
61
|
+
minWidth: 1.3,
|
|
62
|
+
top: 1.2,
|
|
63
|
+
right: 1.2,
|
|
64
|
+
bottom: 1.2,
|
|
65
|
+
left: 1.2,
|
|
66
|
+
inset: 1.2,
|
|
67
|
+
zIndex: 1.2,
|
|
68
|
+
backgroundImage: 1.1,
|
|
69
|
+
outline: 1.1,
|
|
70
|
+
transition: 1.1,
|
|
71
|
+
pointerEvents: 1.1,
|
|
72
|
+
userSelect: 1.1,
|
|
73
|
+
backdropFilter: .8,
|
|
74
|
+
mixBlendMode: .8,
|
|
75
|
+
backgroundAttachment: .7,
|
|
76
|
+
transitionTimingFunction: .7,
|
|
77
|
+
cornerShape: .6
|
|
78
|
+
};
|
|
24
79
|
function editorProperty(name, label, category, cssProperty, aliases = [], tokenCategory) {
|
|
25
80
|
return {
|
|
26
81
|
name,
|
|
@@ -29,9 +84,13 @@ function editorProperty(name, label, category, cssProperty, aliases = [], tokenC
|
|
|
29
84
|
cssProperty,
|
|
30
85
|
aliases,
|
|
31
86
|
tokenCategory,
|
|
32
|
-
defaultUnit: defaultEditorPropertyUnit(name, category)
|
|
87
|
+
defaultUnit: defaultEditorPropertyUnit(name, category),
|
|
88
|
+
commonness: editorPropertyCommonness(name)
|
|
33
89
|
};
|
|
34
90
|
}
|
|
91
|
+
function editorPropertyCommonness(name) {
|
|
92
|
+
return EDITOR_PROPERTY_COMMONNESS[name] ?? 1;
|
|
93
|
+
}
|
|
35
94
|
function defaultEditorPropertyUnit(name, category) {
|
|
36
95
|
if ([
|
|
37
96
|
"zIndex",
|
|
@@ -281,22 +340,43 @@ async function createEditorMetadata(options) {
|
|
|
281
340
|
properties
|
|
282
341
|
};
|
|
283
342
|
}
|
|
343
|
+
function tokenSourceIdsForPandaConfigSource(options) {
|
|
344
|
+
return parsePandaConfigEditorMetadata(options).tokenSources.map((item) => item.id);
|
|
345
|
+
}
|
|
284
346
|
async function readPandaConfigSource(projectRoot, pandaConfigPath) {
|
|
285
347
|
const root = normalizePath(projectRoot).replace(/\/$/, "");
|
|
286
348
|
const candidates = pandaConfigPath ? [absoluteProjectPath(root, pandaConfigPath)] : DEFAULT_PANDA_CONFIG_FILES.map((fileName) => `${root}/${fileName}`);
|
|
287
|
-
for (const filePath of candidates)
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
349
|
+
for (const filePath of candidates) {
|
|
350
|
+
try {
|
|
351
|
+
await access(filePath);
|
|
352
|
+
} catch (error) {
|
|
353
|
+
if (isMissingFileError$2(error)) continue;
|
|
354
|
+
return {
|
|
355
|
+
ok: false,
|
|
356
|
+
reason: "panda-config-unreadable",
|
|
357
|
+
message: `Failed to access Panda config ${filePath}: ${errorMessage$1(error)}`
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
const safePath = await verifyProjectExistingPath(root, filePath);
|
|
361
|
+
if (!safePath.ok) return {
|
|
296
362
|
ok: false,
|
|
297
363
|
reason: "panda-config-unreadable",
|
|
298
|
-
message:
|
|
364
|
+
message: safePath.message
|
|
299
365
|
};
|
|
366
|
+
try {
|
|
367
|
+
return {
|
|
368
|
+
ok: true,
|
|
369
|
+
filePath,
|
|
370
|
+
sourceText: await readFile(filePath, "utf8")
|
|
371
|
+
};
|
|
372
|
+
} catch (error) {
|
|
373
|
+
if (isMissingFileError$2(error)) continue;
|
|
374
|
+
return {
|
|
375
|
+
ok: false,
|
|
376
|
+
reason: "panda-config-unreadable",
|
|
377
|
+
message: `Failed to read Panda config ${filePath}: ${errorMessage$1(error)}`
|
|
378
|
+
};
|
|
379
|
+
}
|
|
300
380
|
}
|
|
301
381
|
return {
|
|
302
382
|
ok: false,
|
|
@@ -446,7 +526,7 @@ async function resolvePandaConfigEditorMetadata(options) {
|
|
|
446
526
|
} catch (error) {
|
|
447
527
|
return {
|
|
448
528
|
ok: false,
|
|
449
|
-
message: `Failed to resolve Panda token metadata: ${errorMessage(error)}`
|
|
529
|
+
message: `Failed to resolve Panda token metadata: ${errorMessage$1(error)}`
|
|
450
530
|
};
|
|
451
531
|
}
|
|
452
532
|
}
|
|
@@ -697,7 +777,7 @@ function collectColorTokenMetadata(object, options, path = []) {
|
|
|
697
777
|
sourcePath: nextPath,
|
|
698
778
|
writable: options.writable,
|
|
699
779
|
readonlyReason: options.writable ? void 0 : "Token source target is read-only.",
|
|
700
|
-
conditions: options.kind === "semantic-token" && isJsonObject(value) ? Object.entries(value).map(([condition, conditionValue]) => ({
|
|
780
|
+
conditions: options.kind === "semantic-token" && isJsonObject$1(value) ? Object.entries(value).map(([condition, conditionValue]) => ({
|
|
701
781
|
condition,
|
|
702
782
|
value: conditionValue,
|
|
703
783
|
swatch: swatchFromJsonValue(conditionValue)
|
|
@@ -822,7 +902,7 @@ function unavailableMetadataSection(reason, message) {
|
|
|
822
902
|
message
|
|
823
903
|
};
|
|
824
904
|
}
|
|
825
|
-
function isJsonObject(value) {
|
|
905
|
+
function isJsonObject$1(value) {
|
|
826
906
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
827
907
|
}
|
|
828
908
|
function swatchFromJsonValue(value) {
|
|
@@ -848,7 +928,7 @@ function normalizePath(path) {
|
|
|
848
928
|
function isMissingFileError$2(error) {
|
|
849
929
|
return isRecord$3(error) && error.code === "ENOENT";
|
|
850
930
|
}
|
|
851
|
-
function errorMessage(error) {
|
|
931
|
+
function errorMessage$1(error) {
|
|
852
932
|
return error instanceof Error ? error.message : String(error);
|
|
853
933
|
}
|
|
854
934
|
function isRecord$3(value) {
|
|
@@ -866,10 +946,33 @@ function isJsonValue$1(value) {
|
|
|
866
946
|
return Object.values(value).every(isJsonValue$1);
|
|
867
947
|
}
|
|
868
948
|
//#endregion
|
|
949
|
+
//#region src/vite/logging.ts
|
|
950
|
+
function logUnexpectedDevServerError(message, error) {
|
|
951
|
+
console.error(`[sculpted] ${message}`, error);
|
|
952
|
+
}
|
|
953
|
+
function errorMessage(error) {
|
|
954
|
+
return error instanceof Error ? error.message : String(error);
|
|
955
|
+
}
|
|
956
|
+
//#endregion
|
|
957
|
+
//#region src/vite/requestBody.ts
|
|
958
|
+
const MAX_DEV_SERVER_JSON_BODY_BYTES = 1024 * 1024;
|
|
959
|
+
async function readRequestBody(request, maxBytes = MAX_DEV_SERVER_JSON_BODY_BYTES) {
|
|
960
|
+
if (!request[Symbol.asyncIterator]) return "";
|
|
961
|
+
let bytes = 0;
|
|
962
|
+
let body = "";
|
|
963
|
+
for await (const chunk of request) {
|
|
964
|
+
const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
|
|
965
|
+
bytes += Buffer.byteLength(text);
|
|
966
|
+
if (bytes > maxBytes) throw new Error(`Request body exceeds ${maxBytes} bytes.`);
|
|
967
|
+
body += text;
|
|
968
|
+
}
|
|
969
|
+
return body;
|
|
970
|
+
}
|
|
971
|
+
//#endregion
|
|
869
972
|
//#region src/vite/sourceLocation.ts
|
|
870
973
|
async function readOpenSourceLocationRequest(request) {
|
|
871
974
|
try {
|
|
872
|
-
const body = await readRequestBody
|
|
975
|
+
const body = await readRequestBody(request);
|
|
873
976
|
const parsed = JSON.parse(body);
|
|
874
977
|
if (!isOpenSourceLocationRequest(parsed)) return {
|
|
875
978
|
ok: false,
|
|
@@ -900,6 +1003,8 @@ async function resolveOpenSourceLocation(options) {
|
|
|
900
1003
|
} catch {
|
|
901
1004
|
return openSourceLocationFailure("file-not-found", "Component source file does not exist.", { file: toRelativeProjectPath$1(trustedPath.file, options.projectRoot) });
|
|
902
1005
|
}
|
|
1006
|
+
const resolvedPath = await verifyProjectExistingPath(options.projectRoot, trustedPath.file);
|
|
1007
|
+
if (!resolvedPath.ok) return openSourceLocationFailure("path-outside-project", resolvedPath.message, resolvedPath.details);
|
|
903
1008
|
return openSourceLocationSuccess({
|
|
904
1009
|
file: trustedPath.file,
|
|
905
1010
|
line,
|
|
@@ -916,6 +1021,8 @@ async function resolveOpenSourceLocation(options) {
|
|
|
916
1021
|
} catch {
|
|
917
1022
|
return openSourceLocationFailure("file-not-found", "Source file does not exist.", { file: toRelativeProjectPath$1(safePath.file, options.projectRoot) });
|
|
918
1023
|
}
|
|
1024
|
+
const resolvedPath = await verifyProjectExistingPath(options.projectRoot, safePath.file);
|
|
1025
|
+
if (!resolvedPath.ok) return openSourceLocationFailure("path-outside-project", resolvedPath.message, resolvedPath.details);
|
|
919
1026
|
return openSourceLocationSuccess({
|
|
920
1027
|
file: safePath.file,
|
|
921
1028
|
line: parsed.line,
|
|
@@ -935,9 +1042,9 @@ function parseSourceLocationText(source) {
|
|
|
935
1042
|
ok: false,
|
|
936
1043
|
response: openSourceLocationFailure("invalid-request", "Source location must include a file path.")
|
|
937
1044
|
};
|
|
938
|
-
const line =
|
|
939
|
-
const column =
|
|
940
|
-
if (
|
|
1045
|
+
const line = parseOptionalPositiveInteger(match[2]);
|
|
1046
|
+
const column = parseOptionalPositiveInteger(match[3]);
|
|
1047
|
+
if (match[2] !== void 0 && line === void 0 || match[3] !== void 0 && column === void 0) return {
|
|
941
1048
|
ok: false,
|
|
942
1049
|
response: openSourceLocationFailure("invalid-request", "Line and column numbers must be positive integers.")
|
|
943
1050
|
};
|
|
@@ -948,6 +1055,11 @@ function parseSourceLocationText(source) {
|
|
|
948
1055
|
column
|
|
949
1056
|
};
|
|
950
1057
|
}
|
|
1058
|
+
function parseOptionalPositiveInteger(value) {
|
|
1059
|
+
if (value === void 0) return void 0;
|
|
1060
|
+
const parsed = Number(value);
|
|
1061
|
+
return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : void 0;
|
|
1062
|
+
}
|
|
951
1063
|
function openSourceLocationSuccess(options) {
|
|
952
1064
|
const file = toRelativeProjectPath$1(options.file, options.projectRoot);
|
|
953
1065
|
const location = [
|
|
@@ -975,15 +1087,12 @@ function openSourceLocationFailure(code, message, details) {
|
|
|
975
1087
|
}
|
|
976
1088
|
function isOpenSourceLocationRequest(value) {
|
|
977
1089
|
if (!isRecord$2(value)) return false;
|
|
978
|
-
if (value.kind === "source") return typeof value.source === "string" && value.source.length > 0;
|
|
979
|
-
if (value.kind === "component") return typeof value.editId === "string" && value.editId.length > 0;
|
|
1090
|
+
if (value.kind === "source") return hasOnlyKeys$2(value, ["kind", "source"]) && typeof value.source === "string" && value.source.length > 0;
|
|
1091
|
+
if (value.kind === "component") return hasOnlyKeys$2(value, ["kind", "editId"]) && typeof value.editId === "string" && value.editId.length > 0;
|
|
980
1092
|
return false;
|
|
981
1093
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
let body = "";
|
|
985
|
-
for await (const chunk of request) body += typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
|
|
986
|
-
return body;
|
|
1094
|
+
function hasOnlyKeys$2(value, allowedKeys) {
|
|
1095
|
+
return Object.keys(value).every((key) => allowedKeys.includes(key));
|
|
987
1096
|
}
|
|
988
1097
|
function isRecord$2(value) {
|
|
989
1098
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -1010,10 +1119,11 @@ function registerRuntimeModuleRoutes(server, options) {
|
|
|
1010
1119
|
response.setHeader("cache-control", "no-store");
|
|
1011
1120
|
response.end(runtimeModuleSourceMap);
|
|
1012
1121
|
} catch (error) {
|
|
1122
|
+
logUnexpectedDevServerError("Failed to load Sculpted runtime module source map.", error);
|
|
1013
1123
|
response.statusCode = 404;
|
|
1014
1124
|
response.setHeader("content-type", "text/plain");
|
|
1015
1125
|
response.setHeader("cache-control", "no-store");
|
|
1016
|
-
response.end(`Failed to load Sculpted runtime module source map: ${
|
|
1126
|
+
response.end(`Failed to load Sculpted runtime module source map: ${errorMessage(error)}`);
|
|
1017
1127
|
}
|
|
1018
1128
|
});
|
|
1019
1129
|
server.middlewares.use(options.runtimeModuleEndpoint, async (_request, response) => {
|
|
@@ -1024,10 +1134,11 @@ function registerRuntimeModuleRoutes(server, options) {
|
|
|
1024
1134
|
response.setHeader("cache-control", "no-store");
|
|
1025
1135
|
response.end(runtimeModuleSource);
|
|
1026
1136
|
} catch (error) {
|
|
1137
|
+
logUnexpectedDevServerError("Failed to load Sculpted runtime module.", error);
|
|
1027
1138
|
response.statusCode = 500;
|
|
1028
1139
|
response.setHeader("content-type", "text/plain");
|
|
1029
1140
|
response.setHeader("cache-control", "no-store");
|
|
1030
|
-
response.end(`Failed to load Sculpted runtime module: ${
|
|
1141
|
+
response.end(`Failed to load Sculpted runtime module: ${errorMessage(error)}`);
|
|
1031
1142
|
}
|
|
1032
1143
|
});
|
|
1033
1144
|
server.middlewares.use(options.runtimeChunkEndpoint, async (request, response) => {
|
|
@@ -1040,16 +1151,24 @@ function registerRuntimeModuleRoutes(server, options) {
|
|
|
1040
1151
|
return;
|
|
1041
1152
|
}
|
|
1042
1153
|
try {
|
|
1154
|
+
if (!(await runtimeChunkFileNames()).has(fileName)) {
|
|
1155
|
+
response.statusCode = 404;
|
|
1156
|
+
response.setHeader("content-type", "text/plain");
|
|
1157
|
+
response.setHeader("cache-control", "no-store");
|
|
1158
|
+
response.end("Unknown Sculpted runtime chunk.");
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1043
1161
|
const runtimeChunkSource = await readFile(new URL(`./${fileName}`, import.meta.url), "utf8");
|
|
1044
1162
|
response.statusCode = 200;
|
|
1045
1163
|
response.setHeader("content-type", fileName.endsWith(".map") ? "application/json" : "application/javascript");
|
|
1046
1164
|
response.setHeader("cache-control", "no-store");
|
|
1047
1165
|
response.end(runtimeChunkSource);
|
|
1048
1166
|
} catch (error) {
|
|
1167
|
+
logUnexpectedDevServerError("Failed to load Sculpted runtime chunk.", error);
|
|
1049
1168
|
response.statusCode = 404;
|
|
1050
1169
|
response.setHeader("content-type", "text/plain");
|
|
1051
1170
|
response.setHeader("cache-control", "no-store");
|
|
1052
|
-
response.end(`Failed to load Sculpted runtime chunk: ${
|
|
1171
|
+
response.end(`Failed to load Sculpted runtime chunk: ${errorMessage(error)}`);
|
|
1053
1172
|
}
|
|
1054
1173
|
});
|
|
1055
1174
|
server.middlewares.use(DEFAULT_UI_MODULE_SOURCE_MAP_ENDPOINT, async (_request, response) => {
|
|
@@ -1060,10 +1179,11 @@ function registerRuntimeModuleRoutes(server, options) {
|
|
|
1060
1179
|
response.setHeader("cache-control", "no-store");
|
|
1061
1180
|
response.end(uiModuleSourceMap);
|
|
1062
1181
|
} catch (error) {
|
|
1182
|
+
logUnexpectedDevServerError("Failed to load Sculpted UI module source map.", error);
|
|
1063
1183
|
response.statusCode = 404;
|
|
1064
1184
|
response.setHeader("content-type", "text/plain");
|
|
1065
1185
|
response.setHeader("cache-control", "no-store");
|
|
1066
|
-
response.end(`Failed to load Sculpted UI module source map: ${
|
|
1186
|
+
response.end(`Failed to load Sculpted UI module source map: ${errorMessage(error)}`);
|
|
1067
1187
|
}
|
|
1068
1188
|
});
|
|
1069
1189
|
server.middlewares.use(options.uiModuleEndpoint, async (_request, response) => {
|
|
@@ -1074,10 +1194,11 @@ function registerRuntimeModuleRoutes(server, options) {
|
|
|
1074
1194
|
response.setHeader("cache-control", "no-store");
|
|
1075
1195
|
response.end(uiModuleSource);
|
|
1076
1196
|
} catch (error) {
|
|
1197
|
+
logUnexpectedDevServerError("Failed to load Sculpted UI module.", error);
|
|
1077
1198
|
response.statusCode = 500;
|
|
1078
1199
|
response.setHeader("content-type", "text/plain");
|
|
1079
1200
|
response.setHeader("cache-control", "no-store");
|
|
1080
|
-
response.end(`Failed to load Sculpted UI module: ${
|
|
1201
|
+
response.end(`Failed to load Sculpted UI module: ${errorMessage(error)}`);
|
|
1081
1202
|
}
|
|
1082
1203
|
});
|
|
1083
1204
|
}
|
|
@@ -1096,6 +1217,22 @@ function runtimeBootstrapSource(options) {
|
|
|
1096
1217
|
function rewriteInspectorModuleSource(source, runtimeChunkEndpoint, sourceMapEndpoint) {
|
|
1097
1218
|
return source.replaceAll("from \"./", `from "${runtimeChunkEndpoint}`).replace(/\/\/# sourceMappingURL=[^\r\n]+/g, `//# sourceMappingURL=${sourceMapEndpoint}`);
|
|
1098
1219
|
}
|
|
1220
|
+
async function runtimeChunkFileNames() {
|
|
1221
|
+
const [runtimeSource, uiSource] = await Promise.all([readFile(new URL("./runtime.mjs", import.meta.url), "utf8"), readFile(new URL("./ui.mjs", import.meta.url), "utf8")]);
|
|
1222
|
+
return runtimeChunkFileNamesFromSources([runtimeSource, uiSource]);
|
|
1223
|
+
}
|
|
1224
|
+
function runtimeChunkFileNamesFromSources(sources) {
|
|
1225
|
+
const fileNames = /* @__PURE__ */ new Set();
|
|
1226
|
+
for (const source of sources) for (const match of source.matchAll(/(?:from\s+|import\s*\()\s*["']\.\/([^"']+)["']/g)) {
|
|
1227
|
+
const specifier = match[1] ?? "";
|
|
1228
|
+
if (specifier.includes("/") || specifier.includes("\\") || /[?#]/.test(specifier)) continue;
|
|
1229
|
+
const fileName = runtimeChunkFileName(specifier);
|
|
1230
|
+
if (!fileName) continue;
|
|
1231
|
+
fileNames.add(fileName);
|
|
1232
|
+
if (fileName.endsWith(".mjs")) fileNames.add(`${fileName}.map`);
|
|
1233
|
+
}
|
|
1234
|
+
return fileNames;
|
|
1235
|
+
}
|
|
1099
1236
|
function runtimeChunkFileName(url) {
|
|
1100
1237
|
const fileName = (url ?? "").replace(/[?#].*$/, "").split("/").filter(Boolean).at(-1);
|
|
1101
1238
|
if (!fileName || !/^[A-Za-z0-9._-]+\.mjs(?:\.map)?$/.test(fileName)) return void 0;
|
|
@@ -1132,23 +1269,52 @@ function registerStyleModuleRoute(server, options) {
|
|
|
1132
1269
|
return;
|
|
1133
1270
|
}
|
|
1134
1271
|
let sourceText;
|
|
1272
|
+
let styleFileExists = true;
|
|
1135
1273
|
try {
|
|
1136
|
-
|
|
1274
|
+
await access(paths.paths.styleFile);
|
|
1137
1275
|
} catch (error) {
|
|
1138
|
-
if (
|
|
1276
|
+
if (isMissingFileError$1(error)) styleFileExists = false;
|
|
1277
|
+
else {
|
|
1278
|
+
logUnexpectedDevServerError("Failed to read Sculpted style module.", error);
|
|
1139
1279
|
response.statusCode = 400;
|
|
1140
1280
|
response.setHeader("content-type", "application/json");
|
|
1141
1281
|
response.setHeader("cache-control", "no-store");
|
|
1142
|
-
response.end(JSON.stringify(styleModuleFailure("write-failed", `Failed to read style module: ${
|
|
1282
|
+
response.end(JSON.stringify(styleModuleFailure("write-failed", `Failed to read style module: ${errorMessage(error)}`)));
|
|
1143
1283
|
return;
|
|
1144
1284
|
}
|
|
1145
1285
|
}
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1286
|
+
if (styleFileExists) {
|
|
1287
|
+
const safePath = await verifyProjectExistingPath(options.projectRoot, paths.paths.styleFile);
|
|
1288
|
+
if (!safePath.ok) {
|
|
1289
|
+
response.statusCode = 400;
|
|
1290
|
+
response.setHeader("content-type", "application/json");
|
|
1291
|
+
response.setHeader("cache-control", "no-store");
|
|
1292
|
+
response.end(JSON.stringify(styleModuleFailure(safePath.code, safePath.message, safePath.details)));
|
|
1293
|
+
return;
|
|
1294
|
+
}
|
|
1295
|
+
try {
|
|
1296
|
+
sourceText = await readFile(paths.paths.styleFile, "utf8");
|
|
1297
|
+
} catch (error) {
|
|
1298
|
+
logUnexpectedDevServerError("Failed to read Sculpted style module.", error);
|
|
1299
|
+
response.statusCode = 400;
|
|
1300
|
+
response.setHeader("content-type", "application/json");
|
|
1301
|
+
response.setHeader("cache-control", "no-store");
|
|
1302
|
+
response.end(JSON.stringify(styleModuleFailure("write-failed", `Failed to read style module: ${errorMessage(error)}`)));
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
let result;
|
|
1307
|
+
try {
|
|
1308
|
+
result = readComponentStyleModule({
|
|
1309
|
+
projectRoot: options.projectRoot,
|
|
1310
|
+
componentSource: requestResult.componentSource,
|
|
1311
|
+
sourceText,
|
|
1312
|
+
cssImportSources: options.cssImportSources
|
|
1313
|
+
});
|
|
1314
|
+
} catch (error) {
|
|
1315
|
+
logUnexpectedDevServerError("Failed to inspect Sculpted style module.", error);
|
|
1316
|
+
result = styleModuleFailure("write-failed", `Failed to inspect style module: ${errorMessage(error)}`);
|
|
1317
|
+
}
|
|
1152
1318
|
response.statusCode = result.ok ? 200 : 400;
|
|
1153
1319
|
response.setHeader("content-type", "application/json");
|
|
1154
1320
|
response.setHeader("cache-control", "no-store");
|
|
@@ -1157,9 +1323,9 @@ function registerStyleModuleRoute(server, options) {
|
|
|
1157
1323
|
}
|
|
1158
1324
|
async function readStyleModuleRequest(request) {
|
|
1159
1325
|
try {
|
|
1160
|
-
const body = await readRequestBody
|
|
1326
|
+
const body = await readRequestBody(request);
|
|
1161
1327
|
const parsed = JSON.parse(body);
|
|
1162
|
-
if (!isRecord$1(parsed) || typeof parsed.componentSource !== "string") return {
|
|
1328
|
+
if (!isRecord$1(parsed) || !hasOnlyKeys$1(parsed, ["componentSource"]) || typeof parsed.componentSource !== "string" || parsed.componentSource.length === 0) return {
|
|
1163
1329
|
ok: false,
|
|
1164
1330
|
response: styleModuleFailure("invalid-edit", "Request body is not a valid style-module request.")
|
|
1165
1331
|
};
|
|
@@ -1174,12 +1340,6 @@ async function readStyleModuleRequest(request) {
|
|
|
1174
1340
|
};
|
|
1175
1341
|
}
|
|
1176
1342
|
}
|
|
1177
|
-
async function readRequestBody$1(request) {
|
|
1178
|
-
if (!request[Symbol.asyncIterator]) return "";
|
|
1179
|
-
let body = "";
|
|
1180
|
-
for await (const chunk of request) body += typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
|
|
1181
|
-
return body;
|
|
1182
|
-
}
|
|
1183
1343
|
function styleModuleFailure(code, message, details) {
|
|
1184
1344
|
return {
|
|
1185
1345
|
ok: false,
|
|
@@ -1193,6 +1353,9 @@ function styleModuleFailure(code, message, details) {
|
|
|
1193
1353
|
function isMissingFileError$1(error) {
|
|
1194
1354
|
return isRecord$1(error) && error.code === "ENOENT";
|
|
1195
1355
|
}
|
|
1356
|
+
function hasOnlyKeys$1(value, allowedKeys) {
|
|
1357
|
+
return Object.keys(value).every((key) => allowedKeys.includes(key));
|
|
1358
|
+
}
|
|
1196
1359
|
function isRecord$1(value) {
|
|
1197
1360
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1198
1361
|
}
|
|
@@ -1509,42 +1672,49 @@ function registerWritebackRoutes(server, options) {
|
|
|
1509
1672
|
response.end(JSON.stringify(requestResult.response));
|
|
1510
1673
|
return;
|
|
1511
1674
|
}
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1675
|
+
let result;
|
|
1676
|
+
try {
|
|
1677
|
+
result = requestResult.request.kind === "panda-css-inline-source" ? await writeInlineCssSourcePatch({
|
|
1678
|
+
request: requestResult.request,
|
|
1679
|
+
projectRoot: options.projectRoot,
|
|
1680
|
+
cssImportSources: options.cssImportSources,
|
|
1681
|
+
sourceSyntax: options.sourceSyntax,
|
|
1682
|
+
attributes: options.attributes,
|
|
1683
|
+
onManifestEntries: options.onManifestEntries
|
|
1684
|
+
}) : requestResult.request.kind === "panda-css-style-module-source" || requestResult.request.kind === "panda-css-style-module-attach" || requestResult.request.kind === "panda-css-style-module-detach" ? await writeStyleModulePatch({
|
|
1685
|
+
request: requestResult.request,
|
|
1686
|
+
projectRoot: options.projectRoot,
|
|
1687
|
+
cssImportSources: options.cssImportSources,
|
|
1688
|
+
styledSystemPackageName: await inferStyledSystemPackageName(options.projectRoot),
|
|
1689
|
+
attributes: options.attributes,
|
|
1690
|
+
onManifestEntries: options.onManifestEntries
|
|
1691
|
+
}) : requestResult.request.kind === "panda-css-batch" ? await writeStaticCssBatchPatch({
|
|
1692
|
+
manifest: options.manifest(),
|
|
1693
|
+
request: requestResult.request,
|
|
1694
|
+
projectRoot: options.projectRoot,
|
|
1695
|
+
cssImportSources: options.cssImportSources,
|
|
1696
|
+
sourceSyntax: options.sourceSyntax,
|
|
1697
|
+
onManifestEntries: options.onManifestEntries
|
|
1698
|
+
}) : await writeStaticCssPatch({
|
|
1699
|
+
manifest: options.manifest(),
|
|
1700
|
+
request: requestResult.request,
|
|
1701
|
+
projectRoot: options.projectRoot,
|
|
1702
|
+
cssImportSources: options.cssImportSources,
|
|
1703
|
+
sourceSyntax: options.sourceSyntax,
|
|
1704
|
+
onManifestEntries: options.onManifestEntries
|
|
1705
|
+
});
|
|
1706
|
+
} catch (error) {
|
|
1707
|
+
logUnexpectedDevServerError("Unhandled Sculpted writeback failure.", error);
|
|
1708
|
+
const failure = styleEditFailure(requestResult.request.kind === "panda-css-batch" ? requestResult.request.requests.map((item) => item.editId).join(" ") : requestResult.request.editId, "write-failed", `Unhandled Sculpted writeback failure: ${errorMessage(error)}`);
|
|
1709
|
+
result = requestResult.request.kind === "panda-css-batch" ? styleEditBatchFailure(failure) : failure;
|
|
1710
|
+
}
|
|
1541
1711
|
response.statusCode = result.ok ? 200 : 400;
|
|
1542
1712
|
response.setHeader("content-type", "application/json");
|
|
1543
1713
|
response.setHeader("cache-control", "no-store");
|
|
1544
1714
|
response.end(JSON.stringify(result));
|
|
1545
1715
|
if (result.ok && result.written && result.manifestUpdate) {
|
|
1546
1716
|
notifyViteAboutWrittenFiles(server, options.projectRoot, result.manifestUpdate.changedFiles);
|
|
1547
|
-
server
|
|
1717
|
+
sendViteEvent$1(server, SCULPTED_EVENTS.manifestUpdate, result.manifestUpdate);
|
|
1548
1718
|
}
|
|
1549
1719
|
});
|
|
1550
1720
|
server.middlewares.use(DEFAULT_TOKEN_WRITEBACK_ENDPOINT, async (request, response) => {
|
|
@@ -1563,27 +1733,42 @@ function registerWritebackRoutes(server, options) {
|
|
|
1563
1733
|
response.end(JSON.stringify(requestResult.response));
|
|
1564
1734
|
return;
|
|
1565
1735
|
}
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1736
|
+
let result;
|
|
1737
|
+
try {
|
|
1738
|
+
result = await writeTokenConfigPatch({
|
|
1739
|
+
request: requestResult.request,
|
|
1740
|
+
projectRoot: options.projectRoot,
|
|
1741
|
+
pandaConfigPath: options.pandaConfigPath
|
|
1742
|
+
});
|
|
1743
|
+
} catch (error) {
|
|
1744
|
+
logUnexpectedDevServerError("Unhandled Sculpted token writeback failure.", error);
|
|
1745
|
+
result = tokenConfigEditFailure(requestResult.request.editId, "write-failed", `Unhandled Sculpted token writeback failure: ${errorMessage(error)}`);
|
|
1746
|
+
}
|
|
1571
1747
|
response.statusCode = result.ok ? 200 : 400;
|
|
1572
1748
|
response.setHeader("content-type", "application/json");
|
|
1573
1749
|
response.setHeader("cache-control", "no-store");
|
|
1574
1750
|
response.end(JSON.stringify(result));
|
|
1575
1751
|
if (result.ok && result.written && result.metadataUpdate) {
|
|
1576
1752
|
notifyViteAboutWrittenFiles(server, options.projectRoot, result.metadataUpdate.changedFiles);
|
|
1577
|
-
server
|
|
1753
|
+
sendViteEvent$1(server, SCULPTED_EVENTS.metadataUpdate, result.metadataUpdate);
|
|
1578
1754
|
}
|
|
1579
1755
|
});
|
|
1580
1756
|
}
|
|
1757
|
+
function sendViteEvent$1(server, event, payload) {
|
|
1758
|
+
try {
|
|
1759
|
+
server.ws?.send(event, payload);
|
|
1760
|
+
} catch {}
|
|
1761
|
+
}
|
|
1581
1762
|
function notifyViteAboutWrittenFiles(server, projectRoot, changedFiles) {
|
|
1582
1763
|
for (const changedFile of changedFiles) {
|
|
1583
1764
|
const absoluteFile = normalizePath$1(`${projectRoot.replace(/\/$/, "")}/${changedFile}`);
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1765
|
+
try {
|
|
1766
|
+
const modules = server.moduleGraph?.getModulesByFile?.(absoluteFile);
|
|
1767
|
+
if (modules) for (const module of modules) server.moduleGraph?.invalidateModule?.(module);
|
|
1768
|
+
} catch {}
|
|
1769
|
+
try {
|
|
1770
|
+
server.watcher?.emit?.("change", absoluteFile);
|
|
1771
|
+
} catch {}
|
|
1587
1772
|
}
|
|
1588
1773
|
}
|
|
1589
1774
|
async function readStyleEditRequest(request) {
|
|
@@ -1624,44 +1809,87 @@ async function readTokenConfigEditRequest(request) {
|
|
|
1624
1809
|
};
|
|
1625
1810
|
}
|
|
1626
1811
|
}
|
|
1627
|
-
async function readRequestBody(request) {
|
|
1628
|
-
if (!request[Symbol.asyncIterator]) return "";
|
|
1629
|
-
let body = "";
|
|
1630
|
-
for await (const chunk of request) body += typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8");
|
|
1631
|
-
return body;
|
|
1632
|
-
}
|
|
1633
1812
|
function isStyleEditRequest(value) {
|
|
1634
1813
|
if (!isRecord(value)) return false;
|
|
1814
|
+
if (!hasOnlyKeys(value, [
|
|
1815
|
+
"editId",
|
|
1816
|
+
"kind",
|
|
1817
|
+
"edits",
|
|
1818
|
+
"options"
|
|
1819
|
+
])) return false;
|
|
1635
1820
|
if (typeof value.editId !== "string" || value.editId.length === 0) return false;
|
|
1636
1821
|
if (value.kind !== "panda-css") return false;
|
|
1637
1822
|
if (!Array.isArray(value.edits) || value.edits.length === 0) return false;
|
|
1823
|
+
if (!isStyleEditOptions(value.options, true)) return false;
|
|
1638
1824
|
return value.edits.every((edit) => {
|
|
1639
1825
|
if (!isRecord(edit)) return false;
|
|
1640
|
-
if (edit.op === "set") return
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1826
|
+
if (edit.op === "set") return hasOnlyKeys(edit, [
|
|
1827
|
+
"op",
|
|
1828
|
+
"path",
|
|
1829
|
+
"value"
|
|
1830
|
+
]) && isPath(edit.path) && isJsonValue(edit.value);
|
|
1831
|
+
if (edit.op === "delete") return hasOnlyKeys(edit, ["op", "path"]) && isPath(edit.path);
|
|
1832
|
+
if (edit.op === "rename") return hasOnlyKeys(edit, [
|
|
1833
|
+
"op",
|
|
1834
|
+
"from",
|
|
1835
|
+
"to"
|
|
1836
|
+
]) && isPath(edit.from) && isPath(edit.to);
|
|
1837
|
+
if (edit.op === "replace-object") return hasOnlyKeys(edit, ["op", "value"]) && isJsonObject(edit.value);
|
|
1644
1838
|
return false;
|
|
1645
1839
|
});
|
|
1646
1840
|
}
|
|
1647
1841
|
function isStyleEditBatchRequest(value) {
|
|
1648
1842
|
if (!isRecord(value)) return false;
|
|
1843
|
+
if (!hasOnlyKeys(value, [
|
|
1844
|
+
"kind",
|
|
1845
|
+
"requests",
|
|
1846
|
+
"options"
|
|
1847
|
+
])) return false;
|
|
1649
1848
|
if (value.kind !== "panda-css-batch") return false;
|
|
1650
1849
|
if (!Array.isArray(value.requests) || value.requests.length === 0) return false;
|
|
1850
|
+
if (!isStyleEditOptions(value.options, false)) return false;
|
|
1651
1851
|
return value.requests.every(isStyleEditRequest);
|
|
1652
1852
|
}
|
|
1653
1853
|
function isInlineCssSourceCreateRequest(value) {
|
|
1654
1854
|
if (!isRecord(value)) return false;
|
|
1855
|
+
if (!hasOnlyKeys(value, [
|
|
1856
|
+
"editId",
|
|
1857
|
+
"kind",
|
|
1858
|
+
"jsxSource",
|
|
1859
|
+
"edits",
|
|
1860
|
+
"options"
|
|
1861
|
+
])) return false;
|
|
1655
1862
|
if (typeof value.editId !== "string" || value.editId.length === 0) return false;
|
|
1656
1863
|
if (value.kind !== "panda-css-inline-source") return false;
|
|
1657
1864
|
if (typeof value.jsxSource !== "string" || value.jsxSource.length === 0) return false;
|
|
1658
|
-
|
|
1865
|
+
if (value.edits !== void 0) {
|
|
1866
|
+
if (!Array.isArray(value.edits)) return false;
|
|
1867
|
+
if (!value.edits.every((edit) => {
|
|
1868
|
+
if (!isRecord(edit)) return false;
|
|
1869
|
+
if (edit.op === "set") return hasOnlyKeys(edit, [
|
|
1870
|
+
"op",
|
|
1871
|
+
"path",
|
|
1872
|
+
"value"
|
|
1873
|
+
]) && isPath(edit.path) && isJsonValue(edit.value);
|
|
1874
|
+
if (edit.op === "delete") return hasOnlyKeys(edit, ["op", "path"]) && isPath(edit.path);
|
|
1875
|
+
return false;
|
|
1876
|
+
})) return false;
|
|
1877
|
+
}
|
|
1878
|
+
return isStyleEditOptions(value.options, false);
|
|
1659
1879
|
}
|
|
1660
1880
|
function isStyleModuleEditRequest(value) {
|
|
1661
1881
|
return isStyleModuleSourceCreateRequest(value) || isStyleModuleSourceAttachRequest(value) || isStyleModuleSourceDetachRequest(value);
|
|
1662
1882
|
}
|
|
1663
1883
|
function isStyleModuleSourceCreateRequest(value) {
|
|
1664
1884
|
if (!isRecord(value)) return false;
|
|
1885
|
+
if (!hasOnlyKeys(value, [
|
|
1886
|
+
"editId",
|
|
1887
|
+
"kind",
|
|
1888
|
+
"componentSource",
|
|
1889
|
+
"name",
|
|
1890
|
+
"edits",
|
|
1891
|
+
"options"
|
|
1892
|
+
])) return false;
|
|
1665
1893
|
if (typeof value.editId !== "string" || value.editId.length === 0) return false;
|
|
1666
1894
|
if (value.kind !== "panda-css-style-module-source") return false;
|
|
1667
1895
|
if (typeof value.componentSource !== "string" || value.componentSource.length === 0) return false;
|
|
@@ -1670,40 +1898,82 @@ function isStyleModuleSourceCreateRequest(value) {
|
|
|
1670
1898
|
if (!Array.isArray(value.edits)) return false;
|
|
1671
1899
|
if (!value.edits.every((edit) => {
|
|
1672
1900
|
if (!isRecord(edit)) return false;
|
|
1673
|
-
if (edit.op === "set") return
|
|
1674
|
-
|
|
1901
|
+
if (edit.op === "set") return hasOnlyKeys(edit, [
|
|
1902
|
+
"op",
|
|
1903
|
+
"path",
|
|
1904
|
+
"value"
|
|
1905
|
+
]) && isPath(edit.path) && isJsonValue(edit.value);
|
|
1906
|
+
if (edit.op === "delete") return hasOnlyKeys(edit, ["op", "path"]) && isPath(edit.path);
|
|
1675
1907
|
return false;
|
|
1676
1908
|
})) return false;
|
|
1677
1909
|
}
|
|
1678
|
-
return value.options
|
|
1910
|
+
return isStyleEditOptions(value.options, false);
|
|
1679
1911
|
}
|
|
1680
1912
|
function isStyleModuleSourceAttachRequest(value) {
|
|
1681
1913
|
if (!isRecord(value)) return false;
|
|
1914
|
+
if (!hasOnlyKeys(value, [
|
|
1915
|
+
"editId",
|
|
1916
|
+
"kind",
|
|
1917
|
+
"jsxSource",
|
|
1918
|
+
"componentSource",
|
|
1919
|
+
"name",
|
|
1920
|
+
"options"
|
|
1921
|
+
])) return false;
|
|
1682
1922
|
if (typeof value.editId !== "string" || value.editId.length === 0) return false;
|
|
1683
1923
|
if (value.kind !== "panda-css-style-module-attach") return false;
|
|
1684
1924
|
if (typeof value.jsxSource !== "string" || value.jsxSource.length === 0) return false;
|
|
1685
1925
|
if (typeof value.componentSource !== "string" || value.componentSource.length === 0) return false;
|
|
1686
1926
|
if (typeof value.name !== "string" || value.name.length === 0) return false;
|
|
1687
|
-
return value.options
|
|
1927
|
+
return isStyleEditOptions(value.options, false);
|
|
1688
1928
|
}
|
|
1689
1929
|
function isStyleModuleSourceDetachRequest(value) {
|
|
1690
1930
|
if (!isRecord(value)) return false;
|
|
1931
|
+
if (!hasOnlyKeys(value, [
|
|
1932
|
+
"editId",
|
|
1933
|
+
"kind",
|
|
1934
|
+
"jsxSource",
|
|
1935
|
+
"componentSource",
|
|
1936
|
+
"name",
|
|
1937
|
+
"options"
|
|
1938
|
+
])) return false;
|
|
1691
1939
|
if (typeof value.editId !== "string" || value.editId.length === 0) return false;
|
|
1692
1940
|
if (value.kind !== "panda-css-style-module-detach") return false;
|
|
1693
1941
|
if (typeof value.jsxSource !== "string" || value.jsxSource.length === 0) return false;
|
|
1694
1942
|
if (typeof value.componentSource !== "string" || value.componentSource.length === 0) return false;
|
|
1695
1943
|
if (typeof value.name !== "string" || value.name.length === 0) return false;
|
|
1696
|
-
return value.options
|
|
1944
|
+
return isStyleEditOptions(value.options, false);
|
|
1697
1945
|
}
|
|
1698
1946
|
function isTokenConfigEditRequest(value) {
|
|
1699
1947
|
if (!isRecord(value)) return false;
|
|
1948
|
+
if (!hasOnlyKeys(value, [
|
|
1949
|
+
"editId",
|
|
1950
|
+
"kind",
|
|
1951
|
+
"sourceTargetId",
|
|
1952
|
+
"section",
|
|
1953
|
+
"path",
|
|
1954
|
+
"value",
|
|
1955
|
+
"options"
|
|
1956
|
+
])) return false;
|
|
1700
1957
|
if (typeof value.editId !== "string" || value.editId.length === 0) return false;
|
|
1701
1958
|
if (value.kind !== "panda-token-config") return false;
|
|
1702
1959
|
if (typeof value.sourceTargetId !== "string" || value.sourceTargetId.length === 0) return false;
|
|
1703
1960
|
if (value.section !== "tokens.colors" && value.section !== "semanticTokens.colors") return false;
|
|
1704
1961
|
if (!isPath(value.path)) return false;
|
|
1705
1962
|
if (!isJsonPrimitive(value.value)) return false;
|
|
1706
|
-
return value.options
|
|
1963
|
+
return isStyleEditOptions(value.options, true);
|
|
1964
|
+
}
|
|
1965
|
+
function isStyleEditOptions(value, allowExpectedSourceHash) {
|
|
1966
|
+
if (value === void 0) return true;
|
|
1967
|
+
if (!isRecord(value)) return false;
|
|
1968
|
+
for (const key of Object.keys(value)) {
|
|
1969
|
+
if (key === "write" || key === "format") continue;
|
|
1970
|
+
if (key === "expectedSourceHash" && allowExpectedSourceHash) continue;
|
|
1971
|
+
return false;
|
|
1972
|
+
}
|
|
1973
|
+
return (!("write" in value) || typeof value.write === "boolean") && (!("format" in value) || typeof value.format === "boolean") && (!allowExpectedSourceHash || !("expectedSourceHash" in value) || typeof value.expectedSourceHash === "string");
|
|
1974
|
+
}
|
|
1975
|
+
function hasOnlyKeys(value, allowedKeys) {
|
|
1976
|
+
return Object.keys(value).every((key) => allowedKeys.includes(key));
|
|
1707
1977
|
}
|
|
1708
1978
|
function styleEditBatchFailure(response) {
|
|
1709
1979
|
return {
|
|
@@ -1714,14 +1984,17 @@ function styleEditBatchFailure(response) {
|
|
|
1714
1984
|
error: response.error
|
|
1715
1985
|
};
|
|
1716
1986
|
}
|
|
1717
|
-
function
|
|
1718
|
-
|
|
1987
|
+
function isNewInlineSourceEntry(entry, request) {
|
|
1988
|
+
const initialSetPaths = request.edits?.flatMap((edit) => edit.op === "set" && edit.path.length === 1 ? edit.path : []) ?? [];
|
|
1989
|
+
return entry.kind === "panda-css" && (entry.attribute === "class" || entry.attribute === "className") && (initialSetPaths.length === 0 ? Object.keys(entry.styleObject).length === 0 : initialSetPaths.every((path) => path in entry.styleObject));
|
|
1719
1990
|
}
|
|
1720
1991
|
async function writeInlineCssSourcePatch(options) {
|
|
1721
1992
|
const parsed = parseJsxSourceFile(options.request.jsxSource);
|
|
1722
1993
|
if (!parsed.ok) return styleEditFailure(options.request.editId, parsed.code, parsed.message, parsed.details);
|
|
1723
1994
|
const filePath = safeProjectSourcePath(options.projectRoot, parsed.file);
|
|
1724
1995
|
if (!filePath.ok) return styleEditFailure(options.request.editId, filePath.code, filePath.message, filePath.details);
|
|
1996
|
+
const readPath = await verifyWriteTarget(options.projectRoot, filePath.file, options.request.editId);
|
|
1997
|
+
if (readPath) return readPath;
|
|
1725
1998
|
let sourceText;
|
|
1726
1999
|
try {
|
|
1727
2000
|
sourceText = await readFile(filePath.file, "utf8");
|
|
@@ -1744,22 +2017,30 @@ async function writeInlineCssSourcePatch(options) {
|
|
|
1744
2017
|
});
|
|
1745
2018
|
if (!patch.ok || !patch.nextSource) return patch;
|
|
1746
2019
|
if (options.request.options?.write !== true) return patch;
|
|
2020
|
+
let transformedEntries;
|
|
1747
2021
|
try {
|
|
1748
|
-
|
|
2022
|
+
transformedEntries = transformTsxSource({
|
|
2023
|
+
sourceText: patch.nextSource,
|
|
2024
|
+
filePath: filePath.file,
|
|
2025
|
+
projectRoot: options.projectRoot,
|
|
2026
|
+
attributes: options.attributes,
|
|
2027
|
+
cssImportSources: options.cssImportSources,
|
|
2028
|
+
sourceSyntax: options.sourceSyntax
|
|
2029
|
+
}).entries;
|
|
1749
2030
|
} catch (error) {
|
|
1750
|
-
return styleEditFailure(options.request.editId, "write-failed", `Failed to
|
|
2031
|
+
return styleEditFailure(options.request.editId, "write-failed", `Failed to analyze source after inline source creation: ${error instanceof Error ? error.message : String(error)}`);
|
|
1751
2032
|
}
|
|
1752
|
-
const nextEntries =
|
|
1753
|
-
sourceText: patch.nextSource,
|
|
1754
|
-
filePath: filePath.file,
|
|
1755
|
-
projectRoot: options.projectRoot,
|
|
1756
|
-
attributes: options.attributes,
|
|
1757
|
-
cssImportSources: options.cssImportSources,
|
|
1758
|
-
sourceSyntax: options.sourceSyntax
|
|
1759
|
-
}).entries.map((entry) => isNewEmptyInlineSourceEntry(entry) ? {
|
|
2033
|
+
const nextEntries = transformedEntries.map((entry) => isNewInlineSourceEntry(entry, options.request) ? {
|
|
1760
2034
|
...entry,
|
|
1761
2035
|
jsxSourceAliases: Array.from(new Set([...entry.jsxSourceAliases ?? [], options.request.jsxSource]))
|
|
1762
2036
|
} : entry);
|
|
2037
|
+
const writePath = await verifyWriteTarget(options.projectRoot, filePath.file, options.request.editId);
|
|
2038
|
+
if (writePath) return writePath;
|
|
2039
|
+
try {
|
|
2040
|
+
await writeFile(filePath.file, patch.nextSource, "utf8");
|
|
2041
|
+
} catch (error) {
|
|
2042
|
+
return styleEditFailure(options.request.editId, "write-failed", `Failed to write source file: ${error instanceof Error ? error.message : String(error)}`);
|
|
2043
|
+
}
|
|
1763
2044
|
options.onManifestEntries(filePath.file, nextEntries);
|
|
1764
2045
|
const manifestUpdate = {
|
|
1765
2046
|
version: 1,
|
|
@@ -1780,6 +2061,8 @@ async function writeStyleModulePatch(options) {
|
|
|
1780
2061
|
if (!paths.ok) return styleEditFailure(options.request.editId, paths.code, paths.message, paths.details);
|
|
1781
2062
|
const write = options.request.options?.write === true;
|
|
1782
2063
|
if (options.request.kind === "panda-css-style-module-source") {
|
|
2064
|
+
const readPath = await verifyWriteTarget(options.projectRoot, paths.paths.styleFile, options.request.editId);
|
|
2065
|
+
if (readPath) return readPath;
|
|
1783
2066
|
let sourceText;
|
|
1784
2067
|
try {
|
|
1785
2068
|
sourceText = await readFile(paths.paths.styleFile, "utf8");
|
|
@@ -1801,18 +2084,25 @@ async function writeStyleModulePatch(options) {
|
|
|
1801
2084
|
});
|
|
1802
2085
|
if (!patch.ok || !patch.nextSource) return patch;
|
|
1803
2086
|
if (!write) return patch;
|
|
2087
|
+
let nextEntries;
|
|
2088
|
+
try {
|
|
2089
|
+
nextEntries = analyzePandaCssSource({
|
|
2090
|
+
sourceText: patch.nextSource,
|
|
2091
|
+
filePath: paths.paths.styleFile,
|
|
2092
|
+
projectRoot: options.projectRoot,
|
|
2093
|
+
cssImportSources: options.cssImportSources
|
|
2094
|
+
}).entries;
|
|
2095
|
+
} catch (error) {
|
|
2096
|
+
return styleEditFailure(options.request.editId, "write-failed", `Failed to analyze style module after writeback: ${error instanceof Error ? error.message : String(error)}`);
|
|
2097
|
+
}
|
|
2098
|
+
const writePath = await verifyWriteTarget(options.projectRoot, paths.paths.styleFile, options.request.editId);
|
|
2099
|
+
if (writePath) return writePath;
|
|
1804
2100
|
try {
|
|
1805
2101
|
await mkdir(dirname(paths.paths.styleFile), { recursive: true });
|
|
1806
2102
|
await writeFile(paths.paths.styleFile, patch.nextSource, "utf8");
|
|
1807
2103
|
} catch (error) {
|
|
1808
2104
|
return styleEditFailure(options.request.editId, "write-failed", `Failed to write style module: ${error instanceof Error ? error.message : String(error)}`);
|
|
1809
2105
|
}
|
|
1810
|
-
const nextEntries = analyzePandaCssSource({
|
|
1811
|
-
sourceText: patch.nextSource,
|
|
1812
|
-
filePath: paths.paths.styleFile,
|
|
1813
|
-
projectRoot: options.projectRoot,
|
|
1814
|
-
cssImportSources: options.cssImportSources
|
|
1815
|
-
}).entries;
|
|
1816
2106
|
options.onManifestEntries(paths.paths.styleFile, nextEntries);
|
|
1817
2107
|
const manifestUpdate = {
|
|
1818
2108
|
version: 1,
|
|
@@ -1826,12 +2116,16 @@ async function writeStyleModulePatch(options) {
|
|
|
1826
2116
|
};
|
|
1827
2117
|
}
|
|
1828
2118
|
let componentSourceText;
|
|
2119
|
+
const componentReadPath = await verifyWriteTarget(options.projectRoot, paths.paths.componentFile, options.request.editId);
|
|
2120
|
+
if (componentReadPath) return componentReadPath;
|
|
1829
2121
|
try {
|
|
1830
2122
|
componentSourceText = await readFile(paths.paths.componentFile, "utf8");
|
|
1831
2123
|
} catch (error) {
|
|
1832
2124
|
return styleEditFailure(options.request.editId, "write-failed", `Failed to read component module before style attachment: ${error instanceof Error ? error.message : String(error)}`);
|
|
1833
2125
|
}
|
|
1834
2126
|
let styleSourceText;
|
|
2127
|
+
const styleReadPath = await verifyWriteTarget(options.projectRoot, paths.paths.styleFile, options.request.editId);
|
|
2128
|
+
if (styleReadPath) return styleReadPath;
|
|
1835
2129
|
try {
|
|
1836
2130
|
styleSourceText = await readFile(paths.paths.styleFile, "utf8");
|
|
1837
2131
|
} catch (error) {
|
|
@@ -1863,28 +2157,36 @@ async function writeStyleModulePatch(options) {
|
|
|
1863
2157
|
});
|
|
1864
2158
|
if (!patch.ok || !patch.nextSource) return patch;
|
|
1865
2159
|
if (!write) return patch;
|
|
2160
|
+
let componentEntries;
|
|
2161
|
+
let analyzedStyleEntries;
|
|
1866
2162
|
try {
|
|
1867
|
-
|
|
2163
|
+
componentEntries = transformTsxSource({
|
|
2164
|
+
sourceText: patch.nextSource,
|
|
2165
|
+
filePath: paths.paths.componentFile,
|
|
2166
|
+
projectRoot: options.projectRoot,
|
|
2167
|
+
attributes: options.attributes,
|
|
2168
|
+
cssImportSources: options.cssImportSources
|
|
2169
|
+
}).entries;
|
|
2170
|
+
analyzedStyleEntries = analyzePandaCssSource({
|
|
2171
|
+
sourceText: styleSourceText,
|
|
2172
|
+
filePath: paths.paths.styleFile,
|
|
2173
|
+
projectRoot: options.projectRoot,
|
|
2174
|
+
cssImportSources: options.cssImportSources
|
|
2175
|
+
}).entries;
|
|
1868
2176
|
} catch (error) {
|
|
1869
|
-
return styleEditFailure(options.request.editId, "write-failed", `Failed to
|
|
2177
|
+
return styleEditFailure(options.request.editId, "write-failed", `Failed to analyze style-module attachment after writeback: ${error instanceof Error ? error.message : String(error)}`);
|
|
1870
2178
|
}
|
|
1871
|
-
const componentEntries = transformTsxSource({
|
|
1872
|
-
sourceText: patch.nextSource,
|
|
1873
|
-
filePath: paths.paths.componentFile,
|
|
1874
|
-
projectRoot: options.projectRoot,
|
|
1875
|
-
attributes: options.attributes,
|
|
1876
|
-
cssImportSources: options.cssImportSources
|
|
1877
|
-
}).entries;
|
|
1878
|
-
const analyzedStyleEntries = analyzePandaCssSource({
|
|
1879
|
-
sourceText: styleSourceText,
|
|
1880
|
-
filePath: paths.paths.styleFile,
|
|
1881
|
-
projectRoot: options.projectRoot,
|
|
1882
|
-
cssImportSources: options.cssImportSources
|
|
1883
|
-
}).entries;
|
|
1884
2179
|
const styleEntries = styleModuleEntriesWithJsxAlias({
|
|
1885
2180
|
entries: analyzedStyleEntries,
|
|
1886
2181
|
request: options.request
|
|
1887
2182
|
});
|
|
2183
|
+
const writePath = await verifyWriteTarget(options.projectRoot, paths.paths.componentFile, options.request.editId);
|
|
2184
|
+
if (writePath) return writePath;
|
|
2185
|
+
try {
|
|
2186
|
+
await writeFile(paths.paths.componentFile, patch.nextSource, "utf8");
|
|
2187
|
+
} catch (error) {
|
|
2188
|
+
return styleEditFailure(options.request.editId, "write-failed", `Failed to write component module: ${error instanceof Error ? error.message : String(error)}`);
|
|
2189
|
+
}
|
|
1888
2190
|
options.onManifestEntries(paths.paths.componentFile, componentEntries);
|
|
1889
2191
|
options.onManifestEntries(paths.paths.styleFile, styleEntries);
|
|
1890
2192
|
const manifestUpdate = {
|
|
@@ -1918,6 +2220,8 @@ async function writeStaticCssPatch(options) {
|
|
|
1918
2220
|
if (!entry) return styleEditFailure(options.request.editId, "manifest-entry-not-found", "No manifest entry exists for edit id.");
|
|
1919
2221
|
const filePath = trustedManifestFilePath(options.manifest, entry);
|
|
1920
2222
|
if (!filePath.ok) return styleEditFailure(options.request.editId, filePath.code, filePath.message, filePath.details);
|
|
2223
|
+
const readPath = await verifyWriteTarget(options.projectRoot, filePath.file, options.request.editId);
|
|
2224
|
+
if (readPath) return readPath;
|
|
1921
2225
|
let sourceText;
|
|
1922
2226
|
try {
|
|
1923
2227
|
sourceText = await readFile(filePath.file, "utf8");
|
|
@@ -1940,18 +2244,25 @@ async function writeStaticCssPatch(options) {
|
|
|
1940
2244
|
});
|
|
1941
2245
|
if (!patch.ok || !patch.nextSource) return patch;
|
|
1942
2246
|
if (options.request.options?.write !== true) return patch;
|
|
2247
|
+
let nextEntries;
|
|
2248
|
+
try {
|
|
2249
|
+
nextEntries = analyzePandaCssSource({
|
|
2250
|
+
sourceText: patch.nextSource,
|
|
2251
|
+
filePath: filePath.file,
|
|
2252
|
+
projectRoot: options.projectRoot,
|
|
2253
|
+
cssImportSources: options.cssImportSources,
|
|
2254
|
+
sourceSyntax: options.sourceSyntax
|
|
2255
|
+
}).entries;
|
|
2256
|
+
} catch (error) {
|
|
2257
|
+
return styleEditFailure(options.request.editId, "write-failed", `Failed to analyze source after writeback: ${error instanceof Error ? error.message : String(error)}`);
|
|
2258
|
+
}
|
|
2259
|
+
const writePath = await verifyWriteTarget(options.projectRoot, filePath.file, options.request.editId);
|
|
2260
|
+
if (writePath) return writePath;
|
|
1943
2261
|
try {
|
|
1944
2262
|
await writeFile(filePath.file, patch.nextSource, "utf8");
|
|
1945
2263
|
} catch (error) {
|
|
1946
2264
|
return styleEditFailure(options.request.editId, "write-failed", `Failed to write source file: ${error instanceof Error ? error.message : String(error)}`);
|
|
1947
2265
|
}
|
|
1948
|
-
const nextEntries = analyzePandaCssSource({
|
|
1949
|
-
sourceText: patch.nextSource,
|
|
1950
|
-
filePath: filePath.file,
|
|
1951
|
-
projectRoot: options.projectRoot,
|
|
1952
|
-
cssImportSources: options.cssImportSources,
|
|
1953
|
-
sourceSyntax: options.sourceSyntax
|
|
1954
|
-
}).entries;
|
|
1955
2266
|
options.onManifestEntries(filePath.file, nextEntries);
|
|
1956
2267
|
const manifestUpdate = {
|
|
1957
2268
|
version: 1,
|
|
@@ -1983,6 +2294,8 @@ async function writeStaticCssBatchPatch(options) {
|
|
|
1983
2294
|
}
|
|
1984
2295
|
const prepared = [];
|
|
1985
2296
|
for (const group of groups.values()) {
|
|
2297
|
+
const readPath = await verifyWriteTarget(options.projectRoot, group.file, group.requests.map((request) => request.editId).join(" "));
|
|
2298
|
+
if (readPath) return styleEditBatchFailure(readPath);
|
|
1986
2299
|
let sourceText;
|
|
1987
2300
|
try {
|
|
1988
2301
|
sourceText = await readFile(group.file, "utf8");
|
|
@@ -2004,30 +2317,52 @@ async function writeStaticCssBatchPatch(options) {
|
|
|
2004
2317
|
sourceSyntax: options.sourceSyntax
|
|
2005
2318
|
});
|
|
2006
2319
|
if (!patch.ok || !patch.nextSource) return styleEditBatchFailure(patch);
|
|
2320
|
+
let nextEntries;
|
|
2321
|
+
if (write) try {
|
|
2322
|
+
nextEntries = analyzePandaCssSource({
|
|
2323
|
+
sourceText: patch.nextSource,
|
|
2324
|
+
filePath: group.file,
|
|
2325
|
+
projectRoot: options.projectRoot,
|
|
2326
|
+
cssImportSources: options.cssImportSources,
|
|
2327
|
+
sourceSyntax: options.sourceSyntax
|
|
2328
|
+
}).entries;
|
|
2329
|
+
} catch (error) {
|
|
2330
|
+
return styleEditBatchFailure(styleEditFailure(group.requests[0]?.editId ?? "", "write-failed", `Failed to analyze source after batch writeback: ${error instanceof Error ? error.message : String(error)}`));
|
|
2331
|
+
}
|
|
2007
2332
|
prepared.push({
|
|
2008
2333
|
file: group.file,
|
|
2009
2334
|
changedFile: group.changedFile,
|
|
2010
2335
|
requests: group.requests,
|
|
2011
|
-
|
|
2336
|
+
previousSource: sourceText,
|
|
2337
|
+
nextSource: patch.nextSource,
|
|
2338
|
+
nextEntries
|
|
2012
2339
|
});
|
|
2013
2340
|
}
|
|
2014
2341
|
const changedFiles = prepared.map((item) => item.changedFile);
|
|
2015
2342
|
const entryIds = [];
|
|
2016
|
-
if (write)
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2343
|
+
if (write) {
|
|
2344
|
+
const written = [];
|
|
2345
|
+
for (const item of prepared) {
|
|
2346
|
+
const writePath = await verifyWriteTarget(options.projectRoot, item.file, item.requests.map((request) => request.editId).join(" "));
|
|
2347
|
+
if (writePath) return styleEditBatchFailure(writePath);
|
|
2348
|
+
try {
|
|
2349
|
+
await writeFile(item.file, item.nextSource, "utf8");
|
|
2350
|
+
written.push(item);
|
|
2351
|
+
} catch (error) {
|
|
2352
|
+
const rollbackFailures = [];
|
|
2353
|
+
for (const writtenItem of [...written].reverse()) try {
|
|
2354
|
+
await writeFile(writtenItem.file, writtenItem.previousSource, "utf8");
|
|
2355
|
+
} catch (rollbackError) {
|
|
2356
|
+
rollbackFailures.push(`${writtenItem.changedFile}: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
|
|
2357
|
+
}
|
|
2358
|
+
return styleEditBatchFailure(styleEditFailure(item.requests[0]?.editId ?? "", "write-failed", `Failed to write source file: ${error instanceof Error ? error.message : String(error)}`, rollbackFailures.length > 0 ? { rollbackFailures } : void 0));
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
for (const item of prepared) {
|
|
2362
|
+
if (!item.nextEntries) continue;
|
|
2363
|
+
options.onManifestEntries(item.file, item.nextEntries);
|
|
2364
|
+
entryIds.push(...item.nextEntries.map((nextEntry) => nextEntry.id));
|
|
2021
2365
|
}
|
|
2022
|
-
const nextEntries = analyzePandaCssSource({
|
|
2023
|
-
sourceText: item.nextSource,
|
|
2024
|
-
filePath: item.file,
|
|
2025
|
-
projectRoot: options.projectRoot,
|
|
2026
|
-
cssImportSources: options.cssImportSources,
|
|
2027
|
-
sourceSyntax: options.sourceSyntax
|
|
2028
|
-
}).entries;
|
|
2029
|
-
options.onManifestEntries(item.file, nextEntries);
|
|
2030
|
-
entryIds.push(...nextEntries.map((nextEntry) => nextEntry.id));
|
|
2031
2366
|
}
|
|
2032
2367
|
const manifestUpdate = write ? {
|
|
2033
2368
|
version: 1,
|
|
@@ -2060,6 +2395,8 @@ async function writeTokenConfigPatch(options) {
|
|
|
2060
2395
|
if (!tokenSource) return tokenConfigEditFailure(options.request.editId, "manifest-entry-not-found", "No token source exists for source target id.", { sourceTargetId: options.request.sourceTargetId });
|
|
2061
2396
|
const filePath = trustedTokenSourceFilePath(options.projectRoot, tokenSource);
|
|
2062
2397
|
if (!filePath.ok) return tokenConfigEditFailure(options.request.editId, filePath.code, filePath.message, filePath.details);
|
|
2398
|
+
const readPath = await verifyWriteTarget(options.projectRoot, filePath.file, options.request.editId);
|
|
2399
|
+
if (readPath) return tokenConfigEditFailure(options.request.editId, readPath.error?.code ?? "path-outside-project", readPath.error?.message ?? "Token source path resolves outside the project root.");
|
|
2063
2400
|
let sourceText;
|
|
2064
2401
|
try {
|
|
2065
2402
|
sourceText = await readFile(filePath.file, "utf8");
|
|
@@ -2082,19 +2419,27 @@ async function writeTokenConfigPatch(options) {
|
|
|
2082
2419
|
});
|
|
2083
2420
|
if (!patch.ok || !patch.nextSource) return patch;
|
|
2084
2421
|
if (!write) return patch;
|
|
2422
|
+
let nextTokenSourceIds;
|
|
2423
|
+
try {
|
|
2424
|
+
nextTokenSourceIds = tokenSourceIdsForPandaConfigSource({
|
|
2425
|
+
projectRoot: options.projectRoot,
|
|
2426
|
+
filePath: filePath.file,
|
|
2427
|
+
sourceText: patch.nextSource
|
|
2428
|
+
});
|
|
2429
|
+
} catch (error) {
|
|
2430
|
+
return tokenConfigEditFailure(options.request.editId, "write-failed", `Failed to prepare editor metadata for token writeback: ${error instanceof Error ? error.message : String(error)}`);
|
|
2431
|
+
}
|
|
2432
|
+
const writePath = await verifyWriteTarget(options.projectRoot, filePath.file, options.request.editId);
|
|
2433
|
+
if (writePath) return writePath;
|
|
2085
2434
|
try {
|
|
2086
2435
|
await writeFile(filePath.file, patch.nextSource, "utf8");
|
|
2087
2436
|
} catch (error) {
|
|
2088
2437
|
return tokenConfigEditFailure(options.request.editId, "write-failed", `Failed to write Panda config: ${error instanceof Error ? error.message : String(error)}`);
|
|
2089
2438
|
}
|
|
2090
|
-
const nextMetadata = await createEditorMetadata({
|
|
2091
|
-
projectRoot: options.projectRoot,
|
|
2092
|
-
pandaConfigPath: options.pandaConfigPath
|
|
2093
|
-
});
|
|
2094
2439
|
const metadataUpdate = {
|
|
2095
2440
|
version: 1,
|
|
2096
2441
|
changedFiles: [toRelativeProjectPath$1(filePath.file, options.projectRoot)],
|
|
2097
|
-
tokenSourceIds:
|
|
2442
|
+
tokenSourceIds: nextTokenSourceIds
|
|
2098
2443
|
};
|
|
2099
2444
|
return {
|
|
2100
2445
|
...patch,
|
|
@@ -2111,6 +2456,11 @@ async function inferStyledSystemPackageName(projectRoot) {
|
|
|
2111
2456
|
return;
|
|
2112
2457
|
}
|
|
2113
2458
|
}
|
|
2459
|
+
async function verifyWriteTarget(projectRoot, filePath, editId) {
|
|
2460
|
+
const verified = await verifyProjectWritePath(projectRoot, filePath);
|
|
2461
|
+
if (verified.ok) return void 0;
|
|
2462
|
+
return styleEditFailure(editId, verified.code, verified.message, verified.details);
|
|
2463
|
+
}
|
|
2114
2464
|
function styleEditFailure(editId, code, message, details) {
|
|
2115
2465
|
return {
|
|
2116
2466
|
ok: false,
|
|
@@ -2160,21 +2510,17 @@ function isPath(value) {
|
|
|
2160
2510
|
}
|
|
2161
2511
|
function isJsonValue(value) {
|
|
2162
2512
|
if (value === null) return true;
|
|
2163
|
-
if (
|
|
2164
|
-
|
|
2165
|
-
"number",
|
|
2166
|
-
"boolean"
|
|
2167
|
-
].includes(typeof value)) return true;
|
|
2513
|
+
if (typeof value === "string" || typeof value === "boolean") return true;
|
|
2514
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
2168
2515
|
if (Array.isArray(value)) return value.every(isJsonValue);
|
|
2169
2516
|
if (!isRecord(value)) return false;
|
|
2170
2517
|
return Object.values(value).every(isJsonValue);
|
|
2171
2518
|
}
|
|
2172
2519
|
function isJsonPrimitive(value) {
|
|
2173
|
-
return value === null ||
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
].includes(typeof value);
|
|
2520
|
+
return value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);
|
|
2521
|
+
}
|
|
2522
|
+
function isJsonObject(value) {
|
|
2523
|
+
return isRecord(value) && Object.values(value).every(isJsonValue);
|
|
2178
2524
|
}
|
|
2179
2525
|
//#endregion
|
|
2180
2526
|
//#region src/vite.ts
|
|
@@ -2217,10 +2563,20 @@ function sculpted(options = {}) {
|
|
|
2217
2563
|
response.end(JSON.stringify(manifest()));
|
|
2218
2564
|
});
|
|
2219
2565
|
nextServer.middlewares.use(editorMetadataEndpoint, async (_request, response) => {
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2566
|
+
let metadata;
|
|
2567
|
+
try {
|
|
2568
|
+
metadata = await createEditorMetadata({
|
|
2569
|
+
projectRoot,
|
|
2570
|
+
pandaConfigPath: options.panda?.configPath
|
|
2571
|
+
});
|
|
2572
|
+
} catch (error) {
|
|
2573
|
+
logUnexpectedDevServerError("Failed to create Sculpted editor metadata.", error);
|
|
2574
|
+
response.statusCode = 500;
|
|
2575
|
+
response.setHeader("content-type", "text/plain");
|
|
2576
|
+
response.setHeader("cache-control", "no-store");
|
|
2577
|
+
response.end(`Failed to create Sculpted editor metadata: ${errorMessage(error)}`);
|
|
2578
|
+
return;
|
|
2579
|
+
}
|
|
2224
2580
|
response.statusCode = 200;
|
|
2225
2581
|
response.setHeader("content-type", "application/json");
|
|
2226
2582
|
response.setHeader("cache-control", "no-store");
|
|
@@ -2242,11 +2598,17 @@ function sculpted(options = {}) {
|
|
|
2242
2598
|
response.end(JSON.stringify(requestResult.response));
|
|
2243
2599
|
return;
|
|
2244
2600
|
}
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2601
|
+
let result;
|
|
2602
|
+
try {
|
|
2603
|
+
result = await resolveOpenSourceLocation({
|
|
2604
|
+
request: requestResult.request,
|
|
2605
|
+
manifest: manifest(),
|
|
2606
|
+
projectRoot
|
|
2607
|
+
});
|
|
2608
|
+
} catch (error) {
|
|
2609
|
+
logUnexpectedDevServerError("Unhandled Sculpted source-open failure.", error);
|
|
2610
|
+
result = openSourceLocationFailure("open-failed", `Unhandled Sculpted source-open failure: ${errorMessage(error)}`);
|
|
2611
|
+
}
|
|
2250
2612
|
response.statusCode = result.ok ? 200 : 400;
|
|
2251
2613
|
response.setHeader("content-type", "application/json");
|
|
2252
2614
|
response.setHeader("cache-control", "no-store");
|
|
@@ -2303,7 +2665,7 @@ function sculpted(options = {}) {
|
|
|
2303
2665
|
sourceSyntax: options.sourceSyntax
|
|
2304
2666
|
});
|
|
2305
2667
|
manifestByFile.set(filePath, result.entries);
|
|
2306
|
-
if (result.entries.length > 0) server
|
|
2668
|
+
if (result.entries.length > 0) sendViteEvent(server, SCULPTED_EVENTS.manifestUpdate, {
|
|
2307
2669
|
version: 1,
|
|
2308
2670
|
changedFiles: [toRelativeProjectPath$1(filePath, projectRoot)],
|
|
2309
2671
|
entryIds: result.entries.map((entry) => entry.id)
|
|
@@ -2316,5 +2678,10 @@ function sculpted(options = {}) {
|
|
|
2316
2678
|
}
|
|
2317
2679
|
};
|
|
2318
2680
|
}
|
|
2681
|
+
function sendViteEvent(server, event, payload) {
|
|
2682
|
+
try {
|
|
2683
|
+
server?.ws?.send(event, payload);
|
|
2684
|
+
} catch {}
|
|
2685
|
+
}
|
|
2319
2686
|
//#endregion
|
|
2320
2687
|
export { sculpted };
|