sculpted 0.0.0 → 0.1.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.
Files changed (31) hide show
  1. package/LICENSE +105 -0
  2. package/README.md +233 -0
  3. package/dist/index.d.mts +129 -0
  4. package/dist/index.mjs +3 -0
  5. package/dist/patcher-BAw2kF1Q.mjs +2594 -0
  6. package/dist/protocol-BJm-xGHP.mjs +54 -0
  7. package/dist/runtime-DwE3PVhB.d.mts +64 -0
  8. package/dist/runtime.d.mts +2 -0
  9. package/dist/runtime.mjs +613 -0
  10. package/dist/sourceSyntax-DanNzS7Y.d.mts +103 -0
  11. package/dist/types-CdByW0ji.d.mts +381 -0
  12. package/dist/ui.d.mts +54 -0
  13. package/dist/ui.mjs +11125 -0
  14. package/dist/vite.d.mts +85 -0
  15. package/dist/vite.mjs +2325 -0
  16. package/examples/manual-vite-preact-pandacss/README.md +75 -0
  17. package/examples/manual-vite-preact-pandacss/index.html +12 -0
  18. package/examples/manual-vite-preact-pandacss/package.json +23 -0
  19. package/examples/manual-vite-preact-pandacss/panda.config.ts +43 -0
  20. package/examples/manual-vite-preact-pandacss/pnpm-lock.yaml +3359 -0
  21. package/examples/manual-vite-preact-pandacss/pnpm-workspace.yaml +2 -0
  22. package/examples/manual-vite-preact-pandacss/postcss.config.cjs +5 -0
  23. package/examples/manual-vite-preact-pandacss/src/TsrxManualPanel.tsrx +47 -0
  24. package/examples/manual-vite-preact-pandacss/src/index.css +8 -0
  25. package/examples/manual-vite-preact-pandacss/src/main.style.ts +33 -0
  26. package/examples/manual-vite-preact-pandacss/src/main.tsx +484 -0
  27. package/examples/manual-vite-preact-pandacss/src/tsrx.d.ts +5 -0
  28. package/examples/manual-vite-preact-pandacss/tsconfig.json +21 -0
  29. package/examples/manual-vite-preact-pandacss/vite.config.ts +20 -0
  30. package/package.json +66 -8
  31. package/readme.md +0 -1
