@betterstart/cli 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +133 -0
- package/dist/cli.d.ts +1 -9
- package/dist/cli.js +13484 -367
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +24 -266
- package/dist/index.js +4 -11378
- package/dist/index.js.map +1 -1
- package/package.json +29 -42
- package/templates/schema.json +959 -0
- package/templates/tiptap/hooks/use-composed-ref.ts +43 -0
- package/templates/tiptap/hooks/use-cursor-visibility.ts +68 -0
- package/templates/tiptap/hooks/use-element-rect.ts +166 -0
- package/templates/tiptap/hooks/use-is-breakpoint.ts +32 -0
- package/templates/tiptap/hooks/use-menu-navigation.ts +182 -0
- package/templates/tiptap/hooks/use-scrolling.ts +64 -0
- package/templates/tiptap/hooks/use-throttled-callback.ts +146 -0
- package/templates/tiptap/hooks/use-tiptap-editor.ts +46 -0
- package/templates/tiptap/hooks/use-unmount.ts +21 -0
- package/templates/tiptap/hooks/use-window-size.ts +87 -0
- package/templates/tiptap/lib/tiptap-utils.ts +587 -0
- package/templates/tiptap/styles/_keyframe-animations.scss +91 -0
- package/templates/tiptap/styles/_variables.scss +296 -0
- package/templates/tiptap/tiptap-extension/node-background-extension.ts +138 -0
- package/templates/tiptap/tiptap-icons/align-center-icon.tsx +38 -0
- package/templates/tiptap/tiptap-icons/align-justify-icon.tsx +38 -0
- package/templates/tiptap/tiptap-icons/align-left-icon.tsx +38 -0
- package/templates/tiptap/tiptap-icons/align-right-icon.tsx +38 -0
- package/templates/tiptap/tiptap-icons/arrow-left-icon.tsx +24 -0
- package/templates/tiptap/tiptap-icons/ban-icon.tsx +26 -0
- package/templates/tiptap/tiptap-icons/blockquote-icon.tsx +44 -0
- package/templates/tiptap/tiptap-icons/bold-icon.tsx +26 -0
- package/templates/tiptap/tiptap-icons/chevron-down-icon.tsx +26 -0
- package/templates/tiptap/tiptap-icons/close-icon.tsx +24 -0
- package/templates/tiptap/tiptap-icons/code-block-icon.tsx +38 -0
- package/templates/tiptap/tiptap-icons/code2-icon.tsx +32 -0
- package/templates/tiptap/tiptap-icons/corner-down-left-icon.tsx +26 -0
- package/templates/tiptap/tiptap-icons/external-link-icon.tsx +28 -0
- package/templates/tiptap/tiptap-icons/heading-five-icon.tsx +28 -0
- package/templates/tiptap/tiptap-icons/heading-four-icon.tsx +28 -0
- package/templates/tiptap/tiptap-icons/heading-icon.tsx +24 -0
- package/templates/tiptap/tiptap-icons/heading-one-icon.tsx +28 -0
- package/templates/tiptap/tiptap-icons/heading-six-icon.tsx +30 -0
- package/templates/tiptap/tiptap-icons/heading-three-icon.tsx +36 -0
- package/templates/tiptap/tiptap-icons/heading-two-icon.tsx +28 -0
- package/templates/tiptap/tiptap-icons/highlighter-icon.tsx +26 -0
- package/templates/tiptap/tiptap-icons/image-plus-icon.tsx +26 -0
- package/templates/tiptap/tiptap-icons/italic-icon.tsx +24 -0
- package/templates/tiptap/tiptap-icons/link-icon.tsx +28 -0
- package/templates/tiptap/tiptap-icons/list-icon.tsx +56 -0
- package/templates/tiptap/tiptap-icons/list-ordered-icon.tsx +56 -0
- package/templates/tiptap/tiptap-icons/list-todo-icon.tsx +50 -0
- package/templates/tiptap/tiptap-icons/moon-star-icon.tsx +30 -0
- package/templates/tiptap/tiptap-icons/redo2-icon.tsx +26 -0
- package/templates/tiptap/tiptap-icons/strike-icon.tsx +28 -0
- package/templates/tiptap/tiptap-icons/subscript-icon.tsx +38 -0
- package/templates/tiptap/tiptap-icons/sun-icon.tsx +58 -0
- package/templates/tiptap/tiptap-icons/superscript-icon.tsx +38 -0
- package/templates/tiptap/tiptap-icons/trash-icon.tsx +26 -0
- package/templates/tiptap/tiptap-icons/underline-icon.tsx +26 -0
- package/templates/tiptap/tiptap-icons/undo2-icon.tsx +26 -0
- package/templates/tiptap/tiptap-node/blockquote-node/blockquote-node.scss +37 -0
- package/templates/tiptap/tiptap-node/code-block-node/code-block-node.scss +54 -0
- package/templates/tiptap/tiptap-node/heading-node/heading-node.scss +45 -0
- package/templates/tiptap/tiptap-node/horizontal-rule-node/horizontal-rule-node-extension.ts +10 -0
- package/templates/tiptap/tiptap-node/horizontal-rule-node/horizontal-rule-node.scss +25 -0
- package/templates/tiptap/tiptap-node/image-node/image-node.scss +35 -0
- package/templates/tiptap/tiptap-node/image-upload-node/image-upload-node-extension.ts +154 -0
- package/templates/tiptap/tiptap-node/image-upload-node/image-upload-node.scss +249 -0
- package/templates/tiptap/tiptap-node/image-upload-node/image-upload-node.tsx +522 -0
- package/templates/tiptap/tiptap-node/image-upload-node/index.tsx +1 -0
- package/templates/tiptap/tiptap-node/list-node/list-node.scss +208 -0
- package/templates/tiptap/tiptap-node/paragraph-node/paragraph-node.scss +273 -0
- package/templates/tiptap/tiptap-ui/blockquote-button/blockquote-button.tsx +104 -0
- package/templates/tiptap/tiptap-ui/blockquote-button/index.tsx +2 -0
- package/templates/tiptap/tiptap-ui/blockquote-button/use-blockquote.ts +252 -0
- package/templates/tiptap/tiptap-ui/code-block-button/code-block-button.tsx +106 -0
- package/templates/tiptap/tiptap-ui/code-block-button/index.tsx +2 -0
- package/templates/tiptap/tiptap-ui/code-block-button/use-code-block.ts +261 -0
- package/templates/tiptap/tiptap-ui/color-highlight-button/color-highlight-button.scss +49 -0
- package/templates/tiptap/tiptap-ui/color-highlight-button/color-highlight-button.tsx +153 -0
- package/templates/tiptap/tiptap-ui/color-highlight-button/index.tsx +2 -0
- package/templates/tiptap/tiptap-ui/color-highlight-button/use-color-highlight.ts +345 -0
- package/templates/tiptap/tiptap-ui/color-highlight-popover/color-highlight-popover.tsx +207 -0
- package/templates/tiptap/tiptap-ui/color-highlight-popover/index.tsx +1 -0
- package/templates/tiptap/tiptap-ui/heading-button/heading-button.tsx +107 -0
- package/templates/tiptap/tiptap-ui/heading-button/index.tsx +2 -0
- package/templates/tiptap/tiptap-ui/heading-button/use-heading.ts +314 -0
- package/templates/tiptap/tiptap-ui/heading-dropdown-menu/heading-dropdown-menu.tsx +131 -0
- package/templates/tiptap/tiptap-ui/heading-dropdown-menu/index.tsx +2 -0
- package/templates/tiptap/tiptap-ui/heading-dropdown-menu/use-heading-dropdown-menu.ts +130 -0
- package/templates/tiptap/tiptap-ui/image-upload-button/image-upload-button.tsx +114 -0
- package/templates/tiptap/tiptap-ui/image-upload-button/index.tsx +2 -0
- package/templates/tiptap/tiptap-ui/image-upload-button/use-image-upload.ts +192 -0
- package/templates/tiptap/tiptap-ui/link-popover/index.tsx +2 -0
- package/templates/tiptap/tiptap-ui/link-popover/link-popover.tsx +285 -0
- package/templates/tiptap/tiptap-ui/link-popover/use-link-popover.ts +286 -0
- package/templates/tiptap/tiptap-ui/list-button/index.tsx +2 -0
- package/templates/tiptap/tiptap-ui/list-button/list-button.tsx +108 -0
- package/templates/tiptap/tiptap-ui/list-button/use-list.ts +329 -0
- package/templates/tiptap/tiptap-ui/list-dropdown-menu/index.tsx +1 -0
- package/templates/tiptap/tiptap-ui/list-dropdown-menu/list-dropdown-menu.tsx +123 -0
- package/templates/tiptap/tiptap-ui/list-dropdown-menu/use-list-dropdown-menu.ts +203 -0
- package/templates/tiptap/tiptap-ui/mark-button/index.tsx +2 -0
- package/templates/tiptap/tiptap-ui/mark-button/mark-button.tsx +107 -0
- package/templates/tiptap/tiptap-ui/mark-button/use-mark.ts +206 -0
- package/templates/tiptap/tiptap-ui/text-align-button/index.tsx +2 -0
- package/templates/tiptap/tiptap-ui/text-align-button/text-align-button.tsx +118 -0
- package/templates/tiptap/tiptap-ui/text-align-button/use-text-align.ts +212 -0
- package/templates/tiptap/tiptap-ui/undo-redo-button/index.tsx +2 -0
- package/templates/tiptap/tiptap-ui/undo-redo-button/undo-redo-button.tsx +105 -0
- package/templates/tiptap/tiptap-ui/undo-redo-button/use-undo-redo.ts +173 -0
- package/templates/tiptap/tiptap-ui-primitive/badge/badge-colors.scss +395 -0
- package/templates/tiptap/tiptap-ui-primitive/badge/badge-group.scss +16 -0
- package/templates/tiptap/tiptap-ui-primitive/badge/badge.scss +99 -0
- package/templates/tiptap/tiptap-ui-primitive/badge/badge.tsx +46 -0
- package/templates/tiptap/tiptap-ui-primitive/badge/index.tsx +1 -0
- package/templates/tiptap/tiptap-ui-primitive/button/button-colors.scss +429 -0
- package/templates/tiptap/tiptap-ui-primitive/button/button-group.scss +22 -0
- package/templates/tiptap/tiptap-ui-primitive/button/button.scss +314 -0
- package/templates/tiptap/tiptap-ui-primitive/button/button.tsx +102 -0
- package/templates/tiptap/tiptap-ui-primitive/button/index.tsx +1 -0
- package/templates/tiptap/tiptap-ui-primitive/card/card.scss +77 -0
- package/templates/tiptap/tiptap-ui-primitive/card/card.tsx +59 -0
- package/templates/tiptap/tiptap-ui-primitive/card/index.tsx +1 -0
- package/templates/tiptap/tiptap-ui-primitive/dropdown-menu/dropdown-menu.scss +63 -0
- package/templates/tiptap/tiptap-ui-primitive/dropdown-menu/dropdown-menu.tsx +95 -0
- package/templates/tiptap/tiptap-ui-primitive/dropdown-menu/index.tsx +1 -0
- package/templates/tiptap/tiptap-ui-primitive/input/index.tsx +1 -0
- package/templates/tiptap/tiptap-ui-primitive/input/input.scss +45 -0
- package/templates/tiptap/tiptap-ui-primitive/input/input.tsx +18 -0
- package/templates/tiptap/tiptap-ui-primitive/popover/index.tsx +1 -0
- package/templates/tiptap/tiptap-ui-primitive/popover/popover.scss +63 -0
- package/templates/tiptap/tiptap-ui-primitive/popover/popover.tsx +33 -0
- package/templates/tiptap/tiptap-ui-primitive/separator/index.tsx +1 -0
- package/templates/tiptap/tiptap-ui-primitive/separator/separator.scss +23 -0
- package/templates/tiptap/tiptap-ui-primitive/separator/separator.tsx +33 -0
- package/templates/tiptap/tiptap-ui-primitive/spacer/index.tsx +1 -0
- package/templates/tiptap/tiptap-ui-primitive/spacer/spacer.tsx +21 -0
- package/templates/tiptap/tiptap-ui-primitive/toolbar/index.tsx +1 -0
- package/templates/tiptap/tiptap-ui-primitive/toolbar/toolbar.scss +98 -0
- package/templates/tiptap/tiptap-ui-primitive/toolbar/toolbar.tsx +113 -0
- package/templates/tiptap/tiptap-ui-primitive/tooltip/index.tsx +1 -0
- package/templates/tiptap/tiptap-ui-primitive/tooltip/tooltip.scss +43 -0
- package/templates/tiptap/tiptap-ui-primitive/tooltip/tooltip.tsx +223 -0
- package/templates/ui/accordion.tsx +52 -0
- package/templates/ui/alert-dialog.tsx +116 -0
- package/templates/ui/alert.tsx +48 -0
- package/templates/ui/aspect-ratio.tsx +7 -0
- package/templates/ui/avatar.tsx +46 -0
- package/templates/ui/badge.tsx +32 -0
- package/templates/ui/breadcrumb.tsx +98 -0
- package/templates/ui/button-group.tsx +77 -0
- package/templates/ui/button.tsx +48 -0
- package/templates/ui/calendar.tsx +176 -0
- package/templates/ui/card.tsx +54 -0
- package/templates/ui/carousel.tsx +234 -0
- package/templates/ui/chart.tsx +349 -0
- package/templates/ui/checkbox.tsx +27 -0
- package/templates/ui/collapsible.tsx +11 -0
- package/templates/ui/command.tsx +142 -0
- package/templates/ui/context-menu.tsx +188 -0
- package/templates/ui/curriculum-editor.tsx +601 -0
- package/templates/ui/date-picker.tsx +70 -0
- package/templates/ui/dialog.tsx +103 -0
- package/templates/ui/drawer.tsx +99 -0
- package/templates/ui/dropdown-menu.tsx +185 -0
- package/templates/ui/dynamic-list-field.tsx +95 -0
- package/templates/ui/empty.tsx +90 -0
- package/templates/ui/field.tsx +231 -0
- package/templates/ui/file-upload-example.tsx +113 -0
- package/templates/ui/form.tsx +172 -0
- package/templates/ui/hover-card.tsx +28 -0
- package/templates/ui/icon-picker.tsx +435 -0
- package/templates/ui/icons-data.ts +6 -0
- package/templates/ui/image-upload-field.tsx +360 -0
- package/templates/ui/input-group.tsx +160 -0
- package/templates/ui/input-otp.tsx +70 -0
- package/templates/ui/input.tsx +21 -0
- package/templates/ui/item.tsx +171 -0
- package/templates/ui/kbd.tsx +28 -0
- package/templates/ui/label.tsx +20 -0
- package/templates/ui/logo.tsx +113 -0
- package/templates/ui/markdown-editor.tsx +303 -0
- package/templates/ui/markdown-utils.ts +128 -0
- package/templates/ui/media-upload-field.tsx +255 -0
- package/templates/ui/menubar.tsx +230 -0
- package/templates/ui/navigation-menu.tsx +119 -0
- package/templates/ui/pagination.tsx +96 -0
- package/templates/ui/placeholder.tsx +25 -0
- package/templates/ui/popover.tsx +32 -0
- package/templates/ui/progress.tsx +24 -0
- package/templates/ui/radio-group.tsx +37 -0
- package/templates/ui/resizable.tsx +41 -0
- package/templates/ui/rich-text-editor.tsx +374 -0
- package/templates/ui/scroll-area.tsx +45 -0
- package/templates/ui/select.tsx +151 -0
- package/templates/ui/separator.tsx +25 -0
- package/templates/ui/sheet.tsx +120 -0
- package/templates/ui/sidebar.tsx +684 -0
- package/templates/ui/skeleton.tsx +7 -0
- package/templates/ui/slider.tsx +24 -0
- package/templates/ui/sonner.tsx +29 -0
- package/templates/ui/spinner.tsx +15 -0
- package/templates/ui/switch.tsx +28 -0
- package/templates/ui/table.tsx +93 -0
- package/templates/ui/tabs.tsx +54 -0
- package/templates/ui/textarea.tsx +20 -0
- package/templates/ui/toast.tsx +127 -0
- package/templates/ui/toggle-group.tsx +56 -0
- package/templates/ui/toggle.tsx +43 -0
- package/templates/ui/tooltip.tsx +31 -0
- package/templates/ui/use-mobile.tsx +19 -0
- package/templates/ui/video-upload-field.tsx +368 -0
- package/dist/chunk-EIH4RRIJ.js +0 -183
- package/dist/chunk-EIH4RRIJ.js.map +0 -1
- package/dist/chunk-NKRQYAS6.js +0 -260
- package/dist/chunk-NKRQYAS6.js.map +0 -1
- package/dist/chunk-QLVSHP7X.js +0 -235
- package/dist/chunk-QLVSHP7X.js.map +0 -1
- package/dist/chunk-WY6BC55D.js +0 -357
- package/dist/chunk-WY6BC55D.js.map +0 -1
- package/dist/config/index.d.ts +0 -93
- package/dist/config/index.js +0 -58
- package/dist/config/index.js.map +0 -1
- package/dist/core/index.d.ts +0 -415
- package/dist/core/index.js +0 -906
- package/dist/core/index.js.map +0 -1
- package/dist/import-resolver-BaZ-rzkH.d.ts +0 -123
- package/dist/logger-awLb347n.d.ts +0 -81
- package/dist/plugins/index.d.ts +0 -213
- package/dist/plugins/index.js +0 -365
- package/dist/plugins/index.js.map +0 -1
- package/dist/types-ByX_gl6y.d.ts +0 -232
- package/dist/types-eI549DEG.d.ts +0 -331
package/dist/core/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/constants.ts","../../src/core/field-helpers.ts","../../src/core/type-mappers.ts"],"sourcesContent":["/**\n * Centralized constants for the codegen package\n * These replace magic strings scattered throughout generators\n */\n\n// ============================================================================\n// Field Types\n// ============================================================================\n\n/**\n * All supported field types for schema definitions\n */\nexport const FIELD_TYPES = {\n // Primitives\n STRING: 'string',\n NUMBER: 'number',\n BOOLEAN: 'boolean',\n TEXT: 'text',\n DECIMAL: 'decimal',\n VARCHAR: 'varchar',\n SERIAL: 'serial',\n\n // Date/Time\n DATE: 'date',\n TIMESTAMP: 'timestamp',\n TIME: 'time',\n\n // Rich content\n MARKDOWN: 'markdown',\n IMAGE: 'image',\n VIDEO: 'video',\n MEDIA: 'media',\n ICON: 'icon',\n\n // Structure\n GROUP: 'group',\n TABS: 'tabs',\n LIST: 'list',\n SEPARATOR: 'separator',\n\n // Relations\n SELECT: 'select',\n RELATIONSHIP: 'relationship',\n\n // Complex content types\n CURRICULUM: 'curriculum'\n} as const\n\n/**\n * Field types that contain nested fields\n */\nexport const NESTED_FIELD_TYPES = [FIELD_TYPES.GROUP, FIELD_TYPES.TABS, FIELD_TYPES.LIST] as const\n\n/**\n * Field types that represent rich text content\n */\nexport const RICH_TEXT_FIELD_TYPES = [FIELD_TYPES.MARKDOWN, FIELD_TYPES.TEXT] as const\n\n/**\n * Field types that are stored as long text in the database\n */\nexport const LONG_TEXT_FIELD_TYPES = [\n FIELD_TYPES.TEXT,\n FIELD_TYPES.MARKDOWN,\n FIELD_TYPES.LIST,\n FIELD_TYPES.MEDIA,\n FIELD_TYPES.VIDEO,\n FIELD_TYPES.CURRICULUM\n] as const\n\n// ============================================================================\n// Column Types\n// ============================================================================\n\n/**\n * All supported column types for admin tables\n */\nexport const COLUMN_TYPES = {\n TEXT: 'text',\n BADGE: 'badge',\n DATE: 'date',\n CUSTOM: 'custom',\n AVATAR: 'avatar',\n LINK: 'link',\n IMAGE: 'image',\n EMAIL: 'email',\n NUMBER: 'number',\n BOOLEAN: 'boolean'\n} as const\n\n// ============================================================================\n// Form Field Types\n// ============================================================================\n\n/**\n * All supported form field types\n */\nexport const FORM_FIELD_TYPES = {\n TEXT: 'text',\n TEXTAREA: 'textarea',\n EMAIL: 'email',\n PHONE: 'phone',\n NUMBER: 'number',\n URL: 'url',\n DATE: 'date',\n SELECT: 'select',\n RADIO: 'radio',\n CHECKBOX: 'checkbox',\n MULTISELECT: 'multiselect',\n FILE: 'file',\n UPLOAD: 'upload',\n GROUP: 'group',\n TIMEZONE: 'timezone',\n LIST: 'list'\n} as const\n\n// ============================================================================\n// Auto-generated Fields\n// ============================================================================\n\n/**\n * Fields that are automatically added to schemas\n */\nexport const AUTO_FIELDS = {\n ID: 'id',\n CREATED_AT: 'createdAt',\n UPDATED_AT: 'updatedAt',\n PUBLISHED: 'published',\n SLUG: 'slug'\n} as const\n\n/**\n * Fields automatically added for form submissions\n */\nexport const FORM_SUBMISSION_FIELDS = {\n SUBMITTED_AT: 'submittedAt',\n IP_ADDRESS: 'ipAddress',\n USER_AGENT: 'userAgent'\n} as const\n\n// ============================================================================\n// Database Constants\n// ============================================================================\n\n/**\n * Default Drizzle column configurations\n */\nexport const DRIZZLE_DEFAULTS = {\n VARCHAR_LENGTH: 255,\n DECIMAL_PRECISION: 10,\n DECIMAL_SCALE: 2\n} as const\n\n// ============================================================================\n// Generator Names\n// ============================================================================\n\n/**\n * Core generators that are always included\n */\nexport const CORE_GENERATORS = [\n 'database',\n 'actions',\n 'hooks',\n 'columns',\n 'table',\n 'page',\n 'page-content',\n 'form',\n 'create-page',\n 'edit-page',\n 'navigation'\n] as const\n\n/**\n * Optional generators that can be enabled via config\n */\nexport const OPTIONAL_GENERATORS = [] as const\n\n// ============================================================================\n// File Extensions\n// ============================================================================\n\nexport const FILE_EXTENSIONS = {\n TYPESCRIPT: '.ts',\n TSX: '.tsx',\n JSON: '.json',\n SQL: '.sql'\n} as const\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\nexport type FieldTypeValue = (typeof FIELD_TYPES)[keyof typeof FIELD_TYPES]\nexport type ColumnTypeValue = (typeof COLUMN_TYPES)[keyof typeof COLUMN_TYPES]\nexport type FormFieldTypeValue = (typeof FORM_FIELD_TYPES)[keyof typeof FORM_FIELD_TYPES]\n\n/**\n * Check if a value is a valid field type\n */\nexport function isFieldType(value: string): value is FieldTypeValue {\n return Object.values(FIELD_TYPES).includes(value as FieldTypeValue)\n}\n\n/**\n * Check if a field type contains nested fields\n */\nexport function isNestedFieldType(type: string): boolean {\n return (NESTED_FIELD_TYPES as readonly string[]).includes(type)\n}\n\n/**\n * Check if a field type is stored as long text\n */\nexport function isLongTextFieldType(type: string): boolean {\n return (LONG_TEXT_FIELD_TYPES as readonly string[]).includes(type)\n}\n","/**\n * Field helper utilities for the codegen package\n * Consolidates duplicated field-checking functions from actions.ts, form.ts, etc.\n */\n\nimport type { FieldType, FormField, FormSchema, SchemaField } from '../types'\nimport { FIELD_TYPES } from './constants'\n\n// ============================================================================\n// Field Tree Walking\n// ============================================================================\n\n/**\n * Options for walking the field tree\n */\nexport interface WalkFieldsOptions {\n /** Include fields inside list items */\n includeLists?: boolean\n /** Include fields inside groups */\n includeGroups?: boolean\n /** Include fields inside tabs */\n includeTabs?: boolean\n}\n\nconst DEFAULT_WALK_OPTIONS: WalkFieldsOptions = {\n includeLists: true,\n includeGroups: true,\n includeTabs: true\n}\n\n/**\n * Walk through all fields in a schema, including nested ones\n * @param fields - The fields to walk\n * @param callback - Called for each field with depth and parent info\n * @param options - Control which nested structures to traverse\n */\nexport function walkFields(\n fields: SchemaField[],\n callback: (field: SchemaField, depth: number, parent?: SchemaField) => void,\n options: WalkFieldsOptions = DEFAULT_WALK_OPTIONS\n): void {\n function walk(fieldsToWalk: SchemaField[], depth: number, parent?: SchemaField): void {\n for (const field of fieldsToWalk) {\n callback(field, depth, parent)\n\n // Recurse into nested structures\n if (options.includeGroups && field.type === 'group' && field.fields) {\n walk(field.fields, depth + 1, field)\n }\n if (options.includeLists && field.type === 'list' && field.fields) {\n walk(field.fields, depth + 1, field)\n }\n if (options.includeTabs && field.type === 'tabs' && field.tabs) {\n for (const tab of field.tabs) {\n if (tab.fields) {\n walk(tab.fields, depth + 1, field)\n }\n }\n }\n }\n }\n\n walk(fields, 0)\n}\n\n// ============================================================================\n// Field Type Checking\n// ============================================================================\n\n/**\n * Check if any field in the tree matches a specific type\n * Replaces the many checkForFieldType() functions\n */\nexport function hasFieldType(\n fields: SchemaField[],\n type: FieldType | string,\n options?: WalkFieldsOptions\n): boolean {\n let found = false\n walkFields(\n fields,\n (field) => {\n if (field.type === type) {\n found = true\n }\n },\n options\n )\n return found\n}\n\n/**\n * Check if any field in the tree matches any of the given types\n */\nexport function hasAnyFieldType(\n fields: SchemaField[],\n types: (FieldType | string)[],\n options?: WalkFieldsOptions\n): boolean {\n let found = false\n walkFields(\n fields,\n (field) => {\n if (types.includes(field.type)) {\n found = true\n }\n },\n options\n )\n return found\n}\n\n/**\n * Check if any field uses icons (either icon type or hasIcon property)\n * Replaces checkForIconUsage() from form.ts\n */\nexport function hasIconUsage(fields: SchemaField[], options?: WalkFieldsOptions): boolean {\n let found = false\n walkFields(\n fields,\n (field) => {\n if (field.type === 'icon' || field.hasIcon) {\n found = true\n }\n },\n options\n )\n return found\n}\n\n/**\n * Check if any field is a relationship field\n * Replaces checkForRelationshipField() from form.ts\n */\nexport function hasRelationshipField(fields: SchemaField[], options?: WalkFieldsOptions): boolean {\n return hasFieldType(fields, FIELD_TYPES.RELATIONSHIP, options)\n}\n\n/**\n * Check if any field is a markdown field\n * Replaces checkForMarkdownField() from form.ts\n */\nexport function hasMarkdownField(fields: SchemaField[], options?: WalkFieldsOptions): boolean {\n return hasFieldType(fields, FIELD_TYPES.MARKDOWN, options)\n}\n\n/**\n * Check if any field is a textarea/text field\n * Replaces checkForTextareaField() from form.ts\n */\nexport function hasTextareaField(fields: SchemaField[], options?: WalkFieldsOptions): boolean {\n return hasFieldType(fields, FIELD_TYPES.TEXT, options)\n}\n\n// ============================================================================\n// Field Collection\n// ============================================================================\n\n/**\n * Collect all fields of a specific type\n */\nexport function collectFieldsByType(\n fields: SchemaField[],\n type: FieldType | string,\n options?: WalkFieldsOptions\n): SchemaField[] {\n const result: SchemaField[] = []\n walkFields(\n fields,\n (field) => {\n if (field.type === type) {\n result.push(field)\n }\n },\n options\n )\n return result\n}\n\n/**\n * Get all many-to-many relationship fields\n * Replaces getManyToManyFields() from actions.ts and database.ts\n */\nexport function getManyToManyFields(fields: SchemaField[]): SchemaField[] {\n const flat = flattenFields(fields)\n return flat.filter((f) => f.type === 'relationship' && f.multiple === true && f.relationship)\n}\n\n/**\n * Get all relationship fields (excluding many-to-many)\n * Replaces _getNestedRelationshipFields() from actions.ts\n */\nexport function getNestedRelationshipFields(\n fields: SchemaField[],\n options?: WalkFieldsOptions\n): SchemaField[] {\n const result: SchemaField[] = []\n walkFields(\n fields,\n (field) => {\n if (field.type === 'relationship' && field.relationship && !field.multiple) {\n result.push(field)\n }\n },\n options\n )\n return result\n}\n\n/**\n * Collect relationship fields from top-level and groups only (not lists)\n * Used for form imports where list relationships use different handling\n */\nexport function collectRelationshipFieldsTopLevel(fields: SchemaField[]): SchemaField[] {\n const result: SchemaField[] = []\n\n function collect(fieldsToCheck: SchemaField[]): void {\n for (const f of fieldsToCheck) {\n if (f.type === 'relationship' && f.relationship) {\n result.push(f)\n }\n if (f.type === 'group' && f.fields) {\n collect(f.fields)\n }\n // Don't recurse into list fields - those use uncontrolled Popover\n }\n }\n\n collect(fields)\n return result\n}\n\n/**\n * Collect ALL relationship fields including those in lists\n * Used for data hooks\n */\nexport function collectAllRelationshipFields(fields: SchemaField[]): SchemaField[] {\n return collectFieldsByType(fields, FIELD_TYPES.RELATIONSHIP)\n}\n\n/**\n * Get list fields that have nested fields (not just items)\n */\nexport function getListFieldsWithNestedFields(fields: SchemaField[]): SchemaField[] {\n const result: SchemaField[] = []\n\n function collect(fieldsToCheck: SchemaField[]): void {\n for (const f of fieldsToCheck) {\n if (f.type === 'list' && f.fields && f.fields.length > 0) {\n result.push(f)\n }\n if (f.type === 'group' && f.fields) {\n collect(f.fields)\n }\n }\n }\n\n collect(fields)\n return result\n}\n\n/**\n * Get nested list fields (list fields inside list fields)\n */\nexport function getNestedListFields(\n fields: SchemaField[]\n): { parent: SchemaField; nested: SchemaField }[] {\n const result: { parent: SchemaField; nested: SchemaField }[] = []\n\n const listFields = getListFieldsWithNestedFields(fields)\n for (const parent of listFields) {\n if (parent.fields) {\n for (const nested of parent.fields) {\n if (nested.type === 'list' && nested.fields && nested.fields.length > 0) {\n result.push({ parent, nested })\n }\n }\n }\n }\n\n return result\n}\n\n// ============================================================================\n// Field Flattening\n// ============================================================================\n\n/**\n * Auto-generated ID field that's injected if not present in schema\n */\nconst AUTO_ID_FIELD: SchemaField = {\n name: 'id',\n type: 'serial',\n primaryKey: true\n}\n\n/**\n * Ensure fields have an ID field - automatically injects one if not present\n */\nexport function ensureIdField(fields: SchemaField[]): SchemaField[] {\n const hasIdField = fields.some((f) => f.primaryKey || f.name === 'id')\n if (hasIdField) {\n return fields\n }\n // Prepend the auto-generated ID field\n return [AUTO_ID_FIELD, ...fields]\n}\n\n/**\n * Flatten group and tabs fields into individual fields for database operations\n * Automatically ensures an ID field exists\n */\nexport function flattenFields(fields: SchemaField[]): SchemaField[] {\n // First ensure we have an ID field\n const fieldsWithId = ensureIdField(fields)\n return flattenFieldsWithoutIdCheck(fieldsWithId)\n}\n\n/**\n * Internal helper to flatten without adding ID (for nested structures)\n */\nfunction flattenFieldsWithoutIdCheck(fields: SchemaField[]): SchemaField[] {\n const flattened: SchemaField[] = []\n\n for (const field of fields) {\n if (field.type === 'group' && field.fields) {\n flattened.push(...flattenFieldsWithoutIdCheck(field.fields))\n } else if (field.type === 'tabs' && field.tabs) {\n for (const tab of field.tabs) {\n if (tab.fields) {\n flattened.push(...flattenFieldsWithoutIdCheck(tab.fields))\n }\n }\n } else {\n flattened.push(field)\n }\n }\n\n return flattened\n}\n\n// ============================================================================\n// Form Field Helpers\n// ============================================================================\n\n/**\n * Get all fields from a form schema (including from steps)\n * Replaces getAllFields() from email-template.ts and form-generator.ts\n */\nexport function getAllFormFields(schema: FormSchema): FormField[] {\n const allFields: FormField[] = []\n\n if (schema.steps) {\n for (const step of schema.steps) {\n for (const field of step.fields) {\n // Flatten group fields\n if (field.type === 'group' && field.fields) {\n // Propagate condition from group to nested fields\n for (const nestedField of field.fields) {\n allFields.push({\n ...nestedField,\n condition: nestedField.condition || field.condition\n })\n }\n } else {\n allFields.push(field)\n }\n }\n }\n } else if (schema.fields) {\n for (const field of schema.fields) {\n // Flatten group fields\n if (field.type === 'group' && field.fields) {\n // Propagate condition from group to nested fields\n for (const nestedField of field.fields) {\n allFields.push({\n ...nestedField,\n condition: nestedField.condition || field.condition\n })\n }\n } else {\n allFields.push(field)\n }\n }\n }\n\n return allFields\n}\n\n/**\n * Check if a form schema is multi-step\n */\nexport function isMultiStepForm(schema: FormSchema): boolean {\n return Array.isArray(schema.steps) && schema.steps.length > 0\n}\n\n// ============================================================================\n// Field Analysis Results\n// ============================================================================\n\n/**\n * Result of analyzing all field types in a schema\n */\nexport interface FieldAnalysis {\n hasBoolean: boolean\n hasImage: boolean\n hasVideo: boolean\n hasMedia: boolean\n hasDate: boolean\n hasList: boolean\n hasNestedList: boolean\n hasSelect: boolean\n hasMarkdown: boolean\n hasTextarea: boolean\n hasSeparator: boolean\n hasIcon: boolean\n hasRelationship: boolean\n hasManyToMany: boolean\n fieldTypes: Set<string>\n}\n\n/**\n * Analyze all field types in a schema\n * Returns a comprehensive analysis that can be used to determine imports, etc.\n */\nexport function analyzeFields(fields: SchemaField[]): FieldAnalysis {\n const fieldTypes = new Set<string>()\n let hasIcon = false\n let hasNestedList = false\n\n walkFields(fields, (field) => {\n fieldTypes.add(field.type)\n if (field.type === 'icon' || field.hasIcon) {\n hasIcon = true\n }\n })\n\n // Check for nested lists\n const listFields = getListFieldsWithNestedFields(fields)\n for (const listField of listFields) {\n if (listField.fields?.some((f) => f.type === 'list')) {\n hasNestedList = true\n break\n }\n }\n\n return {\n hasBoolean: fieldTypes.has(FIELD_TYPES.BOOLEAN),\n hasImage: fieldTypes.has(FIELD_TYPES.IMAGE),\n hasVideo: fieldTypes.has(FIELD_TYPES.VIDEO),\n hasMedia: fieldTypes.has(FIELD_TYPES.MEDIA),\n hasDate: fieldTypes.has(FIELD_TYPES.DATE),\n hasList: fieldTypes.has(FIELD_TYPES.LIST),\n hasNestedList,\n hasSelect: fieldTypes.has(FIELD_TYPES.SELECT),\n hasMarkdown: fieldTypes.has(FIELD_TYPES.MARKDOWN),\n hasTextarea: fieldTypes.has(FIELD_TYPES.TEXT),\n hasSeparator: fieldTypes.has(FIELD_TYPES.SEPARATOR),\n hasIcon,\n hasRelationship: fieldTypes.has(FIELD_TYPES.RELATIONSHIP),\n hasManyToMany: getManyToManyFields(fields).length > 0,\n fieldTypes\n }\n}\n","/**\n * Type mapping utilities for the codegen package\n * Consolidates type mapping functions from form.ts, database.ts, actions.ts, form-generator.ts\n */\n\nimport type { FormField, SchemaField } from '../types'\nimport { quotePropertyName, singularize, toPascalCase } from '../utils'\nimport { DRIZZLE_DEFAULTS } from './constants'\n\n// ============================================================================\n// Schema Field → Drizzle Type (for database.ts)\n// ============================================================================\n\n/**\n * Check if a field name suggests it's a URL field\n */\nfunction isUrlField(fieldName: string): boolean {\n const urlKeywords = ['url', 'link', 'href', 'website', 'avatar', 'logo', 'thumbnail']\n const lowerName = fieldName.toLowerCase()\n return urlKeywords.some((keyword) => lowerName.includes(keyword))\n}\n\n/**\n * Map a schema field type to Drizzle ORM column type\n * @param field - The schema field\n * @param requiredImports - Set to track which Drizzle imports are needed\n * @returns The Drizzle column type expression\n */\nexport function toDrizzleType(field: SchemaField, requiredImports: Set<string>): string {\n switch (field.type) {\n case 'serial':\n requiredImports.add('serial')\n return 'serial()'\n case 'string':\n case 'varchar':\n // Use text() for URL-like fields or if no length specified and field name suggests URL\n if (isUrlField(field.name) && !field.length) {\n requiredImports.add('text')\n return 'text()'\n }\n requiredImports.add('varchar')\n return field.length\n ? `varchar({ length: ${field.length} })`\n : `varchar({ length: ${DRIZZLE_DEFAULTS.VARCHAR_LENGTH} })`\n case 'image':\n case 'video':\n case 'media':\n // Media fields (URLs) should use text() to handle long URLs\n requiredImports.add('text')\n return 'text()'\n case 'text':\n case 'markdown':\n case 'richtext':\n requiredImports.add('text')\n return 'text()'\n case 'number':\n requiredImports.add('integer')\n return 'integer()'\n case 'decimal':\n requiredImports.add('decimal')\n if (field.precision && field.scale) {\n return `decimal({ precision: ${field.precision}, scale: ${field.scale} })`\n }\n return `decimal({ precision: ${DRIZZLE_DEFAULTS.DECIMAL_PRECISION}, scale: ${DRIZZLE_DEFAULTS.DECIMAL_SCALE} })`\n case 'boolean':\n requiredImports.add('boolean')\n return 'boolean()'\n case 'timestamp':\n requiredImports.add('timestamp')\n return \"timestamp({ precision: 3, mode: 'string' })\"\n case 'date':\n requiredImports.add('date')\n return \"date({ mode: 'string' })\"\n case 'time':\n case 'select':\n case 'icon':\n requiredImports.add('varchar')\n return field.length\n ? `varchar({ length: ${field.length} })`\n : `varchar({ length: ${DRIZZLE_DEFAULTS.VARCHAR_LENGTH} })`\n case 'curriculum':\n requiredImports.add('jsonb')\n return `jsonb().$type<{ mode: 'sequential'; items: Array<{ title?: string; description?: string }> } | { mode: 'weekly'; weeks: Array<{ weekNumber: number; weekTitle?: string; weekDescription?: string; durationHours?: number; items: Array<{ title?: string; description?: string }> }> }>()`\n case 'list':\n requiredImports.add('jsonb')\n // If list has nested fields, store as array of objects, otherwise as array of strings\n if (field.fields && field.fields.length > 0) {\n const nestedType = buildNestedListType(field.fields)\n return `jsonb().$type<Array<{ ${nestedType} }>>()`\n }\n return 'jsonb().$type<string[]>()'\n case 'relationship':\n // Single relationships store foreign key ID\n requiredImports.add('integer')\n return 'integer()'\n default:\n requiredImports.add('text')\n return 'text()'\n }\n}\n\n/**\n * Build nested type string for list fields with nested fields\n */\nfunction buildNestedListType(fields: SchemaField[]): string {\n return fields\n .flatMap((f) => {\n let type: string\n if (f.type === 'list' && f.fields && f.fields.length > 0) {\n // Nested list with fields - array of objects\n const innerType = f.fields\n .map((nf) => {\n let nfType: string\n if (nf.type === 'boolean') {\n nfType = 'boolean'\n } else if (nf.type === 'number' || nf.type === 'decimal') {\n nfType = 'number'\n } else {\n nfType = 'string'\n }\n return `${quotePropertyName(nf.name)}?: ${nfType}`\n })\n .join('; ')\n type = `Array<{ ${innerType} }>`\n } else if (f.type === 'list') {\n type = 'string[]'\n } else if (f.type === 'number' || f.type === 'decimal') {\n type = 'number'\n } else if (f.type === 'boolean') {\n type = 'boolean'\n } else {\n type = 'string'\n }\n const result = [`${quotePropertyName(f.name)}?: ${type}`]\n // Add icon field if hasIcon is true\n if (f.hasIcon) {\n result.push(`${quotePropertyName(`${f.name}Icon`)}?: string`)\n }\n return result\n })\n .join('; ')\n}\n\n// ============================================================================\n// Schema Field → Zod Type (for form.ts)\n// ============================================================================\n\n/**\n * Map a schema field type to Zod validation schema\n * @param field - The schema field\n * @returns The Zod schema expression as a string\n */\nexport function toZodType(field: SchemaField): string {\n const label = field.label || field.name\n\n switch (field.type) {\n case 'serial':\n case 'number':\n case 'decimal':\n return field.required\n ? `z.number({ message: '${label} is required' })`\n : 'z.number().optional()'\n case 'boolean':\n return 'z.boolean()'\n case 'string':\n case 'varchar':\n case 'text':\n case 'markdown':\n case 'richtext': {\n if (field.name.toLowerCase().includes('email')) {\n const base = field.required\n ? `z.string().min(1, '${label} is required').email('Please enter a valid email address')`\n : `z.string().email('Please enter a valid email address').optional()`\n return field.length ? `${base}.max(${field.length})` : base\n }\n const base = field.required ? `z.string().min(1, '${label} is required')` : 'z.string()'\n return field.length ? `${base}.max(${field.length})` : base\n }\n case 'date':\n if (!field.required) {\n return 'z.string().transform(val => val === \"\" ? undefined : val).optional()'\n }\n return `z.string().min(1, '${label} is required')`\n case 'timestamp':\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'image':\n case 'video':\n case 'media': {\n if (!field.required) {\n return 'z.string().transform(val => val === \"\" ? undefined : val).optional()'\n }\n const mediaType =\n field.type === 'image' ? 'an image' : field.type === 'video' ? 'a video' : 'media'\n const base = `z.string().min(1, 'Please upload ${mediaType} for ${label}').url('Please provide a valid ${field.type} URL')`\n return field.length ? `${base}.max(${field.length})` : base\n }\n case 'list':\n return buildZodListType(field, label)\n case 'select': {\n if (field.options && field.options.length > 0) {\n const values = field.options.map((opt) => `'${opt.value}'`).join(', ')\n const valuesArray = `[${values}] as const`\n return field.required\n ? `z.string().min(1, '${label} is required').refine((val) => (${valuesArray} as readonly string[]).includes(val), { message: 'Invalid ${label}' })`\n : `z.string().refine((val) => !val || (${valuesArray} as readonly string[]).includes(val), { message: 'Invalid ${label}' }).optional()`\n }\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n case 'icon':\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'relationship': {\n if (field.multiple) {\n return field.required\n ? `z.array(z.number()).min(1, '${label} is required')`\n : 'z.array(z.number()).optional()'\n }\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n case 'curriculum':\n // Curriculum stores both items and weeks - mode determines which editor to show\n return `z.object({\n mode: z.enum(['sequential', 'weekly']),\n items: z.array(z.object({\n title: z.string().max(255).optional(),\n description: z.string().max(500).optional()\n })).max(50),\n weeks: z.array(z.object({\n weekNumber: z.number().int().positive(),\n weekTitle: z.string().max(100).optional(),\n weekDescription: z.string().max(1000).optional(),\n durationHours: z.number().positive().optional(),\n items: z.array(z.object({\n title: z.string().max(255).optional(),\n description: z.string().max(500).optional()\n })).max(20)\n })).max(20)\n }).optional()`\n default:\n return field.required ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n}\n\n/**\n * Build Zod type for list fields\n */\nfunction buildZodListType(field: SchemaField, label: string): string {\n // Handle list with nested fields (array of objects)\n if (field.fields && field.fields.length > 0) {\n const nestedFields = field.fields\n .flatMap((nestedField) => {\n const defs: string[] = []\n const nestedZodType = toZodType(nestedField)\n const alreadyOptional = nestedZodType.includes('.optional()')\n let nestedDef = ` ${quotePropertyName(nestedField.name)}: ${nestedZodType}`\n if (!nestedField.required && !alreadyOptional) {\n nestedDef += '.optional()'\n }\n defs.push(nestedDef)\n // Add icon field if hasIcon is true\n if (nestedField.hasIcon) {\n defs.push(` ${quotePropertyName(`${nestedField.name}Icon`)}: z.string().optional()`)\n }\n return defs\n })\n .join(',\\n')\n const objectSchema = `z.object({\\n${nestedFields}\\n })`\n const arraySchema = field.maxItems\n ? `z.array(${objectSchema}).max(${field.maxItems}, '${label} cannot exceed ${field.maxItems} items')`\n : `z.array(${objectSchema})`\n return field.required\n ? `${arraySchema}.min(1, '${label} must have at least one item')`\n : `${arraySchema}.optional()`\n }\n // Handle list with items (simple string array)\n if (field.items?.type === 'string' || field.items?.type === 'varchar') {\n const itemSchema = field.items.length ? `z.string().max(${field.items.length})` : 'z.string()'\n const arraySchema = field.maxItems\n ? `z.array(${itemSchema}).max(${field.maxItems}, '${label} cannot exceed ${field.maxItems} items')`\n : `z.array(${itemSchema})`\n return field.required\n ? `${arraySchema}.min(1, '${label} must have at least one item')`\n : `${arraySchema}.optional()`\n }\n return field.required\n ? `z.array(z.string()).min(1, '${label} must have at least one item')`\n : 'z.array(z.string()).optional()'\n}\n\n// ============================================================================\n// Schema Field → TypeScript Type (for actions.ts)\n// ============================================================================\n\n/**\n * Map a schema field type to TypeScript type\n * @param field - The schema field\n * @param mode - 'input' for form input types, 'output' for database output types\n * @returns The TypeScript type as a string\n */\nexport function toTypeScriptType(field: SchemaField, mode: 'input' | 'output' = 'output'): string {\n switch (field.type) {\n case 'serial':\n case 'number':\n case 'decimal':\n return 'number'\n case 'boolean':\n return 'boolean'\n case 'string':\n case 'varchar':\n case 'text':\n case 'markdown':\n case 'richtext':\n case 'date':\n case 'time':\n case 'timestamp':\n case 'image':\n case 'video':\n case 'media':\n case 'icon':\n case 'select':\n return 'string'\n case 'relationship':\n // For input, relationships are stored as IDs (strings)\n // For output, return the full related object\n if (mode === 'input') {\n return field.multiple ? 'number[]' : 'string'\n }\n if (field.relationship) {\n const relationshipSingular = singularize(field.relationship)\n const relationshipPascal = toPascalCase(relationshipSingular)\n return field.multiple ? `${relationshipPascal}Data[]` : `${relationshipPascal}Data | null`\n }\n return 'string'\n case 'list':\n if (field.fields && field.fields.length > 0) {\n const nestedType = field.fields\n .flatMap((f) => {\n // For nested list fields, relationship fields are stored as IDs (strings) in JSONB\n const type = toTypeScriptType(f, 'input')\n const fields = [`${quotePropertyName(f.name)}?: ${type}`]\n if (f.hasIcon) {\n fields.push(`${quotePropertyName(`${f.name}Icon`)}?: string`)\n }\n return fields\n })\n .join('; ')\n return `Array<{ ${nestedType} }>`\n }\n return 'string[]'\n case 'curriculum':\n return '{ mode: \"sequential\" | \"weekly\"; items: Array<{ title?: string; description?: string }>; weeks: Array<{ weekNumber: number; weekTitle?: string; weekDescription?: string; durationHours?: number; items: Array<{ title?: string; description?: string }> }> }'\n default:\n return 'string'\n }\n}\n\n// ============================================================================\n// Schema Field → Form Field Type (for form.ts)\n// ============================================================================\n\n/**\n * Map a schema field type to HTML form input type\n * @param field - The schema field\n * @returns The form input type (checkbox, textarea, number, date, etc.)\n */\nexport function toFormFieldType(field: SchemaField): string {\n switch (field.type) {\n case 'boolean':\n return 'checkbox'\n case 'text':\n return 'textarea'\n case 'markdown':\n return 'markdown'\n case 'richtext':\n return 'richtext'\n case 'number':\n case 'decimal':\n return 'number'\n case 'date':\n return 'date'\n case 'time':\n return 'time'\n case 'timestamp':\n return 'datetime-local'\n default:\n return 'text'\n }\n}\n\n// ============================================================================\n// Form Field → Drizzle Type (for form-generator.ts)\n// ============================================================================\n\n/**\n * Map a form field type to Drizzle ORM column type\n * @param field - The form field\n * @param requiredImports - Set to track which Drizzle imports are needed\n * @returns The Drizzle column type expression\n */\nexport function formFieldToDrizzleType(field: FormField, requiredImports: Set<string>): string {\n switch (field.type) {\n case 'text':\n requiredImports.add('varchar')\n return field.maxLength\n ? `varchar({ length: ${field.maxLength} })`\n : `varchar({ length: ${DRIZZLE_DEFAULTS.VARCHAR_LENGTH} })`\n case 'textarea':\n requiredImports.add('text')\n return 'text()'\n case 'email':\n requiredImports.add('varchar')\n return `varchar({ length: ${DRIZZLE_DEFAULTS.VARCHAR_LENGTH} })`\n case 'phone':\n requiredImports.add('varchar')\n return 'varchar({ length: 50 })'\n case 'number':\n requiredImports.add('integer')\n return 'integer()'\n case 'url':\n requiredImports.add('varchar')\n return 'varchar({ length: 500 })'\n case 'date':\n requiredImports.add('date')\n return \"date({ mode: 'string' })\"\n case 'select':\n case 'radio':\n case 'timezone':\n requiredImports.add('varchar')\n return `varchar({ length: ${DRIZZLE_DEFAULTS.VARCHAR_LENGTH} })`\n case 'checkbox':\n requiredImports.add('boolean')\n return 'boolean()'\n case 'multiselect':\n requiredImports.add('jsonb')\n return 'jsonb().$type<string[]>()'\n case 'list':\n requiredImports.add('jsonb')\n if (field.fields && field.fields.length > 0) {\n return 'jsonb().$type<Record<string, unknown>[]>()'\n }\n return 'jsonb().$type<string[]>()'\n case 'file':\n case 'upload':\n requiredImports.add('text')\n return 'text()'\n default:\n requiredImports.add('text')\n return 'text()'\n }\n}\n\n// ============================================================================\n// Form Field → Zod Type (for form-generator.ts)\n// ============================================================================\n\nexport interface FormFieldZodOptions {\n /** Treat field as optional even if required (for conditional fields) */\n treatAsOptional?: boolean\n}\n\n/**\n * Map a form field type to Zod validation schema\n * @param field - The form field\n * @param options - Options for generating the zod type\n * @returns The Zod schema expression as a string\n */\nexport function formFieldToZodType(field: FormField, options: FormFieldZodOptions = {}): string {\n const label = field.label\n const isRequired = field.required && !options.treatAsOptional\n\n switch (field.type) {\n case 'text': {\n let zodType = isRequired ? `z.string().min(1, '${label} is required')` : 'z.string()'\n if (field.minLength) {\n zodType += `.min(${field.minLength}, '${label} must be at least ${field.minLength} characters')`\n }\n if (field.maxLength) {\n zodType += `.max(${field.maxLength}, '${label} must be at most ${field.maxLength} characters')`\n }\n if (field.pattern) {\n zodType += `.regex(new RegExp('${field.pattern}'), 'Invalid ${label} format')`\n }\n return isRequired ? zodType : `${zodType}.optional()`\n }\n case 'textarea': {\n let zodType = isRequired ? `z.string().min(1, '${label} is required')` : 'z.string()'\n if (field.minLength) {\n zodType += `.min(${field.minLength}, '${label} must be at least ${field.minLength} characters')`\n }\n if (field.maxLength) {\n zodType += `.max(${field.maxLength}, '${label} must be at most ${field.maxLength} characters')`\n }\n return isRequired ? zodType : `${zodType}.optional()`\n }\n case 'email':\n return isRequired\n ? `z.string().min(1, '${label} is required').email('Please enter a valid email address')`\n : `z.string().optional().refine((val) => !val || val.trim() === '' || z.string().email().safeParse(val).success, { message: 'Please enter a valid email address' })`\n case 'phone': {\n const pattern =\n field.pattern || '^[+]?[(]?[0-9]{1,4}[)]?[-\\\\s\\\\.]?[(]?[0-9]{1,4}[)]?[-\\\\s\\\\.]?[0-9]{1,9}$'\n return isRequired\n ? `z.string().min(1, '${label} is required').regex(new RegExp('${pattern}'), 'Please enter a valid phone number')`\n : `z.string().optional().refine((val) => !val || val.trim() === '' || new RegExp('${pattern}').test(val), { message: 'Please enter a valid phone number' })`\n }\n case 'number': {\n let zodType = isRequired ? `z.number({ message: '${label} is required' })` : 'z.number()'\n if (field.min !== undefined) {\n zodType += `.min(${field.min}, '${label} must be at least ${field.min}')`\n }\n if (field.max !== undefined) {\n zodType += `.max(${field.max}, '${label} must be at most ${field.max}')`\n }\n return isRequired ? zodType : `${zodType}.optional()`\n }\n case 'url':\n return isRequired\n ? `z.string().min(1, '${label} is required').url('Please enter a valid URL')`\n : `z.string().optional().refine((val) => !val || val.trim() === '' || z.string().url().safeParse(val).success, { message: 'Please enter a valid URL' })`\n case 'date':\n return isRequired\n ? `z.string().min(1, '${label} is required')`\n : 'z.string().transform(val => val === \"\" ? undefined : val).optional()'\n case 'select':\n case 'radio':\n if (field.options && field.options.length > 0) {\n const values = field.options.map((opt) => `'${opt.value}'`).join(', ')\n return isRequired\n ? `z.enum([${values}], { message: '${label} is required' })`\n : `z.enum([${values}]).optional()`\n }\n return isRequired ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'checkbox':\n return isRequired\n ? `z.literal(true, { message: '${label} is required' })`\n : 'z.boolean().optional()'\n case 'multiselect':\n return isRequired\n ? `z.array(z.string()).min(1, '${label} is required')`\n : 'z.array(z.string()).optional()'\n case 'timezone':\n return isRequired ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n case 'list':\n if (field.fields && field.fields.length > 0) {\n const nestedFields = field.fields\n .map((f) => `${f.name}: ${formFieldToZodType(f, options)}`)\n .join(', ')\n return isRequired\n ? `z.array(z.object({ ${nestedFields} })).min(1, '${label} is required')`\n : `z.array(z.object({ ${nestedFields} })).optional()`\n }\n return isRequired\n ? `z.array(z.string()).min(1, '${label} is required')`\n : 'z.array(z.string()).optional()'\n case 'file':\n case 'upload':\n return isRequired ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n default:\n return isRequired ? `z.string().min(1, '${label} is required')` : 'z.string().optional()'\n }\n}\n\n// ============================================================================\n// SQL Type Mapping (for raw SQL migrations)\n// ============================================================================\n\n/**\n * Map a schema field type to SQL column type\n * @param field - The schema field\n * @returns The SQL column type\n */\nexport function toSQLType(field: SchemaField): string {\n switch (field.type) {\n case 'serial':\n return 'SERIAL'\n case 'string':\n case 'varchar':\n return field.length\n ? `VARCHAR(${field.length})`\n : `VARCHAR(${DRIZZLE_DEFAULTS.VARCHAR_LENGTH})`\n case 'text':\n case 'markdown':\n case 'richtext':\n case 'image':\n case 'video':\n case 'media':\n return 'TEXT'\n case 'number':\n return 'INTEGER'\n case 'decimal':\n return `DECIMAL(${field.precision || DRIZZLE_DEFAULTS.DECIMAL_PRECISION}, ${field.scale || DRIZZLE_DEFAULTS.DECIMAL_SCALE})`\n case 'boolean':\n return 'BOOLEAN'\n case 'timestamp':\n return 'TIMESTAMP(3)'\n case 'date':\n return 'DATE'\n case 'time':\n case 'select':\n case 'icon':\n return `VARCHAR(${DRIZZLE_DEFAULTS.VARCHAR_LENGTH})`\n case 'list':\n case 'curriculum':\n return 'JSONB'\n case 'relationship':\n return 'INTEGER'\n default:\n return 'TEXT'\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYO,IAAM,cAAc;AAAA;AAAA,EAEzB,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA;AAAA,EAGR,MAAM;AAAA,EACN,WAAW;AAAA,EACX,MAAM;AAAA;AAAA,EAGN,UAAU;AAAA,EACV,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AAAA;AAAA,EAGN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,WAAW;AAAA;AAAA,EAGX,QAAQ;AAAA,EACR,cAAc;AAAA;AAAA,EAGd,YAAY;AACd;AAKO,IAAM,qBAAqB,CAAC,YAAY,OAAO,YAAY,MAAM,YAAY,IAAI;AAKjF,IAAM,wBAAwB,CAAC,YAAY,UAAU,YAAY,IAAI;AAKrE,IAAM,wBAAwB;AAAA,EACnC,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AACd;AASO,IAAM,eAAe;AAAA,EAC1B,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AACX;AASO,IAAM,mBAAmB;AAAA,EAC9B,MAAM;AAAA,EACN,UAAU;AAAA,EACV,OAAO;AAAA,EACP,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,UAAU;AAAA,EACV,MAAM;AACR;AASO,IAAM,cAAc;AAAA,EACzB,IAAI;AAAA,EACJ,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,MAAM;AACR;AAKO,IAAM,yBAAyB;AAAA,EACpC,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,YAAY;AACd;AASO,IAAM,mBAAmB;AAAA,EAC9B,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,eAAe;AACjB;AASO,IAAM,kBAAkB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,IAAM,sBAAsB,CAAC;AAM7B,IAAM,kBAAkB;AAAA,EAC7B,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AACP;AAaO,SAAS,YAAY,OAAwC;AAClE,SAAO,OAAO,OAAO,WAAW,EAAE,SAAS,KAAuB;AACpE;AAKO,SAAS,kBAAkB,MAAuB;AACvD,SAAQ,mBAAyC,SAAS,IAAI;AAChE;AAKO,SAAS,oBAAoB,MAAuB;AACzD,SAAQ,sBAA4C,SAAS,IAAI;AACnE;;;ACjMA,IAAM,uBAA0C;AAAA,EAC9C,cAAc;AAAA,EACd,eAAe;AAAA,EACf,aAAa;AACf;AAQO,SAAS,WACd,QACA,UACA,UAA6B,sBACvB;AACN,WAAS,KAAK,cAA6B,OAAe,QAA4B;AACpF,eAAW,SAAS,cAAc;AAChC,eAAS,OAAO,OAAO,MAAM;AAG7B,UAAI,QAAQ,iBAAiB,MAAM,SAAS,WAAW,MAAM,QAAQ;AACnE,aAAK,MAAM,QAAQ,QAAQ,GAAG,KAAK;AAAA,MACrC;AACA,UAAI,QAAQ,gBAAgB,MAAM,SAAS,UAAU,MAAM,QAAQ;AACjE,aAAK,MAAM,QAAQ,QAAQ,GAAG,KAAK;AAAA,MACrC;AACA,UAAI,QAAQ,eAAe,MAAM,SAAS,UAAU,MAAM,MAAM;AAC9D,mBAAW,OAAO,MAAM,MAAM;AAC5B,cAAI,IAAI,QAAQ;AACd,iBAAK,IAAI,QAAQ,QAAQ,GAAG,KAAK;AAAA,UACnC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,OAAK,QAAQ,CAAC;AAChB;AAUO,SAAS,aACd,QACA,MACA,SACS;AACT,MAAI,QAAQ;AACZ;AAAA,IACE;AAAA,IACA,CAAC,UAAU;AACT,UAAI,MAAM,SAAS,MAAM;AACvB,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACA,SAAO;AACT;AAKO,SAAS,gBACd,QACA,OACA,SACS;AACT,MAAI,QAAQ;AACZ;AAAA,IACE;AAAA,IACA,CAAC,UAAU;AACT,UAAI,MAAM,SAAS,MAAM,IAAI,GAAG;AAC9B,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,aAAa,QAAuB,SAAsC;AACxF,MAAI,QAAQ;AACZ;AAAA,IACE;AAAA,IACA,CAAC,UAAU;AACT,UAAI,MAAM,SAAS,UAAU,MAAM,SAAS;AAC1C,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,qBAAqB,QAAuB,SAAsC;AAChG,SAAO,aAAa,QAAQ,YAAY,cAAc,OAAO;AAC/D;AAMO,SAAS,iBAAiB,QAAuB,SAAsC;AAC5F,SAAO,aAAa,QAAQ,YAAY,UAAU,OAAO;AAC3D;AAMO,SAAS,iBAAiB,QAAuB,SAAsC;AAC5F,SAAO,aAAa,QAAQ,YAAY,MAAM,OAAO;AACvD;AASO,SAAS,oBACd,QACA,MACA,SACe;AACf,QAAM,SAAwB,CAAC;AAC/B;AAAA,IACE;AAAA,IACA,CAAC,UAAU;AACT,UAAI,MAAM,SAAS,MAAM;AACvB,eAAO,KAAK,KAAK;AAAA,MACnB;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,oBAAoB,QAAsC;AACxE,QAAM,OAAO,cAAc,MAAM;AACjC,SAAO,KAAK,OAAO,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,aAAa,QAAQ,EAAE,YAAY;AAC9F;AAMO,SAAS,4BACd,QACA,SACe;AACf,QAAM,SAAwB,CAAC;AAC/B;AAAA,IACE;AAAA,IACA,CAAC,UAAU;AACT,UAAI,MAAM,SAAS,kBAAkB,MAAM,gBAAgB,CAAC,MAAM,UAAU;AAC1E,eAAO,KAAK,KAAK;AAAA,MACnB;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,kCAAkC,QAAsC;AACtF,QAAM,SAAwB,CAAC;AAE/B,WAAS,QAAQ,eAAoC;AACnD,eAAW,KAAK,eAAe;AAC7B,UAAI,EAAE,SAAS,kBAAkB,EAAE,cAAc;AAC/C,eAAO,KAAK,CAAC;AAAA,MACf;AACA,UAAI,EAAE,SAAS,WAAW,EAAE,QAAQ;AAClC,gBAAQ,EAAE,MAAM;AAAA,MAClB;AAAA,IAEF;AAAA,EACF;AAEA,UAAQ,MAAM;AACd,SAAO;AACT;AAMO,SAAS,6BAA6B,QAAsC;AACjF,SAAO,oBAAoB,QAAQ,YAAY,YAAY;AAC7D;AAKO,SAAS,8BAA8B,QAAsC;AAClF,QAAM,SAAwB,CAAC;AAE/B,WAAS,QAAQ,eAAoC;AACnD,eAAW,KAAK,eAAe;AAC7B,UAAI,EAAE,SAAS,UAAU,EAAE,UAAU,EAAE,OAAO,SAAS,GAAG;AACxD,eAAO,KAAK,CAAC;AAAA,MACf;AACA,UAAI,EAAE,SAAS,WAAW,EAAE,QAAQ;AAClC,gBAAQ,EAAE,MAAM;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAEA,UAAQ,MAAM;AACd,SAAO;AACT;AAKO,SAAS,oBACd,QACgD;AAChD,QAAM,SAAyD,CAAC;AAEhE,QAAM,aAAa,8BAA8B,MAAM;AACvD,aAAW,UAAU,YAAY;AAC/B,QAAI,OAAO,QAAQ;AACjB,iBAAW,UAAU,OAAO,QAAQ;AAClC,YAAI,OAAO,SAAS,UAAU,OAAO,UAAU,OAAO,OAAO,SAAS,GAAG;AACvE,iBAAO,KAAK,EAAE,QAAQ,OAAO,CAAC;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AASA,IAAM,gBAA6B;AAAA,EACjC,MAAM;AAAA,EACN,MAAM;AAAA,EACN,YAAY;AACd;AAKO,SAAS,cAAc,QAAsC;AAClE,QAAM,aAAa,OAAO,KAAK,CAAC,MAAM,EAAE,cAAc,EAAE,SAAS,IAAI;AACrE,MAAI,YAAY;AACd,WAAO;AAAA,EACT;AAEA,SAAO,CAAC,eAAe,GAAG,MAAM;AAClC;AAMO,SAAS,cAAc,QAAsC;AAElE,QAAM,eAAe,cAAc,MAAM;AACzC,SAAO,4BAA4B,YAAY;AACjD;AAKA,SAAS,4BAA4B,QAAsC;AACzE,QAAM,YAA2B,CAAC;AAElC,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,WAAW,MAAM,QAAQ;AAC1C,gBAAU,KAAK,GAAG,4BAA4B,MAAM,MAAM,CAAC;AAAA,IAC7D,WAAW,MAAM,SAAS,UAAU,MAAM,MAAM;AAC9C,iBAAW,OAAO,MAAM,MAAM;AAC5B,YAAI,IAAI,QAAQ;AACd,oBAAU,KAAK,GAAG,4BAA4B,IAAI,MAAM,CAAC;AAAA,QAC3D;AAAA,MACF;AAAA,IACF,OAAO;AACL,gBAAU,KAAK,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,SAAO;AACT;AAUO,SAAS,iBAAiB,QAAiC;AAChE,QAAM,YAAyB,CAAC;AAEhC,MAAI,OAAO,OAAO;AAChB,eAAW,QAAQ,OAAO,OAAO;AAC/B,iBAAW,SAAS,KAAK,QAAQ;AAE/B,YAAI,MAAM,SAAS,WAAW,MAAM,QAAQ;AAE1C,qBAAW,eAAe,MAAM,QAAQ;AACtC,sBAAU,KAAK;AAAA,cACb,GAAG;AAAA,cACH,WAAW,YAAY,aAAa,MAAM;AAAA,YAC5C,CAAC;AAAA,UACH;AAAA,QACF,OAAO;AACL,oBAAU,KAAK,KAAK;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AAAA,EACF,WAAW,OAAO,QAAQ;AACxB,eAAW,SAAS,OAAO,QAAQ;AAEjC,UAAI,MAAM,SAAS,WAAW,MAAM,QAAQ;AAE1C,mBAAW,eAAe,MAAM,QAAQ;AACtC,oBAAU,KAAK;AAAA,YACb,GAAG;AAAA,YACH,WAAW,YAAY,aAAa,MAAM;AAAA,UAC5C,CAAC;AAAA,QACH;AAAA,MACF,OAAO;AACL,kBAAU,KAAK,KAAK;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,gBAAgB,QAA6B;AAC3D,SAAO,MAAM,QAAQ,OAAO,KAAK,KAAK,OAAO,MAAM,SAAS;AAC9D;AA+BO,SAAS,cAAc,QAAsC;AAClE,QAAM,aAAa,oBAAI,IAAY;AACnC,MAAI,UAAU;AACd,MAAI,gBAAgB;AAEpB,aAAW,QAAQ,CAAC,UAAU;AAC5B,eAAW,IAAI,MAAM,IAAI;AACzB,QAAI,MAAM,SAAS,UAAU,MAAM,SAAS;AAC1C,gBAAU;AAAA,IACZ;AAAA,EACF,CAAC;AAGD,QAAM,aAAa,8BAA8B,MAAM;AACvD,aAAW,aAAa,YAAY;AAClC,QAAI,UAAU,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,GAAG;AACpD,sBAAgB;AAChB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,YAAY,WAAW,IAAI,YAAY,OAAO;AAAA,IAC9C,UAAU,WAAW,IAAI,YAAY,KAAK;AAAA,IAC1C,UAAU,WAAW,IAAI,YAAY,KAAK;AAAA,IAC1C,UAAU,WAAW,IAAI,YAAY,KAAK;AAAA,IAC1C,SAAS,WAAW,IAAI,YAAY,IAAI;AAAA,IACxC,SAAS,WAAW,IAAI,YAAY,IAAI;AAAA,IACxC;AAAA,IACA,WAAW,WAAW,IAAI,YAAY,MAAM;AAAA,IAC5C,aAAa,WAAW,IAAI,YAAY,QAAQ;AAAA,IAChD,aAAa,WAAW,IAAI,YAAY,IAAI;AAAA,IAC5C,cAAc,WAAW,IAAI,YAAY,SAAS;AAAA,IAClD;AAAA,IACA,iBAAiB,WAAW,IAAI,YAAY,YAAY;AAAA,IACxD,eAAe,oBAAoB,MAAM,EAAE,SAAS;AAAA,IACpD;AAAA,EACF;AACF;;;AC/bA,SAAS,WAAW,WAA4B;AAC9C,QAAM,cAAc,CAAC,OAAO,QAAQ,QAAQ,WAAW,UAAU,QAAQ,WAAW;AACpF,QAAM,YAAY,UAAU,YAAY;AACxC,SAAO,YAAY,KAAK,CAAC,YAAY,UAAU,SAAS,OAAO,CAAC;AAClE;AAQO,SAAS,cAAc,OAAoB,iBAAsC;AACtF,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,sBAAgB,IAAI,QAAQ;AAC5B,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAEH,UAAI,WAAW,MAAM,IAAI,KAAK,CAAC,MAAM,QAAQ;AAC3C,wBAAgB,IAAI,MAAM;AAC1B,eAAO;AAAA,MACT;AACA,sBAAgB,IAAI,SAAS;AAC7B,aAAO,MAAM,SACT,qBAAqB,MAAM,MAAM,QACjC,qBAAqB,iBAAiB,cAAc;AAAA,IAC1D,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAEH,sBAAgB,IAAI,MAAM;AAC1B,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,sBAAgB,IAAI,MAAM;AAC1B,aAAO;AAAA,IACT,KAAK;AACH,sBAAgB,IAAI,SAAS;AAC7B,aAAO;AAAA,IACT,KAAK;AACH,sBAAgB,IAAI,SAAS;AAC7B,UAAI,MAAM,aAAa,MAAM,OAAO;AAClC,eAAO,wBAAwB,MAAM,SAAS,YAAY,MAAM,KAAK;AAAA,MACvE;AACA,aAAO,wBAAwB,iBAAiB,iBAAiB,YAAY,iBAAiB,aAAa;AAAA,IAC7G,KAAK;AACH,sBAAgB,IAAI,SAAS;AAC7B,aAAO;AAAA,IACT,KAAK;AACH,sBAAgB,IAAI,WAAW;AAC/B,aAAO;AAAA,IACT,KAAK;AACH,sBAAgB,IAAI,MAAM;AAC1B,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,sBAAgB,IAAI,SAAS;AAC7B,aAAO,MAAM,SACT,qBAAqB,MAAM,MAAM,QACjC,qBAAqB,iBAAiB,cAAc;AAAA,IAC1D,KAAK;AACH,sBAAgB,IAAI,OAAO;AAC3B,aAAO;AAAA,IACT,KAAK;AACH,sBAAgB,IAAI,OAAO;AAE3B,UAAI,MAAM,UAAU,MAAM,OAAO,SAAS,GAAG;AAC3C,cAAM,aAAa,oBAAoB,MAAM,MAAM;AACnD,eAAO,yBAAyB,UAAU;AAAA,MAC5C;AACA,aAAO;AAAA,IACT,KAAK;AAEH,sBAAgB,IAAI,SAAS;AAC7B,aAAO;AAAA,IACT;AACE,sBAAgB,IAAI,MAAM;AAC1B,aAAO;AAAA,EACX;AACF;AAKA,SAAS,oBAAoB,QAA+B;AAC1D,SAAO,OACJ,QAAQ,CAAC,MAAM;AACd,QAAI;AACJ,QAAI,EAAE,SAAS,UAAU,EAAE,UAAU,EAAE,OAAO,SAAS,GAAG;AAExD,YAAM,YAAY,EAAE,OACjB,IAAI,CAAC,OAAO;AACX,YAAI;AACJ,YAAI,GAAG,SAAS,WAAW;AACzB,mBAAS;AAAA,QACX,WAAW,GAAG,SAAS,YAAY,GAAG,SAAS,WAAW;AACxD,mBAAS;AAAA,QACX,OAAO;AACL,mBAAS;AAAA,QACX;AACA,eAAO,GAAG,kBAAkB,GAAG,IAAI,CAAC,MAAM,MAAM;AAAA,MAClD,CAAC,EACA,KAAK,IAAI;AACZ,aAAO,WAAW,SAAS;AAAA,IAC7B,WAAW,EAAE,SAAS,QAAQ;AAC5B,aAAO;AAAA,IACT,WAAW,EAAE,SAAS,YAAY,EAAE,SAAS,WAAW;AACtD,aAAO;AAAA,IACT,WAAW,EAAE,SAAS,WAAW;AAC/B,aAAO;AAAA,IACT,OAAO;AACL,aAAO;AAAA,IACT;AACA,UAAM,SAAS,CAAC,GAAG,kBAAkB,EAAE,IAAI,CAAC,MAAM,IAAI,EAAE;AAExD,QAAI,EAAE,SAAS;AACb,aAAO,KAAK,GAAG,kBAAkB,GAAG,EAAE,IAAI,MAAM,CAAC,WAAW;AAAA,IAC9D;AACA,WAAO;AAAA,EACT,CAAC,EACA,KAAK,IAAI;AACd;AAWO,SAAS,UAAU,OAA4B;AACpD,QAAM,QAAQ,MAAM,SAAS,MAAM;AAEnC,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,MAAM,WACT,wBAAwB,KAAK,qBAC7B;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,YAAY;AACf,UAAI,MAAM,KAAK,YAAY,EAAE,SAAS,OAAO,GAAG;AAC9C,cAAMA,QAAO,MAAM,WACf,sBAAsB,KAAK,+DAC3B;AACJ,eAAO,MAAM,SAAS,GAAGA,KAAI,QAAQ,MAAM,MAAM,MAAMA;AAAA,MACzD;AACA,YAAM,OAAO,MAAM,WAAW,sBAAsB,KAAK,mBAAmB;AAC5E,aAAO,MAAM,SAAS,GAAG,IAAI,QAAQ,MAAM,MAAM,MAAM;AAAA,IACzD;AAAA,IACA,KAAK;AACH,UAAI,CAAC,MAAM,UAAU;AACnB,eAAO;AAAA,MACT;AACA,aAAO,sBAAsB,KAAK;AAAA,IACpC,KAAK;AACH,aAAO,MAAM,WAAW,sBAAsB,KAAK,mBAAmB;AAAA,IACxE,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,SAAS;AACZ,UAAI,CAAC,MAAM,UAAU;AACnB,eAAO;AAAA,MACT;AACA,YAAM,YACJ,MAAM,SAAS,UAAU,aAAa,MAAM,SAAS,UAAU,YAAY;AAC7E,YAAM,OAAO,oCAAoC,SAAS,QAAQ,KAAK,kCAAkC,MAAM,IAAI;AACnH,aAAO,MAAM,SAAS,GAAG,IAAI,QAAQ,MAAM,MAAM,MAAM;AAAA,IACzD;AAAA,IACA,KAAK;AACH,aAAO,iBAAiB,OAAO,KAAK;AAAA,IACtC,KAAK,UAAU;AACb,UAAI,MAAM,WAAW,MAAM,QAAQ,SAAS,GAAG;AAC7C,cAAM,SAAS,MAAM,QAAQ,IAAI,CAAC,QAAQ,IAAI,IAAI,KAAK,GAAG,EAAE,KAAK,IAAI;AACrE,cAAM,cAAc,IAAI,MAAM;AAC9B,eAAO,MAAM,WACT,sBAAsB,KAAK,mCAAmC,WAAW,6DAA6D,KAAK,SAC3I,uCAAuC,WAAW,6DAA6D,KAAK;AAAA,MAC1H;AACA,aAAO,MAAM,WAAW,sBAAsB,KAAK,mBAAmB;AAAA,IACxE;AAAA,IACA,KAAK;AACH,aAAO,MAAM,WAAW,sBAAsB,KAAK,mBAAmB;AAAA,IACxE,KAAK,gBAAgB;AACnB,UAAI,MAAM,UAAU;AAClB,eAAO,MAAM,WACT,+BAA+B,KAAK,mBACpC;AAAA,MACN;AACA,aAAO,MAAM,WAAW,sBAAsB,KAAK,mBAAmB;AAAA,IACxE;AAAA,IACA,KAAK;AAEH,aAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiBT;AACE,aAAO,MAAM,WAAW,sBAAsB,KAAK,mBAAmB;AAAA,EAC1E;AACF;AAKA,SAAS,iBAAiB,OAAoB,OAAuB;AAEnE,MAAI,MAAM,UAAU,MAAM,OAAO,SAAS,GAAG;AAC3C,UAAM,eAAe,MAAM,OACxB,QAAQ,CAAC,gBAAgB;AACxB,YAAM,OAAiB,CAAC;AACxB,YAAM,gBAAgB,UAAU,WAAW;AAC3C,YAAM,kBAAkB,cAAc,SAAS,aAAa;AAC5D,UAAI,YAAY,OAAO,kBAAkB,YAAY,IAAI,CAAC,KAAK,aAAa;AAC5E,UAAI,CAAC,YAAY,YAAY,CAAC,iBAAiB;AAC7C,qBAAa;AAAA,MACf;AACA,WAAK,KAAK,SAAS;AAEnB,UAAI,YAAY,SAAS;AACvB,aAAK,KAAK,OAAO,kBAAkB,GAAG,YAAY,IAAI,MAAM,CAAC,yBAAyB;AAAA,MACxF;AACA,aAAO;AAAA,IACT,CAAC,EACA,KAAK,KAAK;AACb,UAAM,eAAe;AAAA,EAAe,YAAY;AAAA;AAChD,UAAM,cAAc,MAAM,WACtB,WAAW,YAAY,SAAS,MAAM,QAAQ,MAAM,KAAK,kBAAkB,MAAM,QAAQ,aACzF,WAAW,YAAY;AAC3B,WAAO,MAAM,WACT,GAAG,WAAW,YAAY,KAAK,mCAC/B,GAAG,WAAW;AAAA,EACpB;AAEA,MAAI,MAAM,OAAO,SAAS,YAAY,MAAM,OAAO,SAAS,WAAW;AACrE,UAAM,aAAa,MAAM,MAAM,SAAS,kBAAkB,MAAM,MAAM,MAAM,MAAM;AAClF,UAAM,cAAc,MAAM,WACtB,WAAW,UAAU,SAAS,MAAM,QAAQ,MAAM,KAAK,kBAAkB,MAAM,QAAQ,aACvF,WAAW,UAAU;AACzB,WAAO,MAAM,WACT,GAAG,WAAW,YAAY,KAAK,mCAC/B,GAAG,WAAW;AAAA,EACpB;AACA,SAAO,MAAM,WACT,+BAA+B,KAAK,mCACpC;AACN;AAYO,SAAS,iBAAiB,OAAoB,OAA2B,UAAkB;AAChG,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAGH,UAAI,SAAS,SAAS;AACpB,eAAO,MAAM,WAAW,aAAa;AAAA,MACvC;AACA,UAAI,MAAM,cAAc;AACtB,cAAM,uBAAuB,YAAY,MAAM,YAAY;AAC3D,cAAM,qBAAqB,aAAa,oBAAoB;AAC5D,eAAO,MAAM,WAAW,GAAG,kBAAkB,WAAW,GAAG,kBAAkB;AAAA,MAC/E;AACA,aAAO;AAAA,IACT,KAAK;AACH,UAAI,MAAM,UAAU,MAAM,OAAO,SAAS,GAAG;AAC3C,cAAM,aAAa,MAAM,OACtB,QAAQ,CAAC,MAAM;AAEd,gBAAM,OAAO,iBAAiB,GAAG,OAAO;AACxC,gBAAM,SAAS,CAAC,GAAG,kBAAkB,EAAE,IAAI,CAAC,MAAM,IAAI,EAAE;AACxD,cAAI,EAAE,SAAS;AACb,mBAAO,KAAK,GAAG,kBAAkB,GAAG,EAAE,IAAI,MAAM,CAAC,WAAW;AAAA,UAC9D;AACA,iBAAO;AAAA,QACT,CAAC,EACA,KAAK,IAAI;AACZ,eAAO,WAAW,UAAU;AAAA,MAC9B;AACA,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAWO,SAAS,gBAAgB,OAA4B;AAC1D,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAYO,SAAS,uBAAuB,OAAkB,iBAAsC;AAC7F,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,sBAAgB,IAAI,SAAS;AAC7B,aAAO,MAAM,YACT,qBAAqB,MAAM,SAAS,QACpC,qBAAqB,iBAAiB,cAAc;AAAA,IAC1D,KAAK;AACH,sBAAgB,IAAI,MAAM;AAC1B,aAAO;AAAA,IACT,KAAK;AACH,sBAAgB,IAAI,SAAS;AAC7B,aAAO,qBAAqB,iBAAiB,cAAc;AAAA,IAC7D,KAAK;AACH,sBAAgB,IAAI,SAAS;AAC7B,aAAO;AAAA,IACT,KAAK;AACH,sBAAgB,IAAI,SAAS;AAC7B,aAAO;AAAA,IACT,KAAK;AACH,sBAAgB,IAAI,SAAS;AAC7B,aAAO;AAAA,IACT,KAAK;AACH,sBAAgB,IAAI,MAAM;AAC1B,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,sBAAgB,IAAI,SAAS;AAC7B,aAAO,qBAAqB,iBAAiB,cAAc;AAAA,IAC7D,KAAK;AACH,sBAAgB,IAAI,SAAS;AAC7B,aAAO;AAAA,IACT,KAAK;AACH,sBAAgB,IAAI,OAAO;AAC3B,aAAO;AAAA,IACT,KAAK;AACH,sBAAgB,IAAI,OAAO;AAC3B,UAAI,MAAM,UAAU,MAAM,OAAO,SAAS,GAAG;AAC3C,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,sBAAgB,IAAI,MAAM;AAC1B,aAAO;AAAA,IACT;AACE,sBAAgB,IAAI,MAAM;AAC1B,aAAO;AAAA,EACX;AACF;AAiBO,SAAS,mBAAmB,OAAkB,UAA+B,CAAC,GAAW;AAC9F,QAAM,QAAQ,MAAM;AACpB,QAAM,aAAa,MAAM,YAAY,CAAC,QAAQ;AAE9C,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK,QAAQ;AACX,UAAI,UAAU,aAAa,sBAAsB,KAAK,mBAAmB;AACzE,UAAI,MAAM,WAAW;AACnB,mBAAW,QAAQ,MAAM,SAAS,MAAM,KAAK,qBAAqB,MAAM,SAAS;AAAA,MACnF;AACA,UAAI,MAAM,WAAW;AACnB,mBAAW,QAAQ,MAAM,SAAS,MAAM,KAAK,oBAAoB,MAAM,SAAS;AAAA,MAClF;AACA,UAAI,MAAM,SAAS;AACjB,mBAAW,sBAAsB,MAAM,OAAO,gBAAgB,KAAK;AAAA,MACrE;AACA,aAAO,aAAa,UAAU,GAAG,OAAO;AAAA,IAC1C;AAAA,IACA,KAAK,YAAY;AACf,UAAI,UAAU,aAAa,sBAAsB,KAAK,mBAAmB;AACzE,UAAI,MAAM,WAAW;AACnB,mBAAW,QAAQ,MAAM,SAAS,MAAM,KAAK,qBAAqB,MAAM,SAAS;AAAA,MACnF;AACA,UAAI,MAAM,WAAW;AACnB,mBAAW,QAAQ,MAAM,SAAS,MAAM,KAAK,oBAAoB,MAAM,SAAS;AAAA,MAClF;AACA,aAAO,aAAa,UAAU,GAAG,OAAO;AAAA,IAC1C;AAAA,IACA,KAAK;AACH,aAAO,aACH,sBAAsB,KAAK,+DAC3B;AAAA,IACN,KAAK,SAAS;AACZ,YAAM,UACJ,MAAM,WAAW;AACnB,aAAO,aACH,sBAAsB,KAAK,oCAAoC,OAAO,6CACtE,kFAAkF,OAAO;AAAA,IAC/F;AAAA,IACA,KAAK,UAAU;AACb,UAAI,UAAU,aAAa,wBAAwB,KAAK,qBAAqB;AAC7E,UAAI,MAAM,QAAQ,QAAW;AAC3B,mBAAW,QAAQ,MAAM,GAAG,MAAM,KAAK,qBAAqB,MAAM,GAAG;AAAA,MACvE;AACA,UAAI,MAAM,QAAQ,QAAW;AAC3B,mBAAW,QAAQ,MAAM,GAAG,MAAM,KAAK,oBAAoB,MAAM,GAAG;AAAA,MACtE;AACA,aAAO,aAAa,UAAU,GAAG,OAAO;AAAA,IAC1C;AAAA,IACA,KAAK;AACH,aAAO,aACH,sBAAsB,KAAK,mDAC3B;AAAA,IACN,KAAK;AACH,aAAO,aACH,sBAAsB,KAAK,mBAC3B;AAAA,IACN,KAAK;AAAA,IACL,KAAK;AACH,UAAI,MAAM,WAAW,MAAM,QAAQ,SAAS,GAAG;AAC7C,cAAM,SAAS,MAAM,QAAQ,IAAI,CAAC,QAAQ,IAAI,IAAI,KAAK,GAAG,EAAE,KAAK,IAAI;AACrE,eAAO,aACH,WAAW,MAAM,kBAAkB,KAAK,qBACxC,WAAW,MAAM;AAAA,MACvB;AACA,aAAO,aAAa,sBAAsB,KAAK,mBAAmB;AAAA,IACpE,KAAK;AACH,aAAO,aACH,+BAA+B,KAAK,qBACpC;AAAA,IACN,KAAK;AACH,aAAO,aACH,+BAA+B,KAAK,mBACpC;AAAA,IACN,KAAK;AACH,aAAO,aAAa,sBAAsB,KAAK,mBAAmB;AAAA,IACpE,KAAK;AACH,UAAI,MAAM,UAAU,MAAM,OAAO,SAAS,GAAG;AAC3C,cAAM,eAAe,MAAM,OACxB,IAAI,CAAC,MAAM,GAAG,EAAE,IAAI,KAAK,mBAAmB,GAAG,OAAO,CAAC,EAAE,EACzD,KAAK,IAAI;AACZ,eAAO,aACH,sBAAsB,YAAY,gBAAgB,KAAK,mBACvD,sBAAsB,YAAY;AAAA,MACxC;AACA,aAAO,aACH,+BAA+B,KAAK,mBACpC;AAAA,IACN,KAAK;AAAA,IACL,KAAK;AACH,aAAO,aAAa,sBAAsB,KAAK,mBAAmB;AAAA,IACpE;AACE,aAAO,aAAa,sBAAsB,KAAK,mBAAmB;AAAA,EACtE;AACF;AAWO,SAAS,UAAU,OAA4B;AACpD,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO,MAAM,SACT,WAAW,MAAM,MAAM,MACvB,WAAW,iBAAiB,cAAc;AAAA,IAChD,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,WAAW,MAAM,aAAa,iBAAiB,iBAAiB,KAAK,MAAM,SAAS,iBAAiB,aAAa;AAAA,IAC3H,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,WAAW,iBAAiB,cAAc;AAAA,IACnD,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;","names":["base"]}
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { U as UserConfig, B as BetterstartConfig, R as ResolvedPaths, l as ResolvedConfig, I as ImportPaths } from './types-eI549DEG.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Configuration loader for @betterstart/cli
|
|
5
|
-
* Handles loading, merging, and resolving configuration
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Supported configuration file names (in priority order)
|
|
10
|
-
*/
|
|
11
|
-
declare const CONFIG_FILE_NAMES: string[];
|
|
12
|
-
/**
|
|
13
|
-
* Find the configuration file in a directory
|
|
14
|
-
* @param cwd - Directory to search in
|
|
15
|
-
* @returns Path to the config file or undefined if not found
|
|
16
|
-
*/
|
|
17
|
-
declare function findConfigFile(cwd: string): string | undefined;
|
|
18
|
-
/**
|
|
19
|
-
* Load configuration from a file
|
|
20
|
-
* @param configPath - Path to the configuration file
|
|
21
|
-
* @returns The loaded configuration
|
|
22
|
-
*/
|
|
23
|
-
declare function loadConfigFile(configPath: string): Promise<UserConfig>;
|
|
24
|
-
/**
|
|
25
|
-
* Load configuration from a directory
|
|
26
|
-
* Automatically finds and loads the config file, or uses defaults
|
|
27
|
-
*
|
|
28
|
-
* @param cwd - Directory to load config from (defaults to process.cwd())
|
|
29
|
-
* @param presetName - Optional preset name to use as base
|
|
30
|
-
* @returns The loaded and merged configuration
|
|
31
|
-
*/
|
|
32
|
-
declare function loadConfig(cwd?: string, presetName?: string): Promise<BetterstartConfig>;
|
|
33
|
-
/**
|
|
34
|
-
* Find the project root directory
|
|
35
|
-
* Looks for common root indicators (package.json, pnpm-workspace.yaml, turbo.json)
|
|
36
|
-
*
|
|
37
|
-
* @param startDir - Directory to start searching from
|
|
38
|
-
* @returns The project root directory
|
|
39
|
-
*/
|
|
40
|
-
declare function findProjectRoot(startDir: string): string;
|
|
41
|
-
/**
|
|
42
|
-
* Resolve configuration paths to absolute paths
|
|
43
|
-
*
|
|
44
|
-
* @param config - The configuration to resolve
|
|
45
|
-
* @param projectRoot - The project root directory
|
|
46
|
-
* @returns Configuration with resolved absolute paths
|
|
47
|
-
*/
|
|
48
|
-
declare function resolvePaths(config: BetterstartConfig, projectRoot: string): ResolvedPaths;
|
|
49
|
-
/**
|
|
50
|
-
* Fully resolve configuration including paths
|
|
51
|
-
*
|
|
52
|
-
* @param config - The configuration to resolve
|
|
53
|
-
* @param projectRoot - The project root directory (optional, auto-detected if not provided)
|
|
54
|
-
* @returns Fully resolved configuration
|
|
55
|
-
*/
|
|
56
|
-
declare function resolveConfig(config: BetterstartConfig, projectRoot?: string): ResolvedConfig;
|
|
57
|
-
/**
|
|
58
|
-
* Helper function for defining configuration in betterstart.config.ts
|
|
59
|
-
* Provides type checking and autocomplete
|
|
60
|
-
*
|
|
61
|
-
* @example
|
|
62
|
-
* ```ts
|
|
63
|
-
* // betterstart.config.ts
|
|
64
|
-
* import { defineConfig } from '@betterstart/cli'
|
|
65
|
-
*
|
|
66
|
-
* export default defineConfig({
|
|
67
|
-
* paths: {
|
|
68
|
-
* app: 'apps/web',
|
|
69
|
-
* database: 'packages/database'
|
|
70
|
-
* }
|
|
71
|
-
* })
|
|
72
|
-
* ```
|
|
73
|
-
*/
|
|
74
|
-
declare function defineConfig(config: UserConfig): UserConfig;
|
|
75
|
-
/**
|
|
76
|
-
* Validate a configuration
|
|
77
|
-
* @param config - The configuration to validate
|
|
78
|
-
* @returns Array of validation errors (empty if valid)
|
|
79
|
-
*/
|
|
80
|
-
declare function validateConfig(config: BetterstartConfig): string[];
|
|
81
|
-
/**
|
|
82
|
-
* Check if resolved paths exist and are accessible
|
|
83
|
-
* @param paths - The resolved paths to check
|
|
84
|
-
* @returns Object with path existence status
|
|
85
|
-
*/
|
|
86
|
-
declare function checkPaths(paths: ResolvedPaths): Record<keyof ResolvedPaths, boolean>;
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Resolves import paths from config for use in generated code.
|
|
90
|
-
* All generators should use this instead of hardcoding import paths.
|
|
91
|
-
*/
|
|
92
|
-
declare class ImportResolver {
|
|
93
|
-
private readonly imports;
|
|
94
|
-
constructor(imports: ImportPaths);
|
|
95
|
-
/** Import path for database package (db instance, table schemas) */
|
|
96
|
-
get database(): string;
|
|
97
|
-
/** Import path for admin UI components */
|
|
98
|
-
get adminUi(): string;
|
|
99
|
-
/** Import path for public/web UI components */
|
|
100
|
-
get webUi(): string;
|
|
101
|
-
/** Import path for React Query hooks */
|
|
102
|
-
get hooks(): string;
|
|
103
|
-
/** Import path for utility functions (cn, truncate, hexToOklab) */
|
|
104
|
-
get utils(): string;
|
|
105
|
-
/** Import path for lib base (renderMarkdownInline, etc.) */
|
|
106
|
-
get lib(): string;
|
|
107
|
-
/** Import path for lib/markdown sub-module */
|
|
108
|
-
get libMarkdown(): string;
|
|
109
|
-
/** Import path for table-meta type augmentation */
|
|
110
|
-
get tableMeta(): string;
|
|
111
|
-
/**
|
|
112
|
-
* Resolve the import path for a schema's server actions.
|
|
113
|
-
* Replaces `{name}` placeholder with the actual schema name.
|
|
114
|
-
*/
|
|
115
|
-
actions(schemaName: string): string;
|
|
116
|
-
/**
|
|
117
|
-
* Get the escaped lib import path for use in regex matching.
|
|
118
|
-
* Used by hook.ts to update existing hook files.
|
|
119
|
-
*/
|
|
120
|
-
get libEscaped(): string;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export { CONFIG_FILE_NAMES as C, ImportResolver as I, loadConfig as a, findProjectRoot as b, resolveConfig as c, defineConfig as d, checkPaths as e, findConfigFile as f, loadConfigFile as l, resolvePaths as r, validateConfig as v };
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Logger abstraction for the codegen package
|
|
3
|
-
* Replaces direct console.log calls to support library usage and testing
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Log levels
|
|
7
|
-
*/
|
|
8
|
-
type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
|
|
9
|
-
/**
|
|
10
|
-
* Logger interface
|
|
11
|
-
*/
|
|
12
|
-
interface Logger {
|
|
13
|
-
debug(message: string, ...args: unknown[]): void;
|
|
14
|
-
info(message: string, ...args: unknown[]): void;
|
|
15
|
-
warn(message: string, ...args: unknown[]): void;
|
|
16
|
-
error(message: string, ...args: unknown[]): void;
|
|
17
|
-
success(message: string, ...args: unknown[]): void;
|
|
18
|
-
/**
|
|
19
|
-
* Log a step in a process (e.g., "1️⃣ Generating database schema...")
|
|
20
|
-
*/
|
|
21
|
-
step(stepNumber: number, message: string): void;
|
|
22
|
-
/**
|
|
23
|
-
* Log a completed step
|
|
24
|
-
*/
|
|
25
|
-
stepComplete(message: string): void;
|
|
26
|
-
/**
|
|
27
|
-
* Set the log level
|
|
28
|
-
*/
|
|
29
|
-
setLevel(level: LogLevel): void;
|
|
30
|
-
/**
|
|
31
|
-
* Get the current log level
|
|
32
|
-
*/
|
|
33
|
-
getLevel(): LogLevel;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Buffered logger that stores log messages for later retrieval
|
|
37
|
-
*/
|
|
38
|
-
interface LogEntry {
|
|
39
|
-
level: LogLevel | 'success' | 'step' | 'stepComplete';
|
|
40
|
-
message: string;
|
|
41
|
-
args: unknown[];
|
|
42
|
-
timestamp: Date;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Create a console logger
|
|
46
|
-
*/
|
|
47
|
-
declare function createConsoleLogger(level?: LogLevel): Logger;
|
|
48
|
-
/**
|
|
49
|
-
* Create a silent logger (for testing or library usage)
|
|
50
|
-
*/
|
|
51
|
-
declare function createSilentLogger(): Logger;
|
|
52
|
-
/**
|
|
53
|
-
* Create a buffered logger (for testing)
|
|
54
|
-
*/
|
|
55
|
-
declare function createBufferedLogger(level?: LogLevel): Logger & {
|
|
56
|
-
getEntries(): LogEntry[];
|
|
57
|
-
clear(): void;
|
|
58
|
-
};
|
|
59
|
-
/**
|
|
60
|
-
* Get the global logger
|
|
61
|
-
*/
|
|
62
|
-
declare function getLogger(): Logger;
|
|
63
|
-
/**
|
|
64
|
-
* Set the global logger
|
|
65
|
-
*/
|
|
66
|
-
declare function setLogger(logger: Logger): void;
|
|
67
|
-
/**
|
|
68
|
-
* Reset the global logger to the default console logger
|
|
69
|
-
*/
|
|
70
|
-
declare function resetLogger(): void;
|
|
71
|
-
declare const logger: {
|
|
72
|
-
readonly debug: (message: string, ...args: unknown[]) => void;
|
|
73
|
-
readonly info: (message: string, ...args: unknown[]) => void;
|
|
74
|
-
readonly warn: (message: string, ...args: unknown[]) => void;
|
|
75
|
-
readonly error: (message: string, ...args: unknown[]) => void;
|
|
76
|
-
readonly success: (message: string, ...args: unknown[]) => void;
|
|
77
|
-
readonly step: (stepNumber: number, message: string) => void;
|
|
78
|
-
readonly stepComplete: (message: string) => void;
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
export { type LogLevel as L, type Logger as a, type LogEntry as b, createConsoleLogger as c, createSilentLogger as d, createBufferedLogger as e, getLogger as g, logger as l, resetLogger as r, setLogger as s };
|
package/dist/plugins/index.d.ts
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import { j as BetterstartPlugin, g as PluginContext, h as GeneratedFile, C as CustomGenerator, F as FieldTypeHandler, i as PluginCommand } from '../types-eI549DEG.js';
|
|
2
|
-
export { f as PluginHooks } from '../types-eI549DEG.js';
|
|
3
|
-
import '../logger-awLb347n.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Plugin manager for @betterstart/cli
|
|
7
|
-
* Handles plugin registration, lifecycle, and execution
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Plugin manager for handling plugin lifecycle and registration
|
|
12
|
-
*/
|
|
13
|
-
declare class PluginManager {
|
|
14
|
-
private plugins;
|
|
15
|
-
private initialized;
|
|
16
|
-
/**
|
|
17
|
-
* Register a plugin
|
|
18
|
-
*/
|
|
19
|
-
register(plugin: BetterstartPlugin): void;
|
|
20
|
-
/**
|
|
21
|
-
* Register multiple plugins
|
|
22
|
-
*/
|
|
23
|
-
registerAll(plugins: BetterstartPlugin[]): void;
|
|
24
|
-
/**
|
|
25
|
-
* Unregister a plugin
|
|
26
|
-
*/
|
|
27
|
-
unregister(pluginName: string): boolean;
|
|
28
|
-
/**
|
|
29
|
-
* Get a registered plugin by name
|
|
30
|
-
*/
|
|
31
|
-
get(pluginName: string): BetterstartPlugin | undefined;
|
|
32
|
-
/**
|
|
33
|
-
* Get all registered plugins
|
|
34
|
-
*/
|
|
35
|
-
getAll(): BetterstartPlugin[];
|
|
36
|
-
/**
|
|
37
|
-
* Check if a plugin is registered
|
|
38
|
-
*/
|
|
39
|
-
has(pluginName: string): boolean;
|
|
40
|
-
/**
|
|
41
|
-
* Initialize all plugins
|
|
42
|
-
*/
|
|
43
|
-
initialize(context: PluginContext): Promise<void>;
|
|
44
|
-
/**
|
|
45
|
-
* Run beforeGenerate hooks on all plugins
|
|
46
|
-
*/
|
|
47
|
-
runBeforeGenerate(context: PluginContext, schema: unknown): Promise<void>;
|
|
48
|
-
/**
|
|
49
|
-
* Run afterGenerate hooks on all plugins
|
|
50
|
-
*/
|
|
51
|
-
runAfterGenerate(context: PluginContext, files: GeneratedFile[]): Promise<void>;
|
|
52
|
-
/**
|
|
53
|
-
* Get a generator by name from any registered plugin
|
|
54
|
-
*/
|
|
55
|
-
getGenerator(name: string): CustomGenerator | undefined;
|
|
56
|
-
/**
|
|
57
|
-
* Get all generators from all plugins
|
|
58
|
-
*/
|
|
59
|
-
getAllGenerators(): Map<string, {
|
|
60
|
-
plugin: string;
|
|
61
|
-
generator: CustomGenerator;
|
|
62
|
-
}>;
|
|
63
|
-
/**
|
|
64
|
-
* Get all generator names
|
|
65
|
-
*/
|
|
66
|
-
getGeneratorNames(): string[];
|
|
67
|
-
/**
|
|
68
|
-
* Get a field type handler by name from any registered plugin
|
|
69
|
-
*/
|
|
70
|
-
getFieldType(name: string): FieldTypeHandler | undefined;
|
|
71
|
-
/**
|
|
72
|
-
* Get all field types from all plugins
|
|
73
|
-
*/
|
|
74
|
-
getAllFieldTypes(): Map<string, {
|
|
75
|
-
plugin: string;
|
|
76
|
-
handler: FieldTypeHandler;
|
|
77
|
-
}>;
|
|
78
|
-
/**
|
|
79
|
-
* Get all field type names
|
|
80
|
-
*/
|
|
81
|
-
getFieldTypeNames(): string[];
|
|
82
|
-
/**
|
|
83
|
-
* Get a command by name from any registered plugin
|
|
84
|
-
*/
|
|
85
|
-
getCommand(name: string): PluginCommand | undefined;
|
|
86
|
-
/**
|
|
87
|
-
* Get all commands from all plugins
|
|
88
|
-
*/
|
|
89
|
-
getAllCommands(): Map<string, {
|
|
90
|
-
plugin: string;
|
|
91
|
-
command: PluginCommand;
|
|
92
|
-
}>;
|
|
93
|
-
/**
|
|
94
|
-
* Get all command names
|
|
95
|
-
*/
|
|
96
|
-
getCommandNames(): string[];
|
|
97
|
-
/**
|
|
98
|
-
* Get plugin summary
|
|
99
|
-
*/
|
|
100
|
-
getSummary(): PluginSummary;
|
|
101
|
-
/**
|
|
102
|
-
* Clear all registered plugins
|
|
103
|
-
*/
|
|
104
|
-
clear(): void;
|
|
105
|
-
}
|
|
106
|
-
interface PluginInfo {
|
|
107
|
-
name: string;
|
|
108
|
-
version: string;
|
|
109
|
-
description?: string;
|
|
110
|
-
generators: string[];
|
|
111
|
-
fieldTypes: string[];
|
|
112
|
-
commands: string[];
|
|
113
|
-
}
|
|
114
|
-
interface PluginSummary {
|
|
115
|
-
count: number;
|
|
116
|
-
plugins: PluginInfo[];
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Get the global plugin manager instance
|
|
120
|
-
*/
|
|
121
|
-
declare function getPluginManager(): PluginManager;
|
|
122
|
-
/**
|
|
123
|
-
* Create a new plugin manager instance
|
|
124
|
-
*/
|
|
125
|
-
declare function createPluginManager(): PluginManager;
|
|
126
|
-
/**
|
|
127
|
-
* Reset the global plugin manager
|
|
128
|
-
*/
|
|
129
|
-
declare function resetPluginManager(): void;
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Plugin system types for @betterstart/cli
|
|
133
|
-
* Re-exports types from config and adds plugin-specific utilities
|
|
134
|
-
*/
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Events emitted during plugin lifecycle
|
|
138
|
-
*/
|
|
139
|
-
type PluginEvent = 'init' | 'beforeGenerate' | 'afterGenerate' | 'beforeWrite' | 'afterWrite' | 'error';
|
|
140
|
-
/**
|
|
141
|
-
* Event handler type
|
|
142
|
-
*/
|
|
143
|
-
type PluginEventHandler<T = unknown> = (context: PluginContext, data: T) => Promise<void>;
|
|
144
|
-
/**
|
|
145
|
-
* Options for creating a plugin
|
|
146
|
-
*/
|
|
147
|
-
interface CreatePluginOptions {
|
|
148
|
-
name: string;
|
|
149
|
-
version: string;
|
|
150
|
-
description?: string;
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Plugin builder for fluent API
|
|
154
|
-
*/
|
|
155
|
-
interface PluginBuilder {
|
|
156
|
-
/** Add an onInit hook */
|
|
157
|
-
onInit(handler: (context: PluginContext) => Promise<void>): PluginBuilder;
|
|
158
|
-
/** Add an onBeforeGenerate hook */
|
|
159
|
-
onBeforeGenerate(handler: (context: PluginContext, schema: unknown) => Promise<void>): PluginBuilder;
|
|
160
|
-
/** Add an onAfterGenerate hook */
|
|
161
|
-
onAfterGenerate(handler: (context: PluginContext, files: GeneratedFile[]) => Promise<void>): PluginBuilder;
|
|
162
|
-
/** Add a custom generator */
|
|
163
|
-
addGenerator(name: string, description: string, generate: (context: PluginContext, schema: unknown) => Promise<GeneratedFile[]>): PluginBuilder;
|
|
164
|
-
/** Add a custom field type */
|
|
165
|
-
addFieldType(name: string, handler: {
|
|
166
|
-
zodType: (field: unknown) => string;
|
|
167
|
-
drizzleType: (field: unknown, imports: Set<string>) => string;
|
|
168
|
-
typescriptType: (field: unknown, mode: 'input' | 'output') => string;
|
|
169
|
-
formComponent?: (field: unknown) => string;
|
|
170
|
-
}): PluginBuilder;
|
|
171
|
-
/** Add a CLI command */
|
|
172
|
-
addCommand(name: string, description: string, options: Array<{
|
|
173
|
-
flags: string;
|
|
174
|
-
description: string;
|
|
175
|
-
default?: unknown;
|
|
176
|
-
}>, handler: (options: Record<string, unknown>) => Promise<void>): PluginBuilder;
|
|
177
|
-
/** Build the plugin */
|
|
178
|
-
build(): BetterstartPlugin;
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* Create a plugin using the builder pattern
|
|
182
|
-
*/
|
|
183
|
-
declare function createPlugin(options: CreatePluginOptions): PluginBuilder;
|
|
184
|
-
/**
|
|
185
|
-
* Check if a plugin has a specific hook
|
|
186
|
-
*/
|
|
187
|
-
declare function hasHook(plugin: BetterstartPlugin, hook: keyof NonNullable<BetterstartPlugin['hooks']>): boolean;
|
|
188
|
-
/**
|
|
189
|
-
* Check if a plugin provides a specific generator
|
|
190
|
-
*/
|
|
191
|
-
declare function hasGenerator(plugin: BetterstartPlugin, generatorName: string): boolean;
|
|
192
|
-
/**
|
|
193
|
-
* Check if a plugin provides a specific field type
|
|
194
|
-
*/
|
|
195
|
-
declare function hasFieldType(plugin: BetterstartPlugin, fieldTypeName: string): boolean;
|
|
196
|
-
/**
|
|
197
|
-
* Check if a plugin provides a specific command
|
|
198
|
-
*/
|
|
199
|
-
declare function hasCommand(plugin: BetterstartPlugin, commandName: string): boolean;
|
|
200
|
-
/**
|
|
201
|
-
* Get all generator names from a plugin
|
|
202
|
-
*/
|
|
203
|
-
declare function getGeneratorNames(plugin: BetterstartPlugin): string[];
|
|
204
|
-
/**
|
|
205
|
-
* Get all field type names from a plugin
|
|
206
|
-
*/
|
|
207
|
-
declare function getFieldTypeNames(plugin: BetterstartPlugin): string[];
|
|
208
|
-
/**
|
|
209
|
-
* Get all command names from a plugin
|
|
210
|
-
*/
|
|
211
|
-
declare function getCommandNames(plugin: BetterstartPlugin): string[];
|
|
212
|
-
|
|
213
|
-
export { BetterstartPlugin, type CreatePluginOptions, CustomGenerator, FieldTypeHandler, GeneratedFile, type PluginBuilder, PluginCommand, PluginContext, type PluginEvent, type PluginEventHandler, type PluginInfo, PluginManager, type PluginSummary, createPlugin, createPluginManager, getCommandNames, getFieldTypeNames, getGeneratorNames, getPluginManager, hasCommand, hasFieldType, hasGenerator, hasHook, resetPluginManager };
|