create-jsonlink 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # create-jsonlink
2
+
3
+ The official starter and initialization CLI for **[JSON Link](https://json-link.pages.dev)**.
4
+
5
+ Scaffold a high-performance React + Vite + TypeScript application preconfigured with the JSON Link localization workspace, or initialize JSON Link into any existing React project with a single command.
6
+
7
+ ---
8
+
9
+ ## Usage
10
+
11
+ ### Option 1: Create a New Localized App (Zero Setup)
12
+
13
+ ```bash
14
+ npm create jsonlink my-i18n-app
15
+ # or
16
+ npx create-jsonlink my-i18n-app
17
+ ```
18
+
19
+ Then start your app:
20
+
21
+ ```bash
22
+ cd my-i18n-app
23
+ npm install
24
+ npm run dev
25
+ ```
26
+
27
+ - **App**: `http://localhost:5173`
28
+ - **JSON Link Live Dashboard**: `http://localhost:5173/__jsonlink`
29
+
30
+ ---
31
+
32
+ ### Option 2: Initialize in an Existing Vite Project
33
+
34
+ Run inside any existing React + Vite repository root:
35
+
36
+ ```bash
37
+ npx create-jsonlink
38
+ ```
39
+
40
+ This will automatically:
41
+ 1. Detect your package manager (`npm`, `pnpm`, `bun`, `yarn`).
42
+ 2. Inject `jsonLink()` into your `vite.config.ts`.
43
+ 3. Add `@jsonlink/vite-plugin` to `devDependencies`.
44
+ 4. Scaffold `src/locales/` (`en.json`, `my.json`, `translations.d.ts`, `i18n.ts`).
45
+
46
+ ---
47
+
48
+ ## What is Included?
49
+
50
+ - **Vite Devtool Plugin**: Two-way disk synchronization with instant Vite HMR.
51
+ - **Embedded Dev Dashboard**: Full spreadsheet localization table at `http://localhost:5173/__jsonlink`.
52
+ - **Zero Runtime Overhead**: The devtool runs strictly during `vite dev` and tree-shakes completely out of production builds.
53
+ - **Type-Safe Autocomplete**: Full TypeScript definition generation (`translations.d.ts`) for key names and variable interpolations.
54
+ - **Lossless Myanmar Support**: Built-in Unicode and Zawgyi font handling.
55
+
56
+ ---
57
+
58
+ ## License
59
+
60
+ MIT © [Pyae Phyo Maung](https://github.com/pyaephyomaungdev/json-link)
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { runCli } from '../dist/index.js';
4
+
5
+ runCli();
@@ -0,0 +1,5 @@
1
+ import { initExistingProject, findViteConfig, detectPackageManager } from './initExisting.js';
2
+ import { scaffoldStarterProject } from './scaffoldStarter.js';
3
+ export { initExistingProject, scaffoldStarterProject, detectPackageManager, findViteConfig };
4
+ export declare function runCli(argv?: string[]): void;
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9F,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,cAAc,EAAE,CAAC;AAE7F,wBAAgB,MAAM,CAAC,IAAI,WAAwB,GAAG,IAAI,CAqGzD"}
package/dist/index.js ADDED
@@ -0,0 +1,93 @@
1
+ import path from 'node:path';
2
+ import { initExistingProject, findViteConfig, detectPackageManager } from './initExisting.js';
3
+ import { scaffoldStarterProject } from './scaffoldStarter.js';
4
+ export { initExistingProject, scaffoldStarterProject, detectPackageManager, findViteConfig };
5
+ export function runCli(argv = process.argv.slice(2)) {
6
+ const args = argv.filter(a => !a.startsWith('-'));
7
+ const flags = new Set(argv.filter(a => a.startsWith('-')));
8
+ if (flags.has('--help') || flags.has('-h')) {
9
+ console.log(`
10
+ \x1b[36m⚡ create-jsonlink\x1b[0m — Instant local-first localization for React + Vite
11
+
12
+ \x1b[1mUsage:\x1b[0m
13
+ npm create jsonlink [project-name]
14
+ npx create-jsonlink [project-name]
15
+
16
+ \x1b[1mModes:\x1b[0m
17
+ 1. \x1b[32mNew Project Mode:\x1b[0m
18
+ npx create-jsonlink my-i18n-app
19
+ Scaffolds a complete React + TypeScript + Vite project preconfigured with JSON Link.
20
+
21
+ 2. \x1b[32mExisting Project Mode:\x1b[0m
22
+ npx create-jsonlink
23
+ (Run inside an existing Vite project root to inject plugin and scaffold locales)
24
+ `);
25
+ process.exit(0);
26
+ }
27
+ const projectName = args[0];
28
+ const cwd = process.cwd();
29
+ // Mode 1: Project name provided -> Scaffold new starter app
30
+ if (projectName) {
31
+ const targetDir = path.resolve(cwd, projectName);
32
+ console.log(`\n\x1b[36m⚡ Creating a new JSON Link localized project in\x1b[0m \x1b[1m${targetDir}\x1b[0m...\n`);
33
+ const result = scaffoldStarterProject({ targetDir, projectName });
34
+ if (!result.success) {
35
+ console.error(`\x1b[31m✖ ${result.message}\x1b[0m\n`);
36
+ process.exit(1);
37
+ }
38
+ console.log(`\x1b[32m✔\x1b[0m Project created successfully!`);
39
+ console.log(`\x1b[32m✔\x1b[0m React 19 + TypeScript + Vite configured`);
40
+ console.log(`\x1b[32m✔\x1b[0m JSON Link plugin and reactive i18n client scaffolded\n`);
41
+ console.log(`\x1b[1mNext steps:\x1b[0m`);
42
+ console.log(` cd \x1b[36m${projectName}\x1b[0m`);
43
+ console.log(` \x1b[36mnpm install\x1b[0m`);
44
+ console.log(` \x1b[36mnpm run dev\x1b[0m\n`);
45
+ console.log(`Open in browser:`);
46
+ console.log(` App: \x1b[36mhttp://localhost:5173\x1b[0m`);
47
+ console.log(` Live Devtool: \x1b[36mhttp://localhost:5173/__jsonlink\x1b[0m\n`);
48
+ return;
49
+ }
50
+ // Mode 2: No argument provided -> Check if current folder is a Vite project
51
+ const existingViteConfig = findViteConfig(cwd);
52
+ if (existingViteConfig) {
53
+ console.log(`\n\x1b[36m⚡ Existing Vite project detected. Initializing JSON Link...\x1b[0m\n`);
54
+ const pm = detectPackageManager(cwd);
55
+ const result = initExistingProject(cwd);
56
+ if (!result.success) {
57
+ console.error(`\x1b[31m✖ ${result.message}\x1b[0m\n`);
58
+ process.exit(1);
59
+ }
60
+ console.log(`\x1b[32m✔\x1b[0m Injected JSON Link plugin into \x1b[1m${result.viteConfigFile}\x1b[0m`);
61
+ if (result.localesCreated) {
62
+ console.log(`\x1b[32m✔\x1b[0m Created \x1b[1msrc/locales/\x1b[0m (en.json, my.json, translations.d.ts, i18n.ts)`);
63
+ }
64
+ else {
65
+ console.log(`\x1b[33mℹ\x1b[0m Existing \x1b[1msrc/locales/\x1b[0m preserved`);
66
+ }
67
+ if (result.packageUpdated) {
68
+ console.log(`\x1b[32m✔\x1b[0m Added \x1b[1m@jsonlink/vite-plugin\x1b[0m to devDependencies in package.json`);
69
+ }
70
+ console.log(`\n\x1b[32m\x1b[1m🎉 JSON Link Dev Dashboard is ready!\x1b[0m\n`);
71
+ console.log(`Run your dev server:`);
72
+ console.log(` \x1b[36m${pm === 'npm' ? 'npm run dev' : `${pm} dev`}\x1b[0m\n`);
73
+ console.log(`Open translation workspace:`);
74
+ console.log(` 👉 \x1b[36mhttp://localhost:5173/__jsonlink\x1b[0m\n`);
75
+ return;
76
+ }
77
+ // Mode 3: Neither project name nor Vite config in current dir -> Default starter in ./jsonlink-app
78
+ const defaultDir = 'jsonlink-app';
79
+ const targetDir = path.resolve(cwd, defaultDir);
80
+ console.log(`\n\x1b[36m⚡ No Vite project detected in current directory.\x1b[0m`);
81
+ console.log(`Scaffolding a new starter app in \x1b[1m./${defaultDir}\x1b[0m...\n`);
82
+ const result = scaffoldStarterProject({ targetDir, projectName: defaultDir });
83
+ if (!result.success) {
84
+ console.error(`\x1b[31m✖ ${result.message}\x1b[0m\n`);
85
+ process.exit(1);
86
+ }
87
+ console.log(`\x1b[32m✔\x1b[0m Project created successfully!`);
88
+ console.log(`\n\x1b[1mNext steps:\x1b[0m`);
89
+ console.log(` cd \x1b[36m${defaultDir}\x1b[0m`);
90
+ console.log(` \x1b[36mnpm install\x1b[0m`);
91
+ console.log(` \x1b[36mnpm run dev\x1b[0m\n`);
92
+ }
93
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface InitExistingResult {
2
+ success: boolean;
3
+ viteConfigFile?: string;
4
+ localesCreated?: boolean;
5
+ packageUpdated?: boolean;
6
+ message?: string;
7
+ }
8
+ export declare function detectPackageManager(targetDir: string): 'pnpm' | 'yarn' | 'bun' | 'npm';
9
+ export declare function findViteConfig(targetDir: string): string | null;
10
+ export declare function injectVitePlugin(configContent: string): {
11
+ content: string;
12
+ changed: boolean;
13
+ };
14
+ export declare function scaffoldLocales(targetDir: string): boolean;
15
+ export declare function ensurePluginDependency(targetDir: string): boolean;
16
+ export declare function initExistingProject(targetDir?: string): InitExistingResult;
17
+ //# sourceMappingURL=initExisting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initExisting.d.ts","sourceRoot":"","sources":["../src/initExisting.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAKvF;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgB/D;AAED,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAqB7F;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAyI1D;AAED,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAkBjE;AAED,wBAAgB,mBAAmB,CAAC,SAAS,SAAgB,GAAG,kBAAkB,CAwBjF"}
@@ -0,0 +1,219 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ export function detectPackageManager(targetDir) {
4
+ if (fs.existsSync(path.join(targetDir, 'pnpm-lock.yaml')))
5
+ return 'pnpm';
6
+ if (fs.existsSync(path.join(targetDir, 'bun.lockb')) || fs.existsSync(path.join(targetDir, 'bun.lock')))
7
+ return 'bun';
8
+ if (fs.existsSync(path.join(targetDir, 'yarn.lock')))
9
+ return 'yarn';
10
+ return 'npm';
11
+ }
12
+ export function findViteConfig(targetDir) {
13
+ const possibleFiles = [
14
+ 'vite.config.ts',
15
+ 'vite.config.js',
16
+ 'vite.config.mjs',
17
+ 'vite.config.mts',
18
+ ];
19
+ for (const file of possibleFiles) {
20
+ const fullPath = path.join(targetDir, file);
21
+ if (fs.existsSync(fullPath)) {
22
+ return fullPath;
23
+ }
24
+ }
25
+ return null;
26
+ }
27
+ export function injectVitePlugin(configContent) {
28
+ if (configContent.includes('jsonLink(') || configContent.includes('@jsonlink/vite-plugin')) {
29
+ return { content: configContent, changed: false };
30
+ }
31
+ let updated = configContent;
32
+ const importStatement = "import { jsonLink } from '@jsonlink/vite-plugin';\n";
33
+ updated = importStatement + updated;
34
+ const pluginsRegex = /plugins\s*:\s*\[/;
35
+ if (pluginsRegex.test(updated)) {
36
+ updated = updated.replace(pluginsRegex, 'plugins: [\n jsonLink(),');
37
+ }
38
+ else {
39
+ const defineRegex = /defineConfig\s*\(\s*\{/;
40
+ if (defineRegex.test(updated)) {
41
+ updated = updated.replace(defineRegex, 'defineConfig({\n plugins: [jsonLink()],');
42
+ }
43
+ }
44
+ return { content: updated, changed: true };
45
+ }
46
+ export function scaffoldLocales(targetDir) {
47
+ const localesDir = path.join(targetDir, 'src', 'locales');
48
+ if (fs.existsSync(localesDir)) {
49
+ return false;
50
+ }
51
+ fs.mkdirSync(localesDir, { recursive: true });
52
+ const enData = {
53
+ "app.title": "My Localized App",
54
+ "app.description": "A modern multilingual application with JSON Link and React.",
55
+ "auth.welcome": "Welcome back, {username}!",
56
+ "common.save": "Save Changes",
57
+ "common.cancel": "Cancel",
58
+ "common.switch_language": "Language",
59
+ "common.english": "English",
60
+ "common.myanmar": "မြန်မာ"
61
+ };
62
+ fs.writeFileSync(path.join(localesDir, 'en.json'), JSON.stringify(enData, null, 2) + '\n');
63
+ const myData = {
64
+ "app.title": "ကျွန်ုပ်၏အက်ပ်",
65
+ "app.description": "JSON Link နှင့် React ဖြင့် တည်ဆောက်ထားသော ဘာသာစကားစုံသုံး အက်ပ်။",
66
+ "auth.welcome": "ကြိုဆိုပါတယ် {username}!",
67
+ "common.save": "သိမ်းဆည်းမည်",
68
+ "common.cancel": "မလုပ်တော့ပါ",
69
+ "common.switch_language": "ဘာသာစကား",
70
+ "common.english": "English",
71
+ "common.myanmar": "မြန်မာ"
72
+ };
73
+ fs.writeFileSync(path.join(localesDir, 'my.json'), JSON.stringify(myData, null, 2) + '\n');
74
+ const defaultKeys = Object.keys(enData);
75
+ const dtsContent = `export type SupportedLanguage = "en" | "my";
76
+
77
+ export type TranslationKey =
78
+ ${defaultKeys.map(k => ` | ${JSON.stringify(k)}`).join('\n')};
79
+
80
+ export interface TranslationDictionary {
81
+ [key: string]: string;
82
+ }
83
+ `;
84
+ fs.writeFileSync(path.join(localesDir, 'translations.d.ts'), dtsContent);
85
+ const i18nContent = `import { useSyncExternalStore } from 'react';
86
+ import type { SupportedLanguage, TranslationKey } from './translations';
87
+ import en from './en.json';
88
+ import my from './my.json';
89
+
90
+ export const SUPPORTED_LANGUAGES: SupportedLanguage[] = ['en', 'my'];
91
+
92
+ export const resources: Record<SupportedLanguage, Record<string, any>> = {
93
+ 'en': en,
94
+ 'my': my,
95
+ };
96
+
97
+ let currentLanguage: SupportedLanguage = 'en';
98
+ const listeners = new Set<() => void>();
99
+
100
+ function notify() {
101
+ listeners.forEach((listener) => listener());
102
+ }
103
+
104
+ export function setLanguage(lang: SupportedLanguage): void {
105
+ if (resources[lang]) {
106
+ currentLanguage = lang;
107
+ notify();
108
+ }
109
+ }
110
+
111
+ export function getLanguage(): SupportedLanguage {
112
+ return currentLanguage;
113
+ }
114
+
115
+ function resolveValue(obj: Record<string, any>, key: string): string | undefined {
116
+ if (!obj) return undefined;
117
+ if (obj[key] !== undefined) return String(obj[key]);
118
+ const parts = key.split('.');
119
+ let current: any = obj;
120
+ for (const part of parts) {
121
+ if (current && typeof current === 'object' && part in current) {
122
+ current = current[part];
123
+ } else {
124
+ return undefined;
125
+ }
126
+ }
127
+ return typeof current === 'string' ? current : undefined;
128
+ }
129
+
130
+ export function t(
131
+ key: TranslationKey | (string & {}),
132
+ params?: Record<string, string | number>,
133
+ lang?: SupportedLanguage
134
+ ): string {
135
+ const activeLang = lang || currentLanguage;
136
+ const dict = resources[activeLang] || resources['en'] || {};
137
+ let text = resolveValue(dict, key);
138
+
139
+ if (text === undefined) {
140
+ text = resolveValue(resources['en'] || {}, key) ?? key;
141
+ }
142
+
143
+ if (params && typeof text === 'string') {
144
+ return text.replace(/\\{([a-zA-Z0-9_]+)\\}/g, (_, varName) => {
145
+ return params[varName] !== undefined ? String(params[varName]) : \`{\${varName}}\`;
146
+ });
147
+ }
148
+
149
+ return text;
150
+ }
151
+
152
+ export function useTranslation() {
153
+ const lang = useSyncExternalStore(
154
+ (callback) => {
155
+ listeners.add(callback);
156
+ return () => listeners.delete(callback);
157
+ },
158
+ () => currentLanguage
159
+ );
160
+
161
+ return {
162
+ t,
163
+ language: lang,
164
+ setLanguage,
165
+ languages: SUPPORTED_LANGUAGES,
166
+ };
167
+ }
168
+
169
+ if (import.meta.hot) {
170
+ import.meta.hot.accept((newModule) => {
171
+ if (newModule) notify();
172
+ });
173
+ }
174
+ `;
175
+ fs.writeFileSync(path.join(localesDir, 'i18n.ts'), i18nContent);
176
+ return true;
177
+ }
178
+ export function ensurePluginDependency(targetDir) {
179
+ const pkgPath = path.join(targetDir, 'package.json');
180
+ if (!fs.existsSync(pkgPath))
181
+ return false;
182
+ try {
183
+ const raw = fs.readFileSync(pkgPath, 'utf-8');
184
+ const pkg = JSON.parse(raw);
185
+ pkg.devDependencies = pkg.devDependencies || {};
186
+ if (!pkg.devDependencies['@jsonlink/vite-plugin']) {
187
+ pkg.devDependencies['@jsonlink/vite-plugin'] = '^1.0.0';
188
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
189
+ return true;
190
+ }
191
+ }
192
+ catch {
193
+ // Ignore JSON parse errors
194
+ }
195
+ return false;
196
+ }
197
+ export function initExistingProject(targetDir = process.cwd()) {
198
+ const configPath = findViteConfig(targetDir);
199
+ if (!configPath) {
200
+ return {
201
+ success: false,
202
+ message: 'No Vite configuration found (vite.config.ts/js).',
203
+ };
204
+ }
205
+ const rawConfig = fs.readFileSync(configPath, 'utf-8');
206
+ const { content: updatedConfig, changed } = injectVitePlugin(rawConfig);
207
+ if (changed) {
208
+ fs.writeFileSync(configPath, updatedConfig, 'utf-8');
209
+ }
210
+ const localesCreated = scaffoldLocales(targetDir);
211
+ const packageUpdated = ensurePluginDependency(targetDir);
212
+ return {
213
+ success: true,
214
+ viteConfigFile: path.basename(configPath),
215
+ localesCreated,
216
+ packageUpdated,
217
+ };
218
+ }
219
+ //# sourceMappingURL=initExisting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initExisting.js","sourceRoot":"","sources":["../src/initExisting.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export interface StarterOptions {
2
+ targetDir: string;
3
+ projectName: string;
4
+ }
5
+ export declare function scaffoldStarterProject(options: StarterOptions): {
6
+ success: boolean;
7
+ message?: string;
8
+ };
9
+ //# sourceMappingURL=scaffoldStarter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffoldStarter.d.ts","sourceRoot":"","sources":["../src/scaffoldStarter.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,cAAc,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CA6iBtG"}
@@ -0,0 +1,542 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ export function scaffoldStarterProject(options) {
4
+ const { targetDir, projectName } = options;
5
+ if (fs.existsSync(targetDir)) {
6
+ const files = fs.readdirSync(targetDir);
7
+ if (files.length > 0) {
8
+ return {
9
+ success: false,
10
+ message: `Target directory "${projectName}" is not empty. Please use an empty directory or existing Vite project.`,
11
+ };
12
+ }
13
+ }
14
+ else {
15
+ fs.mkdirSync(targetDir, { recursive: true });
16
+ }
17
+ // 1. package.json
18
+ const packageJson = {
19
+ name: projectName,
20
+ private: true,
21
+ version: "0.1.0",
22
+ type: "module",
23
+ scripts: {
24
+ dev: "vite",
25
+ build: "tsc -b && vite build",
26
+ preview: "vite preview"
27
+ },
28
+ dependencies: {
29
+ react: "^19.0.0",
30
+ "react-dom": "^19.0.0",
31
+ "lucide-react": "^1.16.0"
32
+ },
33
+ devDependencies: {
34
+ "@jsonlink/vite-plugin": "^1.0.0",
35
+ "@types/react": "^19.0.10",
36
+ "@types/react-dom": "^19.0.4",
37
+ "@vitejs/plugin-react": "^4.3.4",
38
+ typescript: "~5.7.2",
39
+ vite: "^6.2.0"
40
+ }
41
+ };
42
+ fs.writeFileSync(path.join(targetDir, 'package.json'), JSON.stringify(packageJson, null, 2) + '\n');
43
+ // 2. vite.config.ts
44
+ const viteConfig = `import { defineConfig } from 'vite';
45
+ import react from '@vitejs/plugin-react';
46
+ import { jsonLink } from '@jsonlink/vite-plugin';
47
+
48
+ // https://vite.dev/config/
49
+ export default defineConfig({
50
+ plugins: [
51
+ react(),
52
+ jsonLink({
53
+ localesDir: './src/locales',
54
+ route: '/__jsonlink',
55
+ }),
56
+ ],
57
+ });
58
+ `;
59
+ fs.writeFileSync(path.join(targetDir, 'vite.config.ts'), viteConfig);
60
+ // 3. tsconfig.json, tsconfig.app.json, tsconfig.node.json
61
+ const tsconfig = {
62
+ files: [],
63
+ references: [
64
+ { path: "./tsconfig.app.json" },
65
+ { path: "./tsconfig.node.json" }
66
+ ]
67
+ };
68
+ fs.writeFileSync(path.join(targetDir, 'tsconfig.json'), JSON.stringify(tsconfig, null, 2) + '\n');
69
+ const tsconfigApp = {
70
+ compilerOptions: {
71
+ target: "ES2020",
72
+ useDefineForClassFields: true,
73
+ lib: ["ES2020", "DOM", "DOM.Iterable"],
74
+ module: "ESNext",
75
+ skipLibCheck: true,
76
+ moduleResolution: "bundler",
77
+ allowImportingTsExtensions: false,
78
+ isolatedModules: true,
79
+ moduleDetection: "force",
80
+ noEmit: true,
81
+ jsx: "react-jsx",
82
+ strict: true,
83
+ noUnusedLocals: true,
84
+ noUnusedParameters: true,
85
+ noFallthroughCasesInSwitch: true
86
+ },
87
+ include: ["src"]
88
+ };
89
+ fs.writeFileSync(path.join(targetDir, 'tsconfig.app.json'), JSON.stringify(tsconfigApp, null, 2) + '\n');
90
+ const tsconfigNode = {
91
+ compilerOptions: {
92
+ target: "ES2022",
93
+ lib: ["ES2023"],
94
+ module: "ESNext",
95
+ skipLibCheck: true,
96
+ moduleResolution: "bundler",
97
+ isolatedModules: true,
98
+ moduleDetection: "force",
99
+ noEmit: true,
100
+ strict: true
101
+ },
102
+ include: ["vite.config.ts"]
103
+ };
104
+ fs.writeFileSync(path.join(targetDir, 'tsconfig.node.json'), JSON.stringify(tsconfigNode, null, 2) + '\n');
105
+ // 4. index.html
106
+ const indexHtml = `<!doctype html>
107
+ <html lang="en">
108
+ <head>
109
+ <meta charset="UTF-8" />
110
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
111
+ <link rel="preconnect" href="https://fonts.googleapis.com">
112
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
113
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Noto+Sans+Myanmar:wght@400;500;600;700&display=swap" rel="stylesheet">
114
+ <title>JSON Link App</title>
115
+ </head>
116
+ <body>
117
+ <div id="root"></div>
118
+ <script type="module" src="/src/main.tsx"></script>
119
+ </body>
120
+ </html>
121
+ `;
122
+ fs.writeFileSync(path.join(targetDir, 'index.html'), indexHtml);
123
+ // 5. src directory
124
+ const srcDir = path.join(targetDir, 'src');
125
+ fs.mkdirSync(srcDir, { recursive: true });
126
+ // 6. src/index.css
127
+ const indexCss = `:root {
128
+ font-family: 'Inter', 'Noto Sans Myanmar', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
129
+ line-height: 1.5;
130
+ font-weight: 400;
131
+ color-scheme: dark light;
132
+ color: rgba(255, 255, 255, 0.87);
133
+ background-color: #0f172a;
134
+ }
135
+
136
+ body {
137
+ margin: 0;
138
+ display: flex;
139
+ place-items: center;
140
+ min-width: 320px;
141
+ min-height: 100vh;
142
+ }
143
+
144
+ #root {
145
+ width: 100%;
146
+ max-width: 960px;
147
+ margin: 0 auto;
148
+ padding: 2rem;
149
+ text-align: center;
150
+ }
151
+ `;
152
+ fs.writeFileSync(path.join(srcDir, 'index.css'), indexCss);
153
+ // 7. src/App.css
154
+ const appCss = `.container {
155
+ display: flex;
156
+ flex-direction: column;
157
+ align-items: center;
158
+ gap: 2rem;
159
+ }
160
+
161
+ .badge {
162
+ display: inline-flex;
163
+ align-items: center;
164
+ gap: 0.5rem;
165
+ background: rgba(30, 41, 59, 0.8);
166
+ border: 1px solid rgba(148, 163, 184, 0.2);
167
+ padding: 0.35rem 1rem;
168
+ border-radius: 9999px;
169
+ font-size: 0.875rem;
170
+ color: #38bdf8;
171
+ }
172
+
173
+ .title {
174
+ font-size: 2.75rem;
175
+ font-weight: 800;
176
+ margin: 0;
177
+ background: linear-gradient(135deg, #f8fafc 0%, #94a3b8 100%);
178
+ -webkit-background-clip: text;
179
+ -webkit-text-fill-color: transparent;
180
+ }
181
+
182
+ .subtitle {
183
+ font-size: 1.15rem;
184
+ color: #94a3b8;
185
+ margin: 0;
186
+ max-width: 600px;
187
+ }
188
+
189
+ .lang-picker {
190
+ display: inline-flex;
191
+ background: #1e293b;
192
+ padding: 0.25rem;
193
+ border-radius: 0.75rem;
194
+ border: 1px solid #334155;
195
+ gap: 0.25rem;
196
+ }
197
+
198
+ .lang-btn {
199
+ padding: 0.5rem 1.25rem;
200
+ border-radius: 0.5rem;
201
+ border: none;
202
+ background: transparent;
203
+ color: #94a3b8;
204
+ font-weight: 500;
205
+ cursor: pointer;
206
+ transition: all 0.2s;
207
+ }
208
+
209
+ .lang-btn.active {
210
+ background: #3b82f6;
211
+ color: #ffffff;
212
+ }
213
+
214
+ .card-grid {
215
+ display: grid;
216
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
217
+ gap: 1.5rem;
218
+ width: 100%;
219
+ }
220
+
221
+ .card {
222
+ background: #1e293b;
223
+ border: 1px solid #334155;
224
+ border-radius: 1rem;
225
+ padding: 1.75rem;
226
+ text-align: left;
227
+ display: flex;
228
+ flex-direction: column;
229
+ justify-content: space-between;
230
+ }
231
+
232
+ .card h3 {
233
+ margin-top: 0;
234
+ margin-bottom: 0.5rem;
235
+ color: #f8fafc;
236
+ }
237
+
238
+ .card p {
239
+ color: #94a3b8;
240
+ font-size: 0.95rem;
241
+ line-height: 1.6;
242
+ }
243
+
244
+ .btn-action {
245
+ display: inline-flex;
246
+ align-items: center;
247
+ justify-content: center;
248
+ gap: 0.5rem;
249
+ background: #2563eb;
250
+ color: #ffffff;
251
+ padding: 0.75rem 1.25rem;
252
+ border-radius: 0.5rem;
253
+ text-decoration: none;
254
+ font-weight: 600;
255
+ border: none;
256
+ cursor: pointer;
257
+ margin-top: 1rem;
258
+ transition: background 0.2s;
259
+ }
260
+
261
+ .btn-action:hover {
262
+ background: #1d4ed8;
263
+ }
264
+
265
+ .btn-outline {
266
+ background: transparent;
267
+ border: 1px solid #475569;
268
+ color: #f8fafc;
269
+ }
270
+
271
+ .btn-outline:hover {
272
+ background: #334155;
273
+ }
274
+ `;
275
+ fs.writeFileSync(path.join(srcDir, 'App.css'), appCss);
276
+ // 8. src/main.tsx
277
+ const mainTsx = `import React from 'react';
278
+ import ReactDOM from 'react-dom/client';
279
+ import App from './App';
280
+ import './index.css';
281
+
282
+ ReactDOM.createRoot(document.getElementById('root')!).render(
283
+ <React.StrictMode>
284
+ <App />
285
+ </React.StrictMode>
286
+ );
287
+ `;
288
+ fs.writeFileSync(path.join(srcDir, 'main.tsx'), mainTsx);
289
+ // 9. src/App.tsx
290
+ const appTsx = `import { useState } from 'react';
291
+ import { useTranslation, SupportedLanguage } from './locales/i18n';
292
+ import './App.css';
293
+
294
+ export default function App() {
295
+ const { t, language, setLanguage, languages } = useTranslation();
296
+ const [count, setCount] = useState(0);
297
+
298
+ return (
299
+ <div className="container">
300
+ <div className="badge">
301
+ <span>⚡</span>
302
+ <span>JSON Link Local-First Platform</span>
303
+ </div>
304
+
305
+ <h1 className="title">{t('app.title')}</h1>
306
+ <p className="subtitle">{t('app.subtitle')}</p>
307
+
308
+ {/* Language Switcher */}
309
+ <div className="lang-picker">
310
+ {languages.map((lang: SupportedLanguage) => (
311
+ <button
312
+ key={lang}
313
+ className={\`lang-btn \${language === lang ? 'active' : ''}\`}
314
+ onClick={() => setLanguage(lang)}
315
+ >
316
+ {lang === 'en' ? 'English' : 'မြန်မာ'}
317
+ </button>
318
+ ))}
319
+ </div>
320
+
321
+ <div className="card-grid">
322
+ {/* Interactive Demo Card */}
323
+ <div className="card">
324
+ <div>
325
+ <h3>{t('counter.label')}</h3>
326
+ <p>{t('auth.welcome', { username: 'Developer' })}</p>
327
+ <p>{t('counter.clicks', { count })}</p>
328
+ </div>
329
+ <button className="btn-action btn-outline" onClick={() => setCount((c) => c + 1)}>
330
+ {t('counter.button')}
331
+ </button>
332
+ </div>
333
+
334
+ {/* Devtool Dashboard Card */}
335
+ <div className="card">
336
+ <div>
337
+ <h3>{t('dashboard.card.title')}</h3>
338
+ <p>{t('dashboard.card.desc')}</p>
339
+ </div>
340
+ <a
341
+ href="/__jsonlink"
342
+ target="_blank"
343
+ rel="noopener noreferrer"
344
+ className="btn-action"
345
+ >
346
+ {t('dashboard.card.button')} ↗
347
+ </a>
348
+ </div>
349
+ </div>
350
+ </div>
351
+ );
352
+ }
353
+ `;
354
+ fs.writeFileSync(path.join(srcDir, 'App.tsx'), appTsx);
355
+ // 10. src/locales/
356
+ const localesDir = path.join(srcDir, 'locales');
357
+ fs.mkdirSync(localesDir, { recursive: true });
358
+ const enJson = {
359
+ "app.title": "JSON Link Starter",
360
+ "app.subtitle": "Instant local-first localization for modern React applications with Vite HMR.",
361
+ "auth.welcome": "Welcome back, {username}!",
362
+ "counter.label": "Reactive Localization Demo",
363
+ "counter.clicks": "You have clicked {count} times.",
364
+ "counter.button": "Increment Counter",
365
+ "dashboard.card.title": "Live Translation Workspace",
366
+ "dashboard.card.desc": "Inspect, edit, and organize all your translation keys side-by-side with two-way disk synchronization.",
367
+ "dashboard.card.button": "Open Dev Dashboard",
368
+ "common.switch_language": "Language",
369
+ "common.english": "English",
370
+ "common.myanmar": "မြန်မာ"
371
+ };
372
+ fs.writeFileSync(path.join(localesDir, 'en.json'), JSON.stringify(enJson, null, 2) + '\n');
373
+ const myJson = {
374
+ "app.title": "JSON Link စတင်အသုံးပြုခြင်း",
375
+ "app.subtitle": "React အက်ပ်များအတွက် Vite HMR ဖြင့် ချက်ချင်းချိတ်ဆက်အလုပ်လုပ်သော ဘာသာစကားစုံသုံး စနစ်။",
376
+ "auth.welcome": "ကြိုဆိုပါတယ် {username}!",
377
+ "counter.label": "အပြန်အလှန်တုံ့ပြန်နိုင်သော ကောင်တာ",
378
+ "counter.clicks": "သင် {count} ကြိမ် နှိပ်ခဲ့ပြီးပါပြီ။",
379
+ "counter.button": "ကောင်တာ တိုးမည်",
380
+ "dashboard.card.title": "တိုက်ရိုက် ဘာသာပြန် ဒက်ရှ်ဘုတ်",
381
+ "dashboard.card.desc": "စာသားများကို စာရင်းဇယားအတိုင်း ယှဉ်တွဲပြင်ဆင်ပြီး Disk ပေါ်သို့ တိုက်ရိုက်သိမ်းဆည်းနိုင်ပါသည်။",
382
+ "dashboard.card.button": "ဒက်ရှ်ဘုတ် ဖွင့်မည်",
383
+ "common.switch_language": "ဘာသာစကား",
384
+ "common.english": "English",
385
+ "common.myanmar": "မြန်မာ"
386
+ };
387
+ fs.writeFileSync(path.join(localesDir, 'my.json'), JSON.stringify(myJson, null, 2) + '\n');
388
+ const defaultKeys = Object.keys(enJson);
389
+ const translationsDts = `export type SupportedLanguage = "en" | "my";
390
+
391
+ export type TranslationKey =
392
+ ${defaultKeys.map(k => ` | ${JSON.stringify(k)}`).join('\n')};
393
+
394
+ export interface TranslationDictionary {
395
+ [key: string]: string;
396
+ }
397
+ `;
398
+ fs.writeFileSync(path.join(localesDir, 'translations.d.ts'), translationsDts);
399
+ const i18nTs = `import { useSyncExternalStore } from 'react';
400
+ import type { SupportedLanguage, TranslationKey } from './translations';
401
+ import en from './en.json';
402
+ import my from './my.json';
403
+
404
+ export const SUPPORTED_LANGUAGES: SupportedLanguage[] = ['en', 'my'];
405
+
406
+ export const resources: Record<SupportedLanguage, Record<string, any>> = {
407
+ 'en': en,
408
+ 'my': my,
409
+ };
410
+
411
+ let currentLanguage: SupportedLanguage = 'en';
412
+ const listeners = new Set<() => void>();
413
+
414
+ function notify() {
415
+ listeners.forEach((listener) => listener());
416
+ }
417
+
418
+ export function setLanguage(lang: SupportedLanguage): void {
419
+ if (resources[lang]) {
420
+ currentLanguage = lang;
421
+ notify();
422
+ }
423
+ }
424
+
425
+ export function getLanguage(): SupportedLanguage {
426
+ return currentLanguage;
427
+ }
428
+
429
+ function resolveValue(obj: Record<string, any>, key: string): string | undefined {
430
+ if (!obj) return undefined;
431
+ if (obj[key] !== undefined) return String(obj[key]);
432
+ const parts = key.split('.');
433
+ let current: any = obj;
434
+ for (const part of parts) {
435
+ if (current && typeof current === 'object' && part in current) {
436
+ current = current[part];
437
+ } else {
438
+ return undefined;
439
+ }
440
+ }
441
+ return typeof current === 'string' ? current : undefined;
442
+ }
443
+
444
+ export function t(
445
+ key: TranslationKey | (string & {}),
446
+ params?: Record<string, string | number>,
447
+ lang?: SupportedLanguage
448
+ ): string {
449
+ const activeLang = lang || currentLanguage;
450
+ const dict = resources[activeLang] || resources['en'] || {};
451
+ let text = resolveValue(dict, key);
452
+
453
+ if (text === undefined) {
454
+ text = resolveValue(resources['en'] || {}, key) ?? key;
455
+ }
456
+
457
+ if (params && typeof text === 'string') {
458
+ return text.replace(/\\{([a-zA-Z0-9_]+)\\}/g, (_, varName) => {
459
+ return params[varName] !== undefined ? String(params[varName]) : \`{\${varName}}\`;
460
+ });
461
+ }
462
+
463
+ return text;
464
+ }
465
+
466
+ export function useTranslation() {
467
+ const lang = useSyncExternalStore(
468
+ (callback) => {
469
+ listeners.add(callback);
470
+ return () => listeners.delete(callback);
471
+ },
472
+ () => currentLanguage
473
+ );
474
+
475
+ return {
476
+ t,
477
+ language: lang,
478
+ setLanguage,
479
+ languages: SUPPORTED_LANGUAGES,
480
+ };
481
+ }
482
+
483
+ if (import.meta.hot) {
484
+ import.meta.hot.accept((newModule) => {
485
+ if (newModule) notify();
486
+ });
487
+ }
488
+ `;
489
+ fs.writeFileSync(path.join(localesDir, 'i18n.ts'), i18nTs);
490
+ // 11. .gitignore
491
+ const gitignore = `# Logs
492
+ logs
493
+ *.log
494
+ npm-debug.log*
495
+ yarn-debug.log*
496
+ yarn-error.log*
497
+ pnpm-debug.log*
498
+ lerna-debug.log*
499
+
500
+ node_modules
501
+ dist
502
+ dist-ssr
503
+ *.local
504
+
505
+ # Editor directories and files
506
+ .vscode/*
507
+ !.vscode/extensions.json
508
+ .idea
509
+ .DS_Store
510
+ *.suo
511
+ *.ntvs*
512
+ *.njsproj
513
+ *.sln
514
+ *.sw?
515
+ `;
516
+ fs.writeFileSync(path.join(targetDir, '.gitignore'), gitignore);
517
+ // 12. README.md
518
+ const readme = `# ${projectName}
519
+
520
+ A modern React + Vite application preconfigured with **[JSON Link](https://json-link.pages.dev)**.
521
+
522
+ ## Quick Start
523
+
524
+ \`\`\`bash
525
+ # Install dependencies
526
+ npm install
527
+
528
+ # Start local development server
529
+ npm run dev
530
+ \`\`\`
531
+
532
+ - App is running at: **\`http://localhost:5173\`**
533
+ - JSON Link Live Dashboard: **\`http://localhost:5173/__jsonlink\`**
534
+
535
+ ## Two-Way Disk Synchronization
536
+
537
+ Changes made in the \`/__jsonlink\` web devtool are written directly to \`src/locales/*.json\` on disk with instant Vite HMR.
538
+ `;
539
+ fs.writeFileSync(path.join(targetDir, 'README.md'), readme);
540
+ return { success: true };
541
+ }
542
+ //# sourceMappingURL=scaffoldStarter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffoldStarter.js","sourceRoot":"","sources":["../src/scaffoldStarter.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "create-jsonlink",
3
+ "version": "1.0.0",
4
+ "description": "Scaffold a modern React + Vite application preconfigured with JSON Link localization workspace, or initialize JSON Link in an existing project",
5
+ "author": "Pyae Phyo Maung",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "bin": {
11
+ "create-jsonlink": "./bin/create-jsonlink.js"
12
+ },
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/pyaephyomaungdev/json-link.git",
19
+ "directory": "packages/create-jsonlink"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "bin",
24
+ "README.md"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsc -p tsconfig.json"
28
+ },
29
+ "keywords": [
30
+ "create-jsonlink",
31
+ "jsonlink",
32
+ "json-link",
33
+ "i18n",
34
+ "vite",
35
+ "vite-plugin",
36
+ "react",
37
+ "localization",
38
+ "translation",
39
+ "starter",
40
+ "scaffold",
41
+ "myanmar"
42
+ ]
43
+ }