openapi-typescript
Version:
Generate TypeScript types from Swagger OpenAPI specs
189 lines • 7.79 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveSchema = exports.VIRTUAL_JSON_URL = void 0;
const node_fetch_1 = __importDefault(require("node-fetch"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const url_1 = require("url");
const slash_1 = __importDefault(require("slash"));
const mime_1 = __importDefault(require("mime"));
const js_yaml_1 = __importDefault(require("js-yaml"));
const kleur_1 = require("kleur");
const utils_1 = require("./utils");
exports.VIRTUAL_JSON_URL = `file:///_json`;
function parseSchema(schema, type) {
if (type === "YAML") {
try {
return js_yaml_1.default.load(schema);
}
catch (err) {
throw new Error(`YAML: ${err.toString()}`);
}
}
else {
try {
return JSON.parse(schema);
}
catch (err) {
throw new Error(`JSON: ${err.toString()}`);
}
}
}
function isFile(url) {
return url.protocol === "file:";
}
function resolveSchema(url) {
if (url.startsWith("http://") || url.startsWith("https://")) {
return new url_1.URL(url);
}
const localPath = path_1.default.isAbsolute(url)
? new url_1.URL("", `file://${(0, slash_1.default)(url)}`)
: new url_1.URL(url, `file://${(0, slash_1.default)(process.cwd())}/`);
if (!fs_1.default.existsSync(localPath)) {
throw new Error(`Could not locate ${url}`);
}
else if (fs_1.default.statSync(localPath).isDirectory()) {
throw new Error(`${localPath} is a directory not a file`);
}
return localPath;
}
exports.resolveSchema = resolveSchema;
function parseHttpHeaders(httpHeaders) {
const finalHeaders = {};
for (const [k, v] of Object.entries(httpHeaders)) {
if (typeof v === "string") {
finalHeaders[k] = v;
}
else {
try {
const stringVal = JSON.stringify(v);
finalHeaders[k] = stringVal;
}
catch (err) {
console.error((0, kleur_1.red)(`Cannot parse key: ${k} into JSON format. Continuing with the next HTTP header that is specified`));
}
}
}
return finalHeaders;
}
async function load(schema, options) {
const urlCache = options.urlCache || new Set();
const isJSON = schema instanceof url_1.URL === false;
let schemaID = isJSON ? new url_1.URL(exports.VIRTUAL_JSON_URL).href : schema.href;
const schemas = options.schemas;
if (isJSON) {
schemas[schemaID] = schema;
}
else {
if (urlCache.has(schemaID))
return options.schemas;
urlCache.add(schemaID);
let contents = "";
let contentType = "";
const schemaURL = schema;
if (isFile(schemaURL)) {
contents = await fs_1.default.promises.readFile(schemaURL, "utf8");
contentType = mime_1.default.getType(schemaID) || "";
}
else {
const headers = {
"User-Agent": "openapi-typescript",
};
if (options.auth)
headers.Authorizaton = options.auth;
if (options.httpHeaders) {
const parsedHeaders = parseHttpHeaders(options.httpHeaders);
for (const [k, v] of Object.entries(parsedHeaders)) {
headers[k] = v;
}
}
const res = await (0, node_fetch_1.default)(schemaID, { method: options.httpMethod || "GET", headers });
contentType = res.headers.get("Content-Type") || "";
contents = await res.text();
}
const isYAML = contentType === "application/openapi+yaml" || contentType === "text/yaml";
const isJSON = contentType === "application/json" ||
contentType === "application/json5" ||
contentType === "application/openapi+json";
if (isYAML) {
schemas[schemaID] = parseSchema(contents, "YAML");
}
else if (isJSON) {
schemas[schemaID] = parseSchema(contents, "JSON");
}
else {
try {
schemas[schemaID] = parseSchema(contents, "JSON");
}
catch (err1) {
try {
schemas[schemaID] = parseSchema(contents, "YAML");
}
catch (err2) {
throw new Error(`Unknown format${contentType ? `: "${contentType}"` : ""}. Only YAML or JSON supported.`);
}
}
}
}
const refPromises = [];
schemas[schemaID] = JSON.parse(JSON.stringify(schemas[schemaID]), (k, v) => {
if (k !== "$ref" || typeof v !== "string")
return v;
const { url: refURL } = (0, utils_1.parseRef)(v);
if (refURL) {
const isRemoteURL = refURL.startsWith("http://") || refURL.startsWith("https://");
if (isJSON && !isRemoteURL) {
throw new Error(`Can’t load URL "${refURL}" from dynamic JSON. Load this schema from a URL instead.`);
}
const nextURL = isRemoteURL ? new url_1.URL(refURL) : new url_1.URL((0, slash_1.default)(refURL), schema);
refPromises.push(load(nextURL, { ...options, urlCache }).then((subschemas) => {
for (const subschemaURL of Object.keys(subschemas)) {
schemas[subschemaURL] = subschemas[subschemaURL];
}
}));
return v.replace(refURL, nextURL.href);
}
return v;
});
await Promise.all(refPromises);
if (schemaID === options.rootURL.href) {
for (const subschemaURL of Object.keys(schemas)) {
schemas[subschemaURL] = JSON.parse(JSON.stringify(schemas[subschemaURL]), (k, v) => {
if (k !== "$ref" || typeof v !== "string")
return v;
if (!v.includes("#"))
return v;
const { url, parts } = (0, utils_1.parseRef)(v);
if (url && new url_1.URL(url).href !== options.rootURL.href) {
const relativeURL = isFile(new url_1.URL(url)) && isFile(options.rootURL)
? path_1.default.posix.relative(path_1.default.posix.dirname(options.rootURL.href), url)
: url;
return `external["${relativeURL}"]["${parts.join('"]["')}"]`;
}
if (!url && subschemaURL !== options.rootURL.href) {
const relativeURL = isFile(new url_1.URL(subschemaURL)) && isFile(options.rootURL)
? path_1.default.posix.relative(path_1.default.posix.dirname(options.rootURL.href), subschemaURL)
: subschemaURL;
return `external["${relativeURL}"]["${parts.join('"]["')}"]`;
}
const [base, ...rest] = parts;
return `${base}["${rest.join('"]["')}"]`;
});
if (subschemaURL !== options.rootURL.href) {
const relativeURL = isFile(new url_1.URL(subschemaURL)) && isFile(options.rootURL)
? path_1.default.posix.relative(path_1.default.posix.dirname(options.rootURL.href), subschemaURL)
: subschemaURL;
if (relativeURL !== subschemaURL) {
schemas[relativeURL] = schemas[subschemaURL];
delete schemas[subschemaURL];
}
}
}
}
return schemas;
}
exports.default = load;
//# sourceMappingURL=load.js.map