diff --git a/.github/workflows/updates.yml b/.github/workflows/updates.yml index 56ec71c5d..a74c23acc 100644 --- a/.github/workflows/updates.yml +++ b/.github/workflows/updates.yml @@ -25,7 +25,7 @@ jobs: run: npm install - name: Run NOAA stations update - run: tools/update-noaa-stations + run: tools/update-noaa-stations.ts - name: Check for changes id: changes diff --git a/README.md b/README.md index d94053b51..2dda278df 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ You can also manually trigger the workflow from the Actions tab in GitHub. To manually update NOAA stations: ```bash -$ tools/update-noaa-stations +$ tools/update-noaa-stations.ts ``` This will scan all existing NOAA station files, fetch any new stations from NOAA's API, and update harmonic constituents for all stations. diff --git a/package.json b/package.json index fc626cc07..c27857f3d 100644 --- a/package.json +++ b/package.json @@ -23,16 +23,21 @@ "doc": "docs" }, "scripts": { - "build": "vite build", + "build": "tsc -b && tsc -p tsconfig.node.json && vite build", "prepare": "npm run build", "test": "vitest" }, "devDependencies": { + "@neaps/tide-predictor": "^0.2.1", + "@types/make-fetch-happen": "^10.0.4", + "@types/node": "^25.0.3", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", + "country-code-lookup": "^0.1.3", "geo-tz": "^8.1.4", "make-fetch-happen": "^15.0.3", "moment": "^2.30.1", + "sort-object-keys": "^2.0.1", "vite": "^7.2.6", "vite-plugin-dts": "^4.5.4", "vitest": "^4.0.15" diff --git a/schemas/station.schema.json b/schemas/station.schema.json index c06a7f121..a9de06022 100644 --- a/schemas/station.schema.json +++ b/schemas/station.schema.json @@ -137,8 +137,7 @@ "name", "id", "published_harmonics", - "url", - "source_url" + "url" ], "additionalProperties": true, "properties": { @@ -161,11 +160,6 @@ "type": "string", "format": "uri", "description": "URL to this station's data or information in the source's website" - }, - "source_url": { - "type": "string", - "format": "uri", - "description": "URL to the source API endpoint for this station's data" } } }, diff --git a/src/constituents.json b/src/constituents.json new file mode 100644 index 000000000..20edcef70 --- /dev/null +++ b/src/constituents.json @@ -0,0 +1,602 @@ +[ + { + "name": "M2", + "description": "Principal lunar semidiurnal constituent", + "speed": 28.984104 + }, + { + "name": "S2", + "description": "Principal solar semidiurnal constituent", + "speed": 30 + }, + { + "name": "N2", + "description": "Larger lunar elliptic semidiurnal constituent", + "speed": 28.43973 + }, + { + "name": "K1", + "description": "Lunar diurnal constituent", + "speed": 15.041069 + }, + { + "name": "M4", + "description": "Shallow water overtides of principal lunar constituent", + "speed": 57.96821 + }, + { + "name": "O1", + "description": "Lunar diurnal constituent", + "speed": 13.943035 + }, + { + "name": "M6", + "description": "Shallow water overtides of principal lunar constituent", + "speed": 86.95232 + }, + { + "name": "MK3", + "description": "Shallow water terdiurnal", + "speed": 44.025173 + }, + { + "name": "S4", + "description": "Shallow water overtides of principal solar constituent", + "speed": 60 + }, + { + "name": "MN4", + "description": "Shallow water quarter diurnal constituent", + "speed": 57.423832 + }, + { + "name": "NU2", + "description": "Larger lunar evectional constituent", + "speed": 28.512583 + }, + { + "name": "S6", + "description": "Shallow water overtides of principal solar constituent", + "speed": 90 + }, + { + "name": "MU2", + "description": "Variational constituent", + "speed": 27.968208 + }, + { + "name": "2N2", + "description": "Lunar elliptical semidiurnal second-order constituent", + "speed": 27.895355 + }, + { + "name": "OO1", + "description": "Lunar diurnal", + "speed": 16.139101 + }, + { + "name": "LAM2", + "description": "Smaller lunar evectional constituent", + "speed": 29.455626 + }, + { + "name": "S1", + "description": "Solar diurnal constituent", + "speed": 15 + }, + { + "name": "M1", + "description": "Smaller lunar elliptic diurnal constituent", + "speed": 14.496694 + }, + { + "name": "J1", + "description": "Smaller lunar elliptic diurnal constituent", + "speed": 15.5854435 + }, + { + "name": "MM", + "description": "Lunar monthly constituent", + "speed": 0.5443747 + }, + { + "name": "SSA", + "description": "Solar semiannual constituent", + "speed": 0.0821373 + }, + { + "name": "SA", + "description": "Solar annual constituent", + "speed": 0.0410686 + }, + { + "name": "MSF", + "description": "Lunisolar synodic fortnightly constituent", + "speed": 1.0158958 + }, + { + "name": "MF", + "description": "Lunisolar fortnightly constituent", + "speed": 1.0980331 + }, + { + "name": "RHO", + "description": "Larger lunar evectional diurnal constituent", + "speed": 13.471515 + }, + { + "name": "Q1", + "description": "Larger lunar elliptic diurnal constituent", + "speed": 13.398661 + }, + { + "name": "T2", + "description": "Larger solar elliptic constituent", + "speed": 29.958933 + }, + { + "name": "R2", + "description": "Smaller solar elliptic constituent", + "speed": 30.041067 + }, + { + "name": "2Q1", + "description": "Larger elliptic diurnal", + "speed": 12.854286 + }, + { + "name": "P1", + "description": "Solar diurnal constituent", + "speed": 14.958931 + }, + { + "name": "2SM2", + "description": "Shallow water semidiurnal constituent", + "speed": 31.015896 + }, + { + "name": "M3", + "description": "Lunar terdiurnal constituent", + "speed": 43.47616 + }, + { + "name": "L2", + "description": "Smaller lunar elliptic semidiurnal constituent", + "speed": 29.528479 + }, + { + "name": "2MK3", + "description": "Shallow water terdiurnal constituent", + "speed": 42.92714 + }, + { + "name": "K2", + "description": "Lunisolar semidiurnal constituent", + "speed": 30.082138 + }, + { + "name": "M8", + "description": "Shallow water eighth diurnal constituent", + "speed": 115.93642 + }, + { + "name": "MS4", + "description": "Shallow water quarter diurnal constituent", + "speed": 58.984104 + }, + { + "name": "SIGMA1", + "description": null, + "speed": 12.92714 + }, + { + "name": "MP1", + "description": null, + "speed": 14.025173 + }, + { + "name": "CHI1", + "description": null, + "speed": 14.569548 + }, + { + "name": "2PO1", + "description": null, + "speed": 15.974827 + }, + { + "name": "SO1", + "description": null, + "speed": 16.056965 + }, + { + "name": "MSN2", + "description": null, + "speed": 30.544374 + }, + { + "name": "MNS2", + "description": null, + "speed": 27.423834 + }, + { + "name": "OP2", + "description": null, + "speed": 28.901966 + }, + { + "name": "MKS2", + "description": null, + "speed": 29.066242 + }, + { + "name": "2NS2", + "description": null, + "speed": 26.87946 + }, + { + "name": "MLN2S2", + "description": null, + "speed": 26.952312 + }, + { + "name": "2ML2S2", + "description": null, + "speed": 27.496687 + }, + { + "name": "SKM2", + "description": null, + "speed": 31.098034 + }, + { + "name": "2MS2K2", + "description": null, + "speed": 27.803934 + }, + { + "name": "MKL2S2", + "description": null, + "speed": 28.59472 + }, + { + "name": "M2KS2", + "description": null, + "speed": 29.148378 + }, + { + "name": "2SNMK2", + "description": null, + "speed": 29.373487 + }, + { + "name": "2KMSN2", + "description": null, + "speed": 30.708649 + }, + { + "name": "SO3", + "description": null, + "speed": 43.943035 + }, + { + "name": "SK3", + "description": null, + "speed": 45.04107 + }, + { + "name": "NO3", + "description": null, + "speed": 42.382767 + }, + { + "name": "MK4", + "description": null, + "speed": 59.066242 + }, + { + "name": "SN4", + "description": null, + "speed": 58.439728 + }, + { + "name": "2MLS4", + "description": null, + "speed": 57.49669 + }, + { + "name": "3MS4", + "description": null, + "speed": 56.952312 + }, + { + "name": "ML4", + "description": null, + "speed": 58.512585 + }, + { + "name": "N4", + "description": null, + "speed": 56.87946 + }, + { + "name": "SL4", + "description": null, + "speed": 59.52848 + }, + { + "name": "MNO5", + "description": null, + "speed": 71.36687 + }, + { + "name": "2MO5", + "description": null, + "speed": 71.91125 + }, + { + "name": "2MK5", + "description": null, + "speed": 73.00928 + }, + { + "name": "MSK5", + "description": null, + "speed": 74.02517 + }, + { + "name": "3KM5", + "description": null, + "speed": 74.10731 + }, + { + "name": "2MP5", + "description": null, + "speed": 72.92714 + }, + { + "name": "3MP5", + "description": null, + "speed": 71.99338 + }, + { + "name": "MNK5", + "description": null, + "speed": 72.464905 + }, + { + "name": "2SM6", + "description": null, + "speed": 88.98411 + }, + { + "name": "2MN6", + "description": null, + "speed": 86.407936 + }, + { + "name": "MSN6", + "description": null, + "speed": 87.423836 + }, + { + "name": "2MS6", + "description": null, + "speed": 87.96821 + }, + { + "name": "2NMLS6", + "description": null, + "speed": 85.392044 + }, + { + "name": "2NM6", + "description": null, + "speed": 85.86356 + }, + { + "name": "MSL6", + "description": null, + "speed": 88.51258 + }, + { + "name": "2ML6", + "description": null, + "speed": 87.49669 + }, + { + "name": "MSK6", + "description": null, + "speed": 89.06624 + }, + { + "name": "2MLNS6", + "description": null, + "speed": 85.93642 + }, + { + "name": "3MLS6", + "description": null, + "speed": 86.48079 + }, + { + "name": "2MK6", + "description": null, + "speed": 88.05035 + }, + { + "name": "2MNO7", + "description": null, + "speed": 100.350975 + }, + { + "name": "2NMK7", + "description": null, + "speed": 100.90463 + }, + { + "name": "2MSO7", + "description": null, + "speed": 101.91125 + }, + { + "name": "MSKO7", + "description": null, + "speed": 103.00928 + }, + { + "name": "2MSN8", + "description": null, + "speed": 116.407936 + }, + { + "name": "3MS8", + "description": null, + "speed": 116.95232 + }, + { + "name": "2MS8", + "description": null, + "speed": 117.96821 + }, + { + "name": "2MN8", + "description": null, + "speed": 114.847664 + }, + { + "name": "3MN8", + "description": null, + "speed": 115.392044 + }, + { + "name": "2MSL8", + "description": null, + "speed": 117.49669 + }, + { + "name": "4MLS8", + "description": null, + "speed": 115.4649 + }, + { + "name": "3ML8", + "description": null, + "speed": 116.48079 + }, + { + "name": "3MK8", + "description": null, + "speed": 117.03445 + }, + { + "name": "2MSK8", + "description": null, + "speed": 118.05035 + }, + { + "name": "2M2NK9", + "description": null, + "speed": 129.88873 + }, + { + "name": "3MNK9", + "description": null, + "speed": 130.4331 + }, + { + "name": "4MK9", + "description": null, + "speed": 130.97748 + }, + { + "name": "3MSK9", + "description": null, + "speed": 131.99338 + }, + { + "name": "4MN10", + "description": null, + "speed": 144.37614 + }, + { + "name": "M10", + "description": null, + "speed": 144.92052 + }, + { + "name": "3MNS10", + "description": null, + "speed": 145.39204 + }, + { + "name": "4MS10", + "description": null, + "speed": 145.93642 + }, + { + "name": "3MSL10", + "description": null, + "speed": 146.48079 + }, + { + "name": "3M2S10", + "description": null, + "speed": 146.95232 + }, + { + "name": "4MSK11", + "description": null, + "speed": 160.97748 + }, + { + "name": "4MNS12", + "description": null, + "speed": 174.37614 + }, + { + "name": "5MS12", + "description": null, + "speed": 174.92052 + }, + { + "name": "4MSL12", + "description": null, + "speed": 175.46489 + }, + { + "name": "4M2S12", + "description": null, + "speed": 175.93642 + }, + { + "name": "TK1", + "description": null, + "speed": 14.917865 + }, + { + "name": "RP1", + "description": null, + "speed": 15.082135 + }, + { + "name": "KP1", + "description": null, + "speed": 15.123206 + }, + { + "name": "THETA1", + "description": null, + "speed": 15.512589 + }, + { + "name": "KJ2", + "description": null, + "speed": 30.626513 + }, + { + "name": "OO2", + "description": null, + "speed": 27.341696 + } +] diff --git a/src/index.ts b/src/index.ts index 5ff3903ab..a276f2947 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -type HarmonicConstituent = { +export interface HarmonicConstituent { name: string description?: string amplitude: number @@ -13,7 +13,7 @@ export interface Station { name: string continent: string country: string - region: string + region?: string timezone: string disclaimers: string type: 'reference' | 'subordinate' @@ -26,7 +26,6 @@ export interface Station { id: string published_harmonics: boolean url: string - source_url: string } // License information @@ -43,15 +42,15 @@ export interface Station { // Subordinate station offsets (empty object for reference stations) offsets?: { reference: string - height: { high: number; low: number, type: 'ratio' | 'fixed' } + height: { high: number; low: number; type: 'ratio' | 'fixed' } time: { high: number; low: number } } datums: Record } -const stations: Station[] = Object.values( +export { default as constituents } from './constituents.json' with { type: 'json' } + +export const stations: Station[] = Object.values( import.meta.glob('../data/**/*.json', { eager: true, import: 'default' }) ) - -export default stations diff --git a/test/validate.test.ts b/test/validate.test.ts index 12ffa1219..054d83e1b 100755 --- a/test/validate.test.ts +++ b/test/validate.test.ts @@ -5,14 +5,14 @@ import { readFile } from 'fs/promises' import { join } from 'path' import Ajv2020 from 'ajv/dist/2020.js' import addFormats from 'ajv-formats' -import stations from '../src/index.js' +import { stations } from '../src/index.js' const ROOT = new URL('..', import.meta.url).pathname const SCHEMA_PATH = join(ROOT, 'schemas', 'station.schema.json') const schema = JSON.parse(await readFile(SCHEMA_PATH, 'utf-8')) -const ajv = new Ajv2020({ allErrors: true, strict: false }) -addFormats(ajv) +const ajv = new (Ajv2020 as any)({ allErrors: true, strict: false }) +;(addFormats as any)(ajv) const validate = ajv.compile(schema) describe('schema', () => { diff --git a/tools/README.md b/tools/README.md index 511fe36e5..4f6e36b45 100644 --- a/tools/README.md +++ b/tools/README.md @@ -5,7 +5,7 @@ The command `update-noaa-stations` updates all NOAA station files in the data directory with the latest harmonic constituents from the NOAA API. ```shell -tools/update-noaa-stations +tools/update-noaa-stations.ts ``` ### Hawaii diff --git a/tools/station.ts b/tools/station.ts new file mode 100644 index 000000000..bc43cac8e --- /dev/null +++ b/tools/station.ts @@ -0,0 +1,77 @@ +import type { Station } from '../src/index.js' +import { find as findTz } from 'geo-tz/all' +import { slugify } from './util.ts' +import countryLookup from 'country-code-lookup' +import { join, dirname } from 'path' +import { mkdir, writeFile } from 'fs/promises' +import sortObject from 'sort-object-keys' + +const __dirname = new URL('.', import.meta.url).pathname +export const DATA_DIR = join(__dirname, '..', 'data') + +const sortOrder: (keyof Station)[] = [ + 'id', + 'name', + 'region', + 'country', + 'continent', + 'latitude', + 'longitude', + 'timezone', + 'source', + 'license', + 'disclaimers', + 'datums', + 'type', + 'harmonic_constituents', + 'offsets', +] + +export function normalize( + station: Omit +): Station { + const { iso2, continent, country } = + countryLookup.byCountry(station.country) || + countryLookup.byIso(station.country) || + {} + + if (!iso2 || !continent || !country) { + throw new Error( + `Unable to find country info for station: ${station.name} (${station.country})` + ) + } + + const timezone = findTz(station.latitude, station.longitude)[0] + + if (!timezone) { + throw new Error( + `Unable to find timezone for station: ${station.name} (${station.latitude}, ${station.longitude})` + ) + } + + // TODO: sort keys by order of JSON schema. Mutation for now to maintain key order + return sortObject( + { + ...station, + id: [iso2, station.region, station.name] + .filter((v): v is string => typeof v === 'string' && v.length > 0) + .map(slugify) + .join('/'), + timezone, + continent, + country, + }, + sortOrder + ) +} + +export async function save(data: Station) { + const filePath = join(DATA_DIR, `${data.id}.json`) + const directory = dirname(filePath) + + // Create directory if it doesn't exist + await mkdir(directory, { recursive: true }) + + // Write the JSON file + return writeFile(filePath, JSON.stringify(data, null, 2) + '\n') +} diff --git a/tools/update-noaa-stations b/tools/update-noaa-stations.ts similarity index 72% rename from tools/update-noaa-stations rename to tools/update-noaa-stations.ts index e3217fcdd..a8e3f27d9 100755 --- a/tools/update-noaa-stations +++ b/tools/update-noaa-stations.ts @@ -1,11 +1,9 @@ #!/usr/bin/env node -import { writeFile, mkdir } from 'fs/promises' -import { join } from 'path' -import { fileURLToPath } from 'url' -import { dirname } from 'path' -import { find as findTz } from 'geo-tz/all' +import { writeFile } from 'fs/promises' import createFetch from 'make-fetch-happen' +import { normalize, save } from './station.ts' +import type { Station } from '../src/index.ts' const fetch = createFetch.defaults({ cachePath: 'node_modules/.cache', @@ -13,12 +11,7 @@ const fetch = createFetch.defaults({ retry: 10, }) -const __filename = fileURLToPath(import.meta.url) -const __dirname = dirname(__filename) - -const DATA_DIR = join(__dirname, '..', 'data') const NOAA_SOURCE_NAME = 'US National Oceanic and Atmospheric Administration' -const NEW_STATIONS_DIR = join(DATA_DIR, 'us') const STATIONS_URL = 'https://api.tidesandcurrents.noaa.gov/mdapi/prod/webapi/stations.json' @@ -31,8 +24,8 @@ async function main() { `${STATIONS_URL}?type=tidepredictions&expand=details,tidepredoffsets&units=metric` ).then((r) => r.json()) - const referenceStations = stations.filter((s) => s.type === 'R') - const subordinateStations = stations.filter((s) => s.type === 'S') + const referenceStations = stations.filter((s: any) => s.type === 'R') + const subordinateStations = stations.filter((s: any) => s.type === 'S') console.log(`Fetched metadata for ${stations.length} stations.`) @@ -48,7 +41,8 @@ async function main() { for (const meta of subordinateStations) { // This should never happen, but just in case - if (idMap.has(meta.id)) throw new Error("Duplicate station ID found: " + meta.id) + if (idMap.has(meta.id)) + throw new Error('Duplicate station ID found: ' + meta.id) // At least one station lists itself as its own reference, but doesn't have harmonic data if (meta.id === meta.tidepredoffsets.refStationId) continue @@ -60,27 +54,13 @@ async function main() { console.log(`\nDone. Created ${subordinateStations.length} stations.`) } -function slugify(text) { - return String(text) - .toLowerCase() - .replace(/[^a-z0-9]+/g, '-') - .replace(/^-+|-+$/g, '') -} - -async function saveStation(data) { - let dir = NEW_STATIONS_DIR - if (data.region) dir = join(dir, data.region.toLowerCase()) - const filePath = join(dir, `${slugify(data.name)}.json`) - await mkdir(dir, { recursive: true }) - await writeFile(filePath, JSON.stringify(data, null, 2) + '\n') +async function saveStation(data: Station) { + await save(data) return data } -async function buildStation(meta) { - const id = slugify(['us', meta.state, meta.name].filter(Boolean).join('-')) - +async function buildStation(meta: any): Promise { const station = { - id, name: meta.name, continent: 'North America', country: 'United States', @@ -88,13 +68,12 @@ async function buildStation(meta) { type: meta.type == 'S' ? 'subordinate' : 'reference', latitude: meta.lat, longitude: meta.lng, - timezone: findTz(meta.lat, meta.lng)[0], + timezone: meta.timezone, source: { name: NOAA_SOURCE_NAME, id: meta.id, published_harmonics: true, url: `https://tidesandcurrents.noaa.gov/stationhome.html?id=${meta.id}`, - source_url: `https://api.tidesandcurrents.noaa.gov/mdapi/prod/webapi/stations/${meta.id}.json`, }, license: { type: 'public domain', @@ -115,7 +94,8 @@ async function buildStation(meta) { offsets: { reference: refId, height: { - type: meta.tidepredoffsets.heightAdjustedType === 'R' ? 'ratio' : 'fixed', + type: + meta.tidepredoffsets.heightAdjustedType === 'R' ? 'ratio' : 'fixed', high: meta.tidepredoffsets.heightOffsetHighTide, low: meta.tidepredoffsets.heightOffsetLowTide, }, @@ -140,7 +120,7 @@ async function buildStation(meta) { Object.assign(station, { harmonic_constituents: data.harmonicConstituents.HarmonicConstituents.map( - (h) => ({ + (h: any) => ({ name: h.name, description: h.description, amplitude: h.amplitude, @@ -155,16 +135,18 @@ async function buildStation(meta) { ...(data.datums.HAT ? { HAT: data.datums.HAT } : {}), // Some stations don't have all datums ...(data.datums.datums - ? Object.fromEntries(data.datums.datums.map((d) => [d.name, d.value])) + ? Object.fromEntries( + data.datums.datums.map((d: any) => [d.name, d.value]) + ) : {}), }, disclaimers: (data.disclaimers.disclaimers ?? []) - .map((d) => d.text) + .map((d: any) => d.text) .join('\n'), }) } - return station + return normalize(station as Station) } main().catch(console.error) diff --git a/tools/util.ts b/tools/util.ts new file mode 100644 index 000000000..d52650cdb --- /dev/null +++ b/tools/util.ts @@ -0,0 +1,49 @@ +/** + * Create a URL-safe slug from a station name + */ +export function slugify(text: string) { + return text + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/^-+|-+$/g, '') +} + +export function indexBy(data: T[], key: keyof T) { + return Object.fromEntries( + data.map((r) => { + return [r[key], r] + }) + ) +} + +export function groupBy( + data: T[], + keyFn: (item: T) => string +): Record { + const result: Record = {} + + for (const item of data) { + const key = keyFn(item) + if (!result[key]) { + result[key] = [] + } + result[key].push(item) + } + + return result +} + +/** + * Parse a CSV file + */ +export function parseCSV(content: string): T[] { + const lines = content.trim().split(/[\r\n]+/) + const headers = (lines.shift() ?? '').split(',') + + return lines.map((line) => { + const values = line.split(',') + return Object.fromEntries( + headers.map((header, index) => [header, values[index]]) + ) as T + }) +} diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 000000000..a098db02f --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "esnext", + "moduleResolution": "bundler", + + // Strictness + "strict": true, + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + "noImplicitReturns": true, + "noImplicitOverride": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noPropertyAccessFromIndexSignature": true, + + // Modern best practices + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true, + + // Output + "sourceMap": true, + "declaration": true + } +} diff --git a/tsconfig.json b/tsconfig.json index 75378043c..93552a0c5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,28 +1,10 @@ { + "extends": "./tsconfig.base.json", "compilerOptions": { "rootDir": "./src", "outDir": "./dist", - "module": "esnext", - "target": "esnext", - "sourceMap": true, - "declaration": true, "types": ["vite/client"], - - "noUncheckedIndexedAccess": true, - "exactOptionalPropertyTypes": true, - "noImplicitReturns": true, - "noImplicitOverride": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - "noPropertyAccessFromIndexSignature": true, - - // Recommended Options - "strict": true, - "verbatimModuleSyntax": true, - "isolatedModules": true, - "noUncheckedSideEffectImports": true, - "moduleDetection": "force", - "skipLibCheck": true - } + "tsBuildInfoFile": "./dist/.tsbuildinfo" + }, + "include": ["src/**/*"] } diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 000000000..498738f71 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "module": "nodenext", + "moduleResolution": "nodenext", + "noEmit": true, + "types": ["node", "vite/client"], + "allowImportingTsExtensions": true + }, + "include": ["vite.config.js", "test/**/*", "tools/**/*"], + "exclude": ["src/**/*.ts"] +}