UNPKG

fuckdoc

Version:

An NPM package for component document generator

438 lines (433 loc) 13.2 kB
#!/usr/bin/env node var __create = Object.create; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropNames = Object.getOwnPropertyNames; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); // src/utils.ts var import_axios = __toESM(require("axios")); var path = require("path"); var fs = require("fs"); var glob = require("glob"); var { parse: CommentParser } = require("comment-parser"); var CWD = process.cwd(); var DefaultConfig = { paths: ["src/**/*"] }; var fileExists = (filePath) => new Promise((r) => { fs.exists(filePath, (exists) => { if (exists) { r(true); } else { r(false); } }); }); var isDirectory = (filePath) => { const stat = fs.lstatSync(filePath); return stat.isDirectory(); }; var isAllowSuffix = (suffix, userSuffix) => [...["js", "ts", "tsx", "jsx", "mjs", "vue", "weex"], ...[userSuffix]].includes(suffix); var commonRequire = (path4) => { const res = require(path4); return res; }; var loadConfig = async () => { const configFilePath = path.join(CWD, "/fuckdoc.config.js"); let config = DefaultConfig; const isConfigFileExists = await fileExists(configFilePath); if (isConfigFileExists) { const userConfig = commonRequire(configFilePath); if (Object.keys(userConfig).length) { config = userConfig; } } return config; }; var scanFile = async () => { const config = await loadConfig(); const { paths = [], suffix = [] } = config; const allFilePathsMap = /* @__PURE__ */ new Map(); paths.forEach((path4) => { let files = glob.sync(path4, {}); files = files.forEach((filePath) => { const fullPath = `${CWD}/${filePath}`; if (!isDirectory(fullPath)) { if (!allFilePathsMap.has(fullPath)) { allFilePathsMap.set(fullPath, fullPath); } } }); }); const fileFiltedPath = [...allFilePathsMap.values()]; const imgFilePath = []; const codeFilePath = []; fileFiltedPath.forEach((item) => { if (item.indexOf(".fuckdoc.") > 0) { return imgFilePath.push(item); } const strArr = item.split("."); const suf = strArr[strArr.length - 1]; if (isAllowSuffix(suf, suffix)) { return codeFilePath.push(item); } }); return [imgFilePath, codeFilePath, fileFiltedPath]; }; var scanData = async () => { const [imgFilePath, codeFilePath, fileFiltedPath] = await scanFile(); const codeCommentFCMap = /* @__PURE__ */ new Map(); const codeCommentFFMap = /* @__PURE__ */ new Map(); codeFilePath.forEach((codePath) => { const temp = fs.readFileSync(codePath, { encoding: "utf-8" }); const parsed = CommentParser(temp) || []; const tempFCArr = []; const tempFFArr = []; parsed.forEach((parseItem) => { const { description = "", tags = [] } = parseItem; const isFC = description.indexOf("F:C") >= 0; const isFF = description.indexOf("F:F") >= 0; const params = []; if (isFC || isFF) { let title = ""; let desc = ""; let startLine = 0; tags.forEach((tag, index) => { if (tag.tag === "title") { title = `${tag.name} ${tag.description}`; } if (tag.tag === "description") { desc = `${tag.name} ${tag.description}`; } if (tag.source[0] && tag.source[0].number != null) { startLine = tag.source[0].number; } if (tag.tag === "param") { params.push({ name: tag.name, type: tag.type, description: tag.description }); } }); if (isFC) { tempFCArr.push({ type: "FC" /* FC */, title, desc, startLine, params }); } if (isFF) { tempFFArr.push({ type: "FF" /* FF */, title, desc, startLine, params }); } } }); if (tempFCArr.length) { codeCommentFCMap.set(codePath, tempFCArr); } if (tempFFArr.length) { codeCommentFFMap.set(codePath, tempFFArr); } }); const FCArr = []; const FFArr = []; const imgFilePathMap = /* @__PURE__ */ new Map(); imgFilePath.forEach((imgFullPath) => { const codeFullPath = imgFullPath.split(".fuckdoc.")[0]; if (imgFilePathMap.get(codeFullPath)) { imgFilePathMap.get(codeFullPath).push(imgFullPath); } else { imgFilePathMap.set(codeFullPath, [imgFullPath]); } }); [...imgFilePathMap.keys()].forEach((codeFullPath) => { const imgPaths = imgFilePathMap.get(codeFullPath); if (fileFiltedPath.includes(codeFullPath)) { if (codeCommentFCMap.has(codeFullPath)) { const infos = codeCommentFCMap.get(codeFullPath); infos.forEach((info) => { FCArr.push({ imgPaths, codePath: codeFullPath, info }); }); codeCommentFCMap.delete(codeFullPath); } else { FCArr.push({ imgPaths, codePath: codeFullPath }); } } else { FCArr.push({ imgPaths }); } }); [...codeCommentFCMap.keys()].forEach((codePath) => { codeCommentFCMap.get(codePath).forEach((info) => { FCArr.push({ codePath, info }); }); }); [...codeCommentFFMap.keys()].forEach((codePath) => { codeCommentFFMap.get(codePath).forEach((info) => { FFArr.push({ codePath, info }); }); }); const config = await loadConfig(); reportLog({ where: "scan_data", c_num: FCArr.length, f_num: FFArr.length }); return { ["FC" /* FC */]: FCArr, ["FF" /* FF */]: FFArr, title: config.title }; }; function debounce(fn, wait2 = 50) { let timer = null; return function(...args) { if (timer) { clearTimeout(timer); } timer = setTimeout(() => { fn.apply(this, args); }, wait2); }; } var reportLog = ({ where = "unknown", c_num = 0, f_num = 0 }) => { try { const { platform } = process; import_axios.default.get(`http://fuckdoc-log.cn-beijing.log.aliyuncs.com/logstores/npm/track?APIVersion=0.6.0&platform=${platform}&where=${where}&c_num=${c_num}&f_num=${f_num}`); } catch (e) { } }; // src/server/index.ts var import_ws = require("ws"); var path2 = require("path"); var glob2 = require("glob"); var Koa = require("koa"); var koaStatic = require("koa-static"); var koaRouter = require("koa-router"); var fs2 = require("fs"); var mime = require("mime-types"); var childProcess = require("child_process"); var cors = require("koa2-cors"); var launch = require("launch-editor"); var openInEditor = require("open-in-editor"); var portfinder = require("portfinder"); var colors = require("ansi-colors"); var chokidar = require("chokidar"); var globalData; var globalWs; var globalWsPort; var wait = (time) => new Promise((r) => { setTimeout(() => { r(true); }, time); }); var doOpenEditor = (path4) => new Promise((r, j) => { launch(path4, "code", (fileName, errorMsg) => { j(errorMsg); }); r(true); }); var initServer = (config) => { const app = new Koa(); const router = new koaRouter(); app.use(cors()); app.use(router.routes()); app.use(koaStatic(path2.join(__dirname, "../", "client"), { index: "index.html", hidden: false, defer: true })); router.get("/img", async (ctx) => { const { path: path4 } = ctx.request.query; const file = fs2.readFileSync(path4); const mimeType = mime.lookup(path4); ctx.set("content-type", mimeType); ctx.body = file; }); router.get("/open-source", async (ctx) => { const { path: path4 } = ctx.request.query; try { const res = await doOpenEditor(path4); await wait(1500); ctx.body = JSON.stringify({ success: true }); } catch (e) { ctx.body = JSON.stringify({ success: false, msg: e }); } }); router.get("/data", async (ctx) => { ctx.type = "json"; ctx.body = JSON.stringify({ data: __spreadProps(__spreadValues({}, globalData), { wsPort: globalWsPort }) }); }); portfinder.getPort({ port: 9527, stopPort: 9999 }, (err, port) => { const { port: configPort } = config; const finalPort = configPort || port; app.listen(finalPort, () => { console.log("\n"); console.log(colors.green("\u{1F389}\u{1F389}\u{1F389} fuckdoc\u5DF2\u7ECF\u542F\u52A8 \u{1F389}\u{1F389}\u{1F389}")); console.log("\n"); console.log(colors.green(`\u70B9\u51FB http://127.0.0.1:${finalPort} \u8BD5\u8BD5\u5427\uFF01`)); console.log("\n"); }); }); }; async function refreshData() { globalData = await scanData(); globalWs && globalWs.send(JSON.stringify({ type: "Refresh" })); } function initWatch(config) { const { paths } = config; const watcher = chokidar.watch(paths, { ignored: /(^|[\/\\])\../, persistent: true }); const debounceRefreshData = debounce(refreshData, 1e3); watcher.on("all", (path4) => { debounceRefreshData(); }); } function initWs(callback) { portfinder.getPort({ port: 10357, stopPort: 10400 }, (err, port) => { globalWsPort = port; callback(); const wss = new import_ws.WebSocketServer({ port }); wss.on("connection", function connection(ws) { globalWs = ws; }); }); } async function startServer() { const config = await loadConfig(); globalData = await scanData(); initWs(() => { initServer(config); initWatch(config); }); } // src/sharp/index.ts var sharp = require("sharp"); var path3 = require("path"); var cliProgress = require("cli-progress"); var colors2 = require("ansi-colors"); var deleteFile = require("delete"); async function startSharp() { const [imgFilePath] = await scanFile(); const filtedImgPath = imgFilePath.filter((imgPath) => !imgPath.endsWith(".webp")); const imageTotal = filtedImgPath.length; if (imageTotal === 0) { console.log("\n"); console.log(colors2.green("\u{1F389}\u{1F389}\u{1F389} \u5DF2\u5B8C\u6210\u538B\u7F29 \u{1F389}\u{1F389}\u{1F389}")); console.log("\n"); console.log(colors2.green("fuckdoc \u5DF2\u5C06\u56FE\u7247\u5168\u90E8\u538B\u7F29\u4E3Awebp\u683C\u5F0F")); console.log("\n"); return; } const progressBar = new cliProgress.SingleBar({ format: `fuckdoc \u56FE\u7247\u538B\u7F29 |${colors2.cyan("{bar}")}| {percentage}% || {value}/{total} images`, barCompleteChar: "\u2588", barIncompleteChar: "\u2591", hideCursor: true, clearOnComplete: false }); progressBar.start(imageTotal, 0); let sharpedCount = 0; filtedImgPath.forEach(async (imagePath) => { const imgPathArr = imagePath.split("."); imgPathArr[imgPathArr.length - 1] = "webp"; const webpImgPath = imgPathArr.join("."); sharp(imagePath).toFile(webpImgPath, (err, info) => { deleteFile.sync([imagePath]); sharpedCount += 1; progressBar.update(sharpedCount); if (sharpedCount >= imageTotal) { setTimeout(() => { progressBar.stop(); console.log("\n"); console.log(colors2.green("\u{1F389}\u{1F389}\u{1F389} \u538B\u7F29\u5B8C\u6BD5 \u{1F389}\u{1F389}\u{1F389}")); console.log("\n"); console.log(colors2.green("fuckdoc \u5DF2\u5C06\u56FE\u7247\u5168\u90E8\u538B\u7F29\u4E3Awebp\u683C\u5F0F")); console.log("\n"); }, 500); } }); }); } var sharp_default = startSharp; // src/index.ts var isSharp = process.argv.filter((item) => item.indexOf("sharp") >= 0).length > 0; if (isSharp) { reportLog({ where: "sharp" }); sharp_default(); } else { reportLog({ where: "start" }); startServer(); }