@object-ui/cli 17.2.0 → 17.5.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/CHANGELOG.md +303 -0
- package/README.md +0 -8
- package/dist/{chunk-EV2DCI7W.js → chunk-2MZA766D.js} +429 -551
- package/dist/chunk-2MZA766D.js.map +1 -0
- package/dist/cli.js +225 -94
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +11 -10
- package/dist/chunk-EV2DCI7W.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/serve.ts","../src/utils/app-generator.ts","../src/utils/scaffold-dependencies.ts","../src/commands/init.ts"],"sourcesContent":["/**\n * ObjectUI\n * Copyright (c) 2024-present ObjectStack Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { createServer } from 'vite';\nimport react from '@vitejs/plugin-react';\nimport { existsSync, mkdirSync } from 'fs';\nimport { join, resolve, relative } from 'path';\nimport chalk from 'chalk';\nimport { execSync } from 'child_process';\nimport { scanPagesDirectory, createTempAppWithRouting, createTempApp, parseSchemaFile, type RouteInfo } from '../utils/app-generator.js';\n\ninterface ServeOptions {\n port: string;\n host: string;\n}\n\nexport async function serve(schemaPath: string, options: ServeOptions) {\n const cwd = process.cwd();\n \n // Check if pages directory exists for file-system routing\n const pagesDir = join(cwd, 'pages');\n const hasPagesDir = existsSync(pagesDir);\n \n let routes: RouteInfo[] = [];\n let schema: unknown = null;\n let useFileSystemRouting = false;\n\n if (hasPagesDir) {\n // File-system based routing\n console.log(chalk.blue('📁 Detected pages/ directory - using file-system routing'));\n routes = scanPagesDirectory(pagesDir);\n useFileSystemRouting = true;\n \n if (routes.length === 0) {\n throw new Error('No schema files found in pages/ directory');\n }\n \n console.log(chalk.green(`✓ Found ${routes.length} route(s)`));\n routes.forEach(route => {\n console.log(chalk.dim(` ${route.path} → ${relative(cwd, route.filePath)}`));\n });\n } else {\n // Single schema file mode\n const fullSchemaPath = resolve(cwd, schemaPath);\n\n // Check if schema file exists\n if (!existsSync(fullSchemaPath)) {\n throw new Error(`Schema file not found: ${schemaPath}\\nRun 'objectui init' to create a sample schema.`);\n }\n\n console.log(chalk.blue('📋 Loading schema:'), chalk.cyan(schemaPath));\n\n // Read and validate schema\n try {\n schema = parseSchemaFile(fullSchemaPath);\n } catch (error) {\n // The caught error's message is inlined below. We can't pass it as the\n // `Error` `cause` option because this package targets ES2020, whose lib\n // types the 1-arg `Error` constructor only; hence the scoped disable.\n // eslint-disable-next-line preserve-caught-error\n throw new Error(`Invalid schema file: ${error instanceof Error ? error.message : error}`);\n }\n }\n\n // Create temporary app directory\n const tmpDir = join(cwd, '.objectui-tmp');\n mkdirSync(tmpDir, { recursive: true });\n\n // Create temporary app files\n if (useFileSystemRouting) {\n createTempAppWithRouting(tmpDir, routes);\n } else {\n createTempApp(tmpDir, schema);\n }\n\n // Install dependencies\n console.log(chalk.blue('📦 Installing dependencies...'));\n console.log(chalk.dim(' This may take a moment on first run...'));\n try {\n execSync('npm install --silent --prefer-offline', { \n cwd: tmpDir, \n stdio: 'inherit',\n });\n console.log(chalk.green('✓ Dependencies installed'));\n } catch {\n throw new Error('Failed to install dependencies. Please check your internet connection and try again.');\n }\n\n console.log(chalk.green('✓ Schema loaded successfully'));\n console.log(chalk.blue('🚀 Starting development server...\\n'));\n\n // Create Vite config\n const viteConfig = {\n root: tmpDir,\n server: {\n port: parseInt(options.port),\n host: options.host,\n open: true,\n },\n plugins: [react()],\n };\n\n // Create Vite server\n const server = await createServer(viteConfig);\n\n await server.listen();\n\n const { port, host } = server.config.server;\n const protocol = server.config.server.https ? 'https' : 'http';\n const displayHost = host === '0.0.0.0' ? 'localhost' : host;\n\n console.log();\n console.log(chalk.green('✓ Server started successfully!'));\n console.log();\n console.log(chalk.bold(' Local: ') + chalk.cyan(`${protocol}://${displayHost}:${port}`));\n console.log();\n console.log(chalk.dim(' Press Ctrl+C to stop the server'));\n console.log();\n}\n","/**\n * ObjectUI\n * Copyright (c) 2024-present ObjectStack Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { readFileSync, writeFileSync, mkdirSync, readdirSync, statSync, existsSync } from 'fs';\nimport { dirname, join } from 'path';\nimport chalk from 'chalk';\nimport * as yaml from 'js-yaml';\n\nimport {\n platformPackageRange,\n REACT_RANGE,\n SCAFFOLD_DEV_DEPENDENCIES\n} from './scaffold-dependencies.js';\n\nexport interface RouteInfo {\n path: string;\n filePath: string;\n schema: unknown;\n isDynamic: boolean;\n paramName?: string;\n}\n\n// Helper function to check if a file is a supported schema file\nexport function isSupportedSchemaFile(filename: string): boolean {\n return filename.endsWith('.json') || \n filename.endsWith('.yml') ||\n filename.endsWith('.yaml');\n}\n\n// Helper function to extract the base filename without extension\nexport function getBaseFileName(filename: string): string {\n // Remove supported extensions\n return filename\n .replace(/\\.(json|yml|yaml)$/, '');\n}\n\n// Helper function to parse schema file (JSON or YAML)\nexport function parseSchemaFile(filePath: string): unknown {\n const content = readFileSync(filePath, 'utf-8');\n \n if (filePath.endsWith('.json')) {\n return JSON.parse(content);\n } else if (filePath.endsWith('.yml') || filePath.endsWith('.yaml')) {\n return yaml.load(content);\n }\n \n throw new Error(`Unsupported file format: ${filePath}`);\n}\n\nexport function scanPagesDirectory(pagesDir: string): RouteInfo[] {\n const routes: RouteInfo[] = [];\n \n const scanDir = (dir: string, routePrefix: string = '') => {\n const entries = readdirSync(dir);\n \n for (const entry of entries) {\n const fullPath = join(dir, entry);\n const stat = statSync(fullPath);\n \n if (stat.isDirectory()) {\n // Recursively scan subdirectories\n const newPrefix = routePrefix + '/' + entry;\n scanDir(fullPath, newPrefix);\n } else if (isSupportedSchemaFile(entry)) {\n // Process schema file\n const fileName = getBaseFileName(entry);\n let routePath: string;\n let isDynamic = false;\n let paramName: string | undefined;\n \n if (fileName === 'index') {\n // index.schema.json or index.page.json maps to the directory path\n routePath = routePrefix || '/';\n } else if (fileName.startsWith('[') && fileName.endsWith(']')) {\n // Dynamic route: [id].schema.json -> /:id\n paramName = fileName.slice(1, -1);\n routePath = routePrefix + '/:' + paramName;\n isDynamic = true;\n } else {\n // Regular file: about.schema.json -> /about\n routePath = routePrefix + '/' + fileName;\n }\n \n // Read and parse schema\n try {\n const schema = parseSchemaFile(fullPath);\n \n routes.push({\n path: routePath,\n filePath: fullPath,\n schema,\n isDynamic,\n paramName,\n });\n } catch (error) {\n console.warn(chalk.yellow(`⚠ Warning: Failed to parse ${fullPath}: ${error instanceof Error ? error.message : error}`));\n }\n }\n }\n };\n \n scanDir(pagesDir);\n \n // Sort routes: exact routes first, then dynamic routes\n routes.sort((a, b) => {\n if (a.isDynamic && !b.isDynamic) return 1;\n if (!a.isDynamic && b.isDynamic) return -1;\n return a.path.localeCompare(b.path);\n });\n \n return routes;\n}\n\n/**\n * `@object-ui/*` packages the generated apps IMPORT, and therefore must declare.\n *\n * Every entry is imported by a generated `src/App.tsx` — the two platform\n * packages by name, the seven plugins as side-effect imports that register\n * their components with the registry. Until objectui#3827 only the first two\n * were declared, so a generated app asked npm for nine packages having named\n * two of them; the seven plugins resolved in this workspace purely because the\n * temp app is created under `<cwd>` and hoisting reached the root\n * `node_modules`.\n *\n * `@object-ui/core` and `@object-ui/types` are deliberately absent: the\n * generated sources never import them (only `commands/dev.ts` aliases them for\n * Vite), and declaring a versioned dependency nothing imports is the defect\n * objectui#3755 removed from the sibling generator. `app-generator.test.ts`\n * gates both directions.\n */\nconst PLATFORM_RUNTIME_PACKAGES = [\n '@object-ui/react',\n '@object-ui/components',\n '@object-ui/plugin-charts',\n '@object-ui/plugin-editor',\n '@object-ui/plugin-kanban',\n '@object-ui/plugin-markdown',\n '@object-ui/plugin-form',\n '@object-ui/plugin-grid',\n '@object-ui/plugin-view'\n] as const;\n\n/**\n * `dependencies` for an app generated WITHOUT routing (`createTempApp`).\n *\n * Exactly the packages `src/main.tsx` and `src/App.tsx` import. No\n * `react-router-dom` and no `lucide-react`: this variant generates neither a\n * router nor a layout.\n */\nfunction buildAppDependencies(): Record<string, string> {\n const range = platformPackageRange();\n return {\n react: REACT_RANGE,\n 'react-dom': REACT_RANGE,\n ...Object.fromEntries(PLATFORM_RUNTIME_PACKAGES.map((name) => [name, range]))\n };\n}\n\n/**\n * `dependencies` for a routed app (`createTempAppWithRouting`).\n *\n * Adds the two packages the routed variant's own sources import and the plain\n * one's do not: `react-router-dom` (router in `src/App.tsx`) and `lucide-react`\n * (icons in `src/Layout.tsx`).\n *\n * `lucide-react` was imported and never declared until objectui#3827 — twice\n * over, `import * as LucideIcons` plus a named `{ Moon, Sun }`, both live in\n * the generated layout. `commands/dev.ts` had been papering over it in the\n * consumer, aliasing `lucide-react` to a path resolved out of\n * `packages/components` with the comment \"avoid dependency not found in temp\n * app\"; that alias only runs in monorepo mode, so every other path was left\n * with an unsatisfiable import. Declaring it at the producer is the fix — the\n * alias becomes a workspace convenience rather than the only thing holding the\n * import up.\n */\nfunction buildRoutedAppDependencies(): Record<string, string> {\n const range = platformPackageRange();\n return {\n react: REACT_RANGE,\n 'react-dom': REACT_RANGE,\n 'react-router-dom': '^7.18.2',\n 'lucide-react': '^1.29.0',\n ...Object.fromEntries(PLATFORM_RUNTIME_PACKAGES.map((name) => [name, range]))\n };\n}\n\n\n/**\n * The generated `src/vite-env.d.ts`, identical for both generators.\n *\n * Both entries do `import './index.css'`, and TypeScript has no idea what a\n * `.css` module is: without this the entry file fails its own `tsconfig.json`\n * with \"Cannot find module or type declarations for side-effect import of\n * './index.css'\". `vite/client` is where the `declare module '*.css'` ambient\n * declarations live, `vite` is already in the generated `devDependencies`, and\n * this is the file `create-vite`'s own React+TS template writes for the same\n * reason — so the fix is the ecosystem's spelling of it rather than a local\n * invention (objectui#3853).\n *\n * It is the one generated `src/**` file that is deliberately unreachable from\n * `src/main.tsx`: an ambient declaration is pulled in by the tsconfig's\n * `include`, never by the module graph. `app-generator.test.ts`'s reachability\n * gate exempts `.d.ts` for exactly that reason and pins the exemption's width.\n */\nconst APP_VITE_ENV_D_TS = `/// <reference types=\"vite/client\" />\\n`;\n\n/** The generated `tsconfig.json`, identical for both generators. */\nconst APP_TSCONFIG = {\n compilerOptions: {\n target: 'ES2020',\n useDefineForClassFields: true,\n lib: ['ES2020', 'DOM', 'DOM.Iterable'],\n module: 'ESNext',\n skipLibCheck: true,\n moduleResolution: 'bundler',\n allowImportingTsExtensions: true,\n resolveJsonModule: true,\n isolatedModules: true,\n noEmit: true,\n jsx: 'react-jsx',\n strict: true,\n noUnusedLocals: true,\n noUnusedParameters: true,\n noFallthroughCasesInSwitch: true\n },\n include: ['src']\n};\n\n/**\n * The generated `postcss.config.js`, identical for both generators.\n *\n * Tailwind 4 moved the PostCSS plugin out of `tailwindcss` into\n * `@tailwindcss/postcss`; naming the old `tailwindcss` key resolves to a shim\n * whose only job is to throw (\"It looks like you're trying to use `tailwindcss`\n * directly as a PostCSS plugin\"). Spelled exactly like\n * `packages/components/postcss.config.js` — objectui#3852.\n */\nconst APP_POSTCSS_CONFIG = `export default {\n plugins: {\n '@tailwindcss/postcss': {},\n autoprefixer: {},\n },\n};`;\n\n/**\n * Where the generator is running, as far as the generated files are concerned.\n *\n * Passed in rather than read from `process.cwd()` inside the builders so the\n * file map is a pure function of its inputs and can be asserted over directly.\n */\nexport interface AppGeneratorContext {\n /** The directory `objectui` was invoked from. */\n cwd: string;\n /** Whether `cwd` is a pnpm workspace root (root `node_modules` is reachable). */\n isMonorepo: boolean;\n}\n\n/** The context the CLI commands themselves generate under. */\nfunction currentContext(): AppGeneratorContext {\n const cwd = process.cwd();\n return { cwd, isMonorepo: existsSync(join(cwd, 'pnpm-workspace.yaml')) };\n}\n\n/**\n * The generated `package.json` for an app without routing.\n *\n * In a monorepo both maps are written EMPTY, which is pre-existing behaviour:\n * the temp app lives under `<cwd>` and resolves everything by hoisting, and\n * `commands/dev.ts` skips `npm install` entirely there. The consequence worth\n * naming is that the ranges below are never the ranges exercised in this repo\n * (objectui#3742's second cost), which is exactly why the tests anchor them to\n * in-repo manifests instead of trusting a green command.\n */\nexport function buildAppPackageJson(context: Pick<AppGeneratorContext, 'isMonorepo'>): Record<string, unknown> {\n return {\n name: 'objectui-temp-app',\n private: true,\n type: 'module',\n // In monorepo, we use root node_modules, so we don't need dependencies here\n dependencies: context.isMonorepo ? {} : buildAppDependencies(),\n devDependencies: context.isMonorepo ? {} : { ...SCAFFOLD_DEV_DEPENDENCIES }\n };\n}\n\n/**\n * The generated `package.json` for a routed app.\n *\n * Unlike the variant above this one has no monorepo branch — it always writes\n * the full manifest, so a missing declaration here is missing everywhere and\n * cannot be explained away by hoisting.\n */\nexport function buildRoutedAppPackageJson(): Record<string, unknown> {\n return {\n name: 'objectui-temp-app',\n private: true,\n type: 'module',\n dependencies: buildRoutedAppDependencies(),\n devDependencies: { ...SCAFFOLD_DEV_DEPENDENCIES }\n };\n}\n\n/**\n * The `@source` directives the generated `src/index.css` registers.\n *\n * Tailwind 4's replacement for v3's `content` globs, and a 1:1 translation of\n * the ones the generated `tailwind.config.js` carried until objectui#3852:\n * the app's own `index.html` and `src/**`, widened inside a workspace to the\n * component library and every `plugin-*` package (the two absolute globs the v3\n * config built from `cwd`, semantics unchanged).\n *\n * Two things are load-bearing and were measured rather than assumed:\n *\n * 1. Relative `@source` paths resolve against the directory of the CSS file\n * that declares them, NOT the app root — this file is written to\n * `src/index.css`, so the app's own sources are `../src/**`, spelled exactly\n * as `packages/components/src/index.css` spells its own.\n * 2. Outside a workspace the platform packages are installed rather than\n * aliased, and their classes live in built JS. v4 does not auto-scan\n * `node_modules` (it is gitignored), so an explicit `@source` over the\n * installed `dist` is the only thing that compiles the library's utilities —\n * the gap the v3 `content` list also had, in the form v4 gives us to close\n * it.\n */\nfunction buildAppSourceDirectives(context: AppGeneratorContext): string[] {\n const sources = [`@source '../index.html';`, `@source '../src/**/*.{js,ts,jsx,tsx,json}';`];\n if (context.isMonorepo) {\n sources.push(`@source '${join(context.cwd, 'packages/components/src/**/*.{ts,tsx}')}';`);\n sources.push(`@source '${join(context.cwd, 'packages/plugin-*/src/**/*.{ts,tsx}')}';`);\n } else {\n sources.push(`@source '../node_modules/@object-ui/*/dist/**/*.js';`);\n }\n return sources;\n}\n\n/**\n * The generated `@theme` block: v4's replacement for v3's `theme.extend`.\n *\n * Token-for-token the set `packages/components/src/index.css` declares, because\n * the generated app owns the single Tailwind entrypoint for everything it\n * renders — the component library deliberately does NOT inject its own sheet\n * (see the note at the top of `packages/components/src/index.ts`), so a token\n * the library's classes need and this block omits simply does not compile. The\n * v3 config's `theme.extend.colors` omitted the eight `sidebar-*` tokens that\n * the generated `src/Layout.tsx` itself uses (`bg-sidebar-primary`,\n * `data-[state=open]:bg-sidebar-accent`, …); `app-generator.test.ts` pins the\n * two sets equal so the omission cannot come back.\n */\nconst APP_THEME_TOKENS = `@theme {\n /* Border radius tokens */\n --radius-lg: var(--radius);\n --radius-md: calc(var(--radius) - 2px);\n --radius-sm: calc(var(--radius) - 4px);\n\n /* Color tokens mapped to the CSS variables declared below */\n --color-border: hsl(var(--border));\n --color-input: hsl(var(--input));\n --color-ring: hsl(var(--ring));\n --color-background: hsl(var(--background));\n --color-foreground: hsl(var(--foreground));\n --color-primary: hsl(var(--primary));\n --color-primary-foreground: hsl(var(--primary-foreground));\n --color-secondary: hsl(var(--secondary));\n --color-secondary-foreground: hsl(var(--secondary-foreground));\n --color-destructive: hsl(var(--destructive));\n --color-destructive-foreground: hsl(var(--destructive-foreground));\n --color-muted: hsl(var(--muted));\n --color-muted-foreground: hsl(var(--muted-foreground));\n --color-accent: hsl(var(--accent));\n --color-accent-foreground: hsl(var(--accent-foreground));\n --color-popover: hsl(var(--popover));\n --color-popover-foreground: hsl(var(--popover-foreground));\n --color-card: hsl(var(--card));\n --color-card-foreground: hsl(var(--card-foreground));\n --color-sidebar: hsl(var(--sidebar));\n --color-sidebar-foreground: hsl(var(--sidebar-foreground));\n --color-sidebar-primary: hsl(var(--sidebar-primary));\n --color-sidebar-primary-foreground: hsl(var(--sidebar-primary-foreground));\n --color-sidebar-accent: hsl(var(--sidebar-accent));\n --color-sidebar-accent-foreground: hsl(var(--sidebar-accent-foreground));\n --color-sidebar-border: hsl(var(--sidebar-border));\n --color-sidebar-ring: hsl(var(--sidebar-ring));\n\n /* Chart colors */\n --color-chart-1: hsl(var(--chart-1));\n --color-chart-2: hsl(var(--chart-2));\n --color-chart-3: hsl(var(--chart-3));\n --color-chart-4: hsl(var(--chart-4));\n --color-chart-5: hsl(var(--chart-5));\n}`;\n\n/**\n * The light/dark custom properties every token above resolves through.\n *\n * Plain CSS at the top level rather than inside `@layer base`, matching\n * `packages/components/src/index.css`: `@theme` already emits into `:root`, and\n * `.dark` only has to override the values. Every `var(--x)` named by\n * `APP_THEME_TOKENS` is declared here — pinned by a test, since a token that\n * resolves to nothing is a class that silently renders unstyled.\n */\nconst APP_THEME_VARIABLES = `:root {\n color-scheme: light;\n\n --background: 0 0% 100%;\n --foreground: 222.2 84% 4.9%;\n --card: 0 0% 100%;\n --card-foreground: 222.2 84% 4.9%;\n --popover: 0 0% 100%;\n --popover-foreground: 222.2 84% 4.9%;\n --primary: 222.2 47.4% 11.2%;\n --primary-foreground: 210 40% 98%;\n --secondary: 210 40% 96.1%;\n --secondary-foreground: 222.2 47.4% 11.2%;\n --muted: 210 40% 96.1%;\n --muted-foreground: 215.4 16.3% 46.9%;\n --accent: 210 40% 96.1%;\n --accent-foreground: 222.2 47.4% 11.2%;\n --destructive: 0 84.2% 60.2%;\n --destructive-foreground: 210 40% 98%;\n --border: 214.3 31.8% 91.4%;\n --input: 214.3 31.8% 91.4%;\n --ring: 222.2 84% 4.9%;\n --radius: 0.5rem;\n --chart-1: 12 76% 61%;\n --chart-2: 173 58% 39%;\n --chart-3: 197 37% 24%;\n --chart-4: 43 74% 66%;\n --chart-5: 27 87% 67%;\n\n /* Sidebar colors */\n --sidebar: 0 0% 98%;\n --sidebar-foreground: 240 5.3% 26.1%;\n --sidebar-primary: 240 5.9% 10%;\n --sidebar-primary-foreground: 0 0% 98%;\n --sidebar-accent: 240 4.8% 95.9%;\n --sidebar-accent-foreground: 240 5.9% 10%;\n --sidebar-border: 220 13% 91%;\n --sidebar-ring: 217.2 91.2% 59.8%;\n}\n\n.dark {\n color-scheme: dark;\n\n --background: 222.2 84% 4.9%;\n --foreground: 210 40% 98%;\n --card: 222.2 84% 4.9%;\n --card-foreground: 210 40% 98%;\n --popover: 222.2 84% 4.9%;\n --popover-foreground: 210 40% 98%;\n --primary: 210 40% 98%;\n --primary-foreground: 222.2 47.4% 11.2%;\n --secondary: 217.2 32.6% 17.5%;\n --secondary-foreground: 210 40% 98%;\n --muted: 217.2 32.6% 17.5%;\n --muted-foreground: 215 20.2% 65.1%;\n --accent: 217.2 32.6% 17.5%;\n --accent-foreground: 210 40% 98%;\n --destructive: 0 62.8% 30.6%;\n --destructive-foreground: 210 40% 98%;\n --border: 217.2 32.6% 17.5%;\n --input: 217.2 32.6% 17.5%;\n --ring: 212.7 26.8% 83.9%;\n --chart-1: 220 70% 50%;\n --chart-2: 160 60% 45%;\n --chart-3: 30 80% 55%;\n --chart-4: 280 65% 60%;\n --chart-5: 340 75% 55%;\n\n /* Sidebar colors for dark mode */\n --sidebar: 240 5.9% 10%;\n --sidebar-foreground: 240 4.8% 95.9%;\n --sidebar-primary: 224.3 76.3% 48%;\n --sidebar-primary-foreground: 0 0% 100%;\n --sidebar-accent: 240 3.7% 15.9%;\n --sidebar-accent-foreground: 240 4.8% 95.9%;\n --sidebar-border: 240 3.7% 15.9%;\n --sidebar-ring: 217.2 91.2% 59.8%;\n}`;\n\n/**\n * The generated `src/index.css` — one Tailwind 4 entrypoint, both generators.\n *\n * Replaces the v3 trio (`@tailwind base/components/utilities` directives, a\n * `tailwind.config.js`, and a `tailwindcss`-keyed PostCSS config) with the\n * CSS-first form this repo uses everywhere: `@import 'tailwindcss'`,\n * `@custom-variant dark`, `@source`, `@theme`. No `tailwind.config.js` is\n * written at all — in v4 a config file is inert unless a stylesheet points\n * `@config` at it, and every source of truth it used to hold now lives here\n * (objectui#3852; the repo itself has carried zero `tailwind.config.*` files\n * since its own v4 migration).\n *\n * The two generators emitted byte-identical CSS apart from three utilities on\n * `body`, so they now share this one builder; the `body` rules below are the\n * routed variant's (`font-sans antialiased min-h-screen`), written as the plain\n * CSS that `packages/components/src/index.css` uses instead of `@apply`.\n */\nfunction buildAppIndexCss(context: AppGeneratorContext): string {\n return `@import 'tailwindcss';\n\n/* Class-based dark variant: follow \\`.dark\\` on <html> — the routed app's\n \\`src/theme-provider.tsx\\` toggles exactly that class — instead of the OS\n \\`prefers-color-scheme\\`. Same spelling as packages/components/src/index.css. */\n@custom-variant dark (&:where(.dark, .dark *));\n\n/* Sources to scan for utility classes (v4's replacement for v3 \\`content\\`) */\n${buildAppSourceDirectives(context).join('\\n')}\n\n${APP_THEME_TOKENS}\n\n${APP_THEME_VARIABLES}\n\n* {\n border-color: hsl(var(--border));\n}\n\nbody {\n background-color: hsl(var(--background));\n color: hsl(var(--foreground));\n font-family: var(--font-sans);\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n min-height: 100vh;\n}`;\n}\n\n/** Writes a generated file map onto `tmpDir`, creating nested directories. */\nfunction writeGeneratedFiles(tmpDir: string, files: Record<string, string>): void {\n for (const [relativePath, contents] of Object.entries(files)) {\n const target = join(tmpDir, relativePath);\n mkdirSync(dirname(target), { recursive: true });\n writeFileSync(target, contents);\n }\n}\n\nexport function createTempApp(tmpDir: string, schema: unknown) {\n writeGeneratedFiles(tmpDir, buildAppFiles(schema, currentContext()));\n}\n\n/**\n * Every file `createTempApp` writes, as `relative path -> contents`.\n *\n * Exported so the tests assert over the SAME artifact the CLI writes rather\n * than over this file's source text — the shape objectui#3733/#3826 settled on\n * for the sibling generator, and the only way a structural gate (imports vs\n * declarations, entry reachability) can be written at all.\n */\nexport function buildAppFiles(schema: unknown, context: AppGeneratorContext): Record<string, string> {\n // Create index.html\n const html = `<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Object UI App</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/src/main.tsx\"></script>\n </body>\n</html>`;\n\n // Create main.tsx\n const mainTsx = `import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App';\nimport './index.css';\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n <React.StrictMode>\n <App />\n </React.StrictMode>\n);`;\n\n // Create App.tsx\n const appTsx = `import { SchemaRenderer } from '@object-ui/react';\nimport '@object-ui/components';\nimport '@object-ui/plugin-charts';\nimport '@object-ui/plugin-editor';\nimport '@object-ui/plugin-kanban';\nimport '@object-ui/plugin-markdown';\nimport '@object-ui/plugin-form';\nimport '@object-ui/plugin-grid';\nimport '@object-ui/plugin-view';\n\nconst schema = ${JSON.stringify(schema, null, 2)};\n\nfunction App() {\n return <SchemaRenderer schema={schema} />;\n}\n\nexport default App;`;\n\n return {\n 'index.html': html,\n 'src/main.tsx': mainTsx,\n 'src/App.tsx': appTsx,\n 'src/vite-env.d.ts': APP_VITE_ENV_D_TS,\n 'src/index.css': buildAppIndexCss(context),\n 'postcss.config.js': APP_POSTCSS_CONFIG,\n 'package.json': JSON.stringify(buildAppPackageJson(context), null, 2),\n 'tsconfig.json': JSON.stringify(APP_TSCONFIG, null, 2)\n };\n}\n\nexport function createTempAppWithRouting(tmpDir: string, routes: RouteInfo[], appConfig?: unknown) {\n writeGeneratedFiles(tmpDir, buildRoutedAppFiles(routes, appConfig, currentContext()));\n}\n\n/**\n * Every file `createTempAppWithRouting` writes, as `relative path -> contents`.\n *\n * `src/main.tsx` is the entry — `index.html` loads exactly that one module — so\n * every other generated `src/**` module has to be reachable from it, which is\n * the reachability gate objectui#3826 established for the sibling generator and\n * `app-generator.test.ts` ports here. `src/Layout.tsx` is written only when\n * `appConfig` is present, precisely because that is the only case in which\n * `src/App.tsx` imports it.\n */\nexport function buildRoutedAppFiles(\n routes: RouteInfo[],\n appConfig: unknown,\n context: AppGeneratorContext\n): Record<string, string> {\n const files: Record<string, string> = {};\n\n // Create index.html\n const html = `<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>${(appConfig as any)?.title || 'Object UI App'}</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/src/main.tsx\"></script>\n </body>\n</html>`;\n\n files['index.html'] = html;\n\n const schemaImports: string[] = [];\n const routeComponents: string[] = [];\n\n routes.forEach((route, index) => {\n const schemaVarName = `schema${index}`;\n const schemaFileName = `page${index}.json`;\n\n // Add schema to the schemas directory\n files[`src/schemas/${schemaFileName}`] = JSON.stringify(route.schema, null, 2);\n\n // Add import statement\n schemaImports.push(`import ${schemaVarName} from './schemas/${schemaFileName}';`);\n\n // Add route component\n routeComponents.push(` <Route path=\"${route.path}\" element={<SchemaRenderer schema={${schemaVarName}} />} />`);\n });\n\n // Create theme-provider.tsx\n const themeProviderTsx = `import { createContext, useContext, useEffect, useState } from \"react\"\n\ntype Theme = \"dark\" | \"light\" | \"system\"\n\ntype ThemeProviderProps = {\n children: React.ReactNode\n defaultTheme?: Theme\n storageKey?: string\n}\n\ntype ThemeProviderState = {\n theme: Theme\n setTheme: (theme: Theme) => void\n}\n\nconst initialState: ThemeProviderState = {\n theme: \"system\",\n setTheme: () => null,\n}\n\nconst ThemeProviderContext = createContext<ThemeProviderState>(initialState)\n\nexport function ThemeProvider({\n children,\n defaultTheme = \"system\",\n storageKey = \"vite-ui-theme\",\n ...props\n}: ThemeProviderProps) {\n const [theme, setTheme] = useState<Theme>(\n () => (localStorage.getItem(storageKey) as Theme) || defaultTheme\n )\n\n useEffect(() => {\n const root = window.document.documentElement\n\n root.classList.remove(\"light\", \"dark\")\n\n if (theme === \"system\") {\n const systemTheme = window.matchMedia(\"(prefers-color-scheme: dark)\")\n .matches\n ? \"dark\"\n : \"light\"\n\n root.classList.add(systemTheme)\n return\n }\n\n root.classList.add(theme)\n }, [theme])\n\n const value = {\n theme,\n setTheme: (theme: Theme) => {\n localStorage.setItem(storageKey, theme)\n setTheme(theme)\n },\n }\n\n return (\n <ThemeProviderContext.Provider {...props} value={value}>\n {children}\n </ThemeProviderContext.Provider>\n )\n}\n\nexport const useTheme = () => {\n const context = useContext(ThemeProviderContext)\n\n if (context === undefined)\n throw new Error(\"useTheme must be used within a ThemeProvider\")\n\n return context\n}`;\n files['src/theme-provider.tsx'] = themeProviderTsx;\n\n // Create main.tsx\n const mainTsx = `import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App';\nimport './index.css';\nimport { ThemeProvider } from \"./theme-provider\"\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n <React.StrictMode>\n <ThemeProvider defaultTheme=\"dark\" storageKey=\"vite-ui-theme\">\n <App />\n </ThemeProvider>\n </React.StrictMode>\n);`;\n\n files['src/main.tsx'] = mainTsx;\n\n // Generate Layout Code if appConfig is present\n let layoutImport = '';\n let layoutWrapperStart = '';\n let layoutWrapperEnd = '';\n \n if (appConfig) {\n // Very basic Layout implementation for now\n // Logic: If appConfig is present, current version assumes it's just a config object, \n // but we need a Layout component that renders navigation.\n // Since we don't have a Layout component in @object-ui/components yet, we generate a simple one.\n\n const layoutCode = `\nimport type { ComponentType, ReactNode } from 'react';\nimport { Link, useLocation } from 'react-router-dom';\nimport * as LucideIcons from 'lucide-react';\nimport { Moon, Sun } from \"lucide-react\"\nimport { useTheme } from \"./theme-provider\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n SidebarProvider,\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarHeader,\n SidebarRail,\n SidebarGroup,\n SidebarMenu,\n SidebarMenuItem,\n SidebarMenuButton,\n SidebarMenuSub,\n SidebarMenuSubItem,\n SidebarMenuSubButton,\n SidebarInset,\n SidebarTrigger,\n Separator,\n Collapsible,\n CollapsibleTrigger,\n CollapsibleContent\n} from '@object-ui/components';\n\n/** One entry of \\`app.json\\`'s \\`menu\\`, as this layout reads it. */\ntype MenuItem = {\n label?: string;\n path?: string;\n icon?: string;\n children?: MenuItem[];\n};\n\n/** The \\`app.json\\` fields this layout renders. */\ntype AppConfig = {\n title?: string;\n logo?: string;\n menu?: MenuItem[];\n};\n\n// Lucide publishes every icon as a named export, and a menu entry names one as\n// a string — so the lookup is a runtime index into the namespace object, which\n// has no index signature. Narrowing it to the component-by-name shape this file\n// actually uses keeps that honest without an \\`any\\` or a \\`@ts-expect-error\\`; the\n// \\`undefined\\` arm is real, since the namespace also exports helpers that are not\n// components and a schema may name an icon that does not exist.\nconst lucideIcons = LucideIcons as unknown as Record<\n string,\n ComponentType<{ className?: string }> | undefined\n>;\n\nconst DynamicIcon = ({ name, className }: { name: string; className?: string }) => {\n const Icon = lucideIcons[name];\n if (!Icon) return null;\n return <Icon className={className} />;\n};\n\nexport function ModeToggle() {\n const { setTheme } = useTheme()\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <SidebarMenuButton size=\"lg\" className=\"data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground\">\n <div className=\"flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground\">\n <Sun className=\"h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0\" />\n <Moon className=\"absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100\" />\n </div>\n <div className=\"grid flex-1 text-left text-sm leading-tight\">\n <span className=\"truncate font-semibold\">Switch Theme</span>\n <span className=\"truncate text-xs\">Light / Dark</span>\n </div>\n <LucideIcons.ChevronsUpDown className=\"ml-auto size-4\" />\n </SidebarMenuButton>\n </DropdownMenuTrigger>\n <DropdownMenuContent className=\"w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg\" side=\"bottom\" align=\"end\" sideOffset={4}>\n <DropdownMenuItem onClick={() => setTheme(\"light\")}>\n <LucideIcons.Sun className=\"mr-2 size-4\" />\n Light\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => setTheme(\"dark\")}>\n <LucideIcons.Moon className=\"mr-2 size-4\" />\n Dark\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => setTheme(\"system\")}>\n <LucideIcons.Monitor className=\"mr-2 size-4\" />\n System\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n\nconst AppLayout = ({ app, children }: { app: AppConfig; children: ReactNode }) => {\n const location = useLocation();\n const menu = app.menu || [];\n \n return (\n <SidebarProvider>\n <Sidebar collapsible=\"icon\">\n <SidebarHeader>\n <div className=\"flex items-center gap-2 px-2 py-2\">\n <div className=\"flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground\">\n {app.logo && <DynamicIcon name={app.logo} className=\"size-4\" />}\n {!app.logo && <span className=\"text-xl font-bold\">O</span>}\n </div>\n <div className=\"grid flex-1 text-left text-sm leading-tight\">\n <span className=\"truncate font-semibold\">{app.title || \"Object UI\"}</span>\n <span className=\"truncate text-xs\">Showcase</span>\n </div>\n </div>\n </SidebarHeader>\n <SidebarContent>\n <SidebarGroup>\n <SidebarMenu>\n {menu.map((item, idx) => {\n // Collapsible Item (Children present)\n if (item.children && item.children.length > 0) {\n const isActive = item.children.some(child => child.path === location.pathname);\n return (\n <Collapsible key={idx} asChild defaultOpen={isActive} className=\"group/collapsible\">\n <SidebarMenuItem>\n <CollapsibleTrigger asChild>\n <SidebarMenuButton tooltip={item.label}>\n {item.icon && <DynamicIcon name={item.icon} />}\n <span>{item.label}</span>\n <DynamicIcon name=\"ChevronRight\" className=\"ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90\" />\n </SidebarMenuButton>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child, cIdx) => (\n <SidebarMenuSubItem key={cIdx}>\n <SidebarMenuSubButton asChild isActive={location.pathname === child.path}>\n <Link to={child.path || '#'}>\n <span>{child.label}</span>\n </Link>\n </SidebarMenuSubButton>\n </SidebarMenuSubItem>\n ))}\n </SidebarMenuSub>\n </CollapsibleContent>\n </SidebarMenuItem>\n </Collapsible>\n );\n }\n\n // Single Item\n if (item.path) {\n return (\n <SidebarMenuItem key={idx}>\n <SidebarMenuButton asChild isActive={location.pathname === item.path} tooltip={item.label}>\n <Link to={item.path}>\n {item.icon && <DynamicIcon name={item.icon} />}\n <span>{item.label}</span>\n </Link>\n </SidebarMenuButton>\n </SidebarMenuItem>\n );\n }\n return null;\n })}\n </SidebarMenu>\n </SidebarGroup>\n </SidebarContent>\n <SidebarFooter>\n <SidebarMenu>\n <SidebarMenuItem>\n <ModeToggle />\n </SidebarMenuItem>\n </SidebarMenu>\n </SidebarFooter>\n <SidebarRail />\n </Sidebar>\n \n <SidebarInset>\n <header className=\"flex h-16 shrink-0 items-center gap-2 border-b bg-background px-4\">\n <SidebarTrigger className=\"-ml-1\" />\n <Separator orientation=\"vertical\" className=\"mr-2 h-4\" />\n <div className=\"flex flex-1 items-center justify-between\">\n <span className=\"font-medium\">{app.title}</span>\n </div>\n </header>\n <div className=\"flex-1 flex flex-col min-h-0 bg-muted/20 p-4\">\n <div className=\"mx-auto max-w-full w-full\">\n {children}\n </div>\n </div>\n </SidebarInset>\n </SidebarProvider>\n );\n};\n\nexport default AppLayout;\n`;\n files['src/Layout.tsx'] = layoutCode;\n \n layoutImport = `import AppLayout from './Layout';\\nconst appConfig = ${JSON.stringify(appConfig)};`;\n layoutWrapperStart = `<AppLayout app={appConfig}>`;\n layoutWrapperEnd = `</AppLayout>`;\n }\n\n // Create App.tsx with routing\n //\n // `Link` is deliberately absent from this import: the only `<Link>` in the\n // generated app is in `src/Layout.tsx`, which imports it itself. Naming it\n // here bought nothing and cost a TS6133 under the `noUnusedLocals` this\n // generator's own `tsconfig.json` declares (objectui#3853).\n const appTsx = `import { BrowserRouter, Routes, Route } from 'react-router-dom';\nimport { SchemaRenderer } from '@object-ui/react';\nimport '@object-ui/components';\nimport '@object-ui/plugin-charts';\nimport '@object-ui/plugin-editor';\nimport '@object-ui/plugin-kanban';\nimport '@object-ui/plugin-markdown';\nimport '@object-ui/plugin-form';\nimport '@object-ui/plugin-grid';\nimport '@object-ui/plugin-view';\n${schemaImports.join('\\n')}\n${layoutImport}\n\nfunction App() {\n return (\n <BrowserRouter>\n ${layoutWrapperStart}\n <Routes>\n${routeComponents.join('\\n')}\n </Routes>\n ${layoutWrapperEnd}\n </BrowserRouter>\n );\n}\n\nexport default App;`;\n\n files['src/App.tsx'] = appTsx;\n\n files['src/vite-env.d.ts'] = APP_VITE_ENV_D_TS;\n files['src/index.css'] = buildAppIndexCss(context);\n files['postcss.config.js'] = APP_POSTCSS_CONFIG;\n files['package.json'] = JSON.stringify(buildRoutedAppPackageJson(), null, 2);\n files['tsconfig.json'] = JSON.stringify(APP_TSCONFIG, null, 2);\n\n return files;\n}\n","/**\n * ObjectUI\n * Copyright (c) 2024-present ObjectStack Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n/**\n * The one place a generated manifest's version ranges come from.\n *\n * This CLI writes a `package.json` from THREE generators, not two:\n * `utils/app-generator.ts` builds the plain and routed temp apps that\n * `objectui dev` runs, and `commands/init.ts` builds the project scaffold\n * `objectui init` hands to an external user. objectui#3742 / objectui#3754 /\n * objectui#3827 established the discipline for the first two — one range per\n * dependency, quoted from this repo rather than invented, derived from this\n * CLI's own version where the package ships in lockstep with it — and\n * `app-generator.test.ts`'s `DEPENDENCY_ANCHORS` gates it.\n *\n * The init scaffold sat outside all of it (objectui#3892). It asked for\n * `@object-ui/components`/`@object-ui/react` at `^2.0.0` while those packages\n * publish at 17.x, so the first command an external user runs produced a\n * project whose `npm install` resolved a major with nothing to do with the CLI\n * that wrote it — the same defect objectui#3827 fixed one generator over, where\n * the literal was `^0.1.0`. Its toolchain ranges had fossilised a major behind\n * the repo besides (vite `^7.3.1` vs `^8.2.0`, typescript `^5.9.3` vs `^6.0.3`).\n *\n * Both halves are cured by not having a literal to fossilise: this module owns\n * the values, all three generators read them, and the anchor table judges the\n * union. Copying a range into a fourth generator is still possible, but it now\n * fails the completeness gate instead of shipping.\n */\n\nimport { existsSync, readFileSync } from 'fs';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } from 'url';\n\n/** This package's own name, used to locate its manifest for the platform range. */\nconst CLI_PACKAGE_NAME = '@object-ui/cli';\n\n/** Memoised so the manifest walk happens at most once per process. */\nlet cachedCliVersion: string | undefined;\n\n/**\n * This CLI's own version, read from its own `package.json`.\n *\n * Walks up from this module rather than joining a fixed `../package.json`,\n * because the same source sits at `src/utils/` in the repo and is bundled into\n * `dist/` when published — a relative depth that is correct in one is wrong in\n * the other.\n */\nexport function cliVersion(): string {\n if (cachedCliVersion !== undefined) return cachedCliVersion;\n\n let dir = dirname(fileURLToPath(import.meta.url));\n for (;;) {\n const candidate = join(dir, 'package.json');\n if (existsSync(candidate)) {\n const manifest = JSON.parse(readFileSync(candidate, 'utf-8')) as {\n name?: string;\n version?: string;\n };\n if (manifest.name === CLI_PACKAGE_NAME && typeof manifest.version === 'string') {\n cachedCliVersion = manifest.version;\n return cachedCliVersion;\n }\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n throw new Error(\n `Could not locate the ${CLI_PACKAGE_NAME} manifest to version the generated app's ` +\n `platform dependencies against. Refusing to write a package.json with a guessed range.`\n );\n}\n\n/**\n * The range every generated manifest declares for every `@object-ui/*` package.\n *\n * Derived from this CLI's own version instead of being written out as a\n * literal, because `.changeset/config.json` puts `@object-ui/cli` in the SAME\n * `fixed` group as every platform package a generated app declares: they are\n * released together and always carry the identical version. So `^<own\n * version>` is both current and guaranteed to exist on the registry — whatever\n * CLI version a user is running was published alongside its siblings.\n *\n * The literals it replaces were `^0.1.0` in the app generators (objectui#3827)\n * and `^2.0.0` in the init scaffold (objectui#3892), for packages published at\n * 17.x. Neither resolved to anything the CLI had been tested against; `^0.1.0`\n * resolved to nothing published at all. A literal here is not merely a fossil\n * risk, it is a fossil generator: the fixed group re-versions on every release,\n * so any hard-coded range is stale the next day. Deriving it removes the class.\n */\nexport function platformPackageRange(): string {\n return `^${cliVersion()}`;\n}\n\n/**\n * React's range in every generated manifest.\n *\n * Quotes the repo root verbatim (an exact pin there) rather than the wider\n * `^18.0.0 || ^19.0.0` the platform packages accept as a peer. The peer range\n * says what CAN work; this says what is actually exercised — inside this\n * workspace the temp app resolves React by hoisting to the root, so the root's\n * version is the only one the generated code has ever run against. Declaring\n * `^18.3.1`, as the app generators did until objectui#3827, or `^19.2.0`, as\n * the init scaffold did until objectui#3892, names a version nothing here\n * tests: the second is not even wrong about the major, which is exactly how it\n * survived unnoticed.\n */\nexport const REACT_RANGE = '19.2.8';\n\n/**\n * `devDependencies` shared by every generated manifest (identical in all three).\n *\n * Every range is anchored to an in-repo manifest, and\n * `app-generator.test.ts`'s `DEPENDENCY_ANCHORS` names the anchor for each one\n * and fails on an unanchored addition. The Tailwind-side entries were held at\n * v3 as an explicit `TAILWIND_V3_DEFERRED` ledger by objectui#3827, because\n * bumping the range without rewriting the CSS pipeline beside it would produce\n * an app that installs and renders unstyled. objectui#3852 rewrote that\n * pipeline, so they are anchored to this repo's Tailwind 4 like everything\n * else — `tailwindcss` to the root, `@tailwindcss/postcss` (v4's PostCSS\n * plugin, a separate package) to the in-repo range every `postcss.config.*`\n * here already names.\n *\n * The init scaffold declared this exact key set at its own, older literals\n * until objectui#3892 — same nine packages, every range behind, two of them by\n * a major. Sharing the map rather than re-anchoring a second copy is what makes\n * a repo-side bump reach all three generators in one edit; a generator that\n * ever needs to differ can spread this and override the one key, which stays\n * visible to the anchor table.\n */\nexport const SCAFFOLD_DEV_DEPENDENCIES: Record<string, string> = {\n '@tailwindcss/postcss': '^4.3.3',\n '@types/react': '19.2.18',\n '@types/react-dom': '19.2.4',\n '@vitejs/plugin-react': '^6.0.5',\n autoprefixer: '^10.5.4',\n postcss: '^8.5.26',\n tailwindcss: '^4.3.3',\n typescript: '^6.0.3',\n vite: '^8.2.1'\n};\n","/**\n * ObjectUI\n * Copyright (c) 2024-present ObjectStack Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { existsSync, writeFileSync, mkdirSync } from 'fs';\nimport { dirname, join } from 'path';\nimport chalk from 'chalk';\n\nimport {\n platformPackageRange,\n REACT_RANGE,\n SCAFFOLD_DEV_DEPENDENCIES\n} from '../utils/scaffold-dependencies.js';\n\ninterface InitOptions {\n template: string;\n}\n\nconst templates = {\n simple: {\n type: 'div',\n className: 'min-h-screen flex items-center justify-center bg-gradient-to-br from-blue-50 to-indigo-100',\n body: {\n type: 'card',\n className: 'w-full max-w-md shadow-lg',\n title: 'Welcome to Object UI',\n description: 'Start building your application with JSON schemas',\n body: {\n type: 'div',\n className: 'p-6 space-y-4',\n body: [\n {\n type: 'text',\n content: 'This is a simple example. Edit app.json to customize your application.',\n className: 'text-sm text-muted-foreground',\n },\n {\n type: 'button',\n label: 'Get Started',\n className: 'w-full',\n },\n ],\n },\n },\n },\n form: {\n type: 'div',\n className: 'min-h-screen flex items-center justify-center bg-gradient-to-br from-purple-50 to-pink-100 p-4',\n body: {\n type: 'card',\n className: 'w-full max-w-2xl shadow-xl',\n title: 'Contact Form',\n description: 'Fill out the form below to get in touch',\n body: {\n type: 'div',\n className: 'p-6 space-y-6',\n body: [\n {\n type: 'div',\n className: 'grid grid-cols-2 gap-4',\n body: [\n {\n type: 'input',\n label: 'First Name',\n placeholder: 'John',\n required: true,\n },\n {\n type: 'input',\n label: 'Last Name',\n placeholder: 'Doe',\n required: true,\n },\n ],\n },\n {\n type: 'input',\n label: 'Email Address',\n inputType: 'email',\n placeholder: 'john.doe@example.com',\n required: true,\n },\n {\n type: 'input',\n label: 'Phone Number',\n inputType: 'tel',\n placeholder: '+1 (555) 000-0000',\n },\n {\n type: 'textarea',\n label: 'Message',\n placeholder: 'Tell us what you need...',\n rows: 4,\n },\n {\n type: 'div',\n className: 'flex gap-3',\n body: [\n {\n type: 'button',\n label: 'Submit',\n className: 'flex-1',\n },\n {\n type: 'button',\n label: 'Reset',\n variant: 'outline',\n className: 'flex-1',\n },\n ],\n },\n ],\n },\n },\n },\n dashboard: {\n type: 'div',\n className: 'min-h-screen bg-muted/10',\n body: [\n {\n type: 'div',\n className: 'border-b bg-background',\n body: {\n type: 'div',\n className: 'container mx-auto px-6 py-4',\n body: {\n type: 'div',\n className: 'flex items-center justify-between',\n body: [\n {\n type: 'div',\n className: 'text-2xl font-bold',\n body: { type: 'text', content: 'Dashboard' },\n },\n {\n type: 'button',\n label: 'New Item',\n size: 'sm',\n },\n ],\n },\n },\n },\n {\n type: 'div',\n className: 'container mx-auto p-6 space-y-6',\n body: [\n {\n type: 'div',\n className: 'grid gap-4 md:grid-cols-2 lg:grid-cols-4',\n body: [\n {\n type: 'card',\n className: 'shadow-sm',\n body: [\n {\n type: 'div',\n className: 'p-6 pb-2',\n body: {\n type: 'div',\n className: 'text-sm font-medium text-muted-foreground',\n body: { type: 'text', content: 'Total Revenue' },\n },\n },\n {\n type: 'div',\n className: 'p-6 pt-0',\n body: [\n {\n type: 'div',\n className: 'text-2xl font-bold',\n body: { type: 'text', content: '$45,231.89' },\n },\n {\n type: 'div',\n className: 'text-xs text-muted-foreground mt-1',\n body: { type: 'text', content: '+20.1% from last month' },\n },\n ],\n },\n ],\n },\n {\n type: 'card',\n className: 'shadow-sm',\n body: [\n {\n type: 'div',\n className: 'p-6 pb-2',\n body: {\n type: 'div',\n className: 'text-sm font-medium text-muted-foreground',\n body: { type: 'text', content: 'Active Users' },\n },\n },\n {\n type: 'div',\n className: 'p-6 pt-0',\n body: [\n {\n type: 'div',\n className: 'text-2xl font-bold',\n body: { type: 'text', content: '+2,350' },\n },\n {\n type: 'div',\n className: 'text-xs text-muted-foreground mt-1',\n body: { type: 'text', content: '+180.1% from last month' },\n },\n ],\n },\n ],\n },\n {\n type: 'card',\n className: 'shadow-sm',\n body: [\n {\n type: 'div',\n className: 'p-6 pb-2',\n body: {\n type: 'div',\n className: 'text-sm font-medium text-muted-foreground',\n body: { type: 'text', content: 'Sales' },\n },\n },\n {\n type: 'div',\n className: 'p-6 pt-0',\n body: [\n {\n type: 'div',\n className: 'text-2xl font-bold',\n body: { type: 'text', content: '+12,234' },\n },\n {\n type: 'div',\n className: 'text-xs text-muted-foreground mt-1',\n body: { type: 'text', content: '+19% from last month' },\n },\n ],\n },\n ],\n },\n {\n type: 'card',\n className: 'shadow-sm',\n body: [\n {\n type: 'div',\n className: 'p-6 pb-2',\n body: {\n type: 'div',\n className: 'text-sm font-medium text-muted-foreground',\n body: { type: 'text', content: 'Active Now' },\n },\n },\n {\n type: 'div',\n className: 'p-6 pt-0',\n body: [\n {\n type: 'div',\n className: 'text-2xl font-bold',\n body: { type: 'text', content: '+573' },\n },\n {\n type: 'div',\n className: 'text-xs text-muted-foreground mt-1',\n body: { type: 'text', content: '+201 since last hour' },\n },\n ],\n },\n ],\n },\n ],\n },\n {\n type: 'card',\n className: 'shadow-sm',\n title: 'Recent Activity',\n description: 'Your latest updates and notifications',\n body: {\n type: 'div',\n className: 'p-6 pt-0 space-y-4',\n body: [\n {\n type: 'div',\n className: 'flex items-center gap-4 border-b pb-4',\n body: [\n {\n type: 'div',\n className: 'flex-1',\n body: [\n {\n type: 'div',\n className: 'font-medium',\n body: { type: 'text', content: 'New user registration' },\n },\n {\n type: 'div',\n className: 'text-sm text-muted-foreground',\n body: { type: 'text', content: '2 minutes ago' },\n },\n ],\n },\n ],\n },\n {\n type: 'div',\n className: 'flex items-center gap-4 border-b pb-4',\n body: [\n {\n type: 'div',\n className: 'flex-1',\n body: [\n {\n type: 'div',\n className: 'font-medium',\n body: { type: 'text', content: 'Payment received' },\n },\n {\n type: 'div',\n className: 'text-sm text-muted-foreground',\n body: { type: 'text', content: '15 minutes ago' },\n },\n ],\n },\n ],\n },\n {\n type: 'div',\n className: 'flex items-center gap-4',\n body: [\n {\n type: 'div',\n className: 'flex-1',\n body: [\n {\n type: 'div',\n className: 'font-medium',\n body: { type: 'text', content: 'New order placed' },\n },\n {\n type: 'div',\n className: 'text-sm text-muted-foreground',\n body: { type: 'text', content: '1 hour ago' },\n },\n ],\n },\n ],\n },\n ],\n },\n },\n ],\n },\n ],\n },\n};\n\n/**\n * The `package.json` `objectui init` writes into a new user project.\n *\n * Split out of `init()` so it can be judged without running the command:\n * `app-generator.test.ts`'s `DEPENDENCY_ANCHORS` now covers this manifest\n * alongside the two temp-app generators, which is the gate it had none of\n * before (objectui#3892 — the literals live in `.ts` source, so objectui#3711's\n * version-claims scan never saw them either).\n *\n * Not one range is written here. Every value comes from\n * `utils/scaffold-dependencies.ts`, which is also what the app generators read;\n * see that module for why the `@object-ui/*` range is derived from the CLI's\n * own version rather than declared.\n */\nexport function buildInitPackageJson(name: string): Record<string, unknown> {\n const platformRange = platformPackageRange();\n return {\n name,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts: {\n dev: 'vite',\n build: 'tsc && vite build',\n preview: 'vite preview',\n },\n dependencies: {\n '@object-ui/components': platformRange,\n '@object-ui/react': platformRange,\n react: REACT_RANGE,\n 'react-dom': REACT_RANGE,\n },\n devDependencies: { ...SCAFFOLD_DEV_DEPENDENCIES },\n };\n}\n\n/**\n * Every file `objectui init` writes, as `relative path -> contents`.\n *\n * Split out of `init()` for the same reason `buildInitPackageJson` was\n * (objectui#3892): the command writes with `fs` directly, so until the map is a\n * value there is nothing for a structural gate to judge. `app-generator.ts`\n * exports `buildAppFiles` / `buildRoutedAppFiles` for exactly this, and the two\n * gates `app-generator.test.ts` runs over those maps — every import declared,\n * every versioned declaration imported — are what objectui#4061 and\n * objectui#4062 were both invisible to. This scaffold is the third generator and\n * had never been under either.\n *\n * `init()` below writes this map and nothing else, and a test pins that\n * equivalence through the real bin, so the map cannot drift from the artifact.\n */\nexport function buildInitFiles(name: string, templateName: string): Record<string, string> {\n const template = templates[templateName as keyof typeof templates];\n if (!template) {\n throw new Error(\n `Unknown template: ${templateName}\\nAvailable templates: ${Object.keys(templates).join(', ')}`\n );\n }\n\n const readme = `# ${name}\n\nAn Object UI application built from JSON schemas.\n\n## Getting Started\n\n1. Install dependencies:\n \\`\\`\\`bash\n npm install\n \\`\\`\\`\n\n2. Start the development server:\n \\`\\`\\`bash\n npm run dev\n \\`\\`\\`\n\n3. Open your browser and visit http://localhost:3000\n\n## Customize Your App\n\nEdit \\`app.json\\` to customize your application. The dev server will automatically reload when you save changes.\n\n## Available Templates\n\n- **simple**: A minimal getting started template\n- **form**: A contact form example\n- **dashboard**: A full dashboard with metrics and activity feed\n\n## Learn More\n\n- [Object UI Documentation](https://www.objectui.org)\n- [Schema Reference](https://www.objectui.org/docs/protocol/overview)\n- [Component Library](https://www.objectui.org/docs/api/components)\n\n## Commands\n\n- \\`npm run dev\\` - Start development server\n- \\`npm run build\\` - Build for production\n- \\`npm run preview\\` - Preview production build\n\nBuilt with ❤️ using [Object UI](https://www.objectui.org)\n`;\n\n const gitignore = `.objectui-tmp\nnode_modules\ndist\n.DS_Store\n*.log\n`;\n\n const viteConfig = `import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\n\nexport default defineConfig({\n plugins: [react()],\n server: {\n port: 3000,\n },\n});\n`;\n\n // No tailwind.config.js is written: this scaffold's CSS pipeline is Tailwind 4\n // (`postcss.config.js` names `@tailwindcss/postcss`, `src/index.css` does\n // `@import 'tailwindcss'`), and v4 reads a JS config only when a stylesheet\n // points `@config` at one — none does. The file this used to write was\n // therefore inert: an authoritative-looking `content` list that nothing\n // consumed, while v4's own source detection already covers `index.html` and\n // `src/**` from the project root. objectui#3852 removed the same dead file\n // from the temp-app generators; objectui#3892 removes it here.\n\n const postcssConfig = `export default {\n plugins: {\n '@tailwindcss/postcss': {},\n autoprefixer: {},\n },\n};\n`;\n\n const indexHtml = `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>${name}</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/src/main.tsx\"></script>\n </body>\n</html>\n`;\n\n // The component library's PREBUILT stylesheet, not a `@source` scan of it.\n //\n // The theme utilities these templates lean on (`text-muted-foreground` and\n // `bg-muted/10` in `simple`/`dashboard`, `shadow-sm` on every `card`) resolve\n // through tokens declared in a `@theme` block that lives in\n // `packages/components/src/index.css` — a file `files` does not publish, so an\n // installed consumer cannot compile it and cannot obtain those tokens by\n // scanning `node_modules` either. objectui#3884 measured both halves against a\n // real install: the full class surface a `node_modules` glob reaches is 1331\n // rules, all of them already inside the published `dist/index.css`'s 1410 — the\n // prebuilt sheet is a strict superset, and the `@source` lines are the\n // redundant ~100 kB. `@object-ui/components` exports it as `./style.css`\n // (objectui#4062).\n //\n // Components only. `@object-ui/fields` publishes a `style.css` too and\n // quick-start names it, but `@object-ui/fields@17.3.0` ships ZERO css\n // (measured on the published tarball, objectui#4059) and this scaffold does not\n // depend on it — importing it would be a declaration in the wrong direction\n // (objectui#3755) pointing at an empty file.\n const indexCss = `@import 'tailwindcss';\n@import '@object-ui/components/style.css';\n`;\n\n const mainTsx = `import { StrictMode } from 'react';\nimport { createRoot } from 'react-dom/client';\nimport App from './App';\nimport './index.css';\n\ncreateRoot(document.getElementById('root')!).render(\n <StrictMode>\n <App />\n </StrictMode>,\n);\n`;\n\n // `import '@object-ui/components'` is what fills the component registry, and\n // nothing else does it.\n //\n // `SchemaRenderer` resolves each node through `ComponentRegistry.get(type)`\n // and renders `Unknown component type: <type>` on a miss; registration happens\n // as a side effect of importing `@object-ui/components`, which\n // `@object-ui/react` does not depend on. Without this line every node of all\n // three templates — `div`, `card`, `text`, `button`, `input`, `textarea` — took\n // the miss path, so the scaffold's entire visible output was error boxes\n // (objectui#4061).\n //\n // Components alone, no `@object-ui/plugin-*`: all six types above are\n // registered by this one package (measured), and none of the three templates\n // names a plugin type. The temp-app generator imports nine packages because it\n // renders arbitrary user schemas; adding nine dependencies to a minimal\n // scaffold that uses none of them is the declared-but-unused direction\n // objectui#3755 removed.\n const appTsx = `import { SchemaRenderer } from '@object-ui/react';\n// Registers the component renderers SchemaRenderer looks up. Side-effect\n// import — removing it makes every node render \"Unknown component type\".\nimport '@object-ui/components';\nimport schema from '../app.json';\n\nexport default function App() {\n return <SchemaRenderer schema={schema} />;\n}\n`;\n\n // The ambient declaration that makes `src/main.tsx`'s `import './index.css'`\n // compile under the `tsconfig` written below.\n //\n // TypeScript has no built-in notion of a `.css` module, so without this the\n // entry fails that config with \"Cannot find module or type declarations for\n // side-effect import of './index.css'\" (TS2882) — and unlike the two temp-app\n // generators objectui#3853 fixed, the error is LIVE here: the `package.json`\n // this scaffold writes declares `build: \"tsc && vite build\"`, so `objectui\n // init` followed by the `npm run build` the generated README names fails on a\n // file the tool itself produced, before Vite is ever reached (objectui#4111).\n //\n // `vite/client` is where the `declare module '*.css'` declarations live,\n // `vite` is already in `SCAFFOLD_DEV_DEPENDENCIES`, and this is the file\n // `create-vite`'s own React+TS template writes for the same reason — the\n // ecosystem's spelling of the fix rather than a local invention.\n //\n // Byte-identical to `APP_VITE_ENV_D_TS` in `utils/app-generator.ts`;\n // `app-generator.test.ts` pins all three generators to the one string rather\n // than trusting them not to drift. It is also the one generated `src/**` file\n // deliberately unreachable from `src/main.tsx`: an ambient declaration enters\n // the program through the tsconfig's `include`, never through the module\n // graph, which is why that suite's reachability gate exempts `.d.ts`.\n const viteEnvDts = `/// <reference types=\"vite/client\" />\\n`;\n\n const tsconfig = {\n compilerOptions: {\n target: 'ES2020',\n useDefineForClassFields: true,\n lib: ['ES2020', 'DOM', 'DOM.Iterable'],\n module: 'ESNext',\n skipLibCheck: true,\n moduleResolution: 'bundler',\n allowImportingTsExtensions: true,\n isolatedModules: true,\n moduleDetection: 'force',\n noEmit: true,\n jsx: 'react-jsx',\n strict: true,\n noUnusedLocals: true,\n noUnusedParameters: true,\n noFallthroughCasesInSwitch: true,\n resolveJsonModule: true,\n },\n include: ['src'],\n };\n\n // Insertion order is the order `init()` writes and logs them.\n return {\n 'app.json': JSON.stringify(template, null, 2),\n 'README.md': readme,\n '.gitignore': gitignore,\n 'package.json': JSON.stringify(buildInitPackageJson(name), null, 2),\n 'vite.config.ts': viteConfig,\n 'postcss.config.js': postcssConfig,\n 'index.html': indexHtml,\n 'src/index.css': indexCss,\n 'src/main.tsx': mainTsx,\n 'src/App.tsx': appTsx,\n 'src/vite-env.d.ts': viteEnvDts,\n 'tsconfig.json': JSON.stringify(tsconfig, null, 2),\n };\n}\n\nexport async function init(name: string, options: InitOptions) {\n const cwd = process.cwd();\n const projectDir = join(cwd, name);\n\n // Check if directory already exists\n if (existsSync(projectDir) && name !== '.') {\n throw new Error(`Directory \"${name}\" already exists. Please choose a different name.`);\n }\n\n const targetDir = name === '.' ? cwd : projectDir;\n\n // Create project directory if needed\n if (name !== '.') {\n mkdirSync(projectDir, { recursive: true });\n }\n\n console.log(chalk.blue('🎨 Creating Object UI application...'));\n console.log(chalk.dim(` Template: ${options.template}`));\n console.log();\n\n // Writes the file map and nothing else — see `buildInitFiles`. Unknown\n // templates still throw here, before the first write.\n for (const [relativePath, contents] of Object.entries(\n buildInitFiles(name, options.template)\n )) {\n const target = join(targetDir, relativePath);\n mkdirSync(dirname(target), { recursive: true });\n writeFileSync(target, contents);\n console.log(chalk.green(`✓ Created ${relativePath}`));\n }\n\n console.log();\n console.log(chalk.green('✨ Application created successfully!'));\n console.log();\n console.log(chalk.bold('Next steps:'));\n console.log();\n if (name !== '.') {\n console.log(chalk.cyan(` cd ${name}`));\n }\n console.log(chalk.cyan(' npm install'));\n console.log(chalk.cyan(' npm run dev'));\n console.log();\n console.log(chalk.dim(' The development server will start on http://localhost:3000'));\n console.log();\n}\n"],"mappings":"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","names":["existsSync","mkdirSync","join","chalk","readFileSync","existsSync","dirname","join","readFileSync","join","existsSync","dirname","join","existsSync","chalk","mkdirSync","existsSync","writeFileSync","mkdirSync","dirname","join","chalk","join","existsSync","mkdirSync","chalk","dirname","writeFileSync"]}
|
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
parseSchemaFile,
|
|
7
7
|
scanPagesDirectory,
|
|
8
8
|
serve
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-2MZA766D.js";
|
|
10
10
|
|
|
11
11
|
// src/cli.ts
|
|
12
12
|
import { Command } from "commander";
|
|
@@ -20,6 +20,22 @@ import { join, resolve, dirname } from "path";
|
|
|
20
20
|
import chalk from "chalk";
|
|
21
21
|
import { execSync } from "child_process";
|
|
22
22
|
import { createRequire } from "module";
|
|
23
|
+
async function loadTempAppPostcssPlugins() {
|
|
24
|
+
try {
|
|
25
|
+
const [tailwindPostcss, autoprefixer] = await Promise.all([
|
|
26
|
+
import("@tailwindcss/postcss"),
|
|
27
|
+
import("autoprefixer")
|
|
28
|
+
]);
|
|
29
|
+
return [tailwindPostcss.default(), autoprefixer.default()];
|
|
30
|
+
} catch (error) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Failed to load the Tailwind CSS PostCSS pipeline: ${error instanceof Error ? error.message : error}
|
|
33
|
+
Both '@tailwindcss/postcss' and 'autoprefixer' are dependencies of @object-ui/cli \u2014 a
|
|
34
|
+
broken install of the CLI is the likeliest cause; reinstall it and try again.
|
|
35
|
+
(Refusing to start unstyled: that failure is silent in the browser.)`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
23
39
|
async function dev(schemaPath, options) {
|
|
24
40
|
const cwd = process.cwd();
|
|
25
41
|
let _projectRoot = cwd;
|
|
@@ -154,20 +170,7 @@ Run 'objectui init' to create a sample schema.`);
|
|
|
154
170
|
} catch (e) {
|
|
155
171
|
console.warn("\u26A0\uFE0F Could not resolve lucide-react automatically:", e);
|
|
156
172
|
}
|
|
157
|
-
|
|
158
|
-
const tailwindcss = require2("tailwindcss");
|
|
159
|
-
const autoprefixer = require2("autoprefixer");
|
|
160
|
-
viteConfig.css = {
|
|
161
|
-
postcss: {
|
|
162
|
-
plugins: [
|
|
163
|
-
tailwindcss(join(tmpDir, "tailwind.config.js")),
|
|
164
|
-
autoprefixer()
|
|
165
|
-
]
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
} catch (_e) {
|
|
169
|
-
console.warn(chalk.yellow("\u26A0\uFE0F Failed to load PostCSS plugins from root node_modules. Styles might not work correctly."));
|
|
170
|
-
}
|
|
173
|
+
viteConfig.css = { postcss: { plugins: await loadTempAppPostcssPlugins() } };
|
|
171
174
|
}
|
|
172
175
|
const server = await createServer(viteConfig);
|
|
173
176
|
await server.listen();
|
|
@@ -510,94 +513,222 @@ export const ${name}Plugin = {
|
|
|
510
513
|
// src/commands/doctor.ts
|
|
511
514
|
import chalk7 from "chalk";
|
|
512
515
|
import { existsSync as existsSync7, readFileSync } from "fs";
|
|
513
|
-
import { join as join7 } from "path";
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
516
|
+
import { dirname as dirname2, join as join7, resolve as resolvePath } from "path";
|
|
517
|
+
var CSS_ENTRY_CANDIDATES = [
|
|
518
|
+
"src/index.css",
|
|
519
|
+
"src/main.css",
|
|
520
|
+
"src/styles.css",
|
|
521
|
+
"src/style.css",
|
|
522
|
+
"src/app.css",
|
|
523
|
+
"src/global.css",
|
|
524
|
+
"src/globals.css",
|
|
525
|
+
"app/globals.css",
|
|
526
|
+
"app/global.css",
|
|
527
|
+
"styles/globals.css",
|
|
528
|
+
"index.css",
|
|
529
|
+
"styles.css"
|
|
530
|
+
];
|
|
531
|
+
var TAILWIND_CONFIG_CANDIDATES = [
|
|
532
|
+
"tailwind.config.js",
|
|
533
|
+
"tailwind.config.cjs",
|
|
534
|
+
"tailwind.config.mjs",
|
|
535
|
+
"tailwind.config.ts"
|
|
536
|
+
];
|
|
537
|
+
var POSTCSS_CONFIG_CANDIDATES = [
|
|
538
|
+
"postcss.config.js",
|
|
539
|
+
"postcss.config.cjs",
|
|
540
|
+
"postcss.config.mjs",
|
|
541
|
+
"postcss.config.ts"
|
|
542
|
+
];
|
|
543
|
+
var V4_CSS_IMPORT = /@import\s+["']tailwindcss["']/;
|
|
544
|
+
var V3_CSS_DIRECTIVE = /@tailwind\s+(?:base|components|utilities|screens|variants)\b/;
|
|
545
|
+
var CSS_SOURCE_DIRECTIVE = /@source\s+["']/;
|
|
546
|
+
var CSS_CONFIG_DIRECTIVE = /@config\s+["']/;
|
|
547
|
+
var V4_POSTCSS_PLUGIN = /@tailwindcss\/postcss/;
|
|
548
|
+
var V3_POSTCSS_PLUGIN = /["']tailwindcss["']|(?:^|[{,\s])tailwindcss\s*:/m;
|
|
549
|
+
function readIfExists(path) {
|
|
550
|
+
try {
|
|
551
|
+
return existsSync7(path) ? readFileSync(path, "utf-8") : null;
|
|
552
|
+
} catch {
|
|
553
|
+
return null;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
function findFile(cwd, candidates) {
|
|
557
|
+
for (const rel of candidates) {
|
|
558
|
+
const abs = join7(cwd, rel);
|
|
559
|
+
if (existsSync7(abs)) return abs;
|
|
560
|
+
}
|
|
561
|
+
return null;
|
|
562
|
+
}
|
|
563
|
+
function majorOf(range) {
|
|
564
|
+
const match = /(\d+)/.exec(range);
|
|
565
|
+
if (!match) return null;
|
|
566
|
+
const major = Number.parseInt(match[1], 10);
|
|
567
|
+
return Number.isNaN(major) ? null : major;
|
|
568
|
+
}
|
|
569
|
+
function isInstalledFrom(cwd, specifier) {
|
|
570
|
+
let dir = resolvePath(cwd);
|
|
571
|
+
for (; ; ) {
|
|
572
|
+
if (existsSync7(join7(dir, "node_modules", ...specifier.split("/")))) return true;
|
|
573
|
+
const parent = dirname2(dir);
|
|
574
|
+
if (parent === dir) return false;
|
|
575
|
+
dir = parent;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
function runDiagnostics(cwd) {
|
|
579
|
+
const results = [];
|
|
580
|
+
const ok = (id, message) => {
|
|
581
|
+
results.push({ id, level: "ok", message });
|
|
582
|
+
};
|
|
583
|
+
const warn = (id, message) => {
|
|
584
|
+
results.push({ id, level: "warn", message });
|
|
585
|
+
};
|
|
586
|
+
const error = (id, message) => {
|
|
587
|
+
results.push({ id, level: "error", message });
|
|
588
|
+
};
|
|
519
589
|
const pkgPath = join7(cwd, "package.json");
|
|
520
|
-
|
|
590
|
+
const pkgRaw = readIfExists(pkgPath);
|
|
591
|
+
let pkg = null;
|
|
592
|
+
if (pkgRaw === null) {
|
|
593
|
+
error("package-json-missing", "package.json not found");
|
|
594
|
+
} else {
|
|
521
595
|
try {
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
596
|
+
pkg = JSON.parse(pkgRaw);
|
|
597
|
+
} catch {
|
|
598
|
+
error("package-json-unreadable", "Failed to parse package.json");
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
const deps = pkg ? { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} } : {};
|
|
602
|
+
if (pkg) {
|
|
603
|
+
if (deps.react) {
|
|
604
|
+
ok("react-installed", "React installed");
|
|
605
|
+
} else {
|
|
606
|
+
warn("react-missing", "React not found in dependencies");
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
const tailwindRange = pkg ? deps.tailwindcss : void 0;
|
|
610
|
+
if (pkg && !tailwindRange) {
|
|
611
|
+
warn("tailwind-missing", "Tailwind CSS not found in dependencies");
|
|
612
|
+
}
|
|
613
|
+
if (tailwindRange) {
|
|
614
|
+
const major = majorOf(tailwindRange);
|
|
615
|
+
if (major !== null && major < 4) {
|
|
616
|
+
warn(
|
|
617
|
+
"tailwind-major-legacy",
|
|
618
|
+
`Tailwind CSS ${tailwindRange} detected \u2014 ObjectUI targets Tailwind 4. Upgrade with \`npx @tailwindcss/upgrade\`, then move configuration into your CSS entry (\`@import 'tailwindcss'\`, \`@theme\`, \`@source\`).`
|
|
619
|
+
);
|
|
620
|
+
} else {
|
|
621
|
+
ok("tailwind-installed", `Tailwind CSS ${tailwindRange} installed`);
|
|
622
|
+
}
|
|
623
|
+
if (deps["@tailwindcss/postcss"]) {
|
|
624
|
+
ok("tailwind-postcss-declared", "@tailwindcss/postcss declared");
|
|
625
|
+
} else if (isInstalledFrom(cwd, "@tailwindcss/postcss")) {
|
|
626
|
+
ok(
|
|
627
|
+
"tailwind-postcss-installed",
|
|
628
|
+
"@tailwindcss/postcss installed (provided by the workspace)"
|
|
629
|
+
);
|
|
630
|
+
} else {
|
|
631
|
+
error(
|
|
632
|
+
"tailwind-postcss-missing",
|
|
633
|
+
"Tailwind CSS 4 needs @tailwindcss/postcss, which is neither declared nor installed here. v4 moved the PostCSS plugin out of `tailwindcss` into its own package; without it PostCSS fails to load and no styles are emitted. Install it: `npm i -D @tailwindcss/postcss`."
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
const postcssConfigPath = findFile(cwd, POSTCSS_CONFIG_CANDIDATES);
|
|
637
|
+
if (postcssConfigPath) {
|
|
638
|
+
const postcssConfig = readIfExists(postcssConfigPath) ?? "";
|
|
639
|
+
const hasV4Plugin = V4_POSTCSS_PLUGIN.test(postcssConfig);
|
|
640
|
+
const hasV3Plugin = V3_POSTCSS_PLUGIN.test(postcssConfig);
|
|
641
|
+
if (hasV3Plugin) {
|
|
642
|
+
error(
|
|
643
|
+
"postcss-plugin-v3",
|
|
644
|
+
"PostCSS config names `tailwindcss` as a plugin \u2014 the Tailwind 3 spelling. In v4 that entry resolves to a shim whose only job is to throw. Replace it with `'@tailwindcss/postcss': {}`."
|
|
645
|
+
);
|
|
646
|
+
} else if (hasV4Plugin) {
|
|
647
|
+
ok("postcss-plugin-v4", "PostCSS config uses @tailwindcss/postcss");
|
|
526
648
|
} else {
|
|
527
|
-
|
|
528
|
-
|
|
649
|
+
warn(
|
|
650
|
+
"postcss-plugin-absent",
|
|
651
|
+
"PostCSS config does not register a Tailwind plugin. Add `'@tailwindcss/postcss': {}` so Tailwind runs during the build."
|
|
652
|
+
);
|
|
529
653
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
654
|
+
}
|
|
655
|
+
const cssEntries = CSS_ENTRY_CANDIDATES.map((rel) => ({
|
|
656
|
+
rel,
|
|
657
|
+
content: readIfExists(join7(cwd, rel))
|
|
658
|
+
})).filter((entry) => entry.content !== null);
|
|
659
|
+
const importsTailwind = cssEntries.some((entry) => V4_CSS_IMPORT.test(entry.content));
|
|
660
|
+
const usesV3Directives = cssEntries.some((entry) => V3_CSS_DIRECTIVE.test(entry.content));
|
|
661
|
+
const declaresSource = cssEntries.some((entry) => CSS_SOURCE_DIRECTIVE.test(entry.content));
|
|
662
|
+
const optsIntoJsConfig = cssEntries.some((entry) => CSS_CONFIG_DIRECTIVE.test(entry.content));
|
|
663
|
+
if (cssEntries.length === 0) {
|
|
664
|
+
} else if (importsTailwind) {
|
|
665
|
+
ok("css-entry-v4-import", "CSS entry runs `@import 'tailwindcss'`");
|
|
666
|
+
if (declaresSource) {
|
|
667
|
+
ok("css-entry-source", "CSS entry declares `@source` scanning paths");
|
|
536
668
|
}
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
|
|
669
|
+
} else if (usesV3Directives) {
|
|
670
|
+
error(
|
|
671
|
+
"css-entry-v3-directives",
|
|
672
|
+
"CSS entry still uses the Tailwind 3 `@tailwind base/components/utilities` directives. Tailwind 4 replaces all three with a single `@import 'tailwindcss';`."
|
|
673
|
+
);
|
|
674
|
+
} else {
|
|
675
|
+
warn(
|
|
676
|
+
"css-entry-no-tailwind",
|
|
677
|
+
`No CSS entry runs \`@import 'tailwindcss'\`, so Tailwind never starts. Checked: ${cssEntries.map((entry) => entry.rel).join(", ")}.`
|
|
678
|
+
);
|
|
540
679
|
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
680
|
+
const tailwindConfigPath = findFile(cwd, TAILWIND_CONFIG_CANDIDATES);
|
|
681
|
+
if (tailwindConfigPath && !optsIntoJsConfig) {
|
|
682
|
+
const rel = tailwindConfigPath.slice(cwd.length + 1);
|
|
683
|
+
warn(
|
|
684
|
+
"tailwind-config-inert",
|
|
685
|
+
`${rel} exists but nothing opts into it \u2014 Tailwind 4 ignores a JS config unless a stylesheet declares \`@config\`. Anything it sets (theme, content/@source paths, plugins) has no effect today. Either delete it and move the settings into your CSS entry, or add \`@config '${rel}';\` there.`
|
|
686
|
+
);
|
|
687
|
+
} else if (tailwindConfigPath) {
|
|
688
|
+
ok("tailwind-config-active", "JS Tailwind config is loaded via `@config`");
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
if (existsSync7(join7(cwd, "tsconfig.json"))) {
|
|
692
|
+
ok("tsconfig-found", "tsconfig.json found");
|
|
693
|
+
const tsRange = deps.typescript;
|
|
694
|
+
if (tsRange) {
|
|
695
|
+
const major = majorOf(tsRange);
|
|
696
|
+
if (major !== null && major < 5) {
|
|
697
|
+
warn("typescript-legacy", `TypeScript ${tsRange} detected \u2014 version 5.0+ recommended`);
|
|
555
698
|
} else {
|
|
556
|
-
|
|
557
|
-
issues++;
|
|
699
|
+
ok("typescript-version", `TypeScript ${tsRange} (5.0+ required)`);
|
|
558
700
|
}
|
|
559
|
-
} catch (_e) {
|
|
560
701
|
}
|
|
561
702
|
} else {
|
|
562
|
-
|
|
563
|
-
issues++;
|
|
703
|
+
warn("tsconfig-missing", "tsconfig.json not found");
|
|
564
704
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
if (tsVer) {
|
|
572
|
-
const majorVer = parseInt(tsVer.replace(/[^0-9.]/g, "").split(".")[0], 10);
|
|
573
|
-
if (majorVer >= 5) {
|
|
574
|
-
console.log(chalk7.green(`\u2713 TypeScript ${tsVer} (5.0+ required)`));
|
|
575
|
-
} else {
|
|
576
|
-
console.log(chalk7.yellow(`\u26A0\uFE0F TypeScript ${tsVer} detected \u2014 version 5.0+ recommended`));
|
|
577
|
-
issues++;
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
} catch (_e) {
|
|
705
|
+
if (pkg) {
|
|
706
|
+
if (deps["@object-ui/react"] && !deps.react) {
|
|
707
|
+
warn("peer-react", "@object-ui/react requires react as a peer dependency");
|
|
708
|
+
}
|
|
709
|
+
if (deps["@object-ui/components"] && !deps.tailwindcss) {
|
|
710
|
+
warn("peer-tailwind", "@object-ui/components requires tailwindcss as a peer dependency");
|
|
581
711
|
}
|
|
582
|
-
} else {
|
|
583
|
-
console.log(chalk7.yellow("\u26A0\uFE0F tsconfig.json not found"));
|
|
584
|
-
issues++;
|
|
585
712
|
}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
}
|
|
598
|
-
}
|
|
713
|
+
return results;
|
|
714
|
+
}
|
|
715
|
+
function countIssues(results) {
|
|
716
|
+
return results.filter((result) => result.level !== "ok").length;
|
|
717
|
+
}
|
|
718
|
+
async function doctor() {
|
|
719
|
+
console.log(chalk7.bold("Object UI Doctor"));
|
|
720
|
+
console.log("Diagnosis in progress...\n");
|
|
721
|
+
const results = runDiagnostics(process.cwd());
|
|
722
|
+
for (const result of results) {
|
|
723
|
+
if (result.level === "ok") {
|
|
724
|
+
console.log(chalk7.green(`\u2713 ${result.message}`));
|
|
725
|
+
} else if (result.level === "warn") {
|
|
726
|
+
console.log(chalk7.yellow(`\u26A0\uFE0F ${result.message}`));
|
|
727
|
+
} else {
|
|
728
|
+
console.log(chalk7.red(`x ${result.message}`));
|
|
599
729
|
}
|
|
600
730
|
}
|
|
731
|
+
const issues = countIssues(results);
|
|
601
732
|
console.log("\nResult:");
|
|
602
733
|
if (issues === 0) {
|
|
603
734
|
console.log(chalk7.green("Everything looks good! \u2728"));
|
|
@@ -618,13 +749,13 @@ async function add(component) {
|
|
|
618
749
|
import chalk9 from "chalk";
|
|
619
750
|
import { spawn } from "child_process";
|
|
620
751
|
import { existsSync as existsSync8 } from "fs";
|
|
621
|
-
import { join as join8, resolve as resolve4, dirname as
|
|
752
|
+
import { join as join8, resolve as resolve4, dirname as dirname3 } from "path";
|
|
622
753
|
import { fileURLToPath } from "url";
|
|
623
754
|
async function studio() {
|
|
624
755
|
console.log(chalk9.bold("\n\u{1F3A8} Starting ObjectUI Studio...\n"));
|
|
625
756
|
const cwd = process.cwd();
|
|
626
757
|
const __filename3 = fileURLToPath(import.meta.url);
|
|
627
|
-
const __dirname3 =
|
|
758
|
+
const __dirname3 = dirname3(__filename3);
|
|
628
759
|
const candidates = [
|
|
629
760
|
join8(cwd, "apps/console"),
|
|
630
761
|
resolve4(__dirname3, "../../apps/console"),
|
|
@@ -846,10 +977,10 @@ ${index + 1}. ${issue.message}`));
|
|
|
846
977
|
// src/commands/create-plugin.ts
|
|
847
978
|
import chalk12 from "chalk";
|
|
848
979
|
import { spawn as spawn2 } from "child_process";
|
|
849
|
-
import { resolve as resolve6, dirname as
|
|
980
|
+
import { resolve as resolve6, dirname as dirname4 } from "path";
|
|
850
981
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
851
982
|
var __filename = fileURLToPath2(import.meta.url);
|
|
852
|
-
var __dirname =
|
|
983
|
+
var __dirname = dirname4(__filename);
|
|
853
984
|
async function createPlugin(pluginName) {
|
|
854
985
|
console.log(chalk12.blue("\u{1F680} Creating ObjectUI plugin...\n"));
|
|
855
986
|
const createPluginScript = resolve6(
|
|
@@ -973,9 +1104,9 @@ async function analyze(options = {}) {
|
|
|
973
1104
|
// src/cli.ts
|
|
974
1105
|
import { readFileSync as readFileSync4 } from "fs";
|
|
975
1106
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
976
|
-
import { dirname as
|
|
1107
|
+
import { dirname as dirname5, join as join11 } from "path";
|
|
977
1108
|
var __filename2 = fileURLToPath3(import.meta.url);
|
|
978
|
-
var __dirname2 =
|
|
1109
|
+
var __dirname2 = dirname5(__filename2);
|
|
979
1110
|
var packageJson = JSON.parse(
|
|
980
1111
|
readFileSync4(join11(__dirname2, "../package.json"), "utf-8")
|
|
981
1112
|
);
|