@eide/uniformgen 0.1.0
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 +356 -0
- package/dist/auth/credentials.d.ts +58 -0
- package/dist/auth/credentials.d.ts.map +1 -0
- package/dist/auth/credentials.js +107 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +563 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +113 -0
- package/dist/commands/login.d.ts +9 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +158 -0
- package/dist/commands/logout.d.ts +5 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +13 -0
- package/dist/commands/push.d.ts +13 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/push.js +328 -0
- package/dist/commands/scaffold.d.ts +19 -0
- package/dist/commands/scaffold.d.ts.map +1 -0
- package/dist/commands/scaffold.js +366 -0
- package/dist/commands/seed.d.ts +20 -0
- package/dist/commands/seed.d.ts.map +1 -0
- package/dist/commands/seed.js +380 -0
- package/dist/commands/select-project.d.ts +10 -0
- package/dist/commands/select-project.d.ts.map +1 -0
- package/dist/commands/select-project.js +277 -0
- package/dist/commands/setup.d.ts +5 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +51 -0
- package/dist/commands/sync.d.ts +13 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +318 -0
- package/dist/commands/whoami.d.ts +5 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +31 -0
- package/dist/config/load-config.d.ts +6 -0
- package/dist/config/load-config.d.ts.map +1 -0
- package/dist/config/load-config.js +103 -0
- package/dist/config/settings.d.ts +20 -0
- package/dist/config/settings.d.ts.map +1 -0
- package/dist/config/settings.js +64 -0
- package/dist/config/types.d.ts +152 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +94 -0
- package/dist/fetcher/fetch-schemas.d.ts +140 -0
- package/dist/fetcher/fetch-schemas.d.ts.map +1 -0
- package/dist/fetcher/fetch-schemas.js +223 -0
- package/dist/fetcher/fetch-workflows.d.ts +53 -0
- package/dist/fetcher/fetch-workflows.d.ts.map +1 -0
- package/dist/fetcher/fetch-workflows.js +164 -0
- package/dist/generated/hooks/customer-detail.d.ts +74 -0
- package/dist/generated/hooks/customer-detail.d.ts.map +1 -0
- package/dist/generated/hooks/customer-detail.js +113 -0
- package/dist/generated/hooks/design-system.d.ts +74 -0
- package/dist/generated/hooks/design-system.d.ts.map +1 -0
- package/dist/generated/hooks/design-system.js +109 -0
- package/dist/generated/hooks/index.d.ts +16 -0
- package/dist/generated/hooks/index.d.ts.map +1 -0
- package/dist/generated/hooks/index.js +14 -0
- package/dist/generated/hooks/shopify-collection.d.ts +74 -0
- package/dist/generated/hooks/shopify-collection.d.ts.map +1 -0
- package/dist/generated/hooks/shopify-collection.js +113 -0
- package/dist/generated/hooks/shopify-market.d.ts +74 -0
- package/dist/generated/hooks/shopify-market.d.ts.map +1 -0
- package/dist/generated/hooks/shopify-market.js +109 -0
- package/dist/generated/hooks/shopify-product.d.ts +74 -0
- package/dist/generated/hooks/shopify-product.d.ts.map +1 -0
- package/dist/generated/hooks/shopify-product.js +113 -0
- package/dist/generated/hooks/shopify-variant.d.ts +74 -0
- package/dist/generated/hooks/shopify-variant.d.ts.map +1 -0
- package/dist/generated/hooks/shopify-variant.js +113 -0
- package/dist/generated/hooks/template.d.ts +74 -0
- package/dist/generated/hooks/template.d.ts.map +1 -0
- package/dist/generated/hooks/template.js +107 -0
- package/dist/generated/types/config.d.ts +88 -0
- package/dist/generated/types/config.d.ts.map +1 -0
- package/dist/generated/types/config.js +14 -0
- package/dist/generated/types/data-models/index.d.ts +7 -0
- package/dist/generated/types/data-models/index.d.ts.map +1 -0
- package/dist/generated/types/data-models/index.js +6 -0
- package/dist/generated/types/data-models/test.d.ts +29 -0
- package/dist/generated/types/data-models/test.d.ts.map +1 -0
- package/dist/generated/types/data-models/test.js +1 -0
- package/dist/generated/types/data-models/watch.d.ts +26 -0
- package/dist/generated/types/data-models/watch.d.ts.map +1 -0
- package/dist/generated/types/data-models/watch.js +1 -0
- package/dist/generated/types/field-types.d.ts +255 -0
- package/dist/generated/types/field-types.d.ts.map +1 -0
- package/dist/generated/types/field-types.js +35 -0
- package/dist/generated/types/hooks.d.ts +106 -0
- package/dist/generated/types/hooks.d.ts.map +1 -0
- package/dist/generated/types/hooks.js +9 -0
- package/dist/generated/types/index.d.ts +10 -0
- package/dist/generated/types/index.d.ts.map +1 -0
- package/dist/generated/types/index.js +9 -0
- package/dist/generated/types/models/button-variant.d.ts +16 -0
- package/dist/generated/types/models/button-variant.d.ts.map +1 -0
- package/dist/generated/types/models/button-variant.js +1 -0
- package/dist/generated/types/models/color-palette.d.ts +27 -0
- package/dist/generated/types/models/color-palette.d.ts.map +1 -0
- package/dist/generated/types/models/color-palette.js +1 -0
- package/dist/generated/types/models/color-with-scale.d.ts +15 -0
- package/dist/generated/types/models/color-with-scale.d.ts.map +1 -0
- package/dist/generated/types/models/color-with-scale.js +1 -0
- package/dist/generated/types/models/context.d.ts +53 -0
- package/dist/generated/types/models/context.d.ts.map +1 -0
- package/dist/generated/types/models/context.js +51 -0
- package/dist/generated/types/models/customer-detail.d.ts +32 -0
- package/dist/generated/types/models/customer-detail.d.ts.map +1 -0
- package/dist/generated/types/models/customer-detail.js +26 -0
- package/dist/generated/types/models/design-system-badges.d.ts +16 -0
- package/dist/generated/types/models/design-system-badges.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-badges.js +1 -0
- package/dist/generated/types/models/design-system-buttons.d.ts +17 -0
- package/dist/generated/types/models/design-system-buttons.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-buttons.js +1 -0
- package/dist/generated/types/models/design-system-cards.d.ts +16 -0
- package/dist/generated/types/models/design-system-cards.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-cards.js +1 -0
- package/dist/generated/types/models/design-system-colors.d.ts +12 -0
- package/dist/generated/types/models/design-system-colors.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-colors.js +1 -0
- package/dist/generated/types/models/design-system-dark-mode.d.ts +13 -0
- package/dist/generated/types/models/design-system-dark-mode.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-dark-mode.js +1 -0
- package/dist/generated/types/models/design-system-focus-ring.d.ts +14 -0
- package/dist/generated/types/models/design-system-focus-ring.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-focus-ring.js +1 -0
- package/dist/generated/types/models/design-system-grid.d.ts +18 -0
- package/dist/generated/types/models/design-system-grid.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-grid.js +1 -0
- package/dist/generated/types/models/design-system-inputs.d.ts +26 -0
- package/dist/generated/types/models/design-system-inputs.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-inputs.js +1 -0
- package/dist/generated/types/models/design-system-links.d.ts +16 -0
- package/dist/generated/types/models/design-system-links.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-links.js +1 -0
- package/dist/generated/types/models/design-system-shadows.d.ts +20 -0
- package/dist/generated/types/models/design-system-shadows.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-shadows.js +1 -0
- package/dist/generated/types/models/design-system-spacing.d.ts +13 -0
- package/dist/generated/types/models/design-system-spacing.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-spacing.js +1 -0
- package/dist/generated/types/models/design-system-transitions.d.ts +15 -0
- package/dist/generated/types/models/design-system-transitions.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-transitions.js +1 -0
- package/dist/generated/types/models/design-system-typography.d.ts +21 -0
- package/dist/generated/types/models/design-system-typography.d.ts.map +1 -0
- package/dist/generated/types/models/design-system-typography.js +1 -0
- package/dist/generated/types/models/design-system.d.ts +138 -0
- package/dist/generated/types/models/design-system.d.ts.map +1 -0
- package/dist/generated/types/models/design-system.js +64 -0
- package/dist/generated/types/models/experiment.d.ts +57 -0
- package/dist/generated/types/models/experiment.d.ts.map +1 -0
- package/dist/generated/types/models/experiment.js +55 -0
- package/dist/generated/types/models/font-file.d.ts +16 -0
- package/dist/generated/types/models/font-file.d.ts.map +1 -0
- package/dist/generated/types/models/font-file.js +1 -0
- package/dist/generated/types/models/index.d.ts +38 -0
- package/dist/generated/types/models/index.d.ts.map +1 -0
- package/dist/generated/types/models/index.js +12 -0
- package/dist/generated/types/models/integration.d.ts +32 -0
- package/dist/generated/types/models/integration.d.ts.map +1 -0
- package/dist/generated/types/models/integration.js +26 -0
- package/dist/generated/types/models/route-tree.d.ts +43 -0
- package/dist/generated/types/models/route-tree.d.ts.map +1 -0
- package/dist/generated/types/models/route-tree.js +39 -0
- package/dist/generated/types/models/segment.d.ts +57 -0
- package/dist/generated/types/models/segment.d.ts.map +1 -0
- package/dist/generated/types/models/segment.js +55 -0
- package/dist/generated/types/models/shopify-collection.d.ts +32 -0
- package/dist/generated/types/models/shopify-collection.d.ts.map +1 -0
- package/dist/generated/types/models/shopify-collection.js +26 -0
- package/dist/generated/types/models/shopify-market.d.ts +32 -0
- package/dist/generated/types/models/shopify-market.d.ts.map +1 -0
- package/dist/generated/types/models/shopify-market.js +26 -0
- package/dist/generated/types/models/shopify-product.d.ts +32 -0
- package/dist/generated/types/models/shopify-product.d.ts.map +1 -0
- package/dist/generated/types/models/shopify-product.js +26 -0
- package/dist/generated/types/models/shopify-variant.d.ts +32 -0
- package/dist/generated/types/models/shopify-variant.d.ts.map +1 -0
- package/dist/generated/types/models/shopify-variant.js +26 -0
- package/dist/generated/types/models/template.d.ts +53 -0
- package/dist/generated/types/models/template.d.ts.map +1 -0
- package/dist/generated/types/models/template.js +40 -0
- package/dist/generated/types/models/typography-variant.d.ts +15 -0
- package/dist/generated/types/models/typography-variant.d.ts.map +1 -0
- package/dist/generated/types/models/typography-variant.js +1 -0
- package/dist/generated/types/scalars.d.ts +56 -0
- package/dist/generated/types/scalars.d.ts.map +1 -0
- package/dist/generated/types/scalars.js +6 -0
- package/dist/generators/admin/index.d.ts +32 -0
- package/dist/generators/admin/index.d.ts.map +1 -0
- package/dist/generators/admin/index.js +219 -0
- package/dist/generators/admin/mutations.d.ts +23 -0
- package/dist/generators/admin/mutations.d.ts.map +1 -0
- package/dist/generators/admin/mutations.js +424 -0
- package/dist/generators/admin/queries.d.ts +20 -0
- package/dist/generators/admin/queries.d.ts.map +1 -0
- package/dist/generators/admin/queries.js +476 -0
- package/dist/generators/admin/types.d.ts +28 -0
- package/dist/generators/admin/types.d.ts.map +1 -0
- package/dist/generators/admin/types.js +254 -0
- package/dist/generators/cms/index.d.ts +29 -0
- package/dist/generators/cms/index.d.ts.map +1 -0
- package/dist/generators/cms/index.js +126 -0
- package/dist/generators/cms/route.d.ts +27 -0
- package/dist/generators/cms/route.d.ts.map +1 -0
- package/dist/generators/cms/route.js +409 -0
- package/dist/generators/cms/types.d.ts +15 -0
- package/dist/generators/cms/types.d.ts.map +1 -0
- package/dist/generators/cms/types.js +137 -0
- package/dist/generators/contexts/index.d.ts +25 -0
- package/dist/generators/contexts/index.d.ts.map +1 -0
- package/dist/generators/contexts/index.js +591 -0
- package/dist/generators/documents/data-models.d.ts +6 -0
- package/dist/generators/documents/data-models.d.ts.map +1 -0
- package/dist/generators/documents/data-models.js +61 -0
- package/dist/generators/documents/entity-models.d.ts +7 -0
- package/dist/generators/documents/entity-models.d.ts.map +1 -0
- package/dist/generators/documents/entity-models.js +87 -0
- package/dist/generators/documents/workflows.d.ts +11 -0
- package/dist/generators/documents/workflows.d.ts.map +1 -0
- package/dist/generators/documents/workflows.js +101 -0
- package/dist/generators/filters/index.d.ts +16 -0
- package/dist/generators/filters/index.d.ts.map +1 -0
- package/dist/generators/filters/index.js +384 -0
- package/dist/generators/hooks/agnostic.d.ts +16 -0
- package/dist/generators/hooks/agnostic.d.ts.map +1 -0
- package/dist/generators/hooks/agnostic.js +248 -0
- package/dist/generators/hooks/index.d.ts +9 -0
- package/dist/generators/hooks/index.d.ts.map +1 -0
- package/dist/generators/hooks/index.js +8 -0
- package/dist/generators/hooks/react.d.ts +16 -0
- package/dist/generators/hooks/react.d.ts.map +1 -0
- package/dist/generators/hooks/react.js +394 -0
- package/dist/generators/hooks/remix.d.ts +16 -0
- package/dist/generators/hooks/remix.d.ts.map +1 -0
- package/dist/generators/hooks/remix.js +349 -0
- package/dist/generators/hooks/workflows.d.ts +23 -0
- package/dist/generators/hooks/workflows.d.ts.map +1 -0
- package/dist/generators/hooks/workflows.js +312 -0
- package/dist/generators/resolve/index.d.ts +13 -0
- package/dist/generators/resolve/index.d.ts.map +1 -0
- package/dist/generators/resolve/index.js +13 -0
- package/dist/generators/resolve/platform.d.ts +29 -0
- package/dist/generators/resolve/platform.d.ts.map +1 -0
- package/dist/generators/resolve/platform.js +479 -0
- package/dist/generators/types/config.d.ts +7 -0
- package/dist/generators/types/config.d.ts.map +1 -0
- package/dist/generators/types/config.js +113 -0
- package/dist/generators/types/data-models.d.ts +10 -0
- package/dist/generators/types/data-models.d.ts.map +1 -0
- package/dist/generators/types/data-models.js +100 -0
- package/dist/generators/types/entity-models.d.ts +13 -0
- package/dist/generators/types/entity-models.d.ts.map +1 -0
- package/dist/generators/types/entity-models.js +241 -0
- package/dist/generators/types/field-types.d.ts +9 -0
- package/dist/generators/types/field-types.d.ts.map +1 -0
- package/dist/generators/types/field-types.js +651 -0
- package/dist/generators/types/hooks.d.ts +7 -0
- package/dist/generators/types/hooks.d.ts.map +1 -0
- package/dist/generators/types/hooks.js +132 -0
- package/dist/generators/types/scalars.d.ts +6 -0
- package/dist/generators/types/scalars.d.ts.map +1 -0
- package/dist/generators/types/scalars.js +68 -0
- package/dist/generators/types/user-details.d.ts +6 -0
- package/dist/generators/types/user-details.d.ts.map +1 -0
- package/dist/generators/types/user-details.js +60 -0
- package/dist/generators/types/workflows.d.ts +15 -0
- package/dist/generators/types/workflows.d.ts.map +1 -0
- package/dist/generators/types/workflows.js +163 -0
- package/dist/graphql/generated/gql.d.ts +47 -0
- package/dist/graphql/generated/gql.d.ts.map +1 -0
- package/dist/graphql/generated/gql.js +10 -0
- package/dist/graphql/generated/graphql.d.ts +8455 -0
- package/dist/graphql/generated/graphql.d.ts.map +1 -0
- package/dist/graphql/generated/graphql.js +573 -0
- package/dist/graphql/generated/index.d.ts +2 -0
- package/dist/graphql/generated/index.d.ts.map +1 -0
- package/dist/graphql/generated/index.js +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/schema/define-entity-model.d.ts +122 -0
- package/dist/schema/define-entity-model.d.ts.map +1 -0
- package/dist/schema/define-entity-model.js +59 -0
- package/dist/schema/schema-loader.d.ts +10 -0
- package/dist/schema/schema-loader.d.ts.map +1 -0
- package/dist/schema/schema-loader.js +91 -0
- package/dist/utils/field-mapping.d.ts +83 -0
- package/dist/utils/field-mapping.d.ts.map +1 -0
- package/dist/utils/field-mapping.js +334 -0
- package/dist/writer/write-files.d.ts +12 -0
- package/dist/writer/write-files.d.ts.map +1 -0
- package/dist/writer/write-files.js +35 -0
- package/package.json +70 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agnostic Hooks Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates framework-agnostic typed helper functions that parse
|
|
5
|
+
* the generic entity API responses into strongly typed data.
|
|
6
|
+
*/
|
|
7
|
+
import { toPascalCase, sanitizeFieldName } from '../../utils/field-mapping.js';
|
|
8
|
+
/**
|
|
9
|
+
* Map metadata field type to TypeScript type
|
|
10
|
+
*/
|
|
11
|
+
function getMetadataValueType(fieldType) {
|
|
12
|
+
switch (fieldType) {
|
|
13
|
+
case 'string':
|
|
14
|
+
return 'string';
|
|
15
|
+
case 'number':
|
|
16
|
+
return 'number';
|
|
17
|
+
case 'boolean':
|
|
18
|
+
return 'boolean';
|
|
19
|
+
case 'date':
|
|
20
|
+
return 'string'; // ISO date string from JSON
|
|
21
|
+
case 'array':
|
|
22
|
+
return 'unknown[]';
|
|
23
|
+
case 'object':
|
|
24
|
+
return 'Record<string, unknown>';
|
|
25
|
+
default:
|
|
26
|
+
return 'unknown';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build a nested TypeScript interface from dot-notation paths
|
|
31
|
+
*/
|
|
32
|
+
function buildNestedMetadataType(fields, depth = 0) {
|
|
33
|
+
// Group fields by their first path segment
|
|
34
|
+
const groups = new Map();
|
|
35
|
+
const directFields = [];
|
|
36
|
+
for (const field of fields) {
|
|
37
|
+
const parts = field.key.split('.');
|
|
38
|
+
if (parts.length === 1) {
|
|
39
|
+
directFields.push(field);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
const firstPart = parts[0];
|
|
43
|
+
const remaining = {
|
|
44
|
+
...field,
|
|
45
|
+
key: parts.slice(1).join('.'),
|
|
46
|
+
};
|
|
47
|
+
if (!groups.has(firstPart)) {
|
|
48
|
+
groups.set(firstPart, []);
|
|
49
|
+
}
|
|
50
|
+
groups.get(firstPart).push(remaining);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const indent = ' '.repeat(depth + 1);
|
|
54
|
+
const lines = [];
|
|
55
|
+
// Add direct fields
|
|
56
|
+
for (const field of directFields) {
|
|
57
|
+
const valueType = getMetadataValueType(field.type);
|
|
58
|
+
const fieldName = sanitizeFieldName(field.key);
|
|
59
|
+
const optional = field.required ? '' : '?';
|
|
60
|
+
lines.push(`${indent}${fieldName}${optional}: ${valueType};`);
|
|
61
|
+
}
|
|
62
|
+
// Add nested groups
|
|
63
|
+
for (const [groupName, groupFields] of groups) {
|
|
64
|
+
const nestedType = buildNestedMetadataType(groupFields, depth + 1);
|
|
65
|
+
if (nestedType !== '{}') {
|
|
66
|
+
const fieldName = sanitizeFieldName(groupName);
|
|
67
|
+
lines.push(`${indent}${fieldName}?: ${nestedType}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (lines.length === 0) {
|
|
71
|
+
return '{}';
|
|
72
|
+
}
|
|
73
|
+
const closeIndent = ' '.repeat(depth);
|
|
74
|
+
return `{\n${lines.join('\n')}\n${closeIndent}}`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Generate metadata type interface for a model
|
|
78
|
+
*/
|
|
79
|
+
function generateMetadataType(model) {
|
|
80
|
+
const metadataFields = model.metadataSchema?.fields;
|
|
81
|
+
if (!metadataFields || metadataFields.length === 0) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
return buildNestedMetadataType(metadataFields, 0);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Check if model is inline-only (no records mode)
|
|
88
|
+
*/
|
|
89
|
+
function isInlineOnlyModel(model) {
|
|
90
|
+
return model.modes.inline && !model.modes.records;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Generate agnostic typed helpers for an entity model
|
|
94
|
+
*/
|
|
95
|
+
export function generateAgnosticHooks(model, _allModels) {
|
|
96
|
+
// Skip inline-only models - they don't have standalone records
|
|
97
|
+
if (isInlineOnlyModel(model)) {
|
|
98
|
+
return '';
|
|
99
|
+
}
|
|
100
|
+
const typeName = toPascalCase(model.key);
|
|
101
|
+
const dataTypeName = `${typeName}Data`;
|
|
102
|
+
const filtersTypeName = `${typeName}Filters`;
|
|
103
|
+
const lines = [];
|
|
104
|
+
// File header
|
|
105
|
+
lines.push(`/**`);
|
|
106
|
+
lines.push(` * ${model.name} - Typed Helpers`);
|
|
107
|
+
lines.push(` *`);
|
|
108
|
+
lines.push(` * @generated by UniformGen - DO NOT EDIT MANUALLY`);
|
|
109
|
+
lines.push(` */`);
|
|
110
|
+
lines.push('');
|
|
111
|
+
// Imports
|
|
112
|
+
lines.push(`import type { ${dataTypeName} } from '../types/models/${model.key}.js';`);
|
|
113
|
+
lines.push(`import type { FilterInput, SortInput } from '../types/field-types.js';`);
|
|
114
|
+
lines.push(`import { type ${filtersTypeName}, build${typeName}Filters } from '../filters/${model.key}.js';`);
|
|
115
|
+
lines.push('');
|
|
116
|
+
// Re-export filter types for convenience
|
|
117
|
+
lines.push(`// Re-export filter types for convenience`);
|
|
118
|
+
lines.push(`export type { ${filtersTypeName} } from '../filters/${model.key}.js';`);
|
|
119
|
+
lines.push(`export { build${typeName}Filters } from '../filters/${model.key}.js';`);
|
|
120
|
+
lines.push(`export type { FilterInput, SortInput } from '../types/field-types.js';`);
|
|
121
|
+
lines.push('');
|
|
122
|
+
// Generate metadata type if model has metadataSchema
|
|
123
|
+
const metadataType = generateMetadataType(model);
|
|
124
|
+
const metadataTypeName = `${typeName}Metadata`;
|
|
125
|
+
if (metadataType) {
|
|
126
|
+
lines.push(`/** Typed metadata for ${model.name} */`);
|
|
127
|
+
lines.push(`export interface ${metadataTypeName} ${metadataType}`);
|
|
128
|
+
lines.push('');
|
|
129
|
+
}
|
|
130
|
+
// EntityRecord type (simplified version of what the API returns)
|
|
131
|
+
lines.push(`/** Entity record from the API */`);
|
|
132
|
+
lines.push(`export interface ${typeName}Record {`);
|
|
133
|
+
lines.push(` id: string;`);
|
|
134
|
+
lines.push(` modelKey: '${model.key}';`);
|
|
135
|
+
lines.push(` naturalKey?: string;`);
|
|
136
|
+
lines.push(` data: ${dataTypeName};`);
|
|
137
|
+
if (metadataType) {
|
|
138
|
+
lines.push(` metadata?: ${metadataTypeName};`);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
lines.push(` metadata?: Record<string, unknown>;`);
|
|
142
|
+
}
|
|
143
|
+
lines.push(` versionNumber: number;`);
|
|
144
|
+
lines.push(` publishedVersionNumber?: number;`);
|
|
145
|
+
lines.push(` status: 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';`);
|
|
146
|
+
lines.push(` createdAt: string;`);
|
|
147
|
+
lines.push(` updatedAt: string;`);
|
|
148
|
+
lines.push(`}`);
|
|
149
|
+
lines.push('');
|
|
150
|
+
// Parse single entity
|
|
151
|
+
lines.push(`/**`);
|
|
152
|
+
lines.push(` * Parse a generic entity record into a typed ${model.name} record`);
|
|
153
|
+
lines.push(` */`);
|
|
154
|
+
lines.push(`export function parse${typeName}(entity: {`);
|
|
155
|
+
lines.push(` id: string;`);
|
|
156
|
+
lines.push(` modelKey: string;`);
|
|
157
|
+
lines.push(` naturalKey?: string;`);
|
|
158
|
+
lines.push(` data: unknown;`);
|
|
159
|
+
lines.push(` metadata?: unknown;`);
|
|
160
|
+
lines.push(` versionNumber: number;`);
|
|
161
|
+
lines.push(` publishedVersionNumber?: number;`);
|
|
162
|
+
lines.push(` status: string;`);
|
|
163
|
+
lines.push(` createdAt: string;`);
|
|
164
|
+
lines.push(` updatedAt: string;`);
|
|
165
|
+
lines.push(`}): ${typeName}Record {`);
|
|
166
|
+
lines.push(` return {`);
|
|
167
|
+
lines.push(` ...entity,`);
|
|
168
|
+
lines.push(` modelKey: '${model.key}',`);
|
|
169
|
+
lines.push(` data: entity.data as ${dataTypeName},`);
|
|
170
|
+
if (metadataType) {
|
|
171
|
+
lines.push(` metadata: entity.metadata as ${metadataTypeName},`);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
lines.push(` metadata: entity.metadata as Record<string, unknown>,`);
|
|
175
|
+
}
|
|
176
|
+
lines.push(` status: entity.status as 'DRAFT' | 'PUBLISHED' | 'ARCHIVED',`);
|
|
177
|
+
lines.push(` };`);
|
|
178
|
+
lines.push(`}`);
|
|
179
|
+
lines.push('');
|
|
180
|
+
// Parse list of entities
|
|
181
|
+
lines.push(`/**`);
|
|
182
|
+
lines.push(` * Parse a list of generic entity records into typed ${model.name} records`);
|
|
183
|
+
lines.push(` */`);
|
|
184
|
+
lines.push(`export function parse${typeName}List(entities: Array<{`);
|
|
185
|
+
lines.push(` id: string;`);
|
|
186
|
+
lines.push(` modelKey: string;`);
|
|
187
|
+
lines.push(` naturalKey?: string;`);
|
|
188
|
+
lines.push(` data: unknown;`);
|
|
189
|
+
lines.push(` metadata?: unknown;`);
|
|
190
|
+
lines.push(` versionNumber: number;`);
|
|
191
|
+
lines.push(` publishedVersionNumber?: number;`);
|
|
192
|
+
lines.push(` status: string;`);
|
|
193
|
+
lines.push(` createdAt: string;`);
|
|
194
|
+
lines.push(` updatedAt: string;`);
|
|
195
|
+
lines.push(`}>): ${typeName}Record[] {`);
|
|
196
|
+
lines.push(` return entities.map(parse${typeName});`);
|
|
197
|
+
lines.push(`}`);
|
|
198
|
+
lines.push('');
|
|
199
|
+
// Extract data helper
|
|
200
|
+
lines.push(`/**`);
|
|
201
|
+
lines.push(` * Extract typed data from a ${model.name} record`);
|
|
202
|
+
lines.push(` */`);
|
|
203
|
+
lines.push(`export function get${typeName}Data(entity: { data: unknown }): ${dataTypeName} {`);
|
|
204
|
+
lines.push(` return entity.data as ${dataTypeName};`);
|
|
205
|
+
lines.push(`}`);
|
|
206
|
+
lines.push('');
|
|
207
|
+
// Type guard
|
|
208
|
+
lines.push(`/**`);
|
|
209
|
+
lines.push(` * Type guard to check if an entity is a ${model.name}`);
|
|
210
|
+
lines.push(` */`);
|
|
211
|
+
lines.push(`export function is${typeName}(entity: { modelKey: string }): entity is ${typeName}Record {`);
|
|
212
|
+
lines.push(` return entity.modelKey === '${model.key}';`);
|
|
213
|
+
lines.push(`}`);
|
|
214
|
+
return lines.join('\n') + '\n';
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Generate index file for agnostic hooks
|
|
218
|
+
*/
|
|
219
|
+
export function generateAgnosticHooksIndex(models) {
|
|
220
|
+
const recordModels = models.filter((m) => m.modes.records);
|
|
221
|
+
let indexCode = `/**
|
|
222
|
+
* Typed Entity Helpers
|
|
223
|
+
*
|
|
224
|
+
* Framework-agnostic typed helpers for parsing entity API responses.
|
|
225
|
+
*
|
|
226
|
+
* @generated by UniformGen - DO NOT EDIT MANUALLY
|
|
227
|
+
*/\n\n`;
|
|
228
|
+
// Re-export base types
|
|
229
|
+
indexCode += `// Re-export base filter and sort types\n`;
|
|
230
|
+
indexCode += `export type { FilterInput, SortInput } from '../types/field-types.js';\n\n`;
|
|
231
|
+
for (const model of recordModels) {
|
|
232
|
+
const typeName = toPascalCase(model.key);
|
|
233
|
+
const hasMetadata = model.metadataSchema?.fields && model.metadataSchema.fields.length > 0;
|
|
234
|
+
indexCode += `export {\n`;
|
|
235
|
+
indexCode += ` parse${typeName},\n`;
|
|
236
|
+
indexCode += ` parse${typeName}List,\n`;
|
|
237
|
+
indexCode += ` get${typeName}Data,\n`;
|
|
238
|
+
indexCode += ` is${typeName},\n`;
|
|
239
|
+
indexCode += ` type ${typeName}Record,\n`;
|
|
240
|
+
if (hasMetadata) {
|
|
241
|
+
indexCode += ` type ${typeName}Metadata,\n`;
|
|
242
|
+
}
|
|
243
|
+
indexCode += ` type ${typeName}Filters,\n`;
|
|
244
|
+
indexCode += ` build${typeName}Filters,\n`;
|
|
245
|
+
indexCode += `} from './${model.key}.js';\n`;
|
|
246
|
+
}
|
|
247
|
+
return indexCode;
|
|
248
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks Generators
|
|
3
|
+
*
|
|
4
|
+
* Generates typed hooks/helpers based on the configured framework.
|
|
5
|
+
*/
|
|
6
|
+
export { generateAgnosticHooks, generateAgnosticHooksIndex } from './agnostic.js';
|
|
7
|
+
export { generateReactHooks, generateReactHooksIndex } from './react.js';
|
|
8
|
+
export { generateRemixHooks, generateRemixHooksIndex } from './remix.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/generators/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks Generators
|
|
3
|
+
*
|
|
4
|
+
* Generates typed hooks/helpers based on the configured framework.
|
|
5
|
+
*/
|
|
6
|
+
export { generateAgnosticHooks, generateAgnosticHooksIndex } from './agnostic.js';
|
|
7
|
+
export { generateReactHooks, generateReactHooksIndex } from './react.js';
|
|
8
|
+
export { generateRemixHooks, generateRemixHooksIndex } from './remix.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React/Apollo Hooks Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates typed React hooks using Apollo Client that wrap
|
|
5
|
+
* the generic entity API with strongly typed responses.
|
|
6
|
+
*/
|
|
7
|
+
import type { EntityModel } from '../../fetcher/fetch-schemas.js';
|
|
8
|
+
/**
|
|
9
|
+
* Generate React/Apollo hooks for an entity model
|
|
10
|
+
*/
|
|
11
|
+
export declare function generateReactHooks(model: EntityModel, _allModels: EntityModel[]): string;
|
|
12
|
+
/**
|
|
13
|
+
* Generate index file for React hooks
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateReactHooksIndex(models: EntityModel[]): string;
|
|
16
|
+
//# sourceMappingURL=react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../../src/generators/hooks/react.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAuB,MAAM,gCAAgC,CAAC;AAoGvF;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,WAAW,EAAE,GACxB,MAAM,CAqQR;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAuDrE"}
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React/Apollo Hooks Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates typed React hooks using Apollo Client that wrap
|
|
5
|
+
* the generic entity API with strongly typed responses.
|
|
6
|
+
*/
|
|
7
|
+
import { toPascalCase, toCamelCase, sanitizeFieldName } from '../../utils/field-mapping.js';
|
|
8
|
+
/**
|
|
9
|
+
* Map metadata field type to TypeScript type
|
|
10
|
+
*/
|
|
11
|
+
function getMetadataValueType(fieldType) {
|
|
12
|
+
switch (fieldType) {
|
|
13
|
+
case 'string':
|
|
14
|
+
return 'string';
|
|
15
|
+
case 'number':
|
|
16
|
+
return 'number';
|
|
17
|
+
case 'boolean':
|
|
18
|
+
return 'boolean';
|
|
19
|
+
case 'date':
|
|
20
|
+
return 'string'; // ISO date string from JSON
|
|
21
|
+
case 'array':
|
|
22
|
+
return 'unknown[]';
|
|
23
|
+
case 'object':
|
|
24
|
+
return 'Record<string, unknown>';
|
|
25
|
+
default:
|
|
26
|
+
return 'unknown';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build a nested TypeScript interface from dot-notation paths
|
|
31
|
+
*/
|
|
32
|
+
function buildNestedMetadataType(fields, depth = 0) {
|
|
33
|
+
// Group fields by their first path segment
|
|
34
|
+
const groups = new Map();
|
|
35
|
+
const directFields = [];
|
|
36
|
+
for (const field of fields) {
|
|
37
|
+
const parts = field.key.split('.');
|
|
38
|
+
if (parts.length === 1) {
|
|
39
|
+
directFields.push(field);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
const firstPart = parts[0];
|
|
43
|
+
const remaining = {
|
|
44
|
+
...field,
|
|
45
|
+
key: parts.slice(1).join('.'),
|
|
46
|
+
};
|
|
47
|
+
if (!groups.has(firstPart)) {
|
|
48
|
+
groups.set(firstPart, []);
|
|
49
|
+
}
|
|
50
|
+
groups.get(firstPart).push(remaining);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const indent = ' '.repeat(depth + 1);
|
|
54
|
+
const lines = [];
|
|
55
|
+
// Add direct fields
|
|
56
|
+
for (const field of directFields) {
|
|
57
|
+
const valueType = getMetadataValueType(field.type);
|
|
58
|
+
const fieldName = sanitizeFieldName(field.key);
|
|
59
|
+
const optional = field.required ? '' : '?';
|
|
60
|
+
lines.push(`${indent}${fieldName}${optional}: ${valueType};`);
|
|
61
|
+
}
|
|
62
|
+
// Add nested groups
|
|
63
|
+
for (const [groupName, groupFields] of groups) {
|
|
64
|
+
const nestedType = buildNestedMetadataType(groupFields, depth + 1);
|
|
65
|
+
if (nestedType !== '{}') {
|
|
66
|
+
const fieldName = sanitizeFieldName(groupName);
|
|
67
|
+
lines.push(`${indent}${fieldName}?: ${nestedType}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (lines.length === 0) {
|
|
71
|
+
return '{}';
|
|
72
|
+
}
|
|
73
|
+
const closeIndent = ' '.repeat(depth);
|
|
74
|
+
return `{\n${lines.join('\n')}\n${closeIndent}}`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Generate metadata type interface for a model
|
|
78
|
+
*/
|
|
79
|
+
function generateMetadataType(model) {
|
|
80
|
+
const metadataFields = model.metadataSchema?.fields;
|
|
81
|
+
if (!metadataFields || metadataFields.length === 0) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
return buildNestedMetadataType(metadataFields, 0);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Check if model is inline-only (no records mode)
|
|
88
|
+
*/
|
|
89
|
+
function isInlineOnlyModel(model) {
|
|
90
|
+
return model.modes.inline && !model.modes.records;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Generate React/Apollo hooks for an entity model
|
|
94
|
+
*/
|
|
95
|
+
export function generateReactHooks(model, _allModels) {
|
|
96
|
+
// Skip inline-only models - they don't have standalone records
|
|
97
|
+
if (isInlineOnlyModel(model)) {
|
|
98
|
+
return '';
|
|
99
|
+
}
|
|
100
|
+
const typeName = toPascalCase(model.key);
|
|
101
|
+
const dataTypeName = `${typeName}Data`;
|
|
102
|
+
const camelName = toCamelCase(model.key);
|
|
103
|
+
const filtersTypeName = `${typeName}Filters`;
|
|
104
|
+
const lines = [];
|
|
105
|
+
// File header
|
|
106
|
+
lines.push(`/**`);
|
|
107
|
+
lines.push(` * ${model.name} - React Hooks`);
|
|
108
|
+
lines.push(` *`);
|
|
109
|
+
lines.push(` * @generated by UniformGen - DO NOT EDIT MANUALLY`);
|
|
110
|
+
lines.push(` */`);
|
|
111
|
+
lines.push('');
|
|
112
|
+
// Imports
|
|
113
|
+
lines.push(`import { useQuery, useMutation, type QueryHookOptions, type MutationHookOptions } from '@apollo/client';`);
|
|
114
|
+
lines.push(`import {`);
|
|
115
|
+
lines.push(` Get${typeName}Document,`);
|
|
116
|
+
lines.push(` List${typeName}sDocument,`);
|
|
117
|
+
lines.push(` Create${typeName}Document,`);
|
|
118
|
+
lines.push(` Update${typeName}Document,`);
|
|
119
|
+
lines.push(` Delete${typeName}Document,`);
|
|
120
|
+
lines.push(` Publish${typeName}Document,`);
|
|
121
|
+
lines.push(` Unpublish${typeName}Document,`);
|
|
122
|
+
lines.push(`} from '../documents/${model.key}.js';`);
|
|
123
|
+
lines.push(`import type { ${dataTypeName} } from '../types/models/${model.key}.js';`);
|
|
124
|
+
lines.push(`import type { FilterInput, SortInput } from '../types/field-types.js';`);
|
|
125
|
+
lines.push(`import { type ${filtersTypeName}, build${typeName}Filters } from '../filters/${model.key}.js';`);
|
|
126
|
+
lines.push('');
|
|
127
|
+
// Re-export filter types for convenience
|
|
128
|
+
lines.push(`// Re-export filter types for convenience`);
|
|
129
|
+
lines.push(`export type { ${filtersTypeName} } from '../filters/${model.key}.js';`);
|
|
130
|
+
lines.push(`export { build${typeName}Filters } from '../filters/${model.key}.js';`);
|
|
131
|
+
lines.push('');
|
|
132
|
+
// Generate metadata type if model has metadataSchema
|
|
133
|
+
const metadataType = generateMetadataType(model);
|
|
134
|
+
const metadataTypeName = `${typeName}Metadata`;
|
|
135
|
+
if (metadataType) {
|
|
136
|
+
lines.push(`/** Typed metadata for ${model.name} */`);
|
|
137
|
+
lines.push(`export interface ${metadataTypeName} ${metadataType}`);
|
|
138
|
+
lines.push('');
|
|
139
|
+
}
|
|
140
|
+
// Typed record interface
|
|
141
|
+
lines.push(`/** Typed ${model.name} record */`);
|
|
142
|
+
lines.push(`export interface ${typeName}Record {`);
|
|
143
|
+
lines.push(` id: string;`);
|
|
144
|
+
lines.push(` modelKey: '${model.key}';`);
|
|
145
|
+
lines.push(` naturalKey?: string;`);
|
|
146
|
+
lines.push(` data: ${dataTypeName};`);
|
|
147
|
+
if (metadataType) {
|
|
148
|
+
lines.push(` metadata?: ${metadataTypeName};`);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
lines.push(` metadata?: Record<string, unknown>;`);
|
|
152
|
+
}
|
|
153
|
+
lines.push(` versionNumber: number;`);
|
|
154
|
+
lines.push(` publishedVersionNumber?: number;`);
|
|
155
|
+
lines.push(` status: 'DRAFT' | 'PUBLISHED' | 'ARCHIVED';`);
|
|
156
|
+
lines.push(` createdAt: string;`);
|
|
157
|
+
lines.push(` updatedAt: string;`);
|
|
158
|
+
lines.push(`}`);
|
|
159
|
+
lines.push('');
|
|
160
|
+
// List result interface
|
|
161
|
+
lines.push(`/** Typed list result */`);
|
|
162
|
+
lines.push(`export interface ${typeName}ListResult {`);
|
|
163
|
+
lines.push(` items: ${typeName}Record[];`);
|
|
164
|
+
lines.push(` total: number;`);
|
|
165
|
+
lines.push(` hasMore: boolean;`);
|
|
166
|
+
lines.push(`}`);
|
|
167
|
+
lines.push('');
|
|
168
|
+
// Parse helper
|
|
169
|
+
lines.push(`/** Parse raw entity to typed record */`);
|
|
170
|
+
lines.push(`function parse${typeName}(entity: any): ${typeName}Record {`);
|
|
171
|
+
lines.push(` return {`);
|
|
172
|
+
lines.push(` ...entity,`);
|
|
173
|
+
lines.push(` modelKey: '${model.key}',`);
|
|
174
|
+
lines.push(` data: entity.data as ${dataTypeName},`);
|
|
175
|
+
if (metadataType) {
|
|
176
|
+
lines.push(` metadata: entity.metadata as ${metadataTypeName},`);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
lines.push(` metadata: entity.metadata as Record<string, unknown>,`);
|
|
180
|
+
}
|
|
181
|
+
lines.push(` };`);
|
|
182
|
+
lines.push(`}`);
|
|
183
|
+
lines.push('');
|
|
184
|
+
// useGet hook
|
|
185
|
+
lines.push(`/**`);
|
|
186
|
+
lines.push(` * Fetch a single ${model.name} by ID`);
|
|
187
|
+
lines.push(` */`);
|
|
188
|
+
lines.push(`export function use${typeName}(`);
|
|
189
|
+
lines.push(` id: string,`);
|
|
190
|
+
lines.push(` options?: Omit<QueryHookOptions, 'variables'> & { preview?: boolean }`);
|
|
191
|
+
lines.push(`) {`);
|
|
192
|
+
lines.push(` const { preview, ...queryOptions } = options ?? {};`);
|
|
193
|
+
lines.push(` const result = useQuery(Get${typeName}Document, {`);
|
|
194
|
+
lines.push(` ...queryOptions,`);
|
|
195
|
+
lines.push(` variables: { id, preview },`);
|
|
196
|
+
lines.push(` });`);
|
|
197
|
+
lines.push('');
|
|
198
|
+
lines.push(` return {`);
|
|
199
|
+
lines.push(` ...result,`);
|
|
200
|
+
lines.push(` ${camelName}: result.data?.entity ? parse${typeName}(result.data.entity) : undefined,`);
|
|
201
|
+
lines.push(` };`);
|
|
202
|
+
lines.push(`}`);
|
|
203
|
+
lines.push('');
|
|
204
|
+
// useList hook with typed filters
|
|
205
|
+
lines.push(`/**`);
|
|
206
|
+
lines.push(` * Fetch a list of ${model.name} records`);
|
|
207
|
+
lines.push(` * `);
|
|
208
|
+
lines.push(` * @example`);
|
|
209
|
+
lines.push(` * // Using typed filters (recommended)`);
|
|
210
|
+
lines.push(` * const { ${camelName}s } = use${typeName}s({`);
|
|
211
|
+
lines.push(` * filters: { title: { contains: 'example' } },`);
|
|
212
|
+
lines.push(` * });`);
|
|
213
|
+
lines.push(` * `);
|
|
214
|
+
lines.push(` * @example`);
|
|
215
|
+
lines.push(` * // Using raw FilterInput array`);
|
|
216
|
+
lines.push(` * const { ${camelName}s } = use${typeName}s({`);
|
|
217
|
+
lines.push(` * rawFilters: [{ field: 'data.title', operator: 'contains', value: 'example' }],`);
|
|
218
|
+
lines.push(` * });`);
|
|
219
|
+
lines.push(` */`);
|
|
220
|
+
lines.push(`export function use${typeName}s(options?: {`);
|
|
221
|
+
lines.push(` limit?: number;`);
|
|
222
|
+
lines.push(` offset?: number;`);
|
|
223
|
+
lines.push(` /** Typed filters with autocomplete support */`);
|
|
224
|
+
lines.push(` filters?: ${filtersTypeName};`);
|
|
225
|
+
lines.push(` /** Raw filter array (use filters for type safety) */`);
|
|
226
|
+
lines.push(` rawFilters?: FilterInput[];`);
|
|
227
|
+
lines.push(` sort?: SortInput;`);
|
|
228
|
+
lines.push(` preview?: boolean;`);
|
|
229
|
+
lines.push(` queryOptions?: Omit<QueryHookOptions, 'variables'>;`);
|
|
230
|
+
lines.push(`}) {`);
|
|
231
|
+
lines.push(` const { queryOptions, filters, rawFilters, ...rest } = options ?? {};`);
|
|
232
|
+
lines.push(` `);
|
|
233
|
+
lines.push(` // Convert typed filters to FilterInput array`);
|
|
234
|
+
lines.push(` const apiFilters = filters ? build${typeName}Filters(filters) : rawFilters;`);
|
|
235
|
+
lines.push(` `);
|
|
236
|
+
lines.push(` const result = useQuery(List${typeName}sDocument, {`);
|
|
237
|
+
lines.push(` ...queryOptions,`);
|
|
238
|
+
lines.push(` variables: { ...rest, filters: apiFilters },`);
|
|
239
|
+
lines.push(` });`);
|
|
240
|
+
lines.push('');
|
|
241
|
+
lines.push(` const typedResult: ${typeName}ListResult | undefined = result.data?.entities`);
|
|
242
|
+
lines.push(` ? {`);
|
|
243
|
+
lines.push(` items: result.data.entities.items.map(parse${typeName}),`);
|
|
244
|
+
lines.push(` total: result.data.entities.total,`);
|
|
245
|
+
lines.push(` hasMore: result.data.entities.hasMore,`);
|
|
246
|
+
lines.push(` }`);
|
|
247
|
+
lines.push(` : undefined;`);
|
|
248
|
+
lines.push('');
|
|
249
|
+
lines.push(` return {`);
|
|
250
|
+
lines.push(` ...result,`);
|
|
251
|
+
lines.push(` ${camelName}s: typedResult,`);
|
|
252
|
+
lines.push(` };`);
|
|
253
|
+
lines.push(`}`);
|
|
254
|
+
lines.push('');
|
|
255
|
+
// useCreate mutation
|
|
256
|
+
lines.push(`/**`);
|
|
257
|
+
lines.push(` * Create a new ${model.name}`);
|
|
258
|
+
lines.push(` */`);
|
|
259
|
+
lines.push(`export function useCreate${typeName}(`);
|
|
260
|
+
lines.push(` options?: MutationHookOptions`);
|
|
261
|
+
lines.push(`) {`);
|
|
262
|
+
lines.push(` const [mutate, result] = useMutation(Create${typeName}Document, options);`);
|
|
263
|
+
lines.push('');
|
|
264
|
+
lines.push(` const create${typeName} = async (data: ${dataTypeName}) => {`);
|
|
265
|
+
lines.push(` const response = await mutate({ variables: { data } });`);
|
|
266
|
+
lines.push(` return response.data?.createEntity ? parse${typeName}(response.data.createEntity) : undefined;`);
|
|
267
|
+
lines.push(` };`);
|
|
268
|
+
lines.push('');
|
|
269
|
+
lines.push(` return [create${typeName}, result] as const;`);
|
|
270
|
+
lines.push(`}`);
|
|
271
|
+
lines.push('');
|
|
272
|
+
// useUpdate mutation
|
|
273
|
+
lines.push(`/**`);
|
|
274
|
+
lines.push(` * Update an existing ${model.name}`);
|
|
275
|
+
lines.push(` */`);
|
|
276
|
+
lines.push(`export function useUpdate${typeName}(`);
|
|
277
|
+
lines.push(` options?: MutationHookOptions`);
|
|
278
|
+
lines.push(`) {`);
|
|
279
|
+
lines.push(` const [mutate, result] = useMutation(Update${typeName}Document, options);`);
|
|
280
|
+
lines.push('');
|
|
281
|
+
lines.push(` const update${typeName} = async (id: string, data: Partial<${dataTypeName}>) => {`);
|
|
282
|
+
lines.push(` const response = await mutate({ variables: { id, data } });`);
|
|
283
|
+
lines.push(` return response.data?.updateEntity ? parse${typeName}(response.data.updateEntity) : undefined;`);
|
|
284
|
+
lines.push(` };`);
|
|
285
|
+
lines.push('');
|
|
286
|
+
lines.push(` return [update${typeName}, result] as const;`);
|
|
287
|
+
lines.push(`}`);
|
|
288
|
+
lines.push('');
|
|
289
|
+
// useDelete mutation
|
|
290
|
+
lines.push(`/**`);
|
|
291
|
+
lines.push(` * Delete a ${model.name}`);
|
|
292
|
+
lines.push(` */`);
|
|
293
|
+
lines.push(`export function useDelete${typeName}(`);
|
|
294
|
+
lines.push(` options?: MutationHookOptions`);
|
|
295
|
+
lines.push(`) {`);
|
|
296
|
+
lines.push(` const [mutate, result] = useMutation(Delete${typeName}Document, options);`);
|
|
297
|
+
lines.push('');
|
|
298
|
+
lines.push(` const delete${typeName} = async (id: string) => {`);
|
|
299
|
+
lines.push(` const response = await mutate({ variables: { id } });`);
|
|
300
|
+
lines.push(` return response.data?.deleteEntity;`);
|
|
301
|
+
lines.push(` };`);
|
|
302
|
+
lines.push('');
|
|
303
|
+
lines.push(` return [delete${typeName}, result] as const;`);
|
|
304
|
+
lines.push(`}`);
|
|
305
|
+
lines.push('');
|
|
306
|
+
// usePublish mutation
|
|
307
|
+
lines.push(`/**`);
|
|
308
|
+
lines.push(` * Publish a ${model.name}`);
|
|
309
|
+
lines.push(` */`);
|
|
310
|
+
lines.push(`export function usePublish${typeName}(`);
|
|
311
|
+
lines.push(` options?: MutationHookOptions`);
|
|
312
|
+
lines.push(`) {`);
|
|
313
|
+
lines.push(` const [mutate, result] = useMutation(Publish${typeName}Document, options);`);
|
|
314
|
+
lines.push('');
|
|
315
|
+
lines.push(` const publish${typeName} = async (id: string, versionId?: string) => {`);
|
|
316
|
+
lines.push(` const response = await mutate({ variables: { id, versionId } });`);
|
|
317
|
+
lines.push(` return response.data?.publishEntity ? parse${typeName}(response.data.publishEntity) : undefined;`);
|
|
318
|
+
lines.push(` };`);
|
|
319
|
+
lines.push('');
|
|
320
|
+
lines.push(` return [publish${typeName}, result] as const;`);
|
|
321
|
+
lines.push(`}`);
|
|
322
|
+
lines.push('');
|
|
323
|
+
// useUnpublish mutation
|
|
324
|
+
lines.push(`/**`);
|
|
325
|
+
lines.push(` * Unpublish a ${model.name}`);
|
|
326
|
+
lines.push(` */`);
|
|
327
|
+
lines.push(`export function useUnpublish${typeName}(`);
|
|
328
|
+
lines.push(` options?: MutationHookOptions`);
|
|
329
|
+
lines.push(`) {`);
|
|
330
|
+
lines.push(` const [mutate, result] = useMutation(Unpublish${typeName}Document, options);`);
|
|
331
|
+
lines.push('');
|
|
332
|
+
lines.push(` const unpublish${typeName} = async (id: string) => {`);
|
|
333
|
+
lines.push(` const response = await mutate({ variables: { id } });`);
|
|
334
|
+
lines.push(` return response.data?.unpublishEntity ? parse${typeName}(response.data.unpublishEntity) : undefined;`);
|
|
335
|
+
lines.push(` };`);
|
|
336
|
+
lines.push('');
|
|
337
|
+
lines.push(` return [unpublish${typeName}, result] as const;`);
|
|
338
|
+
lines.push(`}`);
|
|
339
|
+
return lines.join('\n') + '\n';
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Generate index file for React hooks
|
|
343
|
+
*/
|
|
344
|
+
export function generateReactHooksIndex(models) {
|
|
345
|
+
const recordModels = models.filter((m) => m.modes.records);
|
|
346
|
+
let indexCode = `/**
|
|
347
|
+
* Typed React Hooks
|
|
348
|
+
*
|
|
349
|
+
* Apollo Client hooks with strongly typed entity responses.
|
|
350
|
+
*
|
|
351
|
+
* @generated by UniformGen - DO NOT EDIT MANUALLY
|
|
352
|
+
*/\n\n`;
|
|
353
|
+
// Re-export base types
|
|
354
|
+
indexCode += `// Re-export base filter and sort types\n`;
|
|
355
|
+
indexCode += `export type { FilterInput, SortInput } from '../types/field-types.js';\n\n`;
|
|
356
|
+
// Re-export context hooks and helpers
|
|
357
|
+
indexCode += `// Context hooks and helpers\n`;
|
|
358
|
+
indexCode += `export {\n`;
|
|
359
|
+
indexCode += ` useAvailableContexts,\n`;
|
|
360
|
+
indexCode += ` fetchAvailableContexts,\n`;
|
|
361
|
+
indexCode += ` isValidContextValue,\n`;
|
|
362
|
+
indexCode += ` getDefaultContextValue,\n`;
|
|
363
|
+
indexCode += ` getContextValues,\n`;
|
|
364
|
+
indexCode += ` GET_AVAILABLE_CONTEXTS,\n`;
|
|
365
|
+
indexCode += ` GET_CONTEXT_VALUES,\n`;
|
|
366
|
+
indexCode += ` type ContextDefinition,\n`;
|
|
367
|
+
indexCode += ` type ContextValue,\n`;
|
|
368
|
+
indexCode += ` type ContextWithValues,\n`;
|
|
369
|
+
indexCode += ` type TypedContexts,\n`;
|
|
370
|
+
indexCode += ` type ContextKey,\n`;
|
|
371
|
+
indexCode += ` CONTEXT_KEYS,\n`;
|
|
372
|
+
indexCode += `} from './contexts.js';\n\n`;
|
|
373
|
+
for (const model of recordModels) {
|
|
374
|
+
const typeName = toPascalCase(model.key);
|
|
375
|
+
const hasMetadata = model.metadataSchema?.fields && model.metadataSchema.fields.length > 0;
|
|
376
|
+
indexCode += `export {\n`;
|
|
377
|
+
indexCode += ` use${typeName},\n`;
|
|
378
|
+
indexCode += ` use${typeName}s,\n`;
|
|
379
|
+
indexCode += ` useCreate${typeName},\n`;
|
|
380
|
+
indexCode += ` useUpdate${typeName},\n`;
|
|
381
|
+
indexCode += ` useDelete${typeName},\n`;
|
|
382
|
+
indexCode += ` usePublish${typeName},\n`;
|
|
383
|
+
indexCode += ` useUnpublish${typeName},\n`;
|
|
384
|
+
indexCode += ` type ${typeName}Record,\n`;
|
|
385
|
+
if (hasMetadata) {
|
|
386
|
+
indexCode += ` type ${typeName}Metadata,\n`;
|
|
387
|
+
}
|
|
388
|
+
indexCode += ` type ${typeName}ListResult,\n`;
|
|
389
|
+
indexCode += ` type ${typeName}Filters,\n`;
|
|
390
|
+
indexCode += ` build${typeName}Filters,\n`;
|
|
391
|
+
indexCode += `} from './${model.key}.js';\n`;
|
|
392
|
+
}
|
|
393
|
+
return indexCode;
|
|
394
|
+
}
|