@mintlify/common
Version:
Commonly shared code within Mintlify
258 lines (257 loc) • 9.43 kB
JavaScript
import { getSecurityOptionsForAuthMethod } from '../../../../index.js';
import { isDocsConfig } from '../../../../isDocsConfig.js';
import { isMdxJsxAttribute, isParamFieldLocation } from '../../../lib/mdx-utils.js';
export const parseAuthMethod = (authMethodString, config) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
const method = authMethodString !== null && authMethodString !== void 0 ? authMethodString : (config && isDocsConfig(config) ? (_c = (_b = (_a = config.api) === null || _a === void 0 ? void 0 : _a.mdx) === null || _b === void 0 ? void 0 : _b.auth) === null || _c === void 0 ? void 0 : _c.method : (_e = (_d = config === null || config === void 0 ? void 0 : config.api) === null || _d === void 0 ? void 0 : _d.auth) === null || _e === void 0 ? void 0 : _e.method);
const name = config && isDocsConfig(config) ? (_h = (_g = (_f = config.api) === null || _f === void 0 ? void 0 : _f.mdx) === null || _g === void 0 ? void 0 : _g.auth) === null || _h === void 0 ? void 0 : _h.name : (_k = (_j = config === null || config === void 0 ? void 0 : config.api) === null || _j === void 0 ? void 0 : _j.auth) === null || _k === void 0 ? void 0 : _k.name;
return getSecurityOptionsForAuthMethod(method, name);
};
export const parseField = (node) => {
let locationAttr;
let schemaInfo;
let required = undefined;
let deprecated = undefined;
let placeholder = undefined;
for (const { name: attrName, value } of node.attributes.filter(isMdxJsxAttribute)) {
if (node.name !== 'ResponseField' && isParamFieldLocation(attrName)) {
// if ParamField or Param, parameter name comes from the `body`, `header`, etc attribute
if (locationAttr) {
console.error('multiple location/name pairs specified');
return;
}
if (attrName === 'body') {
if (typeof value !== 'string' && value !== null) {
console.error(`invalid body parameter name: "${value}"`);
return;
}
locationAttr = {
location: attrName,
name: value,
};
}
else {
if (typeof value !== 'string') {
console.error(`invalid parameter name: "${value}"`);
return;
}
locationAttr = {
location: attrName,
name: value,
};
}
}
else if (node.name === 'ResponseField' && attrName === 'name') {
// if ResponseField, parameter name comes from the `name` attribute
if (locationAttr) {
console.error('multiple names specified');
return;
}
if (typeof value !== 'string') {
console.error(`invalid response field name: "${value}"`);
return;
}
locationAttr = {
location: 'response',
name: value,
};
}
else if (attrName === 'type') {
if (typeof value !== 'string') {
console.error(`invalid type string: "${value}"`);
return;
}
schemaInfo = parseTypeString(value);
}
else if (attrName === 'required') {
if (value === null || (typeof value === 'object' && value.value.trim() === 'true')) {
required = true;
}
}
else if (attrName === 'deprecated') {
if (value === null || (typeof value === 'object' && value.value.trim() === 'true')) {
deprecated = true;
}
}
else if (attrName === 'placeholder') {
if (typeof value === 'string') {
placeholder = value;
}
}
}
if (locationAttr === undefined) {
console.error('no parameter name specified');
return;
}
if (schemaInfo === undefined) {
console.error(`no type specified for parameter "${locationAttr.name}"`);
return;
}
schemaInfo.schema.description = parseDescription(node);
schemaInfo.schema.required = required;
schemaInfo.schema.deprecated = deprecated;
schemaInfo.schema.placeholder = placeholder;
return Object.assign({ locationAttr }, schemaInfo);
};
export const parseDescription = (node) => {
const extractTextFromNode = (node) => {
if (node.type === 'text') {
return [node.value.replace(/\s+/g, ' ').trim()];
}
if (node.type === 'element') {
if (node.tagName === 'code') {
const codeContent = node.children.map(extractTextFromNode).flat().join('');
return [`\`${codeContent}\``];
}
return node.children.flatMap(extractTextFromNode);
}
return [];
};
const descriptionFragments = node.children.flatMap(extractTextFromNode);
return descriptionFragments.length > 0
? descriptionFragments.join(' ').replace(/\s+/g, ' ').trim()
: undefined;
};
const typeStringToSchemaType = {
// string
str: 'string',
string: 'string',
date: 'string',
text: 'string',
url: 'string',
uuid: 'string',
hash: 'string',
bytes: 'string',
xml: 'string',
// integer
int: 'integer',
integer: 'integer',
// number
num: 'number',
number: 'number',
float: 'number',
decimal: 'number',
long: 'number',
double: 'number',
// boolean
bool: 'boolean',
boolean: 'boolean',
// object
obj: 'object',
object: 'object',
record: 'object',
dict: 'object',
dictionary: 'object',
map: 'object',
// array
arr: 'array',
array: 'array',
list: 'array',
// file
file: 'file',
// any
any: 'any',
json: 'any',
// null
null: 'null',
};
const genericStringRegex = /^(\w+)<(.*)>$/;
export const parseTypeString = (typeString) => {
const lowerTypeString = typeString.toLowerCase();
const simpleSchemaType = typeStringToSchemaType[lowerTypeString];
if (lowerTypeString.includes('|')) {
const splitLowerTypeString = lowerTypeString.split('|');
const left = splitLowerTypeString[0];
const right = splitLowerTypeString[1];
if (left && right) {
const leftSchema = parseTypeString(left.trim());
const rightSchema = parseTypeString(right.trim());
if (leftSchema.schema.type === 'array' &&
rightSchema.schema.type === leftSchema.deepestSchema.type) {
return Object.assign({}, leftSchema);
}
if (rightSchema.schema.type === 'array' &&
leftSchema.schema.type === rightSchema.deepestSchema.type) {
return Object.assign({}, rightSchema);
}
}
}
// catch all standard type strings
if (simpleSchemaType) {
return generateSchemaWithTypeString(simpleSchemaType);
}
// catch type strings that end with []
if (lowerTypeString.endsWith('[]')) {
// recursively determine the type of the rest of the string
const subschemaInfo = parseTypeString(lowerTypeString.slice(0, lowerTypeString.length - 2));
return {
schema: {
type: 'array',
items: [subschemaInfo.schema],
},
deepestSchema: subschemaInfo.deepestSchema,
};
}
// catch type strings like foo<bar>
const regexMatch = genericStringRegex.exec(lowerTypeString);
if (regexMatch !== null) {
// unpack capture group 1 (foo) and 2 (bar)
const superType = regexMatch[1];
const subType = regexMatch[2];
if (superType && subType && typeStringToSchemaType[superType] === 'array') {
// catches type strings like array<bar>
// recursively determine the type of everything within the angle brackets
const subschemaInfo = parseTypeString(subType);
return {
schema: {
type: 'array',
items: [subschemaInfo.schema],
},
deepestSchema: subschemaInfo.deepestSchema,
};
}
}
// for any unrecognized typestring, default to object
return generateSchemaWithTypeString('object');
};
const generateSchemaWithTypeString = (type) => {
switch (type) {
case 'string':
case 'number':
case 'integer':
case 'boolean':
case 'file':
case 'null':
case 'any': {
const schema = { type };
return {
schema,
deepestSchema: schema,
};
}
case 'object': {
const schema = {
type: 'object',
properties: {},
};
return {
schema,
deepestSchema: schema,
};
}
case 'array': {
const itemsSchema = {
type: 'object',
properties: {},
};
const schema = {
type: 'array',
items: [itemsSchema],
};
return {
schema,
deepestSchema: itemsSchema,
};
}
}
};