import { readFile, writeFile } from 'fs/promises'; import path from 'path'; import { fileURLToPath } from 'url'; import { LibraryItem, LibraryItems } from '@excalidraw/excalidraw/types' // 如果新增了自定义素材,则需要运行这个脚本将素材同步到lib文件夹,以便下次合成素材库时,不会清除新增素材 const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const inputFile = path.resolve(__dirname, '../library.excalidrawlib'); // 输入目录 const outputFile = path.resolve(__dirname, '../lib/library.excalidrawlib'); // 输出文件路径 interface ExportedLibraryData { type: string; version: number; source: string; libraryItems: LibraryItems; } function isExcalidrawlibFile(fileName: string): boolean { return fileName.endsWith('.excalidrawlib'); } /** * checks if library item does not exist already in current library */ const isUniqueItem = ( existingLibraryItems: LibraryItems, targetLibraryItem: LibraryItem, ) => { return !existingLibraryItems.find((libraryItem) => { if (libraryItem.elements.length !== targetLibraryItem.elements.length) { return false; } // detect z-index difference by checking the excalidraw elements // are in order return libraryItem.elements.every((libItemExcalidrawItem, idx) => { return ( libItemExcalidrawItem.id === targetLibraryItem.elements[idx].id && libItemExcalidrawItem.versionNonce === targetLibraryItem.elements[idx].versionNonce ); }); }); }; function positionError(obj: any, msg?: string): false { console.error({ error_msg: msg, error_obj: obj }) return false } function isLibraryItem(obj: any): obj is LibraryItem { if (!obj) return positionError(obj, "LibraryItem obj does not exist") if (!obj.id || !obj.status || !obj.elements || !obj.created) return positionError(obj, "obj missing fields") if (typeof obj.id !== 'string') return positionError(obj, "obj.id type is not string") if (obj.status !== "published" && obj.status !== "unpublished") return positionError(obj, "obj.status value is wrong") if (!Array.isArray(obj.elements)) return positionError(obj, "obj.elements is not an array") if (typeof obj.created !== 'number') return positionError(obj, "obj.created type is not number") return true } function isLibraryItems(obj: any): obj is LibraryItems { if (!obj) return positionError(obj, "LibraryItems obj does not exist") if (!Array.isArray(obj)) return positionError(obj, "obj is not an array") for (const item of obj) { if (!isLibraryItem(item)) return positionError(obj, "LibraryItems is not an array") } return true } function isExportedLibraryData(obj: any): obj is ExportedLibraryData { if (!obj) return positionError(obj, "ExportedLibraryData obj does not exist") if (obj.type !== "excalidrawlib") return positionError(obj, "obj.type value is not excalidrawlib") if (typeof obj.version !== "number") return positionError(obj, "obj.version type is not number") if (!obj.libraryItems || !isLibraryItems(obj.libraryItems)) return positionError(obj, "The library array does not exist or is wrong") return true } async function readExcalidrawlibFile(filePath: string): Promise { const content = await readFile(filePath, 'utf-8'); const parsed = JSON.parse(content); if (!isExportedLibraryData(parsed)) { console.error({filePath, parsed}) throw new Error(`Invalid excalidrawlib file: ${filePath}`); } return parsed; } async function updateExcalidrawlibFile(inputFilePath: string, outputFilePath: string): Promise { if (!isExcalidrawlibFile(inputFilePath)) return undefined if (!isExcalidrawlibFile(outputFilePath)) return undefined const originalData = await readExcalidrawlibFile(outputFilePath); const inputData = await readExcalidrawlibFile(inputFilePath); const exportedLibraryData: ExportedLibraryData = { type: originalData.type, version: originalData.version, source: originalData.source, libraryItems: [] } inputData.libraryItems.map(item => { if (item.status === 'unpublished' && isUniqueItem(originalData.libraryItems, item)) { exportedLibraryData.libraryItems = [ ...exportedLibraryData.libraryItems, {...item} ] } }) return exportedLibraryData; } async function saveUpdatedExcalidrawlib(data: ExportedLibraryData, filePath: string) { const jsonString = JSON.stringify(data, null, 2); // 缩进美化 await writeFile(filePath, jsonString, 'utf-8'); console.log(`✅ 更新完成,已保存到 ${filePath}`); } // 执行流程 const updated = await updateExcalidrawlibFile(inputFile, outputFile); if (updated !== undefined) { saveUpdatedExcalidrawlib(updated, outputFile); }