airtable-ts-codegen 2.1.0 → 2.2.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 +12 -0
- package/dist/__fixture__/tablesMeta.json.d.ts +126 -0
- package/dist/__fixture__/tablesMeta.json.js +16 -1
- package/dist/cli.js +5 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -2
- package/dist/jsTypeForAirtableType.d.ts +5 -1
- package/dist/jsTypeForAirtableType.js +22 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,6 +22,18 @@ AIRTABLE_API_KEY=pat1234.abcd AIRTABLE_BASE_ID=app1234 AIRTABLE_VIEW_IDS=viw1234
|
|
|
22
22
|
|
|
23
23
|
This will output a file `app1234.ts` that exports table definitions with only the fields visible in the specified views.
|
|
24
24
|
|
|
25
|
+
### Attachment type (unstable)
|
|
26
|
+
|
|
27
|
+
By default, `multipleAttachments` fields are typed as `string[]` (array of URLs). To get full attachment metadata (id, filename, size, type, etc.), set `UNSTABLE_AIRTABLE_ATTACHMENT_TYPE=Attachment`:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
AIRTABLE_API_KEY=pat1234.abcd AIRTABLE_BASE_ID=app1234 UNSTABLE_AIRTABLE_ATTACHMENT_TYPE=Attachment npx airtable-ts-codegen
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This will generate `Attachment[]` instead of `string[]` for attachment fields, giving you access to the full attachment object with properties like `id`, `url`, `filename`, `size`, `type`, `width`, `height`, and `thumbnails`.
|
|
34
|
+
|
|
35
|
+
> **Note:** This option is unstable and may change or be removed in future versions.
|
|
36
|
+
|
|
25
37
|
<details>
|
|
26
38
|
<summary>Example generated file</summary>
|
|
27
39
|
|
|
@@ -35,6 +35,8 @@ export declare const tablesMeta: {
|
|
|
35
35
|
isValid?: never;
|
|
36
36
|
formula?: never;
|
|
37
37
|
result?: never;
|
|
38
|
+
recordLinkFieldId?: never;
|
|
39
|
+
fieldIdInLinkedTable?: never;
|
|
38
40
|
};
|
|
39
41
|
id: string;
|
|
40
42
|
name: string;
|
|
@@ -58,6 +60,8 @@ export declare const tablesMeta: {
|
|
|
58
60
|
isValid?: never;
|
|
59
61
|
formula?: never;
|
|
60
62
|
result?: never;
|
|
63
|
+
recordLinkFieldId?: never;
|
|
64
|
+
fieldIdInLinkedTable?: never;
|
|
61
65
|
};
|
|
62
66
|
id: string;
|
|
63
67
|
name: string;
|
|
@@ -85,6 +89,8 @@ export declare const tablesMeta: {
|
|
|
85
89
|
isValid?: never;
|
|
86
90
|
formula?: never;
|
|
87
91
|
result?: never;
|
|
92
|
+
recordLinkFieldId?: never;
|
|
93
|
+
fieldIdInLinkedTable?: never;
|
|
88
94
|
};
|
|
89
95
|
id: string;
|
|
90
96
|
name: string;
|
|
@@ -108,6 +114,8 @@ export declare const tablesMeta: {
|
|
|
108
114
|
isValid?: never;
|
|
109
115
|
formula?: never;
|
|
110
116
|
result?: never;
|
|
117
|
+
recordLinkFieldId?: never;
|
|
118
|
+
fieldIdInLinkedTable?: never;
|
|
111
119
|
};
|
|
112
120
|
id: string;
|
|
113
121
|
name: string;
|
|
@@ -134,6 +142,8 @@ export declare const tablesMeta: {
|
|
|
134
142
|
isValid?: never;
|
|
135
143
|
formula?: never;
|
|
136
144
|
result?: never;
|
|
145
|
+
recordLinkFieldId?: never;
|
|
146
|
+
fieldIdInLinkedTable?: never;
|
|
137
147
|
};
|
|
138
148
|
id: string;
|
|
139
149
|
name: string;
|
|
@@ -163,6 +173,8 @@ export declare const tablesMeta: {
|
|
|
163
173
|
isValid?: never;
|
|
164
174
|
formula?: never;
|
|
165
175
|
result?: never;
|
|
176
|
+
recordLinkFieldId?: never;
|
|
177
|
+
fieldIdInLinkedTable?: never;
|
|
166
178
|
};
|
|
167
179
|
id: string;
|
|
168
180
|
name: string;
|
|
@@ -186,6 +198,8 @@ export declare const tablesMeta: {
|
|
|
186
198
|
isValid?: never;
|
|
187
199
|
formula?: never;
|
|
188
200
|
result?: never;
|
|
201
|
+
recordLinkFieldId?: never;
|
|
202
|
+
fieldIdInLinkedTable?: never;
|
|
189
203
|
};
|
|
190
204
|
id: string;
|
|
191
205
|
name: string;
|
|
@@ -209,6 +223,8 @@ export declare const tablesMeta: {
|
|
|
209
223
|
isValid?: never;
|
|
210
224
|
formula?: never;
|
|
211
225
|
result?: never;
|
|
226
|
+
recordLinkFieldId?: never;
|
|
227
|
+
fieldIdInLinkedTable?: never;
|
|
212
228
|
};
|
|
213
229
|
id: string;
|
|
214
230
|
name: string;
|
|
@@ -232,6 +248,8 @@ export declare const tablesMeta: {
|
|
|
232
248
|
isValid?: never;
|
|
233
249
|
formula?: never;
|
|
234
250
|
result?: never;
|
|
251
|
+
recordLinkFieldId?: never;
|
|
252
|
+
fieldIdInLinkedTable?: never;
|
|
235
253
|
};
|
|
236
254
|
id: string;
|
|
237
255
|
name: string;
|
|
@@ -255,6 +273,8 @@ export declare const tablesMeta: {
|
|
|
255
273
|
isValid?: never;
|
|
256
274
|
formula?: never;
|
|
257
275
|
result?: never;
|
|
276
|
+
recordLinkFieldId?: never;
|
|
277
|
+
fieldIdInLinkedTable?: never;
|
|
258
278
|
};
|
|
259
279
|
id: string;
|
|
260
280
|
name: string;
|
|
@@ -281,6 +301,8 @@ export declare const tablesMeta: {
|
|
|
281
301
|
symbol?: never;
|
|
282
302
|
durationFormat?: never;
|
|
283
303
|
max?: never;
|
|
304
|
+
recordLinkFieldId?: never;
|
|
305
|
+
fieldIdInLinkedTable?: never;
|
|
284
306
|
};
|
|
285
307
|
id: string;
|
|
286
308
|
name: string;
|
|
@@ -300,6 +322,8 @@ export declare const tablesMeta: {
|
|
|
300
322
|
format: string;
|
|
301
323
|
};
|
|
302
324
|
timeZone: string;
|
|
325
|
+
precision?: never;
|
|
326
|
+
choices?: never;
|
|
303
327
|
};
|
|
304
328
|
};
|
|
305
329
|
choices?: never;
|
|
@@ -317,6 +341,8 @@ export declare const tablesMeta: {
|
|
|
317
341
|
max?: never;
|
|
318
342
|
isValid?: never;
|
|
319
343
|
formula?: never;
|
|
344
|
+
recordLinkFieldId?: never;
|
|
345
|
+
fieldIdInLinkedTable?: never;
|
|
320
346
|
};
|
|
321
347
|
id: string;
|
|
322
348
|
name: string;
|
|
@@ -338,6 +364,8 @@ export declare const tablesMeta: {
|
|
|
338
364
|
format: string;
|
|
339
365
|
};
|
|
340
366
|
timeZone: string;
|
|
367
|
+
precision?: never;
|
|
368
|
+
choices?: never;
|
|
341
369
|
};
|
|
342
370
|
};
|
|
343
371
|
choices?: never;
|
|
@@ -353,6 +381,104 @@ export declare const tablesMeta: {
|
|
|
353
381
|
durationFormat?: never;
|
|
354
382
|
max?: never;
|
|
355
383
|
formula?: never;
|
|
384
|
+
recordLinkFieldId?: never;
|
|
385
|
+
fieldIdInLinkedTable?: never;
|
|
386
|
+
};
|
|
387
|
+
id: string;
|
|
388
|
+
name: string;
|
|
389
|
+
description?: never;
|
|
390
|
+
} | {
|
|
391
|
+
type: string;
|
|
392
|
+
options: {
|
|
393
|
+
isValid: boolean;
|
|
394
|
+
recordLinkFieldId: string;
|
|
395
|
+
fieldIdInLinkedTable: string;
|
|
396
|
+
result: {
|
|
397
|
+
type: string;
|
|
398
|
+
options?: never;
|
|
399
|
+
};
|
|
400
|
+
choices?: never;
|
|
401
|
+
isReversed?: never;
|
|
402
|
+
referencedFieldIds?: never;
|
|
403
|
+
prompt?: never;
|
|
404
|
+
icon?: never;
|
|
405
|
+
color?: never;
|
|
406
|
+
dateFormat?: never;
|
|
407
|
+
timeFormat?: never;
|
|
408
|
+
timeZone?: never;
|
|
409
|
+
precision?: never;
|
|
410
|
+
symbol?: never;
|
|
411
|
+
durationFormat?: never;
|
|
412
|
+
max?: never;
|
|
413
|
+
formula?: never;
|
|
414
|
+
};
|
|
415
|
+
id: string;
|
|
416
|
+
name: string;
|
|
417
|
+
description?: never;
|
|
418
|
+
} | {
|
|
419
|
+
type: string;
|
|
420
|
+
options: {
|
|
421
|
+
isValid: boolean;
|
|
422
|
+
recordLinkFieldId: string;
|
|
423
|
+
fieldIdInLinkedTable: string;
|
|
424
|
+
result: {
|
|
425
|
+
type: string;
|
|
426
|
+
options: {
|
|
427
|
+
precision: number;
|
|
428
|
+
dateFormat?: never;
|
|
429
|
+
timeFormat?: never;
|
|
430
|
+
timeZone?: never;
|
|
431
|
+
choices?: never;
|
|
432
|
+
};
|
|
433
|
+
};
|
|
434
|
+
choices?: never;
|
|
435
|
+
isReversed?: never;
|
|
436
|
+
referencedFieldIds?: never;
|
|
437
|
+
prompt?: never;
|
|
438
|
+
icon?: never;
|
|
439
|
+
color?: never;
|
|
440
|
+
dateFormat?: never;
|
|
441
|
+
timeFormat?: never;
|
|
442
|
+
timeZone?: never;
|
|
443
|
+
precision?: never;
|
|
444
|
+
symbol?: never;
|
|
445
|
+
durationFormat?: never;
|
|
446
|
+
max?: never;
|
|
447
|
+
formula?: never;
|
|
448
|
+
};
|
|
449
|
+
id: string;
|
|
450
|
+
name: string;
|
|
451
|
+
description?: never;
|
|
452
|
+
} | {
|
|
453
|
+
type: string;
|
|
454
|
+
options: {
|
|
455
|
+
isValid: boolean;
|
|
456
|
+
recordLinkFieldId: string;
|
|
457
|
+
fieldIdInLinkedTable: string;
|
|
458
|
+
result: {
|
|
459
|
+
type: string;
|
|
460
|
+
options: {
|
|
461
|
+
choices: never[];
|
|
462
|
+
dateFormat?: never;
|
|
463
|
+
timeFormat?: never;
|
|
464
|
+
timeZone?: never;
|
|
465
|
+
precision?: never;
|
|
466
|
+
};
|
|
467
|
+
};
|
|
468
|
+
choices?: never;
|
|
469
|
+
isReversed?: never;
|
|
470
|
+
referencedFieldIds?: never;
|
|
471
|
+
prompt?: never;
|
|
472
|
+
icon?: never;
|
|
473
|
+
color?: never;
|
|
474
|
+
dateFormat?: never;
|
|
475
|
+
timeFormat?: never;
|
|
476
|
+
timeZone?: never;
|
|
477
|
+
precision?: never;
|
|
478
|
+
symbol?: never;
|
|
479
|
+
durationFormat?: never;
|
|
480
|
+
max?: never;
|
|
481
|
+
formula?: never;
|
|
356
482
|
};
|
|
357
483
|
id: string;
|
|
358
484
|
name: string;
|
|
@@ -63,7 +63,22 @@ exports.tablesMeta = {
|
|
|
63
63
|
{ type: 'createdBy', id: 'fldDcRoVGJXIhVSAi', name: 'Created By' },
|
|
64
64
|
{ type: 'autoNumber', id: 'fldGM8wIYk3G8WMiE', name: 'ID' },
|
|
65
65
|
{ type: 'barcode', id: 'fldMPs1eLH8X5bWeS', name: 'Barcode' },
|
|
66
|
-
{ type: 'button', id: 'fldAG3LTbJRwQVEvS', name: 'Button' }
|
|
66
|
+
{ type: 'button', id: 'fldAG3LTbJRwQVEvS', name: 'Button' },
|
|
67
|
+
{
|
|
68
|
+
type: 'multipleLookupValues', options: {
|
|
69
|
+
isValid: true, recordLinkFieldId: 'fldLinked', fieldIdInLinkedTable: 'fldName', result: { type: 'singleLineText' },
|
|
70
|
+
}, id: 'fldLookupText', name: 'Lookup Text',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
type: 'multipleLookupValues', options: {
|
|
74
|
+
isValid: true, recordLinkFieldId: 'fldLinked', fieldIdInLinkedTable: 'fldNumber', result: { type: 'number', options: { precision: 0 } },
|
|
75
|
+
}, id: 'fldLookupNumber', name: 'Lookup Number',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
type: 'multipleLookupValues', options: {
|
|
79
|
+
isValid: true, recordLinkFieldId: 'fldLinked', fieldIdInLinkedTable: 'fldTags', result: { type: 'multipleSelects', options: { choices: [] } },
|
|
80
|
+
}, id: 'fldLookupTags', name: 'Lookup Tags',
|
|
81
|
+
}],
|
|
67
82
|
views: [],
|
|
68
83
|
}],
|
|
69
84
|
};
|
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,11 @@ if (!baseId) {
|
|
|
13
13
|
throw new Error('No Airtable base id set. Make sure the AIRTABLE_BASE_ID environment variable is set.');
|
|
14
14
|
}
|
|
15
15
|
const viewIds = process.env.AIRTABLE_VIEW_IDS;
|
|
16
|
-
const
|
|
16
|
+
const unstableAttachmentTypeEnv = process.env.UNSTABLE_AIRTABLE_ATTACHMENT_TYPE;
|
|
17
|
+
const unstable_attachmentType = unstableAttachmentTypeEnv === 'Attachment' ? 'Attachment' : 'string';
|
|
18
|
+
const config = {
|
|
19
|
+
apiKey, baseId, ...(viewIds && { viewIds: viewIds.split(',') }), unstable_attachmentType,
|
|
20
|
+
};
|
|
17
21
|
const generateCode = async () => {
|
|
18
22
|
console.log(`Generating TypeScript definitions for base ${baseId}${viewIds ? ` with views ${viewIds}` : ''}...`);
|
|
19
23
|
return (0, _1.main)(config);
|
package/dist/index.d.ts
CHANGED
|
@@ -5,5 +5,13 @@ export type Config = {
|
|
|
5
5
|
endpointUrl?: string;
|
|
6
6
|
requestTimeout?: number;
|
|
7
7
|
customHeaders?: Record<string, string | number | boolean>;
|
|
8
|
+
/**
|
|
9
|
+
* Type to use for multipleAttachments fields.
|
|
10
|
+
* - 'string': generates `string[]` (array of URLs only)
|
|
11
|
+
* - 'Attachment': generates `Attachment[]` (full metadata including id, filename, size, etc.)
|
|
12
|
+
* @default 'string'
|
|
13
|
+
* @unstable This option may change or be removed in future versions.
|
|
14
|
+
*/
|
|
15
|
+
unstable_attachmentType?: 'string' | 'Attachment';
|
|
8
16
|
};
|
|
9
17
|
export declare const main: (config: Config) => Promise<string>;
|
package/dist/index.js
CHANGED
|
@@ -11,10 +11,15 @@ const view_1 = require("./view");
|
|
|
11
11
|
const main = async (config) => {
|
|
12
12
|
const baseSchema = await (0, getBaseSchema_1.getBaseSchema)(config.baseId, config);
|
|
13
13
|
const filteredBaseSchema = await (0, view_1.filterBaseSchemaByView)(baseSchema, config);
|
|
14
|
+
// Determine if we need to import Attachment type
|
|
15
|
+
const useAttachmentType = config.unstable_attachmentType === 'Attachment';
|
|
16
|
+
const importTypes = useAttachmentType
|
|
17
|
+
? 'import type { Attachment, Item, Table } from \'airtable-ts\';'
|
|
18
|
+
: 'import type { Item, Table } from \'airtable-ts\';';
|
|
14
19
|
return [
|
|
15
20
|
'/* DO NOT EDIT: this file was automatically generated by airtable-ts-codegen */',
|
|
16
21
|
'/* eslint-disable */',
|
|
17
|
-
|
|
22
|
+
importTypes,
|
|
18
23
|
'',
|
|
19
24
|
filteredBaseSchema.map((tableSchema) => generateCode(config, tableSchema)).join('\n\n'),
|
|
20
25
|
].join('\n');
|
|
@@ -45,11 +50,12 @@ const generateCode = (config, tableSchema) => {
|
|
|
45
50
|
const itemNameRaw = (0, escapeIdentifier_1.escapeIdentifier)((0, recase_1.recase)(null, 'pascal', tableSchema.name));
|
|
46
51
|
const itemName = /.s$/.test(itemNameRaw) ? itemNameRaw.slice(0, itemNameRaw.length - 1) : itemNameRaw;
|
|
47
52
|
const tableName = (0, escapeIdentifier_1.escapeIdentifier)(`${(0, recase_1.recase)(null, 'camel', tableSchema.name)}Table`);
|
|
53
|
+
const jsTypeOptions = { attachmentType: config.unstable_attachmentType };
|
|
48
54
|
const fields = tableSchema.fields.map((f) => ({
|
|
49
55
|
...f,
|
|
50
56
|
originalName: f.name,
|
|
51
57
|
jsName: (0, escapeIdentifier_1.escapeIdentifier)((0, recase_1.recase)(null, 'camel', (0, escapeIdentifier_1.escapeIdentifier)(f.name))),
|
|
52
|
-
jsType: (0, jsTypeForAirtableType_1.jsTypeForAirtableType)(f),
|
|
58
|
+
jsType: (0, jsTypeForAirtableType_1.jsTypeForAirtableType)(f, jsTypeOptions),
|
|
53
59
|
}));
|
|
54
60
|
return `export interface ${itemName} extends Item {
|
|
55
61
|
id: string,${fields.map(generateInterfaceEntry).join('')}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { type FieldSchema } from './getBaseSchema';
|
|
2
|
+
export type JsTypeOptions = {
|
|
3
|
+
/** Type to use for multipleAttachments fields */
|
|
4
|
+
attachmentType?: 'string' | 'Attachment' | undefined;
|
|
5
|
+
};
|
|
2
6
|
/**
|
|
3
7
|
* Returns the corresponding Typescript type for the given Airtable field type.
|
|
4
8
|
*
|
|
5
9
|
* Unsupported fields return `null` and will be filtered out by the caller.
|
|
6
10
|
*/
|
|
7
|
-
export declare const jsTypeForAirtableType: (field: FieldSchema) => string | null;
|
|
11
|
+
export declare const jsTypeForAirtableType: (field: FieldSchema, options?: JsTypeOptions) => string | null;
|
|
@@ -6,7 +6,7 @@ exports.jsTypeForAirtableType = void 0;
|
|
|
6
6
|
*
|
|
7
7
|
* Unsupported fields return `null` and will be filtered out by the caller.
|
|
8
8
|
*/
|
|
9
|
-
const jsTypeForAirtableType = (field) => {
|
|
9
|
+
const jsTypeForAirtableType = (field, options = {}) => {
|
|
10
10
|
switch (field.type) {
|
|
11
11
|
case 'url':
|
|
12
12
|
case 'email':
|
|
@@ -25,6 +25,7 @@ const jsTypeForAirtableType = (field) => {
|
|
|
25
25
|
case 'createdBy':
|
|
26
26
|
return 'string';
|
|
27
27
|
case 'multipleAttachments':
|
|
28
|
+
return options.attachmentType === 'Attachment' ? 'Attachment[]' : 'string[]';
|
|
28
29
|
case 'multipleCollaborators':
|
|
29
30
|
case 'multipleRecordLinks':
|
|
30
31
|
case 'multipleSelects':
|
|
@@ -46,15 +47,33 @@ const jsTypeForAirtableType = (field) => {
|
|
|
46
47
|
return 'number'; // Unix timestamp in seconds
|
|
47
48
|
case 'checkbox':
|
|
48
49
|
return 'boolean';
|
|
49
|
-
case 'lookup':
|
|
50
50
|
case 'multipleLookupValues':
|
|
51
|
+
if (field.options
|
|
52
|
+
&& 'result' in field.options
|
|
53
|
+
&& typeof field.options.result === 'object'
|
|
54
|
+
&& field.options.result !== null) {
|
|
55
|
+
const innerType = (0, exports.jsTypeForAirtableType)(field.options.result, options);
|
|
56
|
+
if (innerType === null) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
// multipleLookupValues always returns an array
|
|
60
|
+
// Strip nullability from inner type since the array itself represents empty state
|
|
61
|
+
const baseType = innerType.replace(/ \| null$/, '').replace(/^null \| /, '');
|
|
62
|
+
// If inner type is already an array, Airtable flattens lookup results
|
|
63
|
+
if (baseType.endsWith('[]')) {
|
|
64
|
+
return baseType;
|
|
65
|
+
}
|
|
66
|
+
return `${baseType}[]`;
|
|
67
|
+
}
|
|
68
|
+
throw new Error(`Invalid ${field.type} field (no options.result): ${field.id}`);
|
|
69
|
+
case 'lookup':
|
|
51
70
|
case 'rollup':
|
|
52
71
|
case 'formula':
|
|
53
72
|
if (field.options
|
|
54
73
|
&& 'result' in field.options
|
|
55
74
|
&& typeof field.options.result === 'object'
|
|
56
75
|
&& field.options.result !== null) {
|
|
57
|
-
const innerType = (0, exports.jsTypeForAirtableType)(field.options.result);
|
|
76
|
+
const innerType = (0, exports.jsTypeForAirtableType)(field.options.result, options);
|
|
58
77
|
if (innerType === null) {
|
|
59
78
|
return null;
|
|
60
79
|
}
|