@supabase/postgrest-typegen 0.3.1 → 0.5.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 +120 -21
- package/dist/generation/index.d.ts +0 -1
- package/dist/generation/index.js +0 -1
- package/dist/generation/typescript.d.ts +2 -1
- package/dist/generation/typescript.js +205 -400
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/introspection/index.js +3 -1
- package/dist/rpc.d.ts +2 -0
- package/dist/rpc.js +223 -0
- package/dist/sort.js +23 -0
- package/dist/types.d.ts +151 -0
- package/dist/types.js +91 -0
- package/package.json +5 -4
- package/src/generation/index.ts +0 -5
- package/src/generation/typescript.ts +214 -472
- package/src/index.ts +1 -0
- package/src/introspection/index.ts +3 -1
- package/src/rpc.ts +299 -0
- package/src/sort.ts +31 -0
- package/src/types.ts +101 -0
- package/dist/generation/constants.d.ts +0 -9
- package/dist/generation/constants.js +0 -10
- package/dist/generation/swift.d.ts +0 -11
- package/dist/generation/swift.js +0 -358
- package/src/generation/constants.ts +0 -11
- package/src/generation/swift.ts +0 -531
package/src/generation/swift.ts
DELETED
|
@@ -1,531 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
GeneratorMetadata,
|
|
3
|
-
PostgresColumn,
|
|
4
|
-
PostgresForeignTable,
|
|
5
|
-
PostgresMaterializedView,
|
|
6
|
-
PostgresTable,
|
|
7
|
-
PostgresType,
|
|
8
|
-
PostgresView,
|
|
9
|
-
} from "../types.ts";
|
|
10
|
-
import { compareStrings } from "../collation.ts";
|
|
11
|
-
|
|
12
|
-
type Operation = "Select" | "Insert" | "Update";
|
|
13
|
-
export type AccessControl = "internal" | "public" | "private" | "package";
|
|
14
|
-
|
|
15
|
-
export interface GenerateSwiftOptions {
|
|
16
|
-
/** Swift access-control level applied to generated declarations. Default `'internal'`. */
|
|
17
|
-
accessControl?: AccessControl;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
type SwiftGeneratorOptions = {
|
|
21
|
-
accessControl: AccessControl;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
type SwiftEnumCase = {
|
|
25
|
-
formattedName: string;
|
|
26
|
-
rawValue: string;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
type SwiftEnum = {
|
|
30
|
-
formattedEnumName: string;
|
|
31
|
-
protocolConformances: string[];
|
|
32
|
-
cases: SwiftEnumCase[];
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
type SwiftAttribute = {
|
|
36
|
-
formattedAttributeName: string;
|
|
37
|
-
formattedType: string;
|
|
38
|
-
rawName: string;
|
|
39
|
-
isIdentity: boolean;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
type SwiftStruct = {
|
|
43
|
-
formattedStructName: string;
|
|
44
|
-
protocolConformances: string[];
|
|
45
|
-
attributes: SwiftAttribute[];
|
|
46
|
-
codingKeysEnum: SwiftEnum | undefined;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
function formatForSwiftSchemaName(schema: string): string {
|
|
50
|
-
return `${formatForSwiftTypeName(schema)}Schema`;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function pgEnumToSwiftEnum(pgEnum: PostgresType): SwiftEnum {
|
|
54
|
-
return {
|
|
55
|
-
formattedEnumName: formatForSwiftTypeName(pgEnum.name),
|
|
56
|
-
protocolConformances: ["String", "Codable", "Hashable", "Sendable"],
|
|
57
|
-
cases: pgEnum.enums.map((case_) => {
|
|
58
|
-
return {
|
|
59
|
-
formattedName: formatForSwiftPropertyName(case_),
|
|
60
|
-
rawValue: case_,
|
|
61
|
-
};
|
|
62
|
-
}),
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function pgTypeToSwiftStruct(
|
|
67
|
-
table:
|
|
68
|
-
| PostgresTable
|
|
69
|
-
| PostgresForeignTable
|
|
70
|
-
| PostgresView
|
|
71
|
-
| PostgresMaterializedView,
|
|
72
|
-
columns: PostgresColumn[] | undefined,
|
|
73
|
-
operation: Operation,
|
|
74
|
-
{
|
|
75
|
-
types,
|
|
76
|
-
views,
|
|
77
|
-
tables,
|
|
78
|
-
}: { types: PostgresType[]; views: PostgresView[]; tables: PostgresTable[] },
|
|
79
|
-
): SwiftStruct {
|
|
80
|
-
const columnEntries: SwiftAttribute[] =
|
|
81
|
-
columns?.map((column) => {
|
|
82
|
-
let nullable: boolean;
|
|
83
|
-
|
|
84
|
-
if (operation === "Insert") {
|
|
85
|
-
nullable =
|
|
86
|
-
column.is_nullable ||
|
|
87
|
-
column.is_identity ||
|
|
88
|
-
column.is_generated ||
|
|
89
|
-
!!column.default_value;
|
|
90
|
-
} else if (operation === "Update") {
|
|
91
|
-
nullable = true;
|
|
92
|
-
} else {
|
|
93
|
-
nullable = column.is_nullable;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
rawName: column.name,
|
|
98
|
-
formattedAttributeName: formatForSwiftPropertyName(column.name),
|
|
99
|
-
formattedType: pgTypeToSwiftType(column.format, nullable, {
|
|
100
|
-
types,
|
|
101
|
-
views,
|
|
102
|
-
tables,
|
|
103
|
-
}),
|
|
104
|
-
isIdentity: column.is_identity,
|
|
105
|
-
};
|
|
106
|
-
}) ?? [];
|
|
107
|
-
|
|
108
|
-
return {
|
|
109
|
-
formattedStructName: `${formatForSwiftTypeName(table.name)}${operation}`,
|
|
110
|
-
attributes: columnEntries,
|
|
111
|
-
protocolConformances: ["Codable", "Hashable", "Sendable"],
|
|
112
|
-
codingKeysEnum: generateCodingKeysEnumFromAttributes(columnEntries),
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function generateCodingKeysEnumFromAttributes(
|
|
117
|
-
attributes: SwiftAttribute[],
|
|
118
|
-
): SwiftEnum | undefined {
|
|
119
|
-
return attributes.length > 0
|
|
120
|
-
? {
|
|
121
|
-
formattedEnumName: "CodingKeys",
|
|
122
|
-
protocolConformances: ["String", "CodingKey"],
|
|
123
|
-
cases: attributes.map((attribute) => {
|
|
124
|
-
return {
|
|
125
|
-
formattedName: attribute.formattedAttributeName,
|
|
126
|
-
rawValue: attribute.rawName,
|
|
127
|
-
};
|
|
128
|
-
}),
|
|
129
|
-
}
|
|
130
|
-
: undefined;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function pgCompositeTypeToSwiftStruct(
|
|
134
|
-
type: PostgresType,
|
|
135
|
-
{
|
|
136
|
-
types,
|
|
137
|
-
views,
|
|
138
|
-
tables,
|
|
139
|
-
}: { types: PostgresType[]; views: PostgresView[]; tables: PostgresTable[] },
|
|
140
|
-
): SwiftStruct {
|
|
141
|
-
const typeWithRetrievedAttributes = {
|
|
142
|
-
...type,
|
|
143
|
-
attributes: type.attributes.map((attribute) => {
|
|
144
|
-
const type = types.find((type) => type.id === attribute.type_id);
|
|
145
|
-
return {
|
|
146
|
-
...attribute,
|
|
147
|
-
type,
|
|
148
|
-
};
|
|
149
|
-
}),
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const attributeEntries: SwiftAttribute[] =
|
|
153
|
-
typeWithRetrievedAttributes.attributes.map((attribute) => {
|
|
154
|
-
return {
|
|
155
|
-
formattedAttributeName: formatForSwiftTypeName(attribute.name),
|
|
156
|
-
formattedType: pgTypeToSwiftType(attribute.type!.format, false, {
|
|
157
|
-
types,
|
|
158
|
-
views,
|
|
159
|
-
tables,
|
|
160
|
-
}),
|
|
161
|
-
rawName: attribute.name,
|
|
162
|
-
isIdentity: false,
|
|
163
|
-
};
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
return {
|
|
167
|
-
formattedStructName: formatForSwiftTypeName(type.name),
|
|
168
|
-
attributes: attributeEntries,
|
|
169
|
-
protocolConformances: ["Codable", "Hashable", "Sendable"],
|
|
170
|
-
codingKeysEnum: generateCodingKeysEnumFromAttributes(attributeEntries),
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function generateProtocolConformances(protocols: string[]): string {
|
|
175
|
-
return protocols.length === 0 ? "" : `: ${protocols.join(", ")}`;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Serializes a database-provided value as a Swift string literal. Backslashes
|
|
180
|
-
* would otherwise start escape or interpolation sequences (`\(`), double
|
|
181
|
-
* quotes would terminate the literal early, and line breaks or control
|
|
182
|
-
* characters are not allowed in single-line literals, so all of them are
|
|
183
|
-
* escaped per Swift's string literal grammar. U+2028 and U+2029 are legal in
|
|
184
|
-
* Swift literals but are escaped anyway because other tooling mishandles
|
|
185
|
-
* them. Swift unescapes at compile time, so raw values round-trip unchanged.
|
|
186
|
-
*/
|
|
187
|
-
function swiftStringLiteral(value: string): string {
|
|
188
|
-
let escaped = "";
|
|
189
|
-
for (const character of value) {
|
|
190
|
-
switch (character) {
|
|
191
|
-
case "\\":
|
|
192
|
-
escaped += "\\\\";
|
|
193
|
-
break;
|
|
194
|
-
case '"':
|
|
195
|
-
escaped += '\\"';
|
|
196
|
-
break;
|
|
197
|
-
case "\t":
|
|
198
|
-
escaped += "\\t";
|
|
199
|
-
break;
|
|
200
|
-
case "\n":
|
|
201
|
-
escaped += "\\n";
|
|
202
|
-
break;
|
|
203
|
-
case "\r":
|
|
204
|
-
escaped += "\\r";
|
|
205
|
-
break;
|
|
206
|
-
default: {
|
|
207
|
-
const codePoint = character.codePointAt(0)!;
|
|
208
|
-
escaped +=
|
|
209
|
-
codePoint < 0x20 ||
|
|
210
|
-
codePoint === 0x7f ||
|
|
211
|
-
codePoint === 0x2028 ||
|
|
212
|
-
codePoint === 0x2029
|
|
213
|
-
? `\\u{${codePoint.toString(16)}}`
|
|
214
|
-
: character;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
return `"${escaped}"`;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function generateEnum(
|
|
222
|
-
enum_: SwiftEnum,
|
|
223
|
-
{ accessControl, level }: SwiftGeneratorOptions & { level: number },
|
|
224
|
-
): string[] {
|
|
225
|
-
return [
|
|
226
|
-
`${ident(level)}${accessControl} enum ${enum_.formattedEnumName}${generateProtocolConformances(
|
|
227
|
-
enum_.protocolConformances,
|
|
228
|
-
)} {`,
|
|
229
|
-
...enum_.cases.map(
|
|
230
|
-
(case_) =>
|
|
231
|
-
`${ident(level + 1)}case ${case_.formattedName} = ${swiftStringLiteral(case_.rawValue)}`,
|
|
232
|
-
),
|
|
233
|
-
`${ident(level)}}`,
|
|
234
|
-
];
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
function generateStruct(
|
|
238
|
-
struct: SwiftStruct,
|
|
239
|
-
{ accessControl, level }: SwiftGeneratorOptions & { level: number },
|
|
240
|
-
): string[] {
|
|
241
|
-
const identity = struct.attributes.find((column) => column.isIdentity);
|
|
242
|
-
|
|
243
|
-
let protocolConformances = struct.protocolConformances;
|
|
244
|
-
if (identity) {
|
|
245
|
-
protocolConformances.push("Identifiable");
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
let output = [
|
|
249
|
-
`${ident(level)}${accessControl} struct ${struct.formattedStructName}${generateProtocolConformances(
|
|
250
|
-
struct.protocolConformances,
|
|
251
|
-
)} {`,
|
|
252
|
-
];
|
|
253
|
-
|
|
254
|
-
if (identity && identity.formattedAttributeName !== "id") {
|
|
255
|
-
output.push(
|
|
256
|
-
`${ident(level + 1)}${accessControl} var id: ${identity.formattedType} { ${identity.formattedAttributeName} }`,
|
|
257
|
-
);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
output.push(
|
|
261
|
-
...struct.attributes.map(
|
|
262
|
-
(attribute) =>
|
|
263
|
-
`${ident(level + 1)}${accessControl} let ${attribute.formattedAttributeName}: ${attribute.formattedType}`,
|
|
264
|
-
),
|
|
265
|
-
);
|
|
266
|
-
|
|
267
|
-
if (struct.codingKeysEnum) {
|
|
268
|
-
output.push(
|
|
269
|
-
...generateEnum(struct.codingKeysEnum, {
|
|
270
|
-
accessControl,
|
|
271
|
-
level: level + 1,
|
|
272
|
-
}),
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
output.push(`${ident(level)}}`);
|
|
277
|
-
|
|
278
|
-
return output;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Emits tables/views/materialized views in `GeneratorMetadata` order. Pass
|
|
283
|
-
* input pre-sorted with `sortGeneratorMetadata` for deterministic output.
|
|
284
|
-
*/
|
|
285
|
-
export const generateSwift = (
|
|
286
|
-
metadata: GeneratorMetadata,
|
|
287
|
-
opts: GenerateSwiftOptions = {},
|
|
288
|
-
): string => {
|
|
289
|
-
const {
|
|
290
|
-
schemas,
|
|
291
|
-
tables,
|
|
292
|
-
foreignTables,
|
|
293
|
-
views,
|
|
294
|
-
materializedViews,
|
|
295
|
-
columns,
|
|
296
|
-
types,
|
|
297
|
-
} = metadata;
|
|
298
|
-
const { accessControl = "internal" } = opts;
|
|
299
|
-
const columnsByTableId = Object.fromEntries<PostgresColumn[]>(
|
|
300
|
-
[...tables, ...foreignTables, ...views, ...materializedViews].map((t) => [
|
|
301
|
-
t.id,
|
|
302
|
-
[],
|
|
303
|
-
]),
|
|
304
|
-
);
|
|
305
|
-
|
|
306
|
-
for (const column of columns) {
|
|
307
|
-
columnsByTableId[column.table_id]?.push(column);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
let output = [
|
|
311
|
-
"import Foundation",
|
|
312
|
-
"import Supabase",
|
|
313
|
-
"",
|
|
314
|
-
...schemas.flatMap((schema) => {
|
|
315
|
-
const schemaTables = [...tables, ...foreignTables]
|
|
316
|
-
.filter((table) => table.schema === schema.name)
|
|
317
|
-
.sort(({ name: a }, { name: b }) => compareStrings(a, b));
|
|
318
|
-
|
|
319
|
-
const schemaViews = [...views, ...materializedViews]
|
|
320
|
-
.filter((table) => table.schema === schema.name)
|
|
321
|
-
.sort(({ name: a }, { name: b }) => compareStrings(a, b));
|
|
322
|
-
|
|
323
|
-
const schemaEnums = types.filter(
|
|
324
|
-
(type) => type.schema === schema.name && type.enums.length > 0,
|
|
325
|
-
);
|
|
326
|
-
|
|
327
|
-
const schemaCompositeTypes = types.filter(
|
|
328
|
-
(type) => type.schema === schema.name && type.attributes.length > 0,
|
|
329
|
-
);
|
|
330
|
-
|
|
331
|
-
return [
|
|
332
|
-
`${accessControl} enum ${formatForSwiftSchemaName(schema.name)} {`,
|
|
333
|
-
...schemaEnums.flatMap((enum_) =>
|
|
334
|
-
generateEnum(pgEnumToSwiftEnum(enum_), { accessControl, level: 1 }),
|
|
335
|
-
),
|
|
336
|
-
...schemaTables.flatMap((table) =>
|
|
337
|
-
(["Select", "Insert", "Update"] as Operation[])
|
|
338
|
-
.map((operation) =>
|
|
339
|
-
pgTypeToSwiftStruct(
|
|
340
|
-
table,
|
|
341
|
-
columnsByTableId[table.id],
|
|
342
|
-
operation,
|
|
343
|
-
{
|
|
344
|
-
types,
|
|
345
|
-
views,
|
|
346
|
-
tables,
|
|
347
|
-
},
|
|
348
|
-
),
|
|
349
|
-
)
|
|
350
|
-
.flatMap((struct) =>
|
|
351
|
-
generateStruct(struct, { accessControl, level: 1 }),
|
|
352
|
-
),
|
|
353
|
-
),
|
|
354
|
-
...schemaViews.flatMap((view) =>
|
|
355
|
-
generateStruct(
|
|
356
|
-
pgTypeToSwiftStruct(view, columnsByTableId[view.id], "Select", {
|
|
357
|
-
types,
|
|
358
|
-
views,
|
|
359
|
-
tables,
|
|
360
|
-
}),
|
|
361
|
-
{ accessControl, level: 1 },
|
|
362
|
-
),
|
|
363
|
-
),
|
|
364
|
-
...schemaCompositeTypes.flatMap((type) =>
|
|
365
|
-
generateStruct(
|
|
366
|
-
pgCompositeTypeToSwiftStruct(type, { types, views, tables }),
|
|
367
|
-
{
|
|
368
|
-
accessControl,
|
|
369
|
-
level: 1,
|
|
370
|
-
},
|
|
371
|
-
),
|
|
372
|
-
),
|
|
373
|
-
"}",
|
|
374
|
-
];
|
|
375
|
-
}),
|
|
376
|
-
];
|
|
377
|
-
|
|
378
|
-
return `${output.join("\n")}\n`;
|
|
379
|
-
};
|
|
380
|
-
|
|
381
|
-
// TODO: Make this more robust. Currently doesn't handle range types - returns them as string.
|
|
382
|
-
const pgTypeToSwiftType = (
|
|
383
|
-
pgType: string,
|
|
384
|
-
nullable: boolean,
|
|
385
|
-
{
|
|
386
|
-
types,
|
|
387
|
-
views,
|
|
388
|
-
tables,
|
|
389
|
-
}: { types: PostgresType[]; views: PostgresView[]; tables: PostgresTable[] },
|
|
390
|
-
): string => {
|
|
391
|
-
let swiftType: string;
|
|
392
|
-
|
|
393
|
-
if (pgType === "bool") {
|
|
394
|
-
swiftType = "Bool";
|
|
395
|
-
} else if (pgType === "int2") {
|
|
396
|
-
swiftType = "Int16";
|
|
397
|
-
} else if (pgType === "int4") {
|
|
398
|
-
swiftType = "Int32";
|
|
399
|
-
} else if (pgType === "int8") {
|
|
400
|
-
swiftType = "Int64";
|
|
401
|
-
} else if (pgType === "float4") {
|
|
402
|
-
swiftType = "Float";
|
|
403
|
-
} else if (pgType === "float8") {
|
|
404
|
-
swiftType = "Double";
|
|
405
|
-
} else if (["numeric", "decimal"].includes(pgType)) {
|
|
406
|
-
swiftType = "Decimal";
|
|
407
|
-
} else if (pgType === "uuid") {
|
|
408
|
-
swiftType = "UUID";
|
|
409
|
-
} else if (
|
|
410
|
-
[
|
|
411
|
-
"bytea",
|
|
412
|
-
"bpchar",
|
|
413
|
-
"varchar",
|
|
414
|
-
"date",
|
|
415
|
-
"text",
|
|
416
|
-
"citext",
|
|
417
|
-
"time",
|
|
418
|
-
"timetz",
|
|
419
|
-
"timestamp",
|
|
420
|
-
"timestamptz",
|
|
421
|
-
"interval",
|
|
422
|
-
"vector",
|
|
423
|
-
].includes(pgType)
|
|
424
|
-
) {
|
|
425
|
-
swiftType = "String";
|
|
426
|
-
} else if (["json", "jsonb"].includes(pgType)) {
|
|
427
|
-
swiftType = "AnyJSON";
|
|
428
|
-
// `void` and `record` are pseudo-types: Postgres rejects them as a column or
|
|
429
|
-
// composite attribute type ("column has pseudo-type void"), and this
|
|
430
|
-
// generator only renders columns and attributes, never functions. So these
|
|
431
|
-
// two arms are unreachable today and deliberately untested. They are kept
|
|
432
|
-
// because they are the mappings to use if Swift ever emits functions, which
|
|
433
|
-
// is where these types do appear.
|
|
434
|
-
} else if (pgType === "void") {
|
|
435
|
-
swiftType = "Void";
|
|
436
|
-
} else if (pgType === "record") {
|
|
437
|
-
swiftType = "JSONObject";
|
|
438
|
-
} else if (pgType.startsWith("_")) {
|
|
439
|
-
swiftType = `[${pgTypeToSwiftType(pgType.substring(1), false, { types, views, tables })}]`;
|
|
440
|
-
} else {
|
|
441
|
-
const enumType = types.find(
|
|
442
|
-
(type) => type.name === pgType && type.enums.length > 0,
|
|
443
|
-
);
|
|
444
|
-
|
|
445
|
-
const compositeTypes = [...types, ...views, ...tables].find(
|
|
446
|
-
(type) => type.name === pgType,
|
|
447
|
-
);
|
|
448
|
-
|
|
449
|
-
if (enumType) {
|
|
450
|
-
swiftType = `${formatForSwiftTypeName(enumType.name)}`;
|
|
451
|
-
} else if (compositeTypes) {
|
|
452
|
-
// Append a `Select` to the composite type, as that is how is named in the generated struct.
|
|
453
|
-
swiftType = `${formatForSwiftTypeName(compositeTypes.name)}Select`;
|
|
454
|
-
} else {
|
|
455
|
-
swiftType = "AnyJSON";
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
return `${swiftType}${nullable ? "?" : ""}`;
|
|
460
|
-
};
|
|
461
|
-
|
|
462
|
-
function ident(
|
|
463
|
-
level: number,
|
|
464
|
-
options: { width: number } = { width: 2 },
|
|
465
|
-
): string {
|
|
466
|
-
return " ".repeat(level * options.width);
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* Converts a Postgres name to PascalCase.
|
|
471
|
-
*
|
|
472
|
-
* @example
|
|
473
|
-
* ```ts
|
|
474
|
-
* formatForSwiftTypeName('pokedex') // Pokedex
|
|
475
|
-
* formatForSwiftTypeName('pokemon_center') // PokemonCenter
|
|
476
|
-
* formatForSwiftTypeName('victory-road') // VictoryRoad
|
|
477
|
-
* formatForSwiftTypeName('pokemon league') // PokemonLeague
|
|
478
|
-
* formatForSwiftTypeName('_key_id_context') // _KeyIdContext
|
|
479
|
-
* ```
|
|
480
|
-
*/
|
|
481
|
-
function formatForSwiftTypeName(name: string): string {
|
|
482
|
-
// Preserve the initial underscore if it exists
|
|
483
|
-
let prefix = "";
|
|
484
|
-
if (name.startsWith("_")) {
|
|
485
|
-
prefix = "_";
|
|
486
|
-
name = name.slice(1); // Remove the initial underscore for processing
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
return (
|
|
490
|
-
prefix +
|
|
491
|
-
name
|
|
492
|
-
.split(/[^a-zA-Z0-9]+/)
|
|
493
|
-
.map((word) => {
|
|
494
|
-
if (word) {
|
|
495
|
-
return `${word.charAt(0).toUpperCase()}${word.slice(1)}`;
|
|
496
|
-
} else {
|
|
497
|
-
return "";
|
|
498
|
-
}
|
|
499
|
-
})
|
|
500
|
-
.join("")
|
|
501
|
-
);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
const SWIFT_KEYWORDS = ["in", "default", "case"];
|
|
505
|
-
|
|
506
|
-
/**
|
|
507
|
-
* Converts a Postgres name to pascalCase.
|
|
508
|
-
*
|
|
509
|
-
* @example
|
|
510
|
-
* ```ts
|
|
511
|
-
* formatForSwiftTypeName('pokedex') // pokedex
|
|
512
|
-
* formatForSwiftTypeName('pokemon_center') // pokemonCenter
|
|
513
|
-
* formatForSwiftTypeName('victory-road') // victoryRoad
|
|
514
|
-
* formatForSwiftTypeName('pokemon league') // pokemonLeague
|
|
515
|
-
* ```
|
|
516
|
-
*/
|
|
517
|
-
function formatForSwiftPropertyName(name: string): string {
|
|
518
|
-
const propertyName = name
|
|
519
|
-
.split(/[^a-zA-Z0-9]/)
|
|
520
|
-
.map((word, index) => {
|
|
521
|
-
const lowerWord = word.toLowerCase();
|
|
522
|
-
return index !== 0
|
|
523
|
-
? lowerWord.charAt(0).toUpperCase() + lowerWord.slice(1)
|
|
524
|
-
: lowerWord;
|
|
525
|
-
})
|
|
526
|
-
.join("");
|
|
527
|
-
|
|
528
|
-
return SWIFT_KEYWORDS.includes(propertyName)
|
|
529
|
-
? `\`${propertyName}\``
|
|
530
|
-
: propertyName;
|
|
531
|
-
}
|