@upstart.gg/vite-plugins 0.0.38 → 0.0.40
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/dist/upstart-editor-api.d.ts +79 -0
- package/dist/upstart-editor-api.d.ts.map +1 -0
- package/dist/upstart-editor-api.js +208 -0
- package/dist/upstart-editor-api.js.map +1 -0
- package/dist/vite-plugin-upstart-attrs.d.ts +3 -3
- package/dist/vite-plugin-upstart-attrs.d.ts.map +1 -1
- package/dist/vite-plugin-upstart-attrs.js +227 -25
- package/dist/vite-plugin-upstart-attrs.js.map +1 -1
- package/dist/vite-plugin-upstart-branding/plugin.d.ts +17 -0
- package/dist/vite-plugin-upstart-branding/plugin.d.ts.map +1 -0
- package/dist/vite-plugin-upstart-branding/plugin.js +41 -0
- package/dist/vite-plugin-upstart-branding/plugin.js.map +1 -0
- package/dist/vite-plugin-upstart-branding/runtime.d.ts +10 -0
- package/dist/vite-plugin-upstart-branding/runtime.d.ts.map +1 -0
- package/dist/vite-plugin-upstart-branding/runtime.js +118 -0
- package/dist/vite-plugin-upstart-branding/runtime.js.map +1 -0
- package/dist/vite-plugin-upstart-branding/types.d.ts +14 -0
- package/dist/vite-plugin-upstart-branding/types.d.ts.map +1 -0
- package/dist/vite-plugin-upstart-branding/types.js +1 -0
- package/dist/vite-plugin-upstart-editor/plugin.d.ts +3 -3
- package/dist/vite-plugin-upstart-editor/plugin.d.ts.map +1 -1
- package/dist/vite-plugin-upstart-editor/plugin.js +3 -16
- package/dist/vite-plugin-upstart-editor/plugin.js.map +1 -1
- package/dist/vite-plugin-upstart-editor/runtime/click-handler.js +25 -11
- package/dist/vite-plugin-upstart-editor/runtime/click-handler.js.map +1 -1
- package/dist/vite-plugin-upstart-editor/runtime/error-handler.d.ts +5 -0
- package/dist/vite-plugin-upstart-editor/runtime/error-handler.d.ts.map +1 -0
- package/dist/vite-plugin-upstart-editor/runtime/error-handler.js +16 -0
- package/dist/vite-plugin-upstart-editor/runtime/error-handler.js.map +1 -0
- package/dist/vite-plugin-upstart-editor/runtime/hover-overlay.js +1 -1
- package/dist/vite-plugin-upstart-editor/runtime/hover-overlay.js.map +1 -1
- package/dist/vite-plugin-upstart-editor/runtime/index.d.ts +2 -1
- package/dist/vite-plugin-upstart-editor/runtime/index.d.ts.map +1 -1
- package/dist/vite-plugin-upstart-editor/runtime/index.js +42 -7
- package/dist/vite-plugin-upstart-editor/runtime/index.js.map +1 -1
- package/dist/vite-plugin-upstart-editor/runtime/text-editor.d.ts +6 -1
- package/dist/vite-plugin-upstart-editor/runtime/text-editor.d.ts.map +1 -1
- package/dist/vite-plugin-upstart-editor/runtime/text-editor.js +423 -129
- package/dist/vite-plugin-upstart-editor/runtime/text-editor.js.map +1 -1
- package/dist/vite-plugin-upstart-editor/runtime/types.d.ts +18 -10
- package/dist/vite-plugin-upstart-editor/runtime/types.d.ts.map +1 -1
- package/dist/vite-plugin-upstart-theme.d.ts +3 -3
- package/dist/vite-plugin-upstart-theme.d.ts.map +1 -1
- package/dist/vite-plugin-upstart-theme.js +1 -3
- package/dist/vite-plugin-upstart-theme.js.map +1 -1
- package/package.json +12 -4
- package/src/tests/upstart-editor-api.test.ts +98 -174
- package/src/tests/vite-plugin-upstart-attrs.test.ts +408 -105
- package/src/tests/vite-plugin-upstart-branding.test.ts +90 -0
- package/src/tests/vite-plugin-upstart-editor.test.ts +1 -2
- package/src/upstart-editor-api.ts +90 -29
- package/src/vite-plugin-upstart-attrs.ts +376 -38
- package/src/vite-plugin-upstart-branding/plugin.ts +59 -0
- package/src/vite-plugin-upstart-branding/runtime.ts +128 -0
- package/src/vite-plugin-upstart-branding/types.ts +10 -0
- package/src/vite-plugin-upstart-editor/plugin.ts +4 -19
- package/src/vite-plugin-upstart-editor/runtime/click-handler.ts +25 -12
- package/src/vite-plugin-upstart-editor/runtime/error-handler.ts +12 -0
- package/src/vite-plugin-upstart-editor/runtime/hover-overlay.ts +1 -1
- package/src/vite-plugin-upstart-editor/runtime/index.ts +39 -5
- package/src/vite-plugin-upstart-editor/runtime/text-editor.ts +518 -141
- package/src/vite-plugin-upstart-editor/runtime/types.ts +18 -4
- package/src/vite-plugin-upstart-theme.ts +0 -3
- package/src/vite-plugin-upstart-editor/PLAN.md +0 -1391
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { upstartBranding } from "../vite-plugin-upstart-branding/plugin";
|
|
3
|
+
import type { UpstartBrandingPluginOptions } from "../vite-plugin-upstart-branding/types";
|
|
4
|
+
|
|
5
|
+
const MAIN_ID = "/project/src/entry.client.tsx";
|
|
6
|
+
const OTHER_ID = "/project/src/other.tsx";
|
|
7
|
+
|
|
8
|
+
type BrandingPlugin = {
|
|
9
|
+
name?: string;
|
|
10
|
+
transform?: ((code: string, id: string) => unknown) | { handler: (code: string, id: string) => unknown };
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
function getPlugin(options: UpstartBrandingPluginOptions): BrandingPlugin {
|
|
14
|
+
const plugin = upstartBranding.vite(options) as unknown;
|
|
15
|
+
return (Array.isArray(plugin) ? plugin[0] : plugin) as BrandingPlugin;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function runTransform(plugin: BrandingPlugin, code: string, id: string): { code: string } | null {
|
|
19
|
+
const transform = plugin.transform;
|
|
20
|
+
if (!transform) {
|
|
21
|
+
throw new Error("Expected transform hook to be defined");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const handler = typeof transform === "function" ? transform : transform.handler;
|
|
25
|
+
const result = handler(code, id);
|
|
26
|
+
|
|
27
|
+
if (typeof result === "string") {
|
|
28
|
+
return { code: result };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (result && typeof result === "object" && "code" in result) {
|
|
32
|
+
return { code: String((result as { code?: unknown }).code ?? "") };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
describe("upstart-branding plugin", () => {
|
|
39
|
+
test("returns disabled plugin when not enabled", () => {
|
|
40
|
+
const plugin = getPlugin({ enabled: false });
|
|
41
|
+
expect(plugin.name).toBe("upstart-branding-disabled");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("returns disabled plugin with default options", () => {
|
|
45
|
+
const plugin = getPlugin({});
|
|
46
|
+
expect(plugin.name).toBe("upstart-branding-disabled");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("injects runtime init into entry file", () => {
|
|
50
|
+
const plugin = getPlugin({ enabled: true });
|
|
51
|
+
|
|
52
|
+
const result = runTransform(plugin, "console.log('app');", MAIN_ID);
|
|
53
|
+
|
|
54
|
+
expect(result).not.toBeNull();
|
|
55
|
+
expect(result?.code).toContain("initUpstartBranding");
|
|
56
|
+
expect(result?.code).toContain("requestIdleCallback");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("does not inject into non-entry files", () => {
|
|
60
|
+
const plugin = getPlugin({ enabled: true });
|
|
61
|
+
|
|
62
|
+
const result = runTransform(plugin, "console.log('app');", OTHER_ID);
|
|
63
|
+
|
|
64
|
+
expect(result).toBeNull();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("does not inject when initUpstartBranding is already present", () => {
|
|
68
|
+
const plugin = getPlugin({ enabled: true });
|
|
69
|
+
|
|
70
|
+
const result = runTransform(
|
|
71
|
+
plugin,
|
|
72
|
+
"import { initUpstartBranding } from 'x'; initUpstartBranding();",
|
|
73
|
+
MAIN_ID,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
expect(result).toBeNull();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("skips node_modules files", () => {
|
|
80
|
+
const plugin = getPlugin({ enabled: true });
|
|
81
|
+
|
|
82
|
+
const result = runTransform(
|
|
83
|
+
plugin,
|
|
84
|
+
"console.log('app');",
|
|
85
|
+
"/project/node_modules/some-pkg/entry.client.tsx",
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
expect(result).toBeNull();
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -2,7 +2,7 @@ import { describe, expect, test } from "vitest";
|
|
|
2
2
|
import { upstartEditor } from "../vite-plugin-upstart-editor/plugin";
|
|
3
3
|
import type { UpstartEditorPluginOptions } from "../vite-plugin-upstart-editor/runtime/types";
|
|
4
4
|
|
|
5
|
-
const MAIN_ID = "/project/src/
|
|
5
|
+
const MAIN_ID = "/project/src/entry.client.tsx";
|
|
6
6
|
const OTHER_ID = "/project/src/other.tsx";
|
|
7
7
|
|
|
8
8
|
type EditorPlugin = {
|
|
@@ -48,7 +48,6 @@ describe("upstart-editor plugin", () => {
|
|
|
48
48
|
|
|
49
49
|
expect(result).not.toBeNull();
|
|
50
50
|
expect(result?.code).toContain("initUpstartEditor");
|
|
51
|
-
expect(result?.code).toContain("DOMContentLoaded");
|
|
52
51
|
});
|
|
53
52
|
|
|
54
53
|
test("does not inject into non-entry files", () => {
|
|
@@ -1,18 +1,47 @@
|
|
|
1
1
|
import MagicString from "magic-string";
|
|
2
2
|
import fs from "fs/promises";
|
|
3
3
|
import path from "path";
|
|
4
|
+
import z from "zod";
|
|
4
5
|
import type { EditableEntry } from "./vite-plugin-upstart-attrs";
|
|
5
6
|
|
|
7
|
+
export const payloadEditText = z.object({
|
|
8
|
+
action: z.literal("editText"),
|
|
9
|
+
language: z
|
|
10
|
+
.string()
|
|
11
|
+
.length(2)
|
|
12
|
+
.regex(/^[a-z]{2}$/),
|
|
13
|
+
namespace: z.string().regex(/^[a-z0-9_-]+$/),
|
|
14
|
+
key: z.string().regex(/^[a-zA-Z0-9_.-]+$/),
|
|
15
|
+
content: z.string(),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export type PayloadEditText = z.infer<typeof payloadEditText>;
|
|
19
|
+
|
|
20
|
+
export const payloadEditClassName = z.object({
|
|
21
|
+
action: z.literal("editClassName"),
|
|
22
|
+
id: z.string().min(1),
|
|
23
|
+
className: z.string(),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export type PayloadEditClassName = z.infer<typeof payloadEditClassName>;
|
|
27
|
+
|
|
6
28
|
export interface EditableRegistry {
|
|
7
29
|
version: number;
|
|
8
30
|
generatedAt: string;
|
|
9
31
|
elements: Record<string, EditableEntry>;
|
|
10
32
|
}
|
|
11
33
|
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
34
|
+
export type EditResult =
|
|
35
|
+
| {
|
|
36
|
+
success: true;
|
|
37
|
+
error?: never;
|
|
38
|
+
filePath: string;
|
|
39
|
+
}
|
|
40
|
+
| {
|
|
41
|
+
success: false;
|
|
42
|
+
error: string;
|
|
43
|
+
filePath?: never;
|
|
44
|
+
};
|
|
16
45
|
|
|
17
46
|
export class UpstartEditorAPI {
|
|
18
47
|
private registry: EditableRegistry | null = null;
|
|
@@ -47,33 +76,72 @@ export class UpstartEditorAPI {
|
|
|
47
76
|
}
|
|
48
77
|
|
|
49
78
|
/**
|
|
50
|
-
* Edit
|
|
79
|
+
* Edit a translation value in an i18next locale file.
|
|
80
|
+
* Auto-detects flat keys (e.g. "nav.home" as literal key) vs nested keys (e.g. nav -> home).
|
|
81
|
+
* Only updates existing keys — returns an error if the key is not found.
|
|
51
82
|
*/
|
|
52
|
-
async editText(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
} catch (err) {
|
|
57
|
-
return { success: false, error: `Failed to load registry: ${err}` };
|
|
58
|
-
}
|
|
83
|
+
async editText(params: PayloadEditText): Promise<EditResult> {
|
|
84
|
+
const parsed = payloadEditText.safeParse(params);
|
|
85
|
+
if (!parsed.success) {
|
|
86
|
+
return { success: false, error: `Invalid payload: ${parsed.error.message}` };
|
|
59
87
|
}
|
|
88
|
+
const { language, namespace, key, content: newContent } = parsed.data;
|
|
89
|
+
const filePath = path.join(this.projectRoot, "app", "locales", language, `${namespace}.json`);
|
|
60
90
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
91
|
+
let raw: string;
|
|
92
|
+
try {
|
|
93
|
+
raw = await fs.readFile(filePath, "utf-8");
|
|
94
|
+
} catch (err) {
|
|
95
|
+
return { success: false, error: `Failed to read locale file: ${filePath}` };
|
|
64
96
|
}
|
|
65
97
|
|
|
66
|
-
|
|
67
|
-
|
|
98
|
+
let data: Record<string, unknown>;
|
|
99
|
+
try {
|
|
100
|
+
data = JSON.parse(raw);
|
|
101
|
+
} catch (err) {
|
|
102
|
+
return { success: false, error: `Failed to parse locale file: ${filePath}` };
|
|
68
103
|
}
|
|
69
104
|
|
|
70
|
-
|
|
105
|
+
// Strategy 1: check for flat/literal key at top level
|
|
106
|
+
if (key in data && typeof data[key] === "string") {
|
|
107
|
+
data[key] = newContent;
|
|
108
|
+
} else {
|
|
109
|
+
// Strategy 2: nested traversal via dot notation
|
|
110
|
+
const parts = key.split(".");
|
|
111
|
+
let current: Record<string, unknown> = data;
|
|
112
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
113
|
+
const part = parts[i];
|
|
114
|
+
if (current[part] == null || typeof current[part] !== "object") {
|
|
115
|
+
return { success: false, error: `Key "${key}" not found in locale file ${filePath}` };
|
|
116
|
+
}
|
|
117
|
+
current = current[part] as Record<string, unknown>;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const leafKey = parts[parts.length - 1];
|
|
121
|
+
if (!(leafKey in current) || typeof current[leafKey] !== "string") {
|
|
122
|
+
return { success: false, error: `Key "${key}" not found in locale file ${filePath}` };
|
|
123
|
+
}
|
|
124
|
+
current[leafKey] = newContent;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
await fs.writeFile(filePath, JSON.stringify(data, null, 2) + "\n");
|
|
129
|
+
} catch (err) {
|
|
130
|
+
return { success: false, error: `Failed to write locale file: ${filePath}` };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return { success: true, filePath };
|
|
71
134
|
}
|
|
72
135
|
|
|
73
136
|
/**
|
|
74
137
|
* Edit the className of an element
|
|
75
138
|
*/
|
|
76
|
-
async editClassName(
|
|
139
|
+
async editClassName(params: PayloadEditClassName): Promise<EditResult> {
|
|
140
|
+
const parsed = payloadEditClassName.safeParse(params);
|
|
141
|
+
if (!parsed.success) {
|
|
142
|
+
return { success: false, error: `Invalid payload: ${parsed.error.message}` };
|
|
143
|
+
}
|
|
144
|
+
const { id, className: newClassName } = parsed.data;
|
|
77
145
|
if (!this.registry) {
|
|
78
146
|
try {
|
|
79
147
|
await this.loadRegistry();
|
|
@@ -97,11 +165,7 @@ export class UpstartEditorAPI {
|
|
|
97
165
|
/**
|
|
98
166
|
* Apply an edit to a source file
|
|
99
167
|
*/
|
|
100
|
-
private async applyEdit(
|
|
101
|
-
id: string,
|
|
102
|
-
entry: EditableEntry,
|
|
103
|
-
newContent: string
|
|
104
|
-
): Promise<EditResult> {
|
|
168
|
+
private async applyEdit(id: string, entry: EditableEntry, newContent: string): Promise<EditResult> {
|
|
105
169
|
const filePath = path.join(this.projectRoot, entry.file);
|
|
106
170
|
|
|
107
171
|
try {
|
|
@@ -150,12 +214,9 @@ export class UpstartEditorAPI {
|
|
|
150
214
|
}
|
|
151
215
|
|
|
152
216
|
// Save the updated registry
|
|
153
|
-
await fs.writeFile(
|
|
154
|
-
this.registryPath,
|
|
155
|
-
JSON.stringify(this.registry, null, 2)
|
|
156
|
-
);
|
|
217
|
+
await fs.writeFile(this.registryPath, JSON.stringify(this.registry, null, 2));
|
|
157
218
|
|
|
158
|
-
return { success: true };
|
|
219
|
+
return { success: true, filePath };
|
|
159
220
|
} catch (err) {
|
|
160
221
|
return { success: false, error: String(err) };
|
|
161
222
|
}
|