@metaobjectsdev/codegen-ts-tanstack 0.5.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +189 -0
- package/README.md +41 -0
- package/dist/grid-filter-validate.d.ts +20 -0
- package/dist/grid-filter-validate.d.ts.map +1 -0
- package/dist/grid-filter-validate.js +37 -0
- package/dist/grid-filter-validate.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/tanstack-grid-hook.d.ts +15 -0
- package/dist/tanstack-grid-hook.d.ts.map +1 -0
- package/dist/tanstack-grid-hook.js +38 -0
- package/dist/tanstack-grid-hook.js.map +1 -0
- package/dist/tanstack-grid.d.ts +13 -0
- package/dist/tanstack-grid.d.ts.map +1 -0
- package/dist/tanstack-grid.js +36 -0
- package/dist/tanstack-grid.js.map +1 -0
- package/dist/tanstack-query.d.ts +15 -0
- package/dist/tanstack-query.d.ts.map +1 -0
- package/dist/tanstack-query.js +31 -0
- package/dist/tanstack-query.js.map +1 -0
- package/dist/templates/columns-file.d.ts +4 -0
- package/dist/templates/columns-file.d.ts.map +1 -0
- package/dist/templates/columns-file.js +142 -0
- package/dist/templates/columns-file.js.map +1 -0
- package/dist/templates/grid-hook-file.d.ts +4 -0
- package/dist/templates/grid-hook-file.d.ts.map +1 -0
- package/dist/templates/grid-hook-file.js +125 -0
- package/dist/templates/grid-hook-file.js.map +1 -0
- package/dist/templates/hooks-file.d.ts +20 -0
- package/dist/templates/hooks-file.d.ts.map +1 -0
- package/dist/templates/hooks-file.js +208 -0
- package/dist/templates/hooks-file.js.map +1 -0
- package/package.json +48 -0
- package/src/index.ts +4 -0
- package/src/tanstack-grid-hook.ts +50 -0
- package/src/tanstack-grid.ts +44 -0
- package/src/tanstack-query.ts +39 -0
- package/src/templates/columns-file.ts +192 -0
- package/src/templates/grid-hook-file.ts +155 -0
- package/src/templates/hooks-file.ts +235 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { code, imp, joinCode } from "ts-poet";
|
|
2
|
+
import { LAYOUT_SUBTYPE_DATA_GRID, LAYOUT_DATA_GRID_ATTR_PAGE_SIZE, LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_FIELD, LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_ORDER, LAYOUT_DATA_GRID_ATTR_FILTERABLE, LAYOUT_DATA_GRID_ATTR_FILTER, LAYOUT_DATA_GRID_ATTR_COLUMNS, } from "@metaobjectsdev/metadata";
|
|
3
|
+
import { GENERATED_HEADER, entityModuleSpecifier } from "@metaobjectsdev/codegen-ts";
|
|
4
|
+
function humanize(s) {
|
|
5
|
+
return s
|
|
6
|
+
.replace(/([a-z])([A-Z])/g, "$1 $2")
|
|
7
|
+
.replace(/^./, (c) => c.toUpperCase());
|
|
8
|
+
}
|
|
9
|
+
function fieldViewKind(field) {
|
|
10
|
+
const view = field.ownViews()[0];
|
|
11
|
+
return view?.subType ?? "text";
|
|
12
|
+
}
|
|
13
|
+
function fieldLabel(field) {
|
|
14
|
+
const view = field.ownViews()[0];
|
|
15
|
+
const label = view?.ownAttr("label");
|
|
16
|
+
if (typeof label === "string")
|
|
17
|
+
return label;
|
|
18
|
+
return humanize(field.name);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Extract grid specs from an entity's dataGrid layouts, resolving column
|
|
22
|
+
* metadata against the entity's field list.
|
|
23
|
+
*
|
|
24
|
+
* Column set: read from @columns stringArray attr on the layout. If absent,
|
|
25
|
+
* fall back to all fields on the entity (pre-E-T2 behaviour, kept for
|
|
26
|
+
* backwards compat with metadata not yet migrated by E-T4).
|
|
27
|
+
*/
|
|
28
|
+
function extractGrids(entity) {
|
|
29
|
+
// fields() and layouts() are both effective (own + inherited via extends:/super:).
|
|
30
|
+
const fieldsByName = new Map(entity.fields().map((f) => [f.name, f]));
|
|
31
|
+
const grids = [];
|
|
32
|
+
for (const layout of entity.layouts()) {
|
|
33
|
+
if (layout.subType !== LAYOUT_SUBTYPE_DATA_GRID)
|
|
34
|
+
continue;
|
|
35
|
+
// @columns is a stringArray attr on the layout (set by E-T4 migration).
|
|
36
|
+
// Fall back to all entity fields if not present.
|
|
37
|
+
const columnsAttr = layout.ownAttr(LAYOUT_DATA_GRID_ATTR_COLUMNS);
|
|
38
|
+
const columnNames = Array.isArray(columnsAttr)
|
|
39
|
+
? columnsAttr.filter((x) => typeof x === "string")
|
|
40
|
+
: [...fieldsByName.keys()];
|
|
41
|
+
const columns = columnNames.flatMap((name) => {
|
|
42
|
+
const field = fieldsByName.get(name);
|
|
43
|
+
if (!field)
|
|
44
|
+
return []; // columns ref that doesn't exist on entity; defensive skip
|
|
45
|
+
const spec = {
|
|
46
|
+
id: name,
|
|
47
|
+
header: fieldLabel(field),
|
|
48
|
+
viewKind: fieldViewKind(field),
|
|
49
|
+
};
|
|
50
|
+
return [spec];
|
|
51
|
+
});
|
|
52
|
+
const sortField = layout.ownAttr(LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_FIELD);
|
|
53
|
+
const sortOrder = layout.ownAttr(LAYOUT_DATA_GRID_ATTR_DEFAULT_SORT_ORDER);
|
|
54
|
+
const filterAttr = layout.ownAttr(LAYOUT_DATA_GRID_ATTR_FILTER);
|
|
55
|
+
const grid = {
|
|
56
|
+
name: layout.name || "default",
|
|
57
|
+
pageSize: layout.ownAttr(LAYOUT_DATA_GRID_ATTR_PAGE_SIZE) ?? 25,
|
|
58
|
+
filterable: layout.ownAttr(LAYOUT_DATA_GRID_ATTR_FILTERABLE) === true,
|
|
59
|
+
columns,
|
|
60
|
+
};
|
|
61
|
+
if (typeof sortField === "string")
|
|
62
|
+
grid.defaultSortField = sortField;
|
|
63
|
+
if (sortOrder === "asc" || sortOrder === "desc")
|
|
64
|
+
grid.defaultSortOrder = sortOrder;
|
|
65
|
+
if (typeof filterAttr === "object" && filterAttr !== null && !Array.isArray(filterAttr)) {
|
|
66
|
+
grid.filter = filterAttr;
|
|
67
|
+
}
|
|
68
|
+
grids.push(grid);
|
|
69
|
+
}
|
|
70
|
+
return grids;
|
|
71
|
+
}
|
|
72
|
+
function renderColumnDef(col) {
|
|
73
|
+
const parts = [];
|
|
74
|
+
parts.push(` id: ${JSON.stringify(col.id)}`);
|
|
75
|
+
parts.push(` accessorKey: ${JSON.stringify(col.id)}`);
|
|
76
|
+
parts.push(` header: ${JSON.stringify(col.header)}`);
|
|
77
|
+
const meta = [`view: ${JSON.stringify(col.viewKind)}`];
|
|
78
|
+
if (col.sortable !== undefined)
|
|
79
|
+
meta.push(`sortable: ${col.sortable}`);
|
|
80
|
+
if (col.width !== undefined)
|
|
81
|
+
meta.push(`width: ${col.width}`);
|
|
82
|
+
if (col.renderer !== undefined)
|
|
83
|
+
meta.push(`renderer: ${JSON.stringify(col.renderer)}`);
|
|
84
|
+
parts.push(` meta: { ${meta.join(", ")} }`);
|
|
85
|
+
return ` {\n${parts.join(",\n")}\n }`;
|
|
86
|
+
}
|
|
87
|
+
export function renderColumnsFile(entity, ctx) {
|
|
88
|
+
const entityName = entity.name;
|
|
89
|
+
const lcEntity = entityName.charAt(0).toLowerCase() + entityName.slice(1);
|
|
90
|
+
const grids = extractGrids(entity);
|
|
91
|
+
const ColumnDefSym = imp("t:ColumnDef@@tanstack/react-table");
|
|
92
|
+
// Track whether any grid emits a filter const so we know to import <Entity>Filter.
|
|
93
|
+
let hasFilterConst = false;
|
|
94
|
+
const sections = grids.map((grid) => {
|
|
95
|
+
const gridConstName = `${lcEntity}${capitalize(grid.name)}Grid`;
|
|
96
|
+
const columnsConstName = `${lcEntity}${capitalize(grid.name)}Columns`;
|
|
97
|
+
const sortBlock = grid.defaultSortField && grid.defaultSortOrder
|
|
98
|
+
? ` defaultSort: { field: ${JSON.stringify(grid.defaultSortField)}, order: ${JSON.stringify(grid.defaultSortOrder)} as const },\n`
|
|
99
|
+
: "";
|
|
100
|
+
const gridConst = code `
|
|
101
|
+
export const ${gridConstName} = {
|
|
102
|
+
name: ${JSON.stringify(grid.name)},
|
|
103
|
+
pageSize: ${grid.pageSize},
|
|
104
|
+
${sortBlock} filterable: ${grid.filterable},
|
|
105
|
+
};
|
|
106
|
+
`;
|
|
107
|
+
const colsLines = grid.columns.map(renderColumnDef).join(",\n");
|
|
108
|
+
const colsConst = code `
|
|
109
|
+
export const ${columnsConstName}: ${ColumnDefSym}<${entityName}Row>[] = [
|
|
110
|
+
${colsLines},
|
|
111
|
+
];
|
|
112
|
+
`;
|
|
113
|
+
// Emit per-grid filter const when @filter is set. The value is already a
|
|
114
|
+
// desugared, load-time-validated object — emit it verbatim.
|
|
115
|
+
let filterConstCode = null;
|
|
116
|
+
if (grid.filter !== undefined) {
|
|
117
|
+
const filterConstName = `${lcEntity}${capitalize(grid.name)}Filter`;
|
|
118
|
+
hasFilterConst = true;
|
|
119
|
+
filterConstCode = code `
|
|
120
|
+
export const ${filterConstName}: ${entityName}Filter = ${JSON.stringify(grid.filter, null, 2)};
|
|
121
|
+
`;
|
|
122
|
+
}
|
|
123
|
+
return filterConstCode
|
|
124
|
+
? code `${gridConst}\n${colsConst}\n${filterConstCode}`
|
|
125
|
+
: code `${gridConst}\n${colsConst}`;
|
|
126
|
+
});
|
|
127
|
+
const header = `// ${GENERATED_HEADER}-tanstack — DO NOT EDIT.\n` +
|
|
128
|
+
`// Source metadata: ${entityName} (${entity.fqn()})\n`;
|
|
129
|
+
// Import the entity's own file. Same target → relative "./Entity"; cross
|
|
130
|
+
// target → importBase-qualified package path.
|
|
131
|
+
const entityModule = entityModuleSpecifier(ctx.selfTarget, ctx.entityModuleTarget, entity.package, entityName, ctx.extStyle);
|
|
132
|
+
// Import <Entity>Row always; import <Entity>Filter only when a filter const is emitted.
|
|
133
|
+
const entityImportCode = hasFilterConst
|
|
134
|
+
? code `import type { ${entityName} as ${entityName}Row, ${entityName}Filter } from ${JSON.stringify(entityModule)};`
|
|
135
|
+
: code `import type { ${entityName} as ${entityName}Row } from ${JSON.stringify(entityModule)};`;
|
|
136
|
+
const body = joinCode(sections, { on: "\n" });
|
|
137
|
+
return header + entityImportCode.toString() + "\n" + body.toString();
|
|
138
|
+
}
|
|
139
|
+
function capitalize(s) {
|
|
140
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=columns-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"columns-file.js","sourceRoot":"","sources":["../../src/templates/columns-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAa,MAAM,SAAS,CAAC;AAEzD,OAAO,EACL,wBAAwB,EACxB,+BAA+B,EAC/B,wCAAwC,EACxC,wCAAwC,EACxC,gCAAgC,EAChC,4BAA4B,EAC5B,6BAA6B,GAC9B,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAqBrF,SAAS,QAAQ,CAAC,CAAS;IACzB,OAAO,CAAC;SACL,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC;SACnC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,aAAa,CAAC,KAAgB;IACrC,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;IACjC,OAAO,IAAI,EAAE,OAAO,IAAI,MAAM,CAAC;AACjC,CAAC;AAED,SAAS,UAAU,CAAC,KAAgB;IAClC,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACrC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,YAAY,CAAC,MAAkB;IACtC,mFAAmF;IACnF,MAAM,YAAY,GAAG,IAAI,GAAG,CAC1B,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAU,CAAC,CACjD,CAAC;IAEF,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QACtC,IAAI,MAAM,CAAC,OAAO,KAAK,wBAAwB;YAAE,SAAS;QAE1D,wEAAwE;QACxE,iDAAiD;QACjD,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAC;QAClE,MAAM,WAAW,GAAa,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;YACtD,CAAC,CAAE,WAAyB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;YAC9E,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;QAE7B,MAAM,OAAO,GAAiB,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACzD,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,CAAC,KAAK;gBAAE,OAAO,EAAE,CAAC,CAAK,2DAA2D;YACtF,MAAM,IAAI,GAAe;gBACvB,EAAE,EAAQ,IAAI;gBACd,MAAM,EAAI,UAAU,CAAC,KAAK,CAAC;gBAC3B,QAAQ,EAAE,aAAa,CAAC,KAAK,CAAC;aAC/B,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;QAC3E,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;QAE3E,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAC;QAChE,MAAM,IAAI,GAAa;YACrB,IAAI,EAAQ,MAAM,CAAC,IAAI,IAAI,SAAS;YACpC,QAAQ,EAAK,MAAM,CAAC,OAAO,CAAC,+BAA+B,CAAwB,IAAI,EAAE;YACzF,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,gCAAgC,CAAC,KAAK,IAAI;YACrE,OAAO;SACR,CAAC;QACF,IAAI,OAAO,SAAS,KAAK,QAAQ;YAAE,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;QACrE,IAAI,SAAS,KAAK,KAAK,IAAI,SAAS,KAAK,MAAM;YAAE,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;QACnF,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YACxF,IAAI,CAAC,MAAM,GAAG,UAAqC,CAAC;QACtD,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,eAAe,CAAC,GAAe;IACtC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAChD,KAAK,CAAC,IAAI,CAAC,oBAAoB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACzD,KAAK,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACxD,MAAM,IAAI,GAAa,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACjE,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS;QAAE,IAAI,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;IACvE,IAAI,GAAG,CAAC,KAAK,KAAQ,SAAS;QAAE,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;IACjE,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS;QAAE,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvF,KAAK,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/C,OAAO,QAAQ,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAkB,EAAE,GAAkB;IACtE,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;IAC/B,MAAM,QAAQ,GAAK,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5E,MAAM,KAAK,GAAQ,YAAY,CAAC,MAAM,CAAC,CAAC;IAExC,MAAM,YAAY,GAAG,GAAG,CAAC,mCAAmC,CAAC,CAAC;IAE9D,mFAAmF;IACnF,IAAI,cAAc,GAAG,KAAK,CAAC;IAE3B,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAClC,MAAM,aAAa,GAAM,GAAG,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;QACnE,MAAM,gBAAgB,GAAG,GAAG,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;QAEtE,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC,gBAAgB;YAC9D,CAAC,CAAC,2BAA2B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC,YAAY,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC,gBAAgB;YACnI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,SAAS,GAAG,IAAI,CAAA;eACX,aAAa;iBACX,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;iBACzB,IAAI,CAAC,QAAQ;EAC5B,SAAS,kBAAkB,IAAI,CAAC,UAAU;;CAE3C,CAAC;QACE,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChE,MAAM,SAAS,GAAG,IAAI,CAAA;eACX,gBAAgB,KAAK,YAAY,IAAI,UAAU;EAC5D,SAAS;;CAEV,CAAC;QAEE,yEAAyE;QACzE,4DAA4D;QAC5D,IAAI,eAAe,GAAgB,IAAI,CAAC;QACxC,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,eAAe,GAAG,GAAG,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;YACpE,cAAc,GAAG,IAAI,CAAC;YACtB,eAAe,GAAG,IAAI,CAAA;eACb,eAAe,KAAK,UAAU,YAAY,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;CAC5F,CAAC;QACE,CAAC;QAED,OAAO,eAAe;YACpB,CAAC,CAAC,IAAI,CAAA,GAAG,SAAS,KAAK,SAAS,KAAK,eAAe,EAAE;YACtD,CAAC,CAAC,IAAI,CAAA,GAAG,SAAS,KAAK,SAAS,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GACV,MAAM,gBAAgB,4BAA4B;QAClD,uBAAuB,UAAU,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC;IAE1D,yEAAyE;IACzE,8CAA8C;IAC9C,MAAM,YAAY,GAAG,qBAAqB,CACxC,GAAG,CAAC,UAAU,EACd,GAAG,CAAC,kBAAkB,EACtB,MAAM,CAAC,OAAO,EACd,UAAU,EACV,GAAG,CAAC,QAAQ,CACb,CAAC;IACF,wFAAwF;IACxF,MAAM,gBAAgB,GAAG,cAAc;QACrC,CAAC,CAAC,IAAI,CAAA,iBAAiB,UAAU,OAAO,UAAU,QAAQ,UAAU,iBAAiB,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG;QACpH,CAAC,CAAC,IAAI,CAAA,iBAAiB,UAAU,OAAO,UAAU,cAAc,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC;IAElG,MAAM,IAAI,GAAS,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,OAAO,MAAM,GAAG,gBAAgB,CAAC,QAAQ,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;AACvE,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grid-hook-file.d.ts","sourceRoot":"","sources":["../../src/templates/grid-hook-file.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,0BAA0B,CAAC;AAEvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AA8BhE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CA+GjF"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Generated grid-hook template — emits one use<Entity><Grid>Grid() per
|
|
2
|
+
// layout[dataGrid] declared on the entity. The hook owns
|
|
3
|
+
// {sorting, pagination, columnFilters, search} state and runs the query
|
|
4
|
+
// against the entity's CRUD list route with withCount=1 (opt-in envelope).
|
|
5
|
+
//
|
|
6
|
+
// The hook returns the controlled-<EntityGrid> prop shape, so a consumer
|
|
7
|
+
// page is just:
|
|
8
|
+
// const grid = useSubscriberDefaultGrid();
|
|
9
|
+
// <EntityGrid {...grid} columns={subscriberDefaultColumns} grid={subscriberDefaultGrid} />
|
|
10
|
+
import { code, imp, joinCode } from "ts-poet";
|
|
11
|
+
import { LAYOUT_SUBTYPE_DATA_GRID } from "@metaobjectsdev/metadata";
|
|
12
|
+
import { GENERATED_HEADER, entityModuleSpecifier, siblingSpecifier } from "@metaobjectsdev/codegen-ts";
|
|
13
|
+
function extractGrids(entity) {
|
|
14
|
+
const out = [];
|
|
15
|
+
for (const l of entity.layouts()) {
|
|
16
|
+
if (l.subType !== LAYOUT_SUBTYPE_DATA_GRID)
|
|
17
|
+
continue;
|
|
18
|
+
out.push({
|
|
19
|
+
name: l.name || "default",
|
|
20
|
+
pageSize: l.pageSize ?? 25,
|
|
21
|
+
hasFilterPreset: l.filter !== undefined,
|
|
22
|
+
defaultSortField: l.defaultSortField,
|
|
23
|
+
defaultSortOrder: l.defaultSortOrder,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
function capitalize(s) {
|
|
29
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
30
|
+
}
|
|
31
|
+
export function renderGridHookFile(entity, ctx) {
|
|
32
|
+
const entityName = entity.name;
|
|
33
|
+
const lcEntity = entityName.charAt(0).toLowerCase() + entityName.slice(1);
|
|
34
|
+
const grids = extractGrids(entity);
|
|
35
|
+
if (grids.length === 0)
|
|
36
|
+
return "";
|
|
37
|
+
// Import the entity's own file. Same target → relative "./Entity"; cross
|
|
38
|
+
// target → importBase-qualified package path.
|
|
39
|
+
const entityModule = entityModuleSpecifier(ctx.selfTarget, ctx.entityModuleTarget, entity.package, entityName, ctx.extStyle);
|
|
40
|
+
// ts-poet symbols (imp()) — typed and deduped on emit.
|
|
41
|
+
const useStateSym = imp("useState@react");
|
|
42
|
+
const useMemoSym = imp("useMemo@react");
|
|
43
|
+
const useQuerySym = imp("useQuery@@tanstack/react-query");
|
|
44
|
+
const SortingStateSym = imp("t:SortingState@@tanstack/react-table");
|
|
45
|
+
const PaginationStateSym = imp("t:PaginationState@@tanstack/react-table");
|
|
46
|
+
const ColumnFiltersStateSym = imp("t:ColumnFiltersState@@tanstack/react-table");
|
|
47
|
+
const useEntityFetcherSym = imp("useEntityFetcher@@metaobjectsdev/tanstack");
|
|
48
|
+
const buildFilterQsSym = imp("buildFilterQs@@metaobjectsdev/runtime-web");
|
|
49
|
+
const entityImports = code `
|
|
50
|
+
import { ${entityName} } from ${JSON.stringify(entityModule)};
|
|
51
|
+
import type { ${entityName} as ${entityName}Row } from ${JSON.stringify(entityModule)};
|
|
52
|
+
`;
|
|
53
|
+
// Collect names of all filter preset consts needed.
|
|
54
|
+
const filterPresetImports = grids
|
|
55
|
+
.filter((g) => g.hasFilterPreset)
|
|
56
|
+
.map((g) => `${lcEntity}${capitalize(g.name)}Filter`);
|
|
57
|
+
// Columns file is a same-target sibling of the grid-hook (both emitted to
|
|
58
|
+
// selfTarget) — always relative, package-layout aware.
|
|
59
|
+
const columnsModule = siblingSpecifier(ctx.selfTarget, entity.package, `${entityName}.columns`, ctx.extStyle);
|
|
60
|
+
const filterPresetImportCode = filterPresetImports.length > 0
|
|
61
|
+
? code `import { ${filterPresetImports.join(", ")} } from ${JSON.stringify(columnsModule)};\n`
|
|
62
|
+
: code ``;
|
|
63
|
+
const sections = grids.map((grid) => {
|
|
64
|
+
const cap = capitalize(grid.name);
|
|
65
|
+
const hookName = `use${entityName}${cap}Grid`;
|
|
66
|
+
const presetConst = grid.hasFilterPreset ? `${lcEntity}${cap}Filter` : null;
|
|
67
|
+
const initialSorting = grid.defaultSortField
|
|
68
|
+
? `[{ id: ${JSON.stringify(grid.defaultSortField)}, desc: ${JSON.stringify(grid.defaultSortOrder === "desc")} }]`
|
|
69
|
+
: `[]`;
|
|
70
|
+
const initialPagination = `{ pageIndex: 0, pageSize: ${grid.pageSize} }`;
|
|
71
|
+
return code `
|
|
72
|
+
export function ${hookName}() {
|
|
73
|
+
const [sorting, setSorting] = ${useStateSym}<${SortingStateSym}>(${initialSorting});
|
|
74
|
+
const [pagination, setPagination] = ${useStateSym}<${PaginationStateSym}>(${initialPagination});
|
|
75
|
+
const [columnFilters, setColumnFilters] = ${useStateSym}<${ColumnFiltersStateSym}>([]);
|
|
76
|
+
const [search, setSearch] = ${useStateSym}<string>("");
|
|
77
|
+
|
|
78
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
79
|
+
|
|
80
|
+
const qs = ${useMemoSym}(() => {
|
|
81
|
+
const filterObj: Record<string, unknown> = ${presetConst ? `{ ...${presetConst} }` : `{}`};
|
|
82
|
+
for (const f of columnFilters) {
|
|
83
|
+
filterObj[f.id] = f.value as unknown;
|
|
84
|
+
}
|
|
85
|
+
const sort = sorting.length > 0
|
|
86
|
+
? \`\${sorting[0].id}:\${sorting[0].desc ? "desc" : "asc"}\`
|
|
87
|
+
: undefined;
|
|
88
|
+
return ${buildFilterQsSym}({
|
|
89
|
+
...filterObj,
|
|
90
|
+
...(sort !== undefined ? { sort } : {}),
|
|
91
|
+
limit: pagination.pageSize,
|
|
92
|
+
offset: pagination.pageIndex * pagination.pageSize,
|
|
93
|
+
...(search !== "" ? { search } : {}),
|
|
94
|
+
withCount: 1,
|
|
95
|
+
});
|
|
96
|
+
}, [sorting, pagination, columnFilters, search]);
|
|
97
|
+
|
|
98
|
+
const query = ${useQuerySym}<{ rows: ${entityName}Row[]; total: number }>({
|
|
99
|
+
queryKey: [${JSON.stringify(lcEntity)}, "grid", ${JSON.stringify(grid.name)}, qs],
|
|
100
|
+
queryFn: () => fetcher<{ rows: ${entityName}Row[]; total: number }>(
|
|
101
|
+
\`\${${entityName}.$apiPrefix}\${${entityName}.$path}?\${qs}\`,
|
|
102
|
+
),
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
data: query.data?.rows ?? [],
|
|
107
|
+
rowCount: query.data?.total ?? 0,
|
|
108
|
+
state: { sorting, pagination, columnFilters },
|
|
109
|
+
onSortingChange: setSorting,
|
|
110
|
+
onPaginationChange: setPagination,
|
|
111
|
+
onColumnFiltersChange: setColumnFilters,
|
|
112
|
+
search,
|
|
113
|
+
onSearchChange: setSearch,
|
|
114
|
+
isLoading: query.isLoading,
|
|
115
|
+
error: query.error,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
`;
|
|
119
|
+
});
|
|
120
|
+
const header = `// ${GENERATED_HEADER}-tanstack — DO NOT EDIT.\n` +
|
|
121
|
+
`// Source metadata: ${entityName} (${entity.fqn()})\n`;
|
|
122
|
+
const body = joinCode(sections, { on: "\n" });
|
|
123
|
+
return header + entityImports.toString() + filterPresetImportCode.toString() + body.toString();
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=grid-hook-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grid-hook-file.js","sourceRoot":"","sources":["../../src/templates/grid-hook-file.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { MetaObject } from "@metaobjectsdev/metadata";
|
|
2
|
+
import type { RenderContext } from "@metaobjectsdev/codegen-ts";
|
|
3
|
+
/**
|
|
4
|
+
* Render <Entity>.hooks.ts — query-key factory + 2 query hooks + (for non-projections) 3 mutation hooks.
|
|
5
|
+
*
|
|
6
|
+
* Projections (view-backed, read-only) emit only:
|
|
7
|
+
* - <camel>Keys query-key factory
|
|
8
|
+
* - use<Entity>(id) — useQuery on GET :id
|
|
9
|
+
* - use<Entities>(filter) — useQuery on list
|
|
10
|
+
*
|
|
11
|
+
* Full (writable) entities additionally emit:
|
|
12
|
+
* - useCreate<Entity>
|
|
13
|
+
* - useUpdate<Entity>
|
|
14
|
+
* - useDelete<Entity>
|
|
15
|
+
*
|
|
16
|
+
* All hooks call useEntityFetcher() (from @metaobjectsdev/tanstack) for
|
|
17
|
+
* the underlying HTTP. Mutations aggressively invalidate <entity>Keys.all().
|
|
18
|
+
*/
|
|
19
|
+
export declare function renderHooksFile(entity: MetaObject, ctx: RenderContext): string;
|
|
20
|
+
//# sourceMappingURL=hooks-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks-file.d.ts","sourceRoot":"","sources":["../../src/templates/hooks-file.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAGhE;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CAc9E"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { code, imp, joinCode } from "ts-poet";
|
|
2
|
+
import { GENERATED_HEADER, isProjection, pluralize, entityModuleSpecifier } from "@metaobjectsdev/codegen-ts";
|
|
3
|
+
/**
|
|
4
|
+
* Render <Entity>.hooks.ts — query-key factory + 2 query hooks + (for non-projections) 3 mutation hooks.
|
|
5
|
+
*
|
|
6
|
+
* Projections (view-backed, read-only) emit only:
|
|
7
|
+
* - <camel>Keys query-key factory
|
|
8
|
+
* - use<Entity>(id) — useQuery on GET :id
|
|
9
|
+
* - use<Entities>(filter) — useQuery on list
|
|
10
|
+
*
|
|
11
|
+
* Full (writable) entities additionally emit:
|
|
12
|
+
* - useCreate<Entity>
|
|
13
|
+
* - useUpdate<Entity>
|
|
14
|
+
* - useDelete<Entity>
|
|
15
|
+
*
|
|
16
|
+
* All hooks call useEntityFetcher() (from @metaobjectsdev/tanstack) for
|
|
17
|
+
* the underlying HTTP. Mutations aggressively invalidate <entity>Keys.all().
|
|
18
|
+
*/
|
|
19
|
+
export function renderHooksFile(entity, ctx) {
|
|
20
|
+
// Import the entity's own file. Same target → relative "./Entity"; cross
|
|
21
|
+
// target → importBase-qualified package path.
|
|
22
|
+
const entityModule = entityModuleSpecifier(ctx.selfTarget, ctx.entityModuleTarget, entity.package, entity.name, ctx.extStyle);
|
|
23
|
+
if (isProjection(entity)) {
|
|
24
|
+
return renderReadOnlyHooksFile(entity, entityModule);
|
|
25
|
+
}
|
|
26
|
+
return renderFullHooksFile(entity, entityModule);
|
|
27
|
+
}
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Read-only path (projections)
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
function renderReadOnlyHooksFile(entity, entityModule) {
|
|
32
|
+
const entityName = entity.name;
|
|
33
|
+
const entityNamePlural = pluralize(entityName);
|
|
34
|
+
const lcEntity = entityName.charAt(0).toLowerCase() + entityName.slice(1);
|
|
35
|
+
const keysVar = `${lcEntity}Keys`;
|
|
36
|
+
const useQuerySym = imp("useQuery@@tanstack/react-query");
|
|
37
|
+
const useQueryOptionsSym = imp("t:UseQueryOptions@@tanstack/react-query");
|
|
38
|
+
const useQueryResultSym = imp("t:UseQueryResult@@tanstack/react-query");
|
|
39
|
+
const useEntityFetcherSym = imp("useEntityFetcher@@metaobjectsdev/tanstack");
|
|
40
|
+
const buildFilterQsSym = imp("buildFilterQs@@metaobjectsdev/runtime-web");
|
|
41
|
+
const entityImports = code `
|
|
42
|
+
import {
|
|
43
|
+
${entityName},
|
|
44
|
+
type ${entityName} as ${entityName}Row,
|
|
45
|
+
type ${entityName}Filter,
|
|
46
|
+
} from ${JSON.stringify(entityModule)};
|
|
47
|
+
`;
|
|
48
|
+
const queryKeys = code `
|
|
49
|
+
export const ${keysVar} = {
|
|
50
|
+
all: () => [${JSON.stringify(lcEntity)}] as const,
|
|
51
|
+
lists: () => [...${keysVar}.all(), "list"] as const,
|
|
52
|
+
list: (filter?: ${entityName}Filter) => [...${keysVar}.lists(), filter ?? {}] as const,
|
|
53
|
+
details: () => [...${keysVar}.all(), "detail"] as const,
|
|
54
|
+
detail: (id: number) => [...${keysVar}.details(), id] as const,
|
|
55
|
+
};
|
|
56
|
+
`;
|
|
57
|
+
const queries = code `
|
|
58
|
+
export function use${entityName}(
|
|
59
|
+
id: number,
|
|
60
|
+
opts?: Omit<${useQueryOptionsSym}<${entityName}Row>, "queryKey" | "queryFn">,
|
|
61
|
+
): ${useQueryResultSym}<${entityName}Row> {
|
|
62
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
63
|
+
return ${useQuerySym}<${entityName}Row>({
|
|
64
|
+
queryKey: ${keysVar}.detail(id),
|
|
65
|
+
queryFn: () => fetcher<${entityName}Row>(\`\${${entityName}.$apiPrefix}\${${entityName}.$path}/\${id}\`),
|
|
66
|
+
...opts,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function use${entityNamePlural}(
|
|
71
|
+
filter?: ${entityName}Filter,
|
|
72
|
+
opts?: Omit<${useQueryOptionsSym}<${entityName}Row[]>, "queryKey" | "queryFn">,
|
|
73
|
+
): ${useQueryResultSym}<${entityName}Row[]> {
|
|
74
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
75
|
+
const qs = filter ? "?" + ${buildFilterQsSym}(filter as Record<string, unknown>) : "";
|
|
76
|
+
return ${useQuerySym}<${entityName}Row[]>({
|
|
77
|
+
queryKey: ${keysVar}.list(filter),
|
|
78
|
+
queryFn: () => fetcher<${entityName}Row[]>(\`\${${entityName}.$apiPrefix}\${${entityName}.$path}\${qs}\`),
|
|
79
|
+
...opts,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
`;
|
|
83
|
+
const body = joinCode([queryKeys, queries], { on: "\n" });
|
|
84
|
+
const header = `// ${GENERATED_HEADER}-tanstack — DO NOT EDIT.\n` +
|
|
85
|
+
`// Source metadata: ${entityName} (${entity.fqn()})\n`;
|
|
86
|
+
return header + entityImports.toString() + body.toString();
|
|
87
|
+
}
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// Full path (writable entities — table-backed or write-through)
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
function renderFullHooksFile(entity, entityModule) {
|
|
92
|
+
const entityName = entity.name;
|
|
93
|
+
const entityNamePlural = pluralize(entityName);
|
|
94
|
+
const lcEntity = entityName.charAt(0).toLowerCase() + entityName.slice(1);
|
|
95
|
+
const keysVar = `${lcEntity}Keys`;
|
|
96
|
+
const useMutationSym = imp("useMutation@@tanstack/react-query");
|
|
97
|
+
const useQuerySym = imp("useQuery@@tanstack/react-query");
|
|
98
|
+
const useQueryClientSym = imp("useQueryClient@@tanstack/react-query");
|
|
99
|
+
const useQueryOptionsSym = imp("t:UseQueryOptions@@tanstack/react-query");
|
|
100
|
+
const useMutationOptionsSym = imp("t:UseMutationOptions@@tanstack/react-query");
|
|
101
|
+
const useQueryResultSym = imp("t:UseQueryResult@@tanstack/react-query");
|
|
102
|
+
const useMutationResultSym = imp("t:UseMutationResult@@tanstack/react-query");
|
|
103
|
+
const useEntityFetcherSym = imp("useEntityFetcher@@metaobjectsdev/tanstack");
|
|
104
|
+
const buildFilterQsSym = imp("buildFilterQs@@metaobjectsdev/runtime-web");
|
|
105
|
+
const entityImports = code `
|
|
106
|
+
import {
|
|
107
|
+
${entityName},
|
|
108
|
+
type ${entityName} as ${entityName}Row,
|
|
109
|
+
type ${entityName}Insert,
|
|
110
|
+
type ${entityName}Update,
|
|
111
|
+
type ${entityName}Filter,
|
|
112
|
+
} from ${JSON.stringify(entityModule)};
|
|
113
|
+
`;
|
|
114
|
+
const queryKeys = code `
|
|
115
|
+
export const ${keysVar} = {
|
|
116
|
+
all: () => [${JSON.stringify(lcEntity)}] as const,
|
|
117
|
+
lists: () => [...${keysVar}.all(), "list"] as const,
|
|
118
|
+
list: (filter?: ${entityName}Filter) => [...${keysVar}.lists(), filter ?? {}] as const,
|
|
119
|
+
details: () => [...${keysVar}.all(), "detail"] as const,
|
|
120
|
+
detail: (id: number) => [...${keysVar}.details(), id] as const,
|
|
121
|
+
};
|
|
122
|
+
`;
|
|
123
|
+
const queries = code `
|
|
124
|
+
export function use${entityName}(
|
|
125
|
+
id: number,
|
|
126
|
+
opts?: Omit<${useQueryOptionsSym}<${entityName}Row>, "queryKey" | "queryFn">,
|
|
127
|
+
): ${useQueryResultSym}<${entityName}Row> {
|
|
128
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
129
|
+
return ${useQuerySym}<${entityName}Row>({
|
|
130
|
+
queryKey: ${keysVar}.detail(id),
|
|
131
|
+
queryFn: () => fetcher<${entityName}Row>(\`\${${entityName}.$apiPrefix}\${${entityName}.$path}/\${id}\`),
|
|
132
|
+
...opts,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function use${entityNamePlural}(
|
|
137
|
+
filter?: ${entityName}Filter,
|
|
138
|
+
opts?: Omit<${useQueryOptionsSym}<${entityName}Row[]>, "queryKey" | "queryFn">,
|
|
139
|
+
): ${useQueryResultSym}<${entityName}Row[]> {
|
|
140
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
141
|
+
const qs = filter ? "?" + ${buildFilterQsSym}(filter as Record<string, unknown>) : "";
|
|
142
|
+
return ${useQuerySym}<${entityName}Row[]>({
|
|
143
|
+
queryKey: ${keysVar}.list(filter),
|
|
144
|
+
queryFn: () => fetcher<${entityName}Row[]>(\`\${${entityName}.$apiPrefix}\${${entityName}.$path}\${qs}\`),
|
|
145
|
+
...opts,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
`;
|
|
149
|
+
const mutations = code `
|
|
150
|
+
export function useCreate${entityName}(
|
|
151
|
+
opts?: Omit<${useMutationOptionsSym}<${entityName}Row, Error, ${entityName}Insert>, "mutationFn">,
|
|
152
|
+
): ${useMutationResultSym}<${entityName}Row, Error, ${entityName}Insert> {
|
|
153
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
154
|
+
const qc = ${useQueryClientSym}();
|
|
155
|
+
return ${useMutationSym}<${entityName}Row, Error, ${entityName}Insert>({
|
|
156
|
+
mutationFn: (input) => fetcher<${entityName}Row>(\`\${${entityName}.$apiPrefix}\${${entityName}.$path}\`, {
|
|
157
|
+
method: "POST",
|
|
158
|
+
headers: { "Content-Type": "application/json" },
|
|
159
|
+
body: JSON.stringify(input),
|
|
160
|
+
}),
|
|
161
|
+
...opts,
|
|
162
|
+
onSuccess: (...args) => {
|
|
163
|
+
qc.invalidateQueries({ queryKey: ${keysVar}.all() });
|
|
164
|
+
opts?.onSuccess?.(...args);
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function useUpdate${entityName}(
|
|
170
|
+
opts?: Omit<${useMutationOptionsSym}<${entityName}Row, Error, { id: number; input: ${entityName}Update }>, "mutationFn">,
|
|
171
|
+
): ${useMutationResultSym}<${entityName}Row, Error, { id: number; input: ${entityName}Update }> {
|
|
172
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
173
|
+
const qc = ${useQueryClientSym}();
|
|
174
|
+
return ${useMutationSym}({
|
|
175
|
+
mutationFn: ({ id, input }) => fetcher<${entityName}Row>(\`\${${entityName}.$apiPrefix}\${${entityName}.$path}/\${id}\`, {
|
|
176
|
+
method: "PATCH",
|
|
177
|
+
headers: { "Content-Type": "application/json" },
|
|
178
|
+
body: JSON.stringify(input),
|
|
179
|
+
}),
|
|
180
|
+
...opts,
|
|
181
|
+
onSuccess: (...args) => {
|
|
182
|
+
qc.invalidateQueries({ queryKey: ${keysVar}.all() });
|
|
183
|
+
opts?.onSuccess?.(...args);
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function useDelete${entityName}(
|
|
189
|
+
opts?: Omit<${useMutationOptionsSym}<void, Error, number>, "mutationFn">,
|
|
190
|
+
): ${useMutationResultSym}<void, Error, number> {
|
|
191
|
+
const fetcher = ${useEntityFetcherSym}();
|
|
192
|
+
const qc = ${useQueryClientSym}();
|
|
193
|
+
return ${useMutationSym}({
|
|
194
|
+
mutationFn: (id) => fetcher<void>(\`\${${entityName}.$apiPrefix}\${${entityName}.$path}/\${id}\`, { method: "DELETE" }),
|
|
195
|
+
...opts,
|
|
196
|
+
onSuccess: (...args) => {
|
|
197
|
+
qc.invalidateQueries({ queryKey: ${keysVar}.all() });
|
|
198
|
+
opts?.onSuccess?.(...args);
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
`;
|
|
203
|
+
const body = joinCode([queryKeys, queries, mutations], { on: "\n" });
|
|
204
|
+
const header = `// ${GENERATED_HEADER}-tanstack — DO NOT EDIT.\n` +
|
|
205
|
+
`// Source metadata: ${entityName} (${entity.fqn()})\n`;
|
|
206
|
+
return header + entityImports.toString() + body.toString();
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=hooks-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks-file.js","sourceRoot":"","sources":["../../src/templates/hooks-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAa,MAAM,SAAS,CAAC;AAGzD,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAE9G;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,MAAkB,EAAE,GAAkB;IACpE,yEAAyE;IACzE,8CAA8C;IAC9C,MAAM,YAAY,GAAG,qBAAqB,CACxC,GAAG,CAAC,UAAU,EACd,GAAG,CAAC,kBAAkB,EACtB,MAAM,CAAC,OAAO,EACd,MAAM,CAAC,IAAI,EACX,GAAG,CAAC,QAAQ,CACb,CAAC;IACF,IAAI,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,OAAO,uBAAuB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,mBAAmB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AACnD,CAAC;AAED,8EAA8E;AAC9E,+BAA+B;AAC/B,8EAA8E;AAE9E,SAAS,uBAAuB,CAAC,MAAkB,EAAE,YAAoB;IACvE,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;IAC/B,MAAM,gBAAgB,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,GAAG,QAAQ,MAAM,CAAC;IAElC,MAAM,WAAW,GAAG,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAC1D,MAAM,kBAAkB,GAAG,GAAG,CAAC,yCAAyC,CAAC,CAAC;IAC1E,MAAM,iBAAiB,GAAG,GAAG,CAAC,wCAAwC,CAAC,CAAC;IACxE,MAAM,mBAAmB,GAAG,GAAG,CAAC,2CAA2C,CAAC,CAAC;IAC7E,MAAM,gBAAgB,GAAG,GAAG,CAAC,2CAA2C,CAAC,CAAC;IAE1E,MAAM,aAAa,GAAS,IAAI,CAAA;;IAE9B,UAAU;SACL,UAAU,OAAO,UAAU;SAC3B,UAAU;SACV,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;CACpC,CAAC;IAEA,MAAM,SAAS,GAAS,IAAI,CAAA;eACf,OAAO;oBACF,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;uBACrB,OAAO;uBACP,UAAU,kBAAkB,OAAO;uBACnC,OAAO;iCACG,OAAO;;CAEvC,CAAC;IAEA,MAAM,OAAO,GAAS,IAAI,CAAA;qBACP,UAAU;;gBAEf,kBAAkB,IAAI,UAAU;KAC3C,iBAAiB,IAAI,UAAU;oBAChB,mBAAmB;WAC5B,WAAW,IAAI,UAAU;gBACpB,OAAO;6BACM,UAAU,aAAa,UAAU,kBAAkB,UAAU;;;;;qBAKrE,gBAAgB;aACxB,UAAU;gBACP,kBAAkB,IAAI,UAAU;KAC3C,iBAAiB,IAAI,UAAU;oBAChB,mBAAmB;8BACT,gBAAgB;WACnC,WAAW,IAAI,UAAU;gBACpB,OAAO;6BACM,UAAU,eAAe,UAAU,kBAAkB,UAAU;;;;CAI3F,CAAC;IAEA,MAAM,IAAI,GAAS,QAAQ,CAAC,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAEhE,MAAM,MAAM,GACV,MAAM,gBAAgB,4BAA4B;QAClD,uBAAuB,UAAU,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC;IAC1D,OAAO,MAAM,GAAG,aAAa,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;AAC7D,CAAC;AAED,8EAA8E;AAC9E,gEAAgE;AAChE,8EAA8E;AAE9E,SAAS,mBAAmB,CAAC,MAAkB,EAAE,YAAoB;IACnE,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;IAC/B,MAAM,gBAAgB,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,GAAG,QAAQ,MAAM,CAAC;IAElC,MAAM,cAAc,GAAG,GAAG,CAAC,mCAAmC,CAAC,CAAC;IAChE,MAAM,WAAW,GAAG,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAC1D,MAAM,iBAAiB,GAAG,GAAG,CAAC,sCAAsC,CAAC,CAAC;IACtE,MAAM,kBAAkB,GAAG,GAAG,CAAC,yCAAyC,CAAC,CAAC;IAC1E,MAAM,qBAAqB,GAAG,GAAG,CAAC,4CAA4C,CAAC,CAAC;IAChF,MAAM,iBAAiB,GAAG,GAAG,CAAC,wCAAwC,CAAC,CAAC;IACxE,MAAM,oBAAoB,GAAG,GAAG,CAAC,2CAA2C,CAAC,CAAC;IAC9E,MAAM,mBAAmB,GAAG,GAAG,CAAC,2CAA2C,CAAC,CAAC;IAC7E,MAAM,gBAAgB,GAAG,GAAG,CAAC,2CAA2C,CAAC,CAAC;IAE1E,MAAM,aAAa,GAAS,IAAI,CAAA;;IAE9B,UAAU;SACL,UAAU,OAAO,UAAU;SAC3B,UAAU;SACV,UAAU;SACV,UAAU;SACV,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;CACpC,CAAC;IAEA,MAAM,SAAS,GAAS,IAAI,CAAA;eACf,OAAO;oBACF,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;uBACrB,OAAO;uBACP,UAAU,kBAAkB,OAAO;uBACnC,OAAO;iCACG,OAAO;;CAEvC,CAAC;IAEA,MAAM,OAAO,GAAS,IAAI,CAAA;qBACP,UAAU;;gBAEf,kBAAkB,IAAI,UAAU;KAC3C,iBAAiB,IAAI,UAAU;oBAChB,mBAAmB;WAC5B,WAAW,IAAI,UAAU;gBACpB,OAAO;6BACM,UAAU,aAAa,UAAU,kBAAkB,UAAU;;;;;qBAKrE,gBAAgB;aACxB,UAAU;gBACP,kBAAkB,IAAI,UAAU;KAC3C,iBAAiB,IAAI,UAAU;oBAChB,mBAAmB;8BACT,gBAAgB;WACnC,WAAW,IAAI,UAAU;gBACpB,OAAO;6BACM,UAAU,eAAe,UAAU,kBAAkB,UAAU;;;;CAI3F,CAAC;IAEA,MAAM,SAAS,GAAS,IAAI,CAAA;2BACH,UAAU;gBACrB,qBAAqB,IAAI,UAAU,eAAe,UAAU;KACvE,oBAAoB,IAAI,UAAU,eAAe,UAAU;oBAC5C,mBAAmB;eACxB,iBAAiB;WACrB,cAAc,IAAI,UAAU,eAAe,UAAU;qCAC3B,UAAU,aAAa,UAAU,kBAAkB,UAAU;;;;;;;yCAOzD,OAAO;;;;;;2BAMrB,UAAU;gBACrB,qBAAqB,IAAI,UAAU,oCAAoC,UAAU;KAC5F,oBAAoB,IAAI,UAAU,oCAAoC,UAAU;oBACjE,mBAAmB;eACxB,iBAAiB;WACrB,cAAc;6CACoB,UAAU,aAAa,UAAU,kBAAkB,UAAU;;;;;;;yCAOjE,OAAO;;;;;;2BAMrB,UAAU;gBACrB,qBAAqB;KAChC,oBAAoB;oBACL,mBAAmB;eACxB,iBAAiB;WACrB,cAAc;6CACoB,UAAU,kBAAkB,UAAU;;;yCAG1C,OAAO;;;;;CAK/C,CAAC;IAEA,MAAM,IAAI,GAAS,QAAQ,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3E,MAAM,MAAM,GACV,MAAM,gBAAgB,4BAA4B;QAClD,uBAAuB,UAAU,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC;IAC1D,OAAO,MAAM,GAAG,aAAa,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;AAC7D,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@metaobjectsdev/codegen-ts-tanstack",
|
|
3
|
+
"version": "0.5.0-rc.1",
|
|
4
|
+
"description": "TanStack codegen for metaobjects — emits hooks and column definitions for TanStack Query and Table.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"bun": "./src/index.ts",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": ["dist", "src", "README.md", "LICENSE"],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -p .",
|
|
18
|
+
"typecheck": "tsc -p tsconfig.typecheck.json"
|
|
19
|
+
},
|
|
20
|
+
"license": "Apache-2.0",
|
|
21
|
+
"author": "Doug Mealing <doug@dougmealing.com>",
|
|
22
|
+
"homepage": "https://metaobjects.dev",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/metaobjectsdev/metaobjects/issues"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/metaobjectsdev/metaobjects.git",
|
|
29
|
+
"directory": "server/typescript/packages/codegen-ts-tanstack"
|
|
30
|
+
},
|
|
31
|
+
"keywords": ["metaobjects", "codegen", "tanstack", "react-query", "react-table"],
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@metaobjectsdev/metadata": "0.5.0",
|
|
37
|
+
"@metaobjectsdev/codegen-ts": "0.5.0",
|
|
38
|
+
"ts-poet": "^6.10.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"@biomejs/biome": ">=1.9.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@biomejs/biome": "^1.9.0",
|
|
45
|
+
"bun-types": "latest",
|
|
46
|
+
"typescript": "^5.6.0"
|
|
47
|
+
}
|
|
48
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Public API surface for @metaobjectsdev/codegen-ts-tanstack.
|
|
2
|
+
export { tanstackQuery, type TanstackQueryOpts } from "./tanstack-query.js";
|
|
3
|
+
export { tanstackGrid, type TanstackGridOpts } from "./tanstack-grid.js";
|
|
4
|
+
export { tanstackGridHook, type TanstackGridHookOpts } from "./tanstack-grid-hook.js";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { MetaObject } from "@metaobjectsdev/metadata";
|
|
2
|
+
import { LAYOUT_SUBTYPE_DATA_GRID } from "@metaobjectsdev/metadata";
|
|
3
|
+
import { perEntity, type Generator, type GeneratorFactory, formatTs, entityOutputPath } from "@metaobjectsdev/codegen-ts";
|
|
4
|
+
import { renderGridHookFile } from "./templates/grid-hook-file.js";
|
|
5
|
+
|
|
6
|
+
export interface TanstackGridHookOpts {
|
|
7
|
+
filter?: (entity: MetaObject) => boolean;
|
|
8
|
+
target?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function hasDataGridLayout(entity: MetaObject): boolean {
|
|
12
|
+
// layouts() is effective — own + inherited layouts (from extends:/super:).
|
|
13
|
+
return entity.layouts().some((l) => l.subType === LAYOUT_SUBTYPE_DATA_GRID);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Per-entity generator that emits <Entity>.grid.ts — one
|
|
18
|
+
* use<Entity><Grid>Grid() hook per layout[dataGrid] declared on the entity.
|
|
19
|
+
*
|
|
20
|
+
* Per-entity opt-out via @emitTanstack: false. Per-entity opt-IN: presence of
|
|
21
|
+
* at least one dataGrid layout on the object (mirrors tanstackGrid).
|
|
22
|
+
*/
|
|
23
|
+
export const tanstackGridHook = function tanstackGridHook(opts?: TanstackGridHookOpts): Generator {
|
|
24
|
+
const userFilter = opts?.filter ?? (() => true);
|
|
25
|
+
const generator: Generator = {
|
|
26
|
+
name: "tanstack-grid-hook",
|
|
27
|
+
// AND-composes opt-out, user filter, and dataGrid layout presence.
|
|
28
|
+
filter: (e: MetaObject) =>
|
|
29
|
+
e.ownAttr("emitTanstack") !== false
|
|
30
|
+
&& userFilter(e)
|
|
31
|
+
&& hasDataGridLayout(e),
|
|
32
|
+
generate: perEntity(async (entity, ctx) => {
|
|
33
|
+
if (!ctx.renderContext) {
|
|
34
|
+
throw new Error("tanstack-grid-hook: renderContext is required (provided by runGen)");
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
path: entityOutputPath(
|
|
38
|
+
ctx.renderContext.outputLayout,
|
|
39
|
+
entity.package,
|
|
40
|
+
`${entity.name}.grid.ts`,
|
|
41
|
+
),
|
|
42
|
+
content: await formatTs(renderGridHookFile(entity, ctx.renderContext)),
|
|
43
|
+
};
|
|
44
|
+
}),
|
|
45
|
+
};
|
|
46
|
+
if (opts?.target) {
|
|
47
|
+
generator.target = opts.target;
|
|
48
|
+
}
|
|
49
|
+
return generator;
|
|
50
|
+
} as GeneratorFactory<TanstackGridHookOpts | void>;
|