create-qauri 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +95 -0
  3. package/dist/index.mjs +744 -0
  4. package/dist/index.mjs.map +1 -0
  5. package/package.json +52 -0
  6. package/templates/base/README.md.tmpl +22 -0
  7. package/templates/base/gitignore.tmpl +33 -0
  8. package/templates/config/qauri.config.json.tmpl +31 -0
  9. package/templates/frontend/react/index.html +12 -0
  10. package/templates/frontend/react/package.json.tmpl +20 -0
  11. package/templates/frontend/react/src/App.css +32 -0
  12. package/templates/frontend/react/src/App.jsx +17 -0
  13. package/templates/frontend/react/src/main.jsx +10 -0
  14. package/templates/frontend/react/vite.config.js +10 -0
  15. package/templates/frontend/react-ts/index.html +12 -0
  16. package/templates/frontend/react-ts/package.json.tmpl +23 -0
  17. package/templates/frontend/react-ts/src/App.css +32 -0
  18. package/templates/frontend/react-ts/src/App.tsx +17 -0
  19. package/templates/frontend/react-ts/src/main.tsx +10 -0
  20. package/templates/frontend/react-ts/tsconfig.json +15 -0
  21. package/templates/frontend/react-ts/vite.config.ts +10 -0
  22. package/templates/frontend/svelte/index.html +12 -0
  23. package/templates/frontend/svelte/package.json.tmpl +19 -0
  24. package/templates/frontend/svelte/src/App.svelte +46 -0
  25. package/templates/frontend/svelte/src/main.js +7 -0
  26. package/templates/frontend/svelte/vite.config.js +10 -0
  27. package/templates/frontend/svelte-ts/index.html +12 -0
  28. package/templates/frontend/svelte-ts/package.json.tmpl +22 -0
  29. package/templates/frontend/svelte-ts/src/App.svelte +46 -0
  30. package/templates/frontend/svelte-ts/src/main.ts +7 -0
  31. package/templates/frontend/svelte-ts/svelte.config.js +5 -0
  32. package/templates/frontend/svelte-ts/tsconfig.json +14 -0
  33. package/templates/frontend/svelte-ts/vite.config.ts +10 -0
  34. package/templates/frontend/vanilla/index.html +16 -0
  35. package/templates/frontend/vanilla/main.js +6 -0
  36. package/templates/frontend/vanilla/package.json.tmpl +17 -0
  37. package/templates/frontend/vanilla/style.css +25 -0
  38. package/templates/frontend/vanilla-ts/index.html +13 -0
  39. package/templates/frontend/vanilla-ts/main.ts +8 -0
  40. package/templates/frontend/vanilla-ts/package.json.tmpl +18 -0
  41. package/templates/frontend/vanilla-ts/style.css +25 -0
  42. package/templates/frontend/vanilla-ts/tsconfig.json +14 -0
  43. package/templates/frontend/vanilla-ts/vite.config.ts +8 -0
  44. package/templates/frontend/vue/index.html +12 -0
  45. package/templates/frontend/vue/package.json.tmpl +19 -0
  46. package/templates/frontend/vue/src/App.vue +48 -0
  47. package/templates/frontend/vue/src/main.js +4 -0
  48. package/templates/frontend/vue/vite.config.js +10 -0
  49. package/templates/frontend/vue-ts/index.html +12 -0
  50. package/templates/frontend/vue-ts/package.json.tmpl +21 -0
  51. package/templates/frontend/vue-ts/src/App.vue +48 -0
  52. package/templates/frontend/vue-ts/src/main.ts +4 -0
  53. package/templates/frontend/vue-ts/tsconfig.json +15 -0
  54. package/templates/frontend/vue-ts/vite.config.ts +10 -0
  55. package/templates/native/cpp/CMakeLists.txt.tmpl +16 -0
  56. package/templates/native/cpp/main.cpp.tmpl +24 -0
  57. package/templates/native/python/main.py.tmpl +19 -0
  58. package/templates/native/python/pyproject.toml.tmpl +8 -0
  59. package/templates/native/python/requirements.txt.tmpl +2 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/create.ts","../src/validator.ts","../src/utils/config.ts","../src/config.ts","../src/generator.ts","../src/template.ts","../src/writer.ts","../src/utils/npm.ts","../src/utils/port.ts","../src/utils/environment.ts","../src/index.ts"],"sourcesContent":["import * as p from '@clack/prompts';\r\nimport pc from 'picocolors';\r\nimport { resolve } from 'node:path';\r\nimport { existsSync } from 'node:fs';\r\nimport { validateProjectName } from '../validator.js';\r\nimport { FRAMEWORK_META } from '../config.js';\r\nimport { generateProject } from '../generator.js';\r\nimport { installDependencies } from '../utils/npm.js';\r\nimport { findAvailablePort } from '../utils/port.js';\r\nimport {\r\n SUPPORTED_VERSIONS,\r\n detectPython,\r\n detectQt,\r\n detectUv,\r\n validatePythonPath,\r\n validateQtPath,\r\n} from '../utils/environment.js';\r\nimport { removeDir } from '../writer.js';\r\nimport type { FrontendFramework, FrameworkMeta, ProjectConfig, CreateSelections } from '../types.js';\r\n\r\nfunction selectionsToProjectConfig(selections: CreateSelections): ProjectConfig {\r\n const meta = FRAMEWORK_META[selections.frontendFramework];\r\n return {\r\n projectName: selections.projectName,\r\n language: selections.language,\r\n backend: selections.backend,\r\n frontendFramework: selections.frontendFramework,\r\n pythonEnvTool: selections.pythonEnvTool,\r\n buildSystem: 'cmake',\r\n devServerUrl: `http://localhost:${selections.devPort}`,\r\n devServerPort: selections.devPort,\r\n distDir: meta.distDir,\r\n features: selections.features,\r\n newWindowBehavior: selections.newWindowBehavior,\r\n pythonVersion: selections.pythonVersion,\r\n pythonPath: selections.pythonPath,\r\n qtVersion: selections.qtVersion,\r\n qtPath: selections.qtPath,\r\n };\r\n}\r\n\r\nexport async function createCommand(name?: string): Promise<void> {\r\n p.intro(pc.bgCyan(pc.black(' create-qauri-app ')));\r\n\r\n // 1. Project name\r\n const projectName = await p.text({\r\n message: 'What is your project name?',\r\n placeholder: 'my-qauri-app',\r\n initialValue: name,\r\n defaultValue: 'my-qauri-app',\r\n validate: (value): string | undefined => {\r\n const result = validateProjectName(value);\r\n if (!result.valid) return result.message;\r\n return undefined;\r\n },\r\n });\r\n\r\n if (p.isCancel(projectName)) {\r\n p.cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n // 2. Native language\r\n const language = await p.select({\r\n message: 'Select native language.',\r\n options: [\r\n { value: 'cpp' as const, label: 'C++', hint: 'Pure C++ backend' },\r\n { value: 'python' as const, label: 'Python', hint: 'Python backend with PySide6' },\r\n ],\r\n });\r\n\r\n if (p.isCancel(language)) {\r\n p.cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n // 3. Python configuration (only if Python language selected)\r\n let pythonEnvTool: 'pip' | 'uv' | undefined;\r\n let pythonVersion: string = '3.11'; // Default\r\n let pythonPath: string = '';\r\n\r\n if (language === 'python') {\r\n // 3.1 Python package manager\r\n const pmChoice = await p.select({\r\n message: 'Select Python package manager.',\r\n options: [\r\n { value: 'pip' as const, label: 'pip', hint: 'Standard package manager' },\r\n { value: 'uv' as const, label: 'uv', hint: 'Fast package manager (recommended)' },\r\n ],\r\n });\r\n\r\n if (p.isCancel(pmChoice)) {\r\n p.cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n pythonEnvTool = pmChoice;\r\n\r\n if (pmChoice === 'uv' && !detectUv()) {\r\n p.cancel(\r\n 'uv is not installed. Please install it first:\\n' +\r\n ' pip install uv\\n' +\r\n ' or visit: https://docs.astral.sh/uv/',\r\n );\r\n process.exit(1);\r\n }\r\n\r\n // 3.2 Python version\r\n pythonVersion = await p.select({\r\n message: 'Select Python version.',\r\n options: SUPPORTED_VERSIONS.python.map((v) => ({\r\n value: v,\r\n label: `Python ${v}`,\r\n hint: v === '3.11' ? 'recommended' : undefined,\r\n })),\r\n });\r\n\r\n if (p.isCancel(pythonVersion)) {\r\n p.cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n // 3.3 Detect Python path\r\n pythonPath = detectPython(pythonVersion) || '';\r\n if (pythonPath) {\r\n p.log.info(`Python detected: ${pythonPath}`);\r\n } else {\r\n const manualPython = await p.text({\r\n message: `Python ${pythonVersion} not found. Please enter the path to python.exe:`,\r\n placeholder: 'C:/Python311/python.exe',\r\n validate: (value): string | undefined => {\r\n if (!value) return 'Please enter a path.';\r\n if (!validatePythonPath(value)) return 'Path must end with python.exe';\r\n if (!existsSync(value)) return 'File not found.';\r\n return undefined;\r\n },\r\n });\r\n\r\n if (p.isCancel(manualPython)) {\r\n p.cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n pythonPath = manualPython;\r\n p.log.info(`Using Python: ${pythonPath}`);\r\n }\r\n }\r\n\r\n // 4. Qt version\r\n const qtVersion = await p.select({\r\n message: 'Select Qt version.',\r\n options: SUPPORTED_VERSIONS.qt.map((v) => ({\r\n value: v,\r\n label: `Qt ${v}`,\r\n hint: v === '6.5.3' ? 'recommended' : undefined,\r\n })),\r\n });\r\n\r\n if (p.isCancel(qtVersion)) {\r\n p.cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n // 5. Detect Qt path\r\n let qtPath = detectQt(qtVersion);\r\n if (qtPath) {\r\n p.log.info(`Qt detected: ${qtPath}`);\r\n } else {\r\n const manualQt = await p.text({\r\n message: `Qt ${qtVersion} not found. Please enter the Qt MSVC directory:`,\r\n placeholder: 'C:/Qt/6.5.3/msvc2019_64',\r\n validate: (value): string | undefined => {\r\n if (!value) return 'Please enter a path.';\r\n if (!validateQtPath(value)) return 'Qt6Core.dll not found in bin directory.';\r\n return undefined;\r\n },\r\n });\r\n\r\n if (p.isCancel(manualQt)) {\r\n p.cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n qtPath = manualQt;\r\n p.log.info(`Using Qt: ${qtPath}`);\r\n }\r\n\r\n // 6. Web backend\r\n const backend = await p.select({\r\n message: 'Select web backend.',\r\n options: [\r\n { value: 'webview2' as const, label: 'WebView2', hint: 'Windows native (recommended)' },\r\n { value: 'cef' as const, label: 'CEF', hint: 'Chromium Embedded Framework' },\r\n { value: 'both' as const, label: 'Both', hint: 'Dual backend support' },\r\n ],\r\n });\r\n\r\n if (p.isCancel(backend)) {\r\n p.cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n // 7. Frontend framework\r\n const frameworkOptions = (\r\n Object.entries(FRAMEWORK_META) as [FrontendFramework, FrameworkMeta][]\r\n ).map(([value, meta]) => ({ value, label: meta.displayName }));\r\n\r\n const frontendFramework = await p.select({\r\n message: 'Select a frontend framework.',\r\n options: frameworkOptions,\r\n });\r\n\r\n if (p.isCancel(frontendFramework)) {\r\n p.cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n // 8. Features\r\n const features = await p.multiselect({\r\n message: 'Select features.',\r\n options: [\r\n { value: 'devtools', label: 'DevTools (F12)', hint: 'recommended' },\r\n { value: 'reload', label: 'Reload (F5)', hint: 'recommended' },\r\n { value: 'whitelist', label: 'Command Whitelist' },\r\n { value: 'examples', label: 'Include Examples' },\r\n ],\r\n initialValues: ['devtools', 'reload', 'examples'],\r\n required: false,\r\n });\r\n\r\n if (p.isCancel(features)) {\r\n p.cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n // 9. New window behavior\r\n const newWindowBehavior = await p.select({\r\n message: 'New window behavior?',\r\n options: [\r\n { value: 'block', label: 'Block', hint: 'Prevent new windows' },\r\n { value: 'browser', label: 'Browser', hint: 'Open in default browser' },\r\n { value: 'new-window', label: 'New Window', hint: 'Create new Qauri window' },\r\n ],\r\n });\r\n\r\n if (p.isCancel(newWindowBehavior)) {\r\n p.cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n // 10. Install npm dependencies\r\n const installDeps = await p.confirm({\r\n message: 'Install npm dependencies?',\r\n initialValue: true,\r\n });\r\n\r\n if (p.isCancel(installDeps)) {\r\n p.cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n const projectPath = resolve(process.cwd(), projectName);\r\n\r\n // 11. Check if target directory exists\r\n if (existsSync(projectPath)) {\r\n const overwrite = await p.confirm({\r\n message: `Directory \"${projectName}\" already exists. Overwrite?`,\r\n initialValue: false,\r\n });\r\n\r\n if (p.isCancel(overwrite) || !overwrite) {\r\n p.cancel('Operation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n await removeDir(projectPath);\r\n }\r\n\r\n const s = p.spinner();\r\n\r\n try {\r\n // 12. Find available port\r\n s.start('Finding available port...');\r\n const devPort = await findAvailablePort(5173);\r\n s.stop(`Using port ${devPort}`);\r\n\r\n // 13. Create project structure\r\n s.start('Creating project structure...');\r\n\r\n const selections: CreateSelections = {\r\n projectName,\r\n language,\r\n pythonEnvTool,\r\n backend,\r\n frontendFramework,\r\n features: features as string[],\r\n newWindowBehavior,\r\n installDeps,\r\n pythonVersion,\r\n pythonPath,\r\n qtVersion,\r\n qtPath,\r\n devPort,\r\n };\r\n\r\n const config = selectionsToProjectConfig(selections);\r\n await generateProject(projectPath, config);\r\n s.stop('Project structure created');\r\n\r\n // 16. Install npm dependencies\r\n if (installDeps) {\r\n s.start('Installing npm dependencies...');\r\n await installDependencies(projectPath);\r\n s.stop('Dependencies installed');\r\n }\r\n\r\n // 17. Next steps\r\n let nextSteps = `cd ${projectName}`;\r\n if (!installDeps) {\r\n nextSteps += '\\nnpm install';\r\n }\r\n nextSteps += '\\nqauri dev';\r\n\r\n p.note(nextSteps, 'Next steps');\r\n\r\n p.outro(\r\n pc.green('✓') +\r\n ' Project created successfully!\\n' +\r\n pc.dim(' Run \"qauri dev\" to start development'),\r\n );\r\n } catch (error) {\r\n s.stop('Failed');\r\n p.cancel(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n process.exit(1);\r\n }\r\n}\r\n","import { existsSync } from 'node:fs';\r\nimport { resolve } from 'node:path';\r\n\r\nconst PROJECT_NAME_RE = /^[a-zA-Z][a-zA-Z0-9_-]*$/;\r\n\r\n/**\r\n * Validate a project name.\r\n * Accepts letters (upper/lowercase), numbers, hyphens, and underscores; must start with a letter.\r\n */\r\nexport function validateProjectName(name: string): { valid: boolean; message?: string } {\r\n if (!name) {\r\n return { valid: false, message: 'Project name cannot be empty' };\r\n }\r\n if (!PROJECT_NAME_RE.test(name)) {\r\n return {\r\n valid: false,\r\n message:\r\n 'Project name must start with a letter and contain only letters, numbers, hyphens, and underscores',\r\n };\r\n }\r\n return { valid: true };\r\n}\r\n\r\n/** Check whether a directory already exists at the given path. */\r\nexport function checkDirectoryExists(dir: string): boolean {\r\n return existsSync(resolve(dir));\r\n}\r\n","import { readFile } from 'node:fs/promises';\r\nimport { resolve } from 'node:path';\r\nimport type { CreateSelections, QauriConfig } from '../types.js';\r\n\r\n/**\r\n * Build a QauriConfig from user selections.\r\n *\r\n * Maps features array to the appropriate config flags:\r\n * 'devtools' → debug.enableF12\r\n * 'reload' → debug.enableF5\r\n * 'whitelist' → ipc.enableWhitelist\r\n * 'examples' → ipc.allowedCommands (sample list)\r\n */\r\nexport function buildConfig(selections: CreateSelections): QauriConfig {\r\n const features = selections.features ?? [];\r\n const hasFeature = (f: string) => features.includes(f);\r\n\r\n const config: QauriConfig = {\r\n project: {\r\n name: selections.projectName,\r\n version: '0.1.0',\r\n type: selections.language,\r\n },\r\n window: {\r\n title: selections.projectName,\r\n width: 800,\r\n height: 600,\r\n resizable: true,\r\n center: true,\r\n },\r\n dev: {\r\n serverUrl: `http://localhost:${selections.devPort}`,\r\n autoStart: true,\r\n },\r\n prod: {\r\n distDir: '../dist',\r\n entry: 'index.html',\r\n },\r\n debug: {\r\n enableF12: hasFeature('devtools'),\r\n enableF5: hasFeature('reload'),\r\n },\r\n newWindow: {\r\n behavior: (selections.newWindowBehavior as QauriConfig['newWindow']['behavior']) ?? 'block',\r\n },\r\n ipc: {\r\n enableWhitelist: hasFeature('whitelist'),\r\n ...(hasFeature('examples')\r\n ? { allowedCommands: ['greet', 'getSystemInfo', 'readFile'] }\r\n : {}),\r\n },\r\n };\r\n\r\n // Language-specific sections\r\n if (selections.language === 'python') {\r\n config.python = {\r\n ...(selections.pythonVersion ? { version: selections.pythonVersion } : {}),\r\n ...(selections.pythonPath ? { path: selections.pythonPath } : {}),\r\n ...(selections.pythonEnvTool ? { packageManager: selections.pythonEnvTool } : {}),\r\n };\r\n } else {\r\n config.cpp = {};\r\n }\r\n\r\n if (selections.qtVersion || selections.qtPath) {\r\n config.qt = {\r\n ...(selections.qtVersion ? { version: selections.qtVersion } : {}),\r\n ...(selections.qtPath ? { path: selections.qtPath } : {}),\r\n };\r\n }\r\n\r\n return config;\r\n}\r\n\r\n/** Serialize a QauriConfig to a formatted JSON string (2-space indent + trailing newline). */\r\nexport function serializeConfig(config: QauriConfig): string {\r\n return JSON.stringify(config, null, 2) + '\\n';\r\n}\r\n\r\n/** Parse a JSON string into a QauriConfig. */\r\nexport function parseConfig(json: string): QauriConfig {\r\n return JSON.parse(json) as QauriConfig;\r\n}\r\n\r\n/** Load and parse qauri.config.json from disk. Returns null if the file doesn't exist. */\r\nexport async function loadConfigFromFile(configPath?: string): Promise<QauriConfig | null> {\r\n const filePath = configPath ?? resolve('src-qauri', 'qauri.config.json');\r\n try {\r\n const content = await readFile(filePath, 'utf-8');\r\n return parseConfig(content);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n","import type { FrontendFramework, FrameworkMeta } from './types.js';\r\n\r\n/** Per-framework metadata (all Vite-based, same defaults). */\r\nexport const FRAMEWORK_META: Record<FrontendFramework, FrameworkMeta> = {\r\n vanilla: { displayName: 'Vanilla', devServerUrl: 'http://localhost:5173', devServerPort: 5173, distDir: '../dist' },\r\n 'vanilla-ts': { displayName: 'Vanilla (TypeScript)', devServerUrl: 'http://localhost:5173', devServerPort: 5173, distDir: '../dist' },\r\n react: { displayName: 'React', devServerUrl: 'http://localhost:5173', devServerPort: 5173, distDir: '../dist' },\r\n 'react-ts': { displayName: 'React (TypeScript)', devServerUrl: 'http://localhost:5173', devServerPort: 5173, distDir: '../dist' },\r\n vue: { displayName: 'Vue', devServerUrl: 'http://localhost:5173', devServerPort: 5173, distDir: '../dist' },\r\n 'vue-ts': { displayName: 'Vue (TypeScript)', devServerUrl: 'http://localhost:5173', devServerPort: 5173, distDir: '../dist' },\r\n svelte: { displayName: 'Svelte', devServerUrl: 'http://localhost:5173', devServerPort: 5173, distDir: '../dist' },\r\n 'svelte-ts': { displayName: 'Svelte (TypeScript)', devServerUrl: 'http://localhost:5173', devServerPort: 5173, distDir: '../dist' },\r\n};\r\n\r\n// Re-export config utilities from utils/config.ts\r\nexport { buildConfig, serializeConfig, parseConfig, loadConfigFromFile } from './utils/config.js';\r\n","import { join, resolve } from 'node:path';\r\nimport { fileURLToPath } from 'node:url';\r\nimport { readFileSync, existsSync } from 'node:fs';\r\nimport { readdirSync, statSync } from 'node:fs';\r\nimport type { ProjectConfig, FileEntry } from './types.js';\r\nimport type { TemplateContext } from './template.js';\r\nimport { renderTemplate, findUnresolvedVariables, TemplateError } from './template.js';\r\nimport { buildConfig, serializeConfig } from './utils/config.js';\r\nimport type { CreateSelections } from './types.js';\r\nimport { writeFile, copyFile, ensureDir, removeDir } from './writer.js';\r\n\r\nconst __dirname = fileURLToPath(new URL('.', import.meta.url));\r\n\r\n/** Resolve the templates root directory. */\r\nfunction templatesRoot(): string {\r\n // In dist/cli.mjs → ../templates\r\n // In src/ during dev → ../templates\r\n const fromDist = resolve(__dirname, '..', 'templates');\r\n if (existsSync(fromDist)) return fromDist;\r\n // Fallback for tests\r\n const fromSrc = resolve(__dirname, '..', '..', 'templates');\r\n if (existsSync(fromSrc)) return fromSrc;\r\n throw new Error('Templates directory not found');\r\n}\r\n\r\n/** Build the template context from a ProjectConfig. */\r\nexport function buildTemplateContext(config: ProjectConfig): TemplateContext {\r\n const backendMap: Record<string, string> = { webview2: 'webview2', cef: 'cef', both: 'auto' };\r\n return {\r\n projectName: config.projectName,\r\n language: config.language,\r\n backend: config.backend,\r\n backendType: backendMap[config.backend],\r\n frontendFramework: config.frontendFramework,\r\n devServerUrl: config.devServerUrl,\r\n devServerPort: config.devServerPort,\r\n devPort: config.devServerPort,\r\n distDir: config.distDir,\r\n pythonEnvTool: config.pythonEnvTool ?? '',\r\n buildSystem: config.buildSystem ?? '',\r\n features: (config.features ?? []).join(','),\r\n newWindowBehavior: config.newWindowBehavior ?? 'block',\r\n pythonVersion: config.pythonVersion ?? '',\r\n pythonPath: config.pythonPath ?? '',\r\n qtVersion: config.qtVersion ?? '',\r\n qtPath: config.qtPath ?? '',\r\n };\r\n}\r\n\r\n/** Recursively list all files under a directory, returning paths relative to base. */\r\nfunction listFiles(dir: string, base: string = dir): string[] {\r\n const results: string[] = [];\r\n if (!existsSync(dir)) return results;\r\n for (const entry of readdirSync(dir)) {\r\n const full = join(dir, entry);\r\n if (statSync(full).isDirectory()) {\r\n results.push(...listFiles(full, base));\r\n } else {\r\n results.push(full.slice(base.length + 1).replace(/\\\\/g, '/'));\r\n }\r\n }\r\n return results;\r\n}\r\n\r\n/** Resolve the list of files to generate for a given config. */\r\nexport function resolveFileList(config: ProjectConfig): FileEntry[] {\r\n const root = templatesRoot();\r\n const entries: FileEntry[] = [];\r\n\r\n // 1. Base templates\r\n const baseDir = join(root, 'base');\r\n for (const rel of listFiles(baseDir)) {\r\n const isTmpl = rel.endsWith('.tmpl');\r\n const targetName = isTmpl ? rel.slice(0, -5) : rel;\r\n // gitignore.tmpl → .gitignore\r\n const target = targetName === 'gitignore' ? '.gitignore' : targetName;\r\n entries.push({ targetPath: target, templatePath: join(baseDir, rel), isTemplate: isTmpl });\r\n }\r\n\r\n // 2. Config template\r\n const configTmpl = join(root, 'config', 'qauri.config.json.tmpl');\r\n if (existsSync(configTmpl)) {\r\n entries.push({ targetPath: 'src-qauri/qauri.config.json', templatePath: configTmpl, isTemplate: true });\r\n }\r\n\r\n // 3. Native templates\r\n const nativeDir = join(root, 'native', config.language);\r\n for (const rel of listFiles(nativeDir)) {\r\n const isTmpl = rel.endsWith('.tmpl');\r\n const targetName = isTmpl ? rel.slice(0, -5) : rel;\r\n entries.push({ targetPath: `src-qauri/${targetName}`, templatePath: join(nativeDir, rel), isTemplate: isTmpl });\r\n }\r\n\r\n // 4. Frontend templates\r\n const fwDir = join(root, 'frontend', config.frontendFramework);\r\n for (const rel of listFiles(fwDir)) {\r\n const isTmpl = rel.endsWith('.tmpl');\r\n const targetName = isTmpl ? rel.slice(0, -5) : rel;\r\n entries.push({ targetPath: targetName, templatePath: join(fwDir, rel), isTemplate: isTmpl });\r\n }\r\n\r\n return entries;\r\n}\r\n\r\n/** Generate the full project into targetDir. Rolls back on failure. */\r\nexport async function generateProject(targetDir: string, config: ProjectConfig): Promise<void> {\r\n const ctx = buildTemplateContext(config);\r\n const files = resolveFileList(config);\r\n\r\n // Also generate qauri.config.json directly (structured, not template-based)\r\n const selections: CreateSelections = {\r\n projectName: config.projectName,\r\n language: config.language,\r\n pythonEnvTool: config.pythonEnvTool,\r\n backend: config.backend,\r\n frontendFramework: config.frontendFramework,\r\n features: config.features ?? [],\r\n newWindowBehavior: config.newWindowBehavior ?? 'block',\r\n installDeps: false,\r\n pythonVersion: config.pythonVersion,\r\n pythonPath: config.pythonPath,\r\n qtVersion: config.qtVersion,\r\n qtPath: config.qtPath,\r\n devPort: config.devServerPort,\r\n };\r\n const qauriConfig = buildConfig(selections);\r\n const qauriConfigContent = serializeConfig(qauriConfig);\r\n\r\n try {\r\n await ensureDir(targetDir);\r\n\r\n for (const entry of files) {\r\n const dest = join(targetDir, entry.targetPath);\r\n\r\n // qauri.config.json is generated from the structured builder, not the template\r\n if (entry.targetPath === 'src-qauri/qauri.config.json') {\r\n await writeFile(dest, qauriConfigContent);\r\n continue;\r\n }\r\n\r\n if (entry.isTemplate) {\r\n const raw = readFileSync(entry.templatePath, 'utf-8');\r\n const rendered = renderTemplate(raw, ctx);\r\n const unresolved = findUnresolvedVariables(rendered);\r\n if (unresolved.length > 0) {\r\n throw new TemplateError(unresolved[0], entry.templatePath);\r\n }\r\n await writeFile(dest, rendered);\r\n } else {\r\n await copyFile(entry.templatePath, dest);\r\n }\r\n }\r\n } catch (err) {\r\n // Rollback: remove partially created directory\r\n await removeDir(targetDir).catch(() => {});\r\n throw err;\r\n }\r\n}\r\n","import { readFileSync } from 'node:fs';\r\n\r\nconst VAR_RE = /\\{\\{(\\w+)\\}\\}/g;\r\n\r\nexport interface TemplateContext {\r\n [key: string]: string | number | boolean;\r\n}\r\n\r\nexport class TemplateError extends Error {\r\n constructor(\r\n public variable: string,\r\n public templateFile?: string,\r\n ) {\r\n const loc = templateFile ? ` in ${templateFile}` : '';\r\n super(`Undefined template variable \"{{${variable}}}\"${loc}`);\r\n this.name = 'TemplateError';\r\n }\r\n}\r\n\r\n/** Replace {{variable}} placeholders in content with values from context. */\r\nexport function renderTemplate(content: string, context: TemplateContext): string {\r\n return content.replace(VAR_RE, (_match, key: string) => {\r\n if (!(key in context)) {\r\n throw new TemplateError(key);\r\n }\r\n return String(context[key]);\r\n });\r\n}\r\n\r\n/** Return array of unresolved {{...}} variable names in content. */\r\nexport function findUnresolvedVariables(content: string): string[] {\r\n const vars: string[] = [];\r\n let m: RegExpExecArray | null;\r\n const re = new RegExp(VAR_RE.source, 'g');\r\n while ((m = re.exec(content)) !== null) {\r\n vars.push(m[1]);\r\n }\r\n return vars;\r\n}\r\n\r\n/** Read a template file, render it, and verify no unresolved variables remain. */\r\nexport function processTemplateFile(filePath: string, context: TemplateContext): string {\r\n const raw = readFileSync(filePath, 'utf-8');\r\n try {\r\n const rendered = renderTemplate(raw, context);\r\n const unresolved = findUnresolvedVariables(rendered);\r\n if (unresolved.length > 0) {\r\n throw new TemplateError(unresolved[0], filePath);\r\n }\r\n return rendered;\r\n } catch (err) {\r\n if (err instanceof TemplateError && !err.templateFile) {\r\n throw new TemplateError(err.variable, filePath);\r\n }\r\n throw err;\r\n }\r\n}\r\n","import { mkdir, writeFile as fsWriteFile, copyFile as fsCopyFile, rm } from 'node:fs/promises';\r\nimport { dirname } from 'node:path';\r\n\r\n/** Create directory recursively. */\r\nexport async function ensureDir(dir: string): Promise<void> {\r\n await mkdir(dir, { recursive: true });\r\n}\r\n\r\n/** Write content to a file, creating parent directories as needed. */\r\nexport async function writeFile(path: string, content: string): Promise<void> {\r\n try {\r\n await ensureDir(dirname(path));\r\n await fsWriteFile(path, content, 'utf-8');\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new Error(`Failed to write ${path}: ${msg}`);\r\n }\r\n}\r\n\r\n/** Copy a file, creating parent directories as needed. */\r\nexport async function copyFile(src: string, dest: string): Promise<void> {\r\n try {\r\n await ensureDir(dirname(dest));\r\n await fsCopyFile(src, dest);\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : String(err);\r\n throw new Error(`Failed to copy ${src} → ${dest}: ${msg}`);\r\n }\r\n}\r\n\r\n/** Remove a directory recursively (for cleanup on failure). */\r\nexport async function removeDir(dir: string): Promise<void> {\r\n await rm(dir, { recursive: true, force: true });\r\n}\r\n","import { spawn, type ChildProcess } from 'node:child_process';\r\nimport { existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\n\r\n/** Install npm dependencies in a project directory. */\r\nexport async function installDependencies(projectPath: string): Promise<void> {\r\n if (!existsSync(join(projectPath, 'package.json'))) {\r\n throw new Error('package.json not found in project directory');\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n const proc = spawn('npm', ['install'], {\r\n cwd: projectPath,\r\n stdio: 'inherit',\r\n shell: true,\r\n });\r\n\r\n proc.on('close', (code) => {\r\n if (code === 0) {\r\n resolve();\r\n } else {\r\n reject(new Error(`npm install failed with code ${code}`));\r\n }\r\n });\r\n\r\n proc.on('error', (err) => {\r\n reject(new Error(`Failed to start npm: ${err.message}`));\r\n });\r\n });\r\n}\r\n\r\n/** Build frontend (npm run build). */\r\nexport async function buildFrontend(projectPath: string): Promise<void> {\r\n if (!existsSync(join(projectPath, 'package.json'))) {\r\n throw new Error('package.json not found in project directory');\r\n }\r\n\r\n return new Promise((resolve, reject) => {\r\n const proc = spawn('npm', ['run', 'build'], {\r\n cwd: projectPath,\r\n stdio: 'inherit',\r\n shell: true,\r\n });\r\n\r\n proc.on('close', (code) => {\r\n if (code === 0) {\r\n resolve();\r\n } else {\r\n reject(new Error(`npm build failed with code ${code}`));\r\n }\r\n });\r\n\r\n proc.on('error', (err) => {\r\n reject(new Error(`Failed to start npm: ${err.message}`));\r\n });\r\n });\r\n}\r\n\r\n/** Start the frontend dev server (npm run dev). Returns the child process. */\r\nexport function startDevServer(projectPath: string): ChildProcess {\r\n return spawn('npm', ['run', 'dev'], {\r\n cwd: projectPath,\r\n stdio: ['ignore', 'pipe', 'pipe'],\r\n shell: true,\r\n });\r\n}\r\n","import net from 'node:net';\r\n\r\n/** Check if a port is in use by trying to connect. */\r\nfunction isPortInUse(port: number): Promise<boolean> {\r\n return new Promise((resolve) => {\r\n const socket = new net.Socket();\r\n\r\n socket.setTimeout(1000);\r\n\r\n socket.once('connect', () => {\r\n socket.destroy();\r\n resolve(true);\r\n });\r\n\r\n socket.once('timeout', () => {\r\n socket.destroy();\r\n resolve(false);\r\n });\r\n\r\n socket.once('error', () => {\r\n socket.destroy();\r\n resolve(false);\r\n });\r\n\r\n socket.connect(port, '127.0.0.1');\r\n });\r\n}\r\n\r\n/** Check if a port is available (not in use and can be bound). */\r\nexport async function isPortAvailable(port: number): Promise<boolean> {\r\n if (port < 1 || port > 65535) {\r\n return false;\r\n }\r\n\r\n const inUse = await isPortInUse(port);\r\n if (inUse) {\r\n return false;\r\n }\r\n\r\n return new Promise((resolve) => {\r\n const server = net.createServer();\r\n\r\n server.once('error', () => {\r\n resolve(false);\r\n });\r\n\r\n server.once('listening', () => {\r\n server.close();\r\n resolve(true);\r\n });\r\n\r\n server.listen(port, '127.0.0.1');\r\n });\r\n}\r\n\r\n/** Find an available port starting from startPort. */\r\nexport async function findAvailablePort(\r\n startPort: number = 5173,\r\n maxAttempts: number = 100,\r\n): Promise<number> {\r\n for (let i = 0; i < maxAttempts; i++) {\r\n const port = startPort + i;\r\n if (port > 65535) break;\r\n\r\n if (await isPortAvailable(port)) {\r\n return port;\r\n }\r\n }\r\n\r\n return startPort;\r\n}\r\n","import { execSync } from 'node:child_process';\r\nimport { existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\n\r\nexport const SUPPORTED_VERSIONS = {\r\n python: ['3.11'] as const,\r\n qt: ['6.5.3', '6.9.2'] as const,\r\n};\r\n\r\nexport type PythonVersion = (typeof SUPPORTED_VERSIONS.python)[number];\r\nexport type QtVersion = (typeof SUPPORTED_VERSIONS.qt)[number];\r\n\r\n/** Detect Python installation path for a given version. Returns null if not found. */\r\nexport function detectPython(version: string): string | null {\r\n const versionNum = version.replace('.', '');\r\n\r\n const possiblePaths = [\r\n `C:/Application/Python${versionNum}/python.exe`,\r\n `C:/Python${versionNum}/python.exe`,\r\n `C:/Program Files/Python${versionNum}/python.exe`,\r\n `C:/Program Files (x86)/Python${versionNum}/python.exe`,\r\n `${process.env.LOCALAPPDATA}/Programs/Python/Python${versionNum}/python.exe`,\r\n `${process.env.USERPROFILE}/Python${versionNum}/python.exe`,\r\n `${process.env.USERPROFILE}/AppData/Local/Programs/Python/Python${versionNum}/python.exe`,\r\n `${process.env.USERPROFILE}/anaconda3/python.exe`,\r\n `${process.env.USERPROFILE}/miniconda3/python.exe`,\r\n `C:/ProgramData/anaconda3/python.exe`,\r\n `C:/ProgramData/miniconda3/python.exe`,\r\n ];\r\n\r\n for (const p of possiblePaths) {\r\n if (p && existsSync(p)) {\r\n try {\r\n const output = execSync(`\"${p}\" --version`, { encoding: 'utf-8' });\r\n if (output.includes(version)) {\r\n return p;\r\n }\r\n } catch {\r\n // continue\r\n }\r\n }\r\n }\r\n\r\n // Try PATH\r\n try {\r\n const result = execSync('where python', { encoding: 'utf-8' });\r\n const paths = result\r\n .split('\\n')\r\n .map((l) => l.trim())\r\n .filter(Boolean);\r\n\r\n for (const pythonPath of paths) {\r\n if (existsSync(pythonPath)) {\r\n try {\r\n const output = execSync(`\"${pythonPath}\" --version`, { encoding: 'utf-8' });\r\n if (output.includes(version)) {\r\n return pythonPath;\r\n }\r\n } catch {\r\n // continue\r\n }\r\n }\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/** Detect Qt installation path for a given version. Returns null if not found. */\r\nexport function detectQt(version: string): string | null {\r\n const msvcSuffix = version.startsWith('6.9') ? 'msvc2022_64' : 'msvc2019_64';\r\n\r\n const possiblePaths = [\r\n `D:/Tools/Qt/${version}/${msvcSuffix}`,\r\n `D:/Qt/${version}/${msvcSuffix}`,\r\n `C:/Qt/${version}/${msvcSuffix}`,\r\n `C:/Tools/Qt/${version}/${msvcSuffix}`,\r\n `C:/Program Files/Qt/${version}/${msvcSuffix}`,\r\n `${process.env.USERPROFILE}/Qt/${version}/${msvcSuffix}`,\r\n `E:/Qt/${version}/${msvcSuffix}`,\r\n `F:/Qt/${version}/${msvcSuffix}`,\r\n ];\r\n\r\n for (const p of possiblePaths) {\r\n if (p && existsSync(join(p, 'bin', 'Qt6Core.dll'))) {\r\n return p;\r\n }\r\n }\r\n\r\n // Check QTDIR env var\r\n if (process.env.QTDIR) {\r\n const qtDir = process.env.QTDIR;\r\n if (existsSync(join(qtDir, 'bin', 'Qt6Core.dll'))) {\r\n return qtDir;\r\n }\r\n }\r\n\r\n // Search Qt root directories\r\n const qtRoots = [\r\n 'C:/Qt',\r\n 'D:/Qt',\r\n 'D:/Tools/Qt',\r\n `${process.env.USERPROFILE}/Qt`,\r\n ];\r\n\r\n for (const root of qtRoots) {\r\n if (root && existsSync(root)) {\r\n const versionDir = join(root, version, msvcSuffix);\r\n if (existsSync(join(versionDir, 'bin', 'Qt6Core.dll'))) {\r\n return versionDir;\r\n }\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/** Check if uv is installed. */\r\nexport function detectUv(): boolean {\r\n try {\r\n execSync('uv --version', { encoding: 'utf-8', stdio: 'pipe' });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/** Validate that a path looks like a Python executable. */\r\nexport function validatePythonPath(path: string): boolean {\r\n return /python\\.exe$/i.test(path);\r\n}\r\n\r\n/** Validate that a path looks like a Qt installation directory. */\r\nexport function validateQtPath(path: string): boolean {\r\n return existsSync(path) && existsSync(join(path, 'bin', 'Qt6Core.dll'));\r\n}\r\n","#!/usr/bin/env node\r\nimport { createCommand } from './commands/create.js';\r\n\r\n// Parse command line args\r\nconst args = process.argv.slice(2);\r\n\r\n// Handle help flag\r\nif (args.includes('--help') || args.includes('-h')) {\r\n console.log(`\r\nUsage: create-qauri [project-name]\r\n\r\nCreate a new Qauri project with interactive prompts.\r\n\r\nArguments:\r\n project-name Optional project name (will prompt if not provided)\r\n\r\nOptions:\r\n -h, --help Display this help message\r\n -v, --version Display version number\r\n\r\nExamples:\r\n $ npm create qauri@latest\r\n $ npm create qauri@latest my-app\r\n $ pnpm create qauri\r\n `);\r\n process.exit(0);\r\n}\r\n\r\n// Handle version flag\r\nif (args.includes('--version') || args.includes('-v')) {\r\n console.log('0.2.0');\r\n process.exit(0);\r\n}\r\n\r\n// Get project name (filter out flags)\r\nconst projectName = args.find(arg => !arg.startsWith('-'));\r\n\r\n// Run create command\r\nawait createCommand(projectName);\r\n"],"mappings":"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","names":["resolve","existsSync","resolve","resolve","readFileSync","existsSync","resolve","existsSync","readFileSync","existsSync","join","resolve","resolve","existsSync","join","p","projectName","existsSync","resolve"]}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "create-qauri",
3
+ "version": "0.2.0",
4
+ "description": "Create a new Qauri project with interactive prompts",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-qauri": "dist/index.mjs"
8
+ },
9
+ "main": "./dist/index.mjs",
10
+ "files": [
11
+ "dist",
12
+ "templates"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsup",
16
+ "dev": "tsup --watch",
17
+ "type-check": "tsc --noEmit",
18
+ "test": "vitest --run",
19
+ "test:watch": "vitest",
20
+ "prepublishOnly": "npm run build && npm test"
21
+ },
22
+ "keywords": [
23
+ "qauri",
24
+ "scaffolding",
25
+ "create-app",
26
+ "desktop",
27
+ "qt",
28
+ "webview",
29
+ "starter"
30
+ ],
31
+ "author": "Qauri Team",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/popo-studio/qauri-create-app.git"
36
+ },
37
+ "homepage": "https://github.com/popo-studio/qauri-create-app#readme",
38
+ "bugs": {
39
+ "url": "https://github.com/popo-studio/qauri-create-app/issues"
40
+ },
41
+ "dependencies": {
42
+ "@clack/prompts": "^0.11.0",
43
+ "picocolors": "^1.1.1"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^20.0.0",
47
+ "fast-check": "^3.15.0",
48
+ "tsup": "^8.0.0",
49
+ "typescript": "^5.0.0",
50
+ "vitest": "^1.0.0"
51
+ }
52
+ }
@@ -0,0 +1,22 @@
1
+ # {{projectName}}
2
+
3
+ A desktop application built with [Qauri](https://github.com/nicq-dev/qauri-web-component).
4
+
5
+ ## Development
6
+
7
+ ### Frontend
8
+
9
+ ```bash
10
+ npm install
11
+ npm run dev
12
+ ```
13
+
14
+ ### Native (src-qauri)
15
+
16
+ See `src-qauri/` for the native application code.
17
+
18
+ ## Build
19
+
20
+ ```bash
21
+ npm run build
22
+ ```
@@ -0,0 +1,33 @@
1
+ # Dependencies
2
+ node_modules/
3
+
4
+ # Build output
5
+ dist/
6
+
7
+ # Qauri build
8
+ src-qauri/build/
9
+ src-qauri/_build/
10
+
11
+ # Python
12
+ __pycache__/
13
+ *.pyc
14
+ .venv/
15
+ *.egg-info/
16
+
17
+ # C++ build artifacts
18
+ *.obj
19
+ *.o
20
+ *.exe
21
+ *.dll
22
+ *.so
23
+ *.dylib
24
+
25
+ # IDE
26
+ .vscode/
27
+ .idea/
28
+ *.swp
29
+ *.swo
30
+
31
+ # OS
32
+ .DS_Store
33
+ Thumbs.db
@@ -0,0 +1,31 @@
1
+ {
2
+ "app": {
3
+ "name": "{{projectName}}",
4
+ "version": "0.1.0"
5
+ },
6
+ "window": {
7
+ "title": "{{projectName}}",
8
+ "width": 800,
9
+ "height": 600,
10
+ "resizable": true,
11
+ "center": true
12
+ },
13
+ "webview": {
14
+ "backendType": "{{backendType}}",
15
+ "devtools": true,
16
+ "contextMenu": true
17
+ },
18
+ "dev": {
19
+ "enabled": true,
20
+ "serverUrl": "{{devServerUrl}}",
21
+ "port": {{devServerPort}},
22
+ "hotReload": true
23
+ },
24
+ "build": {
25
+ "distDir": "{{distDir}}",
26
+ "indexPath": "index.html"
27
+ },
28
+ "security": {
29
+ "allowedOrigins": ["{{devServerUrl}}"]
30
+ }
31
+ }
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Qauri App</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.jsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "@qauri/api": "^0.1.0",
13
+ "react": "^19.0.0",
14
+ "react-dom": "^19.0.0"
15
+ },
16
+ "devDependencies": {
17
+ "@vitejs/plugin-react": "^4.3.0",
18
+ "vite": "^6.0.0"
19
+ }
20
+ }
@@ -0,0 +1,32 @@
1
+ :root {
2
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
3
+ color: #213547;
4
+ background-color: #ffffff;
5
+ }
6
+
7
+ .app {
8
+ max-width: 1280px;
9
+ margin: 0 auto;
10
+ padding: 2rem;
11
+ text-align: center;
12
+ }
13
+
14
+ h1 {
15
+ font-size: 2.4em;
16
+ line-height: 1.1;
17
+ }
18
+
19
+ button {
20
+ border-radius: 8px;
21
+ border: 1px solid transparent;
22
+ padding: 0.6em 1.2em;
23
+ font-size: 1em;
24
+ font-weight: 500;
25
+ font-family: inherit;
26
+ background-color: #f9f9f9;
27
+ cursor: pointer;
28
+ }
29
+
30
+ button:hover {
31
+ border-color: #646cff;
32
+ }
@@ -0,0 +1,17 @@
1
+ import { useState } from 'react';
2
+
3
+ function App() {
4
+ const [count, setCount] = useState(0);
5
+
6
+ return (
7
+ <div className="app">
8
+ <h1>Welcome to Qauri + React</h1>
9
+ <button onClick={() => setCount(c => c + 1)}>
10
+ count is {count}
11
+ </button>
12
+ <p>Edit <code>src/App.jsx</code> and save to reload.</p>
13
+ </div>
14
+ );
15
+ }
16
+
17
+ export default App;
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom/client';
3
+ import App from './App';
4
+ import './App.css';
5
+
6
+ ReactDOM.createRoot(document.getElementById('root')).render(
7
+ <React.StrictMode>
8
+ <App />
9
+ </React.StrictMode>,
10
+ );
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react';
3
+
4
+ export default defineConfig({
5
+ plugins: [react()],
6
+ server: {
7
+ port: 5173,
8
+ strictPort: true,
9
+ },
10
+ });
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Qauri App</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc -b && vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "@qauri/api": "^0.1.0",
13
+ "react": "^19.0.0",
14
+ "react-dom": "^19.0.0"
15
+ },
16
+ "devDependencies": {
17
+ "@types/react": "^19.0.0",
18
+ "@types/react-dom": "^19.0.0",
19
+ "@vitejs/plugin-react": "^4.3.0",
20
+ "typescript": "^5.6.0",
21
+ "vite": "^6.0.0"
22
+ }
23
+ }
@@ -0,0 +1,32 @@
1
+ :root {
2
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
3
+ color: #213547;
4
+ background-color: #ffffff;
5
+ }
6
+
7
+ .app {
8
+ max-width: 1280px;
9
+ margin: 0 auto;
10
+ padding: 2rem;
11
+ text-align: center;
12
+ }
13
+
14
+ h1 {
15
+ font-size: 2.4em;
16
+ line-height: 1.1;
17
+ }
18
+
19
+ button {
20
+ border-radius: 8px;
21
+ border: 1px solid transparent;
22
+ padding: 0.6em 1.2em;
23
+ font-size: 1em;
24
+ font-weight: 500;
25
+ font-family: inherit;
26
+ background-color: #f9f9f9;
27
+ cursor: pointer;
28
+ }
29
+
30
+ button:hover {
31
+ border-color: #646cff;
32
+ }
@@ -0,0 +1,17 @@
1
+ import { useState } from 'react';
2
+
3
+ function App() {
4
+ const [count, setCount] = useState(0);
5
+
6
+ return (
7
+ <div className="app">
8
+ <h1>Welcome to Qauri + React</h1>
9
+ <button onClick={() => setCount((c) => c + 1)}>
10
+ count is {count}
11
+ </button>
12
+ <p>Edit <code>src/App.tsx</code> and save to reload.</p>
13
+ </div>
14
+ );
15
+ }
16
+
17
+ export default App;
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom/client';
3
+ import App from './App';
4
+ import './App.css';
5
+
6
+ ReactDOM.createRoot(document.getElementById('root')!).render(
7
+ <React.StrictMode>
8
+ <App />
9
+ </React.StrictMode>,
10
+ );
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+ "moduleResolution": "bundler",
9
+ "isolatedModules": true,
10
+ "noEmit": true,
11
+ "jsx": "react-jsx",
12
+ "strict": true
13
+ },
14
+ "include": ["src"]
15
+ }
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react';
3
+
4
+ export default defineConfig({
5
+ plugins: [react()],
6
+ server: {
7
+ port: 5173,
8
+ strictPort: true,
9
+ },
10
+ });
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Qauri App</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="/src/main.js"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "@qauri/api": "^0.1.0"
13
+ },
14
+ "devDependencies": {
15
+ "@sveltejs/vite-plugin-svelte": "^4.0.0",
16
+ "svelte": "^5.0.0",
17
+ "vite": "^6.0.0"
18
+ }
19
+ }
@@ -0,0 +1,46 @@
1
+ <script>
2
+ let count = 0;
3
+ </script>
4
+
5
+ <main class="app">
6
+ <h1>Welcome to Qauri + Svelte</h1>
7
+ <button on:click={() => count++}>
8
+ count is {count}
9
+ </button>
10
+ <p>Edit <code>src/App.svelte</code> and save to reload.</p>
11
+ </main>
12
+
13
+ <style>
14
+ :global(:root) {
15
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
16
+ color: #213547;
17
+ background-color: #ffffff;
18
+ }
19
+
20
+ .app {
21
+ max-width: 1280px;
22
+ margin: 0 auto;
23
+ padding: 2rem;
24
+ text-align: center;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 2.4em;
29
+ line-height: 1.1;
30
+ }
31
+
32
+ button {
33
+ border-radius: 8px;
34
+ border: 1px solid transparent;
35
+ padding: 0.6em 1.2em;
36
+ font-size: 1em;
37
+ font-weight: 500;
38
+ font-family: inherit;
39
+ background-color: #f9f9f9;
40
+ cursor: pointer;
41
+ }
42
+
43
+ button:hover {
44
+ border-color: #646cff;
45
+ }
46
+ </style>
@@ -0,0 +1,7 @@
1
+ import App from './App.svelte';
2
+
3
+ const app = new App({
4
+ target: document.getElementById('app'),
5
+ });
6
+
7
+ export default app;
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from 'vite';
2
+ import { svelte } from '@sveltejs/vite-plugin-svelte';
3
+
4
+ export default defineConfig({
5
+ plugins: [svelte()],
6
+ server: {
7
+ port: 5173,
8
+ strictPort: true,
9
+ },
10
+ });
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Qauri App</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="/src/main.ts"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "check": "svelte-check --tsconfig ./tsconfig.json",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "@qauri/api": "^0.1.0"
14
+ },
15
+ "devDependencies": {
16
+ "@sveltejs/vite-plugin-svelte": "^4.0.0",
17
+ "svelte": "^5.0.0",
18
+ "svelte-check": "^4.0.0",
19
+ "typescript": "^5.6.0",
20
+ "vite": "^6.0.0"
21
+ }
22
+ }