@c9up/ream 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Application.d.ts +85 -5
- package/dist/Application.d.ts.map +1 -1
- package/dist/Application.js +171 -21
- package/dist/Application.js.map +1 -1
- package/dist/ErrorBoundary.d.ts +1 -7
- package/dist/ErrorBoundary.d.ts.map +1 -1
- package/dist/ErrorBoundary.js +31 -31
- package/dist/ErrorBoundary.js.map +1 -1
- package/dist/Ignitor.d.ts +15 -46
- package/dist/Ignitor.d.ts.map +1 -1
- package/dist/Ignitor.js +178 -173
- package/dist/Ignitor.js.map +1 -1
- package/dist/env/Env.d.ts +6 -0
- package/dist/env/Env.d.ts.map +1 -1
- package/dist/env/Env.js +6 -0
- package/dist/env/Env.js.map +1 -1
- package/dist/events/Emitter.d.ts +2 -6
- package/dist/events/Emitter.d.ts.map +1 -1
- package/dist/events/Emitter.js +45 -42
- package/dist/events/Emitter.js.map +1 -1
- package/dist/events/native.d.ts +13 -11
- package/dist/events/native.d.ts.map +1 -1
- package/dist/events/native.js.map +1 -1
- package/dist/http/HttpContext.d.ts +1 -1
- package/dist/http/HttpContext.d.ts.map +1 -1
- package/dist/http/Request.js +0 -13
- package/dist/http/Request.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/native/generated.d.ts +243 -0
- package/dist/native/generated.d.ts.map +1 -0
- package/dist/native/generated.js +7 -0
- package/dist/native/generated.js.map +1 -0
- package/dist/session/drivers/CookieDriver.d.ts +1 -1
- package/dist/session/drivers/CookieDriver.d.ts.map +1 -1
- package/dist/session/drivers/CookieDriver.js +4 -4
- package/dist/session/drivers/CookieDriver.js.map +1 -1
- package/dist/types/index.d.ts +88 -5
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +8 -3
- package/dist/types/index.js.map +1 -1
- package/events.win32-x64-msvc.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +3 -2
- package/scheduler.win32-x64-msvc.node +0 -0
- package/scripts/build-napi-types.mjs +68 -0
- package/scripts/generate-napi-types.mjs +171 -0
- package/src/Application.ts +221 -21
- package/src/ErrorBoundary.ts +31 -31
- package/src/Ignitor.ts +185 -172
- package/src/env/Env.ts +6 -0
- package/src/events/Emitter.ts +45 -42
- package/src/events/native.ts +21 -14
- package/src/http/HttpContext.ts +1 -1
- package/src/http/Request.ts +0 -13
- package/src/index.ts +2 -2
- package/src/native/generated.ts +291 -0
- package/src/session/drivers/CookieDriver.ts +4 -4
- package/src/types/index.ts +92 -5
- package/dist/types/authenticators.d.ts +0 -24
- package/dist/types/authenticators.d.ts.map +0 -1
- package/dist/types/authenticators.js +0 -2
- package/dist/types/authenticators.js.map +0 -1
- package/dist/types/container.d.ts +0 -64
- package/dist/types/container.d.ts.map +0 -1
- package/dist/types/container.js +0 -23
- package/dist/types/container.js.map +0 -1
- package/src/types/authenticators.ts +0 -24
- package/src/types/container.ts +0 -66
package/dist/types/index.d.ts
CHANGED
|
@@ -1,10 +1,93 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The interfaces an application or a package augments
|
|
2
|
+
* The interfaces an application or a package augments — `@c9up/ream/types`.
|
|
3
3
|
*
|
|
4
4
|
* Resolving from the container and picking an auth guard are both string
|
|
5
|
-
* lookups; without a shared interface to augment, every call site casts.
|
|
6
|
-
*
|
|
5
|
+
* lookups; without a shared interface to augment, every call site casts.
|
|
6
|
+
*
|
|
7
|
+
* The augmentable interfaces are DECLARED here rather than re-exported from a
|
|
8
|
+
* neighbouring file, and that is load-bearing: TypeScript augments the module
|
|
9
|
+
* that declares an interface, so a re-export makes
|
|
10
|
+
* `declare module '@c9up/ream/types' { interface Authenticators { … } }` a
|
|
11
|
+
* duplicate declaration instead of an augmentation. warden hit exactly that.
|
|
12
|
+
*/
|
|
13
|
+
import type { Application } from '../Application.js';
|
|
14
|
+
import type { ConfigStore } from '../ConfigLoader.js';
|
|
15
|
+
import type { Console } from '../console/Console.js';
|
|
16
|
+
import type { Kernel } from '../console/Kernel.js';
|
|
17
|
+
import type { Emitter } from '../events/Emitter.js';
|
|
18
|
+
import type { HttpContext } from '../http/HttpContext.js';
|
|
19
|
+
import type { MiddlewareRegistry } from '../middleware/Pipeline.js';
|
|
20
|
+
import type { MigrationRegistry } from '../migrations/MigrationRegistry.js';
|
|
21
|
+
import type { Router } from '../router/Router.js';
|
|
22
|
+
import type { CookieSigner } from '../security/CookieSigner.js';
|
|
23
|
+
import type { SignedUrl } from '../security/SignedUrl.js';
|
|
24
|
+
import type { Server } from '../server/Server.js';
|
|
25
|
+
/**
|
|
26
|
+
* Guard name → what `auth.use(name)` hands back.
|
|
27
|
+
*
|
|
28
|
+
* Empty here, and deliberately: ream owns no auth package, so it cannot know
|
|
29
|
+
* the guards an app configured. The auth package fills it in:
|
|
30
|
+
*
|
|
31
|
+
* ```ts
|
|
32
|
+
* declare module '@c9up/ream/types' {
|
|
33
|
+
* interface Authenticators {
|
|
34
|
+
* session: SessionGuard
|
|
35
|
+
* }
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* Until something augments it, `keyof Authenticators` is `never` and `use()`
|
|
40
|
+
* falls through to its `unknown` signature — the previous behaviour kept as
|
|
41
|
+
* the floor rather than the ceiling.
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* An EMPTY INTERFACE is the whole mechanism here, not an oversight. Rewritten
|
|
45
|
+
* as `type Authenticators = {}` the declaration stops being augmentable:
|
|
46
|
+
* `declare module '@c9up/ream/types' { interface Authenticators { … } }`
|
|
47
|
+
* becomes a duplicate identifier instead of a merge, and warden cannot type
|
|
48
|
+
* `ctx.auth.use()`. That is exactly what shipped in 0.2.3, where the formatter
|
|
49
|
+
* had rewritten it.
|
|
50
|
+
*/
|
|
51
|
+
export interface Authenticators {
|
|
52
|
+
}
|
|
53
|
+
/** A guard name this application knows about. */
|
|
54
|
+
export type AuthenticatorName = keyof Authenticators;
|
|
55
|
+
/**
|
|
56
|
+
* The container's known bindings.
|
|
57
|
+
*
|
|
58
|
+
* Ream core registers the entries below; anything else — `auth` (warden),
|
|
59
|
+
* `logger` (spectrum), `db` (atlas) — reaches this interface by augmentation
|
|
60
|
+
* from the package that owns it, which is why it is open rather than a closed
|
|
61
|
+
* union.
|
|
7
62
|
*/
|
|
8
|
-
export
|
|
9
|
-
|
|
63
|
+
export interface ContainerBindings {
|
|
64
|
+
/** The application instance. */
|
|
65
|
+
app: Application;
|
|
66
|
+
/** Absolute path to the application root. */
|
|
67
|
+
appRoot: string;
|
|
68
|
+
/** The config store built from `config/*.ts`. */
|
|
69
|
+
config: ConfigStore;
|
|
70
|
+
/** The console application (AdonisJS calls its equivalent `ace`). */
|
|
71
|
+
console: Console;
|
|
72
|
+
/** The console kernel that dispatches commands. */
|
|
73
|
+
consoleKernel: Kernel;
|
|
74
|
+
/** The event emitter. */
|
|
75
|
+
emitter: Emitter;
|
|
76
|
+
/** Cookie/value signing and encryption, backed by `APP_KEY`. */
|
|
77
|
+
encryption: CookieSigner;
|
|
78
|
+
/** The `HttpContext` class itself — for `HttpContext.getOrFail()` style access. */
|
|
79
|
+
HttpContext: typeof HttpContext;
|
|
80
|
+
/** Named middleware registered by the app kernel. */
|
|
81
|
+
middleware: MiddlewareRegistry;
|
|
82
|
+
/** Migration sources contributed by data packages (atlas, eon, ...). */
|
|
83
|
+
migrations: MigrationRegistry;
|
|
84
|
+
/** The HTTP router. */
|
|
85
|
+
router: Router;
|
|
86
|
+
/** The HTTP server. */
|
|
87
|
+
server: Server;
|
|
88
|
+
/** Signed-URL generation and verification. */
|
|
89
|
+
signedUrl: SignedUrl;
|
|
90
|
+
}
|
|
91
|
+
/** A token this container knows how to resolve. */
|
|
92
|
+
export type ContainerBinding = keyof ContainerBindings;
|
|
10
93
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AACnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAA;AAC3E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAEjD;;;;;;;;;;;;;;;;;GAiBG;AACH;;;;;;;GAOG;AAEH,MAAM,WAAW,cAAc;CAAG;AAElC,iDAAiD;AACjD,MAAM,MAAM,iBAAiB,GAAG,MAAM,cAAc,CAAA;AAEpD;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,gCAAgC;IAChC,GAAG,EAAE,WAAW,CAAA;IAChB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAA;IACf,iDAAiD;IACjD,MAAM,EAAE,WAAW,CAAA;IACnB,qEAAqE;IACrE,OAAO,EAAE,OAAO,CAAA;IAChB,mDAAmD;IACnD,aAAa,EAAE,MAAM,CAAA;IACrB,yBAAyB;IACzB,OAAO,EAAE,OAAO,CAAA;IAChB,gEAAgE;IAChE,UAAU,EAAE,YAAY,CAAA;IACxB,mFAAmF;IACnF,WAAW,EAAE,OAAO,WAAW,CAAA;IAC/B,qDAAqD;IACrD,UAAU,EAAE,kBAAkB,CAAA;IAC9B,wEAAwE;IACxE,UAAU,EAAE,iBAAiB,CAAA;IAC7B,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,8CAA8C;IAC9C,SAAS,EAAE,SAAS,CAAA;CACrB;AAED,mDAAmD;AACnD,MAAM,MAAM,gBAAgB,GAAG,MAAM,iBAAiB,CAAA"}
|
package/dist/types/index.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The interfaces an application or a package augments
|
|
2
|
+
* The interfaces an application or a package augments — `@c9up/ream/types`.
|
|
3
3
|
*
|
|
4
4
|
* Resolving from the container and picking an auth guard are both string
|
|
5
|
-
* lookups; without a shared interface to augment, every call site casts.
|
|
6
|
-
*
|
|
5
|
+
* lookups; without a shared interface to augment, every call site casts.
|
|
6
|
+
*
|
|
7
|
+
* The augmentable interfaces are DECLARED here rather than re-exported from a
|
|
8
|
+
* neighbouring file, and that is load-bearing: TypeScript augments the module
|
|
9
|
+
* that declares an interface, so a re-export makes
|
|
10
|
+
* `declare module '@c9up/ream/types' { interface Authenticators { … } }` a
|
|
11
|
+
* duplicate declaration instead of an augmentation. warden hit exactly that.
|
|
7
12
|
*/
|
|
8
13
|
export {};
|
|
9
14
|
//# sourceMappingURL=index.js.map
|
package/dist/types/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c9up/ream",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "Ream — Rust-powered Node.js application framework",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -208,7 +208,8 @@
|
|
|
208
208
|
"prebuild": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
209
209
|
"build": "tsc -p tsconfig.build.json",
|
|
210
210
|
"build:rust": "cargo build --release -p ream-http-napi -p ream-scheduler-napi -p ream-events-napi",
|
|
211
|
-
"build:napi": "
|
|
211
|
+
"build:napi-types": "node scripts/build-napi-types.mjs",
|
|
212
|
+
"build:napi": "pnpm build:rust && pnpm build:napi-types && node scripts/copy-napi.mjs",
|
|
212
213
|
"test": "vitest run",
|
|
213
214
|
"test:rust": "cargo test --all",
|
|
214
215
|
"lint": "biome check src/",
|
|
Binary file
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Regenerate `src/native/generated.ts` from the Rust.
|
|
4
|
+
*
|
|
5
|
+
* Node rather than a shell script because this runs inside `build:napi`, and
|
|
6
|
+
* that runs on the Windows prebuild runner too: a bash `mktemp` there hands
|
|
7
|
+
* cargo a `/tmp/...` path the native proc-macro cannot write to, so the
|
|
8
|
+
* type-def file comes back empty and the build fails for no visible reason.
|
|
9
|
+
*
|
|
10
|
+
* One crate at a time on purpose: napi-derive APPENDS to `TYPE_DEF_TMP_PATH`
|
|
11
|
+
* while cargo compiles, and a parallel build interleaves the writes —
|
|
12
|
+
* definitions go missing, silently, and the generated file comes out short.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { execFileSync } from 'node:child_process'
|
|
16
|
+
import { createRequire } from 'node:module'
|
|
17
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
18
|
+
import { tmpdir } from 'node:os'
|
|
19
|
+
import { dirname, join } from 'node:path'
|
|
20
|
+
import { fileURLToPath } from 'node:url'
|
|
21
|
+
|
|
22
|
+
const CRATES = ['ream-events-napi', 'ream-http-napi', 'ream-scheduler-napi']
|
|
23
|
+
|
|
24
|
+
const packageRoot = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
25
|
+
const output = join('src', 'native', 'generated.ts')
|
|
26
|
+
const scratch = mkdtempSync(join(tmpdir(), 'napi-types-'))
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const lines = []
|
|
30
|
+
for (const crate of CRATES) {
|
|
31
|
+
const perCrate = join(scratch, `${crate}.jsonl`)
|
|
32
|
+
writeFileSync(perCrate, '')
|
|
33
|
+
execFileSync('cargo', ['build', '-p', crate], {
|
|
34
|
+
cwd: packageRoot,
|
|
35
|
+
env: { ...process.env, TYPE_DEF_TMP_PATH: perCrate },
|
|
36
|
+
stdio: ['ignore', 'ignore', 'inherit'],
|
|
37
|
+
})
|
|
38
|
+
const emitted = readFileSync(perCrate, 'utf8').split('\n').filter(Boolean)
|
|
39
|
+
if (emitted.length === 0) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`[napi-types] ${crate} emitted nothing — is napi-derive's "type-def" feature on?`,
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
lines.push(...emitted)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const combined = join(scratch, 'combined.jsonl')
|
|
48
|
+
writeFileSync(combined, `${lines.join('\n')}\n`)
|
|
49
|
+
|
|
50
|
+
execFileSync(
|
|
51
|
+
process.execPath,
|
|
52
|
+
[join('scripts', 'generate-napi-types.mjs'), combined, output],
|
|
53
|
+
{ cwd: packageRoot, stdio: 'inherit' },
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
// Formatted here rather than excluded from the linter: the file is checked
|
|
57
|
+
// in, so it should read like the rest of the tree — and formatting it at
|
|
58
|
+
// generation means it never shows up as a diff someone has to fix by hand.
|
|
59
|
+
// Resolved through the package entry rather than `node_modules/.bin`, whose
|
|
60
|
+
// shim is a shell script the Windows runner cannot execute directly.
|
|
61
|
+
const biome = createRequire(import.meta.url).resolve('@biomejs/biome/bin/biome')
|
|
62
|
+
execFileSync(process.execPath, [biome, 'format', '--write', output], {
|
|
63
|
+
cwd: packageRoot,
|
|
64
|
+
stdio: ['ignore', 'ignore', 'inherit'],
|
|
65
|
+
})
|
|
66
|
+
} finally {
|
|
67
|
+
rmSync(scratch, { recursive: true, force: true })
|
|
68
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Generate the TypeScript surface of the native modules FROM the Rust.
|
|
4
|
+
*
|
|
5
|
+
* `napi-derive`'s `type-def` feature emits one JSON line per exported item
|
|
6
|
+
* while cargo compiles. Those lines are the source of truth: they are derived
|
|
7
|
+
* from the `#[napi]` items themselves, so a signature cannot drift from the
|
|
8
|
+
* Rust without this file changing.
|
|
9
|
+
*
|
|
10
|
+
* Hand-written interfaces are what we had before, and they DID drift — making
|
|
11
|
+
* `Bus::on_request` synchronous changed the Rust with nothing on the TypeScript
|
|
12
|
+
* side to notice.
|
|
13
|
+
*
|
|
14
|
+
* One thing napi-rs cannot infer: the shape of a `JsFunction` callback. It
|
|
15
|
+
* emits `(...args: any[]) => any`. Those few are refined below, by name, and
|
|
16
|
+
* the script fails if a refinement no longer matches anything — so the table
|
|
17
|
+
* cannot rot either.
|
|
18
|
+
*
|
|
19
|
+
* TYPE_DEF_TMP_PATH=<file> cargo build -p <crates…>
|
|
20
|
+
* node scripts/generate-napi-types.mjs <file> <out.d.ts>
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { readFileSync, writeFileSync } from 'node:fs'
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Callback signatures napi-rs erases to `any`, restored here.
|
|
27
|
+
*
|
|
28
|
+
* Keyed by `<owner>.<method>`; the value replaces the whole parameter. Every
|
|
29
|
+
* entry must match, or the script fails: a stale refinement is how a hand
|
|
30
|
+
* annotation quietly stops describing the Rust.
|
|
31
|
+
*/
|
|
32
|
+
const CALLBACK_REFINEMENTS = {
|
|
33
|
+
'EventBus.subscribe': {
|
|
34
|
+
from: 'callback: (...args: any[]) => any',
|
|
35
|
+
to: 'callback: (eventJson: string) => void',
|
|
36
|
+
},
|
|
37
|
+
'EventBus.onRequest': {
|
|
38
|
+
from: 'callback: (...args: any[]) => any',
|
|
39
|
+
to: 'callback: (eventJson: string, reply: (response: string) => void) => void',
|
|
40
|
+
},
|
|
41
|
+
'HyperServer.onRequest': {
|
|
42
|
+
from: 'callback: (...args: any[]) => any',
|
|
43
|
+
to: 'callback: (request: string) => Promise<string> | string',
|
|
44
|
+
},
|
|
45
|
+
'HyperServer.onStreamDisconnect': {
|
|
46
|
+
from: 'callback: (...args: any[]) => any',
|
|
47
|
+
to: 'callback: (streamId: string) => void',
|
|
48
|
+
},
|
|
49
|
+
// The Rust hands over a serialised JsTaskPayload — `{ task_name,
|
|
50
|
+
// scheduled_for_ms }` renamed to camelCase by serde.
|
|
51
|
+
'RustScheduler.register': {
|
|
52
|
+
from: 'callback: (...args: any[]) => any',
|
|
53
|
+
to: 'callback: (invocation: { taskName: string; scheduledForMs: number }) => void',
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const [input, output] = process.argv.slice(2)
|
|
58
|
+
if (!input || !output) {
|
|
59
|
+
console.error('usage: generate-napi-types.mjs <type-def file> <out.d.ts>')
|
|
60
|
+
process.exit(2)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const entries = readFileSync(input, 'utf8')
|
|
64
|
+
.split('\n')
|
|
65
|
+
.map((l) => l.trim())
|
|
66
|
+
.filter(Boolean)
|
|
67
|
+
.map((l) => JSON.parse(l))
|
|
68
|
+
|
|
69
|
+
const used = new Set()
|
|
70
|
+
|
|
71
|
+
/** Apply the refinements that belong to `owner`, tracking which ones matched. */
|
|
72
|
+
function refine(owner, body) {
|
|
73
|
+
let out = body
|
|
74
|
+
for (const [key, { from, to }] of Object.entries(CALLBACK_REFINEMENTS)) {
|
|
75
|
+
const [entryOwner] = key.split('.')
|
|
76
|
+
if (entryOwner !== owner) continue
|
|
77
|
+
if (out.includes(from)) {
|
|
78
|
+
out = out.replace(from, to)
|
|
79
|
+
used.add(key)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return out
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* JSDoc as emitted by napi-derive, indented to sit above its member.
|
|
87
|
+
*
|
|
88
|
+
* `*` followed by `/` inside the text closes the comment early — a Rust doc
|
|
89
|
+
* example holding a cron expression (`0 */5 * * *`) is enough to do it, and
|
|
90
|
+
* the generated file then fails to parse. Escaped rather than stripped, so the
|
|
91
|
+
* example still reads correctly.
|
|
92
|
+
*/
|
|
93
|
+
function docBlock(doc, indent = '') {
|
|
94
|
+
if (!doc) return ''
|
|
95
|
+
// Escape every `*/` EXCEPT the one that closes the block. A Rust doc example
|
|
96
|
+
// holding a cron expression (`0 */5 * * *`) closes the comment early
|
|
97
|
+
// otherwise, and the generated file stops parsing — but escaping the closer
|
|
98
|
+
// too breaks it just as thoroughly, whether the block spans one line or many.
|
|
99
|
+
const closer = doc.lastIndexOf('*/')
|
|
100
|
+
const escaped =
|
|
101
|
+
closer === -1
|
|
102
|
+
? doc
|
|
103
|
+
: doc.slice(0, closer).replaceAll('*/', '*\\/') + doc.slice(closer)
|
|
104
|
+
return (
|
|
105
|
+
escaped
|
|
106
|
+
.split('\n')
|
|
107
|
+
.filter((l) => l.length > 0)
|
|
108
|
+
.map((l) => `${indent}${l}`)
|
|
109
|
+
.join('\n') + '\n'
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const interfaces = entries.filter((e) => e.kind === 'interface')
|
|
114
|
+
const structs = entries.filter((e) => e.kind === 'struct')
|
|
115
|
+
const impls = new Map(entries.filter((e) => e.kind === 'impl').map((e) => [e.name, e]))
|
|
116
|
+
const fns = entries.filter((e) => e.kind === 'fn')
|
|
117
|
+
|
|
118
|
+
const out = [
|
|
119
|
+
'// GENERATED FROM THE RUST — do not edit.',
|
|
120
|
+
'//',
|
|
121
|
+
'// Produced by scripts/generate-napi-types.mjs from napi-derive\'s type-def',
|
|
122
|
+
'// output. Editing this file by hand puts it back where it started: a',
|
|
123
|
+
'// description that can disagree with the code it describes.',
|
|
124
|
+
'',
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
for (const iface of interfaces) {
|
|
128
|
+
out.push(docBlock(iface.js_doc))
|
|
129
|
+
out.push(`export interface ${iface.name} {`)
|
|
130
|
+
for (const line of iface.def.split('\n')) {
|
|
131
|
+
out.push(line ? ` ${line.trim()}` : '')
|
|
132
|
+
}
|
|
133
|
+
out.push('}', '')
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
for (const struct of structs) {
|
|
137
|
+
const impl = impls.get(struct.name)
|
|
138
|
+
out.push(docBlock(struct.js_doc))
|
|
139
|
+
out.push(`export declare class ${struct.name} {`)
|
|
140
|
+
if (impl) {
|
|
141
|
+
for (const line of refine(struct.name, impl.def).split('\n')) {
|
|
142
|
+
out.push(line ? ` ${line.trim()}` : '')
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
out.push('}', '')
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
for (const fn of fns) {
|
|
149
|
+
out.push(docBlock(fn.js_doc))
|
|
150
|
+
// napi-derive emits the whole declaration for a function, unlike a struct
|
|
151
|
+
// where `def` holds only the members.
|
|
152
|
+
const declaration = fn.def.trim()
|
|
153
|
+
out.push(
|
|
154
|
+
declaration.startsWith('export declare function')
|
|
155
|
+
? `${declaration};`
|
|
156
|
+
: `export declare function ${fn.name}${declaration};`,
|
|
157
|
+
'',
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const stale = Object.keys(CALLBACK_REFINEMENTS).filter((k) => !used.has(k))
|
|
162
|
+
if (stale.length > 0) {
|
|
163
|
+
console.error(
|
|
164
|
+
`[napi-types] refinement(s) that matched nothing: ${stale.join(', ')}\n` +
|
|
165
|
+
'[napi-types] the Rust changed under them — update or remove the entry.',
|
|
166
|
+
)
|
|
167
|
+
process.exit(1)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
writeFileSync(output, out.join('\n'))
|
|
171
|
+
console.log(`[napi-types] ${output} — ${interfaces.length} interface(s), ${structs.length} class(es), ${fns.length} function(s)`)
|