@@ -0,0 +1,2594 @@
1
+ import "./protocol-BJm-xGHP.mjs";
2
+ import { parseModule } from "@tsrx/core";
3
+ import ts from "typescript";
4
+ import { resolve } from "node:path";
5
+ //#region src/sourceSyntax.ts
6
+ function parseWithSourceParserAdapter(adapter, options) {
7
+ return resolveSourceParserAdapter(options.filePath, adapter).parse(options);
8
+ }
9
+ function parsePandaSource(adapter, options) {
10
+ const parsed = parseWithSourceParserAdapter(adapter, options);
11
+ if (parsed.kind === "typescript") return {
12
+ astKind: "typescript",
13
+ languageId: parsed.languageId,
14
+ filePath: options.filePath,
15
+ sourceText: options.sourceText,
16
+ root: parsed.sourceFile,
17
+ ops: typescriptPandaAstAdapter
18
+ };
19
+ const ops = createEstreePandaAstAdapter(parsed.program);
20
+ return {
21
+ astKind: "estree",
22
+ languageId: parsed.languageId,
23
+ filePath: options.filePath,
24
+ sourceText: options.sourceText,
25
+ root: parsed.program,
26
+ ops
27
+ };
28
+ }
29
+ function resolveSourceParserAdapter(filePath, adapter) {
30
+ return [tsxSourceParserAdapter, ...Array.isArray(adapter) ? adapter : adapter ? [adapter] : []].find((item) => item.isSupportedFile(filePath)) ?? tsxSourceParserAdapter;
31
+ }
32
+ const tsxSourceParserAdapter = {
33
+ languageId: "tsx",
34
+ kind: "typescript",
35
+ isSupportedFile(filePath) {
36
+ return /\.(?:[cm]?tsx?|[cm]?jsx)$/.test(filePath);
37
+ },
38
+ parse(options) {
39
+ return {
40
+ kind: "typescript",
41
+ languageId: "tsx",
42
+ sourceFile: ts.createSourceFile(options.filePath, options.sourceText, ts.ScriptTarget.Latest, true, scriptKindForFile(options.filePath))
43
+ };
44
+ }
45
+ };
46
+ const tsxSourceSyntaxAdapter = tsxSourceParserAdapter;
47
+ const tsrxSourceParserAdapter = {
48
+ languageId: "tsrx",
49
+ kind: "estree",
50
+ isSupportedFile(filePath) {
51
+ return filePath.endsWith(".tsrx");
52
+ },
53
+ parse(options) {
54
+ const comments = [];
55
+ return {
56
+ kind: "estree",
57
+ languageId: "tsrx",
58
+ program: parseModule(options.sourceText, options.filePath, {
59
+ collect: true,
60
+ comments
61
+ }),
62
+ comments
63
+ };
64
+ }
65
+ };
66
+ function scriptKindForFile(filePath) {
67
+ if (/\.[cm]?tsx$/.test(filePath)) return ts.ScriptKind.TSX;
68
+ if (/\.[cm]?jsx$/.test(filePath)) return ts.ScriptKind.JSX;
69
+ return ts.ScriptKind.TS;
70
+ }
71
+ const typescriptPandaAstAdapter = {
72
+ astKind: "typescript",
73
+ walk(root, visit) {
74
+ const walkNode = (node, parent) => {
75
+ visit(node, parent);
76
+ ts.forEachChild(node, (child) => walkNode(child, node));
77
+ };
78
+ walkNode(root, void 0);
79
+ },
80
+ topLevelStatements(root) {
81
+ return [...root.statements];
82
+ },
83
+ isImportDeclaration(node) {
84
+ return ts.isImportDeclaration(node);
85
+ },
86
+ getImportSource(node) {
87
+ return ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier) ? node.moduleSpecifier.text : void 0;
88
+ },
89
+ getNamedImportBindings(node) {
90
+ if (!ts.isImportDeclaration(node)) return [];
91
+ const namedBindings = node.importClause?.namedBindings;
92
+ if (!namedBindings || !ts.isNamedImports(namedBindings)) return [];
93
+ return namedBindings.elements.map((element) => ({
94
+ imported: element.propertyName?.text ?? element.name.text,
95
+ local: element.name.text
96
+ }));
97
+ },
98
+ isCallExpression(node) {
99
+ return ts.isCallExpression(node);
100
+ },
101
+ getCallCalleeIdentifier(node) {
102
+ return ts.isCallExpression(node) && ts.isIdentifier(node.expression) ? node.expression.text : void 0;
103
+ },
104
+ getCallArguments(node) {
105
+ return ts.isCallExpression(node) ? [...node.arguments] : [];
106
+ },
107
+ isObjectExpression(node) {
108
+ return ts.isObjectLiteralExpression(node);
109
+ },
110
+ getObjectProperties(node) {
111
+ return ts.isObjectLiteralExpression(node) ? [...node.properties] : [];
112
+ },
113
+ isPlainProperty(node) {
114
+ return ts.isPropertyAssignment(node);
115
+ },
116
+ isSpreadProperty(node) {
117
+ return ts.isSpreadAssignment(node);
118
+ },
119
+ getPropertyName(node) {
120
+ if (!ts.isPropertyAssignment(node)) return void 0;
121
+ const name = node.name;
122
+ if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) return name.text;
123
+ },
124
+ getPropertyValue(node) {
125
+ return ts.isPropertyAssignment(node) ? node.initializer : void 0;
126
+ },
127
+ getLiteralValue(node) {
128
+ if (!ts.isExpression(node)) return void 0;
129
+ return literalJsonValue(node);
130
+ },
131
+ isIdentifier(node) {
132
+ return ts.isIdentifier(node);
133
+ },
134
+ getRange(node) {
135
+ return {
136
+ start: node.getStart(),
137
+ end: node.getEnd()
138
+ };
139
+ },
140
+ getLocation(node) {
141
+ const sourceFile = node.getSourceFile();
142
+ const start = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
143
+ const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
144
+ return {
145
+ start: {
146
+ line: start.line + 1,
147
+ column: start.character + 1
148
+ },
149
+ end: {
150
+ line: end.line + 1,
151
+ column: end.character + 1
152
+ }
153
+ };
154
+ },
155
+ findObjectExpressionAtRange(root, range) {
156
+ let result;
157
+ this.walk(root, (node) => {
158
+ if (result === void 0 && ts.isObjectLiteralExpression(node) && node.getStart(root) === range.start && node.getEnd() === range.end) result = node;
159
+ });
160
+ return result;
161
+ },
162
+ getParent(_root, node) {
163
+ return node.parent;
164
+ },
165
+ nodeContains(root, target) {
166
+ let found = false;
167
+ const visit = (node) => {
168
+ if (found) return;
169
+ if (node === target) {
170
+ found = true;
171
+ return;
172
+ }
173
+ ts.forEachChild(node, visit);
174
+ };
175
+ visit(root);
176
+ return found;
177
+ },
178
+ getVariableDeclaratorName(node) {
179
+ if (!ts.isVariableDeclaration(node)) return void 0;
180
+ return ts.isIdentifier(node.name) ? node.name.text : void 0;
181
+ },
182
+ getVariableDeclaratorInitializer(node) {
183
+ return ts.isVariableDeclaration(node) ? node.initializer : void 0;
184
+ },
185
+ isVariableDeclaratorInitializer(node, child) {
186
+ return ts.isVariableDeclaration(node) && node.initializer === child;
187
+ },
188
+ getPropertyOwnerName(node) {
189
+ return ts.isPropertyAssignment(node) ? this.getPropertyName(node) : void 0;
190
+ },
191
+ isPropertyValue(node, child) {
192
+ return ts.isPropertyAssignment(node) && node.initializer === child;
193
+ },
194
+ isJsxBoundary(node) {
195
+ return ts.isJsxExpression(node) || ts.isJsxAttribute(node);
196
+ },
197
+ firstImportEnd(root) {
198
+ let position = 0;
199
+ for (const statement of root.statements) {
200
+ if (!ts.isImportDeclaration(statement)) break;
201
+ position = statement.getEnd();
202
+ }
203
+ return position;
204
+ },
205
+ isPatchableLiteral(node) {
206
+ return ts.isExpression(node) && literalJsonValue(node) !== void 0;
207
+ }
208
+ };
209
+ function literalJsonValue(node) {
210
+ if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
211
+ if (ts.isNumericLiteral(node)) return Number(node.text);
212
+ if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(node.operand)) return -Number(node.operand.text);
213
+ if (node.kind === ts.SyntaxKind.TrueKeyword) return true;
214
+ if (node.kind === ts.SyntaxKind.FalseKeyword) return false;
215
+ if (node.kind === ts.SyntaxKind.NullKeyword) return null;
216
+ }
217
+ function createEstreePandaAstAdapter(root) {
218
+ const parents = /* @__PURE__ */ new Map();
219
+ const childrenOf = (node) => {
220
+ const children = [];
221
+ for (const [key, value] of Object.entries(node)) {
222
+ if (key === "loc" || key === "metadata" || key === "comments" || key === "leadingComments" || key === "trailingComments") continue;
223
+ if (isEstreeNode(value)) children.push(value);
224
+ else if (Array.isArray(value)) {
225
+ for (const item of value) if (isEstreeNode(item)) children.push(item);
226
+ }
227
+ }
228
+ return children;
229
+ };
230
+ const walkedForParents = /* @__PURE__ */ new Set();
231
+ const walkNode = (node, parent) => {
232
+ if (walkedForParents.has(node)) return;
233
+ walkedForParents.add(node);
234
+ parents.set(node, parent);
235
+ for (const child of childrenOf(node)) walkNode(child, node);
236
+ };
237
+ walkNode(root, void 0);
238
+ return {
239
+ astKind: "estree",
240
+ walk(nextRoot, visit) {
241
+ const seen = /* @__PURE__ */ new Set();
242
+ const visitNode = (node, parent) => {
243
+ if (seen.has(node)) return;
244
+ seen.add(node);
245
+ visit(node, parent);
246
+ for (const child of childrenOf(node)) visitNode(child, node);
247
+ };
248
+ visitNode(nextRoot, void 0);
249
+ },
250
+ topLevelStatements(nextRoot) {
251
+ return Array.isArray(nextRoot.body) ? nextRoot.body.filter(isEstreeNode) : [];
252
+ },
253
+ isImportDeclaration(node) {
254
+ return node.type === "ImportDeclaration";
255
+ },
256
+ getImportSource(node) {
257
+ if (node.type !== "ImportDeclaration") return void 0;
258
+ const source = node.source;
259
+ return isEstreeNode(source) && typeof source.value === "string" ? source.value : void 0;
260
+ },
261
+ getNamedImportBindings(node) {
262
+ if (node.type !== "ImportDeclaration" || !Array.isArray(node.specifiers)) return [];
263
+ return node.specifiers.filter(isEstreeNode).flatMap((specifier) => {
264
+ if (specifier.type !== "ImportSpecifier") return [];
265
+ const imported = specifier.imported;
266
+ const local = specifier.local;
267
+ if (!isEstreeNode(imported) || !isEstreeNode(local)) return [];
268
+ const importedName = identifierOrLiteralName(imported);
269
+ const localName = identifierOrLiteralName(local);
270
+ return importedName && localName ? [{
271
+ imported: importedName,
272
+ local: localName
273
+ }] : [];
274
+ });
275
+ },
276
+ isCallExpression(node) {
277
+ return node.type === "CallExpression";
278
+ },
279
+ getCallCalleeIdentifier(node) {
280
+ if (node.type !== "CallExpression" || !isEstreeNode(node.callee)) return void 0;
281
+ return node.callee.type === "Identifier" && typeof node.callee.name === "string" ? node.callee.name : void 0;
282
+ },
283
+ getCallArguments(node) {
284
+ return node.type === "CallExpression" && Array.isArray(node.arguments) ? node.arguments.filter(isEstreeNode) : [];
285
+ },
286
+ isObjectExpression(node) {
287
+ return node.type === "ObjectExpression";
288
+ },
289
+ getObjectProperties(node) {
290
+ return node.type === "ObjectExpression" && Array.isArray(node.properties) ? node.properties.filter(isEstreeNode) : [];
291
+ },
292
+ isPlainProperty(node) {
293
+ return node.type === "Property" && node.kind === "init" && node.method !== true;
294
+ },
295
+ isSpreadProperty(node) {
296
+ return node.type === "SpreadElement" || node.type === "SpreadProperty";
297
+ },
298
+ getPropertyName(node) {
299
+ if (node.type !== "Property" || node.computed === true || !isEstreeNode(node.key)) return;
300
+ return identifierOrLiteralName(node.key);
301
+ },
302
+ getPropertyValue(node) {
303
+ return node.type === "Property" && isEstreeNode(node.value) ? node.value : void 0;
304
+ },
305
+ getLiteralValue(node) {
306
+ if (node.type === "Literal") return isJsonLiteral(node.value) ? node.value : void 0;
307
+ if (node.type === "UnaryExpression" && node.operator === "-" && isEstreeNode(node.argument) && node.argument.type === "Literal" && typeof node.argument.value === "number") return -node.argument.value;
308
+ },
309
+ isIdentifier(node) {
310
+ return node.type === "Identifier";
311
+ },
312
+ getRange(node) {
313
+ return {
314
+ start: numericPosition(node.start),
315
+ end: numericPosition(node.end)
316
+ };
317
+ },
318
+ getLocation(node) {
319
+ const loc = node.loc;
320
+ if (!loc) return {
321
+ start: {
322
+ line: 1,
323
+ column: 1
324
+ },
325
+ end: {
326
+ line: 1,
327
+ column: 1
328
+ }
329
+ };
330
+ return {
331
+ start: {
332
+ line: loc.start.line,
333
+ column: loc.start.column + 1
334
+ },
335
+ end: {
336
+ line: loc.end.line,
337
+ column: loc.end.column + 1
338
+ }
339
+ };
340
+ },
341
+ findObjectExpressionAtRange(nextRoot, range) {
342
+ let result;
343
+ this.walk(nextRoot, (node) => {
344
+ if (result === void 0 && node.type === "ObjectExpression" && numericPosition(node.start) === range.start && numericPosition(node.end) === range.end) result = node;
345
+ });
346
+ return result;
347
+ },
348
+ getParent(_root, node) {
349
+ return parents.get(node);
350
+ },
351
+ nodeContains(nextRoot, target) {
352
+ let found = false;
353
+ this.walk(nextRoot, (node) => {
354
+ if (node === target) found = true;
355
+ });
356
+ return found;
357
+ },
358
+ getVariableDeclaratorName(node) {
359
+ if (node.type !== "VariableDeclarator" || !isEstreeNode(node.id)) return void 0;
360
+ return node.id.type === "Identifier" && typeof node.id.name === "string" ? node.id.name : void 0;
361
+ },
362
+ getVariableDeclaratorInitializer(node) {
363
+ return node.type === "VariableDeclarator" && isEstreeNode(node.init) ? node.init : void 0;
364
+ },
365
+ isVariableDeclaratorInitializer(node, child) {
366
+ return node.type === "VariableDeclarator" && node.init === child;
367
+ },
368
+ getPropertyOwnerName(node) {
369
+ return node.type === "Property" ? this.getPropertyName(node) : void 0;
370
+ },
371
+ isPropertyValue(node, child) {
372
+ return node.type === "Property" && node.value === child;
373
+ },
374
+ isJsxBoundary(node) {
375
+ return node.type === "JSXExpressionContainer" || node.type === "Attribute";
376
+ },
377
+ firstImportEnd(nextRoot) {
378
+ let position = 0;
379
+ for (const statement of this.topLevelStatements(nextRoot)) {
380
+ if (statement.type !== "ImportDeclaration") break;
381
+ position = numericPosition(statement.end);
382
+ }
383
+ return position;
384
+ },
385
+ isPatchableLiteral(node) {
386
+ return this.getLiteralValue(node) !== void 0;
387
+ }
388
+ };
389
+ }
390
+ function isEstreeNode(value) {
391
+ return typeof value === "object" && value !== null && typeof value.type === "string";
392
+ }
393
+ function identifierOrLiteralName(node) {
394
+ if (node.type === "Identifier" && typeof node.name === "string") return node.name;
395
+ if (node.type === "Literal") {
396
+ if (typeof node.value === "string") return node.value;
397
+ if (typeof node.value === "number") return String(node.value);
398
+ }
399
+ }
400
+ function isJsonLiteral(value) {
401
+ return value === null || [
402
+ "string",
403
+ "number",
404
+ "boolean"
405
+ ].includes(typeof value);
406
+ }
407
+ function numericPosition(value) {
408
+ return typeof value === "number" ? value : 0;
409
+ }
410
+ //#endregion
411
+ //#region src/analyzer/pandaCssAnalyzer.ts
412
+ const DEFAULT_CSS_IMPORT_SOURCES$1 = [
413
+ "../styled-system/css",
414
+ "@/styled-system/css",
415
+ "styled-system/css"
416
+ ];
417
+ function analyzePandaCssSource(options) {
418
+ const source = parsePandaSource(options.sourceSyntax, {
419
+ filePath: options.filePath,
420
+ sourceText: options.sourceText
421
+ });
422
+ const cssImportSources = new Set(options.cssImportSources ?? DEFAULT_CSS_IMPORT_SOURCES$1);
423
+ const cssNames = /* @__PURE__ */ new Set();
424
+ for (const statement of source.ops.topLevelStatements(source.root)) {
425
+ if (!source.ops.isImportDeclaration(statement)) continue;
426
+ const importSource = source.ops.getImportSource(statement);
427
+ if (!importSource || !cssImportSources.has(importSource)) continue;
428
+ for (const binding of source.ops.getNamedImportBindings(statement)) if (binding.imported === "css") cssNames.add(binding.local);
429
+ }
430
+ if (cssNames.size === 0) return { entries: [] };
431
+ const entries = [];
432
+ let ordinal = 0;
433
+ source.ops.walk(source.root, (node) => {
434
+ const callee = source.ops.getCallCalleeIdentifier(node);
435
+ if (source.ops.isCallExpression(node) && callee && cssNames.has(callee)) entries.push(createEntry(source, options, node, ordinal++));
436
+ });
437
+ return { entries };
438
+ }
439
+ function createEntry(source, options, call, ordinal) {
440
+ const file = toRelativeProjectPath$1(options.filePath, options.projectRoot);
441
+ const callStart = source.ops.getRange(call).start;
442
+ const callPosition = positionAt(source.sourceText, callStart);
443
+ const id = `${file}:${callPosition.line}:${callPosition.column}#${ordinal}`;
444
+ const firstArg = source.ops.getCallArguments(call)[0];
445
+ if (!firstArg) return unsupportedEntry(source, options, call, id, "unsupported-source-shape", "css() has no style object");
446
+ if (!source.ops.isObjectExpression(firstArg)) return unsupportedEntry(source, options, call, id, source.ops.isIdentifier(firstArg) ? "variable-reference" : "dynamic-expression", "css() argument is not a local object literal");
447
+ const extracted = extractStyleObject(source, firstArg);
448
+ if (!extracted.ok) return unsupportedEntry(source, options, call, id, extracted.reason, extracted.description);
449
+ const range = source.ops.getRange(firstArg);
450
+ const name = cssSourceName(source, call);
451
+ return {
452
+ protocolVersion: 1,
453
+ id,
454
+ kind: "panda-css",
455
+ file,
456
+ absoluteFile: normalizePath$5(options.filePath),
457
+ range,
458
+ loc: source.ops.getLocation(firstArg),
459
+ sourceHash: hashSource(options.sourceText.slice(range.start, range.end)),
460
+ ...name ? { name } : {},
461
+ confidence: "high",
462
+ reason: "static local css() object literal",
463
+ callee: source.ops.getCallCalleeIdentifier(call) ?? "css",
464
+ styleObject: extracted.styleObject,
465
+ dynamic: false
466
+ };
467
+ }
468
+ function cssSourceName(source, call) {
469
+ let current = call;
470
+ while (true) {
471
+ const parent = source.ops.getParent(source.root, current);
472
+ if (!parent) return void 0;
473
+ if (source.ops.isJsxBoundary(parent)) return;
474
+ if (source.ops.isPropertyValue(parent, current)) return source.ops.getPropertyOwnerName(parent);
475
+ if (source.ops.isVariableDeclaratorInitializer(parent, current)) return source.ops.getVariableDeclaratorName(parent);
476
+ const propertyName = source.ops.getPropertyOwnerName(parent);
477
+ const propertyValue = source.ops.getPropertyValue(parent);
478
+ if (propertyName && propertyValue && source.ops.nodeContains(propertyValue, call)) return propertyName;
479
+ const variableName = source.ops.getVariableDeclaratorName(parent);
480
+ const initializer = source.ops.getVariableDeclaratorInitializer(parent);
481
+ if (variableName && initializer && source.ops.nodeContains(initializer, call)) return variableName;
482
+ current = parent;
483
+ }
484
+ }
485
+ function unsupportedEntry(source, options, call, id, reason, description) {
486
+ const file = toRelativeProjectPath$1(options.filePath, options.projectRoot);
487
+ const range = source.ops.getRange(call);
488
+ return {
489
+ protocolVersion: 1,
490
+ id,
491
+ kind: "dynamic",
492
+ file,
493
+ absoluteFile: normalizePath$5(options.filePath),
494
+ range,
495
+ loc: source.ops.getLocation(call),
496
+ sourceHash: hashSource(options.sourceText.slice(range.start, range.end)),
497
+ confidence: "low",
498
+ reason: description,
499
+ dynamic: true,
500
+ unsupportedReason: reason
501
+ };
502
+ }
503
+ function extractStyleObject(source, objectNode) {
504
+ const styleObject = {};
505
+ for (const property of source.ops.getObjectProperties(objectNode)) {
506
+ if (source.ops.isSpreadProperty(property)) return {
507
+ ok: false,
508
+ reason: "spread-value",
509
+ description: "Object spread can change which style keys exist at runtime"
510
+ };
511
+ if (!source.ops.isPlainProperty(property)) return {
512
+ ok: false,
513
+ reason: "unsupported-source-shape",
514
+ description: "Only plain property assignments are supported in css() objects"
515
+ };
516
+ const name = source.ops.getPropertyName(property);
517
+ if (name === void 0) return {
518
+ ok: false,
519
+ reason: "unsupported-source-shape",
520
+ description: "Computed style property names are not safe to map to source paths"
521
+ };
522
+ const propertyValue = source.ops.getPropertyValue(property);
523
+ if (!propertyValue) return {
524
+ ok: false,
525
+ reason: "unsupported-source-shape",
526
+ description: "Style property has no value that can be patched"
527
+ };
528
+ const value = extractStyleValue(source, propertyValue);
529
+ if (!value.ok) return value;
530
+ styleObject[name] = value.value;
531
+ }
532
+ return {
533
+ ok: true,
534
+ styleObject
535
+ };
536
+ }
537
+ function extractStyleValue(source, node) {
538
+ if (source.ops.isObjectExpression(node)) {
539
+ const object = extractStyleObject(source, node);
540
+ if (!object.ok) return object;
541
+ return {
542
+ ok: true,
543
+ value: object.styleObject
544
+ };
545
+ }
546
+ const literal = source.ops.getLiteralValue(node);
547
+ if (literal !== void 0) return {
548
+ ok: true,
549
+ value: {
550
+ kind: "literal",
551
+ value: literal,
552
+ range: source.ops.getRange(node),
553
+ loc: source.ops.getLocation(node)
554
+ }
555
+ };
556
+ return {
557
+ ok: false,
558
+ reason: source.ops.isIdentifier(node) ? "variable-reference" : "dynamic-expression",
559
+ description: "Style value is not a literal that can be patched without evaluating user code"
560
+ };
561
+ }
562
+ function positionAt(sourceText, position) {
563
+ let line = 1;
564
+ let lineStart = 0;
565
+ for (let index = 0; index < position; index += 1) if (sourceText.charCodeAt(index) === 10) {
566
+ line += 1;
567
+ lineStart = index + 1;
568
+ }
569
+ return {
570
+ line,
571
+ column: position - lineStart + 1
572
+ };
573
+ }
574
+ function toRelativeProjectPath$1(filePath, projectRoot) {
575
+ const file = normalizePath$5(filePath);
576
+ if (!projectRoot) return file;
577
+ const root = normalizePath$5(projectRoot).replace(/\/$/, "");
578
+ if (file === root) return file.split("/").at(-1) ?? file;
579
+ if (file.startsWith(`${root}/`)) return file.slice(root.length + 1);
580
+ return file;
581
+ }
582
+ function normalizePath$5(path) {
583
+ return path.replace(/\\/g, "/");
584
+ }
585
+ function hashSource(source) {
586
+ let hash = 5381;
587
+ for (let index = 0; index < source.length; index += 1) hash = hash * 33 ^ source.charCodeAt(index);
588
+ return (hash >>> 0).toString(16);
589
+ }
590
+ //#endregion
591
+ //#region src/patcher/inlineCssSourcePatcher.ts
592
+ const DEFAULT_INLINE_CSS_IMPORT_SOURCES = [
593
+ "../styled-system/css",
594
+ "@/styled-system/css",
595
+ "styled-system/css"
596
+ ];
597
+ function createInlineCssSourcePatch(options) {
598
+ const { request, sourceText } = options;
599
+ const parsed = parseJsxSource(request.jsxSource);
600
+ if (!parsed.ok) return failure$3(request.editId, parsed.code, parsed.message, parsed.details);
601
+ const normalizedFile = normalizePath$4(options.filePath);
602
+ if (normalizedFile !== normalizePath$4(`${options.projectRoot.replace(/\/$/, "")}/${parsed.file}`)) return failure$3(request.editId, "stale-source", "JSX source location points to a different file.", {
603
+ filePath: normalizedFile,
604
+ jsxSource: request.jsxSource
605
+ });
606
+ let source;
607
+ try {
608
+ source = parsePandaSource(options.sourceSyntax, {
609
+ filePath: options.filePath,
610
+ sourceText
611
+ });
612
+ } catch (error) {
613
+ return failure$3(request.editId, "parse-error", "Source could not be parsed for writeback.", { message: error instanceof Error ? error.message : String(error) });
614
+ }
615
+ if (source.astKind !== "typescript") return failure$3(request.editId, "unsupported-source-shape", "Inline Panda source creation is not supported for ESTree-backed source yet.");
616
+ const sourceFile = source.root;
617
+ const position = positionForLineColumn$1(sourceFile, parsed.line, parsed.column);
618
+ if (position === void 0) return failure$3(request.editId, "stale-source", "JSX source location is outside the file.");
619
+ const element = findJsxElementAtStart$1(sourceFile, position);
620
+ if (!element) return failure$3(request.editId, "stale-source", "JSX source location no longer points to a JSX element.");
621
+ const existingImport = findCssImportBinding$1(sourceFile, options.cssImportSources);
622
+ const cssLocalName = existingImport?.localName ?? availableCssLocalName(sourceFile);
623
+ const replacements = [];
624
+ const attributeReplacement = inlineCssAttributeReplacement(sourceFile, sourceText, element, cssLocalName, existingImport?.localName);
625
+ if (!attributeReplacement.ok) return failure$3(request.editId, attributeReplacement.code, attributeReplacement.message, attributeReplacement.details);
626
+ replacements.push(attributeReplacement.replacement);
627
+ if (!existingImport) replacements.push({
628
+ range: {
629
+ start: importInsertionPosition$2(sourceFile),
630
+ end: importInsertionPosition$2(sourceFile)
631
+ },
632
+ text: cssImportText$1(cssLocalName, options.cssImportSources)
633
+ });
634
+ const nextSource = applyReplacements$3(sourceText, replacements);
635
+ const file = parsed.file;
636
+ return {
637
+ ok: true,
638
+ editId: request.editId,
639
+ file,
640
+ diff: focusedDiff$3(file, sourceText, nextSource, replacements),
641
+ nextSource,
642
+ written: false
643
+ };
644
+ }
645
+ function inlineCssAttributeReplacement(sourceFile, sourceText, element, cssLocalName, existingCssLocalName) {
646
+ let classAttribute;
647
+ for (const property of element.attributes.properties) {
648
+ if (!ts.isJsxAttribute(property) || !ts.isIdentifier(property.name)) continue;
649
+ if (property.name.text !== "class" && property.name.text !== "className") continue;
650
+ classAttribute = property;
651
+ const expression = property.initializer && jsxAttributeExpression$2(property.initializer);
652
+ if (expression && existingCssLocalName && containsInlineCssCall(sourceFile, expression, existingCssLocalName)) return {
653
+ ok: false,
654
+ code: "unsupported-operation",
655
+ message: "This JSX element already has an inline css() source."
656
+ };
657
+ break;
658
+ }
659
+ if (!classAttribute) {
660
+ const insertPosition = element.getEnd() - (ts.isJsxSelfClosingElement(element) ? 2 : 1);
661
+ return {
662
+ ok: true,
663
+ replacement: {
664
+ range: {
665
+ start: insertPosition,
666
+ end: insertPosition
667
+ },
668
+ text: ` class={${cssLocalName}({})}`
669
+ }
670
+ };
671
+ }
672
+ if (!ts.isIdentifier(classAttribute.name)) return {
673
+ ok: false,
674
+ code: "unsupported-source-shape",
675
+ message: "Namespaced JSX class attributes cannot receive inline css() sources."
676
+ };
677
+ const attributeName = classAttribute.name.text;
678
+ const inlineCssCall = `${cssLocalName}({})`;
679
+ if (!classAttribute.initializer) return {
680
+ ok: true,
681
+ replacement: {
682
+ range: {
683
+ start: classAttribute.getStart(sourceFile),
684
+ end: classAttribute.getEnd()
685
+ },
686
+ text: `${attributeName}={${inlineCssCall}}`
687
+ }
688
+ };
689
+ if (ts.isStringLiteral(classAttribute.initializer)) return {
690
+ ok: true,
691
+ replacement: {
692
+ range: {
693
+ start: classAttribute.getStart(sourceFile),
694
+ end: classAttribute.getEnd()
695
+ },
696
+ text: `${attributeName}={\`${escapeTemplateText$1(classAttribute.initializer.text)} \${${inlineCssCall}}\`}`
697
+ }
698
+ };
699
+ const expression = jsxAttributeExpression$2(classAttribute.initializer);
700
+ if (!expression) return {
701
+ ok: false,
702
+ code: "unsupported-source-shape",
703
+ message: "Only string and expression class attributes can receive inline css() sources."
704
+ };
705
+ const expressionText = sourceText.slice(expression.getStart(sourceFile), expression.getEnd());
706
+ return {
707
+ ok: true,
708
+ replacement: {
709
+ range: {
710
+ start: classAttribute.getStart(sourceFile),
711
+ end: classAttribute.getEnd()
712
+ },
713
+ text: `${attributeName}={[${expressionText}, ${inlineCssCall}].filter(Boolean).join(' ')}`
714
+ }
715
+ };
716
+ }
717
+ function jsxAttributeExpression$2(initializer) {
718
+ if (ts.isJsxExpression(initializer)) return initializer.expression;
719
+ }
720
+ function findJsxElementAtStart$1(sourceFile, position) {
721
+ let result;
722
+ const visit = (node) => {
723
+ if (result) return;
724
+ if ((ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) && node.getStart(sourceFile) === position) {
725
+ result = node;
726
+ return;
727
+ }
728
+ ts.forEachChild(node, visit);
729
+ };
730
+ visit(sourceFile);
731
+ return result;
732
+ }
733
+ function containsInlineCssCall(sourceFile, expression, cssLocalName) {
734
+ let found = false;
735
+ const visit = (node) => {
736
+ if (found) return;
737
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === cssLocalName && ts.isObjectLiteralExpression(node.arguments[0])) {
738
+ found = true;
739
+ return;
740
+ }
741
+ ts.forEachChild(node, visit);
742
+ };
743
+ visit(expression);
744
+ return found;
745
+ }
746
+ function findCssImportBinding$1(sourceFile, cssImportSources) {
747
+ const importSources = new Set(cssImportSources ?? DEFAULT_INLINE_CSS_IMPORT_SOURCES);
748
+ for (const statement of sourceFile.statements) {
749
+ if (!ts.isImportDeclaration(statement)) continue;
750
+ if (!ts.isStringLiteral(statement.moduleSpecifier)) continue;
751
+ if (!importSources.has(statement.moduleSpecifier.text)) continue;
752
+ const namedBindings = statement.importClause?.namedBindings;
753
+ if (!namedBindings || !ts.isNamedImports(namedBindings)) continue;
754
+ for (const element of namedBindings.elements) if ((element.propertyName?.text ?? element.name.text) === "css") return {
755
+ localName: element.name.text,
756
+ moduleSpecifier: statement.moduleSpecifier.text
757
+ };
758
+ }
759
+ }
760
+ function availableCssLocalName(sourceFile) {
761
+ const identifiers = /* @__PURE__ */ new Set();
762
+ const visit = (node) => {
763
+ if (ts.isIdentifier(node)) identifiers.add(node.text);
764
+ ts.forEachChild(node, visit);
765
+ };
766
+ visit(sourceFile);
767
+ return identifiers.has("css") ? "pandaCss" : "css";
768
+ }
769
+ function cssImportText$1(cssLocalName, cssImportSources) {
770
+ const moduleSpecifier = cssImportSources?.[0] ?? DEFAULT_INLINE_CSS_IMPORT_SOURCES[0];
771
+ return `import { ${cssLocalName === "css" ? "css" : `css as ${cssLocalName}`} } from '${moduleSpecifier}'\n`;
772
+ }
773
+ function importInsertionPosition$2(sourceFile) {
774
+ let position = 0;
775
+ for (const statement of sourceFile.statements) {
776
+ if (!ts.isImportDeclaration(statement)) break;
777
+ position = statement.getEnd();
778
+ }
779
+ return position === 0 ? 0 : position + 1;
780
+ }
781
+ function parseJsxSource(source) {
782
+ const match = /^(.*):(\d+):(\d+)$/.exec(source.trim());
783
+ const file = match?.[1]?.trim();
784
+ const line = match?.[2] ? Number.parseInt(match[2], 10) : void 0;
785
+ const column = match?.[3] ? Number.parseInt(match[3], 10) : void 0;
786
+ if (!match || !file || line === void 0 || column === void 0 || line < 1 || column < 1) return {
787
+ ok: false,
788
+ code: "invalid-edit",
789
+ message: "Inline source creation requires a JSX source path with line and column.",
790
+ details: { source }
791
+ };
792
+ return {
793
+ ok: true,
794
+ file,
795
+ line,
796
+ column
797
+ };
798
+ }
799
+ function positionForLineColumn$1(sourceFile, line, column) {
800
+ const lineStart = sourceFile.getLineStarts()[line - 1];
801
+ if (lineStart === void 0) return void 0;
802
+ const position = lineStart + column - 1;
803
+ return position <= sourceFile.text.length ? position : void 0;
804
+ }
805
+ function escapeTemplateText$1(value) {
806
+ return value.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
807
+ }
808
+ function applyReplacements$3(sourceText, replacements) {
809
+ let nextSource = sourceText;
810
+ for (const replacement of [...replacements].sort((left, right) => right.range.start - left.range.start)) nextSource = `${nextSource.slice(0, replacement.range.start)}${replacement.text}${nextSource.slice(replacement.range.end)}`;
811
+ return nextSource;
812
+ }
813
+ function focusedDiff$3(file, sourceText, nextSource, replacements) {
814
+ const firstStart = Math.min(...replacements.map((replacement) => replacement.range.start));
815
+ const lastEnd = Math.max(...replacements.map((replacement) => replacement.range.end));
816
+ const oldStartLine = lineNumberAt$3(sourceText, firstStart);
817
+ const oldEndLine = lineNumberAt$3(sourceText, lastEnd);
818
+ const contextStartLine = Math.max(1, oldStartLine - 2);
819
+ const contextEndLine = oldEndLine + 2;
820
+ const oldLines = sourceText.split("\n");
821
+ const newLines = nextSource.split("\n");
822
+ const oldSlice = oldLines.slice(contextStartLine - 1, contextEndLine);
823
+ const newSlice = newLines.slice(contextStartLine - 1, contextEndLine + (newLines.length - oldLines.length));
824
+ return [
825
+ `--- a/${file}`,
826
+ `+++ b/${file}`,
827
+ `@@ -${contextStartLine},${oldSlice.length} +${contextStartLine},${newSlice.length} @@`,
828
+ ...oldSlice.map((line) => `-${line}`),
829
+ ...newSlice.map((line) => `+${line}`)
830
+ ].join("\n");
831
+ }
832
+ function lineNumberAt$3(sourceText, position) {
833
+ let line = 1;
834
+ for (let index = 0; index < position; index += 1) if (sourceText.charCodeAt(index) === 10) line += 1;
835
+ return line;
836
+ }
837
+ function normalizePath$4(path) {
838
+ return path.replace(/\\/g, "/");
839
+ }
840
+ function failure$3(editId, code, message, details) {
841
+ return {
842
+ ok: false,
843
+ editId,
844
+ written: false,
845
+ error: {
846
+ code,
847
+ message,
848
+ details
849
+ }
850
+ };
851
+ }
852
+ //#endregion
853
+ //#region src/patcher/staticCssPatcher.ts
854
+ function createStaticCssPatch(options) {
855
+ const { manifest, request, sourceText } = options;
856
+ const collected = collectPatchReplacements({
857
+ manifest,
858
+ request,
859
+ sourceText,
860
+ filePath: options.filePath,
861
+ styledSystemPackageName: options.styledSystemPackageName,
862
+ sourceSyntax: options.sourceSyntax
863
+ });
864
+ if (!collected.ok) return collected;
865
+ const overlap = findOverlappingReplacement(collected.replacements);
866
+ if (overlap) return failure$2(request.editId, "ambiguous-target", "Multiple edits target overlapping source ranges.", { ranges: overlap });
867
+ const nextSource = applyReplacements$2(sourceText, collected.replacements);
868
+ return {
869
+ ok: true,
870
+ editId: request.editId,
871
+ file: collected.entry.file,
872
+ diff: focusedDiff$2(collected.entry.file, sourceText, nextSource, collected.replacements),
873
+ nextSource,
874
+ written: false
875
+ };
876
+ }
877
+ function createStaticCssBatchPatch(options) {
878
+ const { requests, sourceText } = options;
879
+ const firstRequest = requests[0];
880
+ if (!firstRequest) return failure$2("", "invalid-edit", "Batch patch requires at least one style edit request.");
881
+ const collectedPatches = requests.map((request) => ({
882
+ request,
883
+ patch: collectPatchReplacements({
884
+ ...options,
885
+ request
886
+ })
887
+ }));
888
+ const failurePatch = collectedPatches.find((item) => !item.patch.ok);
889
+ if (failurePatch && !failurePatch.patch.ok) return failurePatch.patch;
890
+ const successfulPatches = collectedPatches.map((item) => item.patch);
891
+ const replacements = dedupeIdenticalReplacements(successfulPatches.flatMap((patch) => patch.replacements));
892
+ const overlap = findOverlappingReplacement(replacements);
893
+ if (overlap) return failure$2(firstRequest.editId, "ambiguous-target", "Multiple edits target overlapping source ranges.", { ranges: overlap });
894
+ const nextSource = applyReplacements$2(sourceText, replacements);
895
+ const file = successfulPatches[0]?.entry.file ?? "";
896
+ return {
897
+ ok: true,
898
+ editId: requests.map((request) => request.editId).join(" "),
899
+ file,
900
+ diff: focusedDiff$2(file, sourceText, nextSource, replacements),
901
+ nextSource,
902
+ written: false
903
+ };
904
+ }
905
+ function collectPatchReplacements(options) {
906
+ const { manifest, request, sourceText } = options;
907
+ const entry = manifest.entries.find((item) => item.id === request.editId);
908
+ if (!entry) return failure$2(request.editId, "manifest-entry-not-found", "No manifest entry exists for edit id.");
909
+ if (request.kind !== "panda-css" || entry.kind !== "panda-css") return failure$2(request.editId, "unsupported-source-shape", "Only Panda css() entries can be patched.");
910
+ const fileFailure = validateProjectFile$1(manifest, entry, options.filePath);
911
+ if (fileFailure) return failure$2(request.editId, fileFailure.code, fileFailure.message, fileFailure.details);
912
+ if (!entry.range) return failure$2(request.editId, "unsupported-source-shape", "Manifest entry has no source range.");
913
+ if (!entry.sourceHash || hashSource(sourceText.slice(entry.range.start, entry.range.end)) !== entry.sourceHash) return failure$2(request.editId, "stale-source", "Source text no longer matches the manifest entry hash.");
914
+ if (request.options?.expectedSourceHash && request.options.expectedSourceHash !== entry.sourceHash) return failure$2(request.editId, "stale-source", "Edit request was prepared against a different source hash.", {
915
+ expectedSourceHash: request.options.expectedSourceHash,
916
+ actualSourceHash: entry.sourceHash
917
+ });
918
+ let source;
919
+ try {
920
+ source = parsePandaSource(options.sourceSyntax, {
921
+ filePath: entry.absoluteFile ?? entry.file,
922
+ sourceText
923
+ });
924
+ } catch (error) {
925
+ return failure$2(request.editId, "parse-error", "Source could not be parsed for writeback.", { message: error instanceof Error ? error.message : String(error) });
926
+ }
927
+ const objectNode = source.ops.findObjectExpressionAtRange(source.root, entry.range);
928
+ if (!objectNode) return failure$2(request.editId, "stale-source", "Manifest range no longer points to a css() object literal.");
929
+ const parentCall = source.ops.getParent(source.root, objectNode);
930
+ if (!parentCall || !source.ops.isCallExpression(parentCall) || source.ops.getCallCalleeIdentifier(parentCall) !== entry.callee) return failure$2(request.editId, "stale-source", "Manifest range no longer belongs to the expected css() call.");
931
+ const replacements = [];
932
+ const sourceFile = source.astKind === "typescript" ? source.root : void 0;
933
+ const tokenVarImportLocalName = sourceFile && options.styledSystemPackageName ? tokenImportLocalName(sourceFile, options.styledSystemPackageName) : void 0;
934
+ for (const edit of request.edits) {
935
+ if (edit.op === "rename" || edit.op === "replace-object") return failure$2(request.editId, "unsupported-operation", `Unsupported edit operation: ${edit.op}.`);
936
+ const editFailure = validateStyleEdit(edit);
937
+ if (editFailure) return failure$2(request.editId, editFailure.code, editFailure.message, editFailure.details);
938
+ const replacement = replacementForEdit(source, objectNode, edit, sourceText, {
939
+ path: edit.path,
940
+ tokenVarImportLocalName
941
+ });
942
+ if (!replacement.ok) return failure$2(request.editId, replacement.code, replacement.message, replacement.details);
943
+ replacements.push(replacement);
944
+ }
945
+ if (sourceFile && tokenVarImportLocalName && replacements.some((replacement) => replacement.text.includes(`${tokenVarImportLocalName}.var(`))) {
946
+ const tokenImport = tokenVarImportReplacement(sourceFile, options.styledSystemPackageName, tokenVarImportLocalName);
947
+ if (tokenImport) replacements.push(tokenImport);
948
+ }
949
+ if (sourceFile && source.astKind === "typescript" && rootObjectWillBeEmptyAfterEdits(objectNode, request.edits)) {
950
+ const inlineCleanup = inlineEmptyCssCleanupReplacement(objectNode, sourceFile, sourceText);
951
+ if (inlineCleanup) return {
952
+ ok: true,
953
+ entry,
954
+ replacements: [inlineCleanup]
955
+ };
956
+ }
957
+ return {
958
+ ok: true,
959
+ entry,
960
+ replacements
961
+ };
962
+ }
963
+ function validateProjectFile$1(manifest, entry, filePath) {
964
+ const root = normalizePath$3(manifest.projectRoot).replace(/\/$/, "");
965
+ if (!root) return {
966
+ code: "path-outside-project",
967
+ message: "Manifest project root is empty."
968
+ };
969
+ const absoluteFile = normalizePath$3(entry.absoluteFile ?? `${root}/${entry.file}`);
970
+ if (absoluteFile !== root && !absoluteFile.startsWith(`${root}/`)) return {
971
+ code: "path-outside-project",
972
+ message: "Manifest entry points outside the project root.",
973
+ details: {
974
+ file: absoluteFile,
975
+ projectRoot: root
976
+ }
977
+ };
978
+ if (filePath && normalizePath$3(filePath) !== absoluteFile) return {
979
+ code: "stale-source",
980
+ message: "Provided source file does not match the manifest entry file.",
981
+ details: {
982
+ filePath: normalizePath$3(filePath),
983
+ manifestFile: absoluteFile
984
+ }
985
+ };
986
+ }
987
+ function validateStyleEdit(edit) {
988
+ if (edit.path.length === 0 || edit.path.some((part) => part.length === 0)) return {
989
+ code: "invalid-path",
990
+ message: `${edit.op} edits require a non-empty style path.`,
991
+ details: { path: [...edit.path] }
992
+ };
993
+ if (edit.op === "set" && !isJsonPrimitive$1(edit.value)) return {
994
+ code: "unsupported-operation",
995
+ message: "Patching only supports literal primitive values.",
996
+ details: { path: [...edit.path] }
997
+ };
998
+ }
999
+ function replacementForEdit(source, objectNode, edit, sourceText, literalContext) {
1000
+ let current = objectNode;
1001
+ const { path } = edit;
1002
+ for (let index = 0; index < path.length; index += 1) {
1003
+ const part = path[index];
1004
+ const located = locateProperty$1(source, current, part);
1005
+ if (!located.ok) {
1006
+ if (source.astKind === "typescript" && edit.op === "set" && located.reason.code === "invalid-path") {
1007
+ if (!isJsonPrimitive$1(edit.value)) return {
1008
+ ok: false,
1009
+ code: "unsupported-operation",
1010
+ message: "Patching only supports literal primitive values.",
1011
+ details: { path: [...edit.path] }
1012
+ };
1013
+ return insertionForMissingNestedProperty(current, path.slice(index), edit.value, source.root, sourceText, literalContext);
1014
+ }
1015
+ return {
1016
+ ok: false,
1017
+ ...located.reason
1018
+ };
1019
+ }
1020
+ const initializer = source.ops.getPropertyValue(located.property);
1021
+ if (!initializer) return {
1022
+ ok: false,
1023
+ code: "unsupported-source-shape",
1024
+ message: "Target property has no patchable value.",
1025
+ details: { path: [...path] }
1026
+ };
1027
+ if (index === path.length - 1) {
1028
+ if (edit.op === "delete") {
1029
+ if (source.astKind !== "typescript") return {
1030
+ ok: false,
1031
+ code: "unsupported-operation",
1032
+ message: "Delete edits are not supported for ESTree-backed source yet.",
1033
+ details: { path: [...path] }
1034
+ };
1035
+ return {
1036
+ ok: true,
1037
+ range: deletionRangeForProperty(current, located.property, source.root, sourceText),
1038
+ text: ""
1039
+ };
1040
+ }
1041
+ if (!source.ops.isPatchableLiteral(initializer)) return {
1042
+ ok: false,
1043
+ code: "unsupported-source-shape",
1044
+ message: "Target path is not an existing literal value.",
1045
+ details: { path: [...path] }
1046
+ };
1047
+ if (!isJsonPrimitive$1(edit.value)) return {
1048
+ ok: false,
1049
+ code: "unsupported-operation",
1050
+ message: "Patching only supports literal primitive values.",
1051
+ details: { path: [...edit.path] }
1052
+ };
1053
+ return {
1054
+ ok: true,
1055
+ range: source.ops.getRange(initializer),
1056
+ text: literalSource$1(edit.value, literalContext)
1057
+ };
1058
+ }
1059
+ if (!source.ops.isObjectExpression(initializer)) return {
1060
+ ok: false,
1061
+ code: "invalid-path",
1062
+ message: "Target path descends through a non-object value.",
1063
+ details: { path: path.slice(0, index + 1) }
1064
+ };
1065
+ current = initializer;
1066
+ }
1067
+ return {
1068
+ ok: false,
1069
+ code: "invalid-path",
1070
+ message: `${edit.op} edits require a non-empty style path.`
1071
+ };
1072
+ }
1073
+ function insertionForMissingNestedProperty(objectNode, path, value, sourceFile, sourceText, literalContext) {
1074
+ const propertyName = path[0];
1075
+ if (!propertyName) return {
1076
+ ok: false,
1077
+ code: "invalid-path",
1078
+ message: "Missing nested property insertion requires a non-empty path."
1079
+ };
1080
+ return insertionForMissingProperty$1(objectNode, propertyName, nestedStyleObjectSource(path.slice(1), value, literalContext), sourceFile, sourceText, literalContext);
1081
+ }
1082
+ function insertionForMissingProperty$1(objectNode, propertyName, value, sourceFile, sourceText, literalContext) {
1083
+ const closeBrace = objectNode.getEnd() - 1;
1084
+ const multiline = sourceText.slice(objectNode.getStart(sourceFile), objectNode.getEnd()).includes("\n");
1085
+ const property = `${propertyNameSource$1(propertyName)}: ${valueSource(value, {
1086
+ ...literalContext,
1087
+ path: [...literalContext.path.slice(0, -1), propertyName]
1088
+ })}`;
1089
+ if (objectNode.properties.length === 0) {
1090
+ if (!multiline) return {
1091
+ ok: true,
1092
+ range: {
1093
+ start: closeBrace,
1094
+ end: closeBrace
1095
+ },
1096
+ text: property
1097
+ };
1098
+ const parentIndent = indentationBefore$1(sourceText, objectNode.getStart(sourceFile));
1099
+ const childIndent = `${parentIndent} `;
1100
+ return {
1101
+ ok: true,
1102
+ range: {
1103
+ start: closeBrace,
1104
+ end: closeBrace
1105
+ },
1106
+ text: `\n${childIndent}${property},\n${parentIndent}`
1107
+ };
1108
+ }
1109
+ const lastProperty = objectNode.properties[objectNode.properties.length - 1];
1110
+ const trailingComma = commaAfterNode$1(lastProperty, objectNode, sourceText);
1111
+ if (!multiline) {
1112
+ const insertAt = trailingComma ?? lastProperty.getEnd();
1113
+ return {
1114
+ ok: true,
1115
+ range: {
1116
+ start: insertAt,
1117
+ end: insertAt
1118
+ },
1119
+ text: trailingComma === void 0 ? `, ${property}` : ` ${property}`
1120
+ };
1121
+ }
1122
+ const childIndent = indentationBefore$1(sourceText, lastProperty.getStart(sourceFile));
1123
+ if (trailingComma !== void 0) return {
1124
+ ok: true,
1125
+ range: {
1126
+ start: trailingComma + 1,
1127
+ end: trailingComma + 1
1128
+ },
1129
+ text: `\n${childIndent}${property},`
1130
+ };
1131
+ return {
1132
+ ok: true,
1133
+ range: {
1134
+ start: lastProperty.getEnd(),
1135
+ end: lastProperty.getEnd()
1136
+ },
1137
+ text: `,\n${childIndent}${property}`
1138
+ };
1139
+ }
1140
+ function nestedStyleObjectSource(path, value, literalContext) {
1141
+ if (path.length === 0) return {
1142
+ kind: "raw-source",
1143
+ text: literalSource$1(value, literalContext)
1144
+ };
1145
+ const [propertyName, ...rest] = path;
1146
+ return {
1147
+ kind: "raw-source",
1148
+ text: `{ ${propertyNameSource$1(propertyName)}: ${nestedStyleObjectSource(rest, value, {
1149
+ ...literalContext,
1150
+ path: [...literalContext.path.slice(0, -rest.length - 1), propertyName]
1151
+ }).text} }`
1152
+ };
1153
+ }
1154
+ function valueSource(value, context) {
1155
+ if (isRawSourceValue(value)) return value.text;
1156
+ return literalSource$1(value, context);
1157
+ }
1158
+ function isRawSourceValue(value) {
1159
+ return typeof value === "object" && value !== null && "kind" in value && value.kind === "raw-source";
1160
+ }
1161
+ function commaAfterNode$1(node, objectNode, sourceText) {
1162
+ for (let index = node.getEnd(); index < objectNode.getEnd() - 1; index += 1) {
1163
+ const char = sourceText[index];
1164
+ if (char === ",") return index;
1165
+ if (!isWhitespace$1(char)) return void 0;
1166
+ }
1167
+ }
1168
+ function isWhitespace$1(char) {
1169
+ return char === " " || char === " " || char === "\n" || char === "\r";
1170
+ }
1171
+ function indentationBefore$1(sourceText, position) {
1172
+ const lineStart = sourceText.lastIndexOf("\n", position - 1) + 1;
1173
+ return sourceText.slice(lineStart, position).match(/^[ \t]*/)?.[0] ?? "";
1174
+ }
1175
+ function propertyNameSource$1(propertyName) {
1176
+ return /^[$A-Z_a-z][$\w]*$/.test(propertyName) ? propertyName : JSON.stringify(propertyName);
1177
+ }
1178
+ function propertyNameText$2(name) {
1179
+ if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) return name.text;
1180
+ }
1181
+ function deletionRangeForProperty(objectNode, property, sourceFile, sourceText) {
1182
+ const properties = objectNode.properties;
1183
+ const index = properties.findIndex((item) => item === property);
1184
+ const next = properties[index + 1];
1185
+ if (next) return {
1186
+ start: property.getStart(sourceFile),
1187
+ end: next.getStart(sourceFile)
1188
+ };
1189
+ const trailingComma = commaAfterNode$1(property, objectNode, sourceText);
1190
+ const previous = properties[index - 1];
1191
+ if (previous) return {
1192
+ start: previous.getEnd(),
1193
+ end: trailingComma === void 0 ? property.getEnd() : trailingComma + 1
1194
+ };
1195
+ return {
1196
+ start: property.getStart(sourceFile),
1197
+ end: trailingComma === void 0 ? property.getEnd() : trailingComma + 1
1198
+ };
1199
+ }
1200
+ function rootObjectWillBeEmptyAfterEdits(objectNode, edits) {
1201
+ if (objectNode.properties.length === 0) return true;
1202
+ if (edits.some((edit) => edit.op !== "delete" || edit.path.length !== 1)) return false;
1203
+ const deleted = new Set(edits.flatMap((edit) => edit.op === "delete" && edit.path.length === 1 ? [edit.path[0]] : []));
1204
+ for (const property of objectNode.properties) {
1205
+ if (!ts.isPropertyAssignment(property)) return false;
1206
+ const name = propertyNameText$2(property.name);
1207
+ if (name === void 0 || !deleted.has(name)) return false;
1208
+ }
1209
+ return true;
1210
+ }
1211
+ function inlineEmptyCssCleanupReplacement(objectNode, sourceFile, sourceText) {
1212
+ const call = objectNode.parent;
1213
+ if (!ts.isCallExpression(call)) return void 0;
1214
+ const classAttribute = jsxClassAttributeAncestor(call);
1215
+ if (!classAttribute || !ts.isIdentifier(classAttribute.name)) return void 0;
1216
+ const expression = classAttribute.initializer && jsxAttributeExpression$1(classAttribute.initializer);
1217
+ if (!expression) return removeJsxAttributeReplacement(classAttribute);
1218
+ if (unwrapParentheses(expression) === call) return removeJsxAttributeReplacement(classAttribute);
1219
+ const generatedArray = generatedClassJoinArray(expression);
1220
+ if (!generatedArray) return void 0;
1221
+ const keptElements = generatedArray.elements.filter((element) => unwrapParentheses(element) !== call);
1222
+ if (keptElements.length === generatedArray.elements.length) return void 0;
1223
+ if (keptElements.length === 0) return removeJsxAttributeReplacement(classAttribute);
1224
+ const attributeName = classAttribute.name.text;
1225
+ if (keptElements.length === 1) {
1226
+ const keptText = sourceText.slice(keptElements[0].getStart(sourceFile), keptElements[0].getEnd());
1227
+ return {
1228
+ range: {
1229
+ start: classAttribute.getStart(sourceFile),
1230
+ end: classAttribute.getEnd()
1231
+ },
1232
+ text: `${attributeName}={${keptText}}`
1233
+ };
1234
+ }
1235
+ const joinedText = keptElements.map((element) => sourceText.slice(element.getStart(sourceFile), element.getEnd())).join(", ");
1236
+ return {
1237
+ range: {
1238
+ start: classAttribute.getStart(sourceFile),
1239
+ end: classAttribute.getEnd()
1240
+ },
1241
+ text: `${attributeName}={[${joinedText}].filter(Boolean).join(' ')}`
1242
+ };
1243
+ }
1244
+ function jsxClassAttributeAncestor(node) {
1245
+ let current = node;
1246
+ while (current) {
1247
+ if (ts.isJsxAttribute(current) && ts.isIdentifier(current.name) && (current.name.text === "class" || current.name.text === "className")) return current;
1248
+ current = current.parent;
1249
+ }
1250
+ }
1251
+ function jsxAttributeExpression$1(initializer) {
1252
+ if (ts.isJsxExpression(initializer)) return initializer.expression;
1253
+ }
1254
+ function removeJsxAttributeReplacement(attribute) {
1255
+ return {
1256
+ range: {
1257
+ start: attribute.getFullStart(),
1258
+ end: attribute.getEnd()
1259
+ },
1260
+ text: ""
1261
+ };
1262
+ }
1263
+ function generatedClassJoinArray(expression) {
1264
+ const joinCall = unwrapParentheses(expression);
1265
+ if (!ts.isCallExpression(joinCall)) return void 0;
1266
+ if (!ts.isPropertyAccessExpression(joinCall.expression)) return void 0;
1267
+ if (joinCall.expression.name.text !== "join") return void 0;
1268
+ const filterCall = unwrapParentheses(joinCall.expression.expression);
1269
+ if (!ts.isCallExpression(filterCall)) return void 0;
1270
+ if (!ts.isPropertyAccessExpression(filterCall.expression)) return void 0;
1271
+ if (filterCall.expression.name.text !== "filter") return void 0;
1272
+ const array = unwrapParentheses(filterCall.expression.expression);
1273
+ return ts.isArrayLiteralExpression(array) ? array : void 0;
1274
+ }
1275
+ function unwrapParentheses(expression) {
1276
+ let current = expression;
1277
+ while (ts.isParenthesizedExpression(current)) current = current.expression;
1278
+ return current;
1279
+ }
1280
+ function locateProperty$1(source, objectNode, propertyName) {
1281
+ const matches = [];
1282
+ for (const property of source.ops.getObjectProperties(objectNode)) {
1283
+ if (source.ops.isSpreadProperty(property)) return {
1284
+ ok: false,
1285
+ reason: {
1286
+ code: "unsupported-source-shape",
1287
+ message: "Object spread can change which style keys exist at runtime."
1288
+ }
1289
+ };
1290
+ if (!source.ops.isPlainProperty(property)) return {
1291
+ ok: false,
1292
+ reason: {
1293
+ code: "unsupported-source-shape",
1294
+ message: "Only plain property assignments can be patched."
1295
+ }
1296
+ };
1297
+ const name = source.ops.getPropertyName(property);
1298
+ if (name === void 0) return {
1299
+ ok: false,
1300
+ reason: {
1301
+ code: "unsupported-source-shape",
1302
+ message: "Computed property names are not safe to patch."
1303
+ }
1304
+ };
1305
+ if (name === propertyName) matches.push(property);
1306
+ }
1307
+ if (matches.length > 1) return {
1308
+ ok: false,
1309
+ reason: {
1310
+ code: "ambiguous-target",
1311
+ message: "Style object contains duplicate keys for the requested path.",
1312
+ details: { property: propertyName }
1313
+ }
1314
+ };
1315
+ const property = matches[0];
1316
+ if (!property) return {
1317
+ ok: false,
1318
+ reason: {
1319
+ code: "invalid-path",
1320
+ message: "Style object does not contain the requested path.",
1321
+ details: { property: propertyName }
1322
+ }
1323
+ };
1324
+ return {
1325
+ ok: true,
1326
+ property
1327
+ };
1328
+ }
1329
+ function isJsonPrimitive$1(value) {
1330
+ return value === null || [
1331
+ "string",
1332
+ "number",
1333
+ "boolean"
1334
+ ].includes(typeof value);
1335
+ }
1336
+ function literalSource$1(value, context) {
1337
+ if (typeof value === "string") {
1338
+ const complexTokenSource = complexTokenValueSource(value, context);
1339
+ if (complexTokenSource) return complexTokenSource;
1340
+ return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
1341
+ }
1342
+ if (typeof value === "number") return Number.isFinite(value) ? String(value) : "null";
1343
+ if (typeof value === "boolean") return value ? "true" : "false";
1344
+ return "null";
1345
+ }
1346
+ function complexTokenValueSource(value, context) {
1347
+ const property = context?.path.at(-1);
1348
+ if (property !== "border" && property !== "outline") return void 0;
1349
+ const parts = value.trim().split(/\s+/);
1350
+ if (parts.length < 2) return void 0;
1351
+ const colorToken = parts.at(-1);
1352
+ if (!colorToken || !looksLikeColorTokenPath(colorToken)) return void 0;
1353
+ const tokenPath = colorToken.startsWith("colors.") ? colorToken : `colors.${colorToken}`;
1354
+ const prefix = parts.slice(0, -1).join(" ");
1355
+ if (!context?.tokenVarImportLocalName) return `'${escapeSingleQuotedString(`${prefix} token(${tokenPath})`)}'`;
1356
+ return `\`${escapeTemplateText(`${prefix} `)}\${${context.tokenVarImportLocalName}.var(${JSON.stringify(tokenPath)})}\``;
1357
+ }
1358
+ function looksLikeColorTokenPath(value) {
1359
+ return /^(?:colors\.)?[A-Za-z_][\w-]*(?:\.[A-Za-z0-9_][\w-]*)+$/.test(value);
1360
+ }
1361
+ function escapeSingleQuotedString(value) {
1362
+ return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
1363
+ }
1364
+ function escapeTemplateText(value) {
1365
+ return value.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
1366
+ }
1367
+ function tokenImportLocalName(sourceFile, styledSystemPackageName) {
1368
+ const moduleSpecifier = `${styledSystemPackageName}/tokens`;
1369
+ for (const statement of sourceFile.statements) {
1370
+ if (!ts.isImportDeclaration(statement)) continue;
1371
+ if (!ts.isStringLiteral(statement.moduleSpecifier)) continue;
1372
+ if (statement.moduleSpecifier.text !== moduleSpecifier) continue;
1373
+ const namedBindings = statement.importClause?.namedBindings;
1374
+ if (!namedBindings || !ts.isNamedImports(namedBindings)) return void 0;
1375
+ for (const element of namedBindings.elements) if ((element.propertyName?.text ?? element.name.text) === "token") return element.name.text;
1376
+ }
1377
+ return tokenIdentifierAvailable(sourceFile) ? "token" : void 0;
1378
+ }
1379
+ function tokenIdentifierAvailable(sourceFile) {
1380
+ let available = true;
1381
+ const visit = (node) => {
1382
+ if (!available) return;
1383
+ if (ts.isIdentifier(node) && node.text === "token") {
1384
+ available = false;
1385
+ return;
1386
+ }
1387
+ ts.forEachChild(node, visit);
1388
+ };
1389
+ visit(sourceFile);
1390
+ return available;
1391
+ }
1392
+ function tokenVarImportReplacement(sourceFile, styledSystemPackageName, localName) {
1393
+ const moduleSpecifier = `${styledSystemPackageName}/tokens`;
1394
+ for (const statement of sourceFile.statements) {
1395
+ if (!ts.isImportDeclaration(statement)) continue;
1396
+ if (!ts.isStringLiteral(statement.moduleSpecifier)) continue;
1397
+ if (statement.moduleSpecifier.text !== moduleSpecifier) continue;
1398
+ const namedBindings = statement.importClause?.namedBindings;
1399
+ if (!namedBindings || !ts.isNamedImports(namedBindings)) return void 0;
1400
+ if (namedBindings.elements.some((element) => (element.propertyName?.text ?? element.name.text) === "token")) return;
1401
+ const insertAt = namedBindings.elements.end;
1402
+ return {
1403
+ range: {
1404
+ start: insertAt,
1405
+ end: insertAt
1406
+ },
1407
+ text: `, token${localName === "token" ? "" : ` as ${localName}`}`
1408
+ };
1409
+ }
1410
+ const insertAt = importInsertionPosition$1(sourceFile);
1411
+ return {
1412
+ range: {
1413
+ start: insertAt,
1414
+ end: insertAt
1415
+ },
1416
+ text: `import { token${localName === "token" ? "" : ` as ${localName}`} } from '${moduleSpecifier}'\n`
1417
+ };
1418
+ }
1419
+ function importInsertionPosition$1(sourceFile) {
1420
+ let position = 0;
1421
+ for (const statement of sourceFile.statements) {
1422
+ if (!ts.isImportDeclaration(statement)) break;
1423
+ position = statement.getEnd();
1424
+ }
1425
+ return position === 0 ? 0 : position + 1;
1426
+ }
1427
+ function findOverlappingReplacement(replacements) {
1428
+ const sorted = [...replacements].sort((left, right) => left.range.start - right.range.start);
1429
+ for (let index = 1; index < sorted.length; index += 1) if (sorted[index - 1].range.end > sorted[index].range.start) return [sorted[index - 1].range, sorted[index].range];
1430
+ }
1431
+ function dedupeIdenticalReplacements(replacements) {
1432
+ const seen = /* @__PURE__ */ new Set();
1433
+ const deduped = [];
1434
+ for (const replacement of replacements) {
1435
+ const key = `${replacement.range.start}:${replacement.range.end}:${replacement.text}`;
1436
+ if (seen.has(key)) continue;
1437
+ seen.add(key);
1438
+ deduped.push(replacement);
1439
+ }
1440
+ return deduped;
1441
+ }
1442
+ function applyReplacements$2(sourceText, replacements) {
1443
+ let nextSource = sourceText;
1444
+ for (const replacement of [...replacements].sort((left, right) => right.range.start - left.range.start)) nextSource = `${nextSource.slice(0, replacement.range.start)}${replacement.text}${nextSource.slice(replacement.range.end)}`;
1445
+ return nextSource;
1446
+ }
1447
+ function focusedDiff$2(file, sourceText, nextSource, replacements) {
1448
+ const firstStart = Math.min(...replacements.map((replacement) => replacement.range.start));
1449
+ const lastEnd = Math.max(...replacements.map((replacement) => replacement.range.end));
1450
+ const oldStartLine = lineNumberAt$2(sourceText, firstStart);
1451
+ const oldEndLine = lineNumberAt$2(sourceText, lastEnd);
1452
+ const contextStartLine = Math.max(1, oldStartLine - 2);
1453
+ const contextEndLine = oldEndLine + 2;
1454
+ const oldLines = sourceText.split("\n");
1455
+ const newLines = nextSource.split("\n");
1456
+ const oldSlice = oldLines.slice(contextStartLine - 1, contextEndLine);
1457
+ const newSlice = newLines.slice(contextStartLine - 1, contextEndLine + (newLines.length - oldLines.length));
1458
+ return [
1459
+ `--- a/${file}`,
1460
+ `+++ b/${file}`,
1461
+ `@@ -${contextStartLine},${oldSlice.length} +${contextStartLine},${newSlice.length} @@`,
1462
+ ...oldSlice.map((line) => `-${line}`),
1463
+ ...newSlice.map((line) => `+${line}`)
1464
+ ].join("\n");
1465
+ }
1466
+ function lineNumberAt$2(sourceText, position) {
1467
+ let line = 1;
1468
+ for (let index = 0; index < position; index += 1) if (sourceText.charCodeAt(index) === 10) line += 1;
1469
+ return line;
1470
+ }
1471
+ function normalizePath$3(path) {
1472
+ return path.replace(/\\/g, "/");
1473
+ }
1474
+ function failure$2(editId, code, message, details) {
1475
+ return {
1476
+ ok: false,
1477
+ editId,
1478
+ written: false,
1479
+ error: {
1480
+ code,
1481
+ message,
1482
+ details
1483
+ }
1484
+ };
1485
+ }
1486
+ //#endregion
1487
+ //#region src/vite/pathSafety.ts
1488
+ function trustedTokenSourceFilePath(projectRoot, tokenSource) {
1489
+ const root = normalizePath$2(projectRoot).replace(/\/$/, "");
1490
+ const file = normalizePath$2(tokenSource.absoluteFile ?? `${root}/${tokenSource.file}`);
1491
+ if (!root || file !== root && !file.startsWith(`${root}/`)) return {
1492
+ ok: false,
1493
+ code: "path-outside-project",
1494
+ message: "Token source points outside the project root.",
1495
+ details: {
1496
+ file,
1497
+ projectRoot: root
1498
+ }
1499
+ };
1500
+ return {
1501
+ ok: true,
1502
+ file
1503
+ };
1504
+ }
1505
+ function trustedManifestFilePath(manifest, entry) {
1506
+ const root = normalizePath$2(manifest.projectRoot).replace(/\/$/, "");
1507
+ const file = normalizePath$2(entry.absoluteFile ?? `${root}/${entry.file}`);
1508
+ if (!root || file !== root && !file.startsWith(`${root}/`)) return {
1509
+ ok: false,
1510
+ code: "path-outside-project",
1511
+ message: "Manifest entry points outside the project root.",
1512
+ details: {
1513
+ file,
1514
+ projectRoot: root
1515
+ }
1516
+ };
1517
+ return {
1518
+ ok: true,
1519
+ file
1520
+ };
1521
+ }
1522
+ function safeProjectSourcePath(projectRoot, filePath) {
1523
+ const root = normalizePath$2(projectRoot).replace(/\/$/, "");
1524
+ const file = normalizePath$2(resolve(root, filePath)).replace(/\/$/, "");
1525
+ if (!root || file === root || !file.startsWith(`${root}/`)) return {
1526
+ ok: false,
1527
+ code: "path-outside-project",
1528
+ message: "Source path is outside the project root.",
1529
+ details: {
1530
+ file,
1531
+ projectRoot: root
1532
+ }
1533
+ };
1534
+ return {
1535
+ ok: true,
1536
+ file
1537
+ };
1538
+ }
1539
+ function stripViteQuery(id) {
1540
+ return id.split("?")[0] ?? id;
1541
+ }
1542
+ function toRelativeProjectPath(filePath, projectRoot) {
1543
+ if (!projectRoot) return filePath;
1544
+ const root = normalizePath$2(projectRoot).replace(/\/$/, "");
1545
+ if (filePath === root) return filePath.split("/").at(-1) ?? filePath;
1546
+ if (filePath.startsWith(`${root}/`)) return filePath.slice(root.length + 1);
1547
+ return filePath;
1548
+ }
1549
+ function normalizePath$2(path) {
1550
+ return path.replace(/\\/g, "/");
1551
+ }
1552
+ //#endregion
1553
+ //#region src/patcher/styleModulePatcher.ts
1554
+ const DEFAULT_CSS_IMPORT_SOURCES = [
1555
+ "../styled-system/css",
1556
+ "@/styled-system/css",
1557
+ "styled-system/css"
1558
+ ];
1559
+ function componentStyleModulePaths(options) {
1560
+ const parsed = parseSourceRef(options.componentSource, "Component style list requires a component source path with line and column.");
1561
+ if (!parsed.ok) return parsed;
1562
+ const root = normalizePath$1(options.projectRoot).replace(/\/$/, "");
1563
+ const componentFile = normalizePath$1(resolve(root, parsed.file));
1564
+ if (!root || componentFile !== root && !componentFile.startsWith(`${root}/`)) return {
1565
+ ok: false,
1566
+ code: "path-outside-project",
1567
+ message: "Component source path is outside the project root.",
1568
+ details: {
1569
+ componentSource: options.componentSource,
1570
+ projectRoot: root
1571
+ }
1572
+ };
1573
+ const extensionMatch = /\.(tsx|jsx|ts|js)$/.exec(componentFile);
1574
+ if (!extensionMatch) return {
1575
+ ok: false,
1576
+ code: "unsupported-source-shape",
1577
+ message: "Component style lists are only supported for TS/TSX/JS/JSX component modules.",
1578
+ details: { componentSource: options.componentSource }
1579
+ };
1580
+ const componentBase = componentFile.slice(0, -extensionMatch[0].length);
1581
+ const styleFile = `${componentBase}.style.ts`;
1582
+ return {
1583
+ ok: true,
1584
+ paths: {
1585
+ componentFile,
1586
+ styleFile,
1587
+ styleFileRelative: toRelativeProjectPath(styleFile, options.projectRoot),
1588
+ importPath: `./${componentBase.split("/").at(-1) ?? "styles"}.style`
1589
+ }
1590
+ };
1591
+ }
1592
+ function readComponentStyleModule(options) {
1593
+ const paths = componentStyleModulePaths(options);
1594
+ if (!paths.ok) return {
1595
+ ok: false,
1596
+ error: {
1597
+ code: paths.code,
1598
+ message: paths.message,
1599
+ details: paths.details
1600
+ }
1601
+ };
1602
+ if (options.sourceText === void 0) return {
1603
+ ok: true,
1604
+ componentFile: toRelativeProjectPath(paths.paths.componentFile, options.projectRoot),
1605
+ styleFile: paths.paths.styleFileRelative,
1606
+ importPath: paths.paths.importPath,
1607
+ exists: false,
1608
+ sources: []
1609
+ };
1610
+ const parsed = parseStyleModuleSource({
1611
+ projectRoot: options.projectRoot,
1612
+ filePath: paths.paths.styleFile,
1613
+ sourceText: options.sourceText,
1614
+ cssImportSources: options.cssImportSources
1615
+ });
1616
+ if (!parsed.ok) return {
1617
+ ok: false,
1618
+ error: {
1619
+ code: parsed.code,
1620
+ message: parsed.message,
1621
+ details: parsed.details
1622
+ }
1623
+ };
1624
+ return {
1625
+ ok: true,
1626
+ componentFile: toRelativeProjectPath(paths.paths.componentFile, options.projectRoot),
1627
+ styleFile: paths.paths.styleFileRelative,
1628
+ importPath: paths.paths.importPath,
1629
+ exists: true,
1630
+ sources: parsed.sources
1631
+ };
1632
+ }
1633
+ function createStyleModuleSourcePatch(options) {
1634
+ const nameFailure = validateStyleSourceName(options.request.name);
1635
+ if (nameFailure) return failure$1(options.request.editId, nameFailure.code, nameFailure.message);
1636
+ const initialStyleObject = styleObjectTextForSourceCreateEdits(options.request.edits);
1637
+ if (!initialStyleObject.ok) return failure$1(options.request.editId, initialStyleObject.code, initialStyleObject.message);
1638
+ if (options.sourceText === void 0) {
1639
+ const cssLocalName = "css";
1640
+ const nextSource = [
1641
+ cssImportText(cssLocalName, options.cssImportSources),
1642
+ "",
1643
+ "export default {",
1644
+ ` ${options.request.name}: ${cssLocalName}(${initialStyleObject.text}),`,
1645
+ "}",
1646
+ ""
1647
+ ].join("\n");
1648
+ const file = toRelativeProjectPath(options.filePath, options.projectRoot);
1649
+ return {
1650
+ ok: true,
1651
+ editId: options.request.editId,
1652
+ file,
1653
+ diff: nextFileDiff(file, nextSource),
1654
+ nextSource,
1655
+ written: false
1656
+ };
1657
+ }
1658
+ const sourceFile = ts.createSourceFile(options.filePath, options.sourceText, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
1659
+ const exportObject = findDefaultExportObject(sourceFile);
1660
+ if (!exportObject) return failure$1(options.request.editId, "unsupported-source-shape", "Style module sources require a direct export default { ... } object.");
1661
+ if (objectHasProperty(exportObject, options.request.name)) return failure$1(options.request.editId, "invalid-edit", "A style source with that name already exists.");
1662
+ const cssImport = findCssImportBinding(sourceFile, options.cssImportSources);
1663
+ const cssLocalName = cssImport?.localName ?? "css";
1664
+ const replacements = [{
1665
+ range: {
1666
+ start: exportObject.getEnd() - 1,
1667
+ end: exportObject.getEnd() - 1
1668
+ },
1669
+ text: `${exportObject.properties.length === 0 ? "\n" : ""} ${options.request.name}: ${cssLocalName}(${initialStyleObject.text}),\n`
1670
+ }];
1671
+ if (!cssImport) replacements.push({
1672
+ range: {
1673
+ start: importInsertionPosition(sourceFile),
1674
+ end: importInsertionPosition(sourceFile)
1675
+ },
1676
+ text: cssImportText(cssLocalName, options.cssImportSources)
1677
+ });
1678
+ const nextSource = applyReplacements$1(options.sourceText, replacements);
1679
+ const file = toRelativeProjectPath(options.filePath, options.projectRoot);
1680
+ return {
1681
+ ok: true,
1682
+ editId: options.request.editId,
1683
+ file,
1684
+ diff: focusedDiff$1(file, options.sourceText, nextSource, replacements),
1685
+ nextSource,
1686
+ written: false
1687
+ };
1688
+ }
1689
+ function createStyleModuleAttachPatch(options) {
1690
+ const nameFailure = validateStyleSourceName(options.request.name);
1691
+ if (nameFailure) return failure$1(options.request.editId, nameFailure.code, nameFailure.message);
1692
+ const parsed = parseSourceRef(options.request.jsxSource, "Style source attachment requires a JSX source path with line and column.");
1693
+ if (!parsed.ok) return failure$1(options.request.editId, parsed.code, parsed.message, parsed.details);
1694
+ const normalizedFile = normalizePath$1(options.filePath);
1695
+ if (normalizedFile !== normalizePath$1(`${options.projectRoot.replace(/\/$/, "")}/${parsed.file}`)) return failure$1(options.request.editId, "stale-source", "JSX source location points to a different file.", {
1696
+ filePath: normalizedFile,
1697
+ jsxSource: options.request.jsxSource
1698
+ });
1699
+ const paths = componentStyleModulePaths({
1700
+ projectRoot: options.projectRoot,
1701
+ componentSource: options.request.componentSource
1702
+ });
1703
+ if (!paths.ok) return failure$1(options.request.editId, paths.code, paths.message, paths.details);
1704
+ const sourceFile = ts.createSourceFile(options.filePath, options.sourceText, ts.ScriptTarget.Latest, true, options.filePath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
1705
+ const position = positionForLineColumn(sourceFile, parsed.line, parsed.column);
1706
+ if (position === void 0) return failure$1(options.request.editId, "stale-source", "JSX source location is outside the file.");
1707
+ const element = findJsxElementAtStart(sourceFile, position);
1708
+ if (!element) return failure$1(options.request.editId, "stale-source", "JSX source location no longer points to a JSX element.");
1709
+ const importState = stylesImportState(sourceFile, paths.paths.importPath);
1710
+ if (!importState.ok) return failure$1(options.request.editId, importState.code, importState.message, importState.details);
1711
+ const classReplacement = styleModuleAttributeReplacement(sourceFile, options.sourceText, element, options.request.name, options.styledSystemPackageName);
1712
+ if (!classReplacement.ok) return failure$1(options.request.editId, classReplacement.code, classReplacement.message, classReplacement.details);
1713
+ const replacements = [classReplacement.replacement, ...classReplacement.imports];
1714
+ if (!importState.exists) replacements.push({
1715
+ range: {
1716
+ start: importInsertionPosition(sourceFile),
1717
+ end: importInsertionPosition(sourceFile)
1718
+ },
1719
+ text: `import styles from '${paths.paths.importPath}'\n`
1720
+ });
1721
+ const nextSource = applyReplacements$1(options.sourceText, replacements);
1722
+ const file = toRelativeProjectPath(options.filePath, options.projectRoot);
1723
+ return {
1724
+ ok: true,
1725
+ editId: options.request.editId,
1726
+ file,
1727
+ diff: focusedDiff$1(file, options.sourceText, nextSource, replacements),
1728
+ nextSource,
1729
+ written: false
1730
+ };
1731
+ }
1732
+ function createStyleModuleDetachPatch(options) {
1733
+ const nameFailure = validateStyleSourceName(options.request.name);
1734
+ if (nameFailure) return failure$1(options.request.editId, nameFailure.code, nameFailure.message);
1735
+ const parsed = parseSourceRef(options.request.jsxSource, "Style source removal requires a JSX source path with line and column.");
1736
+ if (!parsed.ok) return failure$1(options.request.editId, parsed.code, parsed.message, parsed.details);
1737
+ const normalizedFile = normalizePath$1(options.filePath);
1738
+ if (normalizedFile !== normalizePath$1(`${options.projectRoot.replace(/\/$/, "")}/${parsed.file}`)) return failure$1(options.request.editId, "stale-source", "JSX source location points to a different file.", {
1739
+ filePath: normalizedFile,
1740
+ jsxSource: options.request.jsxSource
1741
+ });
1742
+ const sourceFile = ts.createSourceFile(options.filePath, options.sourceText, ts.ScriptTarget.Latest, true, options.filePath.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
1743
+ const position = positionForLineColumn(sourceFile, parsed.line, parsed.column);
1744
+ if (position === void 0) return failure$1(options.request.editId, "stale-source", "JSX source location is outside the file.");
1745
+ const element = findJsxElementAtStart(sourceFile, position);
1746
+ if (!element) return failure$1(options.request.editId, "stale-source", "JSX source location no longer points to a JSX element.");
1747
+ const replacement = styleModuleAttributeDetachReplacement(sourceFile, options.sourceText, element, options.request.name);
1748
+ if (!replacement) return failure$1(options.request.editId, "unsupported-operation", "The selected style source could not be removed from this class expression.");
1749
+ const nextSource = applyReplacements$1(options.sourceText, [replacement]);
1750
+ const file = toRelativeProjectPath(options.filePath, options.projectRoot);
1751
+ return {
1752
+ ok: true,
1753
+ editId: options.request.editId,
1754
+ file,
1755
+ diff: focusedDiff$1(file, options.sourceText, nextSource, [replacement]),
1756
+ nextSource,
1757
+ written: false
1758
+ };
1759
+ }
1760
+ function parseStyleModuleSource(options) {
1761
+ const exportObject = findDefaultExportObject(ts.createSourceFile(options.filePath, options.sourceText, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS));
1762
+ if (!exportObject) return {
1763
+ ok: false,
1764
+ code: "unsupported-source-shape",
1765
+ message: "Style module sources require a direct export default { ... } object."
1766
+ };
1767
+ const analysis = analyzePandaCssSource({
1768
+ projectRoot: options.projectRoot,
1769
+ filePath: options.filePath,
1770
+ sourceText: options.sourceText,
1771
+ cssImportSources: options.cssImportSources
1772
+ });
1773
+ const entryByName = new Map(analysis.entries.map((entry) => [entry.name, entry]));
1774
+ return {
1775
+ ok: true,
1776
+ sources: exportObject.properties.flatMap((property) => {
1777
+ if (!ts.isPropertyAssignment(property)) return [];
1778
+ const name = propertyNameText$1(property.name);
1779
+ if (!name) return [];
1780
+ if (!ts.isCallExpression(property.initializer)) return [];
1781
+ if (!ts.isObjectLiteralExpression(property.initializer.arguments[0])) return [];
1782
+ const entry = entryByName.get(name);
1783
+ return [{
1784
+ name,
1785
+ editId: entry?.id,
1786
+ file: toRelativeProjectPath(options.filePath, options.projectRoot),
1787
+ sourceHash: entry?.sourceHash,
1788
+ ...entry?.kind === "panda-css" ? { styleObject: entry.styleObject } : {}
1789
+ }];
1790
+ })
1791
+ };
1792
+ }
1793
+ function findDefaultExportObject(sourceFile) {
1794
+ for (const statement of sourceFile.statements) {
1795
+ if (!ts.isExportAssignment(statement) || statement.isExportEquals) continue;
1796
+ if (ts.isObjectLiteralExpression(statement.expression)) return statement.expression;
1797
+ }
1798
+ }
1799
+ function objectHasProperty(objectNode, name) {
1800
+ return objectNode.properties.some((property) => {
1801
+ if (!ts.isPropertyAssignment(property)) return false;
1802
+ return propertyNameText$1(property.name) === name;
1803
+ });
1804
+ }
1805
+ function styleObjectTextForSourceCreateEdits(edits) {
1806
+ if (!edits || edits.length === 0) return {
1807
+ ok: true,
1808
+ text: "{}"
1809
+ };
1810
+ const properties = [];
1811
+ for (const edit of edits) {
1812
+ if (edit.op !== "set") return {
1813
+ ok: false,
1814
+ code: "invalid-edit",
1815
+ message: "New style sources only support setting initial properties."
1816
+ };
1817
+ if (edit.path.length !== 1) return {
1818
+ ok: false,
1819
+ code: "unsupported-operation",
1820
+ message: "New style sources only support top-level initial properties."
1821
+ };
1822
+ const property = edit.path[0];
1823
+ if (!property || !/^[A-Za-z_$][\w$]*$/.test(property)) return {
1824
+ ok: false,
1825
+ code: "invalid-edit",
1826
+ message: "New style source property names must be valid identifiers."
1827
+ };
1828
+ properties.push(`${property}: ${JSON.stringify(edit.value)}`);
1829
+ }
1830
+ return {
1831
+ ok: true,
1832
+ text: `{ ${properties.join(", ")} }`
1833
+ };
1834
+ }
1835
+ function propertyNameText$1(name) {
1836
+ if (ts.isIdentifier(name)) return name.text;
1837
+ if (ts.isStringLiteral(name) || ts.isNumericLiteral(name)) return name.text;
1838
+ }
1839
+ function styleModuleAttributeReplacement(sourceFile, sourceText, element, name, styledSystemPackageName) {
1840
+ let classAttribute;
1841
+ for (const property of element.attributes.properties) {
1842
+ if (!ts.isJsxAttribute(property) || !ts.isIdentifier(property.name)) continue;
1843
+ if (property.name.text !== "class" && property.name.text !== "className") continue;
1844
+ classAttribute = property;
1845
+ break;
1846
+ }
1847
+ const styleReference = `styles.${name}`;
1848
+ if (!classAttribute) {
1849
+ const insertPosition = element.getEnd() - (ts.isJsxSelfClosingElement(element) ? 2 : 1);
1850
+ return {
1851
+ ok: true,
1852
+ replacement: {
1853
+ range: {
1854
+ start: insertPosition,
1855
+ end: insertPosition
1856
+ },
1857
+ text: ` class={${styleReference}}`
1858
+ },
1859
+ imports: []
1860
+ };
1861
+ }
1862
+ const attributeName = ts.isIdentifier(classAttribute.name) ? classAttribute.name.text : "class";
1863
+ if (!classAttribute.initializer) return {
1864
+ ok: true,
1865
+ replacement: {
1866
+ range: {
1867
+ start: classAttribute.getStart(sourceFile),
1868
+ end: classAttribute.getEnd()
1869
+ },
1870
+ text: `${attributeName}={${styleReference}}`
1871
+ },
1872
+ imports: []
1873
+ };
1874
+ const cx = cxImportState(sourceFile, sourceText, styledSystemPackageName);
1875
+ if (!cx.ok) return cx;
1876
+ if (ts.isStringLiteral(classAttribute.initializer)) return {
1877
+ ok: true,
1878
+ replacement: {
1879
+ range: {
1880
+ start: classAttribute.getStart(sourceFile),
1881
+ end: classAttribute.getEnd()
1882
+ },
1883
+ text: `${attributeName}={${cx.localName}(${JSON.stringify(classAttribute.initializer.text)}, ${styleReference})}`
1884
+ },
1885
+ imports: cx.imports
1886
+ };
1887
+ const expression = jsxAttributeExpression(classAttribute.initializer);
1888
+ if (!expression) return {
1889
+ ok: true,
1890
+ replacement: {
1891
+ range: {
1892
+ start: classAttribute.getStart(sourceFile),
1893
+ end: classAttribute.getEnd()
1894
+ },
1895
+ text: `${attributeName}={${styleReference}}`
1896
+ },
1897
+ imports: []
1898
+ };
1899
+ const expressionText = sourceText.slice(expression.getStart(sourceFile), expression.getEnd());
1900
+ const cxArgs = cxCallArguments(sourceFile, sourceText, expression, cx.localName, styleReference);
1901
+ return {
1902
+ ok: true,
1903
+ replacement: {
1904
+ range: {
1905
+ start: classAttribute.getStart(sourceFile),
1906
+ end: classAttribute.getEnd()
1907
+ },
1908
+ text: `${attributeName}={${cx.localName}(${cxArgs ?? `${expressionText}, ${styleReference}`})}`
1909
+ },
1910
+ imports: cx.imports
1911
+ };
1912
+ }
1913
+ function styleModuleAttributeDetachReplacement(sourceFile, sourceText, element, name) {
1914
+ let classAttribute;
1915
+ for (const property of element.attributes.properties) {
1916
+ if (!ts.isJsxAttribute(property) || !ts.isIdentifier(property.name)) continue;
1917
+ if (property.name.text !== "class" && property.name.text !== "className") continue;
1918
+ classAttribute = property;
1919
+ break;
1920
+ }
1921
+ if (!classAttribute?.initializer) return void 0;
1922
+ const expression = jsxAttributeExpression(classAttribute.initializer);
1923
+ if (!expression) return void 0;
1924
+ const styleReference = `styles.${name}`;
1925
+ const attributeName = ts.isIdentifier(classAttribute.name) ? classAttribute.name.text : "class";
1926
+ const replacementText = classExpressionAfterStyleReferenceRemoval(sourceFile, sourceText, expression, styleReference);
1927
+ if (replacementText === void 0) return void 0;
1928
+ return {
1929
+ range: {
1930
+ start: classAttribute.getStart(sourceFile),
1931
+ end: classAttribute.getEnd()
1932
+ },
1933
+ text: replacementText === "" ? "" : `${attributeName}={${replacementText}}`
1934
+ };
1935
+ }
1936
+ function cxImportState(sourceFile, sourceText, styledSystemPackageName) {
1937
+ const moduleSpecifier = `${styledSystemPackageName ?? "styled-system"}/css`;
1938
+ for (const statement of sourceFile.statements) {
1939
+ if (!ts.isImportDeclaration(statement)) continue;
1940
+ if (!ts.isStringLiteral(statement.moduleSpecifier)) continue;
1941
+ if (statement.moduleSpecifier.text !== moduleSpecifier) continue;
1942
+ const namedBindings = statement.importClause?.namedBindings;
1943
+ if (!namedBindings || !ts.isNamedImports(namedBindings)) return {
1944
+ ok: false,
1945
+ code: "unsupported-operation",
1946
+ message: "The styled-system css import must use named imports before cx can be added.",
1947
+ details: { moduleSpecifier }
1948
+ };
1949
+ for (const element of namedBindings.elements) if ((element.propertyName?.text ?? element.name.text) === "cx") return {
1950
+ ok: true,
1951
+ localName: element.name.text,
1952
+ imports: []
1953
+ };
1954
+ return {
1955
+ ok: true,
1956
+ localName: "cx",
1957
+ imports: [{
1958
+ range: {
1959
+ start: namedBindings.elements.end,
1960
+ end: namedBindings.elements.end
1961
+ },
1962
+ text: `${namedBindings.elements.length === 0 ? "" : ","} cx`
1963
+ }]
1964
+ };
1965
+ }
1966
+ if (identifierExists(sourceFile, "cx")) return {
1967
+ ok: false,
1968
+ code: "unsupported-operation",
1969
+ message: "The component module already uses the cx name.",
1970
+ details: { moduleSpecifier }
1971
+ };
1972
+ return {
1973
+ ok: true,
1974
+ localName: "cx",
1975
+ imports: [{
1976
+ range: {
1977
+ start: importInsertionPosition(sourceFile),
1978
+ end: importInsertionPosition(sourceFile)
1979
+ },
1980
+ text: `import { cx } from '${moduleSpecifier}'\n`
1981
+ }]
1982
+ };
1983
+ }
1984
+ function cxCallArguments(sourceFile, sourceText, expression, cxLocalName, styleReference) {
1985
+ if (!ts.isCallExpression(expression)) return void 0;
1986
+ if (!ts.isIdentifier(expression.expression) || expression.expression.text !== cxLocalName) return;
1987
+ return [...expression.arguments.map((argument) => sourceTextForNode(sourceFile, sourceText, argument)), styleReference].join(", ");
1988
+ }
1989
+ function identifierExists(sourceFile, name) {
1990
+ let exists = false;
1991
+ const visit = (node) => {
1992
+ if (exists) return;
1993
+ if (ts.isIdentifier(node) && node.text === name) {
1994
+ exists = true;
1995
+ return;
1996
+ }
1997
+ ts.forEachChild(node, visit);
1998
+ };
1999
+ visit(sourceFile);
2000
+ return exists;
2001
+ }
2002
+ function classExpressionAfterStyleReferenceRemoval(sourceFile, sourceText, expression, styleReference) {
2003
+ if (sourceTextForNode(sourceFile, sourceText, expression) === styleReference) return "";
2004
+ if (ts.isCallExpression(expression) && ts.isIdentifier(expression.expression) && expression.expression.text === "cx") {
2005
+ const remaining = expression.arguments.filter((argument) => sourceTextForNode(sourceFile, sourceText, argument) !== styleReference);
2006
+ if (remaining.length === expression.arguments.length) return void 0;
2007
+ if (remaining.length === 0) return "";
2008
+ if (remaining.length === 1) return sourceTextForNode(sourceFile, sourceText, remaining[0]);
2009
+ const remainingText = remaining.map((argument) => sourceTextForNode(sourceFile, sourceText, argument)).join(", ");
2010
+ return `${expression.expression.text}(${remainingText})`;
2011
+ }
2012
+ const array = ts.isArrayLiteralExpression(expression) ? expression : arrayLiteralFromClassJoinExpression(expression);
2013
+ if (!array || !ts.isArrayLiteralExpression(array)) return void 0;
2014
+ const remaining = array.elements.filter((element) => sourceTextForNode(sourceFile, sourceText, element) !== styleReference);
2015
+ if (remaining.length === array.elements.length) return void 0;
2016
+ if (remaining.length === 0) return "";
2017
+ if (remaining.length === 1) return sourceTextForNode(sourceFile, sourceText, remaining[0]);
2018
+ return `[${remaining.map((element) => sourceTextForNode(sourceFile, sourceText, element)).join(", ")}].filter(Boolean).join(' ')`;
2019
+ }
2020
+ function arrayLiteralFromClassJoinExpression(expression) {
2021
+ if (!ts.isCallExpression(expression)) return void 0;
2022
+ if (!ts.isPropertyAccessExpression(expression.expression)) return void 0;
2023
+ if (expression.expression.name.text !== "join") return void 0;
2024
+ const filterCall = expression.expression.expression;
2025
+ if (!ts.isCallExpression(filterCall)) return void 0;
2026
+ if (!ts.isPropertyAccessExpression(filterCall.expression)) return void 0;
2027
+ if (filterCall.expression.name.text !== "filter") return void 0;
2028
+ if (!ts.isIdentifier(filterCall.arguments[0]) || filterCall.arguments[0].text !== "Boolean") return;
2029
+ const array = filterCall.expression.expression;
2030
+ return ts.isArrayLiteralExpression(array) ? array : void 0;
2031
+ }
2032
+ function sourceTextForNode(sourceFile, sourceText, node) {
2033
+ return sourceText.slice(node.getStart(sourceFile), node.getEnd());
2034
+ }
2035
+ function stylesImportState(sourceFile, importPath) {
2036
+ for (const statement of sourceFile.statements) {
2037
+ if (!ts.isImportDeclaration(statement)) continue;
2038
+ const defaultImport = statement.importClause?.name;
2039
+ if (!defaultImport || defaultImport.text !== "styles") continue;
2040
+ if (ts.isStringLiteral(statement.moduleSpecifier) && statement.moduleSpecifier.text === importPath) return {
2041
+ ok: true,
2042
+ exists: true
2043
+ };
2044
+ return {
2045
+ ok: false,
2046
+ code: "unsupported-operation",
2047
+ message: "The component module already uses the styles import name for another module.",
2048
+ details: { importPath }
2049
+ };
2050
+ }
2051
+ let hasStylesIdentifier = false;
2052
+ const visit = (node) => {
2053
+ if (hasStylesIdentifier) return;
2054
+ if (ts.isIdentifier(node) && node.text === "styles") {
2055
+ hasStylesIdentifier = true;
2056
+ return;
2057
+ }
2058
+ ts.forEachChild(node, visit);
2059
+ };
2060
+ visit(sourceFile);
2061
+ if (hasStylesIdentifier) return {
2062
+ ok: false,
2063
+ code: "unsupported-operation",
2064
+ message: "The component module already uses the styles name.",
2065
+ details: { importPath }
2066
+ };
2067
+ return {
2068
+ ok: true,
2069
+ exists: false
2070
+ };
2071
+ }
2072
+ function findCssImportBinding(sourceFile, cssImportSources) {
2073
+ const importSources = new Set(cssImportSources ?? DEFAULT_CSS_IMPORT_SOURCES);
2074
+ for (const statement of sourceFile.statements) {
2075
+ if (!ts.isImportDeclaration(statement)) continue;
2076
+ if (!ts.isStringLiteral(statement.moduleSpecifier)) continue;
2077
+ if (!importSources.has(statement.moduleSpecifier.text)) continue;
2078
+ const namedBindings = statement.importClause?.namedBindings;
2079
+ if (!namedBindings || !ts.isNamedImports(namedBindings)) continue;
2080
+ for (const element of namedBindings.elements) if ((element.propertyName?.text ?? element.name.text) === "css") return { localName: element.name.text };
2081
+ }
2082
+ }
2083
+ function jsxAttributeExpression(initializer) {
2084
+ if (ts.isJsxExpression(initializer)) return initializer.expression;
2085
+ }
2086
+ function findJsxElementAtStart(sourceFile, position) {
2087
+ let result;
2088
+ const visit = (node) => {
2089
+ if (result) return;
2090
+ if ((ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) && node.getStart(sourceFile) === position) {
2091
+ result = node;
2092
+ return;
2093
+ }
2094
+ ts.forEachChild(node, visit);
2095
+ };
2096
+ visit(sourceFile);
2097
+ return result;
2098
+ }
2099
+ function importInsertionPosition(sourceFile) {
2100
+ let position = 0;
2101
+ for (const statement of sourceFile.statements) {
2102
+ if (!ts.isImportDeclaration(statement)) break;
2103
+ position = statement.getEnd();
2104
+ }
2105
+ return position === 0 ? 0 : position + 1;
2106
+ }
2107
+ function cssImportText(cssLocalName, cssImportSources) {
2108
+ const moduleSpecifier = cssImportSources?.[0] ?? DEFAULT_CSS_IMPORT_SOURCES[0];
2109
+ return `import { ${cssLocalName === "css" ? "css" : `css as ${cssLocalName}`} } from '${moduleSpecifier}'\n`;
2110
+ }
2111
+ function parseSourceRef(source, message) {
2112
+ const match = /^(.*):(\d+):(\d+)$/.exec(source.trim());
2113
+ const file = match?.[1]?.trim();
2114
+ const line = match?.[2] ? Number.parseInt(match[2], 10) : void 0;
2115
+ const column = match?.[3] ? Number.parseInt(match[3], 10) : void 0;
2116
+ if (!match || !file || line === void 0 || column === void 0 || line < 1 || column < 1) return {
2117
+ ok: false,
2118
+ code: "invalid-edit",
2119
+ message,
2120
+ details: { source }
2121
+ };
2122
+ return {
2123
+ ok: true,
2124
+ file,
2125
+ line,
2126
+ column
2127
+ };
2128
+ }
2129
+ function positionForLineColumn(sourceFile, line, column) {
2130
+ const lineStart = sourceFile.getLineStarts()[line - 1];
2131
+ if (lineStart === void 0) return void 0;
2132
+ const position = lineStart + column - 1;
2133
+ return position <= sourceFile.text.length ? position : void 0;
2134
+ }
2135
+ function validateStyleSourceName(name) {
2136
+ if (/^[A-Za-z_$][\w$]*$/.test(name)) return void 0;
2137
+ return {
2138
+ code: "invalid-edit",
2139
+ message: "Style source names must be valid JavaScript identifiers."
2140
+ };
2141
+ }
2142
+ function applyReplacements$1(sourceText, replacements) {
2143
+ let nextSource = sourceText;
2144
+ for (const replacement of [...replacements].sort((left, right) => right.range.start - left.range.start)) nextSource = `${nextSource.slice(0, replacement.range.start)}${replacement.text}${nextSource.slice(replacement.range.end)}`;
2145
+ return nextSource;
2146
+ }
2147
+ function nextFileDiff(file, nextSource) {
2148
+ return [
2149
+ `--- /dev/null`,
2150
+ `+++ b/${file}`,
2151
+ ...nextSource.split("\n").map((line) => `+${line}`)
2152
+ ].join("\n");
2153
+ }
2154
+ function focusedDiff$1(file, sourceText, nextSource, replacements) {
2155
+ const firstStart = Math.min(...replacements.map((replacement) => replacement.range.start));
2156
+ const lastEnd = Math.max(...replacements.map((replacement) => replacement.range.end));
2157
+ const oldStartLine = lineNumberAt$1(sourceText, firstStart);
2158
+ const oldEndLine = lineNumberAt$1(sourceText, lastEnd);
2159
+ const contextStartLine = Math.max(1, oldStartLine - 2);
2160
+ const contextEndLine = oldEndLine + 2;
2161
+ const oldLines = sourceText.split("\n");
2162
+ const newLines = nextSource.split("\n");
2163
+ const oldSlice = oldLines.slice(contextStartLine - 1, contextEndLine);
2164
+ const newSlice = newLines.slice(contextStartLine - 1, contextEndLine + (newLines.length - oldLines.length));
2165
+ return [
2166
+ `--- a/${file}`,
2167
+ `+++ b/${file}`,
2168
+ `@@ -${contextStartLine},${oldSlice.length} +${contextStartLine},${newSlice.length} @@`,
2169
+ ...oldSlice.map((line) => `-${line}`),
2170
+ ...newSlice.map((line) => `+${line}`)
2171
+ ].join("\n");
2172
+ }
2173
+ function lineNumberAt$1(sourceText, position) {
2174
+ let line = 1;
2175
+ for (let index = 0; index < position; index += 1) if (sourceText.charCodeAt(index) === 10) line += 1;
2176
+ return line;
2177
+ }
2178
+ function normalizePath$1(path) {
2179
+ return path.replace(/\\/g, "/");
2180
+ }
2181
+ function failure$1(editId, code, message, details) {
2182
+ return {
2183
+ ok: false,
2184
+ editId,
2185
+ written: false,
2186
+ error: {
2187
+ code,
2188
+ message,
2189
+ details
2190
+ }
2191
+ };
2192
+ }
2193
+ //#endregion
2194
+ //#region src/patcher/tokenConfigPatcher.ts
2195
+ function createTokenConfigPatch(options) {
2196
+ const { request, sourceText, tokenSource } = options;
2197
+ const validation = validateTokenPatchRequest(options);
2198
+ if (validation) return failure(request.editId, validation.code, validation.message, validation.details);
2199
+ const range = tokenSource.range ?? rangeFromTokenSourceId(tokenSource.id);
2200
+ if (!range) return failure(request.editId, "unsupported-source-shape", "Token source target does not include a source range.");
2201
+ if (hashSource(sourceText.slice(range.start, range.end)) !== tokenSource.sourceHash) return failure(request.editId, "stale-source", "Source text no longer matches the token source hash.");
2202
+ if (request.options?.expectedSourceHash && request.options.expectedSourceHash !== tokenSource.sourceHash) return failure(request.editId, "stale-source", "Edit request was prepared against a different token source hash.", {
2203
+ expectedSourceHash: request.options.expectedSourceHash,
2204
+ actualSourceHash: tokenSource.sourceHash
2205
+ });
2206
+ const sourceFile = ts.createSourceFile(tokenSource.absoluteFile ?? tokenSource.file, sourceText, ts.ScriptTarget.Latest, true, tokenSource.file.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
2207
+ const objectNode = findObjectLiteralAtRange(sourceFile, range);
2208
+ if (!objectNode) return failure(request.editId, "stale-source", "Token source range no longer points to an object literal.");
2209
+ const safety = tokenObjectWriteSafety(objectNode);
2210
+ if (!safety.writable) return failure(request.editId, "unsupported-source-shape", safety.reason);
2211
+ const replacement = replacementForTokenPath(objectNode, request, sourceFile, sourceText);
2212
+ if (!replacement.ok) return failure(request.editId, replacement.reason.code, replacement.reason.message, replacement.reason.details);
2213
+ const nextSource = applyReplacements(sourceText, [replacement.replacement]);
2214
+ return {
2215
+ ok: true,
2216
+ editId: request.editId,
2217
+ file: tokenSource.file,
2218
+ diff: focusedDiff(tokenSource.file, sourceText, nextSource, [replacement.replacement]),
2219
+ nextSource,
2220
+ written: false
2221
+ };
2222
+ }
2223
+ function validateTokenPatchRequest(options) {
2224
+ const { projectRoot, request, tokenSource } = options;
2225
+ if (request.kind !== "panda-token-config") return {
2226
+ code: "unsupported-operation",
2227
+ message: "Only Panda token config edits can be patched."
2228
+ };
2229
+ if (request.sourceTargetId !== tokenSource.id) return {
2230
+ code: "manifest-entry-not-found",
2231
+ message: "Token edit request does not match the provided token source target.",
2232
+ details: { sourceTargetId: request.sourceTargetId }
2233
+ };
2234
+ if (!tokenSource.writable || !tokenSource.writableSections.includes(request.section)) return {
2235
+ code: "unsupported-source-shape",
2236
+ message: tokenSource.readonlyReason ?? "Token source is not writable."
2237
+ };
2238
+ if (request.path.length === 0 || request.path.some((part) => part.length === 0)) return {
2239
+ code: "invalid-path",
2240
+ message: "Token edits require a non-empty token path.",
2241
+ details: { path: [...request.path] }
2242
+ };
2243
+ if (!isJsonPrimitive(request.value)) return {
2244
+ code: "unsupported-operation",
2245
+ message: "Token config patching only supports literal primitive values.",
2246
+ details: { path: [...request.path] }
2247
+ };
2248
+ return validateProjectFile(projectRoot, tokenSource, options.filePath);
2249
+ }
2250
+ function validateProjectFile(projectRoot, tokenSource, filePath) {
2251
+ const root = normalizePath(projectRoot).replace(/\/$/, "");
2252
+ if (!root) return {
2253
+ code: "path-outside-project",
2254
+ message: "Project root is empty."
2255
+ };
2256
+ const absoluteFile = normalizePath(tokenSource.absoluteFile ?? `${root}/${tokenSource.file}`);
2257
+ if (absoluteFile !== root && !absoluteFile.startsWith(`${root}/`)) return {
2258
+ code: "path-outside-project",
2259
+ message: "Token source points outside the project root.",
2260
+ details: {
2261
+ file: absoluteFile,
2262
+ projectRoot: root
2263
+ }
2264
+ };
2265
+ if (filePath && normalizePath(filePath) !== absoluteFile) return {
2266
+ code: "stale-source",
2267
+ message: "Provided source file does not match the token source file.",
2268
+ details: {
2269
+ filePath: normalizePath(filePath),
2270
+ tokenSourceFile: absoluteFile
2271
+ }
2272
+ };
2273
+ }
2274
+ function replacementForTokenPath(objectNode, request, sourceFile, sourceText) {
2275
+ let current = objectNode;
2276
+ const { path } = request;
2277
+ for (let index = 0; index < path.length; index += 1) {
2278
+ const part = path[index];
2279
+ const located = locateProperty(current, part);
2280
+ if (!located.ok) {
2281
+ if (located.reason.code === "invalid-path") return {
2282
+ ok: true,
2283
+ replacement: insertionForMissingTokenPath(current, path.slice(index), request.value, sourceFile, sourceText)
2284
+ };
2285
+ return {
2286
+ ok: false,
2287
+ reason: located.reason
2288
+ };
2289
+ }
2290
+ const initializer = located.property.initializer;
2291
+ const tokenObject = objectLiteralExpression(initializer);
2292
+ if (!tokenObject) return {
2293
+ ok: false,
2294
+ reason: {
2295
+ code: "unsupported-source-shape",
2296
+ message: "Token path descends through a non-object value.",
2297
+ details: { path: path.slice(0, index + 1) }
2298
+ }
2299
+ };
2300
+ if (index === path.length - 1) {
2301
+ const valueProperty = locateProperty(tokenObject, "value");
2302
+ if (!valueProperty.ok) return {
2303
+ ok: true,
2304
+ replacement: insertionForMissingProperty(tokenObject, "value", literalSource(request.value), sourceFile, sourceText)
2305
+ };
2306
+ const valueInitializer = valueProperty.property.initializer;
2307
+ if (!isPatchableLiteral(valueInitializer)) return {
2308
+ ok: false,
2309
+ reason: {
2310
+ code: "unsupported-source-shape",
2311
+ message: "Existing token value is not a literal primitive.",
2312
+ details: { path: [...path] }
2313
+ }
2314
+ };
2315
+ return {
2316
+ ok: true,
2317
+ replacement: {
2318
+ range: {
2319
+ start: valueInitializer.getStart(sourceFile),
2320
+ end: valueInitializer.getEnd()
2321
+ },
2322
+ text: literalSource(request.value)
2323
+ }
2324
+ };
2325
+ }
2326
+ if (locateProperty(tokenObject, "value").ok) return {
2327
+ ok: false,
2328
+ reason: {
2329
+ code: "invalid-path",
2330
+ message: "Token path descends through an existing token leaf.",
2331
+ details: { path: path.slice(0, index + 1) }
2332
+ }
2333
+ };
2334
+ current = tokenObject;
2335
+ }
2336
+ return {
2337
+ ok: false,
2338
+ reason: {
2339
+ code: "invalid-path",
2340
+ message: "Token edits require a non-empty token path."
2341
+ }
2342
+ };
2343
+ }
2344
+ function insertionForMissingTokenPath(objectNode, missingPath, value, sourceFile, sourceText) {
2345
+ const multiline = sourceText.slice(objectNode.getStart(sourceFile), objectNode.getEnd()).includes("\n");
2346
+ const fallbackChildIndent = `${indentationBefore(sourceText, objectNode.getStart(sourceFile))} `;
2347
+ const lastProperty = objectNode.properties[objectNode.properties.length - 1];
2348
+ return insertionForMissingProperty(objectNode, tokenBranchSource(missingPath, value, multiline, lastProperty ? indentationBefore(sourceText, lastProperty.getStart(sourceFile)) : fallbackChildIndent), void 0, sourceFile, sourceText);
2349
+ }
2350
+ function insertionForMissingProperty(objectNode, propertyNameOrSource, valueSource, sourceFile, sourceText) {
2351
+ const closeBrace = objectNode.getEnd() - 1;
2352
+ const multiline = sourceText.slice(objectNode.getStart(sourceFile), objectNode.getEnd()).includes("\n");
2353
+ const property = valueSource ? `${propertyNameSource(propertyNameOrSource)}: ${valueSource}` : propertyNameOrSource;
2354
+ if (objectNode.properties.length === 0) {
2355
+ if (!multiline) return {
2356
+ range: {
2357
+ start: closeBrace,
2358
+ end: closeBrace
2359
+ },
2360
+ text: property
2361
+ };
2362
+ const parentIndent = indentationBefore(sourceText, objectNode.getStart(sourceFile));
2363
+ const childIndent = `${parentIndent} `;
2364
+ return {
2365
+ range: {
2366
+ start: closeBrace,
2367
+ end: closeBrace
2368
+ },
2369
+ text: `\n${childIndent}${property},\n${parentIndent}`
2370
+ };
2371
+ }
2372
+ const lastProperty = objectNode.properties[objectNode.properties.length - 1];
2373
+ const trailingComma = commaAfterNode(lastProperty, objectNode, sourceText);
2374
+ if (!multiline) {
2375
+ const insertAt = trailingComma ?? lastProperty.getEnd();
2376
+ return {
2377
+ range: {
2378
+ start: insertAt,
2379
+ end: insertAt
2380
+ },
2381
+ text: trailingComma === void 0 ? `, ${property}` : ` ${property}`
2382
+ };
2383
+ }
2384
+ const childIndent = indentationBefore(sourceText, lastProperty.getStart(sourceFile));
2385
+ if (trailingComma !== void 0) return {
2386
+ range: {
2387
+ start: trailingComma + 1,
2388
+ end: trailingComma + 1
2389
+ },
2390
+ text: `\n${childIndent}${property},`
2391
+ };
2392
+ return {
2393
+ range: {
2394
+ start: lastProperty.getEnd(),
2395
+ end: lastProperty.getEnd()
2396
+ },
2397
+ text: `,\n${childIndent}${property}`
2398
+ };
2399
+ }
2400
+ function tokenBranchSource(path, value, multiline, indent) {
2401
+ const [first, ...rest] = path;
2402
+ if (!first) return "";
2403
+ if (rest.length === 0) return `${propertyNameSource(first)}: { value: ${literalSource(value)} }`;
2404
+ if (!multiline) return `${propertyNameSource(first)}: { ${tokenBranchSource(rest, value, false, indent)} }`;
2405
+ const childIndent = `${indent} `;
2406
+ const nested = tokenBranchSource(rest, value, true, childIndent);
2407
+ return `${propertyNameSource(first)}: {\n${childIndent}${nested},\n${indent}}`;
2408
+ }
2409
+ function findObjectLiteralAtRange(sourceFile, range) {
2410
+ let result;
2411
+ const visit = (node) => {
2412
+ if (ts.isObjectLiteralExpression(node) && node.getStart(sourceFile) === range.start && node.getEnd() === range.end) {
2413
+ result = node;
2414
+ return;
2415
+ }
2416
+ ts.forEachChild(node, visit);
2417
+ };
2418
+ visit(sourceFile);
2419
+ return result;
2420
+ }
2421
+ function tokenObjectWriteSafety(object) {
2422
+ const keys = /* @__PURE__ */ new Set();
2423
+ for (const property of object.properties) {
2424
+ if (!ts.isPropertyAssignment(property)) return {
2425
+ writable: false,
2426
+ reason: "Token object contains a spread, shorthand, method, or accessor."
2427
+ };
2428
+ const key = propertyNameText(property.name);
2429
+ if (!key) return {
2430
+ writable: false,
2431
+ reason: "Token object contains a computed key."
2432
+ };
2433
+ if (keys.has(key)) return {
2434
+ writable: false,
2435
+ reason: "Token object contains duplicate keys."
2436
+ };
2437
+ keys.add(key);
2438
+ const valueObject = objectLiteralExpression(property.initializer);
2439
+ if (!valueObject) return {
2440
+ writable: false,
2441
+ reason: "Token object contains a non-object token branch."
2442
+ };
2443
+ if (!objectProperty(valueObject, "value")) {
2444
+ const nestedSafety = tokenObjectWriteSafety(valueObject);
2445
+ if (!nestedSafety.writable) return nestedSafety;
2446
+ }
2447
+ }
2448
+ return { writable: true };
2449
+ }
2450
+ function locateProperty(objectNode, propertyName) {
2451
+ const matches = [];
2452
+ for (const property of objectNode.properties) {
2453
+ if (!ts.isPropertyAssignment(property)) return {
2454
+ ok: false,
2455
+ reason: {
2456
+ code: "unsupported-source-shape",
2457
+ message: "Only plain property assignments can be patched."
2458
+ }
2459
+ };
2460
+ const name = propertyNameText(property.name);
2461
+ if (name === void 0) return {
2462
+ ok: false,
2463
+ reason: {
2464
+ code: "unsupported-source-shape",
2465
+ message: "Computed property names are not safe to patch."
2466
+ }
2467
+ };
2468
+ if (name === propertyName) matches.push(property);
2469
+ }
2470
+ if (matches.length > 1) return {
2471
+ ok: false,
2472
+ reason: {
2473
+ code: "ambiguous-target",
2474
+ message: "Token source contains duplicate keys for the requested path.",
2475
+ details: { property: propertyName }
2476
+ }
2477
+ };
2478
+ const property = matches[0];
2479
+ if (!property) return {
2480
+ ok: false,
2481
+ reason: {
2482
+ code: "invalid-path",
2483
+ message: "Token source does not contain the requested path.",
2484
+ details: { property: propertyName }
2485
+ }
2486
+ };
2487
+ return {
2488
+ ok: true,
2489
+ property
2490
+ };
2491
+ }
2492
+ function objectProperty(objectNode, propertyName) {
2493
+ for (const property of objectNode.properties) {
2494
+ if (!ts.isPropertyAssignment(property)) continue;
2495
+ if (propertyNameText(property.name) === propertyName) return property.initializer;
2496
+ }
2497
+ }
2498
+ function objectLiteralExpression(expression) {
2499
+ if (ts.isObjectLiteralExpression(expression)) return expression;
2500
+ if (ts.isSatisfiesExpression(expression) || ts.isAsExpression(expression)) return objectLiteralExpression(expression.expression);
2501
+ }
2502
+ function propertyNameText(name) {
2503
+ if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) return name.text;
2504
+ }
2505
+ function isPatchableLiteral(node) {
2506
+ return ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node) || ts.isNumericLiteral(node) || node.kind === ts.SyntaxKind.TrueKeyword || node.kind === ts.SyntaxKind.FalseKeyword || node.kind === ts.SyntaxKind.NullKeyword || ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(node.operand);
2507
+ }
2508
+ function isJsonPrimitive(value) {
2509
+ return value === null || [
2510
+ "string",
2511
+ "number",
2512
+ "boolean"
2513
+ ].includes(typeof value);
2514
+ }
2515
+ function literalSource(value) {
2516
+ if (typeof value === "string") return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
2517
+ if (typeof value === "number") return Number.isFinite(value) ? String(value) : "null";
2518
+ if (typeof value === "boolean") return value ? "true" : "false";
2519
+ return "null";
2520
+ }
2521
+ function propertyNameSource(propertyName) {
2522
+ if (/^\d+$/.test(propertyName)) return propertyName;
2523
+ return /^[$A-Z_a-z][$\w]*$/.test(propertyName) ? propertyName : JSON.stringify(propertyName);
2524
+ }
2525
+ function commaAfterNode(node, objectNode, sourceText) {
2526
+ for (let index = node.getEnd(); index < objectNode.getEnd() - 1; index += 1) {
2527
+ const char = sourceText[index];
2528
+ if (char === ",") return index;
2529
+ if (!isWhitespace(char)) return void 0;
2530
+ }
2531
+ }
2532
+ function isWhitespace(char) {
2533
+ return char === " " || char === " " || char === "\n" || char === "\r";
2534
+ }
2535
+ function indentationBefore(sourceText, position) {
2536
+ const lineStart = sourceText.lastIndexOf("\n", position - 1) + 1;
2537
+ return sourceText.slice(lineStart, position).match(/^[ \t]*/)?.[0] ?? "";
2538
+ }
2539
+ function rangeFromTokenSourceId(id) {
2540
+ const parts = id.split("#");
2541
+ const start = Number(parts[parts.length - 2]);
2542
+ const end = Number(parts[parts.length - 1]);
2543
+ if (!Number.isInteger(start) || !Number.isInteger(end) || start < 0 || end < start) return;
2544
+ return {
2545
+ start,
2546
+ end
2547
+ };
2548
+ }
2549
+ function applyReplacements(sourceText, replacements) {
2550
+ let nextSource = sourceText;
2551
+ for (const replacement of [...replacements].sort((left, right) => right.range.start - left.range.start)) nextSource = `${nextSource.slice(0, replacement.range.start)}${replacement.text}${nextSource.slice(replacement.range.end)}`;
2552
+ return nextSource;
2553
+ }
2554
+ function focusedDiff(file, sourceText, nextSource, replacements) {
2555
+ const firstStart = Math.min(...replacements.map((replacement) => replacement.range.start));
2556
+ const lastEnd = Math.max(...replacements.map((replacement) => replacement.range.end));
2557
+ const oldStartLine = lineNumberAt(sourceText, firstStart);
2558
+ const oldEndLine = lineNumberAt(sourceText, lastEnd);
2559
+ const contextStartLine = Math.max(1, oldStartLine - 2);
2560
+ const contextEndLine = oldEndLine + 2;
2561
+ const oldLines = sourceText.split("\n");
2562
+ const newLines = nextSource.split("\n");
2563
+ const oldSlice = oldLines.slice(contextStartLine - 1, contextEndLine);
2564
+ const newSlice = newLines.slice(contextStartLine - 1, contextEndLine + (newLines.length - oldLines.length));
2565
+ return [
2566
+ `--- a/${file}`,
2567
+ `+++ b/${file}`,
2568
+ `@@ -${contextStartLine},${oldSlice.length} +${contextStartLine},${newSlice.length} @@`,
2569
+ ...oldSlice.map((line) => `-${line}`),
2570
+ ...newSlice.map((line) => `+${line}`)
2571
+ ].join("\n");
2572
+ }
2573
+ function lineNumberAt(sourceText, position) {
2574
+ let line = 1;
2575
+ for (let index = 0; index < position; index += 1) if (sourceText.charCodeAt(index) === 10) line += 1;
2576
+ return line;
2577
+ }
2578
+ function normalizePath(path) {
2579
+ return path.replace(/\\/g, "/");
2580
+ }
2581
+ function failure(editId, code, message, details) {
2582
+ return {
2583
+ ok: false,
2584
+ editId,
2585
+ written: false,
2586
+ error: {
2587
+ code,
2588
+ message,
2589
+ details
2590
+ }
2591
+ };
2592
+ }
2593
+ //#endregion
2594
+ export { tsxSourceParserAdapter as C, tsrxSourceParserAdapter as S, typescriptPandaAstAdapter as T, hashSource as _, createStyleModuleSourcePatch as a, parseWithSourceParserAdapter as b, safeProjectSourcePath as c, trustedManifestFilePath as d, trustedTokenSourceFilePath as f, analyzePandaCssSource as g, createInlineCssSourcePatch as h, createStyleModuleDetachPatch as i, stripViteQuery as l, createStaticCssPatch as m, componentStyleModulePaths as n, readComponentStyleModule as o, createStaticCssBatchPatch as p, createStyleModuleAttachPatch as r, normalizePath$2 as s, createTokenConfigPatch as t, toRelativeProjectPath as u, createEstreePandaAstAdapter as v, tsxSourceSyntaxAdapter as w, resolveSourceParserAdapter as x, parsePandaSource as y };