@amritk/mjst 0.18.0 → 0.20.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/README.md +23 -1
- package/dist/cli-config.d.ts +14 -9
- package/dist/cli.js +9 -6
- package/dist/create-output-writer.d.ts +19 -17
- package/dist/create-output-writer.js +3 -27
- package/dist/emit-examples.d.ts +3 -4
- package/dist/emit-message-contracts.d.ts +6 -0
- package/dist/emit-message-contracts.js +11 -2
- package/dist/help-text.d.ts +1 -1
- package/dist/help-text.js +4 -1
- package/dist/lint/preset-ruleset.d.ts +61 -0
- package/dist/lint/preset-ruleset.js +55 -0
- package/dist/lint/run.js +6 -14
- package/dist/load-config.d.ts +0 -8
- package/dist/load-config.js +2 -0
- package/dist/parse-cli-args.js +6 -1
- package/dist/validate-config.d.ts +5 -2
- package/dist/validate-config.js +3 -0
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -217,6 +217,19 @@ config/service.yaml:2:7 error config-schema /port must be integer
|
|
|
217
217
|
|
|
218
218
|
With no `-r`, mjst discovers a `.lint.{yaml,yml,json,js,mjs}` ruleset by walking up from each linted file. A ruleset maps a JSONPath (`given`) to a function (`then`) — `schema` (JSON Schema), `casing`, `pattern`, `truthy`, and more, plus your own. The [`@amritk/lint` README](../lint#ruleset-format) documents the ruleset format and built-in functions. For machine-readable output (JSON, SARIF, …), call the [`@amritk/lint`](../lint) library's `lintDocument`, which returns structured findings.
|
|
219
219
|
|
|
220
|
+
Your own ruleset can build on a preset: `extends: [asyncapi]` (or `[oas]`) layers your rules on top of the preset's, with the preset's custom functions and format detection intact — through `-r <file>` and `.lint.*` discovery alike. Relative `extends` targets and custom `functions` still resolve next to your ruleset file. Extend at most one preset per ruleset: the two bring different formats and functions and neither can resolve the other, so a ruleset naming both is refused up front. Lint AsyncAPI and OpenAPI documents in separate runs.
|
|
221
|
+
|
|
222
|
+
```yaml
|
|
223
|
+
# .lint.yaml — the AsyncAPI preset plus a house rule
|
|
224
|
+
extends:
|
|
225
|
+
- asyncapi
|
|
226
|
+
rules:
|
|
227
|
+
needs-terms-of-service:
|
|
228
|
+
given: "$.info"
|
|
229
|
+
severity: error
|
|
230
|
+
then: { field: termsOfService, function: truthy }
|
|
231
|
+
```
|
|
232
|
+
|
|
220
233
|
| Flag | Description |
|
|
221
234
|
| --- | --- |
|
|
222
235
|
| `<documents..>` | Files or globs to lint (positional). |
|
|
@@ -394,7 +407,7 @@ The exit code is `0` on success, `1` when compilation fails (unloadable module,
|
|
|
394
407
|
<td align="center"><code>false</code></td>
|
|
395
408
|
</tr>
|
|
396
409
|
<tr>
|
|
397
|
-
<td colspan="4">
|
|
410
|
+
<td colspan="4">Deprecated and ignored. Generated files always replace whatever is at their path, so this flag no longer does anything; it is still accepted so existing scripts and config files keep running. Reverting an unwanted replacement is version control's job. Compilation under build still only removes the intermediate sources the run itself generated.</td>
|
|
398
411
|
</tr>
|
|
399
412
|
<tr>
|
|
400
413
|
<td>⚠️ <code>logWarnings</code></td>
|
|
@@ -451,6 +464,15 @@ The exit code is `0` on success, `1` when compilation fails (unloadable module,
|
|
|
451
464
|
<td colspan="4">How generated fast paths (parsers and validators alike) prove a closed object — additionalProperties: false, or a stripUnknown build — carries no undeclared key. 'count-keys' compares Object.keys(obj).length and is the faster form on JavaScriptCore (Bun), where a for…in over a non-extensible object takes the engine's slow path and halves strict-parse throughput. 'count-enumerable' counts with for…in and allocates nothing; it was the faster form on Node 22, but on Node 26 'count-keys' ties or wins there too. Keep the default unless you are pinned to an older V8 and have measured your own shapes; the generated code never detects its runtime.<br><strong>Allowed:</strong> <code>"count-enumerable"</code>, <code>"count-keys"</code></td>
|
|
452
465
|
</tr>
|
|
453
466
|
<tr>
|
|
467
|
+
<td>🧪 <code>formats</code></td>
|
|
468
|
+
<td><code>--formats <list></code></td>
|
|
469
|
+
<td><code>string | array</code></td>
|
|
470
|
+
<td align="center"></td>
|
|
471
|
+
</tr>
|
|
472
|
+
<tr>
|
|
473
|
+
<td colspan="4">String formats the generated validators enforce: "all", or a comma-separated list (e.g. uuid,date-time,email). Omitted, format stays an annotation — JSON Schema's own reading, and what @amritk/runtime-validators does when given no formats. Set it to whatever validates the same schemas at runtime (@amritk/lint and createApi({ formats }) run the interpreter with formats on) so the build-time and runtime answers agree. Both validateX and the flat isX check them, against a formats.ts emitted alongside the validators.</td>
|
|
474
|
+
</tr>
|
|
475
|
+
<tr>
|
|
454
476
|
<td>🧰 <code>helpers</code></td>
|
|
455
477
|
<td><code>--helpers <mode></code></td>
|
|
456
478
|
<td><code>string</code></td>
|
package/dist/cli-config.d.ts
CHANGED
|
@@ -85,15 +85,11 @@ export type CliConfig = {
|
|
|
85
85
|
*/
|
|
86
86
|
readonly build?: boolean;
|
|
87
87
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* the root of the output directory, and reclaims those paths freely. With
|
|
94
|
-
* `outFile` the "output directory" is the directory holding that file, so the
|
|
95
|
-
* manifest lands beside it — generated examples and the `build` output already
|
|
96
|
-
* do.
|
|
88
|
+
* @deprecated No longer has any effect, and is accepted only so existing
|
|
89
|
+
* scripts and config files keep running. Generated files always replace
|
|
90
|
+
* whatever is at their path; version control is where an unwanted replacement
|
|
91
|
+
* shows up and gets reverted. `build` still only ever deletes the intermediate
|
|
92
|
+
* sources the run itself committed.
|
|
97
93
|
*/
|
|
98
94
|
readonly force?: boolean;
|
|
99
95
|
/**
|
|
@@ -133,6 +129,15 @@ export type CliConfig = {
|
|
|
133
129
|
* (Node). Applies to parsers and validators alike.
|
|
134
130
|
*/
|
|
135
131
|
readonly unknownKeys?: UnknownKeysStrategy;
|
|
132
|
+
/**
|
|
133
|
+
* String `format`s the generated validators enforce — `'all'`, or the names to
|
|
134
|
+
* check. Left unset, `format` stays an annotation, which is 2020-12's own
|
|
135
|
+
* reading and what `@amritk/runtime-validators` does when given no formats.
|
|
136
|
+
*
|
|
137
|
+
* Set it to whatever the code validating the same schemas at runtime uses, so
|
|
138
|
+
* the build-time and runtime answers agree.
|
|
139
|
+
*/
|
|
140
|
+
readonly formats?: 'all' | readonly string[];
|
|
136
141
|
/**
|
|
137
142
|
* Controls how generated parsers reference their runtime helpers.
|
|
138
143
|
* - `'package'`: emit `import ... from '@amritk/helpers/...'`.
|
package/dist/cli.js
CHANGED
|
@@ -67,7 +67,7 @@ const commitOrDiscard = async (writer, stageAll) => {
|
|
|
67
67
|
return writer.commit();
|
|
68
68
|
};
|
|
69
69
|
const runExamples = async (config, outputDir, tasks) => {
|
|
70
|
-
const writer = await createOutputWriter(outputDir
|
|
70
|
+
const writer = await createOutputWriter(outputDir);
|
|
71
71
|
const written = await commitOrDiscard(writer, async () => {
|
|
72
72
|
for (const task of tasks) {
|
|
73
73
|
await emitExamples({
|
|
@@ -139,7 +139,7 @@ const findJsonSchemas = async (dir) => {
|
|
|
139
139
|
return results;
|
|
140
140
|
};
|
|
141
141
|
const runValidators = async (config, schema, rootTypeName, writer, validatorsSubDir) => {
|
|
142
|
-
const files = await buildValidatorSchema(schema, rootTypeName, config.typeSuffix, void 0, config.unknownKeys);
|
|
142
|
+
const files = await buildValidatorSchema(schema, rootTypeName, config.typeSuffix, void 0, config.unknownKeys, config.formats);
|
|
143
143
|
const staged = [];
|
|
144
144
|
for (const file of files) {
|
|
145
145
|
const content = config.banner ? resolveBanner(config.banner) + file.content : file.content;
|
|
@@ -156,7 +156,7 @@ const runSingle = async (config, schemaPath, outputDir) => {
|
|
|
156
156
|
const rootTypeName = config.rootType ?? deriveRootTypeName(schema, schemaBaseName(schemaPath));
|
|
157
157
|
console.log(`Root type: ${rootTypeName}`);
|
|
158
158
|
const files = await buildSchema(schema, rootTypeName, void 0, config.typesOnly, config.logWarnings, config.strict, helpersMode, void 0, config.readonly, config.stripUnknown, config.typeSuffix, resolveImportExt(config), config.caseInsensitive, void 0, config.unknownKeys);
|
|
159
|
-
const writer = await createOutputWriter(outputDir
|
|
159
|
+
const writer = await createOutputWriter(outputDir);
|
|
160
160
|
const written = await commitOrDiscard(writer, async () => {
|
|
161
161
|
for (const file of files) {
|
|
162
162
|
const isHelper = file.filename.startsWith("_helpers/");
|
|
@@ -186,7 +186,7 @@ const runSingleFile = async (config, schemaPath, outFilePath) => {
|
|
|
186
186
|
console.log(`Root type: ${rootTypeName}`);
|
|
187
187
|
const files = await buildSchema(schema, rootTypeName, void 0, config.typesOnly, config.logWarnings, config.strict, config.helpers ?? "package", void 0, config.readonly, config.stripUnknown, config.typeSuffix, resolveImportExt(config), config.caseInsensitive, void 0, config.unknownKeys);
|
|
188
188
|
const combined = combineGeneratedFiles(files);
|
|
189
|
-
const writer = await createOutputWriter(outputDir
|
|
189
|
+
const writer = await createOutputWriter(outputDir);
|
|
190
190
|
const written = await commitOrDiscard(writer, async () => {
|
|
191
191
|
await writer.stage(basename(outFilePath), config.banner ? resolveBanner(config.banner) + combined : combined);
|
|
192
192
|
});
|
|
@@ -214,7 +214,7 @@ const runRecursive = async (config, schemaDir, outputDir) => {
|
|
|
214
214
|
await ensureOutputDir(outputDir);
|
|
215
215
|
const helpersMode = resolveHelpersMode(config, outputDir);
|
|
216
216
|
const sharedHelpers = /* @__PURE__ */ new Map();
|
|
217
|
-
const writer = await createOutputWriter(outputDir
|
|
217
|
+
const writer = await createOutputWriter(outputDir);
|
|
218
218
|
const exampleTasks = [];
|
|
219
219
|
const stageAll = async () => {
|
|
220
220
|
for (const schemaFile of schemaFiles) {
|
|
@@ -279,7 +279,7 @@ const runAsyncApi = async (config, documentPath, outputDir) => {
|
|
|
279
279
|
await ensureOutputDir(outputDir);
|
|
280
280
|
const helpersMode = resolveHelpersMode(config, outputDir);
|
|
281
281
|
const sharedHelpers = /* @__PURE__ */ new Map();
|
|
282
|
-
const writer = await createOutputWriter(outputDir
|
|
282
|
+
const writer = await createOutputWriter(outputDir);
|
|
283
283
|
const exampleTasks = [];
|
|
284
284
|
const contractIssues = [];
|
|
285
285
|
let contractMessageCount = 0;
|
|
@@ -385,6 +385,9 @@ const run = async () => {
|
|
|
385
385
|
console.error("Error: provide only one of --out-dir or --out-file, not both.");
|
|
386
386
|
process.exit(1);
|
|
387
387
|
}
|
|
388
|
+
if (config.force) {
|
|
389
|
+
console.warn("Warning: --force is deprecated and does nothing; generated files always replace what is at their path.");
|
|
390
|
+
}
|
|
388
391
|
if (config.rootType !== void 0 && !ROOT_TYPE_PATTERN.test(config.rootType)) {
|
|
389
392
|
console.error(`Error: invalid --root-type "${config.rootType}". Expected a TypeScript identifier (letters, digits, _ or $, not starting with a digit).`);
|
|
390
393
|
process.exit(1);
|
|
@@ -3,22 +3,21 @@
|
|
|
3
3
|
* final location under a temporary name, and only once the whole set is on disk
|
|
4
4
|
* are the temporaries renamed into place.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* The failure mode it exists for is **partial trees**. Writing straight to the
|
|
7
|
+
* final paths meant a failure halfway through (a `_helpers` path occupied by a
|
|
8
|
+
* regular file, a full disk) left some generated files behind and others missing
|
|
9
|
+
* — a tree that compiles against a schema that no longer exists. Staging first
|
|
10
|
+
* means the run either lands completely or leaves the destination as it found it.
|
|
11
|
+
* Renaming is not one atomic operation across the whole set, but every rename
|
|
12
|
+
* happens after all the risky work (generating, creating directories, writing
|
|
13
|
+
* bytes) has already succeeded, so it is the cheapest place to get the guarantee.
|
|
7
14
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* all the risky work (generating, creating directories, writing bytes) has
|
|
15
|
-
* already succeeded, so it is the cheapest place to get the guarantee.
|
|
16
|
-
* 2. **Clobbering hand-written files.** A generated name can collide with a file
|
|
17
|
-
* the user wrote (`index.ts` is the common one), which used to be overwritten
|
|
18
|
-
* without a word — and then, under `--build`, deleted along with the other
|
|
19
|
-
* intermediate sources. A file is only replaced when a previous run claimed it
|
|
20
|
-
* (see {@link MANIFEST_FILENAME}) or `--force` says so, and `--build` is only
|
|
21
|
-
* ever handed the paths this run actually committed.
|
|
15
|
+
* A generated path that already exists is simply replaced. The writer keeps no
|
|
16
|
+
* record of what it produced last time: an output directory is generated output,
|
|
17
|
+
* and version control is where a user sees — and reverts — a replacement they did
|
|
18
|
+
* not want. What the writer still guarantees is that `--build` only ever deletes
|
|
19
|
+
* intermediate sources this run committed, so nothing that was already sitting in
|
|
20
|
+
* the output directory is removed.
|
|
22
21
|
*/
|
|
23
22
|
export type OutputWriter = {
|
|
24
23
|
/**
|
|
@@ -34,7 +33,10 @@ export type OutputWriter = {
|
|
|
34
33
|
/**
|
|
35
34
|
* Creates an {@link OutputWriter} rooted at `rootDir`.
|
|
36
35
|
*
|
|
36
|
+
* Still async with nothing to await: it read the previous run's manifest here
|
|
37
|
+
* until that was removed, and every call site already awaits it. Keeping the
|
|
38
|
+
* signature leaves room for setup that does need I/O.
|
|
39
|
+
*
|
|
37
40
|
* @param rootDir - Output root. Every write must resolve inside it.
|
|
38
|
-
* @param force - Overwrite pre-existing files instead of refusing (`--force`).
|
|
39
41
|
*/
|
|
40
|
-
export declare const createOutputWriter: (rootDir: string
|
|
42
|
+
export declare const createOutputWriter: (rootDir: string) => Promise<OutputWriter>;
|
|
@@ -1,23 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { dirname,
|
|
1
|
+
import { rename, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, resolve, sep } from "node:path";
|
|
3
3
|
import { ensureOutputDir } from "./ensure-output-dir.js";
|
|
4
|
-
const
|
|
5
|
-
const pathExists = async (path) => stat(path).then(() => true, () => false);
|
|
6
|
-
const readManifest = async (root) => {
|
|
7
|
-
const raw = await readFile(join(root, MANIFEST_FILENAME), "utf-8").catch(() => void 0);
|
|
8
|
-
if (raw === void 0)
|
|
9
|
-
return /* @__PURE__ */ new Set();
|
|
10
|
-
try {
|
|
11
|
-
const parsed = JSON.parse(raw);
|
|
12
|
-
const files = Array.isArray(parsed.files) ? parsed.files : [];
|
|
13
|
-
return new Set(files.filter((file) => typeof file === "string").map((file) => resolve(root, file)));
|
|
14
|
-
} catch {
|
|
15
|
-
return /* @__PURE__ */ new Set();
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
const createOutputWriter = async (rootDir, force = false) => {
|
|
4
|
+
const createOutputWriter = async (rootDir) => {
|
|
19
5
|
const root = resolve(rootDir);
|
|
20
|
-
const owned = await readManifest(root);
|
|
21
6
|
const staged = [];
|
|
22
7
|
const stamp = `${process.pid}-${Date.now().toString(36)}`;
|
|
23
8
|
const stage = async (relativePath, content) => {
|
|
@@ -25,9 +10,6 @@ const createOutputWriter = async (rootDir, force = false) => {
|
|
|
25
10
|
if (targetPath !== root && !targetPath.startsWith(root + sep)) {
|
|
26
11
|
throw new Error(`Refusing to write "${relativePath}": it resolves outside the output directory ${root}.`);
|
|
27
12
|
}
|
|
28
|
-
if (!force && !owned.has(targetPath) && await pathExists(targetPath)) {
|
|
29
|
-
throw new Error(`Refusing to overwrite ${targetPath}: it already exists and was not generated by mjst. Move it aside, choose another output directory, or pass --force to overwrite it.`);
|
|
30
|
-
}
|
|
31
13
|
const tempPath = `${targetPath}.mjst-${stamp}-${staged.length}.tmp`;
|
|
32
14
|
await ensureOutputDir(dirname(targetPath));
|
|
33
15
|
await writeFile(tempPath, content, "utf-8");
|
|
@@ -36,12 +18,6 @@ const createOutputWriter = async (rootDir, force = false) => {
|
|
|
36
18
|
const commit = async () => {
|
|
37
19
|
for (const file of staged) {
|
|
38
20
|
await rename(file.tempPath, file.targetPath);
|
|
39
|
-
owned.add(file.targetPath);
|
|
40
|
-
}
|
|
41
|
-
if (staged.length > 0) {
|
|
42
|
-
const files = [...owned].map((path) => relative(root, path)).sort();
|
|
43
|
-
await writeFile(join(root, MANIFEST_FILENAME), `${JSON.stringify({ version: 1, files }, null, 2)}
|
|
44
|
-
`, "utf-8");
|
|
45
21
|
}
|
|
46
22
|
return staged.map((file) => file.relativePath);
|
|
47
23
|
};
|
package/dist/emit-examples.d.ts
CHANGED
|
@@ -11,10 +11,9 @@ export type EmitExamplesOptions = {
|
|
|
11
11
|
/**
|
|
12
12
|
* The run's writer, rooted at the output destination. Examples used to be
|
|
13
13
|
* written straight to disk with `mkdir` + `writeFile`, which meant the one
|
|
14
|
-
* output tree mjst emits that skipped
|
|
15
|
-
*
|
|
16
|
-
* of a directory makes that impossible to reintroduce
|
|
17
|
-
* that does not go through staging, the manifest, and `--force`.
|
|
14
|
+
* output tree mjst emits that skipped staging entirely — a failure part-way
|
|
15
|
+
* through left a half-written `examples/` tree behind. Taking the writer
|
|
16
|
+
* instead of a directory makes that impossible to reintroduce.
|
|
18
17
|
*/
|
|
19
18
|
readonly writer: OutputWriter;
|
|
20
19
|
/**
|
|
@@ -38,6 +38,12 @@ export type EmitMessageContractsResult = {
|
|
|
38
38
|
* accepts no frame in either direction, which is a trap rather than a document.
|
|
39
39
|
* The reasons come back in {@link EmitMessageContractsResult.issues}.
|
|
40
40
|
*
|
|
41
|
+
* Only payloads are projected. A message's `headers` schema is generated as its
|
|
42
|
+
* own tree by the parser run, but has no slot in a messages contract — the
|
|
43
|
+
* contract describes WebSocket frames, and headers are the broker's layer. Each
|
|
44
|
+
* module says so in its header when the channel declares any, rather than
|
|
45
|
+
* leaving the omission to be discovered.
|
|
46
|
+
*
|
|
41
47
|
* The barrel's specifiers are always `.ts`, ignoring `--import-ext`: these
|
|
42
48
|
* modules are the one part of the output `--build` leaves uncompiled (they
|
|
43
49
|
* import the `@amritk/api` peer, and handing tsc an import the output's project
|
|
@@ -11,12 +11,19 @@ ${indent} `);
|
|
|
11
11
|
${entries.join("\n")}
|
|
12
12
|
${indent}},`;
|
|
13
13
|
};
|
|
14
|
-
const renderChannelModule = (contract, channel) => {
|
|
14
|
+
const renderChannelModule = (contract, channel, headerMessages) => {
|
|
15
15
|
const directions = [
|
|
16
16
|
Object.keys(contract.clientToServer).length > 0 ? renderDirection("clientToServer", contract.clientToServer, " ") : void 0,
|
|
17
17
|
Object.keys(contract.serverToClient).length > 0 ? renderDirection("serverToClient", contract.serverToClient, " ") : void 0
|
|
18
18
|
].filter((entry) => entry !== void 0);
|
|
19
19
|
const address = channel.address !== void 0 && channel.address !== channel.key ? ` (${channel.address})` : "";
|
|
20
|
+
const headerNote = headerMessages.length === 0 ? [] : [
|
|
21
|
+
" *",
|
|
22
|
+
" * Payloads only: a message contract describes WebSocket frames, which carry",
|
|
23
|
+
" * no headers of their own. These messages declare a headers schema, and its",
|
|
24
|
+
` * types were generated alongside the payload's, under \`<message>-headers/\`:`,
|
|
25
|
+
` * ${headerMessages.join(", ")}.`
|
|
26
|
+
];
|
|
20
27
|
return [
|
|
21
28
|
"/**",
|
|
22
29
|
` * Message contract for the AsyncAPI channel \`${channel.key}\`${address}.`,
|
|
@@ -29,6 +36,7 @@ const renderChannelModule = (contract, channel) => {
|
|
|
29
36
|
` * \`{ "${contract.discriminator}": "<key>", ... }\` selects its schema by that key, and the`,
|
|
30
37
|
" * tag is removed before the payload below is validated \u2014 which is why no",
|
|
31
38
|
" * payload here declares it.",
|
|
39
|
+
...headerNote,
|
|
32
40
|
" */",
|
|
33
41
|
`import { defineMessages } from '${CONTRACTS_PEER}'`,
|
|
34
42
|
"",
|
|
@@ -70,7 +78,8 @@ const emitMessageContracts = async (options) => {
|
|
|
70
78
|
});
|
|
71
79
|
}
|
|
72
80
|
const filename = `${CONTRACTS_DIR}/${token}.ts`;
|
|
73
|
-
|
|
81
|
+
const headerMessages = channel.messages.filter((message) => message.headers !== void 0).map(({ name }) => name);
|
|
82
|
+
await writer.stage(filename, bannerPrefix + renderChannelModule({ ...contract, exportName }, channel, headerMessages));
|
|
74
83
|
files.push(filename);
|
|
75
84
|
barrel.push(`export { ${exportName} } from './${token}.ts'`);
|
|
76
85
|
}
|
package/dist/help-text.d.ts
CHANGED
|
@@ -4,4 +4,4 @@
|
|
|
4
4
|
* documents these flags (config.schema.json) is not shipped in the published
|
|
5
5
|
* package; the help-text test cross-checks that every flag is listed.
|
|
6
6
|
*/
|
|
7
|
-
export declare const HELP_TEXT = "mjst \u2014 generate TypeScript parsers and type definitions from JSON Schemas\n\nUsage:\n mjst --schema <path> --out-dir <dir> [options]\n mjst --schema-dir <dir> --out-dir <dir> [options]\n mjst --schema <path> --out-file <file> --types-only [options]\n\nSubcommands (each with its own flags and --help):\n mjst lint <files> Lint JSON/YAML documents against a ruleset\n mjst compile-api <module> --out <file> Compile @amritk/api route contracts into a fetch-handler module\n\nInput:\n --schema <path> Schema to process: a JSON Schema file, or a module when --input is set\n --schema-dir <dir> Directory of JSON Schemas, processed recursively (instead of --schema)\n --input <format> Schema source format: json (default), typebox, zod, valibot, effect, avro,\n or asyncapi (an AsyncAPI 2.x/3.0 document, JSON or YAML)\n --export <name> Which export of the schema module to use when --input names a module format\n\nOutput:\n --out-dir <dir> Output directory for the generated files\n --out-file <file> Single-file output instead of a directory (requires --types-only)\n --types-only Generate type definitions only, without parser functions\n --validators Also emit validateX/isX validators into a validators/ subdir\n --examples Also emit fast-check arbitraries + example values under examples/\n --message-contracts Also emit @amritk/api channel contracts under contracts/ (--input asyncapi only)\n --discriminator <p> Property naming which message a frame is, for --message-contracts (default: type)\n --build Compile the generated files to .js/.d.ts (implies --import-ext js)\n --force
|
|
7
|
+
export declare const HELP_TEXT = "mjst \u2014 generate TypeScript parsers and type definitions from JSON Schemas\n\nUsage:\n mjst --schema <path> --out-dir <dir> [options]\n mjst --schema-dir <dir> --out-dir <dir> [options]\n mjst --schema <path> --out-file <file> --types-only [options]\n\nSubcommands (each with its own flags and --help):\n mjst lint <files> Lint JSON/YAML documents against a ruleset\n mjst compile-api <module> --out <file> Compile @amritk/api route contracts into a fetch-handler module\n\nInput:\n --schema <path> Schema to process: a JSON Schema file, or a module when --input is set\n --schema-dir <dir> Directory of JSON Schemas, processed recursively (instead of --schema)\n --input <format> Schema source format: json (default), typebox, zod, valibot, effect, avro,\n or asyncapi (an AsyncAPI 2.x/3.0 document, JSON or YAML)\n --export <name> Which export of the schema module to use when --input names a module format\n\nOutput:\n --out-dir <dir> Output directory for the generated files\n --out-file <file> Single-file output instead of a directory (requires --types-only)\n --types-only Generate type definitions only, without parser functions\n --validators Also emit validateX/isX validators into a validators/ subdir\n --examples Also emit fast-check arbitraries + example values under examples/\n --message-contracts Also emit @amritk/api channel contracts under contracts/ (--input asyncapi only)\n --discriminator <p> Property naming which message a frame is, for --message-contracts (default: type)\n --build Compile the generated files to .js/.d.ts (implies --import-ext js)\n --force Deprecated; ignored (generated files always overwrite)\n --import-ext <ext> Extension on generated relative imports: ts (default) or js\n --helpers <mode> Runtime helpers: package or embedded (default: auto-detect from package.json)\n --root-type <name> Root type name for a single --schema run (default: schema title or filename)\n --type-suffix <s> Suffix appended to every $ref-derived type name\n --banner [text] Prepend a header comment to every generated file\n --readonly Emit deeply readonly type definitions\n\nValidation:\n --strict Throw on type/shape mismatches instead of coercing to defaults\n --strip-unknown Silently drop undeclared input keys at every nesting level\n --case-insensitive Normalize mis-cased enum/const strings to their exact casing\n --log-warnings console.warn on input keys not declared in the schema\n --unknown-keys <s> How closed objects are proven free of undeclared keys:\n count-keys (default, fastest on Bun) or count-enumerable (fastest on Node)\n --formats <f> String formats the generated validators enforce: \"all\", or a\n comma-separated list (e.g. uuid,date-time,email). Off by default,\n which leaves \"format\" an annotation as JSON Schema reads it.\n\nReference resolution:\n --resolve-remote Fetch http(s) $refs while resolving cross-file/remote refs (off by default)\n --allowed-hosts <h> Restrict remote $ref fetches to these hosts (comma-separated; implies --resolve-remote)\n --allow-private-hosts Permit remote $refs to private/loopback hosts (SSRF guard, off by default)\n --allowed-roots <d> Extra directories a local $ref may resolve into, on top of the schema's own\n (comma-separated; relative to the current directory)\n\nMisc:\n --config <path> JSON config file with the same keys; CLI flags take precedence\n --version, -v Print the CLI version\n --help, -h Print this help\n\nDocs: https://github.com/amritk/mjst/tree/main/packages/cli#readme\n";
|
package/dist/help-text.js
CHANGED
|
@@ -25,7 +25,7 @@ Output:
|
|
|
25
25
|
--message-contracts Also emit @amritk/api channel contracts under contracts/ (--input asyncapi only)
|
|
26
26
|
--discriminator <p> Property naming which message a frame is, for --message-contracts (default: type)
|
|
27
27
|
--build Compile the generated files to .js/.d.ts (implies --import-ext js)
|
|
28
|
-
--force
|
|
28
|
+
--force Deprecated; ignored (generated files always overwrite)
|
|
29
29
|
--import-ext <ext> Extension on generated relative imports: ts (default) or js
|
|
30
30
|
--helpers <mode> Runtime helpers: package or embedded (default: auto-detect from package.json)
|
|
31
31
|
--root-type <name> Root type name for a single --schema run (default: schema title or filename)
|
|
@@ -40,6 +40,9 @@ Validation:
|
|
|
40
40
|
--log-warnings console.warn on input keys not declared in the schema
|
|
41
41
|
--unknown-keys <s> How closed objects are proven free of undeclared keys:
|
|
42
42
|
count-keys (default, fastest on Bun) or count-enumerable (fastest on Node)
|
|
43
|
+
--formats <f> String formats the generated validators enforce: "all", or a
|
|
44
|
+
comma-separated list (e.g. uuid,date-time,email). Off by default,
|
|
45
|
+
which leaves "format" an annotation as JSON Schema reads it.
|
|
43
46
|
|
|
44
47
|
Reference resolution:
|
|
45
48
|
--resolve-remote Fetch http(s) $refs while resolving cross-file/remote refs (off by default)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Ruleset } from '@amritk/lint';
|
|
2
|
+
import type { RulesetDefinition } from '@amritk/lint/types';
|
|
3
|
+
/**
|
|
4
|
+
* Routing a ruleset to the right builder: which names mean a built-in preset,
|
|
5
|
+
* whether a ruleset the CLI loaded off disk names one, and how to build with it.
|
|
6
|
+
* The three live together rather than one per file because they are a single
|
|
7
|
+
* concern — the name table is the whole question — and because the two entry
|
|
8
|
+
* points must agree on it: `--ruleset <name>` and a loaded ruleset's `extends`
|
|
9
|
+
* accept exactly the same preset names.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* The two built-in presets the CLI can build a ruleset with. They are mutually
|
|
13
|
+
* exclusive: each preset only knows how to resolve its *own* name inside
|
|
14
|
+
* `extends`, and each brings a different format registry, so one ruleset cannot
|
|
15
|
+
* be built with both.
|
|
16
|
+
*/
|
|
17
|
+
export type PresetName = 'asyncapi' | 'oas';
|
|
18
|
+
/**
|
|
19
|
+
* Every name that resolves to a built-in preset — as `--ruleset <name>` and
|
|
20
|
+
* inside a ruleset's `extends` — mapped to the preset it names. The aliases
|
|
21
|
+
* mirror what the presets' own `extends` resolution accepts, including the
|
|
22
|
+
* legacy Spectral ones.
|
|
23
|
+
*
|
|
24
|
+
* A Map, not a record: the key comes straight from user input, and a record
|
|
25
|
+
* lookup on `constructor` would find `Object.prototype`'s.
|
|
26
|
+
*/
|
|
27
|
+
export declare const PRESET_RULESET_NAMES: ReadonlyMap<string, PresetName>;
|
|
28
|
+
/**
|
|
29
|
+
* Builds a *runnable* ruleset with a preset's builder. Built rather than handed
|
|
30
|
+
* to `lintDocument` as data, deliberately: a preset brings its own custom
|
|
31
|
+
* functions and format detectors, which a definition cannot carry — as data,
|
|
32
|
+
* every one of its rules would be silently skipped (unknown functions, a
|
|
33
|
+
* `formats` gate matching nothing).
|
|
34
|
+
*
|
|
35
|
+
* With no `definition` this is the bare `--ruleset asyncapi` case: the preset's
|
|
36
|
+
* recommended rules and nothing else. With one, the caller's ruleset is built by
|
|
37
|
+
* the preset, whose `extends` resolution knows the preset names and whose
|
|
38
|
+
* `basePath` keeps the user's relative `extends` and `functions` resolving next
|
|
39
|
+
* to their own file.
|
|
40
|
+
*
|
|
41
|
+
* No `restrictTo` is passed, which matches what the core path does for a
|
|
42
|
+
* discovered or `--ruleset` file today: the CLI treats a ruleset on the local
|
|
43
|
+
* disk as trusted configuration. (`--allowed-roots` fences `$ref` resolution in
|
|
44
|
+
* the *document*, a separate concern.) See the "Trust boundary" section of
|
|
45
|
+
* `@amritk/lint`'s README.
|
|
46
|
+
*/
|
|
47
|
+
export declare const buildPresetRuleset: (preset: PresetName, definition?: RulesetDefinition, basePath?: string) => Promise<Ruleset>;
|
|
48
|
+
/**
|
|
49
|
+
* Decides what `lintDocument` should run for a ruleset just loaded off disk —
|
|
50
|
+
* whether it came from `--ruleset <file>` or `.lint.*` discovery.
|
|
51
|
+
*
|
|
52
|
+
* A ruleset that extends a built-in preset has to be built *here*, by that
|
|
53
|
+
* preset's builder: handed over as a definition, `lintDocument` builds it with
|
|
54
|
+
* the core `createRuleset`, which knows neither the preset names nor the
|
|
55
|
+
* functions and format detectors a preset brings. Anything else stays a
|
|
56
|
+
* definition and takes the core path exactly as it did before.
|
|
57
|
+
*
|
|
58
|
+
* @param basePath - The ruleset file's own directory, so its relative `extends` and `functions` still resolve there.
|
|
59
|
+
* @param label - How to name the ruleset in an error, e.g. its path.
|
|
60
|
+
*/
|
|
61
|
+
export declare const buildLoadedRuleset: (definition: RulesetDefinition, basePath: string, label: string) => Promise<RulesetDefinition | Ruleset>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const PRESET_RULESET_NAMES = /* @__PURE__ */ new Map([
|
|
2
|
+
["asyncapi", "asyncapi"],
|
|
3
|
+
["loupe:asyncapi", "asyncapi"],
|
|
4
|
+
["spectral:asyncapi", "asyncapi"],
|
|
5
|
+
["oas", "oas"],
|
|
6
|
+
["loupe:oas", "oas"],
|
|
7
|
+
["spectral:oas", "oas"]
|
|
8
|
+
]);
|
|
9
|
+
const collectPresets = (definition, into, seen) => {
|
|
10
|
+
if (typeof definition !== "object" || definition === null)
|
|
11
|
+
return;
|
|
12
|
+
if (seen.has(definition))
|
|
13
|
+
return;
|
|
14
|
+
seen.add(definition);
|
|
15
|
+
if (!definition.extends)
|
|
16
|
+
return;
|
|
17
|
+
const entries = Array.isArray(definition.extends) ? definition.extends : [definition.extends];
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
const target = Array.isArray(entry) ? entry[0] : entry;
|
|
20
|
+
if (typeof target === "string") {
|
|
21
|
+
const preset = PRESET_RULESET_NAMES.get(target);
|
|
22
|
+
if (preset && !into.has(preset))
|
|
23
|
+
into.set(preset, target);
|
|
24
|
+
} else {
|
|
25
|
+
collectPresets(target, into, seen);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const findExtendedPreset = (definition, label) => {
|
|
30
|
+
const found = /* @__PURE__ */ new Map();
|
|
31
|
+
collectPresets(definition, found, /* @__PURE__ */ new Set());
|
|
32
|
+
const asyncapi = found.get("asyncapi");
|
|
33
|
+
const oas = found.get("oas");
|
|
34
|
+
if (asyncapi && oas) {
|
|
35
|
+
throw new Error(`Ruleset ${label} extends both built-in presets ("${asyncapi}" and "${oas}"), which cannot be combined: each preset brings its own functions and format detectors, and neither can resolve the other. Extend at most one preset per ruleset, and lint AsyncAPI and OpenAPI documents in separate runs.`);
|
|
36
|
+
}
|
|
37
|
+
return asyncapi ? "asyncapi" : oas ? "oas" : void 0;
|
|
38
|
+
};
|
|
39
|
+
const buildPresetRuleset = async (preset, definition, basePath) => {
|
|
40
|
+
if (preset === "asyncapi") {
|
|
41
|
+
const { createAsyncApiRuleset } = await import("@amritk/lint/rules/asyncapi");
|
|
42
|
+
return createAsyncApiRuleset(definition, basePath);
|
|
43
|
+
}
|
|
44
|
+
const { createOpenApiRuleset } = await import("@amritk/lint/rules/openapi");
|
|
45
|
+
return createOpenApiRuleset(definition, basePath);
|
|
46
|
+
};
|
|
47
|
+
const buildLoadedRuleset = async (definition, basePath, label) => {
|
|
48
|
+
const preset = findExtendedPreset(definition, label);
|
|
49
|
+
return preset ? await buildPresetRuleset(preset, definition, basePath) : definition;
|
|
50
|
+
};
|
|
51
|
+
export {
|
|
52
|
+
PRESET_RULESET_NAMES,
|
|
53
|
+
buildLoadedRuleset,
|
|
54
|
+
buildPresetRuleset
|
|
55
|
+
};
|
package/dist/lint/run.js
CHANGED
|
@@ -4,6 +4,7 @@ import { lintDocument, validateRuleset } from "@amritk/lint";
|
|
|
4
4
|
import { DiagnosticSeverity } from "@amritk/lint/types";
|
|
5
5
|
import fg from "fast-glob";
|
|
6
6
|
import yargs from "yargs";
|
|
7
|
+
import { buildLoadedRuleset, buildPresetRuleset, PRESET_RULESET_NAMES } from "./preset-ruleset.js";
|
|
7
8
|
import { createLintResolver } from "./resolver.js";
|
|
8
9
|
import { discoverRuleset, loadRuleset } from "./ruleset-loader.js";
|
|
9
10
|
const SEVERITY_BY_NAME = {
|
|
@@ -13,16 +14,6 @@ const SEVERITY_BY_NAME = {
|
|
|
13
14
|
hint: DiagnosticSeverity.Hint
|
|
14
15
|
};
|
|
15
16
|
const SEVERITY_LABEL = ["error", "warning", "info", "hint"];
|
|
16
|
-
const buildAsyncApiPreset = async () => (await import("@amritk/lint/rules/asyncapi")).createAsyncApiRuleset();
|
|
17
|
-
const buildOpenApiPreset = async () => (await import("@amritk/lint/rules/openapi")).createOpenApiRuleset();
|
|
18
|
-
const PRESET_RULESETS = /* @__PURE__ */ new Map([
|
|
19
|
-
["asyncapi", buildAsyncApiPreset],
|
|
20
|
-
["loupe:asyncapi", buildAsyncApiPreset],
|
|
21
|
-
["spectral:asyncapi", buildAsyncApiPreset],
|
|
22
|
-
["oas", buildOpenApiPreset],
|
|
23
|
-
["loupe:oas", buildOpenApiPreset],
|
|
24
|
-
["spectral:oas", buildOpenApiPreset]
|
|
25
|
-
]);
|
|
26
17
|
const formatReport = (findings) => {
|
|
27
18
|
if (findings.length === 0)
|
|
28
19
|
return "No problems found\n";
|
|
@@ -136,19 +127,20 @@ Run \`mjst lint --help\` for the supported flags.
|
|
|
136
127
|
return void 0;
|
|
137
128
|
const definition = await loadRuleset(discovered);
|
|
138
129
|
reportRulesetProblems(definition, discovered);
|
|
139
|
-
|
|
130
|
+
const basePath = dirname(discovered);
|
|
131
|
+
return { definition: await buildLoadedRuleset(definition, basePath, discovered), basePath };
|
|
140
132
|
};
|
|
141
133
|
let rulesetDefinition;
|
|
142
134
|
let rulesetBasePath;
|
|
143
135
|
if (parsed.ruleset) {
|
|
144
|
-
const preset =
|
|
136
|
+
const preset = PRESET_RULESET_NAMES.get(parsed.ruleset);
|
|
145
137
|
if (preset) {
|
|
146
|
-
rulesetDefinition = await preset
|
|
138
|
+
rulesetDefinition = await buildPresetRuleset(preset);
|
|
147
139
|
} else {
|
|
148
140
|
const definition = await loadRuleset(parsed.ruleset);
|
|
149
|
-
rulesetDefinition = definition;
|
|
150
141
|
rulesetBasePath = dirname(isAbsolute(parsed.ruleset) ? parsed.ruleset : resolve(process.cwd(), parsed.ruleset));
|
|
151
142
|
reportRulesetProblems(definition, parsed.ruleset);
|
|
143
|
+
rulesetDefinition = await buildLoadedRuleset(definition, rulesetBasePath, parsed.ruleset);
|
|
152
144
|
}
|
|
153
145
|
}
|
|
154
146
|
const documents = parsed.documents ?? [];
|
package/dist/load-config.d.ts
CHANGED
|
@@ -1,10 +1,2 @@
|
|
|
1
1
|
import type { CliConfig } from './cli-config.js';
|
|
2
|
-
/**
|
|
3
|
-
* Loads a JSON config file and returns the relevant CLI config properties.
|
|
4
|
-
* The config file should have the same keys as the CLI flags (schema, outDir).
|
|
5
|
-
*
|
|
6
|
-
* Every key is validated up front (see {@link validateConfig}), so the `typeof`
|
|
7
|
-
* guards below are only here to narrow the types for TypeScript — by the time we
|
|
8
|
-
* reach them, nothing can fail them.
|
|
9
|
-
*/
|
|
10
2
|
export declare const loadConfig: (configPath: string) => Promise<Partial<CliConfig>>;
|
package/dist/load-config.js
CHANGED
|
@@ -7,6 +7,7 @@ const isSourceFormat = (value) => typeof value === "string" && SOURCE_FORMATS.in
|
|
|
7
7
|
const isHelpersMode = (value) => value === "package" || value === "embedded";
|
|
8
8
|
const isImportExt = (value) => value === "js" || value === "ts";
|
|
9
9
|
const isStringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
10
|
+
const isFormatsOption = (value) => value === "all" || Array.isArray(value) && value.every((name) => typeof name === "string");
|
|
10
11
|
const loadConfig = async (configPath) => {
|
|
11
12
|
const absolutePath = resolve(configPath);
|
|
12
13
|
const raw = await readFile(absolutePath, "utf-8").catch((error) => {
|
|
@@ -40,6 +41,7 @@ const loadConfig = async (configPath) => {
|
|
|
40
41
|
...typeof obj["caseInsensitive"] === "boolean" && { caseInsensitive: obj["caseInsensitive"] },
|
|
41
42
|
...typeof obj["readonly"] === "boolean" && { readonly: obj["readonly"] },
|
|
42
43
|
...isUnknownKeysStrategy(obj["unknownKeys"]) && { unknownKeys: obj["unknownKeys"] },
|
|
44
|
+
...isFormatsOption(obj["formats"]) && { formats: obj["formats"] },
|
|
43
45
|
...isHelpersMode(obj["helpers"]) && { helpers: obj["helpers"] },
|
|
44
46
|
...isImportExt(obj["importExt"]) && { importExt: obj["importExt"] },
|
|
45
47
|
...typeof obj["rootType"] === "string" && { rootType: obj["rootType"] },
|
package/dist/parse-cli-args.js
CHANGED
|
@@ -28,7 +28,8 @@ const VALUE_KEYS = /* @__PURE__ */ new Set([
|
|
|
28
28
|
"typeSuffix",
|
|
29
29
|
"importExt",
|
|
30
30
|
"rootType",
|
|
31
|
-
"unknownKeys"
|
|
31
|
+
"unknownKeys",
|
|
32
|
+
"formats"
|
|
32
33
|
]);
|
|
33
34
|
const EXTERNAL_VALUE_KEYS = /* @__PURE__ */ new Set(["config"]);
|
|
34
35
|
const toCamelCase = (key) => key.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
@@ -103,6 +104,10 @@ const assignValue = (config, key, value) => {
|
|
|
103
104
|
config.importExt = parsed;
|
|
104
105
|
return true;
|
|
105
106
|
}
|
|
107
|
+
case "formats": {
|
|
108
|
+
config.formats = value === "all" ? "all" : value.split(",").map((name) => name.trim()).filter((name) => name !== "");
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
106
111
|
case "unknownKeys": {
|
|
107
112
|
if (!isUnknownKeysStrategy(value)) {
|
|
108
113
|
throw new Error(`Invalid --unknown-keys value "${value}". Expected one of: ${UNKNOWN_KEYS_STRATEGIES.join(", ")}.`);
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The JSON type each config key accepts, mirroring `config.schema.json`.
|
|
3
|
-
* `boolean|string` is `banner`'s `"type": ["boolean", "string"]
|
|
3
|
+
* `boolean|string` is `banner`'s `"type": ["boolean", "string"]`, and
|
|
4
|
+
* `string|string[]` is `formats`' `"type": ["string", "array"]` — a union the
|
|
5
|
+
* label spells by its element type rather than by the bare word `array`, since
|
|
6
|
+
* "expected string|array" tells a reader less than "expected string|string[]".
|
|
4
7
|
*/
|
|
5
|
-
type ConfigValueType = 'string' | 'boolean' | 'boolean|string' | 'string[]';
|
|
8
|
+
type ConfigValueType = 'string' | 'boolean' | 'boolean|string' | 'string[]' | 'string|string[]';
|
|
6
9
|
/** One key's contract: its JSON type, plus the closed value set when it has one. */
|
|
7
10
|
type ConfigKeySpec = {
|
|
8
11
|
readonly type: ConfigValueType;
|
package/dist/validate-config.js
CHANGED
|
@@ -20,6 +20,7 @@ const CONFIG_KEYS = {
|
|
|
20
20
|
caseInsensitive: { type: "boolean" },
|
|
21
21
|
readonly: { type: "boolean" },
|
|
22
22
|
unknownKeys: { type: "string", enum: [...UNKNOWN_KEYS_STRATEGIES] },
|
|
23
|
+
formats: { type: "string|string[]" },
|
|
23
24
|
helpers: { type: "string", enum: ["package", "embedded"] },
|
|
24
25
|
typeSuffix: { type: "string" },
|
|
25
26
|
banner: { type: "boolean|string" },
|
|
@@ -48,6 +49,8 @@ const matchesType = (value, type) => {
|
|
|
48
49
|
return typeof value === "boolean" || typeof value === "string";
|
|
49
50
|
case "string[]":
|
|
50
51
|
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
52
|
+
case "string|string[]":
|
|
53
|
+
return typeof value === "string" || Array.isArray(value) && value.every((e) => typeof e === "string");
|
|
51
54
|
}
|
|
52
55
|
};
|
|
53
56
|
const validateConfig = (parsed, configPath) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amritk/mjst",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"description": "Generate TypeScript parsers and type definitions from JSON Schemas.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -49,14 +49,14 @@
|
|
|
49
49
|
"./package.json": "./package.json"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@amritk/adapters": "^0.6.
|
|
53
|
-
"@amritk/api": "^0.16.
|
|
54
|
-
"@amritk/asyncapi": "^0.
|
|
55
|
-
"@amritk/generate-examples": "^0.8.
|
|
56
|
-
"@amritk/generate-parsers": "^0.
|
|
57
|
-
"@amritk/generate-validators": "^0.
|
|
58
|
-
"@amritk/helpers": "^0.
|
|
59
|
-
"@amritk/lint": "^0.
|
|
52
|
+
"@amritk/adapters": "^0.6.2",
|
|
53
|
+
"@amritk/api": "^0.16.4",
|
|
54
|
+
"@amritk/asyncapi": "^0.3.0",
|
|
55
|
+
"@amritk/generate-examples": "^0.8.4",
|
|
56
|
+
"@amritk/generate-parsers": "^0.23.0",
|
|
57
|
+
"@amritk/generate-validators": "^0.17.0",
|
|
58
|
+
"@amritk/helpers": "^0.21.0",
|
|
59
|
+
"@amritk/lint": "^0.6.0",
|
|
60
60
|
"@amritk/resolve-refs": "^0.7.1",
|
|
61
61
|
"@amritk/yaml": "^0.7.2",
|
|
62
62
|
"fast-glob": "^3.3.2",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"yargs": "^17.7.2"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@amritk/generate-markdown": "^0.
|
|
67
|
+
"@amritk/generate-markdown": "^0.7.0",
|
|
68
68
|
"@types/yargs": "^17.0.33"
|
|
69
69
|
}
|
|
70
70
|
}
|