UNPKG

@mintlify/common

Version:

Commonly shared code within Mintlify

258 lines (257 loc) 9.43 kB
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, }; } } };