UNPKG

@lonu/stc

Version:

A tool for converting OpenApi/Swagger/Apifox into code.

187 lines (186 loc) 6.05 kB
import * as dntShim from "../_dnt.shims.js"; import * as diff from "diff"; import { copy, emptyDir, ensureFile, exists, expandGlob } from "../deps/jsr.io/@std/fs/1.0.18/mod.js"; import { format as dateFormat } from "../deps/jsr.io/@std/datetime/0.225.5/mod.js"; import denoJson from "../deno.js"; import { getT } from "./i18n/index.js"; /** * 驼峰命名 * @param str - 字符 * @param pascalCase - 是否首字母大写 */ export const camelCase = (str, pascalCase = false) => { if (!str) return ""; const _newStr = pascalCase ? `_${str}` : str; return _newStr.replace(/[\.\_-]{1,}(\w)/g, (_, s) => s.toUpperCase()); }; /** * 首字母小写 * @param str - 字符 */ export const lowerCase = (str) => str.charAt(0).toLowerCase() + str.slice(1); /** * 首字母大写 * @param str - 字符 */ export const upperCase = (str) => str.charAt(0).toUpperCase() + str.slice(1); /** * 读取文件 * @param filePath - 文件路径 */ export const readFile = async (filePath) => { // 检查路径是否存在 if (!(await exists(filePath))) return ""; return dntShim.Deno.readTextFile(filePath); }; /** * 创建文件。如果不存在会被自动创建,存在会被覆盖 * * @param filePath - 文件路径 * @param content - 文件内容 */ export const createFile = async (filePath, content, { append, banner = true } = {}) => { await ensureFile(filePath); await dntShim.Deno.writeFile(filePath, new TextEncoder().encode(`${banner ? `/** ${getT("$t(util.createFileDescription)", { version: denoJson.version, })} * * https://github.com/long-woo/stc * ${dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss")} */\n\n` : ""}${content}`), { append }); }; /** * 将给定的内容写入指定路径的文件中 * * @param {string} filePath - 要创建或覆盖的文件的路径 * @param {ArrayBuffer} content - 要写入文件的内容 * @return {Promise<void>} - 在文件成功写入时解析,或在出现错误时拒绝 */ export const createAppFile = (filePath, content) => dntShim.Deno.writeFile(filePath, new Uint8Array(content)); /** * 覆盖复制文件 * @param from - 复制位置 * @param to - 目标位置 */ export const copyFile = (from, to, options = { overwrite: true }) => { copy(from, to, { overwrite: options.overwrite }); }; /** * 清空目录 * @param dir - 目录 */ export const emptyDirectory = (dir) => emptyDir(dir); /** * ref type * @param ref - ref */ export const getRefType = (ref) => camelCase(decodeURIComponent(ref).replace(/^#\/(definitions|components\/schemas)\//, ""), true); /** * 根据值获取对象的 key * @param obj - 对象 * @param value - 值 */ export const getObjectKeyByValue = (obj, value) => Object.keys(obj).find((key) => obj[key] === value); /** * 检查给定的对象是否具有指定的键。 * * @param {Record<string, string>} obj - 要检查键的对象 * @param {string} name - 要检查的键的名称 * @return {boolean} 如果对象具有指定的键,则返回true,否则返回false */ export const hasKey = (obj, name) => Object.prototype.hasOwnProperty.call(obj, name); /** * Converts a string value to its corresponding JavaScript data type. * * @param {string} value - The value to be converted. * @return {any} The converted JavaScript data type. */ export const convertValue = (value) => { try { return JSON.parse(value); } catch (_) { return value; } }; /** * Fetches a client from the specified URL with optional request options. * * @param {string} url - The URL to fetch the client from. * @param {RequestInit & { timeout?: number }} options - Optional request options. * @return {Promise<Response>} A promise that resolves to the response from the server. */ export const fetchClient = async (url, options = { timeout: 5000 }) => { const responsePromise = fetch(url, options); // 创建一个超时 Promise const timeoutPromise = new Promise((_resolve, reject) => { setTimeout(() => { reject(new Error(getT("$t(util.timeout)"))); }, options?.timeout); }); // 等待任意一个 Promise 完成 const res = await Promise.race([responsePromise, timeoutPromise]); if (res instanceof Response) { // 请求成功,返回响应 return res; } throw res; }; /** * 移除文件 * @param glob - 匹配文件 * @param options - 选项 */ export const removeFile = async (glob, options) => { const _files = await Array.fromAsync(expandGlob(glob, options)); for await (const _file of _files) { await dntShim.Deno.remove(_file.path); } }; /** * 清除文件 banner * @param path - 文件路径 */ export const removeFileBanner = async (path) => { const file = await readFile(path); const content = file.replace(/\/\*\*.+`?https:\/\/github\.com\/long-woo\/stc`?\s+\*\s+(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\s+\*\/\s+/s, ""); return content; }; /** * 生成差异文件 * @param source - 源文件 * @param content - 内容 * @param clean - 是否清除差异 */ export const createDiffFile = async (source, content, clean = true) => { let isChange = true; let newContent = content; if (!clean) { const oldContent = await removeFileBanner(source); if (oldContent) { const diffResult = diff.diffLines(oldContent, newContent); isChange = diffResult.some((item) => item.added || item.removed); if (isChange) { newContent = ""; for (const item of diffResult) { if (item.removed) continue; newContent += item.value; } } // createFile( // `./stc_out/.stc_diff.lock`, // JSON.stringify(diffResult, null, 2), // { // banner: false, // }, // ); } } if (isChange) createFile(source, newContent); };