gruber 0.2.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.
- package/CHANGELOG.md +29 -0
- package/README.md +156 -16
- package/core/configuration.d.ts +157 -0
- package/core/configuration.js +222 -96
- package/core/configuration.test.d.ts +1 -0
- package/core/configuration.test.js +242 -53
- package/{types/core → core}/fetch-router.d.ts +0 -1
- package/core/fetch-router.test.d.ts +1 -0
- package/{types/core → core}/http.d.ts +30 -12
- package/core/http.js +42 -17
- package/core/http.test.d.ts +1 -0
- package/core/http.test.js +57 -35
- package/{types/core → core}/migrator.d.ts +0 -1
- package/core/migrator.test.d.ts +1 -0
- package/{types/core → core}/mod.d.ts +1 -1
- package/core/mod.js +1 -0
- package/{types/core → core}/postgres.d.ts +0 -1
- package/core/structures.d.ts +91 -0
- package/core/structures.js +260 -0
- package/core/structures.test.d.ts +1 -0
- package/core/structures.test.js +474 -0
- package/core/test-deps.d.ts +1 -0
- package/core/test-deps.js +1 -1
- package/{types/core → core}/types.d.ts +0 -1
- package/{types/core → core}/utilities.d.ts +0 -1
- package/core/utilities.test.d.ts +1 -0
- package/package.json +4 -5
- package/{types/source → source}/configuration.d.ts +4 -9
- package/source/configuration.js +0 -2
- package/source/core.d.ts +1 -0
- package/{types/source → source}/express-router.d.ts +2 -3
- package/source/express-router.js +1 -1
- package/{types/source → source}/koa-router.d.ts +0 -1
- package/{types/source → source}/mod.d.ts +0 -3
- package/source/mod.js +2 -2
- package/{types/source → source}/node-router.d.ts +8 -8
- package/source/node-router.js +1 -1
- package/source/package-lock.json +3 -9
- package/source/package.json +0 -2
- package/source/polyfill.d.ts +1 -0
- package/{types/source → source}/postgres.d.ts +0 -1
- package/tsconfig.json +0 -2
- package/types/core/configuration.d.ts +0 -57
- package/types/core/configuration.d.ts.map +0 -1
- package/types/core/configuration.test.d.ts +0 -2
- package/types/core/configuration.test.d.ts.map +0 -1
- package/types/core/fetch-router.d.ts.map +0 -1
- package/types/core/fetch-router.test.d.ts +0 -2
- package/types/core/fetch-router.test.d.ts.map +0 -1
- package/types/core/http.d.ts.map +0 -1
- package/types/core/http.test.d.ts +0 -2
- package/types/core/http.test.d.ts.map +0 -1
- package/types/core/migrator.d.ts.map +0 -1
- package/types/core/migrator.test.d.ts +0 -2
- package/types/core/migrator.test.d.ts.map +0 -1
- package/types/core/mod.d.ts.map +0 -1
- package/types/core/postgres.d.ts.map +0 -1
- package/types/core/test-deps.d.ts +0 -2
- package/types/core/test-deps.d.ts.map +0 -1
- package/types/core/types.d.ts.map +0 -1
- package/types/core/utilities.d.ts.map +0 -1
- package/types/core/utilities.test.d.ts +0 -2
- package/types/core/utilities.test.d.ts.map +0 -1
- package/types/source/configuration.d.ts.map +0 -1
- package/types/source/core.d.ts +0 -2
- package/types/source/core.d.ts.map +0 -1
- package/types/source/express-router.d.ts.map +0 -1
- package/types/source/koa-router.d.ts.map +0 -1
- package/types/source/mod.d.ts.map +0 -1
- package/types/source/node-router.d.ts.map +0 -1
- package/types/source/polyfill.d.ts +0 -2
- package/types/source/polyfill.d.ts.map +0 -1
- package/types/source/postgres.d.ts.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
This file documents notable changes to the project
|
|
4
4
|
|
|
5
|
+
## 0.4.0
|
|
6
|
+
|
|
7
|
+
**new**
|
|
8
|
+
|
|
9
|
+
- Added `config.number(...)` & `config.boolean(...)` types along with `Structure` equivolents.
|
|
10
|
+
- Set a response body when creating a `HTTPError`, either via the constructor or the static methods.
|
|
11
|
+
- Set headers when creating an `HTTPError` and mutate the headers on it too, to be passed to the Response.
|
|
12
|
+
- Structure primatives' fallback is now optional. If a fallback isn't provided, validation will fail if with a "Missing value" if no value is provided.
|
|
13
|
+
- Added an unstable/experimental `Structure.array` for validating an array of a single Structure, e.g. an array of strings.
|
|
14
|
+
- Add number and boolean configurations (and their structures)
|
|
15
|
+
|
|
16
|
+
**fixes**
|
|
17
|
+
|
|
18
|
+
- Improve JSDoc types for Deno / Node clients
|
|
19
|
+
- Fix Structure typings
|
|
20
|
+
- Organise Config/Structure/Spec wording
|
|
21
|
+
|
|
22
|
+
## 0.3.0
|
|
23
|
+
|
|
24
|
+
**new**
|
|
25
|
+
|
|
26
|
+
- Removed use of superstruct in favour of new `structures.js` implementation
|
|
27
|
+
- Added `getJSONSchema` method to `Configuration`
|
|
28
|
+
|
|
29
|
+
**fixed**
|
|
30
|
+
|
|
31
|
+
- Node.js types should work now
|
|
32
|
+
- Node.js types includes a url-pattern polyfil
|
|
33
|
+
|
|
5
34
|
## 0.2.0
|
|
6
35
|
|
|
7
36
|
**new**
|
package/README.md
CHANGED
|
@@ -235,17 +235,20 @@ Building on the [HTTP server](#http-server) above, we'll setup configuration. St
|
|
|
235
235
|
**config.js**
|
|
236
236
|
|
|
237
237
|
```js
|
|
238
|
-
import
|
|
238
|
+
import fs from "node:fs";
|
|
239
239
|
import { getNodeConfiguration } from "gruber";
|
|
240
240
|
|
|
241
241
|
const pkg = JSON.parse(fs.readFileSync("./package.json", "utf8"));
|
|
242
|
-
const config = getNodeConfiguration(
|
|
242
|
+
const config = getNodeConfiguration();
|
|
243
243
|
|
|
244
|
-
export function
|
|
244
|
+
export function getConfigStruct() {
|
|
245
245
|
return config.object({
|
|
246
|
-
env: config.string({
|
|
247
|
-
|
|
248
|
-
|
|
246
|
+
env: config.string({ variable: "NODE_ENV", fallback: "development" }),
|
|
247
|
+
|
|
248
|
+
port: config.number({
|
|
249
|
+
variable: "APP_PORT",
|
|
250
|
+
flag: "--port",
|
|
251
|
+
fallback: 8000,
|
|
249
252
|
}),
|
|
250
253
|
|
|
251
254
|
selfUrl: config.url({
|
|
@@ -253,13 +256,13 @@ export function getSpecification() {
|
|
|
253
256
|
fallback: "http://localhost:3000",
|
|
254
257
|
}),
|
|
255
258
|
|
|
256
|
-
// Short hands?
|
|
257
259
|
meta: config.object({
|
|
258
260
|
name: config.string({ flag: "--app-name", fallback: pkg.name }),
|
|
259
261
|
version: config.string({ fallback: pkg.version }),
|
|
260
262
|
}),
|
|
261
263
|
|
|
262
264
|
database: config.object({
|
|
265
|
+
useSsl: config.boolean({ flag: "--database-ssl", fallback: true }),
|
|
263
266
|
url: config.url({
|
|
264
267
|
variable: "DATABASE_URL",
|
|
265
268
|
flag: "--database-url",
|
|
@@ -271,11 +274,11 @@ export function getSpecification() {
|
|
|
271
274
|
|
|
272
275
|
// Load the configuration and parse it
|
|
273
276
|
export function loadConfiguration(path) {
|
|
274
|
-
return config.load(path,
|
|
277
|
+
return config.load(path, getConfigStruct());
|
|
275
278
|
}
|
|
276
279
|
|
|
277
280
|
// TypeScript thought:
|
|
278
|
-
// export type Configuration = Infer<ReturnType<typeof
|
|
281
|
+
// export type Configuration = Infer<ReturnType<typeof getConfigStruct>>
|
|
279
282
|
|
|
280
283
|
// Expose the configutation for use in the application
|
|
281
284
|
export const appConfig = await loadConfiguration(
|
|
@@ -284,7 +287,12 @@ export const appConfig = await loadConfiguration(
|
|
|
284
287
|
|
|
285
288
|
// Export a method to generate usage documentation
|
|
286
289
|
export function getConfigurationUsage() {
|
|
287
|
-
return config.getUsage(
|
|
290
|
+
return config.getUsage(getConfigStruct());
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Export a method to generate a JSON Schema for the configuration
|
|
294
|
+
export function getConfigurationSchema() {
|
|
295
|
+
return config.getJSONSchema(getConfigStruct());
|
|
288
296
|
}
|
|
289
297
|
```
|
|
290
298
|
|
|
@@ -357,7 +365,7 @@ this can be done like so:
|
|
|
357
365
|
|
|
358
366
|
```js
|
|
359
367
|
export function loadConfiguration() {
|
|
360
|
-
const appConfig = config.loadJsonSync(path,
|
|
368
|
+
const appConfig = config.loadJsonSync(path, getConfigStruct());
|
|
361
369
|
|
|
362
370
|
// Only run these checks when running in production
|
|
363
371
|
if (appConfig.env === "production") {
|
|
@@ -672,7 +680,6 @@ To see how it works, look at the [Node](./node/source/configuration.js) and [Den
|
|
|
672
680
|
You can use the static `getOptions` method both subclasses provide and override the parts you want.
|
|
673
681
|
These are the options:
|
|
674
682
|
|
|
675
|
-
- `superstruct` — Configuration is based on [superstruct](https://docs.superstructjs.org/), you can pass your own instance if you like.
|
|
676
683
|
- `readTextFile(url)` — How to load a text file from the file system
|
|
677
684
|
- `getEnvironmentVariable(key)` — Return a matching environment "variable" for a key
|
|
678
685
|
- `getCommandArgument(key)` — Get the corresponding "flag" from a CLI argument
|
|
@@ -684,10 +691,9 @@ For example, to override in Node:
|
|
|
684
691
|
```js
|
|
685
692
|
import { Configuration, getNodeConfigOptions } from "gruber";
|
|
686
693
|
import Yaml from "yaml";
|
|
687
|
-
import superstruct from "superstruct";
|
|
688
694
|
|
|
689
695
|
const config = new Configuration({
|
|
690
|
-
...getNodeConfigOptions(
|
|
696
|
+
...getNodeConfigOptions(),
|
|
691
697
|
getEnvionmentVariable: () => undefined,
|
|
692
698
|
stringify: (v) => Yaml.stringify(v),
|
|
693
699
|
parse: (v) => Yaml.parse(v),
|
|
@@ -805,6 +811,8 @@ more can be added in the future as the need arrises.
|
|
|
805
811
|
They directly map to HTTP error as codes documented on [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status).
|
|
806
812
|
|
|
807
813
|
```js
|
|
814
|
+
import { HTTPError } from "gruber";
|
|
815
|
+
|
|
808
816
|
const teapot = new HTTPError(418, "I'm a teapot");
|
|
809
817
|
```
|
|
810
818
|
|
|
@@ -818,6 +826,55 @@ teapot.toResponse();
|
|
|
818
826
|
Currently, you can't set the body of the generated Response objects.
|
|
819
827
|
This would be nice to have in the future, but the API should be thoughtfully designed first.
|
|
820
828
|
|
|
829
|
+
**Request body**
|
|
830
|
+
|
|
831
|
+
You can set the body to be returned when the HTTPError is thrown from the constructor or the factory methods:
|
|
832
|
+
|
|
833
|
+
```ts
|
|
834
|
+
import { HTTPError } from "gruber";
|
|
835
|
+
|
|
836
|
+
const teapot = new HTTPError(418, "I'm a teapot", "model=teabot-5000");
|
|
837
|
+
|
|
838
|
+
throw HTTPError.badRequest("no coffee provided");
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
The value of the body is the same as the `body` in the
|
|
842
|
+
[Response constructor](https://developer.mozilla.org/en-US/docs/Web/API/Response/Response#body).
|
|
843
|
+
|
|
844
|
+
**Headers**
|
|
845
|
+
|
|
846
|
+
> _EXPERIMENTAL_
|
|
847
|
+
|
|
848
|
+
If you really want, you can set headers on a HTTPError too:
|
|
849
|
+
|
|
850
|
+
```ts
|
|
851
|
+
import { HTTPError } from "gruber";
|
|
852
|
+
|
|
853
|
+
const teapot = new HTTPError(
|
|
854
|
+
400,
|
|
855
|
+
"Bad Request",
|
|
856
|
+
JSON.stringify({ some: "thing" }),
|
|
857
|
+
{ "Content-Type": "application/json" },
|
|
858
|
+
);
|
|
859
|
+
|
|
860
|
+
// or via mutating the headers object
|
|
861
|
+
teapot.headers.set("X-HOTEL-BAR", "Hotel Bar?");
|
|
862
|
+
```
|
|
863
|
+
|
|
864
|
+
If you want fine-grain control, you might be better off creating a subclass, e.g. `BadJSONRequest`:
|
|
865
|
+
|
|
866
|
+
```ts
|
|
867
|
+
class BadJSONRequest extends HTTPError {
|
|
868
|
+
constructor(body) {
|
|
869
|
+
super(400, "Bad Request", body, { "Content-type": "application/json" });
|
|
870
|
+
this.name = "BadJSONRequest";
|
|
871
|
+
Error.captureStackTrace(this, BadJSONRequest);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
throw new BadJSONRequest({ message: "Something went wrong..." });
|
|
876
|
+
```
|
|
877
|
+
|
|
821
878
|
### FetchRouter
|
|
822
879
|
|
|
823
880
|
`FetchRouter` is a web-native router for routes defined with `defineRoute`.
|
|
@@ -870,7 +927,7 @@ You can use it and override parts of it to customise how the postgres migrator w
|
|
|
870
927
|
|
|
871
928
|
### Utilities
|
|
872
929
|
|
|
873
|
-
|
|
930
|
+
#### loader
|
|
874
931
|
|
|
875
932
|
`loader` let's you memoize the result of a function to create a singleton from it.
|
|
876
933
|
It works synchronously or with promises.
|
|
@@ -914,6 +971,89 @@ This will generate the table:
|
|
|
914
971
|
| Tyler Rockwell | ~ |
|
|
915
972
|
```
|
|
916
973
|
|
|
974
|
+
#### Structure
|
|
975
|
+
|
|
976
|
+
This is an internal primative for validating objects, strings, numbers and URLs for use in [Configuration](#configuration).
|
|
977
|
+
It is based on a very specific use of [superstruct](https://github.com/ianstormtaylor/superstruct) which it made sense to internalise to make the code base more portable.
|
|
978
|
+
A `Structure` is a type that validates a value is correct by throwing an error if validation fails, i.e. the wrong type is passed.
|
|
979
|
+
Every struct has an intrinsic `fallback` so that if no value (`undefined`) is passed, that is used instead.
|
|
980
|
+
|
|
981
|
+
```js
|
|
982
|
+
import { Structure } from "gruber/structures.js";
|
|
983
|
+
|
|
984
|
+
// A string primative, or use "Geoff Testington" if no value is passed.
|
|
985
|
+
const name = Structure.string("Geoff Testington");
|
|
986
|
+
|
|
987
|
+
// A URL instance or a string that contains a valid URL, always converting to a URL
|
|
988
|
+
const website = Structure.url("https://example.com");
|
|
989
|
+
|
|
990
|
+
// A number primative, falling back to 42
|
|
991
|
+
const age = Structure.number(42);
|
|
992
|
+
|
|
993
|
+
// An object with all of the fields above and nothing else
|
|
994
|
+
// defaulting to create { name: "Geoff..", age: 42, website: "https..." } with the same fallback values
|
|
995
|
+
const person = Structure.object({ name, age, website });
|
|
996
|
+
|
|
997
|
+
// Process the Structure and get a value out. The returned value is strongly typed!
|
|
998
|
+
// This will throw if the value passed does not match the schema.
|
|
999
|
+
const value = person.process(/* ... */);
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
Those static Structure methods return a `Structure` instance. You can also create your own types with the constructor. This example shows how to do that, and also starts to unveil how the internals work a bit with [StructError](#structerror).
|
|
1003
|
+
|
|
1004
|
+
```js
|
|
1005
|
+
import { Structure, StructError } from "gruber/structures.js";
|
|
1006
|
+
|
|
1007
|
+
// Create a new boolean structure (this should probably be included as Structure.boolean tbh)
|
|
1008
|
+
const boolean = new Structure(
|
|
1009
|
+
{ type: "boolean", default: false },
|
|
1010
|
+
(input, context) => {
|
|
1011
|
+
if (input === undefined) return false;
|
|
1012
|
+
if (typeof input !== "boolean") {
|
|
1013
|
+
throw new StructError("Expected a boolean", context?.path);
|
|
1014
|
+
}
|
|
1015
|
+
return input;
|
|
1016
|
+
},
|
|
1017
|
+
);
|
|
1018
|
+
```
|
|
1019
|
+
|
|
1020
|
+
To create a custom Structure, you give it a [JSON schema](https://json-schema.org/) and a "process" function.
|
|
1021
|
+
The function is called to validate a value against the structure. It should return the processed value or throw a `StructError`.
|
|
1022
|
+
|
|
1023
|
+
The `context` object might not be set and this means the struct is at the root level. If it is nested in an `object` then the context contains the path that the struct is located at, all the way from the root object. That path is expressed as an array of strings. That path is used to generate friendlier error messages to explain which nested field failed.
|
|
1024
|
+
|
|
1025
|
+
With a Structure, you can generate a JSON Schema:
|
|
1026
|
+
|
|
1027
|
+
```js
|
|
1028
|
+
import { Structure } from "gruber/structures.js";
|
|
1029
|
+
|
|
1030
|
+
const person = Structure.object({
|
|
1031
|
+
name: Structure.string("Geoff Testington"),
|
|
1032
|
+
age: Structure.number(42),
|
|
1033
|
+
website: Structure.url("https://example.com"),
|
|
1034
|
+
});
|
|
1035
|
+
|
|
1036
|
+
console.log(JSON.stringify(person.getSchema(), null, 2));
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
This is a bit WIP, but you could use this to generate a JSON schema to lint configurations in your IDE.
|
|
1040
|
+
|
|
1041
|
+
#### StructError
|
|
1042
|
+
|
|
1043
|
+
This Error subclass contains extra information about why parsing a `Structure` failed.
|
|
1044
|
+
|
|
1045
|
+
- The `message` field is a description of what went wrong, in the context of the structure.
|
|
1046
|
+
- An extra `path` field exists to describe the path from the root object to get to this failed structure
|
|
1047
|
+
- `children` is also available to let a structure have multiple child errors, i.e. for an object to have failures for each of the fields that have failed.
|
|
1048
|
+
|
|
1049
|
+
On the error, there are also methods to help use it:
|
|
1050
|
+
|
|
1051
|
+
- `toFriendlyString` goes through all nested failures and outputs a single message to describe everything that went wrong.
|
|
1052
|
+
- `getOneLiner` converts the error to a succint one-line error message, concatentating the path and message
|
|
1053
|
+
- `[Symbol.iterator]` is also available if you want to loop through all children nodes, only those that do not have children themselves.
|
|
1054
|
+
|
|
1055
|
+
There is also the static method `StructError.chain(error, context)` which is useful for catching errors and applying a context to them (if they are not already a StructError).
|
|
1056
|
+
|
|
917
1057
|
## Node.js library
|
|
918
1058
|
|
|
919
1059
|
There are some specific helpers to help use Gruber in Node.js apps.
|
|
@@ -969,7 +1109,7 @@ For older version of Node.js that don't support the latest web-standards,
|
|
|
969
1109
|
there is a polyfil import you can use to add support for them to your runtime.
|
|
970
1110
|
|
|
971
1111
|
```js
|
|
972
|
-
import "gruber/
|
|
1112
|
+
import "gruber/polyfill.js";
|
|
973
1113
|
```
|
|
974
1114
|
|
|
975
1115
|
This currently polyfils these APIs:
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @template [T=any]
|
|
3
|
+
* @typedef {object} SpecOptions
|
|
4
|
+
* @property {string} [variable]
|
|
5
|
+
* @property {string} [flag]
|
|
6
|
+
* @property {T} fallback
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* @template T
|
|
10
|
+
* @typedef {object} ConfigurationResult
|
|
11
|
+
* @property {'argument' | 'variable' | 'fallback'} source
|
|
12
|
+
* @property {string|T} value
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {object} ConfigurationDescription
|
|
16
|
+
* @property {unknown} fallback
|
|
17
|
+
* @property {Record<string,string>[]} fields
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {object} Specification
|
|
21
|
+
* @property {string} type
|
|
22
|
+
* @property {any} options
|
|
23
|
+
* @property {(name: string) => ConfigurationDescription} describe
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* @param {string} name
|
|
27
|
+
* @param {unknown} value
|
|
28
|
+
* @returns {Specification}
|
|
29
|
+
*/
|
|
30
|
+
export function _getSpec(name: string, value: unknown): Specification;
|
|
31
|
+
export class _ObjectSpec {
|
|
32
|
+
/** @param {Record<string, SpecOptions>} options */
|
|
33
|
+
constructor(options: Record<string, SpecOptions>);
|
|
34
|
+
type: string;
|
|
35
|
+
options: Record<string, SpecOptions<any>>;
|
|
36
|
+
describe(name: any): {
|
|
37
|
+
fallback: {};
|
|
38
|
+
fields: Record<string, string>[];
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export class _LiteralSpec {
|
|
42
|
+
/**
|
|
43
|
+
* @param {string} type
|
|
44
|
+
* @param {SpecOptions<any>} options
|
|
45
|
+
*/
|
|
46
|
+
constructor(type: string, options: SpecOptions<any>);
|
|
47
|
+
type: string;
|
|
48
|
+
options: SpecOptions<any>;
|
|
49
|
+
describe(name: any): {
|
|
50
|
+
fallback: any;
|
|
51
|
+
fields: {
|
|
52
|
+
variable?: string;
|
|
53
|
+
flag?: string;
|
|
54
|
+
fallback: any;
|
|
55
|
+
name: any;
|
|
56
|
+
type: string;
|
|
57
|
+
}[];
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* @typedef {object} ConfigurationOptions
|
|
62
|
+
* @property {(url: URL) => Promise<string | null>} readTextFile
|
|
63
|
+
* @property {(key: string) => (string | undefined)} getEnvironmentVariable
|
|
64
|
+
* @property {(key: string) => (string | undefined)} getCommandArgument
|
|
65
|
+
* @property {(value: any) => (string | Promise<string>)} stringify
|
|
66
|
+
* @property {(value: string) => (any)} parse
|
|
67
|
+
*/
|
|
68
|
+
export class Configuration {
|
|
69
|
+
static spec: symbol;
|
|
70
|
+
/** @param {ConfigurationOptions} options */
|
|
71
|
+
constructor(options: ConfigurationOptions);
|
|
72
|
+
/** @type {ConfigurationOptions} */ options: ConfigurationOptions;
|
|
73
|
+
/**
|
|
74
|
+
* @template {Record<string, Structure<any>>} T
|
|
75
|
+
* @param {T} options
|
|
76
|
+
* @returns {Structure<{ [K in keyof T]: import("./structures.js").Infer<T[K]> }>}
|
|
77
|
+
*/
|
|
78
|
+
object<T extends Record<string, Structure<any>>>(options: T): Structure<{ [K in keyof T]: import("./structures.js").Infer<T[K]>; }>;
|
|
79
|
+
/**
|
|
80
|
+
* @param {SpecOptions<string>} options
|
|
81
|
+
* @returns {Structure<string>}
|
|
82
|
+
*/
|
|
83
|
+
string(options?: SpecOptions<string>): Structure<string>;
|
|
84
|
+
/**
|
|
85
|
+
* @param {SpecOptions<number>} options
|
|
86
|
+
* @returns {Structure<number>}
|
|
87
|
+
*/
|
|
88
|
+
number(options: SpecOptions<number>): Structure<number>;
|
|
89
|
+
/**
|
|
90
|
+
* @param {SpecOptions<boolean>} options
|
|
91
|
+
* @returns {Structure<number>}
|
|
92
|
+
*/
|
|
93
|
+
boolean(options: SpecOptions<boolean>): Structure<number>;
|
|
94
|
+
/**
|
|
95
|
+
* @param {SpecOptions<string|URL>} options
|
|
96
|
+
* @returns {Structure<URL>}
|
|
97
|
+
*/
|
|
98
|
+
url(options: SpecOptions<string | URL>): Structure<URL>;
|
|
99
|
+
/**
|
|
100
|
+
* @template T
|
|
101
|
+
* @param {SpecOptions<T>} options
|
|
102
|
+
* @returns {ConfigurationResult<T>}
|
|
103
|
+
*/
|
|
104
|
+
_getValue<T_1>(options: SpecOptions<T_1>): ConfigurationResult<T_1>;
|
|
105
|
+
/** @param {ConfigurationResult<number>} result */
|
|
106
|
+
_parseFloat(result: ConfigurationResult<number>): number;
|
|
107
|
+
/** @param {ConfigurationResult<boolean>} result */
|
|
108
|
+
_parseBoolean(result: ConfigurationResult<boolean>): any;
|
|
109
|
+
/**
|
|
110
|
+
* @template T
|
|
111
|
+
* @param {URL} url
|
|
112
|
+
* @param {Structure<T>} spec
|
|
113
|
+
* @returns {Promise<T>}
|
|
114
|
+
*/
|
|
115
|
+
load<T_2>(url: URL, spec: Structure<T_2>): Promise<T_2>;
|
|
116
|
+
/** @param {unknown} value */
|
|
117
|
+
getUsage(value: unknown): string;
|
|
118
|
+
/**
|
|
119
|
+
* @param {unknown} struct
|
|
120
|
+
* @param {string} [prefix]
|
|
121
|
+
* @returns {{ config: any, fields: [string, string] }}
|
|
122
|
+
*/
|
|
123
|
+
describe(value: any, prefix?: string): {
|
|
124
|
+
config: any;
|
|
125
|
+
fields: [string, string];
|
|
126
|
+
};
|
|
127
|
+
/** * @param {Structure<any>} struct */
|
|
128
|
+
getJSONSchema(struct: Structure<any>): {
|
|
129
|
+
$schema: string;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
export type SpecOptions<T = any> = {
|
|
133
|
+
variable?: string;
|
|
134
|
+
flag?: string;
|
|
135
|
+
fallback: T;
|
|
136
|
+
};
|
|
137
|
+
export type ConfigurationResult<T> = {
|
|
138
|
+
source: 'argument' | 'variable' | 'fallback';
|
|
139
|
+
value: string | T;
|
|
140
|
+
};
|
|
141
|
+
export type ConfigurationDescription = {
|
|
142
|
+
fallback: unknown;
|
|
143
|
+
fields: Record<string, string>[];
|
|
144
|
+
};
|
|
145
|
+
export type Specification = {
|
|
146
|
+
type: string;
|
|
147
|
+
options: any;
|
|
148
|
+
describe: (name: string) => ConfigurationDescription;
|
|
149
|
+
};
|
|
150
|
+
export type ConfigurationOptions = {
|
|
151
|
+
readTextFile: (url: URL) => Promise<string | null>;
|
|
152
|
+
getEnvironmentVariable: (key: string) => (string | undefined);
|
|
153
|
+
getCommandArgument: (key: string) => (string | undefined);
|
|
154
|
+
stringify: (value: any) => (string | Promise<string>);
|
|
155
|
+
parse: (value: string) => (any);
|
|
156
|
+
};
|
|
157
|
+
import { Structure } from "./structures.js";
|