@c9up/ream 0.1.31 → 0.1.33
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/README.md +4 -1
- package/dist/Application.d.ts +27 -0
- package/dist/Application.d.ts.map +1 -1
- package/dist/Application.js +29 -0
- package/dist/Application.js.map +1 -1
- package/dist/ErrorBoundary.d.ts.map +1 -1
- package/dist/ErrorBoundary.js +13 -1
- package/dist/ErrorBoundary.js.map +1 -1
- package/dist/HttpKernel.d.ts +8 -0
- package/dist/HttpKernel.d.ts.map +1 -1
- package/dist/HttpKernel.js +35 -12
- package/dist/HttpKernel.js.map +1 -1
- package/dist/Ignitor.d.ts +8 -0
- package/dist/Ignitor.d.ts.map +1 -1
- package/dist/Ignitor.js +39 -0
- package/dist/Ignitor.js.map +1 -1
- package/dist/bodyparser/BodyParserMiddleware.d.ts +11 -4
- package/dist/bodyparser/BodyParserMiddleware.d.ts.map +1 -1
- package/dist/bodyparser/BodyParserMiddleware.js +55 -43
- package/dist/bodyparser/BodyParserMiddleware.js.map +1 -1
- package/dist/bodyparser/qsParse.d.ts +52 -0
- package/dist/bodyparser/qsParse.d.ts.map +1 -0
- package/dist/bodyparser/qsParse.js +161 -0
- package/dist/bodyparser/qsParse.js.map +1 -0
- package/dist/bootstrap/hyper-server.d.ts.map +1 -1
- package/dist/bootstrap/hyper-server.js +2 -8
- package/dist/bootstrap/hyper-server.js.map +1 -1
- package/dist/container/Container.d.ts +41 -0
- package/dist/container/Container.d.ts.map +1 -1
- package/dist/container/Container.js +193 -26
- package/dist/container/Container.js.map +1 -1
- package/dist/container/ContainerResolver.d.ts +46 -0
- package/dist/container/ContainerResolver.d.ts.map +1 -0
- package/dist/container/ContainerResolver.js +60 -0
- package/dist/container/ContainerResolver.js.map +1 -0
- package/dist/container/ContextualBindingsBuilder.d.ts +20 -0
- package/dist/container/ContextualBindingsBuilder.d.ts.map +1 -0
- package/dist/container/ContextualBindingsBuilder.js +31 -0
- package/dist/container/ContextualBindingsBuilder.js.map +1 -0
- package/dist/container/types.d.ts +9 -6
- package/dist/container/types.d.ts.map +1 -1
- package/dist/decorators/Service.d.ts +1 -5
- package/dist/decorators/Service.d.ts.map +1 -1
- package/dist/decorators/Service.js +10 -1
- package/dist/decorators/Service.js.map +1 -1
- package/dist/events/Emitter.d.ts +66 -6
- package/dist/events/Emitter.d.ts.map +1 -1
- package/dist/events/Emitter.js +165 -28
- package/dist/events/Emitter.js.map +1 -1
- package/dist/graphql/GraphQLEngine.d.ts.map +1 -1
- package/dist/graphql/GraphQLEngine.js +5 -5
- package/dist/graphql/GraphQLEngine.js.map +1 -1
- package/dist/helpers/duration.d.ts +32 -0
- package/dist/helpers/duration.d.ts.map +1 -0
- package/dist/helpers/duration.js +74 -0
- package/dist/helpers/duration.js.map +1 -0
- package/dist/helpers/napi-loader.d.ts +10 -1
- package/dist/helpers/napi-loader.d.ts.map +1 -1
- package/dist/helpers/napi-loader.js +18 -3
- package/dist/helpers/napi-loader.js.map +1 -1
- package/dist/helpers/types.d.ts +1 -1
- package/dist/helpers/types.d.ts.map +1 -1
- package/dist/http/Exception.d.ts.map +1 -1
- package/dist/http/Exception.js +17 -5
- package/dist/http/Exception.js.map +1 -1
- package/dist/http/HttpContext.d.ts +16 -5
- package/dist/http/HttpContext.d.ts.map +1 -1
- package/dist/http/HttpContext.js +4 -2
- package/dist/http/HttpContext.js.map +1 -1
- package/dist/http/RedirectBuilder.d.ts +48 -2
- package/dist/http/RedirectBuilder.d.ts.map +1 -1
- package/dist/http/RedirectBuilder.js +95 -14
- package/dist/http/RedirectBuilder.js.map +1 -1
- package/dist/http/Request.d.ts +128 -8
- package/dist/http/Request.d.ts.map +1 -1
- package/dist/http/Request.js +259 -8
- package/dist/http/Request.js.map +1 -1
- package/dist/http/Response.d.ts +74 -3
- package/dist/http/Response.d.ts.map +1 -1
- package/dist/http/Response.js +177 -4
- package/dist/http/Response.js.map +1 -1
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/router/Router.d.ts +36 -7
- package/dist/router/Router.d.ts.map +1 -1
- package/dist/router/Router.js +66 -22
- package/dist/router/Router.js.map +1 -1
- package/dist/security/CookieSigner.d.ts +35 -4
- package/dist/security/CookieSigner.d.ts.map +1 -1
- package/dist/security/CookieSigner.js +99 -10
- package/dist/security/CookieSigner.js.map +1 -1
- package/dist/server/Server.d.ts +2 -3
- package/dist/server/Server.d.ts.map +1 -1
- package/dist/server/Server.js +30 -13
- package/dist/server/Server.js.map +1 -1
- package/dist/session/ReadOnlyValuesStore.d.ts +24 -0
- package/dist/session/ReadOnlyValuesStore.d.ts.map +1 -0
- package/dist/session/ReadOnlyValuesStore.js +45 -0
- package/dist/session/ReadOnlyValuesStore.js.map +1 -0
- package/dist/session/Session.d.ts +181 -9
- package/dist/session/Session.d.ts.map +1 -1
- package/dist/session/Session.js +284 -33
- package/dist/session/Session.js.map +1 -1
- package/dist/session/SessionMiddleware.d.ts.map +1 -1
- package/dist/session/SessionMiddleware.js +87 -33
- package/dist/session/SessionMiddleware.js.map +1 -1
- package/dist/session/drivers/DatabaseDriver.d.ts +66 -0
- package/dist/session/drivers/DatabaseDriver.d.ts.map +1 -0
- package/dist/session/drivers/DatabaseDriver.js +132 -0
- package/dist/session/drivers/DatabaseDriver.js.map +1 -0
- package/dist/session/drivers/FileDriver.d.ts +22 -0
- package/dist/session/drivers/FileDriver.d.ts.map +1 -0
- package/dist/session/drivers/FileDriver.js +66 -0
- package/dist/session/drivers/FileDriver.js.map +1 -0
- package/dist/session/drivers/MemoryDriver.d.ts +10 -2
- package/dist/session/drivers/MemoryDriver.d.ts.map +1 -1
- package/dist/session/drivers/MemoryDriver.js +70 -0
- package/dist/session/drivers/MemoryDriver.js.map +1 -1
- package/dist/session/drivers/RedisDriver.d.ts +10 -2
- package/dist/session/drivers/RedisDriver.d.ts.map +1 -1
- package/dist/session/drivers/RedisDriver.js +58 -0
- package/dist/session/drivers/RedisDriver.js.map +1 -1
- package/dist/session/templateTags.d.ts +42 -0
- package/dist/session/templateTags.d.ts.map +1 -0
- package/dist/session/templateTags.js +101 -0
- package/dist/session/templateTags.js.map +1 -0
- package/dist/testing/RequestBuilder.d.ts +38 -1
- package/dist/testing/RequestBuilder.d.ts.map +1 -1
- package/dist/testing/RequestBuilder.js +40 -1
- package/dist/testing/RequestBuilder.js.map +1 -1
- package/dist/testing/TestClient.d.ts +3 -1
- package/dist/testing/TestClient.d.ts.map +1 -1
- package/dist/testing/TestClient.js +3 -1
- package/dist/testing/TestClient.js.map +1 -1
- package/dist/types/helpers.d.ts +1 -1
- package/dist/types/helpers.d.ts.map +1 -1
- package/dist/utils/Macroable.d.ts +14 -5
- package/dist/utils/Macroable.d.ts.map +1 -1
- package/dist/utils/Macroable.js +20 -18
- package/dist/utils/Macroable.js.map +1 -1
- package/events.win32-x64-msvc.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
- package/scheduler.win32-x64-msvc.node +0 -0
- package/src/Application.ts +39 -0
- package/src/ErrorBoundary.ts +13 -1
- package/src/HttpKernel.ts +45 -19
- package/src/Ignitor.ts +39 -0
- package/src/bodyparser/BodyParserMiddleware.ts +66 -44
- package/src/bodyparser/qsParse.ts +179 -0
- package/src/bootstrap/hyper-server.ts +2 -9
- package/src/container/Container.ts +265 -25
- package/src/container/ContainerResolver.ts +84 -0
- package/src/container/ContextualBindingsBuilder.ts +41 -0
- package/src/container/types.ts +11 -7
- package/src/decorators/Service.ts +16 -3
- package/src/events/Emitter.ts +200 -25
- package/src/graphql/GraphQLEngine.ts +7 -8
- package/src/helpers/duration.ts +71 -0
- package/src/helpers/napi-loader.ts +19 -3
- package/src/helpers/types.ts +4 -1
- package/src/http/Exception.ts +17 -5
- package/src/http/HttpContext.ts +20 -5
- package/src/http/RedirectBuilder.ts +126 -11
- package/src/http/Request.ts +283 -13
- package/src/http/Response.ts +213 -6
- package/src/index.ts +17 -3
- package/src/router/Router.ts +98 -33
- package/src/security/CookieSigner.ts +102 -10
- package/src/server/Server.ts +36 -16
- package/src/session/ReadOnlyValuesStore.ts +52 -0
- package/src/session/Session.ts +364 -37
- package/src/session/SessionMiddleware.ts +93 -30
- package/src/session/drivers/DatabaseDriver.ts +184 -0
- package/src/session/drivers/FileDriver.ts +82 -0
- package/src/session/drivers/MemoryDriver.ts +75 -2
- package/src/session/drivers/RedisDriver.ts +77 -2
- package/src/session/templateTags.ts +124 -0
- package/src/testing/RequestBuilder.ts +76 -0
- package/src/testing/TestClient.ts +10 -2
- package/src/types/helpers.ts +4 -1
- package/src/utils/Macroable.ts +23 -8
- package/dist/utils/inflect.d.ts +0 -17
- package/dist/utils/inflect.d.ts.map +0 -1
- package/dist/utils/inflect.js +0 -32
- package/dist/utils/inflect.js.map +0 -1
- package/src/utils/inflect.ts +0 -29
|
@@ -46,6 +46,35 @@ export interface AuthSubject {
|
|
|
46
46
|
extraHeaders?: Record<string, string>
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* What a guard answers when asked to authenticate a test client
|
|
51
|
+
* (AdonisJS `AuthClientResponse`).
|
|
52
|
+
*/
|
|
53
|
+
export interface ClientAuthResponse {
|
|
54
|
+
headers?: Record<string, string>
|
|
55
|
+
session?: Record<string, unknown>
|
|
56
|
+
cookies?: Record<string, string>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The little `loginAs()` needs of a guard.
|
|
61
|
+
*
|
|
62
|
+
* Structurally typed: the test client must not import warden, and an app with
|
|
63
|
+
* its own guard satisfies this by exposing the same method.
|
|
64
|
+
*/
|
|
65
|
+
export interface ClientAuthenticatable {
|
|
66
|
+
authenticateAsClient(...args: never[]): ClientAuthResponse | Promise<ClientAuthResponse>
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Persists session values for a test request and returns the cookie that
|
|
71
|
+
* addresses them. Given the session driver, it writes an entry and hands back
|
|
72
|
+
* `{ <cookieName>: <sessionId> }`.
|
|
73
|
+
*/
|
|
74
|
+
export type SessionSeeder = (
|
|
75
|
+
values: Record<string, unknown>,
|
|
76
|
+
) => Record<string, string> | Promise<Record<string, string>>
|
|
77
|
+
|
|
49
78
|
export interface AuthStrategy {
|
|
50
79
|
/** Compute the headers Warden expects for this user (Bearer token / session cookie / ...). */
|
|
51
80
|
headersFor(subject: AuthSubject): Record<string, string> | Promise<Record<string, string>>
|
|
@@ -156,7 +185,12 @@ export class RequestBuilder {
|
|
|
156
185
|
#cookies: Record<string, string> = {}
|
|
157
186
|
#query = new URLSearchParams()
|
|
158
187
|
#authStrategy: AuthStrategy | null
|
|
188
|
+
#sessionSeeder: SessionSeeder | null
|
|
159
189
|
#pendingAuth: AuthSubject | null = null
|
|
190
|
+
#pendingClientAuth: {
|
|
191
|
+
guard: ClientAuthenticatable
|
|
192
|
+
args: never[]
|
|
193
|
+
} | null = null
|
|
160
194
|
#timeoutMs: number | undefined
|
|
161
195
|
#maxRedirects = DEFAULT_MAX_REDIRECTS
|
|
162
196
|
#sent: Promise<ApiResponse> | null = null
|
|
@@ -170,11 +204,13 @@ export class RequestBuilder {
|
|
|
170
204
|
method: HttpMethod,
|
|
171
205
|
path: string,
|
|
172
206
|
authStrategy: AuthStrategy | null = null,
|
|
207
|
+
sessionSeeder: SessionSeeder | null = null,
|
|
173
208
|
) {
|
|
174
209
|
this.#sender = sender
|
|
175
210
|
this.#method = method
|
|
176
211
|
this.#path = path
|
|
177
212
|
this.#authStrategy = authStrategy
|
|
213
|
+
this.#sessionSeeder = sessionSeeder
|
|
178
214
|
applyRequestExtensions(this)
|
|
179
215
|
}
|
|
180
216
|
|
|
@@ -421,6 +457,23 @@ export class RequestBuilder {
|
|
|
421
457
|
return this
|
|
422
458
|
}
|
|
423
459
|
|
|
460
|
+
/**
|
|
461
|
+
* Send this request as an authenticated user (AdonisJS `loginAs`).
|
|
462
|
+
*
|
|
463
|
+
* await client.get('/dashboard').loginAs(sessionGuard, user)
|
|
464
|
+
* await client.get('/api/me').loginAs(jwtGuard, user)
|
|
465
|
+
* await client.get('/admin').loginAs(basicGuard, 'ada', 'secret')
|
|
466
|
+
*
|
|
467
|
+
* The GUARD answers what to send — a header, a session entry, a cookie — so
|
|
468
|
+
* the test never reproduces how that guard authenticates. A test that forges
|
|
469
|
+
* its own header proves only that the forgery works; this one travels the
|
|
470
|
+
* same verification path as production.
|
|
471
|
+
*/
|
|
472
|
+
loginAs(guard: ClientAuthenticatable, ...args: never[]): this {
|
|
473
|
+
this.#pendingClientAuth = { guard, args }
|
|
474
|
+
return this
|
|
475
|
+
}
|
|
476
|
+
|
|
424
477
|
/** Fire the request (once) and return the rich response. Idempotent. */
|
|
425
478
|
send(): Promise<ApiResponse> {
|
|
426
479
|
if (this.#sent === null) this.#sent = this.#execute()
|
|
@@ -560,6 +613,29 @@ export class RequestBuilder {
|
|
|
560
613
|
}
|
|
561
614
|
}
|
|
562
615
|
|
|
616
|
+
if (this.#pendingClientAuth !== null) {
|
|
617
|
+
const { guard, args } = this.#pendingClientAuth
|
|
618
|
+
const answer = await guard.authenticateAsClient(...args)
|
|
619
|
+
for (const [k, v] of Object.entries(answer.headers ?? {})) {
|
|
620
|
+
this.#headers[k.toLowerCase()] = v
|
|
621
|
+
}
|
|
622
|
+
Object.assign(this.#cookies, answer.cookies ?? {})
|
|
623
|
+
// A session guard answers with session VALUES, which only something
|
|
624
|
+
// holding the session driver can persist. Without a seeder the request
|
|
625
|
+
// would go out unauthenticated and the test would fail somewhere far from
|
|
626
|
+
// the cause — so say it here instead.
|
|
627
|
+
if (answer.session && Object.keys(answer.session).length > 0) {
|
|
628
|
+
if (!this.#sessionSeeder) {
|
|
629
|
+
throw new Error(
|
|
630
|
+
'RequestBuilder: `loginAs()` was given a session-based guard, which needs a session to be written before the request. ' +
|
|
631
|
+
'Pass `sessionSeeder` in the client options (it receives the values and returns the session cookie).',
|
|
632
|
+
)
|
|
633
|
+
}
|
|
634
|
+
const cookie = await this.#sessionSeeder(answer.session)
|
|
635
|
+
Object.assign(this.#cookies, cookie)
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
563
639
|
// Multipart parts (.field()/.file()) take precedence over any body set by
|
|
564
640
|
// json()/form()/body(); encode them with a fresh boundary at send time.
|
|
565
641
|
if (this.#multipart.length > 0) {
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
type HttpMethod,
|
|
24
24
|
type HttpSender,
|
|
25
25
|
RequestBuilder,
|
|
26
|
+
type SessionSeeder,
|
|
26
27
|
type TestResponse,
|
|
27
28
|
} from './RequestBuilder.js'
|
|
28
29
|
|
|
@@ -47,15 +48,22 @@ export class TestClient {
|
|
|
47
48
|
#headers: Dict = {}
|
|
48
49
|
#bootFn: (port: number) => Promise<{ port: number; close: () => Promise<void> | void }>
|
|
49
50
|
#auth: AuthStrategy | null
|
|
51
|
+
#sessionSeeder: SessionSeeder | null
|
|
50
52
|
#routes: RouteManifest | null
|
|
51
53
|
|
|
52
54
|
constructor(
|
|
53
55
|
bootFn: (port: number) => Promise<{ port: number; close: () => Promise<void> | void }>,
|
|
54
|
-
options: {
|
|
56
|
+
options: {
|
|
57
|
+
auth?: AuthStrategy
|
|
58
|
+
routes?: RouteManifest
|
|
59
|
+
/** Writes session values for `loginAs()` with a session-based guard. */
|
|
60
|
+
sessionSeeder?: SessionSeeder
|
|
61
|
+
} = {},
|
|
55
62
|
) {
|
|
56
63
|
this.#bootFn = bootFn
|
|
57
64
|
this.#auth = options.auth ?? null
|
|
58
65
|
this.#routes = options.routes ?? null
|
|
66
|
+
this.#sessionSeeder = options.sessionSeeder ?? null
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
#server: { port: number; close: () => Promise<void> | void } | null = null
|
|
@@ -149,7 +157,7 @@ export class TestClient {
|
|
|
149
157
|
init.body.toString('utf8'),
|
|
150
158
|
init.timeoutMs,
|
|
151
159
|
)
|
|
152
|
-
return new RequestBuilder(sender, method, path, this.#auth)
|
|
160
|
+
return new RequestBuilder(sender, method, path, this.#auth, this.#sessionSeeder)
|
|
153
161
|
}
|
|
154
162
|
|
|
155
163
|
/**
|
package/src/types/helpers.ts
CHANGED
|
@@ -28,7 +28,10 @@ export type UnwrapOpaque<T> = T extends Opaque<infer Base, string> ? Base : T
|
|
|
28
28
|
export type AsyncOrSync<T> = T | Promise<T>
|
|
29
29
|
|
|
30
30
|
/** Constructor type. */
|
|
31
|
-
|
|
31
|
+
// The default `Args` is `never[]`, not `unknown[]`: parameters are
|
|
32
|
+
// contravariant, so only a rest of `never` accepts EVERY concrete parameter
|
|
33
|
+
// list. Pass `Args` explicitly when you need to call the constructor.
|
|
34
|
+
export type Constructor<T = unknown, Args extends unknown[] = never[]> = new (...args: Args) => T
|
|
32
35
|
|
|
33
36
|
/** Abstract constructor type. */
|
|
34
37
|
export type AbstractConstructor<T = unknown> = abstract new (...args: unknown[]) => T
|
package/src/utils/Macroable.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
// biome-ignore-all lint/complexity/noThisInStatic: `this` inside a static method
|
|
2
|
+
// IS the calling class, and that is the whole mechanism here — `this.prototype`
|
|
3
|
+
// is what scopes a macro to the subclass that declared it. Using
|
|
4
|
+
// `Macroable.prototype` put every macro on all eight subclasses at once.
|
|
5
|
+
// Removing the `this` reintroduces that bug.
|
|
6
|
+
|
|
1
7
|
/**
|
|
2
8
|
* Macroable — lets a package extend a class at runtime with extra methods
|
|
3
9
|
* (`macro`) and computed properties (`getter`), AdonisJS-style. A framework
|
|
@@ -22,9 +28,17 @@ export type MacroFn = (...args: unknown[]) => unknown
|
|
|
22
28
|
export type GetterFn = () => unknown
|
|
23
29
|
|
|
24
30
|
export class Macroable {
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Attach a method to every instance of THIS class (AdonisJS `macro`).
|
|
33
|
+
*
|
|
34
|
+
* `this.prototype`, not `Macroable.prototype`: eight classes extend this one,
|
|
35
|
+
* and defining on the base put every macro on all of them — a
|
|
36
|
+
* `Response.macro('json', …)` also landed on `Request`, `Router` and
|
|
37
|
+
* `HttpContext`, and two subclasses declaring the same name clobbered each
|
|
38
|
+
* other silently.
|
|
39
|
+
*/
|
|
40
|
+
static macro(this: typeof Macroable, name: string, fn: MacroFn): void {
|
|
41
|
+
Object.defineProperty(this.prototype, name, {
|
|
28
42
|
value: fn,
|
|
29
43
|
writable: true,
|
|
30
44
|
configurable: true,
|
|
@@ -32,16 +46,17 @@ export class Macroable {
|
|
|
32
46
|
}
|
|
33
47
|
|
|
34
48
|
/**
|
|
35
|
-
* Attach a computed property to every instance (AdonisJS
|
|
36
|
-
* `singleton`, the value is computed once per instance and
|
|
49
|
+
* Attach a computed property to every instance of THIS class (AdonisJS
|
|
50
|
+
* `getter`). With `singleton`, the value is computed once per instance and
|
|
51
|
+
* cached.
|
|
37
52
|
*/
|
|
38
|
-
static getter(name: string, fn: GetterFn, singleton = false): void {
|
|
53
|
+
static getter(this: typeof Macroable, name: string, fn: GetterFn, singleton = false): void {
|
|
39
54
|
if (!singleton) {
|
|
40
|
-
Object.defineProperty(
|
|
55
|
+
Object.defineProperty(this.prototype, name, { get: fn, configurable: true })
|
|
41
56
|
return
|
|
42
57
|
}
|
|
43
58
|
const cacheKey = Symbol(name)
|
|
44
|
-
Object.defineProperty(
|
|
59
|
+
Object.defineProperty(this.prototype, name, {
|
|
45
60
|
configurable: true,
|
|
46
61
|
get(this: Record<symbol, unknown>) {
|
|
47
62
|
if (!(cacheKey in this)) {
|
package/dist/utils/inflect.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimal zero-dependency string inflection — the two operations resourceful
|
|
3
|
-
* routing needs from AdonisJS's `@poppinss/utils/string`: `snakeCase` (route
|
|
4
|
-
* name normalisation) and `singular` (nested-resource param naming, `photos`
|
|
5
|
-
* → `photo_id`).
|
|
6
|
-
*
|
|
7
|
-
* Deviation from AdonisJS (named): `singular` covers regular English plurals
|
|
8
|
-
* only (`-ies→-y`, `-(s|x|z|ch|sh)es→drop es`, trailing `-s→drop`). Irregular
|
|
9
|
-
* plurals (`people→person`, `geese→goose`) are NOT handled — resource names in
|
|
10
|
-
* REST APIs are overwhelmingly regular, and a full inflector (irregular tables,
|
|
11
|
-
* uncountables) would be a dependency-sized rabbit hole for a niche case.
|
|
12
|
-
*/
|
|
13
|
-
/** Convert `camelCase`/`PascalCase`/`kebab-case`/spaced text to `snake_case`. */
|
|
14
|
-
export declare function snakeCase(value: string): string;
|
|
15
|
-
/** Singularize a regular English plural (see module deviation note). */
|
|
16
|
-
export declare function singular(word: string): string;
|
|
17
|
-
//# sourceMappingURL=inflect.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"inflect.d.ts","sourceRoot":"","sources":["../../src/utils/inflect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,iFAAiF;AACjF,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED,wEAAwE;AACxE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM7C"}
|
package/dist/utils/inflect.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimal zero-dependency string inflection — the two operations resourceful
|
|
3
|
-
* routing needs from AdonisJS's `@poppinss/utils/string`: `snakeCase` (route
|
|
4
|
-
* name normalisation) and `singular` (nested-resource param naming, `photos`
|
|
5
|
-
* → `photo_id`).
|
|
6
|
-
*
|
|
7
|
-
* Deviation from AdonisJS (named): `singular` covers regular English plurals
|
|
8
|
-
* only (`-ies→-y`, `-(s|x|z|ch|sh)es→drop es`, trailing `-s→drop`). Irregular
|
|
9
|
-
* plurals (`people→person`, `geese→goose`) are NOT handled — resource names in
|
|
10
|
-
* REST APIs are overwhelmingly regular, and a full inflector (irregular tables,
|
|
11
|
-
* uncountables) would be a dependency-sized rabbit hole for a niche case.
|
|
12
|
-
*/
|
|
13
|
-
/** Convert `camelCase`/`PascalCase`/`kebab-case`/spaced text to `snake_case`. */
|
|
14
|
-
export function snakeCase(value) {
|
|
15
|
-
return value
|
|
16
|
-
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
17
|
-
.replace(/[-\s]+/g, '_')
|
|
18
|
-
.toLowerCase();
|
|
19
|
-
}
|
|
20
|
-
/** Singularize a regular English plural (see module deviation note). */
|
|
21
|
-
export function singular(word) {
|
|
22
|
-
if (word.length > 3 && /ies$/i.test(word))
|
|
23
|
-
return word.replace(/ies$/i, 'y');
|
|
24
|
-
if (/(?:s|x|z|ch|sh)es$/i.test(word))
|
|
25
|
-
return word.replace(/es$/i, '');
|
|
26
|
-
if (/ss$/i.test(word))
|
|
27
|
-
return word;
|
|
28
|
-
if (/s$/i.test(word))
|
|
29
|
-
return word.replace(/s$/i, '');
|
|
30
|
-
return word;
|
|
31
|
-
}
|
|
32
|
-
//# sourceMappingURL=inflect.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"inflect.js","sourceRoot":"","sources":["../../src/utils/inflect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,iFAAiF;AACjF,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,KAAK;SACT,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,WAAW,EAAE,CAAA;AAClB,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;IAC5E,IAAI,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IACrE,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAClC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IACpD,OAAO,IAAI,CAAA;AACb,CAAC"}
|
package/src/utils/inflect.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimal zero-dependency string inflection — the two operations resourceful
|
|
3
|
-
* routing needs from AdonisJS's `@poppinss/utils/string`: `snakeCase` (route
|
|
4
|
-
* name normalisation) and `singular` (nested-resource param naming, `photos`
|
|
5
|
-
* → `photo_id`).
|
|
6
|
-
*
|
|
7
|
-
* Deviation from AdonisJS (named): `singular` covers regular English plurals
|
|
8
|
-
* only (`-ies→-y`, `-(s|x|z|ch|sh)es→drop es`, trailing `-s→drop`). Irregular
|
|
9
|
-
* plurals (`people→person`, `geese→goose`) are NOT handled — resource names in
|
|
10
|
-
* REST APIs are overwhelmingly regular, and a full inflector (irregular tables,
|
|
11
|
-
* uncountables) would be a dependency-sized rabbit hole for a niche case.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/** Convert `camelCase`/`PascalCase`/`kebab-case`/spaced text to `snake_case`. */
|
|
15
|
-
export function snakeCase(value: string): string {
|
|
16
|
-
return value
|
|
17
|
-
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
18
|
-
.replace(/[-\s]+/g, '_')
|
|
19
|
-
.toLowerCase()
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** Singularize a regular English plural (see module deviation note). */
|
|
23
|
-
export function singular(word: string): string {
|
|
24
|
-
if (word.length > 3 && /ies$/i.test(word)) return word.replace(/ies$/i, 'y')
|
|
25
|
-
if (/(?:s|x|z|ch|sh)es$/i.test(word)) return word.replace(/es$/i, '')
|
|
26
|
-
if (/ss$/i.test(word)) return word
|
|
27
|
-
if (/s$/i.test(word)) return word.replace(/s$/i, '')
|
|
28
|
-
return word
|
|
29
|
-
}
|