@eide/foir-cli 0.1.32 → 0.1.34
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/dist/codegen/field-mapping.d.ts +5 -0
- package/dist/codegen/field-mapping.d.ts.map +1 -1
- package/dist/codegen/field-mapping.js +17 -0
- package/dist/codegen/generators/config.js +2 -2
- package/dist/codegen/generators/documents.d.ts.map +1 -1
- package/dist/codegen/generators/documents.js +12 -4
- package/dist/codegen/generators/field-types.d.ts.map +1 -1
- package/dist/codegen/generators/field-types.js +20 -13
- package/dist/codegen/generators/model-types.d.ts.map +1 -1
- package/dist/codegen/generators/model-types.js +28 -4
- package/dist/codegen/generators/typed-operations-common.d.ts +1 -1
- package/dist/codegen/generators/typed-operations-common.d.ts.map +1 -1
- package/dist/codegen/generators/typed-operations-common.js +13 -3
- package/dist/codegen/generators/typed-operations.d.ts.map +1 -1
- package/dist/codegen/generators/typed-operations.js +21 -9
- package/dist/codegen/swift-field-mapping.d.ts.map +1 -1
- package/dist/codegen/swift-field-mapping.js +6 -0
- package/dist/commands/operations.d.ts.map +1 -1
- package/dist/commands/operations.js +55 -0
- package/dist/commands/pull.js +1 -1
- package/dist/graphql/generated.d.ts +47 -0
- package/dist/graphql/generated.d.ts.map +1 -1
- package/dist/graphql/generated.js +135 -10167
- package/package.json +1 -1
|
@@ -20,6 +20,11 @@ export interface FieldSchemaForGen {
|
|
|
20
20
|
}
|
|
21
21
|
export declare function getFieldType(field: FieldSchemaForGen, mode?: 'output' | 'input'): string;
|
|
22
22
|
export declare function getRequiredImports(fields: FieldSchemaForGen[]): Set<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Extract model keys referenced by reference-type fields via `referenceTypes`.
|
|
25
|
+
* Used to generate parameterized `ReferenceValue<Partial<ModelData>>` types.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getReferenceTypeModelRefs(fields: FieldSchemaForGen[]): Set<string>;
|
|
23
28
|
export declare function getInlineSchemaReferences(fields: FieldSchemaForGen[]): Set<string>;
|
|
24
29
|
export declare function toCamelCase(str: string): string;
|
|
25
30
|
export declare function toPascalCase(str: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-mapping.d.ts","sourceRoot":"","sources":["../../src/codegen/field-mapping.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"field-mapping.d.ts","sourceRoot":"","sources":["../../src/codegen/field-mapping.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,qBAAqB,aAqBhC,CAAC;AAEH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAqD1D,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,iBAAiB,EACxB,IAAI,GAAE,QAAQ,GAAG,OAAkB,GAClC,MAAM,CAqCR;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAW3E;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,iBAAiB,EAAE,GAC1B,GAAG,CAAC,MAAM,CAAC,CAUb;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,iBAAiB,EAAE,GAC1B,GAAG,CAAC,MAAM,CAAC,CAcb;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIhD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMpD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CA2EjE"}
|
|
@@ -22,6 +22,7 @@ export const PRIMITIVE_FIELD_TYPES = new Set([
|
|
|
22
22
|
'reference',
|
|
23
23
|
'link',
|
|
24
24
|
'flexible',
|
|
25
|
+
'model',
|
|
25
26
|
]);
|
|
26
27
|
export function isPrimitiveFieldType(type) {
|
|
27
28
|
return PRIMITIVE_FIELD_TYPES.has(type);
|
|
@@ -78,6 +79,7 @@ export const FIELD_TYPE_MAPPING = {
|
|
|
78
79
|
inputType: 'LinkValue',
|
|
79
80
|
needsImport: 'field-types',
|
|
80
81
|
},
|
|
82
|
+
model: { outputType: 'string', inputType: 'string' },
|
|
81
83
|
};
|
|
82
84
|
export function getFieldType(field, mode = 'output') {
|
|
83
85
|
if (!field?.type)
|
|
@@ -127,6 +129,21 @@ export function getRequiredImports(fields) {
|
|
|
127
129
|
}
|
|
128
130
|
return imports;
|
|
129
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* Extract model keys referenced by reference-type fields via `referenceTypes`.
|
|
134
|
+
* Used to generate parameterized `ReferenceValue<Partial<ModelData>>` types.
|
|
135
|
+
*/
|
|
136
|
+
export function getReferenceTypeModelRefs(fields) {
|
|
137
|
+
const refs = new Set();
|
|
138
|
+
for (const field of fields) {
|
|
139
|
+
if (field.type === 'reference' && field.options?.referenceTypes) {
|
|
140
|
+
for (const rt of field.options.referenceTypes) {
|
|
141
|
+
refs.add(rt);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return refs;
|
|
146
|
+
}
|
|
130
147
|
export function getInlineSchemaReferences(fields) {
|
|
131
148
|
const refs = new Set();
|
|
132
149
|
for (const field of fields) {
|
|
@@ -10,7 +10,7 @@ export function generateConfigFile() {
|
|
|
10
10
|
* @generated by foir — DO NOT EDIT MANUALLY
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import type { FieldDef } from './field-types.js';
|
|
13
|
+
import type { FieldDef, JsonValue } from './field-types.js';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Model configuration
|
|
@@ -66,7 +66,7 @@ export interface ModelConfig {
|
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
/** Lifecycle hooks configuration */
|
|
69
|
-
hooks?: Record<string,
|
|
69
|
+
hooks?: Record<string, JsonValue>;
|
|
70
70
|
|
|
71
71
|
/** Field definitions */
|
|
72
72
|
fieldDefs: readonly FieldDef[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../../src/codegen/generators/documents.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../../src/codegen/generators/documents.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAyGlE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAoBhD"}
|
|
@@ -25,10 +25,10 @@ fragment ${typeName}Fields on Record {
|
|
|
25
25
|
updatedAt
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
query Get${typeName}($id: ID!, $locale: String, $preview: Boolean) {
|
|
28
|
+
query Get${typeName}($id: ID!, $locale: String, $preview: Boolean, $fields: FieldSelectionInput) {
|
|
29
29
|
record(id: $id) {
|
|
30
30
|
...${typeName}Fields
|
|
31
|
-
resolved(locale: $locale, preview: $preview) {
|
|
31
|
+
resolved(locale: $locale, preview: $preview, fields: $fields) {
|
|
32
32
|
content
|
|
33
33
|
record { id modelKey naturalKey }
|
|
34
34
|
version { id versionNumber }
|
|
@@ -36,10 +36,10 @@ query Get${typeName}($id: ID!, $locale: String, $preview: Boolean) {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
query Get${typeName}ByKey($naturalKey: String!, $locale: String, $preview: Boolean) {
|
|
39
|
+
query Get${typeName}ByKey($naturalKey: String!, $locale: String, $preview: Boolean, $fields: FieldSelectionInput) {
|
|
40
40
|
recordByKey(modelKey: "${model.key}", naturalKey: $naturalKey) {
|
|
41
41
|
...${typeName}Fields
|
|
42
|
-
resolved(locale: $locale, preview: $preview) {
|
|
42
|
+
resolved(locale: $locale, preview: $preview, fields: $fields) {
|
|
43
43
|
content
|
|
44
44
|
record { id modelKey naturalKey }
|
|
45
45
|
version { id versionNumber }
|
|
@@ -52,6 +52,9 @@ query List${pluralName}(
|
|
|
52
52
|
$offset: Int
|
|
53
53
|
$filters: [FilterInput!]
|
|
54
54
|
$sort: SortInput
|
|
55
|
+
$locale: String
|
|
56
|
+
$preview: Boolean
|
|
57
|
+
$fields: FieldSelectionInput
|
|
55
58
|
) {
|
|
56
59
|
records(
|
|
57
60
|
modelKey: "${model.key}"
|
|
@@ -62,6 +65,11 @@ query List${pluralName}(
|
|
|
62
65
|
) {
|
|
63
66
|
items {
|
|
64
67
|
...${typeName}Fields
|
|
68
|
+
resolved(locale: $locale, preview: $preview, fields: $fields) {
|
|
69
|
+
content
|
|
70
|
+
record { id modelKey naturalKey }
|
|
71
|
+
version { id versionNumber }
|
|
72
|
+
}
|
|
65
73
|
}
|
|
66
74
|
total
|
|
67
75
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-types.d.ts","sourceRoot":"","sources":["../../../src/codegen/generators/field-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,sBAAsB,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"field-types.d.ts","sourceRoot":"","sources":["../../../src/codegen/generators/field-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,sBAAsB,IAAI,MAAM,CAsV/C"}
|
|
@@ -10,12 +10,19 @@ export function generateFieldTypesFile() {
|
|
|
10
10
|
* @generated by foir — DO NOT EDIT MANUALLY
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// JSON-SAFE BASE TYPE
|
|
15
|
+
// =============================================================================
|
|
16
|
+
|
|
17
|
+
/** Recursive JSON-serializable value type. Safe for TanStack Router, Remix, RSC, and other serialization boundaries. */
|
|
18
|
+
export type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };
|
|
19
|
+
|
|
13
20
|
// =============================================================================
|
|
14
21
|
// VALUE TYPES
|
|
15
22
|
// =============================================================================
|
|
16
23
|
|
|
17
24
|
/** Rich text content (Lexical JSON format) */
|
|
18
|
-
export type RichtextValue =
|
|
25
|
+
export type RichtextValue = JsonValue;
|
|
19
26
|
|
|
20
27
|
/** Currency value with amount and ISO 4217 code */
|
|
21
28
|
export interface CurrencyValue {
|
|
@@ -63,19 +70,19 @@ export interface LinkRecordReference {
|
|
|
63
70
|
naturalKey: string;
|
|
64
71
|
}
|
|
65
72
|
|
|
66
|
-
/** Record reference value */
|
|
67
|
-
export interface ReferenceValue {
|
|
73
|
+
/** Record reference value (generic TPreview for typed preview data when reference target is known) */
|
|
74
|
+
export interface ReferenceValue<TPreview = Record<string, JsonValue>> {
|
|
68
75
|
_type: 'reference';
|
|
69
76
|
_schema: string;
|
|
70
77
|
naturalKey: string;
|
|
71
|
-
_preview?:
|
|
78
|
+
_preview?: TPreview;
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
/** Composite/inline value */
|
|
75
82
|
export interface CompositeValue {
|
|
76
83
|
_type: 'composite';
|
|
77
84
|
_schema: string;
|
|
78
|
-
fields: Record<string,
|
|
85
|
+
fields: Record<string, JsonValue>;
|
|
79
86
|
}
|
|
80
87
|
|
|
81
88
|
/** A single item in a flexible field array */
|
|
@@ -86,8 +93,8 @@ export interface FlexibleFieldItem {
|
|
|
86
93
|
_label: string;
|
|
87
94
|
_required?: boolean;
|
|
88
95
|
_helpText?: string;
|
|
89
|
-
_config?: Record<string,
|
|
90
|
-
value:
|
|
96
|
+
_config?: Record<string, JsonValue>;
|
|
97
|
+
value: JsonValue;
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
// =============================================================================
|
|
@@ -159,7 +166,7 @@ export interface ReferenceFilter {
|
|
|
159
166
|
export interface FilterInput {
|
|
160
167
|
field: string;
|
|
161
168
|
operator: string;
|
|
162
|
-
value:
|
|
169
|
+
value: JsonValue;
|
|
163
170
|
}
|
|
164
171
|
|
|
165
172
|
export interface SortInput {
|
|
@@ -176,7 +183,7 @@ export interface VariantContext {
|
|
|
176
183
|
locale?: string;
|
|
177
184
|
device?: string;
|
|
178
185
|
region?: string;
|
|
179
|
-
contexts?: Record<string,
|
|
186
|
+
contexts?: Record<string, JsonValue>;
|
|
180
187
|
}
|
|
181
188
|
|
|
182
189
|
/** Reference resolution options */
|
|
@@ -191,7 +198,7 @@ export interface ResolvedRecord {
|
|
|
191
198
|
id: string;
|
|
192
199
|
modelKey: string;
|
|
193
200
|
naturalKey: string | null;
|
|
194
|
-
metadata?: Record<string,
|
|
201
|
+
metadata?: Record<string, JsonValue>;
|
|
195
202
|
}
|
|
196
203
|
|
|
197
204
|
/** Resolved variant info */
|
|
@@ -206,7 +213,7 @@ export interface ResolvedField {
|
|
|
206
213
|
type: string;
|
|
207
214
|
label?: string;
|
|
208
215
|
required?: boolean;
|
|
209
|
-
value:
|
|
216
|
+
value: JsonValue;
|
|
210
217
|
}
|
|
211
218
|
|
|
212
219
|
/** Resolved content */
|
|
@@ -217,7 +224,7 @@ export interface ResolvedContent {
|
|
|
217
224
|
/** Resolution context output */
|
|
218
225
|
export interface ResolutionContext {
|
|
219
226
|
locale: string;
|
|
220
|
-
contexts: Record<string,
|
|
227
|
+
contexts: Record<string, JsonValue>;
|
|
221
228
|
}
|
|
222
229
|
|
|
223
230
|
/** Base resolved record content */
|
|
@@ -237,7 +244,7 @@ export interface BaseFieldDef {
|
|
|
237
244
|
label: string;
|
|
238
245
|
required?: boolean;
|
|
239
246
|
helpText?: string;
|
|
240
|
-
defaultValue?:
|
|
247
|
+
defaultValue?: JsonValue;
|
|
241
248
|
}
|
|
242
249
|
|
|
243
250
|
export interface TextFieldDef extends BaseFieldDef {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-types.d.ts","sourceRoot":"","sources":["../../../src/codegen/generators/model-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"model-types.d.ts","sourceRoot":"","sources":["../../../src/codegen/generators/model-types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAiBvD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,YAAY,EAAE,GACxB,MAAM,CA2BR"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Generates per-model TypeScript files with config object + data interface.
|
|
3
3
|
*/
|
|
4
|
-
import { getFieldType, getInlineSchemaReferences, generateFieldDef, sanitizeFieldName, toPascalCase, toCamelCase, FIELD_TYPE_MAPPING, } from '../field-mapping.js';
|
|
4
|
+
import { getFieldType, getInlineSchemaReferences, getReferenceTypeModelRefs, generateFieldDef, sanitizeFieldName, toPascalCase, toCamelCase, FIELD_TYPE_MAPPING, } from '../field-mapping.js';
|
|
5
5
|
function isInlineOnlyModel(model) {
|
|
6
6
|
return model.config.inline && !model.config.records;
|
|
7
7
|
}
|
|
@@ -17,7 +17,8 @@ export function generateModelTypes(model, allModels) {
|
|
|
17
17
|
const fields = model.fields ?? [];
|
|
18
18
|
const fieldTypeImports = getFieldTypeImportsForFields(fields);
|
|
19
19
|
const inlineSchemaRefs = getInlineSchemaReferences(fields);
|
|
20
|
-
|
|
20
|
+
const referenceModelRefs = getReferenceTypeModelRefs(fields);
|
|
21
|
+
let code = buildImportStatements(model, fieldTypeImports, inlineSchemaRefs, referenceModelRefs, allModels);
|
|
21
22
|
if (isInlineOnlyModel(model)) {
|
|
22
23
|
code += generateDataInterface(model, fields, typeName, allModels);
|
|
23
24
|
return code;
|
|
@@ -27,7 +28,7 @@ export function generateModelTypes(model, allModels) {
|
|
|
27
28
|
code += generateDataInterface(model, fields, typeName + 'Data', allModels);
|
|
28
29
|
return code;
|
|
29
30
|
}
|
|
30
|
-
function buildImportStatements(model, fieldTypeImports, inlineSchemaRefs, allModels) {
|
|
31
|
+
function buildImportStatements(model, fieldTypeImports, inlineSchemaRefs, referenceModelRefs, allModels) {
|
|
31
32
|
const imports = [];
|
|
32
33
|
if (!isInlineOnlyModel(model)) {
|
|
33
34
|
imports.push("import type { ModelConfig } from '../config.js';");
|
|
@@ -36,7 +37,12 @@ function buildImportStatements(model, fieldTypeImports, inlineSchemaRefs, allMod
|
|
|
36
37
|
const types = Array.from(fieldTypeImports).sort().join(', ');
|
|
37
38
|
imports.push(`import type { ${types} } from '../field-types.js';`);
|
|
38
39
|
}
|
|
39
|
-
|
|
40
|
+
// Collect all model refs (inline schemas + reference type targets) to avoid duplicate imports
|
|
41
|
+
const allModelRefKeys = new Set([
|
|
42
|
+
...inlineSchemaRefs,
|
|
43
|
+
...referenceModelRefs,
|
|
44
|
+
]);
|
|
45
|
+
for (const refKey of allModelRefKeys) {
|
|
40
46
|
if (refKey === model.key)
|
|
41
47
|
continue; // skip self-reference
|
|
42
48
|
const refModel = allModels.find((m) => m.key === refKey);
|
|
@@ -127,6 +133,24 @@ function generateDataInterface(model, fields, interfaceName, allModels) {
|
|
|
127
133
|
fieldType = toPascalCase(field.options.itemType) + 'Data[]';
|
|
128
134
|
}
|
|
129
135
|
}
|
|
136
|
+
// Parameterize ReferenceValue with known reference target types for typed _preview
|
|
137
|
+
if (field.type === 'reference' && field.options?.referenceTypes) {
|
|
138
|
+
const refTypes = field.options.referenceTypes;
|
|
139
|
+
const resolvedPreviewTypes = [];
|
|
140
|
+
for (const refKey of refTypes) {
|
|
141
|
+
const targetModel = allModels.find((m) => m.key === refKey);
|
|
142
|
+
if (targetModel) {
|
|
143
|
+
const targetTypeName = isInlineOnlyModel(targetModel)
|
|
144
|
+
? toPascalCase(refKey)
|
|
145
|
+
: toPascalCase(refKey) + 'Data';
|
|
146
|
+
resolvedPreviewTypes.push(`Partial<${targetTypeName}>`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Only parameterize if all targets resolved — otherwise keep default generic
|
|
150
|
+
if (resolvedPreviewTypes.length === refTypes.length && resolvedPreviewTypes.length > 0) {
|
|
151
|
+
fieldType = `ReferenceValue<${resolvedPreviewTypes.join(' | ')}>`;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
130
154
|
const optional = field.required ? '' : '?';
|
|
131
155
|
const comment = field.helpText ? ` /** ${field.helpText} */\n` : '';
|
|
132
156
|
lines.push(comment + ` ${fieldName}${optional}: ${fieldType};`);
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Generates the shared _common.ts file for typed operations.
|
|
3
3
|
* Contains generic wrapper types used by all per-model operation modules.
|
|
4
4
|
*/
|
|
5
|
-
export declare function generateTypedOperationsCommon(): string;
|
|
5
|
+
export declare function generateTypedOperationsCommon(typesRelPath: string): string;
|
|
6
6
|
//# sourceMappingURL=typed-operations-common.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typed-operations-common.d.ts","sourceRoot":"","sources":["../../../src/codegen/generators/typed-operations-common.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wBAAgB,6BAA6B,
|
|
1
|
+
{"version":3,"file":"typed-operations-common.d.ts","sourceRoot":"","sources":["../../../src/codegen/generators/typed-operations-common.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CA+E1E"}
|
|
@@ -2,20 +2,22 @@
|
|
|
2
2
|
* Generates the shared _common.ts file for typed operations.
|
|
3
3
|
* Contains generic wrapper types used by all per-model operation modules.
|
|
4
4
|
*/
|
|
5
|
-
export function generateTypedOperationsCommon() {
|
|
5
|
+
export function generateTypedOperationsCommon(typesRelPath) {
|
|
6
6
|
return `/**
|
|
7
7
|
* Shared types for typed GraphQL operations.
|
|
8
8
|
*
|
|
9
9
|
* @generated by foir — DO NOT EDIT MANUALLY
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import type { JsonValue } from '${typesRelPath}/field-types.js';
|
|
13
|
+
|
|
12
14
|
/** A record with strongly-typed data. */
|
|
13
15
|
export interface BaseRecord<T> {
|
|
14
16
|
id: string;
|
|
15
17
|
modelKey: string;
|
|
16
18
|
naturalKey: string | null;
|
|
17
19
|
data: T;
|
|
18
|
-
metadata: Record<string,
|
|
20
|
+
metadata: Record<string, JsonValue> | null;
|
|
19
21
|
publishedVersionNumber: number | null;
|
|
20
22
|
publishedAt: string | null;
|
|
21
23
|
versionNumber: number | null;
|
|
@@ -33,7 +35,7 @@ export interface ResolvedContent<T> {
|
|
|
33
35
|
|
|
34
36
|
/** Paginated list result. */
|
|
35
37
|
export interface PaginatedResult<T> {
|
|
36
|
-
items: BaseRecord<T>[];
|
|
38
|
+
items: (BaseRecord<T> & { resolved: ResolvedContent<T> | null })[];
|
|
37
39
|
total: number;
|
|
38
40
|
}
|
|
39
41
|
|
|
@@ -70,5 +72,13 @@ export interface ShareResult {
|
|
|
70
72
|
export interface ShareWithRecord<T> extends ShareResult {
|
|
71
73
|
record: BaseRecord<T>;
|
|
72
74
|
}
|
|
75
|
+
|
|
76
|
+
/** Field selection for resolved content — pick or omit specific fields. */
|
|
77
|
+
export interface FieldSelection<T = Record<string, unknown>> {
|
|
78
|
+
/** Include only these field keys (mutually exclusive with omit) */
|
|
79
|
+
pick?: (keyof T & string)[];
|
|
80
|
+
/** Exclude these field keys (mutually exclusive with omit) */
|
|
81
|
+
omit?: (keyof T & string)[];
|
|
82
|
+
}
|
|
73
83
|
`;
|
|
74
84
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typed-operations.d.ts","sourceRoot":"","sources":["../../../src/codegen/generators/typed-operations.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,YAAY,EACnB,YAAY,EAAE,MAAM,GACnB,MAAM,
|
|
1
|
+
{"version":3,"file":"typed-operations.d.ts","sourceRoot":"","sources":["../../../src/codegen/generators/typed-operations.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,YAAY,EACnB,YAAY,EAAE,MAAM,GACnB,MAAM,CAwRR;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG5E"}
|
|
@@ -21,6 +21,7 @@ export function generateTypedOperations(model, typesRelPath) {
|
|
|
21
21
|
* @generated by foir — DO NOT EDIT MANUALLY
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
+
import type { JsonValue } from '${typesRelPath}/field-types.js';
|
|
24
25
|
import type { ${dataType} } from '${typesRelPath}/models/${model.key}.js';
|
|
25
26
|
import type {
|
|
26
27
|
BaseRecord,
|
|
@@ -28,7 +29,8 @@ import type {
|
|
|
28
29
|
PaginatedResult,
|
|
29
30
|
CreateRecordResult,
|
|
30
31
|
UpdateRecordResult,
|
|
31
|
-
DeleteRecordResult
|
|
32
|
+
DeleteRecordResult,
|
|
33
|
+
FieldSelection,${model.config.sharing?.enabled ? '\n ShareResult,\n ShareWithRecord,' : ''}
|
|
32
34
|
} from './_common.js';
|
|
33
35
|
`);
|
|
34
36
|
// Type alias
|
|
@@ -36,12 +38,12 @@ import type {
|
|
|
36
38
|
lines.push('');
|
|
37
39
|
// GET query
|
|
38
40
|
lines.push(`export const GET_${upperSnake} = \`
|
|
39
|
-
query Get${typeName}($id: ID!, $locale: String, $preview: Boolean) {
|
|
41
|
+
query Get${typeName}($id: ID!, $locale: String, $preview: Boolean, $fields: FieldSelectionInput) {
|
|
40
42
|
record(id: $id) {
|
|
41
43
|
id modelKey naturalKey data metadata
|
|
42
44
|
publishedVersionNumber publishedAt versionNumber changeDescription
|
|
43
45
|
createdAt updatedAt
|
|
44
|
-
resolved(locale: $locale, preview: $preview) {
|
|
46
|
+
resolved(locale: $locale, preview: $preview, fields: $fields) {
|
|
45
47
|
content
|
|
46
48
|
record { id modelKey naturalKey }
|
|
47
49
|
version { id versionNumber }
|
|
@@ -54,6 +56,7 @@ import type {
|
|
|
54
56
|
id: string;
|
|
55
57
|
locale?: string;
|
|
56
58
|
preview?: boolean;
|
|
59
|
+
fields?: FieldSelection<${dataType}>;
|
|
57
60
|
}`);
|
|
58
61
|
lines.push('');
|
|
59
62
|
lines.push(`export interface Get${typeName}Result {
|
|
@@ -64,12 +67,12 @@ import type {
|
|
|
64
67
|
lines.push('');
|
|
65
68
|
// GET BY KEY query
|
|
66
69
|
lines.push(`export const GET_${upperSnake}_BY_KEY = \`
|
|
67
|
-
query Get${typeName}ByKey($naturalKey: String!, $locale: String, $preview: Boolean) {
|
|
70
|
+
query Get${typeName}ByKey($naturalKey: String!, $locale: String, $preview: Boolean, $fields: FieldSelectionInput) {
|
|
68
71
|
recordByKey(modelKey: "${model.key}", naturalKey: $naturalKey) {
|
|
69
72
|
id modelKey naturalKey data metadata
|
|
70
73
|
publishedVersionNumber publishedAt versionNumber changeDescription
|
|
71
74
|
createdAt updatedAt
|
|
72
|
-
resolved(locale: $locale, preview: $preview) {
|
|
75
|
+
resolved(locale: $locale, preview: $preview, fields: $fields) {
|
|
73
76
|
content
|
|
74
77
|
record { id modelKey naturalKey }
|
|
75
78
|
version { id versionNumber }
|
|
@@ -82,6 +85,7 @@ import type {
|
|
|
82
85
|
naturalKey: string;
|
|
83
86
|
locale?: string;
|
|
84
87
|
preview?: boolean;
|
|
88
|
+
fields?: FieldSelection<${dataType}>;
|
|
85
89
|
}`);
|
|
86
90
|
lines.push('');
|
|
87
91
|
lines.push(`export interface Get${typeName}ByKeyResult {
|
|
@@ -92,12 +96,17 @@ import type {
|
|
|
92
96
|
lines.push('');
|
|
93
97
|
// LIST query
|
|
94
98
|
lines.push(`export const LIST_${pluralUpperSnake} = \`
|
|
95
|
-
query List${pluralName}($limit: Int, $offset: Int, $filters: [FilterInput!], $sort: SortInput) {
|
|
99
|
+
query List${pluralName}($limit: Int, $offset: Int, $filters: [FilterInput!], $sort: SortInput, $locale: String, $preview: Boolean, $fields: FieldSelectionInput) {
|
|
96
100
|
records(modelKey: "${model.key}", limit: $limit, offset: $offset, filters: $filters, sort: $sort) {
|
|
97
101
|
items {
|
|
98
102
|
id modelKey naturalKey data metadata
|
|
99
103
|
publishedVersionNumber publishedAt versionNumber changeDescription
|
|
100
104
|
createdAt updatedAt
|
|
105
|
+
resolved(locale: $locale, preview: $preview, fields: $fields) {
|
|
106
|
+
content
|
|
107
|
+
record { id modelKey naturalKey }
|
|
108
|
+
version { id versionNumber }
|
|
109
|
+
}
|
|
101
110
|
}
|
|
102
111
|
total
|
|
103
112
|
}
|
|
@@ -107,8 +116,11 @@ import type {
|
|
|
107
116
|
lines.push(`export interface List${pluralName}Variables {
|
|
108
117
|
limit?: number;
|
|
109
118
|
offset?: number;
|
|
110
|
-
filters?: Array<{ field: string; operator: string; value:
|
|
119
|
+
filters?: Array<{ field: string; operator: string; value: JsonValue }>;
|
|
111
120
|
sort?: { field: string; direction: 'ASC' | 'DESC' };
|
|
121
|
+
locale?: string;
|
|
122
|
+
preview?: boolean;
|
|
123
|
+
fields?: FieldSelection<${dataType}>;
|
|
112
124
|
}`);
|
|
113
125
|
lines.push('');
|
|
114
126
|
lines.push(`export interface List${pluralName}Result {
|
|
@@ -131,7 +143,7 @@ import type {
|
|
|
131
143
|
modelKey: string;
|
|
132
144
|
naturalKey?: string;
|
|
133
145
|
data: Partial<${dataType}>;
|
|
134
|
-
metadata?: Record<string,
|
|
146
|
+
metadata?: Record<string, JsonValue>;
|
|
135
147
|
};
|
|
136
148
|
}`);
|
|
137
149
|
lines.push('');
|
|
@@ -155,7 +167,7 @@ import type {
|
|
|
155
167
|
input: {
|
|
156
168
|
id: string;
|
|
157
169
|
data?: Partial<${dataType}>;
|
|
158
|
-
metadata?: Record<string,
|
|
170
|
+
metadata?: Record<string, JsonValue>;
|
|
159
171
|
changeDescription?: string;
|
|
160
172
|
};
|
|
161
173
|
}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"swift-field-mapping.d.ts","sourceRoot":"","sources":["../../src/codegen/swift-field-mapping.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,MAAM,WAAW,gBAAgB;IAC/B,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,cAAc,EAAE,OAAO,CAAC;IACxB,gFAAgF;IAChF,YAAY,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,cAAc,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"swift-field-mapping.d.ts","sourceRoot":"","sources":["../../src/codegen/swift-field-mapping.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,MAAM,WAAW,gBAAgB;IAC/B,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,cAAc,EAAE,OAAO,CAAC;IACxB,gFAAgF;IAChF,YAAY,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,cAAc,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CA8HrE,CAAC;AAEF;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,GAAG;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAAC;CACvC,CAeA"}
|
|
@@ -124,6 +124,12 @@ export const SWIFT_FIELD_TYPE_MAPPING = {
|
|
|
124
124
|
castExpression: 'as? [String: Any]',
|
|
125
125
|
needsSharedType: true,
|
|
126
126
|
},
|
|
127
|
+
model: {
|
|
128
|
+
type: 'String',
|
|
129
|
+
alwaysOptional: true,
|
|
130
|
+
defaultValue: '""',
|
|
131
|
+
castExpression: 'as? String',
|
|
132
|
+
},
|
|
127
133
|
};
|
|
128
134
|
/**
|
|
129
135
|
* Get the Swift type for a field.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../../src/commands/operations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAkBtD,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,aAAa,GAC9B,IAAI,
|
|
1
|
+
{"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../../src/commands/operations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAkBtD,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,aAAa,GAC9B,IAAI,CA8ZN"}
|
|
@@ -154,6 +154,61 @@ export function registerOperationsCommands(program, globalOpts) {
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
}));
|
|
157
|
+
// quota
|
|
158
|
+
operations
|
|
159
|
+
.command('quota <key>')
|
|
160
|
+
.description('Show quota usage for an operation')
|
|
161
|
+
.option('--json', 'JSON output')
|
|
162
|
+
.action(withErrorHandler(globalOpts, async (key) => {
|
|
163
|
+
const opts = globalOpts();
|
|
164
|
+
const client = await createClient(opts);
|
|
165
|
+
// First get the operation to see its quota rules
|
|
166
|
+
const opData = await client.request(GetOperationDocument, { key });
|
|
167
|
+
if (!opData.operation)
|
|
168
|
+
throw new Error(`Operation "${key}" not found.`);
|
|
169
|
+
const quotas = opData.operation.quotas;
|
|
170
|
+
if (!quotas || quotas.length === 0) {
|
|
171
|
+
if (opts.json || opts.jsonl)
|
|
172
|
+
formatOutput({
|
|
173
|
+
operationKey: key,
|
|
174
|
+
quotas: [],
|
|
175
|
+
message: 'No quotas configured',
|
|
176
|
+
}, opts);
|
|
177
|
+
else
|
|
178
|
+
console.log('No quotas configured for this operation.');
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (opts.json || opts.jsonl) {
|
|
182
|
+
formatOutput({ operationKey: key, quotas }, opts);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
console.log(`\nQuota rules for "${key}":\n`);
|
|
186
|
+
const header = [
|
|
187
|
+
'Segment'.padEnd(20),
|
|
188
|
+
'Scope'.padEnd(10),
|
|
189
|
+
'Limit'.padEnd(8),
|
|
190
|
+
'Window'.padEnd(10),
|
|
191
|
+
].join(' | ');
|
|
192
|
+
console.log(header);
|
|
193
|
+
console.log('-'.repeat(header.length));
|
|
194
|
+
for (const q of quotas) {
|
|
195
|
+
const segment = q.segmentKey ?? '(default)';
|
|
196
|
+
const limit = q.points === 0 ? '\u221e' : String(q.points);
|
|
197
|
+
const window = q.duration >= 86400
|
|
198
|
+
? `${q.duration / 86400}d`
|
|
199
|
+
: q.duration >= 3600
|
|
200
|
+
? `${q.duration / 3600}h`
|
|
201
|
+
: `${q.duration}s`;
|
|
202
|
+
console.log([
|
|
203
|
+
segment.padEnd(20),
|
|
204
|
+
q.scope.padEnd(10),
|
|
205
|
+
limit.padEnd(8),
|
|
206
|
+
window.padEnd(10),
|
|
207
|
+
].join(' | '));
|
|
208
|
+
}
|
|
209
|
+
console.log('');
|
|
210
|
+
}
|
|
211
|
+
}));
|
|
157
212
|
// stats
|
|
158
213
|
operations
|
|
159
214
|
.command('stats <key>')
|
package/dist/commands/pull.js
CHANGED
|
@@ -157,7 +157,7 @@ export function registerPullCommand(program, globalOpts) {
|
|
|
157
157
|
const typesRelPath = computeTypesRelPath(opsDir, typesDir);
|
|
158
158
|
files.push({
|
|
159
159
|
path: resolve(opsDir, '_common.ts'),
|
|
160
|
-
content: generateTypedOperationsCommon(),
|
|
160
|
+
content: generateTypedOperationsCommon(typesRelPath),
|
|
161
161
|
});
|
|
162
162
|
// 7a. Per-model typed operations
|
|
163
163
|
for (const model of publicModels) {
|