Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

airtable-ts

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

airtable-ts - npm Package Compare versions

Comparing version 1.3.0 to 1.3.1

2

dist/mapping/fieldMappers.d.ts
import { AirtableTypeString, FromAirtableTypeString, FromTsTypeString, TsTypeString } from './typeUtils';
type Mapper = {
[T in TsTypeString]?: {
[A in AirtableTypeString]?: {
[A in AirtableTypeString | 'unknown']?: {
toAirtable: (value: FromTsTypeString<T>) => FromAirtableTypeString<A>;

@@ -6,0 +6,0 @@ fromAirtable: (value: FromAirtableTypeString<A> | null | undefined) => FromTsTypeString<T>;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fieldMappers = void 0;
const required = (value) => {
if (value === null || value === undefined) {
throw new Error('[airtable-ts] Missing required value');
}
return value;
};
const typeUtils_1 = require("./typeUtils");
const fallbackMapperPair = (toFallback, fromFallback) => ({

@@ -14,147 +9,47 @@ toAirtable: (value) => value ?? toFallback,

});
const requiredMapperPair = {
toAirtable: (value) => required(value),
fromAirtable: (value) => required(value),
const dateTimeMapperPair = {
// Number assumed to be unix time in seconds
toAirtable: (value) => {
if (value === null)
return null;
const date = new Date(typeof value === 'number' ? value * 1000 : value);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return date.toJSON();
},
fromAirtable: (value) => {
if (value === null || value === undefined)
return null;
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return date.toJSON();
},
};
exports.fieldMappers = {
string: {
url: fallbackMapperPair('', ''),
email: fallbackMapperPair('', ''),
phoneNumber: fallbackMapperPair('', ''),
singleLineText: fallbackMapperPair('', ''),
multilineText: fallbackMapperPair('', ''),
richText: fallbackMapperPair('', ''),
singleSelect: fallbackMapperPair('', ''),
externalSyncSource: {
toAirtable: () => { throw new Error('[airtable-ts] externalSyncSource type field is readonly'); },
fromAirtable: (value) => value ?? '',
},
multipleSelects: {
toAirtable: (value) => {
return [value];
},
fromAirtable: (value) => {
if (!value) {
throw new Error('[airtable-ts] Failed to coerce multipleSelects type field to a single string, as it was blank');
}
if (value.length !== 1) {
throw new Error(`[airtable-ts] Can't coerce multipleSelects to a single string, as there were ${value?.length} entries`);
}
return value[0];
},
},
multipleRecordLinks: {
toAirtable: (value) => {
return [value];
},
fromAirtable: (value) => {
if (!value) {
throw new Error('[airtable-ts] Failed to coerce multipleRecordLinks type field to a single string, as it was blank');
}
if (value.length !== 1) {
throw new Error(`[airtable-ts] Can't coerce multipleRecordLinks to a single string, as there were ${value?.length} entries`);
}
return value[0];
},
},
date: {
toAirtable: (value) => {
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid date string');
}
return date.toJSON().slice(0, 10);
},
fromAirtable: (value) => {
const date = new Date(value ?? '');
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid date string');
}
return date.toJSON();
},
},
dateTime: {
toAirtable: (value) => {
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime string');
}
return date.toJSON();
},
fromAirtable: (value) => {
const date = new Date(value ?? '');
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime string');
}
return date.toJSON();
},
},
createdTime: {
toAirtable: (value) => {
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime string');
}
return date.toJSON();
},
fromAirtable: (value) => {
const date = new Date(value ?? '');
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime string');
}
return date.toJSON();
},
},
lastModifiedTime: {
toAirtable: (value) => {
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime string');
}
return date.toJSON();
},
fromAirtable: (value) => {
const date = new Date(value ?? '');
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime string');
}
return date.toJSON();
},
},
multipleLookupValues: {
toAirtable: () => { throw new Error('[airtable-ts] lookup type field is readonly'); },
fromAirtable: (value) => {
if (!value) {
throw new Error('[airtable-ts] Failed to coerce lookup type field to a single string, as it was blank');
}
if (value.length !== 1) {
throw new Error(`[airtable-ts] Can't coerce lookup to a single string, as there were ${value?.length} entries`);
}
if (typeof value[0] !== 'string') {
throw new Error(`[airtable-ts] Can't coerce singular lookup to a single string, as it was of type ${typeof value[0]}`);
}
return value[0];
},
},
rollup: {
toAirtable: () => { throw new Error('[airtable-ts] rollup type field is readonly'); },
fromAirtable: (value) => {
if (typeof value === 'string')
return value;
if (value === undefined || value === null)
return '';
throw new Error(`[airtable-ts] Can't coerce rollup to a string, as it was of type ${typeof value}`);
},
},
formula: {
toAirtable: () => { throw new Error('[airtable-ts] formula type field is readonly'); },
fromAirtable: (value) => {
if (typeof value === 'string')
return value;
if (value === undefined || value === null)
return '';
throw new Error(`[airtable-ts] Can't coerce formula to a string, as it was of type ${typeof value}`);
},
},
},
const readonly = (airtableType) => () => { throw new Error(`[airtable-ts] ${airtableType} type field is readonly`); };
const coerce = (airtableType, tsType) => (value) => {
const parsedType = (0, typeUtils_1.parseType)(tsType);
if (!parsedType.array && typeof value === parsedType.single) {
return value;
}
if (parsedType.array && Array.isArray(value) && value.every((v) => typeof v === parsedType.single)) {
return value;
}
if (parsedType.nullable && (value === undefined || value === null || (Array.isArray(value) && value.length === 0))) {
return null;
}
if (parsedType.array && typeof value === parsedType.single) {
return [value];
}
if (!parsedType.array && Array.isArray(value) && value.length === 1 && typeof value[0] === parsedType.single) {
return value[0];
}
if (!parsedType.array && Array.isArray(value) && value.length !== 1) {
throw new Error(`[airtable-ts] Can't coerce ${airtableType} to a ${tsType}, as there were ${value.length} array entries`);
}
throw new Error(`[airtable-ts] Can't coerce ${airtableType} to a ${tsType}, as it was of type ${typeof value}`);
};
const stringOrNull = {
'string | null': {

@@ -168,298 +63,53 @@ url: fallbackMapperPair(null, null),

singleSelect: fallbackMapperPair(null, null),
externalSyncSource: {
toAirtable: () => { throw new Error('[airtable-ts] externalSyncSource type field is readonly'); },
fromAirtable: (value) => value ?? null,
},
multipleSelects: {
toAirtable: (value) => {
return value ? [value] : [];
},
fromAirtable: (value) => {
if (!value || value.length === 0) {
return null;
}
if (value.length !== 1) {
throw new Error(`[airtable-ts] Can't coerce multipleSelects to a single string, as there were ${value?.length} entries`);
}
return value[0];
},
toAirtable: (value) => (value ? [value] : []),
fromAirtable: coerce('multipleSelects', 'string | null'),
},
multipleRecordLinks: {
toAirtable: (value) => {
return value ? [value] : [];
},
fromAirtable: (value) => {
if (!value || value.length === 0) {
return null;
}
if (value.length !== 1) {
throw new Error(`[airtable-ts] Can't coerce multipleRecordLinks to a single string, as there were ${value?.length} entries`);
}
return value[0];
},
toAirtable: (value) => (value ? [value] : []),
fromAirtable: coerce('multipleRecordLinks', 'string | null'),
},
date: {
toAirtable: (value) => {
if (value === null)
return null;
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid date');
}
return date.toJSON().slice(0, 10);
},
fromAirtable: (value) => {
if (value === null || value === undefined)
return null;
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid date');
}
return date.toJSON();
},
toAirtable: (value) => dateTimeMapperPair.toAirtable(value)?.slice(0, 10) ?? null,
fromAirtable: dateTimeMapperPair.fromAirtable,
},
dateTime: {
toAirtable: (value) => {
if (value === null)
return null;
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return date.toJSON();
},
fromAirtable: (value) => {
if (value === null || value === undefined)
return null;
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return date.toJSON();
},
dateTime: dateTimeMapperPair,
createdTime: dateTimeMapperPair,
lastModifiedTime: dateTimeMapperPair,
multipleLookupValues: {
toAirtable: readonly('multipleLookupValues'),
fromAirtable: coerce('multipleLookupValues', 'string | null'),
},
createdTime: {
toAirtable: (value) => {
if (value === null)
return null;
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return date.toJSON();
},
fromAirtable: (value) => {
if (value === null || value === undefined)
return null;
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return date.toJSON();
},
externalSyncSource: {
toAirtable: readonly('externalSyncSource'),
fromAirtable: coerce('externalSyncSource', 'string | null'),
},
lastModifiedTime: {
toAirtable: (value) => {
if (value === null)
return null;
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return date.toJSON();
},
fromAirtable: (value) => {
if (value === null || value === undefined)
return null;
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return date.toJSON();
},
},
multipleLookupValues: {
toAirtable: () => { throw new Error('[airtable-ts] lookup type field is readonly'); },
fromAirtable: (value) => {
if (!value || value.length === 0) {
return null;
}
if (value.length !== 1) {
throw new Error(`[airtable-ts] Can't coerce lookup to a single string, as there were ${value?.length} entries`);
}
if (typeof value[0] !== 'string') {
throw new Error(`[airtable-ts] Can't coerce singular lookup to a single string, as it was of type ${typeof value[0]}`);
}
return value[0];
},
},
rollup: {
toAirtable: () => { throw new Error('[airtable-ts] rollup type field is readonly'); },
fromAirtable: (value) => {
if (typeof value === 'string')
return value;
if (value === undefined || value === null)
return null;
throw new Error(`[airtable-ts] Can't coerce rollup to a string, as it was of type ${typeof value}`);
},
toAirtable: readonly('rollup'),
fromAirtable: coerce('rollup', 'string | null'),
},
formula: {
toAirtable: () => { throw new Error('[airtable-ts] formula type field is readonly'); },
fromAirtable: (value) => {
if (typeof value === 'string')
return value;
if (value === undefined || value === null)
return null;
throw new Error(`[airtable-ts] Can't coerce formula to a string, as it was of type ${typeof value}`);
},
toAirtable: readonly('formula'),
fromAirtable: coerce('formula', 'string | null'),
},
},
boolean: {
checkbox: fallbackMapperPair(false, false),
multipleLookupValues: {
toAirtable: () => { throw new Error('[airtable-ts] lookup type field is readonly'); },
fromAirtable: (value) => {
if (!value) {
throw new Error('[airtable-ts] Failed to coerce lookup type field to a single boolean, as it was blank');
}
if (value.length !== 1) {
throw new Error(`[airtable-ts] Can't coerce lookup to a single boolean, as there were ${value?.length} entries`);
}
if (typeof value[0] !== 'boolean') {
throw new Error(`[airtable-ts] Can't coerce singular lookup to a single boolean, as it was of type ${typeof value[0]}`);
}
return value[0];
},
unknown: {
toAirtable: (value) => value,
fromAirtable: coerce('unknown', 'string | null'),
},
},
};
const booleanOrNull = {
'boolean | null': {
checkbox: fallbackMapperPair(null, null),
multipleLookupValues: {
toAirtable: () => { throw new Error('[airtable-ts] lookup type field is readonly'); },
fromAirtable: (value) => {
if (!value || value.length === 0) {
return null;
}
if (value.length !== 1) {
throw new Error(`[airtable-ts] Can't coerce lookup to a single boolean, as there were ${value?.length} entries`);
}
if (typeof value[0] !== 'boolean') {
throw new Error(`[airtable-ts] Can't coerce singular lookup to a single boolean, as it was of type ${typeof value[0]}`);
}
return value[0];
},
toAirtable: readonly('multipleLookupValues'),
fromAirtable: coerce('multipleLookupValues', 'boolean | null'),
},
},
number: {
number: requiredMapperPair,
rating: requiredMapperPair,
duration: requiredMapperPair,
currency: requiredMapperPair,
percent: requiredMapperPair,
count: {
toAirtable: () => { throw new Error('[airtable-ts] count type field is readonly'); },
fromAirtable: (value) => required(value),
unknown: {
toAirtable: (value) => value,
fromAirtable: coerce('unknown', 'boolean | null'),
},
autoNumber: {
toAirtable: () => { throw new Error('[airtable-ts] autoNumber type field is readonly'); },
fromAirtable: (value) => required(value),
},
// Number assumed to be unix time in seconds
date: {
toAirtable: (value) => {
const date = new Date(value * 1000);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid date');
}
return date.toJSON().slice(0, 10);
},
fromAirtable: (value) => {
const date = new Date(value ?? '');
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid date');
}
return Math.floor(date.getTime() / 1000);
},
},
// Number assumed to be unix time in seconds
dateTime: {
toAirtable: (value) => {
const date = new Date(value * 1000);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return date.toJSON();
},
fromAirtable: (value) => {
const date = new Date(value ?? '');
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return Math.floor(date.getTime() / 1000);
},
},
createdTime: {
toAirtable: (value) => {
const date = new Date(value * 1000);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return date.toJSON();
},
fromAirtable: (value) => {
const date = new Date(value ?? '');
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return Math.floor(date.getTime() / 1000);
},
},
lastModifiedTime: {
toAirtable: (value) => {
const date = new Date(value * 1000);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return date.toJSON();
},
fromAirtable: (value) => {
const date = new Date(value ?? '');
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return Math.floor(date.getTime() / 1000);
},
},
multipleLookupValues: {
toAirtable: () => { throw new Error('[airtable-ts] lookup type field is readonly'); },
fromAirtable: (value) => {
if (!value) {
throw new Error('[airtable-ts] Failed to coerce lookup type field to a single number, as it was blank');
}
if (value.length !== 1) {
throw new Error(`[airtable-ts] Can't coerce lookup to a single number, as there were ${value?.length} entries`);
}
if (typeof value[0] !== 'number') {
throw new Error(`[airtable-ts] Can't coerce singular lookup to a single number, as it was of type ${typeof value[0]}`);
}
return value[0];
},
},
rollup: {
toAirtable: () => { throw new Error('[airtable-ts] rollup type field is readonly'); },
fromAirtable: (value) => {
if (typeof value === 'number')
return value;
throw new Error(`[airtable-ts] Can't coerce rollup to a number, as it was of type ${typeof value}`);
},
},
formula: {
toAirtable: () => { throw new Error('[airtable-ts] formula type field is readonly'); },
fromAirtable: (value) => {
if (typeof value === 'number')
return value;
throw new Error(`[airtable-ts] Can't coerce formula to a number, as it was of type ${typeof value}`);
},
},
},
};
const numberOrNull = {
'number | null': {

@@ -473,23 +123,15 @@ number: fallbackMapperPair(null, null),

fromAirtable: (value) => value ?? null,
toAirtable: () => { throw new Error('[airtable-ts] count type field is readonly'); },
toAirtable: readonly('count'),
},
autoNumber: {
fromAirtable: (value) => value ?? null,
toAirtable: () => { throw new Error('[airtable-ts] autoNumber field is readonly'); },
toAirtable: readonly('autoNumber'),
},
// Number assumed to be unix time in seconds
date: {
toAirtable: (value) => {
if (value === null)
return null;
const date = new Date(value * 1000);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid date');
}
return date.toJSON().slice(0, 10);
},
toAirtable: (value) => dateTimeMapperPair.toAirtable(value)?.slice(0, 10) ?? null,
fromAirtable: (value) => {
if (value === null || value === undefined)
const nullableValue = dateTimeMapperPair.fromAirtable(value);
if (nullableValue === null)
return null;
const date = new Date(value);
const date = new Date(nullableValue);
if (Number.isNaN(date.getTime())) {

@@ -501,19 +143,11 @@ throw new Error('[airtable-ts] Invalid date');

},
// Number assumed to be unix time in seconds
dateTime: {
toAirtable: (value) => {
if (value === null)
return null;
const date = new Date(value * 1000);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return date.toJSON();
},
toAirtable: dateTimeMapperPair.toAirtable,
fromAirtable: (value) => {
if (value === null || value === undefined)
const nullableValue = dateTimeMapperPair.fromAirtable(value);
if (nullableValue === null)
return null;
const date = new Date(value);
const date = new Date(nullableValue);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
throw new Error('[airtable-ts] Invalid date');
}

@@ -524,17 +158,10 @@ return Math.floor(date.getTime() / 1000);

createdTime: {
toAirtable: (value) => {
if (value === null)
return null;
const date = new Date(value * 1000);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return date.toJSON();
},
toAirtable: dateTimeMapperPair.toAirtable,
fromAirtable: (value) => {
if (value === null || value === undefined)
const nullableValue = dateTimeMapperPair.fromAirtable(value);
if (nullableValue === null)
return null;
const date = new Date(value);
const date = new Date(nullableValue);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
throw new Error('[airtable-ts] Invalid date');
}

@@ -545,17 +172,10 @@ return Math.floor(date.getTime() / 1000);

lastModifiedTime: {
toAirtable: (value) => {
if (value === null)
return null;
const date = new Date(value * 1000);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
}
return date.toJSON();
},
toAirtable: dateTimeMapperPair.toAirtable,
fromAirtable: (value) => {
if (value === null || value === undefined)
const nullableValue = dateTimeMapperPair.fromAirtable(value);
if (nullableValue === null)
return null;
const date = new Date(value);
const date = new Date(nullableValue);
if (Number.isNaN(date.getTime())) {
throw new Error('[airtable-ts] Invalid dateTime');
throw new Error('[airtable-ts] Invalid date');
}

@@ -566,38 +186,21 @@ return Math.floor(date.getTime() / 1000);

multipleLookupValues: {
toAirtable: () => { throw new Error('[airtable-ts] lookup type field is readonly'); },
fromAirtable: (value) => {
if (!value || value.length === 0) {
return null;
}
if (value.length !== 1) {
throw new Error(`[airtable-ts] Can't coerce lookup to a single number, as there were ${value?.length} entries`);
}
if (typeof value[0] !== 'number') {
throw new Error(`[airtable-ts] Can't coerce singular lookup to a single number, as it was of type ${typeof value[0]}`);
}
return value[0];
},
toAirtable: readonly('multipleLookupValues'),
fromAirtable: coerce('multipleLookupValues', 'number | null'),
},
rollup: {
toAirtable: () => { throw new Error('[airtable-ts] rollup type field is readonly'); },
fromAirtable: (value) => {
if (typeof value === 'number')
return value;
if (value === null || value === undefined)
return null;
throw new Error(`[airtable-ts] Can't coerce rollup to a number, as it was of type ${typeof value}`);
},
toAirtable: readonly('rollup'),
fromAirtable: coerce('rollup', 'number | null'),
},
formula: {
toAirtable: () => { throw new Error('[airtable-ts] formula type field is readonly'); },
fromAirtable: (value) => {
if (typeof value === 'number')
return value;
if (value === null || value === undefined)
return null;
throw new Error(`[airtable-ts] Can't coerce formula to a number, as it was of type ${typeof value}`);
},
toAirtable: readonly('formula'),
fromAirtable: coerce('formula', 'number | null'),
},
unknown: {
toAirtable: (value) => value,
fromAirtable: coerce('unknown', 'number | null'),
},
},
'string[]': {
};
const stringArrayOrNull = {
'string[] | null': {
multipleSelects: fallbackMapperPair([], []),

@@ -607,59 +210,63 @@ multipleRecordLinks: fallbackMapperPair([], []),

toAirtable: () => { throw new Error('[airtable-ts] lookup type field is readonly'); },
fromAirtable: (value) => {
if (!Array.isArray(value)) {
throw new Error('[airtable-ts] Failed to coerce lookup type field to a string array, as it was not an array');
}
if (value.some((v) => typeof v !== 'string')) {
throw new Error('[airtable-ts] Can\'t coerce lookup to a string array, as it had non string type');
}
return value;
},
fromAirtable: coerce('multipleLookupValues', 'string[] | null'),
},
formula: {
toAirtable: () => { throw new Error('[airtable-ts] formula type field is readonly'); },
fromAirtable: (value) => {
if (!Array.isArray(value)) {
throw new Error('[airtable-ts] Failed to coerce formula type field to a string array, as it was not an array');
}
if (value.some((v) => typeof v !== 'string')) {
throw new Error('[airtable-ts] Can\'t coerce formula to a string array, as it had non string type');
}
return value;
},
fromAirtable: coerce('multipleLookupValues', 'string[] | null'),
},
},
'string[] | null': {
multipleSelects: fallbackMapperPair(null, null),
multipleRecordLinks: fallbackMapperPair(null, null),
multipleLookupValues: {
toAirtable: () => { throw new Error('[airtable-ts] lookup type field is readonly'); },
fromAirtable: (value) => {
if (!value && !Array.isArray(value)) {
return null;
}
if (!Array.isArray(value)) {
throw new Error('[airtable-ts] Failed to coerce lookup type field to a string array, as it was not an array');
}
if (value.some((v) => typeof v !== 'string')) {
throw new Error('[airtable-ts] Can\'t coerce lookup to a string array, as it had non string type');
}
return value;
},
unknown: {
toAirtable: (value) => value,
fromAirtable: coerce('unknown', 'string[] | null'),
},
formula: {
toAirtable: () => { throw new Error('[airtable-ts] formula type field is readonly'); },
fromAirtable: (value) => {
if (!value && !Array.isArray(value)) {
return null;
}
if (!Array.isArray(value)) {
throw new Error('[airtable-ts] Failed to coerce formula type field to a string array, as it was not an array');
}
if (value.some((v) => typeof v !== 'string')) {
throw new Error('[airtable-ts] Can\'t coerce formula to a string array, as it had non string type');
}
return value;
},
},
},
};
exports.fieldMappers = {
...stringOrNull,
string: {
...Object.fromEntries(Object.entries(stringOrNull['string | null']).map(([airtableType, nullablePair]) => {
return [airtableType, {
toAirtable: nullablePair.toAirtable,
fromAirtable: (value) => {
const nullableValue = nullablePair.fromAirtable(value);
if (nullableValue === null && ['multipleRecordLinks', 'dateTime', 'createdTime', 'lastModifiedTime'].includes(airtableType)) {
throw new Error(`[airtable-ts] Expected non-null or non-empty value to map to string for field type ${airtableType}`);
}
return nullableValue ?? '';
},
}];
})),
},
...booleanOrNull,
boolean: {
...Object.fromEntries(Object.entries(booleanOrNull['boolean | null']).map(([airtableType, nullablePair]) => {
return [airtableType, {
toAirtable: nullablePair.toAirtable,
fromAirtable: (value) => nullablePair.fromAirtable(value) ?? false,
}];
})),
},
...numberOrNull,
number: {
...Object.fromEntries(Object.entries(numberOrNull['number | null']).map(([airtableType, nullablePair]) => {
return [airtableType, {
toAirtable: nullablePair.toAirtable,
fromAirtable: (value) => {
const nullableValue = nullablePair.fromAirtable(value);
if (nullableValue === null) {
throw new Error(`[airtable-ts] Expected non-null or non-empty value to map to number for field type ${airtableType}`);
}
return nullableValue;
},
}];
})),
},
...stringArrayOrNull,
'string[]': {
...Object.fromEntries(Object.entries(stringArrayOrNull['string[] | null']).map(([airtableType, nullablePair]) => {
return [airtableType, {
toAirtable: nullablePair.toAirtable,
fromAirtable: (value) => nullablePair.fromAirtable(value) ?? [],
}];
})),
},
};

@@ -7,2 +7,16 @@ "use strict";

const typeUtils_1 = require("./typeUtils");
const getMapper = (tsType, airtableType) => {
const tsMapper = fieldMappers_1.fieldMappers[tsType];
if (!tsMapper) {
throw new Error(`[airtable-ts] No mappers for ts type ${tsType}`);
}
if (tsMapper[airtableType]) {
return tsMapper[airtableType];
}
if (tsMapper.unknown) {
console.warn(`[airtable-ts] Unknown airtable type ${airtableType}. This is not fully supported and exact mapping behaviour may change in a future release.`);
return tsMapper.unknown;
}
throw new Error(`[airtable-ts] Expected to be able to map to ts type ${tsType}, but got airtable type ${airtableType} which can't.`);
};
/**

@@ -32,14 +46,6 @@ * This function coerces an Airtable record to a TypeScript object, given an

const value = record.fields[fieldDefinition.name];
const tsMapper = fieldMappers_1.fieldMappers[tsType];
if (!tsMapper) {
throw new Error(`[airtable-ts] No mappers for ts type ${tsType}`);
}
const specificMapper = tsMapper[fieldDefinition.type]?.fromAirtable;
if (!specificMapper) {
// eslint-disable-next-line no-underscore-dangle
throw new Error(`[airtable-ts] Expected field ${record._table.name}.${fieldNameOrId} to be able to map to ts type ${tsType}, but got airtable type ${fieldDefinition.type} which can't.`);
}
try {
const { fromAirtable } = getMapper(tsType, fieldDefinition.type);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
item[fieldNameOrId] = specificMapper(value);
item[fieldNameOrId] = fromAirtable(value);
}

@@ -93,12 +99,16 @@ catch (error) {

}
const tsMapper = fieldMappers_1.fieldMappers[tsType];
if (!tsMapper) {
throw new Error(`[airtable-ts] No mappers for ts type ${tsType}`);
try {
const { toAirtable } = getMapper(tsType, fieldDefinition.type);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
item[fieldNameOrId] = toAirtable(value);
}
const specificMapper = tsMapper[fieldDefinition.type]?.toAirtable;
if (!specificMapper) {
throw new Error(`[airtable-ts] Expected field ${airtableTable.name}.${fieldNameOrId} to be able to map to airtable type \`${fieldDefinition.type}\`, but got ts type \`${tsType}\` which can't.`);
catch (error) {
if (error instanceof Error) {
// eslint-disable-next-line no-underscore-dangle
error.message = `Failed to map field ${airtableTable.name}.${fieldNameOrId}: ${error.message}`;
// eslint-disable-next-line no-underscore-dangle
error.stack = `Error: Failed to map field ${airtableTable.name}.${fieldNameOrId}: ${error.stack?.startsWith('Error: ') ? error.stack.slice('Error: '.length) : error.stack}`;
}
throw error;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
item[fieldNameOrId] = specificMapper(value);
});

@@ -105,0 +115,0 @@ return Object.assign(item, { id: tsRecord.id });

@@ -6,3 +6,9 @@ export type TsTypeString = NonNullToString<any> | ToTsTypeString<any>;

export type AirtableTypeString = 'aiText' | 'autoNumber' | 'barcode' | 'button' | 'checkbox' | 'count' | 'createdBy' | 'createdTime' | 'currency' | 'date' | 'dateTime' | 'duration' | 'email' | 'externalSyncSource' | 'formula' | 'lastModifiedBy' | 'lastModifiedTime' | 'lookup' | 'multipleLookupValues' | 'multilineText' | 'multipleAttachments' | 'multipleCollaborators' | 'multipleRecordLinks' | 'multipleSelects' | 'number' | 'percent' | 'phoneNumber' | 'rating' | 'richText' | 'rollup' | 'singleCollaborator' | 'singleLineText' | 'singleSelect' | 'url';
export type FromAirtableTypeString<T extends AirtableTypeString> = null | (T extends 'url' | 'email' | 'phoneNumber' | 'singleLineText' | 'multilineText' | 'richText' | 'singleSelect' | 'externalSyncSource' | 'date' | 'dateTime' | 'createdTime' | 'lastModifiedTime' ? string : T extends 'multipleRecordLinks' | 'multipleSelects' ? string[] : T extends 'number' | 'rating' | 'duration' | 'currency' | 'percent' | 'count' | 'autoNumber' ? number : T extends 'checkbox' ? boolean : T extends 'lookup' | 'multipleLookupValues' | 'rollup' | 'formula' ? FromAirtableTypeString<any>[] : never);
export type FromAirtableTypeString<T extends AirtableTypeString | 'unknown'> = null | (T extends 'url' | 'email' | 'phoneNumber' | 'singleLineText' | 'multilineText' | 'richText' | 'singleSelect' | 'externalSyncSource' | 'date' | 'dateTime' | 'createdTime' | 'lastModifiedTime' ? string : T extends 'multipleRecordLinks' | 'multipleSelects' ? string[] : T extends 'number' | 'rating' | 'duration' | 'currency' | 'percent' | 'count' | 'autoNumber' ? number : T extends 'checkbox' ? boolean : T extends 'lookup' | 'multipleLookupValues' | 'rollup' | 'formula' ? FromAirtableTypeString<any>[] : T extends 'unknown' ? unknown : never);
interface TypeDef {
single: 'string' | 'number' | 'boolean';
array: boolean;
nullable: boolean;
}
export declare const parseType: (t: TsTypeString) => TypeDef;
/**

@@ -9,0 +15,0 @@ * Verifies whether the given value is assignable to the given type

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.airtableFieldNameTsTypes = exports.matchesType = void 0;
exports.airtableFieldNameTsTypes = exports.matchesType = exports.parseType = void 0;
const parseType = (t) => {

@@ -32,2 +32,3 @@ if (t.endsWith('[] | null')) {

};
exports.parseType = parseType;
/**

@@ -46,3 +47,3 @@ * Verifies whether the given value is assignable to the given type

const matchesType = (value, tsType) => {
const expectedType = parseType(tsType);
const expectedType = (0, exports.parseType)(tsType);
if (expectedType.nullable && value === null) {

@@ -49,0 +50,0 @@ return true;

{
"name": "airtable-ts",
"version": "1.3.0",
"version": "1.3.1",
"description": "A type-safe Airtable SDK",

@@ -5,0 +5,0 @@ "license": "MIT",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc