Derive TS type from JSON Schema
So we don't define (almost) the same schema twice
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
"author": "Râu Cao <raucao@kosmos.org>",
|
"author": "Râu Cao <raucao@kosmos.org>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"json-schema-to-ts": "^3.1.1",
|
||||||
"remotestoragejs": "^2.0.0-beta.8",
|
"remotestoragejs": "^2.0.0-beta.8",
|
||||||
"rimraf": "^6.1.2",
|
"rimraf": "^6.1.2",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
|
|||||||
23
pnpm-lock.yaml
generated
23
pnpm-lock.yaml
generated
@@ -15,6 +15,9 @@ importers:
|
|||||||
specifier: ^3.0.2
|
specifier: ^3.0.2
|
||||||
version: 3.0.2
|
version: 3.0.2
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
json-schema-to-ts:
|
||||||
|
specifier: ^3.1.1
|
||||||
|
version: 3.1.1
|
||||||
remotestoragejs:
|
remotestoragejs:
|
||||||
specifier: ^2.0.0-beta.8
|
specifier: ^2.0.0-beta.8
|
||||||
version: 2.0.0-beta.8
|
version: 2.0.0-beta.8
|
||||||
@@ -27,6 +30,10 @@ importers:
|
|||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
'@babel/runtime@7.28.6':
|
||||||
|
resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@isaacs/balanced-match@4.0.1':
|
'@isaacs/balanced-match@4.0.1':
|
||||||
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
|
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
|
||||||
engines: {node: 20 || >=22}
|
engines: {node: 20 || >=22}
|
||||||
@@ -54,6 +61,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==}
|
resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==}
|
||||||
engines: {node: 20 || >=22}
|
engines: {node: 20 || >=22}
|
||||||
|
|
||||||
|
json-schema-to-ts@3.1.1:
|
||||||
|
resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
|
||||||
latlon-geohash@2.0.0:
|
latlon-geohash@2.0.0:
|
||||||
resolution: {integrity: sha512-OKBswTwrvTdtenV+9C9euBmvgGuqyjJNAzpQCarRz1m8/pYD2nz9fKkXmLs2S3jeXaLi3Ry76twQplKKUlgS/g==}
|
resolution: {integrity: sha512-OKBswTwrvTdtenV+9C9euBmvgGuqyjJNAzpQCarRz1m8/pYD2nz9fKkXmLs2S3jeXaLi3Ry76twQplKKUlgS/g==}
|
||||||
|
|
||||||
@@ -84,6 +95,9 @@ packages:
|
|||||||
engines: {node: 20 || >=22}
|
engines: {node: 20 || >=22}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
ts-algebra@2.0.0:
|
||||||
|
resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==}
|
||||||
|
|
||||||
tv4@1.3.0:
|
tv4@1.3.0:
|
||||||
resolution: {integrity: sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw==}
|
resolution: {integrity: sha512-afizzfpJgvPr+eDkREK4MxJ/+r8nEEHcmitwgnPUqpaP+FpwQyadnxNoSACbgc/b1LsZYtODGoPiFxQrgJgjvw==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
@@ -109,6 +123,8 @@ packages:
|
|||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
|
'@babel/runtime@7.28.6': {}
|
||||||
|
|
||||||
'@isaacs/balanced-match@4.0.1': {}
|
'@isaacs/balanced-match@4.0.1': {}
|
||||||
|
|
||||||
'@isaacs/brace-expansion@5.0.0':
|
'@isaacs/brace-expansion@5.0.0':
|
||||||
@@ -132,6 +148,11 @@ snapshots:
|
|||||||
minipass: 7.1.2
|
minipass: 7.1.2
|
||||||
path-scurry: 2.0.1
|
path-scurry: 2.0.1
|
||||||
|
|
||||||
|
json-schema-to-ts@3.1.1:
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.28.6
|
||||||
|
ts-algebra: 2.0.0
|
||||||
|
|
||||||
latlon-geohash@2.0.0: {}
|
latlon-geohash@2.0.0: {}
|
||||||
|
|
||||||
lru-cache@11.2.4: {}
|
lru-cache@11.2.4: {}
|
||||||
@@ -165,6 +186,8 @@ snapshots:
|
|||||||
glob: 13.0.0
|
glob: 13.0.0
|
||||||
package-json-from-dist: 1.0.1
|
package-json-from-dist: 1.0.1
|
||||||
|
|
||||||
|
ts-algebra@2.0.0: {}
|
||||||
|
|
||||||
tv4@1.3.0: {}
|
tv4@1.3.0: {}
|
||||||
|
|
||||||
typescript@5.9.3: {}
|
typescript@5.9.3: {}
|
||||||
|
|||||||
@@ -1,53 +1,43 @@
|
|||||||
import BaseClient from 'remotestoragejs/release/types/baseclient';
|
import BaseClient from 'remotestoragejs/release/types/baseclient';
|
||||||
import Geohash from 'latlon-geohash';
|
import Geohash from 'latlon-geohash';
|
||||||
import { ulid } from 'ulid';
|
import { ulid } from 'ulid';
|
||||||
|
import { FromSchema } from 'json-schema-to-ts';
|
||||||
|
|
||||||
interface Place {
|
const placeSchema = {
|
||||||
id: string;
|
type: 'object',
|
||||||
title: string;
|
properties: {
|
||||||
lat: number;
|
id: { type: 'string' },
|
||||||
lon: number;
|
title: { type: 'string' },
|
||||||
geohash: string;
|
lat: { type: 'number' },
|
||||||
zoom?: number;
|
lon: { type: 'number' },
|
||||||
url?: string;
|
geohash: { type: 'string' },
|
||||||
osmId?: string;
|
zoom: { type: 'number' },
|
||||||
osmType?: string;
|
url: { type: 'string' },
|
||||||
osmTags?: Record<string, string>;
|
osmId: { type: 'string' },
|
||||||
description?: string;
|
osmType: { type: 'string' },
|
||||||
tags?: string[];
|
osmTags: {
|
||||||
createdAt: string;
|
type: 'object',
|
||||||
updatedAt?: string;
|
additionalProperties: { type: 'string' },
|
||||||
[key: string]: any;
|
},
|
||||||
}
|
description: { type: 'string' },
|
||||||
|
tags: {
|
||||||
|
type: 'array',
|
||||||
|
items: { type: 'string' },
|
||||||
|
default: [],
|
||||||
|
},
|
||||||
|
createdAt: { type: 'string', format: 'date-time' },
|
||||||
|
updatedAt: { type: 'string', format: 'date-time' },
|
||||||
|
},
|
||||||
|
required: ['id', 'title', 'lat', 'lon', 'geohash', 'createdAt'],
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
type Place = FromSchema<typeof placeSchema> & { [key: string]: any };
|
||||||
|
|
||||||
const Places = function (
|
const Places = function (
|
||||||
privateClient: BaseClient /*, publicClient: BaseClient */
|
privateClient: BaseClient /*, publicClient: BaseClient */
|
||||||
) {
|
) {
|
||||||
// Define Schema
|
// Define Schema
|
||||||
privateClient.declareType('place', {
|
privateClient.declareType('place', placeSchema as any);
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
id: { type: 'string', required: true },
|
|
||||||
title: { type: 'string', required: true },
|
|
||||||
lat: { type: 'number', required: true },
|
|
||||||
lon: { type: 'number', required: true },
|
|
||||||
geohash: { type: 'string', required: true },
|
|
||||||
zoom: { type: 'number' },
|
|
||||||
url: { type: 'string' },
|
|
||||||
osmId: { type: 'string' },
|
|
||||||
osmType: { type: 'string' },
|
|
||||||
osmTags: { type: 'object' },
|
|
||||||
description: { type: 'string' },
|
|
||||||
tags: {
|
|
||||||
type: 'array',
|
|
||||||
items: { type: 'string' },
|
|
||||||
default: [],
|
|
||||||
},
|
|
||||||
createdAt: { type: 'string', format: 'date-time', required: true },
|
|
||||||
updatedAt: { type: 'string', format: 'date-time' },
|
|
||||||
},
|
|
||||||
required: ['id', 'title', 'lat', 'lon', 'geohash', 'createdAt'],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Helper to normalize place object
|
// Helper to normalize place object
|
||||||
function preparePlace(data: Partial<Place>): Place {
|
function preparePlace(data: Partial<Place>): Place {
|
||||||
@@ -70,6 +60,7 @@ const Places = function (
|
|||||||
lon,
|
lon,
|
||||||
geohash,
|
geohash,
|
||||||
title,
|
title,
|
||||||
|
tags: data.tags || [],
|
||||||
createdAt: data.createdAt || now,
|
createdAt: data.createdAt || now,
|
||||||
updatedAt: data.id ? now : undefined,
|
updatedAt: data.id ? now : undefined,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user