boss-css 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/_virtual/rolldown_runtime.cjs +43 -0
- package/dist/_virtual/rolldown_runtime.mjs +20 -0
- package/dist/api/browser.cjs +54 -0
- package/dist/api/browser.mjs +48 -0
- package/dist/api/config.cjs +94 -0
- package/dist/api/config.mjs +91 -0
- package/dist/api/css.cjs +304 -0
- package/dist/api/css.mjs +303 -0
- package/dist/api/dictionary.cjs +218 -0
- package/dist/api/dictionary.mjs +215 -0
- package/dist/api/file/dts.cjs +21 -0
- package/dist/api/file/dts.mjs +21 -0
- package/dist/api/file/file.cjs +123 -0
- package/dist/api/file/file.mjs +120 -0
- package/dist/api/file/js.cjs +118 -0
- package/dist/api/file/js.mjs +116 -0
- package/dist/api/names.cjs +52 -0
- package/dist/api/names.mjs +46 -0
- package/dist/api/noopCss.cjs +37 -0
- package/dist/api/noopCss.mjs +36 -0
- package/dist/api/propTree.cjs +54 -0
- package/dist/api/propTree.mjs +48 -0
- package/dist/api/server.cjs +112 -0
- package/dist/api/server.mjs +106 -0
- package/dist/cli/build.cjs +1 -0
- package/dist/cli/build.mjs +3 -0
- package/dist/cli/index.cjs +30 -0
- package/dist/cli/index.mjs +29 -0
- package/dist/cli/tasks/build.cjs +24 -0
- package/dist/cli/tasks/build.mjs +23 -0
- package/dist/cli/tasks/choose.cjs +47 -0
- package/dist/cli/tasks/choose.mjs +46 -0
- package/dist/cli/tasks/compile.cjs +68 -0
- package/dist/cli/tasks/compile.mjs +67 -0
- package/dist/cli/tasks/dev.cjs +51 -0
- package/dist/cli/tasks/dev.mjs +48 -0
- package/dist/cli/tasks/init.cjs +1835 -0
- package/dist/cli/tasks/init.mjs +1831 -0
- package/dist/cli/tasks/watch.cjs +38 -0
- package/dist/cli/tasks/watch.mjs +37 -0
- package/dist/cli/templates/init.cjs +82 -0
- package/dist/cli/templates/init.mjs +78 -0
- package/dist/cli/types.cjs +13 -0
- package/dist/cli/types.mjs +13 -0
- package/dist/cli/utils.cjs +43 -0
- package/dist/cli/utils.mjs +41 -0
- package/dist/compile/classname-strategy.cjs +79 -0
- package/dist/compile/classname-strategy.mjs +77 -0
- package/dist/compile/classname.cjs +366 -0
- package/dist/compile/classname.mjs +360 -0
- package/dist/compile/index.cjs +238 -0
- package/dist/compile/index.mjs +235 -0
- package/dist/compile/jsx.cjs +803 -0
- package/dist/compile/jsx.mjs +800 -0
- package/dist/compile/prepared.cjs +88 -0
- package/dist/compile/prepared.mjs +87 -0
- package/dist/compile/runtime.cjs +33 -0
- package/dist/compile/runtime.mjs +32 -0
- package/dist/compile/transform.cjs +371 -0
- package/dist/compile/transform.mjs +369 -0
- package/dist/cx/index.cjs +93 -0
- package/dist/cx/index.mjs +85 -0
- package/dist/detect-fw/index.cjs +384 -0
- package/dist/detect-fw/index.mjs +379 -0
- package/dist/dev/client.cjs +39 -0
- package/dist/dev/client.mjs +38 -0
- package/dist/dev/plugin/browser.cjs +11 -0
- package/dist/dev/plugin/browser.mjs +9 -0
- package/dist/dev/plugin/server.cjs +86 -0
- package/dist/dev/plugin/server.mjs +78 -0
- package/dist/dev/port.cjs +46 -0
- package/dist/dev/port.mjs +43 -0
- package/dist/dev/runtime.cjs +28 -0
- package/dist/dev/runtime.mjs +29 -0
- package/dist/dev/server.cjs +808 -0
- package/dist/dev/server.mjs +805 -0
- package/dist/dev/shared.cjs +6 -0
- package/dist/dev/shared.mjs +5 -0
- package/dist/eslint-plugin/index.cjs +66 -0
- package/dist/eslint-plugin/index.mjs +66 -0
- package/dist/eslint-plugin/rules/classnames-only.cjs +68 -0
- package/dist/eslint-plugin/rules/classnames-only.mjs +68 -0
- package/dist/eslint-plugin/rules/format-classnames.cjs +137 -0
- package/dist/eslint-plugin/rules/format-classnames.mjs +136 -0
- package/dist/eslint-plugin/rules/no-unknown-classes.cjs +119 -0
- package/dist/eslint-plugin/rules/no-unknown-classes.mjs +119 -0
- package/dist/eslint-plugin/rules/prefer-classnames.cjs +69 -0
- package/dist/eslint-plugin/rules/prefer-classnames.mjs +69 -0
- package/dist/eslint-plugin/rules/prefer-token-values.cjs +197 -0
- package/dist/eslint-plugin/rules/prefer-token-values.mjs +197 -0
- package/dist/eslint-plugin/rules/props-only.cjs +115 -0
- package/dist/eslint-plugin/rules/props-only.mjs +115 -0
- package/dist/eslint-plugin/rules/redundant-cx.cjs +66 -0
- package/dist/eslint-plugin/rules/redundant-cx.mjs +66 -0
- package/dist/eslint-plugin/rules/require-prop-functions.cjs +130 -0
- package/dist/eslint-plugin/rules/require-prop-functions.mjs +130 -0
- package/dist/eslint-plugin/utils/api.cjs +30 -0
- package/dist/eslint-plugin/utils/api.mjs +29 -0
- package/dist/eslint-plugin/utils/ast.cjs +119 -0
- package/dist/eslint-plugin/utils/ast.mjs +112 -0
- package/dist/eslint-plugin/utils/boss-classes.cjs +185 -0
- package/dist/eslint-plugin/utils/boss-classes.mjs +175 -0
- package/dist/eslint-plugin/utils/defaults.cjs +99 -0
- package/dist/eslint-plugin/utils/defaults.mjs +93 -0
- package/dist/eslint-plugin/utils/format.cjs +20 -0
- package/dist/eslint-plugin/utils/format.mjs +19 -0
- package/dist/eslint-plugin/utils/order.cjs +76 -0
- package/dist/eslint-plugin/utils/order.mjs +76 -0
- package/dist/eslint-plugin/utils/property-order.cjs +449 -0
- package/dist/eslint-plugin/utils/property-order.mjs +448 -0
- package/dist/eslint-plugin/utils/static.cjs +36 -0
- package/dist/eslint-plugin/utils/static.mjs +35 -0
- package/dist/fontsource/directory.cjs +39588 -0
- package/dist/fontsource/directory.mjs +39587 -0
- package/dist/fontsource/server.cjs +291 -0
- package/dist/fontsource/server.mjs +282 -0
- package/dist/index.cjs +10 -0
- package/dist/index.mjs +6 -0
- package/dist/log/browser.cjs +28 -0
- package/dist/log/browser.mjs +28 -0
- package/dist/log/server.cjs +32 -0
- package/dist/log/server.mjs +30 -0
- package/dist/merge/index.cjs +590 -0
- package/dist/merge/index.mjs +586 -0
- package/dist/native/browser.cjs +78 -0
- package/dist/native/browser.mjs +77 -0
- package/dist/native/server.cjs +180 -0
- package/dist/native/server.mjs +176 -0
- package/dist/native/styleTypes.cjs +168 -0
- package/dist/native/styleTypes.mjs +164 -0
- package/dist/parser/classname/server.cjs +239 -0
- package/dist/parser/classname/server.mjs +232 -0
- package/dist/parser/jsx/browser.cjs +66 -0
- package/dist/parser/jsx/browser.mjs +63 -0
- package/dist/parser/jsx/extractCode.cjs +99 -0
- package/dist/parser/jsx/extractCode.mjs +98 -0
- package/dist/parser/jsx/extractPrepared.cjs +123 -0
- package/dist/parser/jsx/extractPrepared.mjs +122 -0
- package/dist/parser/jsx/extractProps.cjs +234 -0
- package/dist/parser/jsx/extractProps.mjs +232 -0
- package/dist/parser/jsx/isDOMProp.cjs +17 -0
- package/dist/parser/jsx/isDOMProp.mjs +15 -0
- package/dist/parser/jsx/native.cjs +110 -0
- package/dist/parser/jsx/native.mjs +108 -0
- package/dist/parser/jsx/runtime.cjs +4 -0
- package/dist/parser/jsx/runtime.mjs +3 -0
- package/dist/parser/jsx/server.cjs +278 -0
- package/dist/parser/jsx/server.mjs +268 -0
- package/dist/postcss/index.cjs +16 -0
- package/dist/postcss/index.mjs +16 -0
- package/dist/prop/at/runtime-only.cjs +90 -0
- package/dist/prop/at/runtime-only.mjs +88 -0
- package/dist/prop/at/server.cjs +282 -0
- package/dist/prop/at/server.mjs +268 -0
- package/dist/prop/at/shared.cjs +153 -0
- package/dist/prop/at/shared.mjs +144 -0
- package/dist/prop/bosswind/browser.cjs +18 -0
- package/dist/prop/bosswind/browser.mjs +16 -0
- package/dist/prop/bosswind/runtime-only.cjs +18 -0
- package/dist/prop/bosswind/runtime-only.mjs +16 -0
- package/dist/prop/bosswind/server.cjs +81 -0
- package/dist/prop/bosswind/server.mjs +72 -0
- package/dist/prop/bosswind/shared.cjs +861 -0
- package/dist/prop/bosswind/shared.mjs +855 -0
- package/dist/prop/bosswind/tailwind-theme.cjs +703 -0
- package/dist/prop/bosswind/tailwind-theme.mjs +702 -0
- package/dist/prop/child/runtime-only.cjs +18 -0
- package/dist/prop/child/runtime-only.mjs +15 -0
- package/dist/prop/child/server.cjs +81 -0
- package/dist/prop/child/server.mjs +72 -0
- package/dist/prop/css/getDtsTemplate.cjs +65 -0
- package/dist/prop/css/getDtsTemplate.mjs +63 -0
- package/dist/prop/css/runtime-only.cjs +14 -0
- package/dist/prop/css/runtime-only.mjs +13 -0
- package/dist/prop/css/server.cjs +99 -0
- package/dist/prop/css/server.mjs +90 -0
- package/dist/prop/pseudo/runtime-only.cjs +23 -0
- package/dist/prop/pseudo/runtime-only.mjs +21 -0
- package/dist/prop/pseudo/server.cjs +91 -0
- package/dist/prop/pseudo/server.mjs +82 -0
- package/dist/prop/pseudo/shared.cjs +61 -0
- package/dist/prop/pseudo/shared.mjs +60 -0
- package/dist/reset/server.cjs +34 -0
- package/dist/reset/server.mjs +26 -0
- package/dist/runtime/index.cjs +119 -0
- package/dist/runtime/index.mjs +118 -0
- package/dist/runtime/preact.cjs +4 -0
- package/dist/runtime/preact.mjs +3 -0
- package/dist/runtime/qwik.cjs +21 -0
- package/dist/runtime/qwik.mjs +18 -0
- package/dist/runtime/react.cjs +4 -0
- package/dist/runtime/react.mjs +3 -0
- package/dist/runtime/solid.cjs +15 -0
- package/dist/runtime/solid.mjs +14 -0
- package/dist/runtime/stencil.cjs +25 -0
- package/dist/runtime/stencil.mjs +21 -0
- package/dist/runtime/style.cjs +14 -0
- package/dist/runtime/style.mjs +13 -0
- package/dist/shared/boundaries.cjs +288 -0
- package/dist/shared/boundaries.mjs +285 -0
- package/dist/shared/customCss.cjs +212 -0
- package/dist/shared/customCss.mjs +211 -0
- package/dist/shared/debug.cjs +76 -0
- package/dist/shared/debug.mjs +74 -0
- package/dist/shared/file.cjs +21 -0
- package/dist/shared/file.mjs +19 -0
- package/dist/shared/framework.cjs +10 -0
- package/dist/shared/framework.mjs +9 -0
- package/dist/shared/json.cjs +58 -0
- package/dist/shared/json.mjs +57 -0
- package/dist/shared/types.cjs +11 -0
- package/dist/shared/types.mjs +10 -0
- package/dist/strategy/classic/runtime-only.cjs +190 -0
- package/dist/strategy/classic/runtime-only.mjs +186 -0
- package/dist/strategy/classname-first/runtime-only.cjs +138 -0
- package/dist/strategy/classname-first/runtime-only.mjs +134 -0
- package/dist/strategy/classname-first/server.cjs +139 -0
- package/dist/strategy/classname-first/server.mjs +133 -0
- package/dist/strategy/classname-only/server.cjs +43 -0
- package/dist/strategy/classname-only/server.mjs +35 -0
- package/dist/strategy/inline-first/browser.cjs +61 -0
- package/dist/strategy/inline-first/browser.mjs +58 -0
- package/dist/strategy/inline-first/runtime-only.cjs +159 -0
- package/dist/strategy/inline-first/runtime-only.mjs +155 -0
- package/dist/strategy/inline-first/server.cjs +92 -0
- package/dist/strategy/inline-first/server.mjs +83 -0
- package/dist/strategy/runtime/runtime-only.cjs +24 -0
- package/dist/strategy/runtime/runtime-only.mjs +22 -0
- package/dist/strategy/runtime/server.cjs +72 -0
- package/dist/strategy/runtime/server.mjs +63 -0
- package/dist/strategy/runtime-only/css.cjs +183 -0
- package/dist/strategy/runtime-only/css.mjs +181 -0
- package/dist/tasks/build.cjs +88 -0
- package/dist/tasks/build.mjs +84 -0
- package/dist/tasks/compile.cjs +12 -0
- package/dist/tasks/compile.mjs +12 -0
- package/dist/tasks/postcss.cjs +116 -0
- package/dist/tasks/postcss.mjs +113 -0
- package/dist/tasks/session.cjs +46 -0
- package/dist/tasks/session.mjs +42 -0
- package/dist/tasks/watch.cjs +102 -0
- package/dist/tasks/watch.mjs +99 -0
- package/dist/transform/cache.cjs +24 -0
- package/dist/transform/cache.mjs +21 -0
- package/dist/transform/processFile.cjs +26 -0
- package/dist/transform/processFile.mjs +24 -0
- package/dist/use/token/browser.cjs +65 -0
- package/dist/use/token/browser.mjs +61 -0
- package/dist/use/token/runtime-only.cjs +245 -0
- package/dist/use/token/runtime-only.mjs +239 -0
- package/dist/use/token/server.cjs +325 -0
- package/dist/use/token/server.mjs +313 -0
- package/dist/use/token/vars.cjs +47 -0
- package/dist/use/token/vars.mjs +46 -0
- package/package.json +300 -4
- package/src/api/config.d.ts +1 -0
- package/src/fontsource/types.d.ts +50 -0
- package/src/packages/document-create-element/createElement.browser.js +3 -0
- package/src/packages/document-create-element/createElement.js +7 -0
- package/src/packages/document-create-element/package.json +17 -0
- package/src/packages/is-css-prop/browser.js +13 -0
- package/src/packages/is-css-prop/index.js +13 -0
- package/src/packages/is-css-prop/package-lock.json +52 -0
- package/src/packages/is-css-prop/package.json +17 -0
- package/src/prop/css/csstype.json +4387 -0
- package/src/prop/css/package.json +3 -0
- package/src/reset/reset.css +259 -0
|
@@ -0,0 +1,808 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_api_server = require('../api/server.cjs');
|
|
3
|
+
const require_api_config = require('../api/config.cjs');
|
|
4
|
+
const require_use_token_server = require('../use/token/server.cjs');
|
|
5
|
+
const require_shared = require('./shared.cjs');
|
|
6
|
+
let node_fs_promises = require("node:fs/promises");
|
|
7
|
+
node_fs_promises = require_rolldown_runtime.__toESM(node_fs_promises);
|
|
8
|
+
let node_path = require("node:path");
|
|
9
|
+
node_path = require_rolldown_runtime.__toESM(node_path);
|
|
10
|
+
let node_url = require("node:url");
|
|
11
|
+
let ws = require("ws");
|
|
12
|
+
|
|
13
|
+
//#region src/dev/server.ts
|
|
14
|
+
const DEFAULT_MAX_PORT = require_shared.DEFAULT_DEV_PORT + 49;
|
|
15
|
+
async function startDevServer({ port = require_shared.DEFAULT_DEV_PORT, maxPort = DEFAULT_MAX_PORT, host = "127.0.0.1" } = {}) {
|
|
16
|
+
let currentPort = port;
|
|
17
|
+
let server = null;
|
|
18
|
+
while (currentPort <= maxPort) try {
|
|
19
|
+
server = await listenOnPort(currentPort, host);
|
|
20
|
+
break;
|
|
21
|
+
} catch (error) {
|
|
22
|
+
if (isAddressInUse(error)) {
|
|
23
|
+
currentPort += 1;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
if (!server) throw new Error(`No available ports in range ${port}-${maxPort}`);
|
|
29
|
+
server.on("connection", (socket) => {
|
|
30
|
+
socket.on("message", async (data) => {
|
|
31
|
+
const message = parseClientMessage(data);
|
|
32
|
+
if (!message) return;
|
|
33
|
+
try {
|
|
34
|
+
if (message.type === "select") {
|
|
35
|
+
const entries = await inspectSelection(message.source);
|
|
36
|
+
socket.send(JSON.stringify({
|
|
37
|
+
type: "select-result",
|
|
38
|
+
id: message.id,
|
|
39
|
+
props: entries
|
|
40
|
+
}));
|
|
41
|
+
} else if (message.type === "edit") {
|
|
42
|
+
await applyEdit(message);
|
|
43
|
+
socket.send(JSON.stringify({
|
|
44
|
+
type: "edit-result",
|
|
45
|
+
id: message.id,
|
|
46
|
+
ok: true
|
|
47
|
+
}));
|
|
48
|
+
} else if (message.type === "add-prop") {
|
|
49
|
+
await applyAddProp(message);
|
|
50
|
+
socket.send(JSON.stringify({
|
|
51
|
+
type: "add-prop-result",
|
|
52
|
+
id: message.id,
|
|
53
|
+
ok: true
|
|
54
|
+
}));
|
|
55
|
+
} else if (message.type === "read-file") {
|
|
56
|
+
const content = await readFileForClient(message.path);
|
|
57
|
+
socket.send(JSON.stringify({
|
|
58
|
+
type: "read-file-result",
|
|
59
|
+
id: message.id,
|
|
60
|
+
content
|
|
61
|
+
}));
|
|
62
|
+
} else if (message.type === "write-file") {
|
|
63
|
+
await writeFileForClient(message.path, message.content);
|
|
64
|
+
socket.send(JSON.stringify({
|
|
65
|
+
type: "write-file-result",
|
|
66
|
+
id: message.id,
|
|
67
|
+
ok: true
|
|
68
|
+
}));
|
|
69
|
+
} else if (message.type === "tokens") {
|
|
70
|
+
const tokens = await getTokenSnapshot();
|
|
71
|
+
socket.send(JSON.stringify({
|
|
72
|
+
type: "tokens-result",
|
|
73
|
+
id: message.id,
|
|
74
|
+
tokens
|
|
75
|
+
}));
|
|
76
|
+
} else if (message.type === "boss-types") {
|
|
77
|
+
const content = await getBossTypes();
|
|
78
|
+
socket.send(JSON.stringify({
|
|
79
|
+
type: "boss-types-result",
|
|
80
|
+
id: message.id,
|
|
81
|
+
content
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
} catch (error) {
|
|
85
|
+
const err = error instanceof Error ? error.message : String(error);
|
|
86
|
+
socket.send(JSON.stringify({
|
|
87
|
+
type: "error",
|
|
88
|
+
id: message.id,
|
|
89
|
+
message: err
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
return {
|
|
95
|
+
server,
|
|
96
|
+
port: currentPort
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const listenOnPort = (port, host) => {
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
const server = new ws.WebSocketServer({
|
|
102
|
+
port,
|
|
103
|
+
host
|
|
104
|
+
});
|
|
105
|
+
const onError = (error) => {
|
|
106
|
+
server.removeListener("listening", onListening);
|
|
107
|
+
server.close();
|
|
108
|
+
reject(error);
|
|
109
|
+
};
|
|
110
|
+
const onListening = () => {
|
|
111
|
+
server.removeListener("error", onError);
|
|
112
|
+
resolve(server);
|
|
113
|
+
};
|
|
114
|
+
server.once("error", onError);
|
|
115
|
+
server.once("listening", onListening);
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
const isAddressInUse = (error) => {
|
|
119
|
+
return Boolean(error && typeof error === "object" && "code" in error && error.code === "EADDRINUSE");
|
|
120
|
+
};
|
|
121
|
+
const parseClientMessage = (data) => {
|
|
122
|
+
try {
|
|
123
|
+
const parsed = JSON.parse(data.toString());
|
|
124
|
+
if (!parsed || typeof parsed.type !== "string") return null;
|
|
125
|
+
return parsed;
|
|
126
|
+
} catch {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
async function readFileForClient(filePath) {
|
|
131
|
+
if (!filePath || typeof filePath !== "string") return null;
|
|
132
|
+
const resolved = await resolveSourcePath(filePath);
|
|
133
|
+
if (!await fileExists(resolved)) return null;
|
|
134
|
+
return node_fs_promises.default.readFile(resolved, "utf8");
|
|
135
|
+
}
|
|
136
|
+
async function writeFileForClient(filePath, content) {
|
|
137
|
+
if (!filePath || typeof filePath !== "string") throw new Error("Missing file path for write.");
|
|
138
|
+
const resolved = await resolveSourcePath(filePath);
|
|
139
|
+
await node_fs_promises.default.writeFile(resolved, content ?? "");
|
|
140
|
+
}
|
|
141
|
+
async function getTokenSnapshot() {
|
|
142
|
+
await require_api_server.createApi(await require_api_config.loadConfig());
|
|
143
|
+
return {
|
|
144
|
+
tokens: require_use_token_server.getTokens() || {},
|
|
145
|
+
propGroups: Array.from(require_use_token_server.propMap.entries()).reduce((acc, [group, values]) => {
|
|
146
|
+
acc[group] = Array.from(values);
|
|
147
|
+
return acc;
|
|
148
|
+
}, {})
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
async function getBossTypes() {
|
|
152
|
+
const config = await require_api_config.loadConfig();
|
|
153
|
+
const baseDir = process.cwd();
|
|
154
|
+
const typesPath = node_path.default.join(baseDir, config.configDir ?? ".bo$$", "index.d.ts");
|
|
155
|
+
if (!await fileExists(typesPath)) return null;
|
|
156
|
+
return node_fs_promises.default.readFile(typesPath, "utf8");
|
|
157
|
+
}
|
|
158
|
+
async function inspectSelection(source) {
|
|
159
|
+
const { code, offset, filePath, lineNumber, columnNumber, lineRange } = await readSourceFile(source);
|
|
160
|
+
const tag = findBossTagAtOffset(code, offset, lineRange);
|
|
161
|
+
if (!tag) throw new Error(`Unable to find <$$> element in ${filePath}:${lineNumber}:${columnNumber}`);
|
|
162
|
+
return buildPropEntries(tag, code).entries;
|
|
163
|
+
}
|
|
164
|
+
async function applyEdit(message) {
|
|
165
|
+
const { source, path: propPath, value: rawValue, kind } = message;
|
|
166
|
+
const { code, offset, filePath, lineNumber, columnNumber, lineRange } = await readSourceFile(source);
|
|
167
|
+
const tag = findBossTagAtOffset(code, offset, lineRange);
|
|
168
|
+
if (!tag) throw new Error(`Unable to find <$$> element in ${filePath}:${lineNumber}:${columnNumber}`);
|
|
169
|
+
const { index } = buildPropEntries(tag, code);
|
|
170
|
+
const target = index.get(propPath.join("."));
|
|
171
|
+
if (!target) throw new Error(`Unable to find prop "${propPath.join(".")}" for edit.`);
|
|
172
|
+
const parsedValue = parseValue(rawValue, kind);
|
|
173
|
+
const replacement = formatValue(parsedValue, kind, target.meta);
|
|
174
|
+
let start = 0;
|
|
175
|
+
let end = 0;
|
|
176
|
+
if (target.range) {
|
|
177
|
+
start = target.range.start;
|
|
178
|
+
end = target.range.end;
|
|
179
|
+
} else if (target.attrRange) {
|
|
180
|
+
start = target.attrRange.start;
|
|
181
|
+
end = target.attrRange.end;
|
|
182
|
+
const nextAttr = `${target.attrName ?? propPath[0] ?? "prop"}${kind === "boolean" && parsedValue === true ? "" : `={${replacement}}`}`;
|
|
183
|
+
const updated$1 = replaceText(code, start, end, nextAttr);
|
|
184
|
+
await node_fs_promises.default.writeFile(filePath, updated$1);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const updated = replaceText(code, start, end, replacement);
|
|
188
|
+
await node_fs_promises.default.writeFile(filePath, updated);
|
|
189
|
+
}
|
|
190
|
+
async function applyAddProp(message) {
|
|
191
|
+
const { source, path: propPath, value: rawValue, kind } = message;
|
|
192
|
+
if (!propPath?.length) throw new Error("Missing prop path for add.");
|
|
193
|
+
if (propPath.length > 1) throw new Error("Nested prop insertion is not supported yet.");
|
|
194
|
+
const { code, offset, filePath, lineNumber, columnNumber, lineRange } = await readSourceFile(source);
|
|
195
|
+
const tag = findBossTagAtOffset(code, offset, lineRange);
|
|
196
|
+
if (!tag) throw new Error(`Unable to find <$$> element in ${filePath}:${lineNumber}:${columnNumber}`);
|
|
197
|
+
const { index } = buildPropEntries(tag, code);
|
|
198
|
+
const propKey = propPath.join(".");
|
|
199
|
+
if (index.get(propKey)) {
|
|
200
|
+
await applyEdit({
|
|
201
|
+
...message,
|
|
202
|
+
type: "edit"
|
|
203
|
+
});
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const parsedValue = parseValue(rawValue, kind);
|
|
207
|
+
const replacement = formatValue(parsedValue, kind);
|
|
208
|
+
const attrName = propPath[0];
|
|
209
|
+
const attrText = formatAttribute(attrName, parsedValue, kind, replacement);
|
|
210
|
+
const insertAt = code[tag.end - 2] === "/" ? tag.end - 2 : tag.end - 1;
|
|
211
|
+
const updated = replaceText(code, insertAt, insertAt, `${insertAt > 0 && !/\s/.test(code[insertAt - 1]) ? " " : ""}${attrText}`);
|
|
212
|
+
await node_fs_promises.default.writeFile(filePath, updated);
|
|
213
|
+
}
|
|
214
|
+
async function readSourceFile(source) {
|
|
215
|
+
if (!source?.fileName) throw new Error("Missing source file name for selection.");
|
|
216
|
+
const resolvedPath = await resolveSourcePath(source.fileName);
|
|
217
|
+
const lineNumber = Number.isFinite(source.lineNumber) ? Math.max(1, source.lineNumber) : 1;
|
|
218
|
+
const columnNumber = Number.isFinite(source.columnNumber) ? Math.max(1, source.columnNumber) : 1;
|
|
219
|
+
const code = await node_fs_promises.default.readFile(resolvedPath, "utf8");
|
|
220
|
+
const lineOffsets = buildLineOffsets(code);
|
|
221
|
+
return {
|
|
222
|
+
code,
|
|
223
|
+
filePath: resolvedPath,
|
|
224
|
+
offset: offsetFromLineColumn(lineNumber, columnNumber - 1, lineOffsets),
|
|
225
|
+
lineRange: getLineRange(lineNumber, lineOffsets, code.length),
|
|
226
|
+
lineNumber,
|
|
227
|
+
columnNumber
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
const decodePath = (value) => {
|
|
231
|
+
try {
|
|
232
|
+
return decodeURIComponent(value);
|
|
233
|
+
} catch {
|
|
234
|
+
return value;
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
const isExplicitSource = (value) => {
|
|
238
|
+
return value.startsWith("file://") || value.startsWith("webpack://") || value.startsWith("webpack-internal://") || value.startsWith("http://") || value.startsWith("https://") || value.startsWith("[project]/") || node_path.default.isAbsolute(value);
|
|
239
|
+
};
|
|
240
|
+
const normalizeWebpackPath = (value) => {
|
|
241
|
+
let cleaned = value.replace(/^webpack-internal:\/\//, "").replace(/^webpack:\/\//, "");
|
|
242
|
+
cleaned = cleaned.replace(/^_N_E\//, "");
|
|
243
|
+
cleaned = cleaned.replace(/^\.\//, "");
|
|
244
|
+
cleaned = cleaned.replace(/^\/+/, "");
|
|
245
|
+
return decodePath(cleaned);
|
|
246
|
+
};
|
|
247
|
+
const stripQueryHash = (value) => value.split("?")[0].split("#")[0];
|
|
248
|
+
const resolveSourcePath = async (fileName, sourceRoot) => {
|
|
249
|
+
let candidate = stripQueryHash(fileName);
|
|
250
|
+
if (sourceRoot && !isExplicitSource(candidate)) {
|
|
251
|
+
let root = sourceRoot;
|
|
252
|
+
if (root.startsWith("file://")) root = (0, node_url.fileURLToPath)(root);
|
|
253
|
+
else if (root.startsWith("webpack://")) root = normalizeWebpackPath(root);
|
|
254
|
+
else if (root.startsWith("[project]/")) root = root.slice(10);
|
|
255
|
+
candidate = node_path.default.join(root, candidate);
|
|
256
|
+
}
|
|
257
|
+
if (candidate.startsWith("file://")) return (0, node_url.fileURLToPath)(candidate);
|
|
258
|
+
if (candidate.startsWith("http://") || candidate.startsWith("https://")) try {
|
|
259
|
+
const trimmed = decodePath(new URL(candidate).pathname).replace(/^\/+/, "");
|
|
260
|
+
return await findExistingPath(trimmed) ?? node_path.default.resolve(trimmed);
|
|
261
|
+
} catch {
|
|
262
|
+
return node_path.default.resolve(candidate);
|
|
263
|
+
}
|
|
264
|
+
if (candidate.startsWith("webpack://")) {
|
|
265
|
+
const cleaned = normalizeWebpackPath(candidate);
|
|
266
|
+
return await findExistingPath(cleaned) ?? node_path.default.resolve(cleaned);
|
|
267
|
+
}
|
|
268
|
+
if (candidate.startsWith("webpack-internal://")) {
|
|
269
|
+
const cleaned = normalizeWebpackPath(candidate);
|
|
270
|
+
return await findExistingPath(cleaned) ?? node_path.default.resolve(cleaned);
|
|
271
|
+
}
|
|
272
|
+
if (candidate.startsWith("[project]/")) {
|
|
273
|
+
const cleaned = decodePath(candidate.slice(10));
|
|
274
|
+
return await findExistingPath(cleaned) ?? node_path.default.resolve(cleaned);
|
|
275
|
+
}
|
|
276
|
+
if (node_path.default.isAbsolute(candidate)) return candidate;
|
|
277
|
+
return await findExistingPath(candidate) ?? node_path.default.resolve(candidate);
|
|
278
|
+
};
|
|
279
|
+
const findExistingPath = async (relativePath) => {
|
|
280
|
+
let current = process.cwd();
|
|
281
|
+
for (let i = 0; i < 8; i++) {
|
|
282
|
+
const candidate = node_path.default.resolve(current, relativePath);
|
|
283
|
+
if (await fileExists(candidate)) return candidate;
|
|
284
|
+
const parent = node_path.default.dirname(current);
|
|
285
|
+
if (parent === current) break;
|
|
286
|
+
current = parent;
|
|
287
|
+
}
|
|
288
|
+
return null;
|
|
289
|
+
};
|
|
290
|
+
const fileExists = async (filePath) => {
|
|
291
|
+
try {
|
|
292
|
+
await node_fs_promises.default.access(filePath);
|
|
293
|
+
return true;
|
|
294
|
+
} catch {
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
const buildLineOffsets = (code) => {
|
|
299
|
+
const offsets = [0];
|
|
300
|
+
for (let i = 0; i < code.length; i++) if (code[i] === "\n") offsets.push(i + 1);
|
|
301
|
+
return offsets;
|
|
302
|
+
};
|
|
303
|
+
const offsetFromLineColumn = (lineNumber, columnNumber, offsets) => {
|
|
304
|
+
return (offsets[Math.max(0, lineNumber - 1)] ?? offsets[offsets.length - 1] ?? 0) + Math.max(0, columnNumber);
|
|
305
|
+
};
|
|
306
|
+
const getLineRange = (lineNumber, offsets, codeLength) => {
|
|
307
|
+
const lineIndex = Math.max(0, lineNumber - 1);
|
|
308
|
+
return {
|
|
309
|
+
start: offsets[lineIndex] ?? 0,
|
|
310
|
+
end: offsets[lineIndex + 1] ?? codeLength
|
|
311
|
+
};
|
|
312
|
+
};
|
|
313
|
+
const findBossTagAtOffset = (code, offset, lineRange) => {
|
|
314
|
+
const startIndex = Math.min(Math.max(offset, 0), code.length);
|
|
315
|
+
const minIndex = 0;
|
|
316
|
+
for (let i = startIndex; i >= minIndex; i--) {
|
|
317
|
+
if (code[i] !== "<") continue;
|
|
318
|
+
const next = code[i + 1];
|
|
319
|
+
if (next === "/" || next == null) continue;
|
|
320
|
+
if (!code.startsWith("$$", i + 1)) continue;
|
|
321
|
+
const tag = parseBossTag(code, i);
|
|
322
|
+
if (!tag) continue;
|
|
323
|
+
if (offset >= tag.start && offset <= tag.end) return tag;
|
|
324
|
+
if (lineRange && tag.start <= lineRange.end && tag.end >= lineRange.start) return tag;
|
|
325
|
+
}
|
|
326
|
+
return null;
|
|
327
|
+
};
|
|
328
|
+
const parseBossTag = (code, start) => {
|
|
329
|
+
let i = start + 1;
|
|
330
|
+
if (!code.startsWith("$$", i)) return null;
|
|
331
|
+
i += 2;
|
|
332
|
+
while (i < code.length && isTagNameChar(code[i])) i++;
|
|
333
|
+
const attrs = [];
|
|
334
|
+
while (i < code.length) {
|
|
335
|
+
i = skipWhitespace(code, i);
|
|
336
|
+
if (code[i] === "/" && code[i + 1] === ">") return {
|
|
337
|
+
start,
|
|
338
|
+
end: i + 2,
|
|
339
|
+
attrs
|
|
340
|
+
};
|
|
341
|
+
if (code[i] === ">") return {
|
|
342
|
+
start,
|
|
343
|
+
end: i + 1,
|
|
344
|
+
attrs
|
|
345
|
+
};
|
|
346
|
+
if (code[i] === "{" && code.slice(i, i + 4) === "{...") {
|
|
347
|
+
const end = findMatchingBrace(code, i);
|
|
348
|
+
if (end === -1) return null;
|
|
349
|
+
i = end + 1;
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
const nameStart = i;
|
|
353
|
+
while (i < code.length && isAttrNameChar(code[i])) i++;
|
|
354
|
+
if (i === nameStart) return null;
|
|
355
|
+
const name = code.slice(nameStart, i);
|
|
356
|
+
let attrRange = {
|
|
357
|
+
start: nameStart,
|
|
358
|
+
end: i
|
|
359
|
+
};
|
|
360
|
+
i = skipWhitespace(code, i);
|
|
361
|
+
let value = null;
|
|
362
|
+
if (code[i] === "=") {
|
|
363
|
+
i += 1;
|
|
364
|
+
i = skipWhitespace(code, i);
|
|
365
|
+
const valueStart = i;
|
|
366
|
+
if (code[i] === "\"" || code[i] === "'") {
|
|
367
|
+
const parsed = parseStringLiteral(code, i);
|
|
368
|
+
if (!parsed) return null;
|
|
369
|
+
value = parsed.node;
|
|
370
|
+
i = parsed.next;
|
|
371
|
+
} else if (code[i] === "{") {
|
|
372
|
+
const end = findMatchingBrace(code, i);
|
|
373
|
+
if (end === -1) return null;
|
|
374
|
+
value = parseExpression(code, i + 1, end);
|
|
375
|
+
i = end + 1;
|
|
376
|
+
} else {
|
|
377
|
+
const end = findAttributeValueEnd(code, i);
|
|
378
|
+
value = {
|
|
379
|
+
kind: "unknown",
|
|
380
|
+
range: {
|
|
381
|
+
start: valueStart,
|
|
382
|
+
end
|
|
383
|
+
},
|
|
384
|
+
code: code.slice(valueStart, end)
|
|
385
|
+
};
|
|
386
|
+
i = end;
|
|
387
|
+
}
|
|
388
|
+
attrRange = {
|
|
389
|
+
start: nameStart,
|
|
390
|
+
end: i
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
attrs.push({
|
|
394
|
+
name,
|
|
395
|
+
value,
|
|
396
|
+
range: attrRange
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
return null;
|
|
400
|
+
};
|
|
401
|
+
const isTagNameChar = (char) => /[A-Za-z0-9_$.\-]/.test(char);
|
|
402
|
+
const isAttrNameChar = (char) => /[A-Za-z0-9_$:\-]/.test(char);
|
|
403
|
+
const skipWhitespace = (code, index) => {
|
|
404
|
+
let i = index;
|
|
405
|
+
while (i < code.length && /\s/.test(code[i])) i++;
|
|
406
|
+
return i;
|
|
407
|
+
};
|
|
408
|
+
const findAttributeValueEnd = (code, index) => {
|
|
409
|
+
let i = index;
|
|
410
|
+
while (i < code.length && !/\s/.test(code[i]) && code[i] !== ">" && code[i] !== "/") i++;
|
|
411
|
+
return i;
|
|
412
|
+
};
|
|
413
|
+
const findMatchingBrace = (code, start) => {
|
|
414
|
+
let depth = 0;
|
|
415
|
+
let quote = null;
|
|
416
|
+
for (let i = start; i < code.length; i++) {
|
|
417
|
+
const char = code[i];
|
|
418
|
+
if (quote) {
|
|
419
|
+
if (char === "\\") {
|
|
420
|
+
i += 1;
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
if (char === quote) quote = null;
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
if (char === "\"" || char === "'" || char === "`") {
|
|
427
|
+
quote = char;
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
if (char === "{") depth += 1;
|
|
431
|
+
if (char === "}") {
|
|
432
|
+
depth -= 1;
|
|
433
|
+
if (depth === 0) return i;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return -1;
|
|
437
|
+
};
|
|
438
|
+
const parseStringLiteral = (code, start) => {
|
|
439
|
+
const quote = code[start];
|
|
440
|
+
let i = start + 1;
|
|
441
|
+
let value = "";
|
|
442
|
+
while (i < code.length) {
|
|
443
|
+
const char = code[i];
|
|
444
|
+
if (char === "\\") {
|
|
445
|
+
const next = code[i + 1];
|
|
446
|
+
if (next) {
|
|
447
|
+
value += next;
|
|
448
|
+
i += 2;
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
if (char === quote) {
|
|
453
|
+
const end = i + 1;
|
|
454
|
+
return {
|
|
455
|
+
node: {
|
|
456
|
+
kind: "string",
|
|
457
|
+
value,
|
|
458
|
+
range: {
|
|
459
|
+
start,
|
|
460
|
+
end
|
|
461
|
+
},
|
|
462
|
+
quote
|
|
463
|
+
},
|
|
464
|
+
next: end
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
value += char;
|
|
468
|
+
i += 1;
|
|
469
|
+
}
|
|
470
|
+
return null;
|
|
471
|
+
};
|
|
472
|
+
const parseExpression = (code, start, end) => {
|
|
473
|
+
const parser = new ExpressionParser(code, start, end);
|
|
474
|
+
const node = parser.parseValue();
|
|
475
|
+
parser.skipWhitespace();
|
|
476
|
+
if (!node || parser.index < end) return {
|
|
477
|
+
kind: "unknown",
|
|
478
|
+
range: {
|
|
479
|
+
start,
|
|
480
|
+
end
|
|
481
|
+
},
|
|
482
|
+
code: code.slice(start, end)
|
|
483
|
+
};
|
|
484
|
+
return node;
|
|
485
|
+
};
|
|
486
|
+
var ExpressionParser = class {
|
|
487
|
+
code;
|
|
488
|
+
index;
|
|
489
|
+
end;
|
|
490
|
+
constructor(code, start, end) {
|
|
491
|
+
this.code = code;
|
|
492
|
+
this.index = start;
|
|
493
|
+
this.end = end;
|
|
494
|
+
}
|
|
495
|
+
skipWhitespace() {
|
|
496
|
+
this.index = skipWhitespace(this.code, this.index);
|
|
497
|
+
}
|
|
498
|
+
parseValue() {
|
|
499
|
+
this.skipWhitespace();
|
|
500
|
+
if (this.index >= this.end) return null;
|
|
501
|
+
const char = this.code[this.index];
|
|
502
|
+
if (char === "\"" || char === "'") {
|
|
503
|
+
const parsed = parseStringLiteral(this.code, this.index);
|
|
504
|
+
if (!parsed || parsed.next > this.end) return null;
|
|
505
|
+
this.index = parsed.next;
|
|
506
|
+
return parsed.node;
|
|
507
|
+
}
|
|
508
|
+
if (char === "[") return this.parseArray();
|
|
509
|
+
if (char === "{") return this.parseObject();
|
|
510
|
+
if (char === "-" || /\d/.test(char)) return this.parseNumber();
|
|
511
|
+
if (this.code.startsWith("true", this.index)) {
|
|
512
|
+
const range = {
|
|
513
|
+
start: this.index,
|
|
514
|
+
end: this.index + 4
|
|
515
|
+
};
|
|
516
|
+
this.index += 4;
|
|
517
|
+
return {
|
|
518
|
+
kind: "boolean",
|
|
519
|
+
value: true,
|
|
520
|
+
range
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
if (this.code.startsWith("false", this.index)) {
|
|
524
|
+
const range = {
|
|
525
|
+
start: this.index,
|
|
526
|
+
end: this.index + 5
|
|
527
|
+
};
|
|
528
|
+
this.index += 5;
|
|
529
|
+
return {
|
|
530
|
+
kind: "boolean",
|
|
531
|
+
value: false,
|
|
532
|
+
range
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
return null;
|
|
536
|
+
}
|
|
537
|
+
parseNumber() {
|
|
538
|
+
const start = this.index;
|
|
539
|
+
let i = this.index;
|
|
540
|
+
if (this.code[i] === "-") i++;
|
|
541
|
+
while (i < this.end && /\d/.test(this.code[i])) i++;
|
|
542
|
+
if (i < this.end && this.code[i] === ".") {
|
|
543
|
+
i++;
|
|
544
|
+
while (i < this.end && /\d/.test(this.code[i])) i++;
|
|
545
|
+
}
|
|
546
|
+
const raw = this.code.slice(start, i);
|
|
547
|
+
const value = Number(raw);
|
|
548
|
+
if (Number.isNaN(value)) return null;
|
|
549
|
+
this.index = i;
|
|
550
|
+
return {
|
|
551
|
+
kind: "number",
|
|
552
|
+
value,
|
|
553
|
+
range: {
|
|
554
|
+
start,
|
|
555
|
+
end: i
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
parseArray() {
|
|
560
|
+
const start = this.index;
|
|
561
|
+
this.index += 1;
|
|
562
|
+
const values = [];
|
|
563
|
+
while (this.index < this.end) {
|
|
564
|
+
this.skipWhitespace();
|
|
565
|
+
if (this.code[this.index] === "]") {
|
|
566
|
+
const end = this.index + 1;
|
|
567
|
+
this.index = end;
|
|
568
|
+
return {
|
|
569
|
+
kind: "array",
|
|
570
|
+
value: values,
|
|
571
|
+
range: {
|
|
572
|
+
start,
|
|
573
|
+
end
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
const value = this.parseValue();
|
|
578
|
+
if (!value) return null;
|
|
579
|
+
values.push(value);
|
|
580
|
+
this.skipWhitespace();
|
|
581
|
+
if (this.code[this.index] === ",") {
|
|
582
|
+
this.index += 1;
|
|
583
|
+
continue;
|
|
584
|
+
}
|
|
585
|
+
if (this.code[this.index] === "]") continue;
|
|
586
|
+
return null;
|
|
587
|
+
}
|
|
588
|
+
return null;
|
|
589
|
+
}
|
|
590
|
+
parseObject() {
|
|
591
|
+
const start = this.index;
|
|
592
|
+
this.index += 1;
|
|
593
|
+
const value = {};
|
|
594
|
+
while (this.index < this.end) {
|
|
595
|
+
this.skipWhitespace();
|
|
596
|
+
if (this.code[this.index] === "}") {
|
|
597
|
+
const end = this.index + 1;
|
|
598
|
+
this.index = end;
|
|
599
|
+
return {
|
|
600
|
+
kind: "object",
|
|
601
|
+
value,
|
|
602
|
+
range: {
|
|
603
|
+
start,
|
|
604
|
+
end
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
const key = this.parseObjectKey();
|
|
609
|
+
if (!key) return null;
|
|
610
|
+
this.skipWhitespace();
|
|
611
|
+
if (this.code[this.index] !== ":") return null;
|
|
612
|
+
this.index += 1;
|
|
613
|
+
const val = this.parseValue();
|
|
614
|
+
if (!val) return null;
|
|
615
|
+
value[key] = val;
|
|
616
|
+
this.skipWhitespace();
|
|
617
|
+
if (this.code[this.index] === ",") {
|
|
618
|
+
this.index += 1;
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
if (this.code[this.index] === "}") continue;
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
624
|
+
return null;
|
|
625
|
+
}
|
|
626
|
+
parseObjectKey() {
|
|
627
|
+
this.skipWhitespace();
|
|
628
|
+
const char = this.code[this.index];
|
|
629
|
+
if (char === "\"" || char === "'") {
|
|
630
|
+
const parsed = parseStringLiteral(this.code, this.index);
|
|
631
|
+
if (!parsed || parsed.next > this.end) return null;
|
|
632
|
+
this.index = parsed.next;
|
|
633
|
+
return parsed.node.value;
|
|
634
|
+
}
|
|
635
|
+
const start = this.index;
|
|
636
|
+
if (!/[A-Za-z_$]/.test(char)) return null;
|
|
637
|
+
let i = this.index + 1;
|
|
638
|
+
while (i < this.end && /[A-Za-z0-9_$]/.test(this.code[i])) i++;
|
|
639
|
+
this.index = i;
|
|
640
|
+
return this.code.slice(start, i);
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
const buildPropEntries = (tag, code) => {
|
|
644
|
+
const entries = [];
|
|
645
|
+
const index = /* @__PURE__ */ new Map();
|
|
646
|
+
for (const attr of tag.attrs) {
|
|
647
|
+
if (!attr.value) {
|
|
648
|
+
entries.push({
|
|
649
|
+
path: [attr.name],
|
|
650
|
+
value: true,
|
|
651
|
+
editable: true,
|
|
652
|
+
kind: "boolean"
|
|
653
|
+
});
|
|
654
|
+
index.set(attr.name, {
|
|
655
|
+
attrName: attr.name,
|
|
656
|
+
attrRange: attr.range,
|
|
657
|
+
kind: "boolean"
|
|
658
|
+
});
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
collectParsedNode(attr.value, [attr.name], attr, entries, index, code);
|
|
662
|
+
}
|
|
663
|
+
return {
|
|
664
|
+
entries,
|
|
665
|
+
index
|
|
666
|
+
};
|
|
667
|
+
};
|
|
668
|
+
const collectParsedNode = (node, path, attr, entries, index, code) => {
|
|
669
|
+
if (node.kind === "string") {
|
|
670
|
+
entries.push({
|
|
671
|
+
path,
|
|
672
|
+
value: node.value,
|
|
673
|
+
editable: true,
|
|
674
|
+
kind: "string"
|
|
675
|
+
});
|
|
676
|
+
index.set(path.join("."), {
|
|
677
|
+
attrName: attr.name,
|
|
678
|
+
attrRange: attr.range,
|
|
679
|
+
range: node.range,
|
|
680
|
+
kind: "string",
|
|
681
|
+
meta: { quote: node.quote }
|
|
682
|
+
});
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
if (node.kind === "number") {
|
|
686
|
+
entries.push({
|
|
687
|
+
path,
|
|
688
|
+
value: node.value,
|
|
689
|
+
editable: true,
|
|
690
|
+
kind: "number"
|
|
691
|
+
});
|
|
692
|
+
index.set(path.join("."), {
|
|
693
|
+
attrName: attr.name,
|
|
694
|
+
attrRange: attr.range,
|
|
695
|
+
range: node.range,
|
|
696
|
+
kind: "number"
|
|
697
|
+
});
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
if (node.kind === "boolean") {
|
|
701
|
+
entries.push({
|
|
702
|
+
path,
|
|
703
|
+
value: node.value,
|
|
704
|
+
editable: true,
|
|
705
|
+
kind: "boolean"
|
|
706
|
+
});
|
|
707
|
+
index.set(path.join("."), {
|
|
708
|
+
attrName: attr.name,
|
|
709
|
+
attrRange: attr.range,
|
|
710
|
+
range: node.range,
|
|
711
|
+
kind: "boolean"
|
|
712
|
+
});
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
if (node.kind === "array") {
|
|
716
|
+
if (node.value.every(isPrimitiveNode)) {
|
|
717
|
+
entries.push({
|
|
718
|
+
path,
|
|
719
|
+
value: node.value.map((item) => item.value),
|
|
720
|
+
editable: true,
|
|
721
|
+
kind: "array"
|
|
722
|
+
});
|
|
723
|
+
index.set(path.join("."), {
|
|
724
|
+
attrName: attr.name,
|
|
725
|
+
attrRange: attr.range,
|
|
726
|
+
range: node.range,
|
|
727
|
+
kind: "array"
|
|
728
|
+
});
|
|
729
|
+
} else entries.push({
|
|
730
|
+
path,
|
|
731
|
+
value: null,
|
|
732
|
+
editable: false,
|
|
733
|
+
kind: "expression",
|
|
734
|
+
code: codeFromRange(code, node.range)
|
|
735
|
+
});
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
if (node.kind === "object") {
|
|
739
|
+
for (const [key, value] of Object.entries(node.value)) collectParsedNode(value, [...path, key], attr, entries, index, code);
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
entries.push({
|
|
743
|
+
path,
|
|
744
|
+
value: null,
|
|
745
|
+
editable: false,
|
|
746
|
+
kind: "expression",
|
|
747
|
+
code: node.code
|
|
748
|
+
});
|
|
749
|
+
};
|
|
750
|
+
const isPrimitiveNode = (node) => node.kind === "string" || node.kind === "number" || node.kind === "boolean";
|
|
751
|
+
const codeFromRange = (code, range) => {
|
|
752
|
+
return code.slice(range.start, range.end);
|
|
753
|
+
};
|
|
754
|
+
const parseValue = (rawValue, kind) => {
|
|
755
|
+
if (kind === "number") {
|
|
756
|
+
const num = typeof rawValue === "number" ? rawValue : Number(rawValue);
|
|
757
|
+
if (Number.isNaN(num)) throw new Error("Invalid number value.");
|
|
758
|
+
return num;
|
|
759
|
+
}
|
|
760
|
+
if (kind === "boolean") {
|
|
761
|
+
if (typeof rawValue === "boolean") return rawValue;
|
|
762
|
+
if (rawValue === "true") return true;
|
|
763
|
+
if (rawValue === "false") return false;
|
|
764
|
+
throw new Error("Invalid boolean value.");
|
|
765
|
+
}
|
|
766
|
+
if (kind === "array") {
|
|
767
|
+
if (Array.isArray(rawValue)) return rawValue;
|
|
768
|
+
if (typeof rawValue === "string") {
|
|
769
|
+
const parsed = JSON.parse(rawValue);
|
|
770
|
+
if (!Array.isArray(parsed)) throw new Error("Array value must be a JSON array.");
|
|
771
|
+
return parsed;
|
|
772
|
+
}
|
|
773
|
+
throw new Error("Invalid array value.");
|
|
774
|
+
}
|
|
775
|
+
if (kind === "string") return String(rawValue);
|
|
776
|
+
return rawValue;
|
|
777
|
+
};
|
|
778
|
+
const formatValue = (value, kind, meta) => {
|
|
779
|
+
if (kind === "string") return formatString(String(value ?? ""), meta?.quote);
|
|
780
|
+
if (kind === "number") return String(value);
|
|
781
|
+
if (kind === "boolean") return value ? "true" : "false";
|
|
782
|
+
if (kind === "array") {
|
|
783
|
+
if (!Array.isArray(value)) throw new Error("Array value must be an array.");
|
|
784
|
+
return `[${value.map(formatArrayItem).join(", ")}]`;
|
|
785
|
+
}
|
|
786
|
+
return String(value);
|
|
787
|
+
};
|
|
788
|
+
const formatAttribute = (name, value, kind, formattedValue) => {
|
|
789
|
+
if (kind === "boolean" && value === true) return name;
|
|
790
|
+
if (kind === "string") return `${name}=${formattedValue}`;
|
|
791
|
+
return `${name}={${formattedValue}}`;
|
|
792
|
+
};
|
|
793
|
+
const formatArrayItem = (value) => {
|
|
794
|
+
if (typeof value === "string") return formatString(value, "\"");
|
|
795
|
+
if (typeof value === "number") return String(value);
|
|
796
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
797
|
+
return "null";
|
|
798
|
+
};
|
|
799
|
+
const formatString = (value, quote) => {
|
|
800
|
+
const useQuote = quote ?? "\"";
|
|
801
|
+
return `${useQuote}${value.replace(/\\/g, "\\\\").replace(new RegExp(useQuote, "g"), `\\${useQuote}`).replace(/\n/g, "\\n").replace(/\r/g, "\\r")}${useQuote}`;
|
|
802
|
+
};
|
|
803
|
+
const replaceText = (code, start, end, replacement) => {
|
|
804
|
+
return code.slice(0, start) + replacement + code.slice(end);
|
|
805
|
+
};
|
|
806
|
+
|
|
807
|
+
//#endregion
|
|
808
|
+
exports.startDevServer = startDevServer;
|