| 70 | * Generates ZModel source code from AST. |
| 71 | */ |
| 72 | export class ZModelCodeGenerator { |
| 73 | private readonly options: ZModelCodeOptions; |
| 74 | private readonly quote: string; |
| 75 | constructor(options?: Partial<ZModelCodeOptions>) { |
| 76 | this.options = { |
| 77 | binaryExprNumberOfSpaces: options?.binaryExprNumberOfSpaces ?? 1, |
| 78 | unaryExprNumberOfSpaces: options?.unaryExprNumberOfSpaces ?? 0, |
| 79 | indent: options?.indent ?? 4, |
| 80 | quote: options?.quote ?? 'single', |
| 81 | }; |
| 82 | this.quote = this.options.quote === 'double' ? '"' : "'"; |
| 83 | } |
| 84 | |
| 85 | /** |
| 86 | * Generates ZModel source code from AST. |
| 87 | */ |
| 88 | generate(ast: AstNode): string { |
| 89 | const handler = generationHandlers.get(ast.$type); |
| 90 | if (!handler) { |
| 91 | throw new Error(`No generation handler found for ${ast.$type}`); |
| 92 | } |
| 93 | return handler.value.call(this, ast); |
| 94 | } |
| 95 | |
| 96 | private quotedStr(val: string): string { |
| 97 | const trimmedVal = val.replace(new RegExp(`(?<!\\\\)${this.quote}`, 'g'), `\\${this.quote}`); |
| 98 | return `${this.quote}${trimmedVal}${this.quote}`; |
| 99 | } |
| 100 | |
| 101 | @gen(Model) |
| 102 | private _generateModel(ast: Model) { |
| 103 | return `${ast.imports.map((d) => this.generate(d)).join('\n')}${ast.imports.length > 0 ? '\n\n' : ''}${ast.declarations |
| 104 | .map((d) => this.generate(d)) |
| 105 | .join('\n\n')}`; |
| 106 | } |
| 107 | |
| 108 | @gen(DataSource) |
| 109 | private _generateDataSource(ast: DataSource) { |
| 110 | return `datasource ${ast.name} { |
| 111 | ${ast.fields.map((x) => this.indent + this.generate(x)).join('\n')} |
| 112 | }`; |
| 113 | } |
| 114 | |
| 115 | @gen(ModelImport) |
| 116 | private _generateModelImport(ast: ModelImport) { |
| 117 | return `import ${this.quotedStr(ast.path)}`; |
| 118 | } |
| 119 | |
| 120 | @gen(Enum) |
| 121 | private _generateEnum(ast: Enum) { |
| 122 | const comments = `${ast.comments.join('\n')}\n`; |
| 123 | return `${ast.comments.length > 0 ? comments : ''}enum ${ast.name} { |
| 124 | ${ast.fields.map((x) => this.indent + this.generate(x)).join('\n')}${ |
| 125 | ast.attributes.length > 0 |
| 126 | ? '\n\n' + ast.attributes.map((x) => this.indent + this.generate(x)).join('\n') |
| 127 | : '' |
| 128 | } |
| 129 | }`; |