Skip to content

Commit f097fa6

Browse files
committed
- reorganize codegen api
1 parent 6547335 commit f097fa6

8 files changed

Lines changed: 222 additions & 212 deletions

File tree

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { AppGenerator } from './generation/generators/app-generator'
2+
import { UiFramework, TableType, Formatter } from './definition/context-types'
3+
import { CodeDir, CodeRW } from '../io'
4+
import ts, { factory } from "typescript"
5+
import { Project } from "ts-morph"
6+
import { CodegenOptions } from './interfaces'
7+
import TemplateResolver from './generation/generators/template/template-resolver'
8+
9+
// generates CRUD React pages (master-detail, eg. orders list, order detail form) from typescript
10+
export function generatePages(inputSourceCode: string, io: CodeRW & CodeDir, options?: CodegenOptions) {
11+
const project = new Project({})
12+
const myClassFile = project.createSourceFile("src/types.ts", inputSourceCode)
13+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed })
14+
15+
options?.names.map((typeName) => {
16+
const typeAlias = myClassFile.getTypeAlias(typeName)
17+
const props = typeAlias?.getType()?.getProperties() ?? []
18+
if (typeAlias) {
19+
const entity = {
20+
getName: () => typeName,
21+
getType: () => typeAlias,
22+
properties: props.map((prop) => ({
23+
getName: () => prop.getName(),
24+
getType: () => prop.getTypeAtLocation(myClassFile),
25+
getTypeText: () => prop.getDeclarations()[0].getText()
26+
}))
27+
}
28+
29+
let context = {uiFramework: UiFramework.MaterialUI, formatter: Formatter.None, index: {tableType: TableType.BasicTable, height: "400px"}};
30+
31+
const generator = new AppGenerator(context, entity)
32+
const page = generator.generateListComponent(/* TODO entity / type name should be input - not in context */)
33+
34+
const filePath = `src/components/${typeName}.tsx`
35+
const sourceFile = ts.createSourceFile(
36+
filePath,
37+
'',
38+
ts.ScriptTarget.ESNext,
39+
true,
40+
ts.ScriptKind.TSX
41+
)
42+
const pageSouceCode = printer.printList(ts.ListFormat.MultiLine, factory.createNodeArray([...page!.imports, page!.functionDeclaration]), sourceFile)
43+
io.writeFile(filePath, pageSouceCode)
44+
45+
//generate list wrapper
46+
const indexWrapperTemplatePath = 'path-to-template'//TODO: put here real template path when template will be done
47+
let template = ''
48+
io.readFile(indexWrapperTemplatePath).then((source => {if(source) template = source;}))
49+
50+
const templateResolver = new TemplateResolver(entity);
51+
const listWrapper = templateResolver.generateListPage(template);
52+
53+
if(listWrapper) {
54+
const listWrapperFilePath = `src/components/${typeName}Page.tsx`
55+
const sourceFileWrapperSourceFile = ts.createSourceFile(
56+
listWrapperFilePath,
57+
listWrapper,
58+
ts.ScriptTarget.ESNext,
59+
true,
60+
ts.ScriptKind.TSX
61+
)
62+
63+
// TODO:PC: Need print here? or only: io.writeFile(listWrapperFilePath, listWrapper)
64+
const wrapperPageSourceCode = printer.printFile(sourceFileWrapperSourceFile);
65+
io.writeFile(listWrapperFilePath, wrapperPageSourceCode)
66+
}
67+
}
68+
})
69+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { SourceLineCol } from "../ast";
2+
import { CodeRW } from "../io";
3+
import { isFormWidget } from "./ast/widgetDeclaration";
4+
import {
5+
insertFormWidget,
6+
getColumnSourcePosition as fGetColumnSourcePosition,
7+
getFormWidgetProperties as fGetFormWidgetProperties,
8+
setFormWidgetProperties as fSetFormWidgetProperties
9+
} from './facade/facadeApi'
10+
import { Property } from "./generation/entity";
11+
import { InsertOptions, WidgetProperties } from "./interfaces";
12+
import { getEntityProperty } from "./tests/helper";
13+
14+
export function isSelectedFormWidget(sourceCode:string, formPosition: SourceLineCol){
15+
return isFormWidget(sourceCode, formPosition)
16+
}
17+
18+
export async function getFormWidgetProperties(io: CodeRW,
19+
sourceCode:SourceLineCol): Promise<WidgetProperties>{
20+
return await fGetFormWidgetProperties(sourceCode, io);
21+
}
22+
23+
export async function setFormWidgetProperties(io: CodeRW,
24+
sourceCode:SourceLineCol,
25+
properties: WidgetProperties): Promise<string | undefined>{
26+
27+
return await fSetFormWidgetProperties(sourceCode, io, properties);
28+
}
29+
30+
export async function addFormInput(typesSourceCode: string,
31+
io: CodeRW,
32+
sourceLine:SourceLineCol,
33+
options: InsertOptions): Promise<string | undefined>{
34+
35+
const property: Property = getEntityProperty(typesSourceCode, options.property, options.entityName)[0]
36+
let generatedSource = undefined
37+
38+
if(property){
39+
generatedSource = await insertFormWidget(sourceLine,
40+
{entityField: property, index: options.index},
41+
io)
42+
}
43+
return generatedSource
44+
}
Lines changed: 4 additions & 203 deletions
Original file line numberDiff line numberDiff line change
@@ -1,203 +1,4 @@
1-
import { AppGenerator } from './generation/generators/app-generator'
2-
import { UiFramework, TableType, Formatter } from './definition/context-types'
3-
import { CodeDir, CodeRW } from '../io'
4-
5-
import ts, { factory } from "typescript"
6-
import { Project } from "ts-morph"
7-
import { HookImport } from '../ast/hooks'
8-
import { TagImport } from '../ast/tags'
9-
import {
10-
insertColumn,
11-
insertFormWidget,
12-
deleteColumn as fDeleteColumn,
13-
getColumnSourcePosition as fGetColumnSourcePosition,
14-
getFormWidgetProperties as fGetFormWidgetProperties,
15-
setFormWidgetProperties as fSetFormWidgetProperties
16-
} from './facade/facadeApi'
17-
import { SourceLineCol } from '../ast'
18-
import { Property } from './generation/entity'
19-
import { getEntityProperty } from './tests/helper'
20-
import { isDataTableWidget, isFormWidget } from './ast/widgetDeclaration'
21-
import { CodegenOptions, ColumnSourcePositionOptions, ColumnSourcePositionResult, DeleteOptions, InsertOptions, WidgetProperties } from './interfaces'
22-
import TemplateResolver from './generation/generators/template/template-resolver'
23-
24-
25-
// generates CRUD React pages (master-detail, eg. orders list, order detail form) from typescript
26-
export function generatePages(inputSourceCode: string, io: CodeRW & CodeDir, options?: CodegenOptions) {
27-
const project = new Project({})
28-
const myClassFile = project.createSourceFile("src/types.ts", inputSourceCode)
29-
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed })
30-
31-
options?.names.map((typeName) => {
32-
const typeAlias = myClassFile.getTypeAlias(typeName)
33-
const props = typeAlias?.getType()?.getProperties() ?? []
34-
if (typeAlias) {
35-
const entity = {
36-
getName: () => typeName,
37-
getType: () => typeAlias,
38-
properties: props.map((prop) => ({
39-
getName: () => prop.getName(),
40-
getType: () => prop.getTypeAtLocation(myClassFile),
41-
getTypeText: () => prop.getDeclarations()[0].getText()
42-
}))
43-
}
44-
45-
let context = {uiFramework: UiFramework.MaterialUI, formatter: Formatter.None, index: {tableType: TableType.BasicTable, height: "400px"}};
46-
47-
const generator = new AppGenerator(context, entity)
48-
const page = generator.generateListComponent(/* TODO entity / type name should be input - not in context */)
49-
50-
const filePath = `src/components/${typeName}.tsx`
51-
const sourceFile = ts.createSourceFile(
52-
filePath,
53-
'',
54-
ts.ScriptTarget.ESNext,
55-
true,
56-
ts.ScriptKind.TSX
57-
)
58-
const pageSouceCode = printer.printList(ts.ListFormat.MultiLine, factory.createNodeArray([...page!.imports, page!.functionDeclaration]), sourceFile)
59-
io.writeFile(filePath, pageSouceCode)
60-
61-
//generate list wrapper
62-
const indexWrapperTemplatePath = 'path-to-template'//TODO: put here real template path when template will be done
63-
let template = ''
64-
io.readFile(indexWrapperTemplatePath).then((source => {if(source) template = source;}))
65-
66-
const templateResolver = new TemplateResolver(entity);
67-
const listWrapper = templateResolver.generateListPage(template);
68-
69-
if(listWrapper) {
70-
const listWrapperFilePath = `src/components/${typeName}Page.tsx`
71-
const sourceFileWrapperSourceFile = ts.createSourceFile(
72-
listWrapperFilePath,
73-
listWrapper,
74-
ts.ScriptTarget.ESNext,
75-
true,
76-
ts.ScriptKind.TSX
77-
)
78-
79-
// TODO:PC: Need print here? or only: io.writeFile(listWrapperFilePath, listWrapper)
80-
const wrapperPageSourceCode = printer.printFile(sourceFileWrapperSourceFile);
81-
io.writeFile(listWrapperFilePath, wrapperPageSourceCode)
82-
}
83-
}
84-
})
85-
}
86-
87-
export function isSelectedDataTable(sourceCode:string, tablePosition: SourceLineCol){
88-
return isDataTableWidget(sourceCode, tablePosition)
89-
}
90-
91-
export function isSelectedFormWidget(sourceCode:string, formPosition: SourceLineCol){
92-
return isFormWidget(sourceCode, formPosition)
93-
}
94-
95-
export async function addColumn(typesSourceCode: string,
96-
io: CodeRW,
97-
sourceCode:SourceLineCol,
98-
options: InsertOptions): Promise<string | undefined>{
99-
100-
const property: Property = getEntityProperty(typesSourceCode, options.property, options.entity)[0]
101-
let generatedSource = undefined
102-
103-
if(property){
104-
generatedSource = await insertColumn(sourceCode,
105-
{entityField: property, index: options.index},
106-
io)
107-
}
108-
109-
return generatedSource
110-
}
111-
112-
export async function deleteColumn(io: CodeRW,
113-
sourceCode:SourceLineCol,
114-
options: DeleteOptions): Promise<string | undefined> {
115-
116-
let generatedSource = await fDeleteColumn(sourceCode, options, io);
117-
118-
return generatedSource
119-
}
120-
121-
export async function getFormWidgetProperties(io: CodeRW,
122-
sourceCode:SourceLineCol): Promise<WidgetProperties>{
123-
return await fGetFormWidgetProperties(sourceCode, io);
124-
}
125-
126-
export async function setFormWidgetProperties(io: CodeRW,
127-
sourceCode:SourceLineCol,
128-
properties: WidgetProperties): Promise<string | undefined>{
129-
130-
return await fSetFormWidgetProperties(sourceCode, io, properties);
131-
}
132-
133-
export async function addFormInput(typesSourceCode: string,
134-
io: CodeRW,
135-
sourceLine:SourceLineCol,
136-
options: InsertOptions): Promise<string | undefined>{
137-
138-
const property: Property = getEntityProperty(typesSourceCode, options.property, options.entity)[0]
139-
let generatedSource = undefined
140-
141-
if(property){
142-
143-
generatedSource = await insertFormWidget(sourceLine,
144-
{entityField: property, index: options.index},
145-
io)
146-
}
147-
148-
return generatedSource
149-
}
150-
151-
export async function getColumnSourcePosition(io: CodeRW,
152-
sourceCode:SourceLineCol,
153-
options: ColumnSourcePositionOptions): Promise<ColumnSourcePositionResult | undefined> {
154-
155-
return await fGetColumnSourcePosition(sourceCode, options, io);
156-
}
157-
158-
interface ThemeCodegen {
159-
providerTag(...children: ts.JsxChild[]): any
160-
}
161-
162-
interface IntlCodegen {
163-
providerTag(...children: ts.JsxChild[]): any
164-
}
165-
166-
export interface AppGenerators {
167-
newSourceFileContext(path: string): JsxFileContext
168-
theme: ThemeCodegen,
169-
intl: IntlCodegen,
170-
//authorization: AuthorizationCodegen
171-
}
172-
173-
export class JsxFileContext {
174-
175-
uniqueImports() {
176-
return []
177-
}
178-
179-
useHook(hook: HookImport, ...params: []) {
180-
// TODO unique import
181-
return null
182-
}
183-
184-
tag(tag: TagImport, ...children: ts.JsxChild[]) {
185-
// TODO unique import
186-
return null
187-
}
188-
189-
returnFragment(...children: ts.JsxChild[]): ts.Statement | null {
190-
191-
if (children?.length == 1) {
192-
// TODO handle one child
193-
}
194-
195-
factory.createReturnStatement(factory.createJsxFragment(
196-
factory.createJsxOpeningFragment(),
197-
children,
198-
factory.createJsxJsxClosingFragment()
199-
))
200-
201-
return null
202-
}
203-
}
1+
export * from './interfaces'
2+
export * from './list'
3+
export * from './detail'
4+
export * from './app'

