Files
Web_BAI_Manage_ApiServer/.tmp-openapi-validate/make-openapi-standalone.cjs
XuJiacheng ec6b59b4fa feat: 添加购物车相关迁移和索引功能
- 在 package.json 中添加迁移脚本 `migrate:cart-active-unique-index`。
- 修改 `pocketbase.cart-order.js` 文件,更新 `cart_id` 和 `cart_product_id` 字段的必填属性,并添加唯一索引 `idx_tbl_cart_owner_product_active_unique`。
- 在 `pocketbase.ensure-cart-order-autogen-id.js` 中,调整 `cart_id` 字段的必填属性为可选,并确保 `order_id` 字段为必填。
- 在 `pocketbase.product-list.js` 中,新增 `prod_list_barcode` 字段。
- 新增 `make-openapi-standalone.cjs` 脚本,用于处理 OpenAPI 文档。
- 新增 `pocketbase.cart-active-unique-index.js` 脚本,处理购物车的唯一索引和去重逻辑。
2026-04-09 14:49:12 +08:00

133 lines
4.0 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const YAML = require('yaml');
const repoRoot = path.resolve(process.cwd(), '..');
const specRoot = path.join(repoRoot, 'pocket-base', 'spec');
const folders = ['openapi-wx', 'openapi-manage'];
const allFiles = [];
for (const folder of folders) {
const dir = path.join(specRoot, folder);
for (const name of fs.readdirSync(dir)) {
if (name.endsWith('.yaml')) allFiles.push(path.join(dir, name));
}
}
const docCache = new Map();
function loadDoc(filePath) {
if (!docCache.has(filePath)) {
const text = fs.readFileSync(filePath, 'utf8');
docCache.set(filePath, YAML.parse(text));
}
return docCache.get(filePath);
}
function deepClone(v) {
return v == null ? v : JSON.parse(JSON.stringify(v));
}
function decodePointer(seg) {
return seg.replace(/~1/g, '/').replace(/~0/g, '~');
}
function getByPointer(doc, pointer) {
if (!pointer || pointer === '#' || pointer === '') return doc;
const parts = pointer.replace(/^#/, '').split('/').filter(Boolean).map(decodePointer);
let cur = doc;
for (const p of parts) {
if (cur == null) return undefined;
cur = cur[p];
}
return cur;
}
function mergeObjects(base, extra) {
if (base && typeof base === 'object' && !Array.isArray(base) && extra && typeof extra === 'object' && !Array.isArray(extra)) {
return { ...base, ...extra };
}
return base;
}
function isExternalRef(ref) {
if (typeof ref !== 'string') return false;
if (ref.startsWith('#')) return false;
if (/^https?:\/\//i.test(ref)) return false;
const [filePart] = ref.split('#');
return !!filePart;
}
function resolveExternalRef(ref, baseFile) {
const [filePart, hashPart = ''] = ref.split('#');
const targetFile = path.resolve(path.dirname(baseFile), filePart);
const targetDoc = loadDoc(targetFile);
const pointer = hashPart ? `#${hashPart}` : '#';
const targetNode = getByPointer(targetDoc, pointer);
return { targetFile, targetNode: deepClone(targetNode) };
}
function derefExternals(node, baseFile, seen = new Set()) {
if (Array.isArray(node)) {
return node.map((item) => derefExternals(item, baseFile, seen));
}
if (!node || typeof node !== 'object') {
return node;
}
if (typeof node.$ref === 'string' && isExternalRef(node.$ref)) {
const key = `${baseFile}::${node.$ref}`;
if (seen.has(key)) {
return node;
}
seen.add(key);
const { targetFile, targetNode } = resolveExternalRef(node.$ref, baseFile);
let inlined = derefExternals(targetNode, targetFile, seen);
const siblings = { ...node };
delete siblings.$ref;
if (Object.keys(siblings).length > 0) {
inlined = mergeObjects(inlined, derefExternals(siblings, baseFile, seen));
}
return inlined;
}
const out = {};
for (const [k, v] of Object.entries(node)) {
out[k] = derefExternals(v, baseFile, seen);
}
return out;
}
function ensureTopLevel(doc, filePath) {
if (!doc.openapi) doc.openapi = '3.1.0';
if (!doc.info || typeof doc.info !== 'object') {
const base = path.basename(filePath, '.yaml');
const group = filePath.includes('openapi-wx') ? 'WX Native' : 'Manage Hooks';
doc.info = {
title: `BAI ${group} API - ${base}`,
version: '1.0.0'
};
} else {
if (!doc.info.title) doc.info.title = `BAI API - ${path.basename(filePath, '.yaml')}`;
if (!doc.info.version) doc.info.version = '1.0.0';
}
if (!Array.isArray(doc.servers)) {
doc.servers = [
{ url: 'https://bai-api.blv-oa.com', description: '生产环境' },
{ url: 'http://localhost:8090', description: 'PocketBase 本地环境' }
];
}
}
for (const filePath of allFiles) {
const original = loadDoc(filePath);
const transformed = derefExternals(deepClone(original), filePath);
ensureTopLevel(transformed, filePath);
const outText = YAML.stringify(transformed, { lineWidth: 0 });
fs.writeFileSync(filePath, outText, 'utf8');
docCache.set(filePath, transformed);
}
console.log(`Processed ${allFiles.length} yaml files under openapi-wx/openapi-manage.`);