gruber 0.3.0 → 0.4.0

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.
@@ -26,10 +26,40 @@ describe("Configuration", () => {
26
26
  describe("object", () => {
27
27
  const config = new Configuration(bareOptions);
28
28
 
29
- it("stores the spec", () => {
30
- const result = config.object({});
29
+ it("stores the options", () => {
30
+ const result = config.object({ key: "value" });
31
+
31
32
  assertEquals(result[Configuration.spec].type, "object");
32
- assertEquals(result[Configuration.spec].value, {});
33
+ assertEquals(result[Configuration.spec].options, { key: "value" });
34
+ });
35
+ it("describes itself", () => {
36
+ const spec = config.object({
37
+ fullName: config.string({ variable: "FULL_NAME", fallback: "Geoff T" }),
38
+ age: config.number({ flag: "--age", fallback: 42 }),
39
+ });
40
+ //
41
+ const result = spec[Configuration.spec].describe(
42
+ "person",
43
+ (options, name) => ({ name, ...options }),
44
+ );
45
+
46
+ assertEquals(result, {
47
+ fallback: { fullName: "Geoff T", age: 42 },
48
+ fields: [
49
+ {
50
+ name: "person.fullName",
51
+ type: "string",
52
+ variable: "FULL_NAME",
53
+ fallback: "Geoff T",
54
+ },
55
+ {
56
+ name: "person.age",
57
+ type: "number",
58
+ flag: "--age",
59
+ fallback: 42,
60
+ },
61
+ ],
62
+ });
33
63
  });
34
64
  });
35
65
 
@@ -44,16 +74,118 @@ describe("Configuration", () => {
44
74
  const result = struct.process(undefined);
45
75
  assertEquals(result, "Geoff Testington");
46
76
  });
47
- it("stores the spec", () => {
77
+ it("stores the options", () => {
48
78
  const result = config.string({
49
79
  variable: "SOME_VAR",
80
+ flag: "--some-flag",
50
81
  fallback: "value",
51
82
  });
52
83
  assertEquals(result[Configuration.spec].type, "string");
53
- assertEquals(result[Configuration.spec].value, {
84
+ assertEquals(result[Configuration.spec].options, {
85
+ variable: "SOME_VAR",
86
+ flag: "--some-flag",
87
+ fallback: "value",
88
+ });
89
+ });
90
+ it("describes itself", () => {
91
+ const spec = config.string({
54
92
  variable: "SOME_VAR",
93
+ flag: "--some-flag",
55
94
  fallback: "value",
56
95
  });
96
+ const result = spec[Configuration.spec].describe("fullName");
97
+ assertEquals(result, {
98
+ fallback: "value",
99
+ fields: [
100
+ {
101
+ name: "fullName",
102
+ type: "string",
103
+ variable: "SOME_VAR",
104
+ flag: "--some-flag",
105
+ fallback: "value",
106
+ },
107
+ ],
108
+ });
109
+ });
110
+ });
111
+
112
+ describe("number", () => {
113
+ const config = new Configuration(bareOptions);
114
+
115
+ it("requires a fallback", () => {
116
+ assertThrows(() => config.number({}), TypeError);
117
+ });
118
+ it("uses the fallback", () => {
119
+ const struct = config.number({ fallback: 42 });
120
+ const result = struct.process(undefined);
121
+ assertEquals(result, 42);
122
+ });
123
+ it("stores the options", () => {
124
+ const result = config.number({
125
+ variable: "SOME_VAR",
126
+ flag: "--some-flag",
127
+ fallback: 42,
128
+ });
129
+ assertEquals(result[Configuration.spec].type, "number");
130
+ assertEquals(result[Configuration.spec].options, {
131
+ variable: "SOME_VAR",
132
+ flag: "--some-flag",
133
+ fallback: 42,
134
+ });
135
+ });
136
+ it("parses strings", () => {
137
+ const vars = { SOME_VAR: "12.34" };
138
+ const config = new Configuration({
139
+ ...bareOptions,
140
+ getEnvironmentVariable: (key) => vars[key],
141
+ });
142
+
143
+ const result = config.number({
144
+ variable: "SOME_VAR",
145
+ fallback: 42,
146
+ });
147
+
148
+ assertEquals(result.process(undefined), 12.34);
149
+ });
150
+ });
151
+
152
+ describe("boolean", () => {
153
+ const config = new Configuration(bareOptions);
154
+
155
+ it("requires a fallback", () => {
156
+ assertThrows(() => config.boolean({}), TypeError);
157
+ });
158
+ it("uses the fallback", () => {
159
+ const struct = config.boolean({ fallback: false });
160
+ const result = struct.process(undefined);
161
+ assertEquals(result, false);
162
+ });
163
+ it("stores the options", () => {
164
+ const result = config.boolean({
165
+ variable: "SOME_VAR",
166
+ flag: "--some-flag",
167
+ fallback: false,
168
+ });
169
+ assertEquals(result[Configuration.spec].type, "boolean");
170
+ assertEquals(result[Configuration.spec].options, {
171
+ variable: "SOME_VAR",
172
+ flag: "--some-flag",
173
+ fallback: false,
174
+ });
175
+ });
176
+ it("parses strings", () => {
177
+ const vars = { SOME_VAR: "true" };
178
+ const config = new Configuration({
179
+ ...bareOptions,
180
+ getEnvironmentVariable: (key) => vars[key],
181
+ });
182
+
183
+ const result = config.boolean({
184
+ variable: "SOME_VAR",
185
+ fallback: false,
186
+ });
187
+
188
+ assertEquals(result.process(undefined), true);
57
189
  });
58
190
  });
59
191
 
@@ -73,15 +205,17 @@ describe("Configuration", () => {
73
205
  const result = struct.process(undefined);
74
206
  assertEquals(result, new URL("https://fallback.example.com"));
75
207
  });
76
- it("stores the spec", () => {
208
+ it("stores the options", () => {
77
209
  const result = config.url({
78
210
  variable: "SOME_VAR",
211
+ flag: "--some-flag",
79
212
  fallback: "https://example.com",
80
213
  });
81
214
  assertEquals(result[Configuration.spec].type, "url");
82
- assertEquals(result[Configuration.spec].value, {
215
+ assertEquals(result[Configuration.spec].options, {
83
216
  variable: "SOME_VAR",
84
- fallback: "https://example.com",
217
+ flag: "--some-flag",
218
+ fallback: new URL("https://example.com"),
85
219
  });
86
220
  });
87
221
  });
@@ -96,7 +230,10 @@ describe("Configuration", () => {
96
230
  const result = config._getValue({
97
231
  flag: "--option",
98
232
  });
99
- assertEquals(result, "value-from-arg");
233
+ assertEquals(result, {
234
+ source: "argument",
235
+ value: "value-from-arg",
236
+ });
100
237
  });
101
238
  it("uses environment variables", () => {
102
239
  const env = { MY_VAR: "value-from-env" };
@@ -107,12 +244,74 @@ describe("Configuration", () => {
107
244
  const result = config._getValue({
108
245
  variable: "MY_VAR",
109
246
  });
110
- assertEquals(result, "value-from-env");
247
+ assertEquals(result, {
248
+ source: "variable",
249
+ value: "value-from-env",
250
+ });
111
251
  });
112
252
  it("uses the fallback", () => {
113
253
  const config = new Configuration(bareOptions);
114
254
  const result = config._getValue({ fallback: "value-from-fallback" });
115
- assertEquals(result, "value-from-fallback");
255
+ assertEquals(result, {
256
+ source: "fallback",
257
+ value: "value-from-fallback",
258
+ });
259
+ });
260
+ });
261
+
262
+ describe("_parseFloat", () => {
263
+ it("parses strings", () => {
264
+ const config = new Configuration(bareOptions);
265
+ assertEquals(
266
+ config._parseFloat({ source: "argument", value: "12.34" }),
267
+ 12.34,
268
+ "should parse the float from the result",
269
+ );
270
+ });
271
+ it("passes numbers through", () => {
272
+ const config = new Configuration(bareOptions);
273
+ assertEquals(
274
+ config._parseFloat({ source: "fallback", value: 98.76 }),
275
+ 98.76,
276
+ "should preserve number literals",
277
+ );
278
+ });
279
+ });
280
+
281
+ describe("_parseBoolean", () => {
282
+ it("parses strings", () => {
283
+ const config = new Configuration(bareOptions);
284
+ assertEquals(
285
+ config._parseBoolean({ source: "argument", value: "1" }),
286
+ true,
287
+ );
288
+ assertEquals(
289
+ config._parseBoolean({ source: "argument", value: "true" }),
290
+ true,
291
+ );
292
+ assertEquals(
293
+ config._parseBoolean({ source: "argument", value: "0" }),
294
+ false,
295
+ );
296
+ assertEquals(
297
+ config._parseBoolean({ source: "argument", value: "false" }),
298
+ false,
299
+ );
300
+ });
301
+ it("passes booleans through", () => {
302
+ const config = new Configuration(bareOptions);
303
+ assertEquals(
304
+ config._parseBoolean({ source: "fallback", value: true }),
305
+ true,
306
+ "should preserve boolean literals",
307
+ );
308
+ });
309
+ it("allows empty-string for arguments", () => {
310
+ const config = new Configuration(bareOptions);
311
+ assertEquals(
312
+ config._parseBoolean({ source: "argument", value: "" }),
313
+ true,
314
+ );
116
315
  });
117
316
  });
118
317
 
@@ -155,10 +354,10 @@ describe("Configuration", () => {
155
354
  });
156
355
  });
157
356
 
158
- describe("describeSpecification", () => {
357
+ describe("describe", () => {
159
358
  it("processes strings", () => {
160
359
  const config = new Configuration(bareOptions);
161
- const result = config.describeSpecification(
360
+ const result = config.describe(
162
361
  config.string({
163
362
  fallback: "test-app",
164
363
  variable: "APP_NAME",
@@ -180,7 +379,7 @@ describe("Configuration", () => {
180
379
 
181
380
  it("processes urls", () => {
182
381
  const config = new Configuration(bareOptions);
183
- const result = config.describeSpecification(
382
+ const result = config.describe(
184
383
  config.url({
185
384
  fallback: "https://example.com",
186
385
  variable: "SELF_URL",
@@ -193,7 +392,7 @@ describe("Configuration", () => {
193
392
  {
194
393
  name: "selfUrl",
195
394
  type: "url",
196
- fallback: "https://example.com",
395
+ fallback: new URL("https://example.com"),
197
396
  variable: "SELF_URL",
198
397
  flag: "--self-url",
199
398
  },
@@ -202,7 +401,7 @@ describe("Configuration", () => {
202
401
 
203
402
  it("processes objects", () => {
204
403
  const config = new Configuration(bareOptions);
205
- const result = config.describeSpecification(
404
+ const result = config.describe(
206
405
  config.object({
207
406
  name: config.string({
208
407
  fallback: "testing-app",
package/core/http.d.ts CHANGED
@@ -26,23 +26,42 @@
26
26
  */
27
27
  export function defineRoute<T extends string>(init: import("./types.ts").RouteOptions<T>): import("./types.ts").RouteDefinition<T>;
28
28
  export class HTTPError extends Error {
29
- /** https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400 */
30
- static badRequest(): HTTPError;
31
- /** https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401 */
32
- static unauthorized(): HTTPError;
33
- /** https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404 */
34
- static notFound(): HTTPError;
35
- /** https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500 */
36
- static internalServerError(): HTTPError;
37
- /** https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501 */
38
- static notImplemented(): HTTPError;
29
+ /**
30
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400
31
+ * @param {BodyInit} [body]
32
+ */
33
+ static badRequest(body?: BodyInit): HTTPError;
34
+ /**
35
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401
36
+ * @param {BodyInit} [body]
37
+ */
38
+ static unauthorized(body?: BodyInit): HTTPError;
39
+ /**
40
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404
41
+ * @param {BodyInit} [body]
42
+ */
43
+ static notFound(body?: BodyInit): HTTPError;
44
+ /**
45
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500
46
+ * @param {BodyInit} [body]
47
+ */
48
+ static internalServerError(body?: BodyInit): HTTPError;
49
+ /**
50
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501
51
+ * @param {BodyInit} [body]
52
+ */
53
+ static notImplemented(body?: BodyInit): HTTPError;
39
54
  /**
40
55
  * @param {number} status
41
56
  * @param {string} statusText
57
+ * @param {BodyInit|null|undefined} [body=null]
58
+ * @param {HeadersInit} [headers=undefined]
42
59
  */
43
- constructor(status?: number, statusText?: string);
60
+ constructor(status?: number, statusText?: string, body?: BodyInit | null | undefined, headers?: HeadersInit);
44
61
  /** @type {number} */ status: number;
45
62
  /** @type {string}*/ statusText: string;
63
+ body: BodyInit;
64
+ headers: Headers;
46
65
  toResponse(): Response;
47
66
  }
48
67
  export type HTTPMethod = import("./types.ts").HTTPMethod;
package/core/http.js CHANGED
@@ -41,29 +41,44 @@ export function defineRoute(init) {
41
41
  // NOTE: add more error codes as needed
42
42
  // NOTE: design an API for setting the body on static errors
43
43
  export class HTTPError extends Error {
44
- /** https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400 */
45
- static badRequest() {
46
- return new HTTPError(400, "Bad Request");
44
+ /**
45
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400
46
+ * @param {BodyInit} [body]
47
+ */
48
+ static badRequest(body = undefined) {
49
+ return new HTTPError(400, "Bad Request", body);
47
50
  }
48
51
 
49
- /** https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401 */
50
- static unauthorized() {
51
- return new HTTPError(401, "Unauthorized");
52
+ /**
53
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401
54
+ * @param {BodyInit} [body]
55
+ */
56
+ static unauthorized(body = undefined) {
57
+ return new HTTPError(401, "Unauthorized", body);
52
58
  }
53
59
 
54
- /** https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404 */
55
- static notFound() {
56
- return new HTTPError(404, "Not Found");
60
+ /**
61
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404
62
+ * @param {BodyInit} [body]
63
+ */
64
+ static notFound(body = undefined) {
65
+ return new HTTPError(404, "Not Found", body);
57
66
  }
58
67
 
59
- /** https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500 */
60
- static internalServerError() {
61
- return new HTTPError(500, "Internal Server Error");
68
+ /**
69
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500
70
+ * @param {BodyInit} [body]
71
+ */
72
+ static internalServerError(body = undefined) {
73
+ return new HTTPError(500, "Internal Server Error", body);
62
74
  }
63
75
 
64
- /** https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501 */
65
- static notImplemented() {
66
- return new HTTPError(501, "Not Implemented");
76
+ /**
77
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501
78
+ * @param {BodyInit} [body]
79
+ */
80
+ static notImplemented(body = undefined) {
81
+ return new HTTPError(501, "Not Implemented", body);
67
82
  }
68
83
 
69
84
  /** @type {number} */ status;
@@ -72,19 +87,29 @@ export class HTTPError extends Error {
72
87
  /**
73
88
  * @param {number} status
74
89
  * @param {string} statusText
90
+ * @param {BodyInit|null|undefined} [body=null]
91
+ * @param {HeadersInit} [headers=undefined]
75
92
  */
76
- constructor(status = 200, statusText = "OK") {
93
+ constructor(
94
+ status = 200,
95
+ statusText = "OK",
96
+ body = null,
97
+ headers = undefined,
98
+ ) {
77
99
  super(statusText);
78
100
  this.status = status;
79
101
  this.statusText = statusText;
102
+ this.body = body;
80
103
  this.name = "HTTPError";
104
+ this.headers = new Headers(headers);
81
105
  Error.captureStackTrace(this, HTTPError);
82
106
  }
83
107
 
84
108
  toResponse() {
85
- return new Response(null, {
109
+ return new Response(this.body, {
86
110
  status: this.status,
87
111
  statusText: this.statusText,
112
+ headers: this.headers,
88
113
  });
89
114
  }
90
115
  }
package/core/http.test.js CHANGED
@@ -1,8 +1,8 @@
1
- import { assertInstanceOf, assertEquals } from "./test-deps.js";
1
+ import { assertInstanceOf, assertEquals, describe, it } from "./test-deps.js";
2
2
  import { defineRoute, HTTPError } from "./http.js";
3
3
 
4
- Deno.test("defineRoute", async (t) => {
5
- await t.step("sets the method", () => {
4
+ describe("defineRoute", () => {
5
+ it("sets the method", () => {
6
6
  const result = defineRoute({
7
7
  method: "GET",
8
8
  pathname: "/",
@@ -11,7 +11,7 @@ Deno.test("defineRoute", async (t) => {
11
11
  assertEquals(result.method, "GET");
12
12
  });
13
13
 
14
- await t.step("creates a URLPattern", () => {
14
+ it("creates a URLPattern", () => {
15
15
  const result = defineRoute({
16
16
  method: "GET",
17
17
  pathname: "/hello/:name",
@@ -22,47 +22,69 @@ Deno.test("defineRoute", async (t) => {
22
22
  });
23
23
  });
24
24
 
25
- Deno.test("HTTPError", async (t) => {
26
- await t.step("constructor", () => {
27
- const result = new HTTPError(418, "I'm a teapot");
28
- assertEquals(result.status, 418);
29
- assertEquals(result.statusText, "I'm a teapot");
30
- assertEquals(result.name, "HTTPError");
25
+ describe("HTTPError", () => {
26
+ describe("constructor", () => {
27
+ it("creates the error", () => {
28
+ const result = new HTTPError(418, "I'm a teapot");
29
+ assertEquals(result.status, 418);
30
+ assertEquals(result.statusText, "I'm a teapot");
31
+ assertEquals(result.name, "HTTPError");
32
+ });
31
33
  });
32
34
 
33
- await t.step("toResponse", () => {
34
- const result = new HTTPError(200, "OK").toResponse();
35
- assertEquals(result.status, 200);
36
- assertEquals(result.statusText, "OK");
37
- });
35
+ describe("toResponse", () => {
36
+ it("creates the error", () => {
37
+ const result = new HTTPError(200, "OK").toResponse();
38
+ assertEquals(result.status, 200);
39
+ assertEquals(result.statusText, "OK");
40
+ });
41
+ it("sets headers", () => {
42
+ const error = new HTTPError(200, "OK", null, {
43
+ "X-HOTEL-BAR": "Hotel Bar?",
44
+ });
38
45
 
39
- await t.step("badRequest", () => {
40
- const result = HTTPError.badRequest("body");
41
- assertEquals(result.status, 400);
42
- assertEquals(result.statusText, "Bad Request");
46
+ const result = error.toResponse();
47
+ assertEquals(result.headers.get("X-HOTEL-BAR"), "Hotel Bar?");
48
+ });
43
49
  });
44
50
 
45
- await t.step("unauthorized", () => {
46
- const result = HTTPError.unauthorized();
47
- assertEquals(result.status, 401);
48
- assertEquals(result.statusText, "Unauthorized");
51
+ describe("badRequest", () => {
52
+ it("creates the error", () => {
53
+ const result = HTTPError.badRequest("body");
54
+ assertEquals(result.status, 400);
55
+ assertEquals(result.statusText, "Bad Request");
56
+ });
49
57
  });
50
58
 
51
- await t.step("notFound", () => {
52
- const result = HTTPError.notFound();
53
- assertEquals(result.status, 404);
54
- assertEquals(result.statusText, "Not Found");
59
+ describe("unauthorized", () => {
60
+ it("creates the error", () => {
61
+ const result = HTTPError.unauthorized();
62
+ assertEquals(result.status, 401);
63
+ assertEquals(result.statusText, "Unauthorized");
64
+ });
55
65
  });
56
66
 
57
- await t.step("internalServerError", () => {
58
- const result = HTTPError.internalServerError();
59
- assertEquals(result.status, 500);
60
- assertEquals(result.statusText, "Internal Server Error");
67
+ describe("notFound", () => {
68
+ it("creates the error", () => {
69
+ const result = HTTPError.notFound();
70
+ assertEquals(result.status, 404);
71
+ assertEquals(result.statusText, "Not Found");
72
+ });
61
73
  });
62
74
 
63
- await t.step("notImplemented", () => {
64
- const result = HTTPError.notImplemented();
65
- assertEquals(result.status, 501);
66
- assertEquals(result.statusText, "Not Implemented");
75
+ describe("internalServerError", () => {
76
+ it("creates the error", () => {
77
+ const result = HTTPError.internalServerError();
78
+ assertEquals(result.status, 500);
79
+ assertEquals(result.statusText, "Internal Server Error");
80
+ });
81
+
82
+ describe("notImplemented", () => {
83
+ it("creates the error", () => {
84
+ const result = HTTPError.notImplemented();
85
+ assertEquals(result.status, 501);
86
+ assertEquals(result.statusText, "Not Implemented");
87
+ });
88
+ });
67
89
  });
68
90
  });
package/core/mod.d.ts CHANGED
@@ -3,4 +3,5 @@ export * from "./fetch-router.js";
3
3
  export * from "./http.js";
4
4
  export * from "./migrator.js";
5
5
  export * from "./postgres.js";
6
+ export * from "./structures.js";
6
7
  export * from "./utilities.js";
package/core/mod.js CHANGED
@@ -3,4 +3,5 @@ export * from "./fetch-router.js";
3
3
  export * from "./http.js";
4
4
  export * from "./migrator.js";
5
5
  export * from "./postgres.js";
6
+ export * from "./structures.js";
6
7
  export * from "./utilities.js";
@@ -23,7 +23,7 @@ export class StructError extends Error {
23
23
  */
24
24
  /**
25
25
  * @template T
26
- * @typedef {(input?: unknown, context: StructContext) => T} StructExec
26
+ * @typedef {(input?: unknown, context?: StructContext) => T} StructExec
27
27
  */
28
28
  /**
29
29
  * @template T
@@ -34,26 +34,39 @@ export class StructError extends Error {
34
34
  */
35
35
  export class Structure<T> {
36
36
  /**
37
- * @param {string} fallback
37
+ * @param {string} [fallback]
38
38
  * @returns {Structure<string>}
39
39
  */
40
- static string(fallback: string): Structure<string>;
40
+ static string(fallback?: string): Structure<string>;
41
41
  /**
42
- * @param {number} fallback
42
+ * @param {number} [fallback]
43
43
  * @returns {Structure<number>}
44
44
  */
45
- static number(fallback: number): Structure<number>;
45
+ static number(fallback?: number): Structure<number>;
46
46
  /**
47
- * @param {string | URL} fallback
47
+ * @param {boolean} fallback
48
+ * @returns {Structure<boolean>}
49
+ */
50
+ static boolean(fallback: boolean): Structure<boolean>;
51
+ /**
52
+ * @param {string | URL} [fallback]
48
53
  * @returns {Structure<URL>}
49
54
  */
50
- static url(fallback: string | URL): Structure<URL>;
55
+ static url(fallback?: string | URL): Structure<URL>;
51
56
  /**
52
57
  * @template {Record<string, Structure<any>>} U
53
58
  * @param {U} fields
54
59
  * @returns {Structure<{ [K in keyof U]: Infer<U[K]> }>}
55
60
  */
56
61
  static object<U extends Record<string, Structure<any>>>(fields: U): Structure<{ [K in keyof U]: Infer<U[K]>; }>;
62
+ /**
63
+ * **UNSTABLE** use at your own risk
64
+ *
65
+ * @template {Structure<any>} U
66
+ * @param {U} struct
67
+ * @returns {Structure<Array<Infer<U>>>}
68
+ */
69
+ static array<U_1 extends Structure<any>>(struct: U_1): Structure<Infer<U_1>[]>;
57
70
  /**
58
71
  * @param {Schema} schema
59
72
  * @param {StructExec<T>} process
@@ -68,11 +81,11 @@ export class Structure<T> {
68
81
  export type StructContext = {
69
82
  path: string[];
70
83
  };
71
- export type StructOptions<Type, Schema_1> = {
84
+ export type StructOptions<Type, Schema> = {
72
85
  type: 'object' | 'string' | 'url';
73
86
  schema: Schema;
74
87
  fn: (value: unknown, ctx: StructContext) => Type;
75
88
  };
76
89
  export type Schema = Record<string, unknown>;
77
- export type StructExec<T> = (input?: unknown, context: StructContext) => T;
90
+ export type StructExec<T> = (input?: unknown, context?: StructContext) => T;
78
91
  export type Infer<T> = T extends Structure<infer U> ? U : never;