@otl-core/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +13 -0
- package/dist/index.cjs +661 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +638 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/add.ts","../src/api/client.ts","../src/utils/naming.ts","../src/codegen/type-mapper.ts","../src/codegen/generate-block.ts","../src/codegen/generate-section.ts","../src/codegen/registry-updater.ts","../src/utils/env.ts","../src/utils/project.ts","../src/commands/init.ts","../src/commands/list.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * OTL CMS CLI\n *\n * Schema-driven component scaffolder for the OTL engine.\n */\n\nimport { Command } from \"commander\";\nimport { registerAddCommands } from \"./commands/add\";\nimport { registerInitCommand } from \"./commands/init\";\nimport { registerListCommands } from \"./commands/list\";\n// import { registerSetupCommands } from \"./commands/setup\";\n\nconst program = new Command();\n\nprogram\n .name(\"otl-cli\")\n .description(\"OTL CMS CLI -- scaffold and manage engine components\")\n .version(\"0.1.0\");\n\n// Register command groups\nregisterAddCommands(program);\nregisterListCommands(program);\nregisterInitCommand(program);\n// registerSetupCommands(program);\n\nprogram.parse();\n","/**\n * `otl-cli add` command group.\n *\n * Generates block or section components from their schema definitions\n * and registers them in the appropriate registry file.\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { findBlockSchemaByType, findSectionSchemaByType } from \"../api/client\";\nimport { generateBlockComponent } from \"../codegen/generate-block\";\nimport { generateSectionComponent } from \"../codegen/generate-section\";\nimport {\n addToBlockRegistry,\n addToSectionRegistry,\n} from \"../codegen/registry-updater\";\nimport { loadConfig } from \"../utils/env\";\nimport { requireEngineProject } from \"../utils/project\";\n\nexport function registerAddCommands(program: Command): void {\n const add = program\n .command(\"add\")\n .description(\"Generate a component from a schema definition\");\n\n add\n .command(\"block <name>\")\n .description(\"Generate a block component from its schema\")\n .option(\"--force\", \"Overwrite existing files\")\n .action(async (name: string, opts: { force?: boolean }) => {\n try {\n const paths = requireEngineProject();\n const config = loadConfig();\n\n // Fetch schema\n const schema = await findBlockSchemaByType(config, name);\n if (!schema) {\n console.error(`Error: No block schema found with type \"${name}\".`);\n console.error(\n \"Run 'npx @otl-core/cli list blocks' to see available schemas.\"\n );\n process.exit(1);\n }\n\n // Check output path\n const outputFile = path.join(paths.blocksDir, `${name}.tsx`);\n if (fs.existsSync(outputFile) && !opts.force) {\n console.error(\n `Error: ${path.relative(paths.root, outputFile)} already exists.`\n );\n console.error(\"Use --force to overwrite.\");\n process.exit(1);\n }\n\n // Generate component\n const content = generateBlockComponent(name, schema.fields);\n\n // Ensure directory exists\n fs.mkdirSync(path.dirname(outputFile), { recursive: true });\n fs.writeFileSync(outputFile, content, \"utf-8\");\n\n const relPath = path.relative(paths.root, outputFile);\n console.log(`Created ${relPath}`);\n\n // Update registry\n if (fs.existsSync(paths.blockRegistryFile)) {\n addToBlockRegistry(paths.blockRegistryFile, name);\n console.log(\n `Updated ${path.relative(paths.root, paths.blockRegistryFile)}`\n );\n }\n\n console.log(\"\");\n console.log(`Next: implement your component in ${relPath}`);\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n\n add\n .command(\"section <name>\")\n .description(\"Generate a section component from its schema\")\n .option(\"--force\", \"Overwrite existing files\")\n .action(async (name: string, opts: { force?: boolean }) => {\n try {\n const paths = requireEngineProject();\n const config = loadConfig();\n\n // Fetch schema\n const schema = await findSectionSchemaByType(config, name);\n if (!schema) {\n console.error(`Error: No section schema found with type \"${name}\".`);\n console.error(\n \"Run 'npx @otl-core/cli list sections' to see available schemas.\"\n );\n process.exit(1);\n }\n\n // Check output path\n const outputFile = path.join(paths.sectionsDir, `${name}.tsx`);\n if (fs.existsSync(outputFile) && !opts.force) {\n console.error(\n `Error: ${path.relative(paths.root, outputFile)} already exists.`\n );\n console.error(\"Use --force to overwrite.\");\n process.exit(1);\n }\n\n // Generate component\n const content = generateSectionComponent(name, schema.fields);\n\n // Ensure directory exists\n fs.mkdirSync(path.dirname(outputFile), { recursive: true });\n fs.writeFileSync(outputFile, content, \"utf-8\");\n\n const relPath = path.relative(paths.root, outputFile);\n console.log(`Created ${relPath}`);\n\n // Update registry\n if (fs.existsSync(paths.sectionRegistryFile)) {\n addToSectionRegistry(paths.sectionRegistryFile, name);\n console.log(\n `Updated ${path.relative(paths.root, paths.sectionRegistryFile)}`\n );\n }\n\n console.log(\"\");\n console.log(`Next: implement your component in ${relPath}`);\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n","/**\n * API client for fetching schemas from the OTL backend.\n * Uses native fetch (Node 18+) with deployment token authentication.\n */\n\nimport type {\n ApiSuccessResponse,\n BlockSchemaListData,\n BlockSchemaResponse,\n CliConfig,\n SectionSchemaResponse,\n} from \"../types\";\n\nfunction buildUrl(config: CliConfig, path: string): string {\n const base = config.apiUrl.replace(/\\/+$/, \"\");\n return `${base}/api/v1/public/deployments/${encodeURIComponent(config.deploymentId)}${path}`;\n}\n\nfunction authHeaders(config: CliConfig): Record<string, string> {\n return {\n Authorization: `Bearer ${config.accessToken}`,\n Accept: \"application/json\",\n };\n}\n\nasync function fetchJson<T>(\n url: string,\n headers: Record<string, string>\n): Promise<T> {\n const response = await fetch(url, { headers });\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new Error(\n `API request failed (${response.status} ${response.statusText}): ${body}`\n );\n }\n\n return response.json() as Promise<T>;\n}\n\n/**\n * Fetch all block schemas for the configured deployment.\n */\nexport async function fetchBlockSchemas(\n config: CliConfig\n): Promise<BlockSchemaResponse[]> {\n const url = buildUrl(config, \"/schemas/blocks\");\n const result = await fetchJson<ApiSuccessResponse<BlockSchemaListData>>(\n url,\n authHeaders(config)\n );\n return result.data.schemas;\n}\n\n/**\n * Fetch a single block schema by its ID.\n */\nexport async function fetchBlockSchemaById(\n config: CliConfig,\n schemaId: string\n): Promise<BlockSchemaResponse> {\n const url = buildUrl(\n config,\n `/schemas/blocks/${encodeURIComponent(schemaId)}`\n );\n const result = await fetchJson<ApiSuccessResponse<BlockSchemaResponse>>(\n url,\n authHeaders(config)\n );\n return result.data;\n}\n\n/**\n * Find a block schema by its type name (e.g. \"pricing-card\").\n * Fetches the full list and filters client-side, since the API indexes by ID.\n */\nexport async function findBlockSchemaByType(\n config: CliConfig,\n typeName: string\n): Promise<BlockSchemaResponse | undefined> {\n const schemas = await fetchBlockSchemas(config);\n return schemas.find(s => s.type === typeName);\n}\n\n/**\n * Fetch all section schemas for the configured deployment.\n * The backend returns the array directly (not wrapped in { schemas, total }).\n */\nexport async function fetchSectionSchemas(\n config: CliConfig\n): Promise<SectionSchemaResponse[]> {\n const url = buildUrl(config, \"/schemas/sections\");\n const result = await fetchJson<ApiSuccessResponse<SectionSchemaResponse[]>>(\n url,\n authHeaders(config)\n );\n return result.data;\n}\n\n/**\n * Fetch a single section schema by its ID.\n */\nexport async function fetchSectionSchemaById(\n config: CliConfig,\n schemaId: string\n): Promise<SectionSchemaResponse> {\n const url = buildUrl(\n config,\n `/schemas/sections/${encodeURIComponent(schemaId)}`\n );\n const result = await fetchJson<ApiSuccessResponse<SectionSchemaResponse>>(\n url,\n authHeaders(config)\n );\n return result.data;\n}\n\n/**\n * Find a section schema by its type name (e.g. \"pricing-table\").\n * Fetches the full list and filters client-side.\n */\nexport async function findSectionSchemaByType(\n config: CliConfig,\n typeName: string\n): Promise<SectionSchemaResponse | undefined> {\n const schemas = await fetchSectionSchemas(config);\n return schemas.find(s => s.type === typeName);\n}\n","/**\n * Naming utilities for converting between different case conventions.\n */\n\n/**\n * Convert a kebab-case string to PascalCase.\n * Example: \"pricing-card\" -> \"PricingCard\"\n */\nexport function kebabToPascal(kebab: string): string {\n return kebab\n .split(\"-\")\n .map(segment => segment.charAt(0).toUpperCase() + segment.slice(1))\n .join(\"\");\n}\n\n/**\n * Convert a snake_case or kebab-case field ID to camelCase.\n * Example: \"plan_name\" -> \"planName\"\n * Example: \"plan-name\" -> \"planName\"\n */\nexport function fieldIdToCamel(id: string): string {\n return id.replace(/[-_]([a-z])/g, (_, char: string) => char.toUpperCase());\n}\n\n/**\n * Convert a PascalCase string to a display-friendly name.\n * Example: \"PricingCard\" -> \"Pricing Card\"\n */\nexport function pascalToDisplay(pascal: string): string {\n return pascal.replace(/([A-Z])/g, \" $1\").trim();\n}\n","/**\n * Maps schema field types (InputFieldType from @otl-core/cms-types) to\n * TypeScript type strings used in generated component interfaces.\n *\n * Also tracks which imports from @otl-core/cms-types are needed.\n */\n\nimport type { SchemaField } from \"../types\";\nimport { fieldIdToCamel, kebabToPascal } from \"../utils/naming\";\n\nexport interface TypeImports {\n ColorReference: boolean;\n MediaReference: boolean;\n ResponsiveValue: boolean;\n BlockInstance: boolean;\n LocalizedString: boolean;\n}\n\nexport function createEmptyImports(): TypeImports {\n return {\n ColorReference: false,\n MediaReference: false,\n ResponsiveValue: false,\n BlockInstance: false,\n LocalizedString: false,\n };\n}\n\n/**\n * Produce the import statement for @otl-core/cms-types based on which types\n * are actually used in the generated interface.\n */\nexport function buildTypeImportLine(imports: TypeImports): string | null {\n const needed: string[] = [];\n if (imports.ColorReference) needed.push(\"ColorReference\");\n if (imports.MediaReference) needed.push(\"MediaReference\");\n if (imports.ResponsiveValue) needed.push(\"ResponsiveValue\");\n if (imports.BlockInstance) needed.push(\"BlockInstance\");\n if (imports.LocalizedString) needed.push(\"LocalizedString\");\n\n if (needed.length === 0) {\n return null;\n }\n return `import type { ${needed.join(\", \")} } from \"@otl-core/cms-types\";`;\n}\n\n/** Simple field types that map directly to a TS primitive or literal. */\nconst SIMPLE_TYPE_MAP: Record<string, string> = {\n text: \"string\",\n textarea: \"string\",\n url: \"string\",\n markdown: \"string\",\n html: \"string\",\n code: \"string\",\n richtext: \"string\",\n date: \"string\",\n number: \"number\",\n boolean: \"boolean\",\n color: \"string\",\n \"form-selector\": \"string\",\n \"form-page\": \"string\",\n json: \"Record<string, unknown>\",\n object: \"Record<string, unknown>\",\n array: \"unknown[]\",\n \"container-behavior\": '\"boxed\" | \"edged\" | \"ignore\"',\n};\n\n/**\n * Resolve the TypeScript type string for a single schema field.\n * Mutates `imports` to track which types need importing.\n * Returns the TS type string (e.g. `\"string\"`, `\"ColorReference\"`, etc.).\n */\nexport function resolveFieldType(\n field: SchemaField,\n imports: TypeImports\n): string {\n const simple = SIMPLE_TYPE_MAP[field.type];\n if (simple !== undefined) {\n return simple;\n }\n\n switch (field.type) {\n // Select can be single or multi\n case \"select\":\n return field.multiple ? \"string[]\" : \"string\";\n\n // Theme color types\n case \"theme-color\":\n case \"theme-background-color\":\n case \"theme-foreground-color\":\n imports.ColorReference = true;\n return \"ColorReference\";\n\n // Image / media\n case \"image\":\n imports.MediaReference = true;\n return \"MediaReference\";\n\n // Responsive value types\n case \"spacing\":\n case \"css-value\":\n case \"columns\": // GridColumnsInputField type is \"columns\"\n imports.ResponsiveValue = true;\n return \"ResponsiveValue<string>\";\n\n // Blocks\n case \"blocks\":\n imports.BlockInstance = true;\n return \"BlockInstance[]\";\n\n // Localized text\n case \"localized-text\":\n imports.LocalizedString = true;\n return \"LocalizedString\";\n\n // Group -- will be handled by the interface generator to produce a nested\n // interface. At the type level we return the interface name.\n case \"group\":\n return \"__GROUP__\";\n\n default:\n // Unknown field types fall back to unknown\n return \"unknown\";\n }\n}\n\nexport interface GeneratedInterface {\n /** The main interface name (e.g. \"PricingCardConfig\") */\n name: string;\n /** All interface declarations (main + nested), joined as a string */\n declarations: string;\n /** Tracked imports */\n imports: TypeImports;\n}\n\n/**\n * Generate TypeScript interface declarations from a list of schema fields.\n *\n * @param interfaceName The name for the top-level interface\n * @param fields The schema fields to map\n */\nexport function generateInterface(\n interfaceName: string,\n fields: SchemaField[]\n): GeneratedInterface {\n const imports = createEmptyImports();\n const extraInterfaces: string[] = [];\n\n const lines = buildInterfaceLines(\n interfaceName,\n fields,\n imports,\n extraInterfaces\n );\n\n const mainInterface = [`interface ${interfaceName} {`, ...lines, \"}\"].join(\n \"\\n\"\n );\n\n const declarations = [...extraInterfaces, mainInterface].join(\"\\n\\n\");\n\n return { name: interfaceName, declarations, imports };\n}\n\nfunction buildInterfaceLines(\n parentName: string,\n fields: SchemaField[],\n imports: TypeImports,\n extraInterfaces: string[]\n): string[] {\n const lines: string[] = [];\n\n for (const field of fields) {\n const camelId = fieldIdToCamel(field.id);\n let tsType = resolveFieldType(field, imports);\n\n // Handle group fields -- generate a nested interface\n if (tsType === \"__GROUP__\" && field.fields && field.fields.length > 0) {\n const nestedName = parentName + kebabToPascal(field.id);\n const nestedLines = buildInterfaceLines(\n nestedName,\n field.fields,\n imports,\n extraInterfaces\n );\n const nestedDecl = [\n `interface ${nestedName} {`,\n ...nestedLines,\n \"}\",\n ].join(\"\\n\");\n extraInterfaces.push(nestedDecl);\n tsType = nestedName;\n } else if (tsType === \"__GROUP__\") {\n // Group with no sub-fields\n tsType = \"Record<string, unknown>\";\n }\n\n // Build the property line with optional JSDoc description\n if (field.description) {\n lines.push(` /** ${field.description} */`);\n }\n lines.push(` ${camelId}?: ${tsType};`);\n }\n\n return lines;\n}\n","/**\n * Generates a block component .tsx file from a schema definition.\n */\n\nimport type { SchemaField } from \"../types\";\nimport { fieldIdToCamel, kebabToPascal } from \"../utils/naming\";\nimport { buildTypeImportLine, generateInterface } from \"./type-mapper\";\n\n/**\n * Generate the full file content for a block component.\n *\n * @param typeName The kebab-case schema type (e.g. \"pricing-card\")\n * @param fields The schema field definitions\n * @returns The complete .tsx file content as a string\n */\nexport function generateBlockComponent(\n typeName: string,\n fields: SchemaField[]\n): string {\n const pascal = kebabToPascal(typeName);\n const configName = `${pascal}Config`;\n const componentName = `${pascal}Block`;\n\n const result = generateInterface(configName, fields);\n\n // Build imports\n const importLines: string[] = [];\n\n const typeImportLine = buildTypeImportLine(result.imports);\n if (typeImportLine) {\n // Merge BlockComponentProps into the same import if there are other cms-types imports\n const typesInBraces = typeImportLine\n .replace(\"import type { \", \"\")\n .replace(' } from \"@otl-core/cms-types\";', \"\");\n importLines.push(\n `import type { BlockComponentProps, ${typesInBraces} } from \"@otl-core/cms-types\";`\n );\n } else {\n importLines.push(\n 'import type { BlockComponentProps } from \"@otl-core/cms-types\";'\n );\n }\n\n // Build the config destructuring for the component body\n const fieldIds = fields\n .map(f => fieldIdToCamel(f.id))\n .filter(id => id.length > 0);\n\n const destructuring =\n fieldIds.length > 0 ? ` const { ${fieldIds.join(\", \")} } = config;\\n` : \"\";\n\n // Assemble the file\n const parts: string[] = [\n importLines.join(\"\\n\"),\n \"\",\n result.declarations,\n \"\",\n `export function ${componentName}({ config }: BlockComponentProps<${configName}>) {`,\n destructuring,\n \" return (\",\n \" <div>\",\n ` {/* TODO: Implement ${typeName} block */}`,\n \" </div>\",\n \" );\",\n \"}\",\n \"\",\n ];\n\n return parts.join(\"\\n\");\n}\n","/**\n * Generates a section component .tsx file from a schema definition.\n */\n\nimport type { SchemaField } from \"../types\";\nimport { fieldIdToCamel, kebabToPascal } from \"../utils/naming\";\nimport { buildTypeImportLine, generateInterface } from \"./type-mapper\";\n\n/**\n * Generate the full file content for a section component.\n *\n * @param typeName The kebab-case schema type (e.g. \"pricing-table\")\n * @param fields The schema field definitions\n * @returns The complete .tsx file content as a string\n */\nexport function generateSectionComponent(\n typeName: string,\n fields: SchemaField[]\n): string {\n const pascal = kebabToPascal(typeName);\n const configName = `${pascal}Config`;\n const componentName = `${pascal}Section`;\n\n const result = generateInterface(configName, fields);\n\n // Build imports\n const importLines: string[] = [];\n\n const typeImportLine = buildTypeImportLine(result.imports);\n if (typeImportLine) {\n const typesInBraces = typeImportLine\n .replace(\"import type { \", \"\")\n .replace(' } from \"@otl-core/cms-types\";', \"\");\n importLines.push(\n `import type { SectionComponentProps, ${typesInBraces} } from \"@otl-core/cms-types\";`\n );\n } else {\n importLines.push(\n 'import type { SectionComponentProps } from \"@otl-core/cms-types\";'\n );\n }\n\n // Build the config destructuring for the component body\n const fieldIds = fields\n .map(f => fieldIdToCamel(f.id))\n .filter(id => id.length > 0);\n\n const destructuring =\n fieldIds.length > 0 ? ` const { ${fieldIds.join(\", \")} } = config;\\n` : \"\";\n\n // Assemble the file\n const parts: string[] = [\n importLines.join(\"\\n\"),\n \"\",\n result.declarations,\n \"\",\n `export function ${componentName}({ config }: SectionComponentProps<${configName}>) {`,\n destructuring,\n \" return (\",\n \" <div>\",\n ` {/* TODO: Implement ${typeName} section */}`,\n \" </div>\",\n \" );\",\n \"}\",\n \"\",\n ];\n\n return parts.join(\"\\n\");\n}\n","/**\n * Updates block/section registry files by adding an import statement\n * and a registration call for a newly generated component.\n */\n\nimport * as fs from \"fs\";\nimport { kebabToPascal } from \"../utils/naming\";\n\n/**\n * Add a block component import and registration to the block registry file.\n *\n * @param registryPath Absolute path to block-registry.ts\n * @param typeName The kebab-case block type (e.g. \"pricing-card\")\n */\nexport function addToBlockRegistry(\n registryPath: string,\n typeName: string\n): void {\n const pascal = kebabToPascal(typeName);\n const componentName = `${pascal}Block`;\n const importPath = `@/components/blocks/${typeName}`;\n\n const importLine = `import { ${componentName} } from \"${importPath}\";`;\n const registerLine = `blockRegistry.register(\"${typeName}\", ${componentName});`;\n\n updateRegistryFile(registryPath, importLine, registerLine);\n}\n\n/**\n * Add a section component import and registration to the section registry file.\n *\n * @param registryPath Absolute path to section-registry.ts\n * @param typeName The kebab-case section type (e.g. \"pricing-table\")\n */\nexport function addToSectionRegistry(\n registryPath: string,\n typeName: string\n): void {\n const pascal = kebabToPascal(typeName);\n const componentName = `${pascal}Section`;\n const importPath = `@/components/sections/${typeName}`;\n\n const importLine = `import { ${componentName} } from \"${importPath}\";`;\n const registerLine = `sectionRegistry.register(\"${typeName}\", ${componentName});`;\n\n updateRegistryFile(registryPath, importLine, registerLine);\n}\n\n/**\n * Insert an import line and a registration line into a registry file.\n *\n * Strategy:\n * 1. Check that the import and registration don't already exist.\n * 2. Find the \"Custom Blocks/Sections\" comment block at the end of the file.\n * 3. Insert the import at the end of the existing import section (before the\n * first blank line after imports or before \"// Create instance\").\n * 4. Insert the registration line just before the closing comment block,\n * or at the very end if no comment block is found.\n */\nfunction updateRegistryFile(\n filePath: string,\n importLine: string,\n registerLine: string\n): void {\n let content = fs.readFileSync(filePath, \"utf-8\");\n\n // Bail if already registered\n if (content.includes(registerLine)) {\n return;\n }\n\n // --- Insert the import ---\n // Find the last import statement and insert after it\n const importRegex = /^import .+$/gm;\n let lastImportMatch: RegExpExecArray | null = null;\n let match: RegExpExecArray | null;\n while ((match = importRegex.exec(content)) !== null) {\n lastImportMatch = match;\n }\n\n if (lastImportMatch) {\n const insertPos = lastImportMatch.index + lastImportMatch[0].length;\n content =\n content.slice(0, insertPos) +\n \"\\n\" +\n importLine +\n content.slice(insertPos);\n } else {\n // No imports found; prepend\n content = importLine + \"\\n\" + content;\n }\n\n // --- Insert the registration ---\n // Look for the \"Custom Blocks\" or \"Custom Sections\" comment block\n const customCommentIndex = content.indexOf(\"/**\\n * Custom \");\n if (customCommentIndex !== -1) {\n // Insert just before the comment block, with a blank line\n content =\n content.slice(0, customCommentIndex) +\n registerLine +\n \"\\n\\n\" +\n content.slice(customCommentIndex);\n } else {\n // Append at end\n content = content.trimEnd() + \"\\n\" + registerLine + \"\\n\";\n }\n\n fs.writeFileSync(filePath, content, \"utf-8\");\n}\n","/**\n * Environment utilities for reading CLI configuration from .env.local or process.env.\n */\n\nimport * as dotenv from \"dotenv\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { CliConfig } from \"../types\";\n\n/**\n * Load CLI configuration from .env.local (in the current directory) and\n * process.env. The .env.local file takes precedence for values it defines;\n * process.env acts as a fallback.\n *\n * Returns the resolved config, or throws an error with a user-friendly\n * message when required values are missing.\n */\nexport function loadConfig(): CliConfig {\n // Try to load .env.local from cwd\n const envLocalPath = path.resolve(process.cwd(), \".env.local\");\n let fileEnv: Record<string, string> = {};\n\n if (fs.existsSync(envLocalPath)) {\n const parsed = dotenv.parse(fs.readFileSync(envLocalPath, \"utf-8\"));\n fileEnv = parsed;\n }\n\n const deploymentId =\n fileEnv[\"DEPLOYMENT_ID\"] || process.env[\"DEPLOYMENT_ID\"] || \"\";\n const accessToken =\n fileEnv[\"DEPLOYMENT_ACCESS_TOKEN\"] ||\n process.env[\"DEPLOYMENT_ACCESS_TOKEN\"] ||\n \"\";\n const apiUrl =\n fileEnv[\"API_URL\"] || process.env[\"API_URL\"] || \"http://localhost:8080\";\n\n if (!deploymentId || !accessToken) {\n console.error(\n \"Error: Missing DEPLOYMENT_ID and/or DEPLOYMENT_ACCESS_TOKEN.\"\n );\n console.error(\n \"Run 'npx @otl-core/cli init' to configure your environment.\"\n );\n process.exit(1);\n }\n\n return { deploymentId, accessToken, apiUrl };\n}\n","/**\n * Engine project detection and path resolution.\n */\n\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { EnginePaths } from \"../types\";\n\n/** OTL package names that indicate an engine project. */\nconst ENGINE_MARKERS = [\n \"@otl-core/block-registry\",\n \"@otl-core/section-registry\",\n];\n\ninterface PackageJson {\n name?: string;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\n/**\n * Read and parse a package.json file. Returns null if it cannot be read.\n */\nfunction readPackageJson(dir: string): PackageJson | null {\n const filePath = path.join(dir, \"package.json\");\n if (!fs.existsSync(filePath)) {\n return null;\n }\n try {\n const raw = fs.readFileSync(filePath, \"utf-8\");\n return JSON.parse(raw) as PackageJson;\n } catch {\n return null;\n }\n}\n\n/**\n * Check whether a directory looks like a OTL engine project.\n */\nfunction isEngineProject(dir: string): boolean {\n const pkg = readPackageJson(dir);\n if (!pkg) {\n return false;\n }\n\n const allDeps: Record<string, string> = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n };\n\n return ENGINE_MARKERS.some(marker => marker in allDeps);\n}\n\n/**\n * Detect the engine project root starting from the current working directory.\n * Walks up the directory tree until it finds a matching package.json or hits\n * the filesystem root.\n *\n * Returns the resolved EnginePaths, or prints an error and exits.\n */\nexport function requireEngineProject(): EnginePaths {\n let current = process.cwd();\n\n // Walk up at most 10 levels\n for (let i = 0; i < 10; i++) {\n if (isEngineProject(current)) {\n return {\n root: current,\n blocksDir: path.join(current, \"src\", \"components\", \"blocks\"),\n sectionsDir: path.join(current, \"src\", \"components\", \"sections\"),\n blockRegistryFile: path.join(\n current,\n \"src\",\n \"lib\",\n \"registries\",\n \"block-registry.ts\"\n ),\n sectionRegistryFile: path.join(\n current,\n \"src\",\n \"lib\",\n \"registries\",\n \"section-registry.ts\"\n ),\n };\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n break;\n }\n current = parent;\n }\n\n console.error(\"Error: Not in a OTL engine project.\");\n console.error(\"Could not find a package.json with @otl-core/ dependencies.\");\n console.error(\"Run this command from your engine project root.\");\n process.exit(1);\n}\n","/**\n * `otl-cli init` command.\n *\n * Interactive setup that writes DEPLOYMENT_ID, DEPLOYMENT_ACCESS_TOKEN,\n * and API_URL into .env.local.\n */\n\nimport type { Command } from \"commander\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as readline from \"readline\";\n\nexport function registerInitCommand(program: Command): void {\n program\n .command(\"init\")\n .description(\"Configure deployment credentials in .env.local\")\n .action(async () => {\n try {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const ask = (question: string): Promise<string> =>\n new Promise(resolve => {\n rl.question(question, answer => resolve(answer.trim()));\n });\n\n console.log(\"OTL CMS -- Engine Configuration\");\n console.log(\"\");\n\n const deploymentId = await ask(\"Deployment ID: \");\n if (!deploymentId) {\n console.error(\"Error: Deployment ID is required.\");\n rl.close();\n process.exit(1);\n }\n\n const accessToken = await ask(\"Deployment Access Token: \");\n if (!accessToken) {\n console.error(\"Error: Access token is required.\");\n rl.close();\n process.exit(1);\n }\n\n const apiUrlInput = await ask(\"API URL [http://localhost:8080]: \");\n const apiUrl = apiUrlInput || \"http://localhost:8080\";\n\n rl.close();\n\n // Write or update .env.local\n const envPath = path.resolve(process.cwd(), \".env.local\");\n let content = \"\";\n\n if (fs.existsSync(envPath)) {\n content = fs.readFileSync(envPath, \"utf-8\");\n content = upsertEnvVar(content, \"DEPLOYMENT_ID\", deploymentId);\n content = upsertEnvVar(\n content,\n \"DEPLOYMENT_ACCESS_TOKEN\",\n accessToken\n );\n content = upsertEnvVar(content, \"API_URL\", apiUrl);\n } else {\n content = [\n \"# OTL CMS Engine Configuration\",\n `DEPLOYMENT_ID=${deploymentId}`,\n `DEPLOYMENT_ACCESS_TOKEN=${accessToken}`,\n `API_URL=${apiUrl}`,\n \"\",\n ].join(\"\\n\");\n }\n\n fs.writeFileSync(envPath, content, \"utf-8\");\n console.log(\"\");\n console.log(\"Written to .env.local\");\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n\n/**\n * Update or insert an environment variable in a .env file string.\n * If the variable already exists, its value is replaced.\n * If it doesn't exist, it's appended at the end.\n */\nfunction upsertEnvVar(content: string, key: string, value: string): string {\n const regex = new RegExp(`^${key}=.*$`, \"m\");\n if (regex.test(content)) {\n return content.replace(regex, `${key}=${value}`);\n }\n // Ensure trailing newline before appending\n const base = content.endsWith(\"\\n\") ? content : content + \"\\n\";\n return base + `${key}=${value}\\n`;\n}\n","/**\n * `otl-cli list` command group.\n *\n * Lists available block or section schemas for the configured deployment.\n */\n\nimport type { Command } from \"commander\";\nimport { fetchBlockSchemas, fetchSectionSchemas } from \"../api/client\";\nimport { loadConfig } from \"../utils/env\";\n\nexport function registerListCommands(program: Command): void {\n const list = program\n .command(\"list\")\n .description(\"List available schemas for the deployment\");\n\n list\n .command(\"blocks\")\n .description(\"List all block schemas\")\n .action(async () => {\n try {\n const config = loadConfig();\n const schemas = await fetchBlockSchemas(config);\n\n if (schemas.length === 0) {\n console.log(\"No block schemas found for this deployment.\");\n return;\n }\n\n // Print header\n const typeCol = 24;\n const nameCol = 28;\n const fieldsCol = 8;\n console.log(\n padRight(\"TYPE\", typeCol) +\n padRight(\"NAME\", nameCol) +\n padRight(\"FIELDS\", fieldsCol)\n );\n console.log(\"-\".repeat(typeCol + nameCol + fieldsCol));\n\n for (const schema of schemas) {\n const fieldCount = schema.fields ? schema.fields.length : 0;\n console.log(\n padRight(schema.type, typeCol) +\n padRight(schema.name, nameCol) +\n String(fieldCount)\n );\n }\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n\n list\n .command(\"sections\")\n .description(\"List all section schemas\")\n .action(async () => {\n try {\n const config = loadConfig();\n const schemas = await fetchSectionSchemas(config);\n\n if (schemas.length === 0) {\n console.log(\"No section schemas found for this deployment.\");\n return;\n }\n\n const typeCol = 24;\n const nameCol = 28;\n const fieldsCol = 8;\n console.log(\n padRight(\"TYPE\", typeCol) +\n padRight(\"NAME\", nameCol) +\n padRight(\"FIELDS\", fieldsCol)\n );\n console.log(\"-\".repeat(typeCol + nameCol + fieldsCol));\n\n for (const schema of schemas) {\n const fieldCount = schema.fields ? schema.fields.length : 0;\n console.log(\n padRight(schema.type, typeCol) +\n padRight(schema.name, nameCol) +\n String(fieldCount)\n );\n }\n } catch (err) {\n if (err instanceof Error) {\n console.error(`Error: ${err.message}`);\n }\n process.exit(1);\n }\n });\n}\n\n/** Pad a string to a minimum width with trailing spaces. */\nfunction padRight(str: string, width: number): string {\n if (str.length >= width) {\n return str + \" \";\n }\n return str + \" \".repeat(width - str.length);\n}\n"],"mappings":"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","names":["fs","path","path","fs","fs","path","program","fs","path","program","resolve","program"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@otl-core/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "OTL CMS CLI -- scaffold and manage engine components",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"otl-cli": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup",
|
|
24
|
+
"clean": "rm -rf dist",
|
|
25
|
+
"rebuild": "npm run clean && npm run build",
|
|
26
|
+
"prepublishOnly": "npm run rebuild",
|
|
27
|
+
"test": "vitest run",
|
|
28
|
+
"test:watch": "vitest",
|
|
29
|
+
"test:ui": "vitest --ui"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18"
|
|
33
|
+
},
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/otl-core/cli.git"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"otl",
|
|
40
|
+
"cms",
|
|
41
|
+
"cli",
|
|
42
|
+
"codegen"
|
|
43
|
+
],
|
|
44
|
+
"author": "OTL Core",
|
|
45
|
+
"license": "PolyForm-Shield-1.0.0",
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"commander": "^13.1.0",
|
|
48
|
+
"dotenv": "^16.4.7"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "^20",
|
|
52
|
+
"@vitest/ui": "^4.0.0",
|
|
53
|
+
"tsup": "^8.0.0",
|
|
54
|
+
"typescript": "^5.0.0",
|
|
55
|
+
"vitest": "^4.0.0"
|
|
56
|
+
}
|
|
57
|
+
}
|