diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 835bfba..d460f22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,7 +58,7 @@ jobs: - name: Regenerated declarations must match the committed ones run: | pnpm run gen-types - git diff --exit-code -- lib/sqlite3.d.ts lib/promises.d.ts lib/trace.d.ts + git diff --exit-code -- lib/sqlite3.d.ts lib/promises.d.ts lib/trace.d.ts lib/pool.d.ts # Fast test feedback via a dev rebuild instead of a full prebuild. diff --git a/contrib/check-jsdoc.js b/contrib/check-jsdoc.js index 465164f..51501b8 100644 --- a/contrib/check-jsdoc.js +++ b/contrib/check-jsdoc.js @@ -139,11 +139,19 @@ for (const file of FILES) { const name = m[1]; const where = `${file} ${name} (line ${i + 1})`; if (name === 'constructor' || seen.has(name)) return; - // tsc's declaration emit synthesizes `_base` aliases for - // heritage clauses in the generated entry (e.g. DatabaseClass_base - // for `class DatabaseClass extends NativeDatabase`); there is no - // source-level doc comment they could carry. - if (name.endsWith('_base') && file === 'lib/sqlite3.d.ts') return; + // tsc's declaration emit materializes the wrapper class's + // heritage clause as a module-local const in the generated entry + // (for `class DatabaseClass extends NativeDatabase`): TS 5.9 + // renamed the alias to `_base` (DatabaseClass_base), TS 7 + // keeps the source-local name (NativeDatabase). Either way it is + // compiler state, not a source declaration — there is no doc + // comment it could carry. + if ( + file === 'lib/sqlite3.d.ts' && + (name.endsWith('_base') || name === 'NativeDatabase') + ) { + return; + } seen.add(name); const doc = docFor(lines, i); diff --git a/lib/pool.d.ts b/lib/pool.d.ts index d172fd8..0755a8d 100644 --- a/lib/pool.d.ts +++ b/lib/pool.d.ts @@ -8,7 +8,7 @@ export type PoolOptions = { * with writes — the right shape for a write-heavy file or a * `:memory:` database. */ - readers?: number | undefined; + readers?: number; /** * set `PRAGMA journal_mode = WAL` on the * writer before readers connect (default true). WAL is what lets @@ -16,19 +16,19 @@ export type PoolOptions = { * filesystem that refuses WAL) readers can block on the writer and * rely on `busyTimeout`. */ - walMode?: boolean | undefined; + walMode?: boolean; /** * `PRAGMA busy_timeout` in milliseconds * for every connection (default 5000). */ - busyTimeout?: number | undefined; + busyTimeout?: number; /** * the integer * conversion mode for every connection (see * `configure('integerMode', …)`); the driver default (`'number'`) * applies when omitted. */ - integerMode?: "number" | "bigint" | "mixed" | undefined; + integerMode?: 'number' | 'bigint' | 'mixed'; }; /** * Options for a pool query. @@ -41,7 +41,7 @@ export type PoolQueryOptions = { * single-connection API, an abort that loses the race with a * completing query still rejects and drops the result. */ - signal?: AbortSignal | undefined; + signal?: AbortSignal; }; /** * The query surface inside {@link SqlitePool#transaction}, pinned to the @@ -52,49 +52,20 @@ export type PoolTransaction = { /** * runs a query on the writer, resolving every row. */ - read: (sql: string, params?: import("./native.js").BindParams) => Promise; + read: (sql: string, params?: import('./native.js').BindParams) => Promise; /** * runs a query on the writer, resolving the first row (or undefined). */ - get: (sql: string, params?: import("./native.js").BindParams) => Promise; + get: (sql: string, params?: import('./native.js').BindParams) => Promise; /** * runs a statement inside the transaction, resolving `{lastID, changes, lastIDBigInt}`. */ - write: (sql: string, params?: import("./native.js").BindParams) => Promise; + write: (sql: string, params?: import('./native.js').BindParams) => Promise; /** * runs raw SQL (DDL, pragmas) inside the transaction. */ exec: (sql: string) => Promise; }; -/** - * Creates a worker-thread pool over a database file: one writer - * connection plus `options.readers` read-only connections (default 4), - * each on its own worker. Writes serialize on the writer; reads fan out - * to the readers. All SQLite work happens off the calling thread. - * - * Requires a real file (or a `file:` URI): each connection is separate, - * so a plain `:memory:` database cannot be shared across the pool's - * workers — move in-memory data with `db.serializeToBytes()` + - * {@link sqlite3.deserializeFromBytes} in a worker instead (see - * docs/concurrency.md). With `readers: 0` a `:memory:` pool is fine: - * everything runs on the single writer. - * - * @param {string} filename the database file. - * @param {PoolOptions} [options] the pool options. - * @returns {Promise} the opened pool. - * @throws {TypeError} when the filename is missing or malformed, or an - * option is unknown/invalid. - * @since 9.0.0 - * @example - * const pool = await sqlite3.pool('app.db', { - * readers: 4, - * busyTimeout: 5000, - * }); - * const rows = await pool.read('SELECT * FROM t WHERE a = ?', [1]); - * await pool.write('INSERT INTO t (a) VALUES (?)', [2]); - * await pool.close(); - */ -export function pool(filename: string, options?: PoolOptions): Promise; /** * A worker-thread pool over one database file: a single writer * connection plus read-only reader connections, each on its own worker. @@ -111,7 +82,20 @@ export function pool(filename: string, options?: PoolOptions): Promise; - /** - * @param {string} filename the database file. - * @param {{ readers: number, walMode: boolean, busyTimeout: number, - * integerMode: ('number' | 'bigint' | 'mixed') | undefined }} options - * validated options. - */ - constructor(filename: string, options: { - readers: number; - walMode: boolean; - busyTimeout: number; - integerMode: ("number" | "bigint" | "mixed") | undefined; - }); /** * The database filename the pool was created with. * @@ -184,7 +156,7 @@ export class SqlitePool { * @example * const rows = await pool.read('SELECT id FROM users WHERE name = ?', ['alice']); */ - read(...args: any[]): Promise; + read(...args: any[]): Promise; /** * Runs a query on a reader connection, resolving the first row (or * `undefined`). Same routing and visibility rules as @@ -200,7 +172,7 @@ export class SqlitePool { * @example * const user = await pool.get('SELECT id FROM users WHERE name = ?', ['alice']); */ - get(...args: any[]): Promise; + get(...args: any[]): Promise; /** * Runs a statement on the writer connection, resolving * `{lastID, changes, lastIDBigInt}`. Writes serialize: concurrent @@ -217,7 +189,7 @@ export class SqlitePool { * @example * const result = await pool.write('INSERT INTO users (name) VALUES (?)', ['alice']); */ - write(...args: any[]): Promise; + write(...args: any[]): Promise; /** * Runs raw SQL on the writer connection: DDL, pragmas, * multi-statement scripts. Resolves once every statement has run. @@ -261,7 +233,7 @@ export class SqlitePool { * }); */ transaction(fn: (tx: PoolTransaction) => T | Promise, options?: { - mode?: "deferred" | "immediate" | "exclusive"; + mode?: 'deferred' | 'immediate' | 'exclusive'; }): Promise; /** * Closes the pool: refuses new work, waits for every in-flight @@ -285,5 +257,34 @@ export class SqlitePool { * @since 9.0.0 */ [Symbol.asyncDispose](): Promise; - #private; } +/** + * Creates a worker-thread pool over a database file: one writer + * connection plus `options.readers` read-only connections (default 4), + * each on its own worker. Writes serialize on the writer; reads fan out + * to the readers. All SQLite work happens off the calling thread. + * + * Requires a real file (or a `file:` URI): each connection is separate, + * so a plain `:memory:` database cannot be shared across the pool's + * workers — move in-memory data with `db.serializeToBytes()` + + * {@link sqlite3.deserializeFromBytes} in a worker instead (see + * docs/concurrency.md). With `readers: 0` a `:memory:` pool is fine: + * everything runs on the single writer. + * + * @param {string} filename the database file. + * @param {PoolOptions} [options] the pool options. + * @returns {Promise} the opened pool. + * @throws {TypeError} when the filename is missing or malformed, or an + * option is unknown/invalid. + * @since 9.0.0 + * @example + * const pool = await sqlite3.pool('app.db', { + * readers: 4, + * busyTimeout: 5000, + * }); + * const rows = await pool.read('SELECT * FROM t WHERE a = ?', [1]); + * await pool.write('INSERT INTO t (a) VALUES (?)', [2]); + * await pool.close(); + */ +declare function pool(filename: string, options?: PoolOptions): Promise; +export { pool, SqlitePool }; diff --git a/lib/promises.d.ts b/lib/promises.d.ts index 78552b4..1107834 100644 --- a/lib/promises.d.ts +++ b/lib/promises.d.ts @@ -1,49 +1,3 @@ -/** - * Installs the promise API onto the classes: dual-mode wrappers over the - * existing callback implementations, plus `open()`, `iterate()`, - * `stream()`, `transaction()` and dispose support. Called once from - * lib/sqlite3.js after every callback-mode method is in place. - * - * @param {import('./sqlite3.js').sqlite3} sqlite3 the binding's export - * object, carrying `Database`, `Statement` and `Backup`. - * @returns {void} - */ -export function installPromiseApi(sqlite3: import("./sqlite3.js").sqlite3): void; -/** - * Rewires `sqlite3.verbose()`: wraps the callback-mode cores with the - * long-stack-trace machinery, then reinstalls the dual-mode wrappers so - * promise rejections go through the same augmentation path. - * - * @param {(object: Record, property: string) => void} extendTrace the trace wrapper from lib/trace.js. - * @returns {void} - */ -export function retracePromiseApi(extendTrace: (object: Record, property: string) => void): void; -/** - * Options driving {@link createAsyncIterator}. - */ -export type IteratorOptions = { - /** - * bind parameters for the first fetch. - */ - params?: unknown[] | undefined; - /** - * whether the iterator finalizes (true) - * or merely resets (false) its statement on teardown. - */ - ownsStatement?: boolean | undefined; - /** - * abort the iteration mid-cursor. - */ - signal?: AbortSignal | undefined; - /** - * interrupt the connection on abort. - */ - interrupt?: (() => void) | undefined; - /** - * lazily create the statement (db.iterate). - */ - prepare?: ((callback: (err: Error | null) => void) => import("./sqlite3.js").Statement) | undefined; -}; /** * What promise-mode `run()` resolves to. * @@ -77,7 +31,7 @@ export type SignalOptions = { /** * Abort this operation by interrupting the connection. */ - signal?: AbortSignal | undefined; + signal?: AbortSignal; }; /** * Options for `Database#transaction`. @@ -86,26 +40,26 @@ export type TransactionOptions = { /** * Transaction start mode. */ - mode?: "deferred" | "immediate" | "exclusive" | undefined; + mode?: 'deferred' | 'immediate' | 'exclusive'; /** * Nest via SAVEPOINT even at the top level. */ - savepoint?: boolean | undefined; + savepoint?: boolean; /** * Run the body inside serialize() (strict * FIFO, at the cost of bypassing the statement cache). */ - serialize?: boolean | undefined; + serialize?: boolean; /** * Abort via `db.interrupt()` and reject with the signal's reason. */ - signal?: AbortSignal | undefined; + signal?: AbortSignal; }; /** * Callback of `Statement#fetch`: receives up to `count` rows and whether * the cursor is exhausted. */ -export type FetchCallback = (err: import("./native.js").SqliteError | null, rows: import("./native.js").Row[], done: boolean) => void; +export type FetchCallback = (err: import('./native.js').SqliteError | null, rows: import('./native.js').Row[], done: boolean) => void; /** * Opens a database and resolves once the connection is ready. The * `Database` constructor cannot return a promise; this is the @@ -113,13 +67,7 @@ export type FetchCallback = (err: import("./native.js").SqliteError | null, rows * argument is either open flags or a v9 options object (`mode`, * `untrusted`). */ -export type OpenFunction = (filename: string, modeOrOptions?: number | import("./sqlite3.js").OpenOptions) => Promise; -export type Installed = { - sqlite3: import("./sqlite3.js").sqlite3; - Database: typeof import("./sqlite3-binding.js").Database; - Statement: typeof import("./sqlite3-binding.js").Statement; - Backup: typeof import("./sqlite3-binding.js").Backup; -}; +export type OpenFunction = (filename: string, modeOrOptions?: number | import('./sqlite3.js').OpenOptions) => Promise; /** * Records which database owns a statement, so AbortSignal handling can * reach `db.interrupt()` from a statement method. @@ -128,4 +76,57 @@ export type Installed = { * @param {import('./sqlite3.js').Statement} statement the prepared statement. * @returns {import('./sqlite3.js').Statement} the statement, for inline use. */ -export function associateStatement(db: import("./sqlite3-binding.js").Database, statement: import("./sqlite3.js").Statement): import("./sqlite3.js").Statement; +declare function associateStatement(db: import('./sqlite3-binding.js').Database, statement: import('./sqlite3.js').Statement): import('./sqlite3.js').Statement; +/** + * Options driving {@link createAsyncIterator}. + */ +export type IteratorOptions = { + /** + * bind parameters for the first fetch. + */ + params?: unknown[]; + /** + * whether the iterator finalizes (true) + * or merely resets (false) its statement on teardown. + */ + ownsStatement?: boolean; + /** + * abort the iteration mid-cursor. + */ + signal?: AbortSignal; + /** + * interrupt the connection on abort. + */ + interrupt?: () => void; + /** + * lazily create the statement (db.iterate). + */ + prepare?: ((callback: (err: Error | null) => void) => import('./sqlite3.js').Statement); +}; +export type Installed = { + sqlite3: import('./sqlite3.js').sqlite3; + Database: typeof import('./sqlite3-binding.js').Database; + Statement: typeof import('./sqlite3-binding.js').Statement; + Backup: typeof import('./sqlite3-binding.js').Backup; +}; +/** + * Installs the promise API onto the classes: dual-mode wrappers over the + * existing callback implementations, plus `open()`, `iterate()`, + * `stream()`, `transaction()` and dispose support. Called once from + * lib/sqlite3.js after every callback-mode method is in place. + * + * @param {import('./sqlite3.js').sqlite3} sqlite3 the binding's export + * object, carrying `Database`, `Statement` and `Backup`. + * @returns {void} + */ +export declare function installPromiseApi(sqlite3: import('./sqlite3.js').sqlite3): void; +/** + * Rewires `sqlite3.verbose()`: wraps the callback-mode cores with the + * long-stack-trace machinery, then reinstalls the dual-mode wrappers so + * promise rejections go through the same augmentation path. + * + * @param {(object: Record, property: string) => void} extendTrace the trace wrapper from lib/trace.js. + * @returns {void} + */ +export declare function retracePromiseApi(extendTrace: (object: Record, property: string) => void): void; +export { associateStatement }; diff --git a/lib/sqlite3.d.ts b/lib/sqlite3.d.ts index ca856df..6735e0d 100644 --- a/lib/sqlite3.d.ts +++ b/lib/sqlite3.d.ts @@ -6,8 +6,6 @@ // lib/promises.d.ts and lib/trace.d.ts. // The three shipped .d.ts files together form the public types. -export default sqlite3; -export { DatabaseClass as Database }; /** * A native class (Database, Statement or Backup) before the EventEmitter * prototype is copied onto it. @@ -23,11 +21,11 @@ export type CachedRegistry = { /** * Open (or reuse) a connection, optionally with a callback. */ - Database: (filename: string, callback?: (this: import("./sqlite3-binding.js").Database, err: Error | null) => void) => import("./sqlite3-binding.js").Database; + Database: (filename: string, callback?: (this: import('./sqlite3-binding.js').Database, err: Error | null) => void) => import('./sqlite3-binding.js').Database; /** * The registry itself, keyed by resolved path. */ - objects: Record; + objects: Record; }; /** * The constructor type of the v9 `Database` wrapper: every pre-v9 @@ -36,7 +34,7 @@ export type CachedRegistry = { * below does not reference the module it lives in — that self-reference * is a type-resolution cycle. */ -export type DatabaseConstructor = new (filename: string, a?: number | OpenOptions | ((this: import("./sqlite3-binding.js").Database, err: import("./native.js").SqliteError | null) => void), b?: ((this: import("./sqlite3-binding.js").Database, err: import("./native.js").SqliteError | null) => void) | OpenOptions) => import("./sqlite3-binding.js").Database; +export type DatabaseConstructor = new (filename: string, a?: number | OpenOptions | ((this: import('./sqlite3-binding.js').Database, err: import('./native.js').SqliteError | null) => void), b?: ((this: import('./sqlite3-binding.js').Database, err: import('./native.js').SqliteError | null) => void) | OpenOptions) => import('./sqlite3-binding.js').Database; /** * The public `sqlite3` namespace object the package exports as its * default: the native binding (the five classes and every SQLite @@ -46,14 +44,16 @@ export type DatabaseConstructor = new (filename: string, a?: number | OpenOption * {@link OpenOptions} constructor forms typecheck; instances satisfy the * native type everywhere. */ -export type sqlite3 = import("./sqlite3-binding.js").NativeBinding & { +export type sqlite3 = import('./sqlite3-binding.js').NativeBinding & { Database: DatabaseConstructor; verbose: () => sqlite3; cached: CachedRegistry; - open: import("./promises.js").OpenFunction; - deserializeFromBytes: (bytes: Uint8Array | ArrayBuffer | DataView, options?: import("./native.js").DeserializeOptions) => Promise; - pool: typeof import("./pool.js").pool; + open: import('./promises.js').OpenFunction; + deserializeFromBytes: (bytes: Uint8Array | ArrayBuffer | DataView, options?: import('./native.js').DeserializeOptions) => Promise; + pool: typeof import('./pool.js').pool; }; +declare const sqlite3: sqlite3; +declare const NativeDatabase: typeof import("./native.js").Database & DatabaseConstructor; export type ExtensionPolicy = { /** * the connection was opened `{ untrusted: true }`. @@ -82,7 +82,7 @@ export type OpenOptions = { /** * open flags, e.g. `sqlite3.OPEN_READWRITE`. */ - mode?: number | undefined; + mode?: number; /** * harden the connection for an * attacker-supplied database file: defensive mode, untrusted schema, @@ -90,10 +90,8 @@ export type OpenOptions = { * conservative run-time limits and a deny-all ATTACH gate. See * docs/security.md#untrusted-database-files. */ - untrusted?: boolean | undefined; + untrusted?: boolean; }; -declare const sqlite3: sqlite3; -declare const DatabaseClass_base: typeof import("./native.js").Database & DatabaseConstructor; /** * A connection to a SQLite database — the v9 wrapper around the native * class. Adds the permission-model checks on every open path, the @@ -102,10 +100,9 @@ declare const DatabaseClass_base: typeof import("./native.js").Database & Databa * else, including all pre-v9 positional constructor forms, behaves * exactly as before. * - * @extends {NativeDatabase} * @since 9.0.0 */ -declare class DatabaseClass extends DatabaseClass_base { +declare class DatabaseClass extends NativeDatabase { /** * Opens a database connection. The open itself is asynchronous; the * callback fires (or the `'open'` event emits) once it completes. @@ -127,9 +124,11 @@ declare class DatabaseClass extends DatabaseClass_base { * the target is not permitted, naming the path and the remedy. * @throws {TypeError} when the arguments are malformed. */ - constructor(filename: string, a?: number | OpenOptions | ((this: import("./sqlite3-binding.js").Database, err: import("./native.js").SqliteError | null) => void), b?: ((this: import("./sqlite3-binding.js").Database, err: import("./native.js").SqliteError | null) => void) | OpenOptions); + constructor(filename: string, a?: number | OpenOptions | ((this: import('./sqlite3-binding.js').Database, err: import('./native.js').SqliteError | null) => void), b?: ((this: import('./sqlite3-binding.js').Database, err: import('./native.js').SqliteError | null) => void) | OpenOptions); } -export { Backup, Blob, Session, Statement } from "./sqlite3-binding.js"; +export default sqlite3; +export { Backup, Blob, Session, Statement } from './sqlite3-binding.js'; +export { DatabaseClass as Database }; import './augment.js'; export type { FetchCallback, diff --git a/lib/sqlite3.js b/lib/sqlite3.js index e69899d..fb541d9 100644 --- a/lib/sqlite3.js +++ b/lib/sqlite3.js @@ -739,7 +739,6 @@ function isOpenOptions(value) { * else, including all pre-v9 positional constructor forms, behaves * exactly as before. * - * @extends {NativeDatabase} * @since 9.0.0 */ class DatabaseClass extends NativeDatabase { diff --git a/lib/trace.d.ts b/lib/trace.d.ts index 4779f74..37ded73 100644 --- a/lib/trace.d.ts +++ b/lib/trace.d.ts @@ -22,11 +22,12 @@ export type Traceable = (this: unknown, ...args: unknown[]) => unknown; * @param {number} [pos=-1] position of the callback argument. * @returns {void} */ -export function extendTrace(object: Record, property: string, pos?: number): void; +declare function extendTrace(object: Record, property: string, pos?: number): void; /** * Drops this file's own frames from a stack string. * * @param {string | undefined} stackStr the stack to filter. * @returns {string[]} the surviving frames. */ -export function filter(stackStr: string | undefined): string[]; +declare function filter(stackStr: string | undefined): string[]; +export { extendTrace, filter }; diff --git a/package.json b/package.json index eab24db..37a4038 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "electron": "43.4.1", "prebuildify": "^6.0.1", "semver": "^7.8.5", - "typescript": "~5.9.3" + "typescript": "7.0.2" }, "peerDependencies": { "node-gyp": "13.x" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5f134af..7f200a3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,8 +34,8 @@ importers: specifier: ^7.8.5 version: 7.8.5 typescript: - specifier: ~5.9.3 - version: 5.9.3 + specifier: 7.0.2 + version: 7.0.2 optionalDependencies: node-gyp: specifier: 13.x @@ -147,6 +147,126 @@ packages: '@types/node@24.13.3': resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==, tarball: https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz} + '@typescript/typescript-aix-ppc64@7.0.2': + resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==, tarball: https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [aix] + + '@typescript/typescript-darwin-arm64@7.0.2': + resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==, tarball: https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [darwin] + + '@typescript/typescript-darwin-x64@7.0.2': + resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==, tarball: https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [darwin] + + '@typescript/typescript-freebsd-arm64@7.0.2': + resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==, tarball: https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [freebsd] + + '@typescript/typescript-freebsd-x64@7.0.2': + resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==, tarball: https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [freebsd] + + '@typescript/typescript-linux-arm64@7.0.2': + resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + + '@typescript/typescript-linux-arm@7.0.2': + resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [arm] + os: [linux] + + '@typescript/typescript-linux-loong64@7.0.2': + resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [loong64] + os: [linux] + + '@typescript/typescript-linux-mips64el@7.0.2': + resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [mips64el] + os: [linux] + + '@typescript/typescript-linux-ppc64@7.0.2': + resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [linux] + + '@typescript/typescript-linux-riscv64@7.0.2': + resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [riscv64] + os: [linux] + + '@typescript/typescript-linux-s390x@7.0.2': + resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [s390x] + os: [linux] + + '@typescript/typescript-linux-x64@7.0.2': + resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + + '@typescript/typescript-netbsd-arm64@7.0.2': + resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==, tarball: https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [netbsd] + + '@typescript/typescript-netbsd-x64@7.0.2': + resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==, tarball: https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [netbsd] + + '@typescript/typescript-openbsd-arm64@7.0.2': + resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==, tarball: https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [openbsd] + + '@typescript/typescript-openbsd-x64@7.0.2': + resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==, tarball: https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [openbsd] + + '@typescript/typescript-sunos-x64@7.0.2': + resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==, tarball: https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [sunos] + + '@typescript/typescript-win32-arm64@7.0.2': + resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==, tarball: https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [win32] + + '@typescript/typescript-win32-x64@7.0.2': + resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==, tarball: https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [win32] + '@xmldom/xmldom@0.9.12': resolution: {integrity: sha512-5AXjrcMClTryPe9LgZrygpB1lj7s0S9E0+W+AHaVKAVyHanafK86iPSvG5xHVSp/jC+VH1UXu0TAEmY279xH7A==, tarball: https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.12.tgz} engines: {node: '>=14.6'} @@ -430,9 +550,9 @@ packages: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==, tarball: https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz} engines: {node: '>=12.0.0'} - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==, tarball: https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz} - engines: {node: '>=14.17'} + typescript@7.0.2: + resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==, tarball: https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz} + engines: {node: '>=16.20.0'} hasBin: true undici-types@7.18.2: @@ -598,6 +718,66 @@ snapshots: dependencies: undici-types: 7.18.2 + '@typescript/typescript-aix-ppc64@7.0.2': + optional: true + + '@typescript/typescript-darwin-arm64@7.0.2': + optional: true + + '@typescript/typescript-darwin-x64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-x64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm@7.0.2': + optional: true + + '@typescript/typescript-linux-loong64@7.0.2': + optional: true + + '@typescript/typescript-linux-mips64el@7.0.2': + optional: true + + '@typescript/typescript-linux-ppc64@7.0.2': + optional: true + + '@typescript/typescript-linux-riscv64@7.0.2': + optional: true + + '@typescript/typescript-linux-s390x@7.0.2': + optional: true + + '@typescript/typescript-linux-x64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-sunos-x64@7.0.2': + optional: true + + '@typescript/typescript-win32-arm64@7.0.2': + optional: true + + '@typescript/typescript-win32-x64@7.0.2': + optional: true + '@xmldom/xmldom@0.9.12': {} abbrev@5.0.0: @@ -880,7 +1060,28 @@ snapshots: picomatch: 4.0.5 optional: true - typescript@5.9.3: {} + typescript@7.0.2: + optionalDependencies: + '@typescript/typescript-aix-ppc64': 7.0.2 + '@typescript/typescript-darwin-arm64': 7.0.2 + '@typescript/typescript-darwin-x64': 7.0.2 + '@typescript/typescript-freebsd-arm64': 7.0.2 + '@typescript/typescript-freebsd-x64': 7.0.2 + '@typescript/typescript-linux-arm': 7.0.2 + '@typescript/typescript-linux-arm64': 7.0.2 + '@typescript/typescript-linux-loong64': 7.0.2 + '@typescript/typescript-linux-mips64el': 7.0.2 + '@typescript/typescript-linux-ppc64': 7.0.2 + '@typescript/typescript-linux-riscv64': 7.0.2 + '@typescript/typescript-linux-s390x': 7.0.2 + '@typescript/typescript-linux-x64': 7.0.2 + '@typescript/typescript-netbsd-arm64': 7.0.2 + '@typescript/typescript-netbsd-x64': 7.0.2 + '@typescript/typescript-openbsd-arm64': 7.0.2 + '@typescript/typescript-openbsd-x64': 7.0.2 + '@typescript/typescript-sunos-x64': 7.0.2 + '@typescript/typescript-win32-arm64': 7.0.2 + '@typescript/typescript-win32-x64': 7.0.2 undici-types@7.18.2: {} diff --git a/tools/gen-types.js b/tools/gen-types.js index ca01d44..f2760c9 100644 --- a/tools/gen-types.js +++ b/tools/gen-types.js @@ -5,8 +5,17 @@ // Runs `tsc -p tsconfig.types.json`, which typechecks lib/*.js (checkJs) // against the hand-written native declarations in lib/native.d.ts and // emits declarations into the gitignored types-gen/ scratch directory. -// This script then copies them into lib/, post-processing the package's -// `types` entry (lib/sqlite3.d.ts) in three deterministic steps: +// This script then normalizes the emit with two deterministic steps +// before post-processing the package's `types` entry (lib/sqlite3.d.ts): +// +// 1. strip the raw `@typedef` blocks the JS emit copies verbatim, +// 2. re-attach each @typedef's summary text from its lib/*.js source +// to the rendered `export type` it produced. TS 5.9 attached this +// summary itself; TS 7 drops it (and, in lib/promises.js and +// lib/pool.js, drops the raw block too), which would silently +// strip every type summary from the shipped docs. +// +// The entry is then post-processed in three deterministic steps: // // 1. prepend the GENERATED header, // 2. append `import './augment.js'` so consumers of the package load @@ -24,7 +33,7 @@ // The result is committed; CI regenerates and fails on any diff, so a // declaration can neither drift from the JSDoc nor be silently dropped. import { execFileSync } from 'node:child_process'; -import { copyFileSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { readFileSync, rmSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -47,14 +56,72 @@ const entry = path.join(root, 'lib', 'sqlite3.d.ts'); // tsc's JS emit attaches the original JSDoc verbatim, so a rendered // `export type X` can be followed by a second, raw copy of its @typedef -// block. Drop those: the rendered declaration carries the same docs. +// block. Drop those: the rendered declaration carries the same docs +// once the summaries below are re-attached. function stripRawTypedefComments(text) { return text.replace(/\/\*\*(?:[^*]|\*(?!\/))*?@typedef[\s\S]*?\*\/\n/g, ''); } -const emitted = stripRawTypedefComments( - readFileSync(path.join(emitDir, 'sqlite3.d.ts'), 'utf8'), -); +// The summary text of every `@typedef` in a source file: the comment +// lines before the first @tag (the @property/@since tags are rendered +// or dropped by tsc itself). Blocks without a summary — e.g. +// ExtensionPolicy, documented only through its @property tags — are +// skipped; there is nothing to re-attach for them. +function typedefSummaries(source) { + const summaries = new Map(); + for (const match of source.matchAll(/\/\*\*[\s\S]*?\*\//g)) { + const name = match[0].match( + /@typedef\s*\{[\s\S]*?\}\s*([A-Za-z_$][\w$]*)/, + )?.[1]; + if (!name || summaries.has(name)) continue; + const summary = []; + for (const line of match[0].split('\n').slice(1, -1)) { + const text = line.replace(/^\s*\/?\*+\s?/, '').replace(/\*\/$/, ''); + if (/^@\w/.test(text.trim())) break; + summary.push(text.trimEnd()); + } + while (summary.length && !summary.at(-1).trim()) summary.pop(); + if (summary.some((line) => line.trim())) summaries.set(name, summary); + } + return summaries; +} + +// Prepend each typedef's summary to the rendered `export type` it +// produced, unless the emit already documents that declaration (TS 7 +// keeps docs on functions and classes; only the rendered type aliases +// come out bare). +function attachTypedefSummaries(text, summaries) { + const out = []; + for (const line of text.split('\n')) { + const name = line.match(/^export type ([A-Za-z_$][\w$]*)\b/)?.[1]; + const summary = name === undefined ? undefined : summaries.get(name); + if (summary && out.at(-1) !== ' */') { + out.push('/**'); + for (const text of summary) out.push(` * ${text}`.trimEnd()); + out.push(' */'); + } + out.push(line); + } + return out.join('\n'); +} + +// The lib/*.js source each emitted declaration file is generated from. +const summarySources = { + 'sqlite3.d.ts': 'sqlite3.js', + 'promises.d.ts': 'promises.js', + 'trace.d.ts': 'trace.js', + 'pool.d.ts': 'pool.js', +}; + +const emitted = {}; +for (const [declaration, source] of Object.entries(summarySources)) { + let text = readFileSync(path.join(emitDir, declaration), 'utf8'); + if (declaration === 'sqlite3.d.ts') text = stripRawTypedefComments(text); + emitted[declaration] = attachTypedefSummaries( + text, + typedefSummaries(readFileSync(path.join(root, 'lib', source), 'utf8')), + ); +} // Every `export type X` / `export interface X` in the hand-written // island, keys sorted for a stable diff. Classes are re-exported by the @@ -102,24 +169,18 @@ const header = `// GENERATED FILE — DO NOT EDIT. writeFileSync( entry, - `${header}${emitted}${augmentImport}\n` + + `${header}${emitted['sqlite3.d.ts']}${augmentImport}\n` + block('promises.js', promisesPublicTypes) + block('pool.js', poolPublicTypes) + block('native.js', nativeTypes), ); -copyFileSync( - path.join(emitDir, 'promises.d.ts'), +writeFileSync( path.join(root, 'lib', 'promises.d.ts'), + emitted['promises.d.ts'], ); -copyFileSync( - path.join(emitDir, 'trace.d.ts'), - path.join(root, 'lib', 'trace.d.ts'), -); -copyFileSync( - path.join(emitDir, 'pool.d.ts'), - path.join(root, 'lib', 'pool.d.ts'), -); +writeFileSync(path.join(root, 'lib', 'trace.d.ts'), emitted['trace.d.ts']); +writeFileSync(path.join(root, 'lib', 'pool.d.ts'), emitted['pool.d.ts']); console.log( 'gen-types: lib/sqlite3.d.ts, lib/promises.d.ts, lib/trace.d.ts, lib/pool.d.ts regenerated.', diff --git a/types/consumer.check.ts b/types/consumer.check.ts index 5dd661d..222ee78 100644 --- a/types/consumer.check.ts +++ b/types/consumer.check.ts @@ -57,8 +57,8 @@ async function consumer(): Promise { const constructed = new sqlite3.Database(':memory:', { untrusted: true, }); - // @ts-expect-error untrusted is boolean const constructed2 = new sqlite3.Database(':memory:', { + // @ts-expect-error untrusted is boolean untrusted: 'yes', }); void constructed;