@scalar/cli 2.0.1 → 2.5.1
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 +68 -24
- package/chunks/action-37EV4UHW.js +125 -0
- package/chunks/action-4XI7XJR4.js +204 -0
- package/chunks/action-5IU77OII.js +60 -0
- package/chunks/action-B3KKREWQ.js +64 -0
- package/chunks/action-CH24QGTE.js +86 -0
- package/chunks/action-F3UX5E3M.js +522 -0
- package/chunks/action-FDB7NEOK.js +81 -0
- package/chunks/action-FIXBOJEW.js +244 -0
- package/chunks/action-G26LSVZ7.js +40 -0
- package/chunks/action-H3RTILLM.js +46 -0
- package/chunks/action-HGBBV353.js +86 -0
- package/chunks/action-IUE4IOWO.js +2142 -0
- package/chunks/action-JZLZ7ZAD.js +110 -0
- package/chunks/action-LA6KVAXQ.js +374 -0
- package/chunks/action-M7RQKBSB.js +169 -0
- package/chunks/action-MSLBC2SO.js +92 -0
- package/chunks/action-NVSZT2ZD.js +37 -0
- package/chunks/action-OGQSTRMX.js +37 -0
- package/chunks/action-PAGJ5PWC.js +60 -0
- package/chunks/action-QE2ZQQX7.js +250 -0
- package/chunks/action-QPUSPD5M.js +54 -0
- package/chunks/action-R7IMFHQ5.js +147 -0
- package/chunks/action-SH4UUXPL.js +60 -0
- package/chunks/action-SNLCIBQC.js +84 -0
- package/chunks/action-SQG3JAII.js +150 -0
- package/chunks/action-UZQJNYK4.js +18 -0
- package/chunks/action-VC4DCVST.js +68 -0
- package/chunks/action-VTVFY2MP.js +181 -0
- package/chunks/action-WFWYGY7O.js +67 -0
- package/chunks/action-XMNX5ZYT.js +197 -0
- package/chunks/agent-HCQRMHQ5.js +132 -0
- package/chunks/asyncapi-QM76O55R.js +105 -0
- package/chunks/build.action-P7FCIMYU.js +108 -0
- package/chunks/chunk-24WAOKGG.js +105 -0
- package/chunks/chunk-3L6DLIXJ.js +25530 -0
- package/chunks/chunk-3MZYUBJ6.js +49 -0
- package/chunks/chunk-3ZJYGGAA.js +30 -0
- package/chunks/chunk-4NHMAG6F.js +21 -0
- package/chunks/chunk-4ORL4MST.js +16 -0
- package/chunks/chunk-4ZDQXWBT.js +26 -0
- package/chunks/chunk-6ZMT63IV.js +19 -0
- package/chunks/chunk-7AGLC7WV.js +107 -0
- package/chunks/chunk-AEFPCC4U.js +16 -0
- package/chunks/chunk-AO3F5XWR.js +3147 -0
- package/chunks/chunk-B2MHTD3R.js +90 -0
- package/chunks/chunk-CISTON3A.js +153 -0
- package/chunks/chunk-COBPBRQF.js +25 -0
- package/chunks/chunk-F467BYYR.js +568 -0
- package/chunks/chunk-GSGZHE26.js +352 -0
- package/chunks/chunk-HCPN3KNF.js +637 -0
- package/chunks/chunk-HPL3ZZ2P.js +1726 -0
- package/chunks/chunk-IKT5F47M.js +17344 -0
- package/chunks/chunk-JFIXNSPP.js +26 -0
- package/chunks/chunk-K4DTP5TV.js +32 -0
- package/chunks/chunk-K74E42RV.js +7311 -0
- package/chunks/chunk-KHDYYVYF.js +16 -0
- package/chunks/chunk-LFU5ZUAP.js +350 -0
- package/chunks/chunk-M37TP6U2.js +445 -0
- package/chunks/chunk-OQKDBLOZ.js +741 -0
- package/chunks/chunk-P7H7GY5A.js +14 -0
- package/chunks/chunk-PBXZN65A.js +63911 -0
- package/chunks/chunk-PT5TI77I.js +34 -0
- package/chunks/chunk-Q7DOQHZN.js +404 -0
- package/chunks/chunk-T5HJUAWB.js +242 -0
- package/chunks/chunk-T7B6WNZC.js +18 -0
- package/chunks/chunk-UGGNHILG.js +38 -0
- package/chunks/chunk-VNYE4R7N.js +499 -0
- package/chunks/chunk-X5T526CE.js +23 -0
- package/chunks/chunk-XCSR4RIT.js +210 -0
- package/chunks/chunk-Z2KMGFE6.js +295 -0
- package/chunks/create.action-HDD2WUON.js +108 -0
- package/chunks/delete.action-7GOZY7ID.js +88 -0
- package/chunks/delete.action-VE66JFDS.js +96 -0
- package/chunks/get.action-2745EB4N.js +86 -0
- package/chunks/list.action-3VTXQJRA.js +116 -0
- package/chunks/list.action-4QDCZLSZ.js +95 -0
- package/chunks/publish.action-ULQLZKWU.js +190 -0
- package/chunks/update.action-6QEFP7NA.js +95 -0
- package/chunks/update.action-OROQSP2S.js +101 -0
- package/docs.html +352 -250
- package/index.js +664 -99064
- package/package.json +17 -11
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { createRequire as $$cR } from "node:module"; const require = $$cR(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
getProjectDeployments
|
|
4
|
+
} from "./chunk-PT5TI77I.js";
|
|
5
|
+
import {
|
|
6
|
+
resolveProject
|
|
7
|
+
} from "./chunk-T7B6WNZC.js";
|
|
8
|
+
import {
|
|
9
|
+
formatAbsoluteTime
|
|
10
|
+
} from "./chunk-AEFPCC4U.js";
|
|
11
|
+
import {
|
|
12
|
+
apiService
|
|
13
|
+
} from "./chunk-AO3F5XWR.js";
|
|
14
|
+
import "./chunk-F467BYYR.js";
|
|
15
|
+
import "./chunk-Z2KMGFE6.js";
|
|
16
|
+
import "./chunk-HCPN3KNF.js";
|
|
17
|
+
import "./chunk-B2MHTD3R.js";
|
|
18
|
+
import "./chunk-3L6DLIXJ.js";
|
|
19
|
+
import "./chunk-P7H7GY5A.js";
|
|
20
|
+
import "./chunk-HPL3ZZ2P.js";
|
|
21
|
+
import {
|
|
22
|
+
getAuthData
|
|
23
|
+
} from "./chunk-M37TP6U2.js";
|
|
24
|
+
import "./chunk-4ZDQXWBT.js";
|
|
25
|
+
import "./chunk-VNYE4R7N.js";
|
|
26
|
+
import "./chunk-OQKDBLOZ.js";
|
|
27
|
+
import "./chunk-K74E42RV.js";
|
|
28
|
+
import "./chunk-CISTON3A.js";
|
|
29
|
+
import "./chunk-Q7DOQHZN.js";
|
|
30
|
+
import "./chunk-4ORL4MST.js";
|
|
31
|
+
import {
|
|
32
|
+
output,
|
|
33
|
+
printTable
|
|
34
|
+
} from "./chunk-T5HJUAWB.js";
|
|
35
|
+
import "./chunk-GSGZHE26.js";
|
|
36
|
+
import {
|
|
37
|
+
external_exports,
|
|
38
|
+
slugSchema
|
|
39
|
+
} from "./chunk-IKT5F47M.js";
|
|
40
|
+
import "./chunk-3MZYUBJ6.js";
|
|
41
|
+
|
|
42
|
+
// src/domains/project/deployments/list/action.ts
|
|
43
|
+
import as from "ansis";
|
|
44
|
+
function colorStatus(status) {
|
|
45
|
+
switch (status) {
|
|
46
|
+
case "deployed":
|
|
47
|
+
return as.green(status);
|
|
48
|
+
case "error":
|
|
49
|
+
case "cancelled":
|
|
50
|
+
return as.red(status);
|
|
51
|
+
case "pending":
|
|
52
|
+
case "building":
|
|
53
|
+
return as.yellow(status);
|
|
54
|
+
default:
|
|
55
|
+
return as.dim(status);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function listAction(args) {
|
|
59
|
+
const argsParseResult = external_exports.object({ slug: slugSchema.optional() }).safeParse(args);
|
|
60
|
+
if (argsParseResult.error) {
|
|
61
|
+
return output.error().title("Invalid Arguments").message(argsParseResult.error.issues[0].message).exit("error");
|
|
62
|
+
}
|
|
63
|
+
const { slug } = argsParseResult.data;
|
|
64
|
+
if (!slug) {
|
|
65
|
+
return output.error().title("Invalid argument").message("Slug is required. Try passing --slug flag.").exit("error");
|
|
66
|
+
}
|
|
67
|
+
const apiClient = await apiService();
|
|
68
|
+
const auth = await getAuthData();
|
|
69
|
+
auth.addEventListener((state) => Object.assign(auth, state));
|
|
70
|
+
const resolved = await resolveProject(slug, apiClient);
|
|
71
|
+
if (resolved.kind === "not-found") {
|
|
72
|
+
return output.error().title("Project not found").message(`No project with slug "${slug}" was found for your team.`).exit("error");
|
|
73
|
+
}
|
|
74
|
+
const { project } = resolved;
|
|
75
|
+
const activeUid = project.activeDeployment?.uid ?? null;
|
|
76
|
+
const deploymentsResult = await getProjectDeployments({
|
|
77
|
+
teamUid: auth.teamUid,
|
|
78
|
+
projectUid: project.uid
|
|
79
|
+
});
|
|
80
|
+
if (!deploymentsResult.success) {
|
|
81
|
+
return output.error().title("Could not load deployment history").message(deploymentsResult.error).exit("error");
|
|
82
|
+
}
|
|
83
|
+
if (deploymentsResult.deployments.length === 0) {
|
|
84
|
+
output.info().title(`No deployments found for project "${slug}".`).print();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
printTable(
|
|
88
|
+
[
|
|
89
|
+
{ name: "current", title: " ", alignment: "center" },
|
|
90
|
+
{ name: "id", title: "Build ID", alignment: "left" },
|
|
91
|
+
{ name: "status", title: "Status", alignment: "left" },
|
|
92
|
+
{ name: "deployed", title: "Deployed", alignment: "left" },
|
|
93
|
+
{ name: "commit", title: "Commit", alignment: "left" }
|
|
94
|
+
],
|
|
95
|
+
deploymentsResult.deployments.map((record) => {
|
|
96
|
+
const isLive = record.uid === activeUid;
|
|
97
|
+
const deployedAt = record.deployedAt ?? (record.status === "deployed" ? record.createdAt : null);
|
|
98
|
+
return {
|
|
99
|
+
current: isLive ? as.green("\u279C") : " ",
|
|
100
|
+
id: isLive ? as.green(record.uid) : record.uid,
|
|
101
|
+
status: colorStatus(record.status),
|
|
102
|
+
deployed: deployedAt ? formatAbsoluteTime(deployedAt * 1e3) : as.dim("\u2014"),
|
|
103
|
+
commit: record.commitSha ? record.commitSha.slice(0, 7) : as.dim("\u2014")
|
|
104
|
+
};
|
|
105
|
+
})
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
export {
|
|
109
|
+
listAction
|
|
110
|
+
};
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { createRequire as $$cR } from "node:module"; const require = $$cR(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
getFileOrUrl,
|
|
4
|
+
isAsyncApiContent
|
|
5
|
+
} from "./chunk-24WAOKGG.js";
|
|
6
|
+
import {
|
|
7
|
+
err,
|
|
8
|
+
ok
|
|
9
|
+
} from "./chunk-P7H7GY5A.js";
|
|
10
|
+
import {
|
|
11
|
+
require_dist
|
|
12
|
+
} from "./chunk-K74E42RV.js";
|
|
13
|
+
import "./chunk-CISTON3A.js";
|
|
14
|
+
import "./chunk-Q7DOQHZN.js";
|
|
15
|
+
import "./chunk-4ORL4MST.js";
|
|
16
|
+
import {
|
|
17
|
+
output
|
|
18
|
+
} from "./chunk-T5HJUAWB.js";
|
|
19
|
+
import "./chunk-GSGZHE26.js";
|
|
20
|
+
import "./chunk-IKT5F47M.js";
|
|
21
|
+
import {
|
|
22
|
+
__toESM
|
|
23
|
+
} from "./chunk-3MZYUBJ6.js";
|
|
24
|
+
|
|
25
|
+
// src/domains/document/lint/action.ts
|
|
26
|
+
import as from "ansis";
|
|
27
|
+
|
|
28
|
+
// ../../packages/api-document-lint/dist/constants.js
|
|
29
|
+
var DEFAULT_RULESET = `extends: spectral:oas
|
|
30
|
+
rules: {}`;
|
|
31
|
+
var ASYNCAPI_RULESET = `extends: spectral:asyncapi
|
|
32
|
+
rules: {}`;
|
|
33
|
+
|
|
34
|
+
// ../../packages/api-document-lint/dist/default-ruleset.js
|
|
35
|
+
function isAsyncApiContent2(content) {
|
|
36
|
+
const head = content.slice(0, 500);
|
|
37
|
+
if (head.includes('"asyncapi"')) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
return head.split("\n").some((line) => /^asyncapi\s*:/.test(line.trimStart()));
|
|
41
|
+
}
|
|
42
|
+
function defaultRulesetFor(content) {
|
|
43
|
+
return isAsyncApiContent2(content) ? ASYNCAPI_RULESET : DEFAULT_RULESET;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ../../packages/api-document-lint/dist/run-spectral.js
|
|
47
|
+
import spectralCore from "@stoplight/spectral-core";
|
|
48
|
+
import { bundleAndLoadRuleset } from "@stoplight/spectral-ruleset-bundler/with-loader";
|
|
49
|
+
import "@stoplight/spectral-rulesets";
|
|
50
|
+
var { Spectral } = spectralCore;
|
|
51
|
+
async function runSpectral(input) {
|
|
52
|
+
const rulesetSource = input.ruleset && input.ruleset.trim().length > 0 ? input.ruleset : defaultRulesetFor(input.document);
|
|
53
|
+
const ruleset = await loadRuleset(rulesetSource);
|
|
54
|
+
if (!ruleset.ok) {
|
|
55
|
+
return ruleset;
|
|
56
|
+
}
|
|
57
|
+
const spectral = new Spectral();
|
|
58
|
+
spectral.setRuleset(ruleset.data);
|
|
59
|
+
const diagnostics = await spectral.run(input.document).catch((error) => error instanceof Error ? error : new Error(String(error)));
|
|
60
|
+
if (diagnostics instanceof Error) {
|
|
61
|
+
return err(`Spectral failed to lint the document \u2014 ${diagnostics.message}`);
|
|
62
|
+
}
|
|
63
|
+
return ok(diagnostics);
|
|
64
|
+
}
|
|
65
|
+
async function loadRuleset(source) {
|
|
66
|
+
const ruleset = await bundleAndLoadRuleset("/.spectral.yaml", {
|
|
67
|
+
fs: {
|
|
68
|
+
promises: {
|
|
69
|
+
// @ts-expect-error The loader only ever reads our single virtual file.
|
|
70
|
+
async readFile() {
|
|
71
|
+
return source;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
format: "esm"
|
|
76
|
+
}).catch((error) => error instanceof Error ? error : new Error(String(error)));
|
|
77
|
+
if (ruleset instanceof Error) {
|
|
78
|
+
return err(`Failed to load ruleset \u2014 ${ruleset.message}`);
|
|
79
|
+
}
|
|
80
|
+
return ok(ruleset);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ../../packages/api-document-lint/dist/run-vacuum.js
|
|
84
|
+
import { execFile } from "node:child_process";
|
|
85
|
+
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
86
|
+
import { tmpdir } from "node:os";
|
|
87
|
+
import { join as join2 } from "node:path";
|
|
88
|
+
import { promisify } from "node:util";
|
|
89
|
+
|
|
90
|
+
// ../../packages/api-document-lint/dist/normalize-diagnostics.js
|
|
91
|
+
var EMPTY_RANGE = {
|
|
92
|
+
start: { line: 0, character: 0 },
|
|
93
|
+
end: { line: 0, character: 0 }
|
|
94
|
+
};
|
|
95
|
+
function normalizeDiagnostics(raw) {
|
|
96
|
+
if (!Array.isArray(raw)) {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
return raw.filter(isObject).map((item) => {
|
|
100
|
+
const source = item.source;
|
|
101
|
+
return {
|
|
102
|
+
code: isCode(item.code) ? item.code : "",
|
|
103
|
+
message: typeof item.message === "string" ? item.message : "",
|
|
104
|
+
severity: normalizeSeverity(item.severity),
|
|
105
|
+
path: Array.isArray(item.path) ? item.path.filter(isSegment) : [],
|
|
106
|
+
range: normalizeRange(item.range),
|
|
107
|
+
...typeof source === "string" ? { source } : {}
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
function isObject(value) {
|
|
112
|
+
return typeof value === "object" && value !== null;
|
|
113
|
+
}
|
|
114
|
+
function isCode(value) {
|
|
115
|
+
return typeof value === "string" || typeof value === "number";
|
|
116
|
+
}
|
|
117
|
+
function isSegment(value) {
|
|
118
|
+
return typeof value === "string" || typeof value === "number";
|
|
119
|
+
}
|
|
120
|
+
function normalizeRange(range) {
|
|
121
|
+
if (!isObject(range)) {
|
|
122
|
+
return EMPTY_RANGE;
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
start: normalizePosition(range.start),
|
|
126
|
+
end: normalizePosition(range.end)
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function normalizePosition(position) {
|
|
130
|
+
if (!isObject(position)) {
|
|
131
|
+
return { line: 0, character: 0 };
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
line: toCoordinate(position.line),
|
|
135
|
+
character: toCoordinate(position.character)
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function toCoordinate(value) {
|
|
139
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : 0;
|
|
140
|
+
}
|
|
141
|
+
function normalizeSeverity(severity) {
|
|
142
|
+
return severity === 1 || severity === 2 || severity === 3 ? severity : 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ../../packages/api-document-lint/dist/resolve-binary.js
|
|
146
|
+
import { statSync } from "node:fs";
|
|
147
|
+
import { createRequire } from "node:module";
|
|
148
|
+
import { dirname, join } from "node:path";
|
|
149
|
+
var binaryName = process.platform === "win32" ? "vacuum.exe" : "vacuum";
|
|
150
|
+
function resolveVacuumBinary(override) {
|
|
151
|
+
const explicit = override ?? process.env.VACUUM_BINARY;
|
|
152
|
+
if (explicit) {
|
|
153
|
+
return isFile(explicit) ? ok(explicit) : err(`vacuum binary not found at ${explicit}`);
|
|
154
|
+
}
|
|
155
|
+
const packaged = resolvePackagedBinary();
|
|
156
|
+
if (packaged) {
|
|
157
|
+
return ok(packaged);
|
|
158
|
+
}
|
|
159
|
+
return ok("vacuum");
|
|
160
|
+
}
|
|
161
|
+
function resolvePackagedBinary() {
|
|
162
|
+
try {
|
|
163
|
+
const require2 = createRequire(import.meta.url);
|
|
164
|
+
const packageJsonPath = require2.resolve("@quobix/vacuum/package.json");
|
|
165
|
+
const candidate = join(dirname(packageJsonPath), "bin", binaryName);
|
|
166
|
+
return isFile(candidate) ? candidate : null;
|
|
167
|
+
} catch {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function isFile(path) {
|
|
172
|
+
try {
|
|
173
|
+
return statSync(path, { throwIfNoEntry: false })?.isFile() ?? false;
|
|
174
|
+
} catch {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ../../packages/api-document-lint/dist/run-vacuum.js
|
|
180
|
+
var execFileAsync = promisify(execFile);
|
|
181
|
+
var MAX_BUFFER = 64 * 1024 * 1024;
|
|
182
|
+
var TIMEOUT_MS = 6e4;
|
|
183
|
+
async function runVacuum(input, options = {}) {
|
|
184
|
+
if (input.document.trim().length === 0) {
|
|
185
|
+
return ok([]);
|
|
186
|
+
}
|
|
187
|
+
const binary = resolveVacuumBinary(options.binaryPath);
|
|
188
|
+
if (!binary.ok) {
|
|
189
|
+
return binary;
|
|
190
|
+
}
|
|
191
|
+
const directory = await mkdtemp(join2(tmpdir(), "scalar-lint-")).catch(() => null);
|
|
192
|
+
if (directory === null) {
|
|
193
|
+
return err("vacuum lint failed \u2014 could not create a temporary directory");
|
|
194
|
+
}
|
|
195
|
+
const documentPath = join2(directory, "document.yaml");
|
|
196
|
+
const reportPath = join2(directory, "report.json");
|
|
197
|
+
try {
|
|
198
|
+
const wroteDocument = await writeFile(documentPath, input.document, "utf8").then(() => true).catch(() => false);
|
|
199
|
+
if (!wroteDocument) {
|
|
200
|
+
return err("vacuum lint failed \u2014 could not write the document to a temporary file");
|
|
201
|
+
}
|
|
202
|
+
const args = [
|
|
203
|
+
"spectral-report",
|
|
204
|
+
"--no-style",
|
|
205
|
+
"--no-update-check",
|
|
206
|
+
"--skip-check",
|
|
207
|
+
// Match Spectral's working-directory base for document strings.
|
|
208
|
+
"--base",
|
|
209
|
+
process.cwd()
|
|
210
|
+
];
|
|
211
|
+
if (input.ruleset && input.ruleset.trim().length > 0) {
|
|
212
|
+
const rulesetPath = join2(directory, "ruleset.yaml");
|
|
213
|
+
const wroteRuleset = await writeFile(rulesetPath, input.ruleset, "utf8").then(() => true).catch(() => false);
|
|
214
|
+
if (!wroteRuleset) {
|
|
215
|
+
return err("vacuum lint failed \u2014 could not write the ruleset to a temporary file");
|
|
216
|
+
}
|
|
217
|
+
args.push("--ruleset", rulesetPath);
|
|
218
|
+
}
|
|
219
|
+
args.push(documentPath, reportPath);
|
|
220
|
+
const failure = await execFileAsync(binary.data, args, {
|
|
221
|
+
maxBuffer: MAX_BUFFER,
|
|
222
|
+
timeout: TIMEOUT_MS
|
|
223
|
+
}).then(() => null).catch((error) => error);
|
|
224
|
+
const report = await readFile(reportPath, "utf8").catch(() => null);
|
|
225
|
+
if (report === null) {
|
|
226
|
+
if (failure === null) {
|
|
227
|
+
return err("vacuum ran but its report could not be read");
|
|
228
|
+
}
|
|
229
|
+
return err(`vacuum failed to lint the document \u2014 ${describeFailure(failure)}`);
|
|
230
|
+
}
|
|
231
|
+
const parsed = parseReport(report);
|
|
232
|
+
if (!parsed.ok) {
|
|
233
|
+
return parsed;
|
|
234
|
+
}
|
|
235
|
+
return ok(normalizeDiagnostics(parsed.data));
|
|
236
|
+
} finally {
|
|
237
|
+
await rm(directory, { recursive: true, force: true }).catch(() => void 0);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function describeFailure(failure) {
|
|
241
|
+
if (failure && typeof failure === "object") {
|
|
242
|
+
const stderr = failure.stderr;
|
|
243
|
+
if (typeof stderr === "string" && stderr.trim().length > 0) {
|
|
244
|
+
return stderr.trim();
|
|
245
|
+
}
|
|
246
|
+
if (failure instanceof Error) {
|
|
247
|
+
return failure.message;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return "no report was written";
|
|
251
|
+
}
|
|
252
|
+
function parseReport(report) {
|
|
253
|
+
try {
|
|
254
|
+
const parsed = JSON.parse(report);
|
|
255
|
+
if (!Array.isArray(parsed)) {
|
|
256
|
+
return err("vacuum produced a report in an unexpected shape");
|
|
257
|
+
}
|
|
258
|
+
return ok(parsed);
|
|
259
|
+
} catch {
|
|
260
|
+
return err("vacuum produced an unreadable report");
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// ../../packages/api-document-lint/dist/select-engine.js
|
|
265
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
266
|
+
function selectEngine(ruleset) {
|
|
267
|
+
if (!ruleset || ruleset.trim().length === 0) {
|
|
268
|
+
return "vacuum";
|
|
269
|
+
}
|
|
270
|
+
const parsed = parseRuleset(ruleset);
|
|
271
|
+
if (parsed === null) {
|
|
272
|
+
return "spectral";
|
|
273
|
+
}
|
|
274
|
+
if (hasCustomFunctions(parsed) || hasRuleCustomizations(parsed) || extendsUninspectableRuleset(parsed) || overridesRequireSpectral(parsed)) {
|
|
275
|
+
return "spectral";
|
|
276
|
+
}
|
|
277
|
+
return "vacuum";
|
|
278
|
+
}
|
|
279
|
+
function overridesRequireSpectral(ruleset) {
|
|
280
|
+
const overrides = ruleset.overrides;
|
|
281
|
+
if (!Array.isArray(overrides)) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
return overrides.some((entry) => isRecord(entry) && (hasCustomFunctions(entry) || hasRuleCustomizations(entry) || extendsUninspectableRuleset(entry)));
|
|
285
|
+
}
|
|
286
|
+
function hasRuleCustomizations(ruleset) {
|
|
287
|
+
return ruleset.rules !== void 0 && (!isRecord(ruleset.rules) || Object.keys(ruleset.rules).length > 0);
|
|
288
|
+
}
|
|
289
|
+
function isRecord(value) {
|
|
290
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
291
|
+
}
|
|
292
|
+
function parseRuleset(ruleset) {
|
|
293
|
+
try {
|
|
294
|
+
const value = (0, import_yaml.parse)(ruleset);
|
|
295
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
296
|
+
return value;
|
|
297
|
+
}
|
|
298
|
+
return null;
|
|
299
|
+
} catch {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function hasCustomFunctions(ruleset) {
|
|
304
|
+
const functions = ruleset.functions;
|
|
305
|
+
if (Array.isArray(functions) && functions.length > 0) {
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
return typeof ruleset.functionsDir === "string" && ruleset.functionsDir.length > 0;
|
|
309
|
+
}
|
|
310
|
+
function extendsUninspectableRuleset(ruleset) {
|
|
311
|
+
const extended = ruleset.extends;
|
|
312
|
+
if (extended === void 0) {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
const entries = Array.isArray(extended) ? extended : [extended];
|
|
316
|
+
return entries.some((entry) => !isBuiltInRuleset(entry));
|
|
317
|
+
}
|
|
318
|
+
function isBuiltInRuleset(entry) {
|
|
319
|
+
const source = Array.isArray(entry) ? entry[0] : entry;
|
|
320
|
+
return source === "spectral:oas" || source === "spectral:asyncapi";
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// ../../packages/api-document-lint/dist/lint.js
|
|
324
|
+
async function lint(input, options = {}) {
|
|
325
|
+
const ruleset = input.ruleset && input.ruleset.trim().length > 0 ? input.ruleset : defaultRulesetFor(input.document);
|
|
326
|
+
const resolved = { document: input.document, ruleset };
|
|
327
|
+
const engine = selectEngine(ruleset);
|
|
328
|
+
const diagnostics = engine === "vacuum" ? await runVacuum(resolved, options) : await runSpectral(resolved);
|
|
329
|
+
if (!diagnostics.ok) {
|
|
330
|
+
return diagnostics;
|
|
331
|
+
}
|
|
332
|
+
return ok({ diagnostics: diagnostics.data, engine });
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// src/domains/document/lint/helpers.ts
|
|
336
|
+
var severityToLabel = (severity) => {
|
|
337
|
+
return {
|
|
338
|
+
0: "Error",
|
|
339
|
+
1: "Warning",
|
|
340
|
+
2: "Information",
|
|
341
|
+
3: "Hint"
|
|
342
|
+
}[severity];
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
// src/domains/document/lint/action.ts
|
|
346
|
+
async function lintAction(inputArgument, { rule: ruleArgument }) {
|
|
347
|
+
if (!inputArgument) {
|
|
348
|
+
return output.error().title("Invalid argument").message("Please provide a file path").exit("error");
|
|
349
|
+
}
|
|
350
|
+
const specification = await getFileOrUrl(inputArgument);
|
|
351
|
+
const ruleset = ruleArgument ? await getFileOrUrl(ruleArgument) : isAsyncApiContent(specification) ? ASYNCAPI_RULESET : DEFAULT_RULESET;
|
|
352
|
+
const result = await lint({ document: specification, ruleset });
|
|
353
|
+
if (!result.ok) {
|
|
354
|
+
return output.error().title("Failed to lint the document").message(result.error).exit("error");
|
|
355
|
+
}
|
|
356
|
+
const diagnostics = result.data.diagnostics;
|
|
357
|
+
const hasErrors = diagnostics.some((diagnostic) => diagnostic.severity === 0);
|
|
358
|
+
if (!hasErrors) {
|
|
359
|
+
output.info().message(as.green("\u2714 No issues found!")).print();
|
|
360
|
+
} else {
|
|
361
|
+
output.warn().line(as.red("\u2716 Issues found:")).print();
|
|
362
|
+
}
|
|
363
|
+
for (const diagnostic of diagnostics) {
|
|
364
|
+
output.info().line(`${as.yellow("Rule:")} ${as.bold(String(diagnostic.code))}`).line(`${as.yellow("Message:")} ${diagnostic.message}`).line(`${as.yellow("Severity:")} ${severityToLabel(diagnostic.severity)}`).line(
|
|
365
|
+
`${as.yellow("Location:")} ${diagnostic.range.start.line}:${diagnostic.range.start.character} - ${diagnostic.range.end.line}:${diagnostic.range.end.character}`
|
|
366
|
+
).line(as.gray("---")).print();
|
|
367
|
+
}
|
|
368
|
+
if (hasErrors) {
|
|
369
|
+
output.error().exit("error");
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
export {
|
|
373
|
+
lintAction
|
|
374
|
+
};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { createRequire as $$cR } from "node:module"; const require = $$cR(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
getFileOrUrl,
|
|
4
|
+
isAsyncApiDocument,
|
|
5
|
+
isDocument,
|
|
6
|
+
loadOpenApiDocument,
|
|
7
|
+
printSpecificationBanner,
|
|
8
|
+
safeNormalize
|
|
9
|
+
} from "./chunk-24WAOKGG.js";
|
|
10
|
+
import {
|
|
11
|
+
watchFile
|
|
12
|
+
} from "./chunk-M37TP6U2.js";
|
|
13
|
+
import "./chunk-4ZDQXWBT.js";
|
|
14
|
+
import "./chunk-VNYE4R7N.js";
|
|
15
|
+
import "./chunk-OQKDBLOZ.js";
|
|
16
|
+
import "./chunk-CISTON3A.js";
|
|
17
|
+
import "./chunk-Q7DOQHZN.js";
|
|
18
|
+
import "./chunk-4ORL4MST.js";
|
|
19
|
+
import {
|
|
20
|
+
output
|
|
21
|
+
} from "./chunk-T5HJUAWB.js";
|
|
22
|
+
import "./chunk-GSGZHE26.js";
|
|
23
|
+
import "./chunk-IKT5F47M.js";
|
|
24
|
+
import "./chunk-3MZYUBJ6.js";
|
|
25
|
+
|
|
26
|
+
// src/domains/document/serve/action.ts
|
|
27
|
+
import { serve } from "@hono/node-server";
|
|
28
|
+
import as from "ansis";
|
|
29
|
+
import { Hono } from "hono";
|
|
30
|
+
import { stream } from "hono/streaming";
|
|
31
|
+
|
|
32
|
+
// src/domains/document/serve/load-document.ts
|
|
33
|
+
import { validate } from "@scalar/asyncapi-validator";
|
|
34
|
+
var loadServeDocument = async (input) => {
|
|
35
|
+
const content = await getFileOrUrl(input);
|
|
36
|
+
const document = safeNormalize(content);
|
|
37
|
+
if (!isDocument(document) || !isAsyncApiDocument(document)) {
|
|
38
|
+
return loadOpenApiDocument(content);
|
|
39
|
+
}
|
|
40
|
+
const result = validate(document);
|
|
41
|
+
if (!result.valid) {
|
|
42
|
+
output.warn().title("File does not match the AsyncAPI specification.").print();
|
|
43
|
+
for (const error of result.errors ?? []) {
|
|
44
|
+
output.warn().title(error.message ?? "Invalid AsyncAPI document").print();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
valid: result.valid,
|
|
49
|
+
version: result.version,
|
|
50
|
+
specification: document,
|
|
51
|
+
schema: void 0
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// src/domains/document/serve/action.ts
|
|
56
|
+
async function serveAction(inputArgument, { watch, once, port }) {
|
|
57
|
+
if (!inputArgument) {
|
|
58
|
+
return output.error().title("Invalid argument").message("Please provide a file path").exit("error");
|
|
59
|
+
}
|
|
60
|
+
const result = await loadServeDocument(inputArgument);
|
|
61
|
+
if (result.specification === void 0) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
let { specification } = result;
|
|
65
|
+
printServeBanner(result);
|
|
66
|
+
if (!isAsyncApiDocument(specification) && Object.keys(specification.paths ?? {}).length === 0) {
|
|
67
|
+
output.warn().title("Could not find any paths in the OpenAPI file.").print();
|
|
68
|
+
}
|
|
69
|
+
const app = new Hono();
|
|
70
|
+
app.get("/", (c) => {
|
|
71
|
+
return c.html(getHtmlDocument(specification, watch));
|
|
72
|
+
});
|
|
73
|
+
app.use("/__watcher", async (c, next) => {
|
|
74
|
+
c.header("Content-Type", "text/event-stream");
|
|
75
|
+
c.header("Cache-Control", "no-cache");
|
|
76
|
+
c.header("Connection", "keep-alive");
|
|
77
|
+
await next();
|
|
78
|
+
});
|
|
79
|
+
app.get("/__watcher", (c) => {
|
|
80
|
+
return stream(c, async (s) => {
|
|
81
|
+
if (watch) {
|
|
82
|
+
const subscription = await watchFile(inputArgument, async () => {
|
|
83
|
+
const newResult = await loadServeDocument(inputArgument);
|
|
84
|
+
if (newResult.specification && JSON.stringify(specification) !== JSON.stringify(newResult.specification)) {
|
|
85
|
+
output.info().title(
|
|
86
|
+
as.grey(
|
|
87
|
+
`${isAsyncApiDocument(newResult.specification) ? "AsyncAPI" : "OpenAPI"} file modified`
|
|
88
|
+
)
|
|
89
|
+
).print();
|
|
90
|
+
printServeBanner(newResult);
|
|
91
|
+
specification = newResult.specification;
|
|
92
|
+
s.write("data: file modified\n\n");
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
if (subscription) {
|
|
96
|
+
s.onAbort(() => subscription.unsubscribe());
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
while (true) {
|
|
100
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
const server = serve(
|
|
105
|
+
{
|
|
106
|
+
fetch: app.fetch,
|
|
107
|
+
port: port ?? 3e3
|
|
108
|
+
},
|
|
109
|
+
(info) => {
|
|
110
|
+
output.info().line(
|
|
111
|
+
`${as.green.bold("\u279C API Reference Server")} ${as.white(
|
|
112
|
+
"listening on"
|
|
113
|
+
)} ${as.cyan(`http://localhost:${info.port}`)}`
|
|
114
|
+
).print();
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
if (once) {
|
|
118
|
+
setTimeout(() => {
|
|
119
|
+
server.close();
|
|
120
|
+
}, 2e3);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
var getHtmlDocument = (specification, watch = false) => {
|
|
124
|
+
return `<!doctype html>
|
|
125
|
+
<html>
|
|
126
|
+
<head>
|
|
127
|
+
<title>Scalar API Reference</title>
|
|
128
|
+
<meta charset="utf-8" />
|
|
129
|
+
<meta
|
|
130
|
+
name="viewport"
|
|
131
|
+
content="width=device-width, initial-scale=1" />
|
|
132
|
+
<style>
|
|
133
|
+
body {
|
|
134
|
+
margin: 0;
|
|
135
|
+
}
|
|
136
|
+
</style>
|
|
137
|
+
${watch ? `
|
|
138
|
+
<script>
|
|
139
|
+
const evtSource = new EventSource('__watcher');
|
|
140
|
+
evtSource.onmessage = (event) => {
|
|
141
|
+
console.log(\`message: \${event.data}\`);
|
|
142
|
+
window.location.reload();
|
|
143
|
+
};
|
|
144
|
+
</script>
|
|
145
|
+
` : ""}
|
|
146
|
+
</head>
|
|
147
|
+
<body>
|
|
148
|
+
<script
|
|
149
|
+
id="api-reference"
|
|
150
|
+
type="application/json"
|
|
151
|
+
data-proxy-url="https://proxy.scalar.com">${JSON.stringify(specification)}</script>
|
|
152
|
+
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
|
|
153
|
+
</body>
|
|
154
|
+
</html>`;
|
|
155
|
+
};
|
|
156
|
+
var printServeBanner = (result) => {
|
|
157
|
+
if (isAsyncApiDocument(result.specification)) {
|
|
158
|
+
output.info().title(`AsyncAPI${result.version ? ` v${result.version}` : ""}`).print();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
printSpecificationBanner({
|
|
162
|
+
version: result.version,
|
|
163
|
+
schema: result.valid ? result.schema : void 0
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
export {
|
|
167
|
+
getHtmlDocument,
|
|
168
|
+
serveAction
|
|
169
|
+
};
|