packages/react-lowcode/src/codegen/interfaces.ts

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import ts, { factory } from "typescript";
12
import { SourceLineCol } from "../ast";
3+
import { HookImport } from "../ast/hooks";
4+
import { TagImport } from "../ast/tags";
25
import { UiFramework } from "./definition/context-types";
36

47
export interface CodegenOptions {
@@ -9,7 +12,7 @@ export interface CodegenOptions {
912
}
1013

1114
export interface InsertOptions {
12-
entity: string
15+
entityName: string
1316
property: string
1417
index?: number
1518
}
@@ -39,4 +42,51 @@ export interface WidgetProperty {
3942

4043
export interface WidgetProperties {
4144
properties: WidgetProperty[]
42-
}
45+
}
46+
47+
interface ThemeCodegen {
48+
providerTag(...children: ts.JsxChild[]): any
49+
}
50+
51+
interface IntlCodegen {
52+
providerTag(...children: ts.JsxChild[]): any
53+
}
54+
55+
export interface AppGenerators {
56+
newSourceFileContext(path: string): JsxFileContext
57+
theme: ThemeCodegen,
58+
intl: IntlCodegen,
59+
//authorization: AuthorizationCodegen
60+
}
61+
62+
export class JsxFileContext {
63+
64+
uniqueImports() {
65+
return []
66+
}
67+
68+
useHook(hook: HookImport, ...params: []) {
69+
// TODO unique import
70+
return null
71+
}
72+
73+
tag(tag: TagImport, ...children: ts.JsxChild[]) {
74+
// TODO unique import
75+
return null
76+
}
77+
78+
returnFragment(...children: ts.JsxChild[]): ts.Statement | null {
79+
80+
if (children?.length == 1) {
81+
// TODO handle one child
82+
}
83+
84+
factory.createReturnStatement(factory.createJsxFragment(
85+
factory.createJsxOpeningFragment(),
86+
children,
87+
factory.createJsxJsxClosingFragment()
88+
))
89+
90+
return null
91+
}
92+
}

0 commit comments

Comments
 (0)