@eide/foir-cli 0.1.5 → 0.1.6

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.
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Generates a Swift file for the customer profile schema with:
3
+ * - Field key enum (compile-time safe field keys)
4
+ * - Data struct (typed representation)
5
+ * - Serialization helpers (toSyncData / fromSyncData)
6
+ */
7
+ import type { CodegenCustomerProfileSchema } from '../fetch-customer-profile-schema.js';
8
+ export declare function generateSwiftCustomerProfileFile(schema: CodegenCustomerProfileSchema): string;
9
+ //# sourceMappingURL=swift-customer-profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swift-customer-profile.d.ts","sourceRoot":"","sources":["../../../src/codegen/generators/swift-customer-profile.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAC;AAOxF,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,4BAA4B,GACnC,MAAM,CAgCR"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Generates a Swift file for the customer profile schema with:
3
+ * - Field key enum (compile-time safe field keys)
4
+ * - Data struct (typed representation)
5
+ * - Serialization helpers (toSyncData / fromSyncData)
6
+ */
7
+ import { getSwiftFieldType, SWIFT_FIELD_TYPE_MAPPING, } from '../swift-field-mapping.js';
8
+ export function generateSwiftCustomerProfileFile(schema) {
9
+ const typeName = 'CustomerProfile';
10
+ const fields = schema.fields ?? [];
11
+ const lines = [];
12
+ // Header
13
+ lines.push('//');
14
+ lines.push('// CustomerProfile.swift');
15
+ lines.push('//');
16
+ lines.push(`// Generated from customer profile schema (version ${schema.version})`);
17
+ lines.push('//');
18
+ lines.push('// @generated by foir \u2014 DO NOT EDIT MANUALLY');
19
+ lines.push('//');
20
+ lines.push('');
21
+ lines.push('import Foundation');
22
+ lines.push('');
23
+ // 1. Field key enum
24
+ lines.push(generateFieldsEnum(typeName, fields));
25
+ lines.push('');
26
+ // 2. Data struct
27
+ lines.push(generateDataStruct(typeName, fields));
28
+ lines.push('');
29
+ // 3. Serialization extension
30
+ lines.push(generateSerializationExtension(typeName, fields));
31
+ return lines.join('\n');
32
+ }
33
+ function generateFieldsEnum(typeName, fields) {
34
+ const lines = [];
35
+ lines.push(`// MARK: - ${typeName} Field Keys`);
36
+ lines.push('');
37
+ lines.push(`enum ${typeName}Fields {`);
38
+ for (const field of fields) {
39
+ lines.push(` static let ${field.key} = "${field.key}"`);
40
+ }
41
+ lines.push('}');
42
+ return lines.join('\n');
43
+ }
44
+ function generateDataStruct(typeName, fields) {
45
+ const lines = [];
46
+ lines.push(`// MARK: - ${typeName} Data`);
47
+ lines.push('');
48
+ lines.push(`struct ${typeName}Data {`);
49
+ for (const field of fields) {
50
+ const { type, isOptional } = getSwiftFieldType(field);
51
+ const optionalSuffix = isOptional ? '?' : '';
52
+ lines.push(` var ${field.key}: ${type}${optionalSuffix}`);
53
+ }
54
+ lines.push('}');
55
+ return lines.join('\n');
56
+ }
57
+ function generateSerializationExtension(typeName, fields) {
58
+ const lines = [];
59
+ lines.push(`// MARK: - ${typeName} Serialization`);
60
+ lines.push('');
61
+ lines.push(`extension ${typeName}Data {`);
62
+ // toSyncData()
63
+ lines.push(' func toSyncData() -> [String: Any] {');
64
+ const requiredFields = fields.filter((f) => {
65
+ const { isOptional } = getSwiftFieldType(f);
66
+ return !isOptional;
67
+ });
68
+ const optionalFields = fields.filter((f) => {
69
+ const { isOptional } = getSwiftFieldType(f);
70
+ return isOptional;
71
+ });
72
+ if (requiredFields.length > 0) {
73
+ if (optionalFields.length === 0) {
74
+ lines.push(' return [');
75
+ requiredFields.forEach((f, i) => {
76
+ const comma = i < requiredFields.length - 1 ? ',' : '';
77
+ lines.push(` ${typeName}Fields.${f.key}: ${toSyncValueExpr(f)}${comma}`);
78
+ });
79
+ lines.push(' ]');
80
+ }
81
+ else {
82
+ lines.push(' var data: [String: Any] = [');
83
+ requiredFields.forEach((f, i) => {
84
+ const comma = i < requiredFields.length - 1 ? ',' : '';
85
+ lines.push(` ${typeName}Fields.${f.key}: ${toSyncValueExpr(f)}${comma}`);
86
+ });
87
+ lines.push(' ]');
88
+ for (const f of optionalFields) {
89
+ lines.push(` if let ${f.key} { data[${typeName}Fields.${f.key}] = ${toSyncValueExprForOptional(f)} }`);
90
+ }
91
+ lines.push(' return data');
92
+ }
93
+ }
94
+ else {
95
+ lines.push(' var data: [String: Any] = [:]');
96
+ for (const f of optionalFields) {
97
+ lines.push(` if let ${f.key} { data[${typeName}Fields.${f.key}] = ${toSyncValueExprForOptional(f)} }`);
98
+ }
99
+ lines.push(' return data');
100
+ }
101
+ lines.push(' }');
102
+ lines.push('');
103
+ // fromSyncData()
104
+ lines.push(' static func fromSyncData(_ data: [String: Any]) -> ' +
105
+ typeName +
106
+ 'Data {');
107
+ lines.push(` ${typeName}Data(`);
108
+ fields.forEach((field, i) => {
109
+ const comma = i < fields.length - 1 ? ',' : '';
110
+ const { isOptional, mapping } = getSwiftFieldType(field);
111
+ lines.push(` ${field.key}: ${fromSyncDataExpr(field, typeName, isOptional, mapping)}${comma}`);
112
+ });
113
+ lines.push(' )');
114
+ lines.push(' }');
115
+ lines.push('}');
116
+ lines.push('');
117
+ return lines.join('\n');
118
+ }
119
+ function toSyncValueExpr(field) {
120
+ const mapping = SWIFT_FIELD_TYPE_MAPPING[field.type];
121
+ if (mapping?.needsSharedType) {
122
+ return `${field.key}.toSyncData()`;
123
+ }
124
+ return field.key;
125
+ }
126
+ function toSyncValueExprForOptional(field) {
127
+ const mapping = SWIFT_FIELD_TYPE_MAPPING[field.type];
128
+ if (mapping?.needsSharedType) {
129
+ return `${field.key}.toSyncData()`;
130
+ }
131
+ return field.key;
132
+ }
133
+ function fromSyncDataExpr(field, typeName, isOptional, mapping) {
134
+ const accessor = `data[${typeName}Fields.${field.key}]`;
135
+ if (!mapping) {
136
+ return isOptional ? `${accessor}` : `${accessor} ?? nil`;
137
+ }
138
+ if (mapping.needsSharedType) {
139
+ const dictCast = `${accessor} as? [String: Any]`;
140
+ if (isOptional) {
141
+ return `(${dictCast}).map { ${mapping.type}.fromSyncData($0) }`;
142
+ }
143
+ return `${mapping.type}.fromSyncData(${dictCast} ?? [:])`;
144
+ }
145
+ if (field.type === 'json') {
146
+ return isOptional ? accessor : `${accessor}`;
147
+ }
148
+ if (isOptional) {
149
+ return `${accessor} ${mapping.castExpression}`;
150
+ }
151
+ return `${accessor} ${mapping.castExpression} ?? ${mapping.defaultValue}`;
152
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAqBtD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,aAAa,GAC9B,IAAI,CA8KN"}
1
+ {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAsBtD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,aAAa,GAC9B,IAAI,CAsLN"}
@@ -15,6 +15,7 @@ import { generateSwiftModelFile } from '../codegen/generators/swift-types.js';
15
15
  import { generateSwiftFieldTypesFile } from '../codegen/generators/swift-field-types.js';
16
16
  import { generateSwiftModelKeys } from '../codegen/generators/swift-model-keys.js';
17
17
  import { generateCustomerProfileTypes } from '../codegen/generators/customer-profile-types.js';
18
+ import { generateSwiftCustomerProfileFile } from '../codegen/generators/swift-customer-profile.js';
18
19
  import { writeFiles } from '../codegen/write-files.js';
19
20
  export function registerPullCommand(program, globalOpts) {
20
21
  program
@@ -121,6 +122,13 @@ export function registerPullCommand(program, globalOpts) {
121
122
  content: generateSwiftModelFile(model),
122
123
  });
123
124
  }
125
+ // Customer profile Swift file
126
+ if (hasCustomerProfile) {
127
+ files.push({
128
+ path: resolve(swiftDir, 'CustomerProfile.swift'),
129
+ content: generateSwiftCustomerProfileFile(cpSchema),
130
+ });
131
+ }
124
132
  }
125
133
  // Dry run: list files
126
134
  if (config.dryRun) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eide/foir-cli",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Universal platform CLI for EIDE — scriptable, composable resource management",
5
5
  "type": "module",
6
6
  "publishConfig": {