Add initial project files

This commit is contained in:
Igor Martyniuk
2026-09-01 13:03:41 +03:00
parent 22e111bb44
commit 74cb5b6176
1841 changed files with 242819 additions and 30 deletions
@@ -0,0 +1,50 @@
import { ModuleFieldOption } from '#services/module_generator/types'
interface FieldOption {
label: string
value: string
}
export interface ComboboxOptionGroup {
label?: string
options: FieldOption[]
}
export interface MultiSelectOptionGroup {
heading: string
options: FieldOption[]
}
export function hasGroupedOptions(options: ModuleFieldOption[]): boolean {
return options.some((option) => option.group?.trim())
}
export function toFlatOptions(options: ModuleFieldOption[]): FieldOption[] {
return options.map((option) => ({ label: option.label, value: option.value }))
}
export function toComboboxGroups(options: ModuleFieldOption[]): ComboboxOptionGroup[] {
const groups = new Map<string, ComboboxOptionGroup>()
for (const option of options) {
const key = option.group?.trim() ?? ''
const group = groups.get(key) ?? { label: key || undefined, options: [] }
group.options.push({ label: option.label, value: option.value })
groups.set(key, group)
}
return [...groups.values()]
}
export function toMultiSelectOptions(
options: ModuleFieldOption[]
): FieldOption[] | MultiSelectOptionGroup[] {
if (!hasGroupedOptions(options)) {
return toFlatOptions(options)
}
return toComboboxGroups(options).map((group) => ({
heading: group.label ?? '',
options: group.options,
}))
}
@@ -0,0 +1,65 @@
type SourceChunk = string | null | false | undefined
const EMPTY_JSX_TEXT_EXPRESSION_REGEX = /\{\s*'\s*'\s*\}/g
function normalizeSource(value: string): string {
const trimmed = value.replace(/^\n/, '').replace(/\n\s*$/, '')
const lines = trimmed.split('\n')
const indents = lines
.filter((line) => line.trim().length > 0)
.map((line) => line.match(/^\s*/)?.[0].length ?? 0)
const minIndent = indents.length > 0 ? Math.min(...indents) : 0
return lines
.map((line) => line.slice(Math.min(line.match(/^\s*/)?.[0].length ?? 0, minIndent)))
.join('\n')
.replace(EMPTY_JSX_TEXT_EXPRESSION_REGEX, '')
.trim()
}
export function source(value: string): string {
return normalizeSource(value)
}
export function indentSource(value: string, spaces: number): string {
const prefix = ' '.repeat(spaces)
return normalizeSource(value)
.split('\n')
.map((line) => (line.length > 0 ? `${prefix}${line}` : line))
.join('\n')
}
export class SourceFile {
private readonly imports = new Set<string>()
private readonly sections: string[] = []
addImport(value: SourceChunk): this {
if (value) {
this.imports.add(normalizeSource(value))
}
return this
}
addImports(values: SourceChunk[]): this {
values.forEach((value) => this.addImport(value))
return this
}
addSection(value: SourceChunk): this {
if (value) {
this.sections.push(normalizeSource(value))
}
return this
}
toString(): string {
return [Array.from(this.imports).join('\n'), this.sections.join('\n\n')]
.filter((section) => section.length > 0)
.join('\n\n')
}
}