From d3dfaa7aac85f0a9bb0d791192408cba52e62866 Mon Sep 17 00:00:00 2001 From: yhh <359807859@qq.com> Date: Wed, 3 Dec 2025 16:19:29 +0800 Subject: [PATCH] =?UTF-8?q?feat(asset-system-editor):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E5=99=A8=E8=B5=84=E4=BA=A7=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/asset-system-editor/package.json | 50 +++ packages/asset-system-editor/src/index.ts | 39 ++ .../src/meta/AssetMetaFile.ts | 424 ++++++++++++++++++ .../src/packing/AssetPacker.ts | 408 +++++++++++++++++ packages/asset-system-editor/tsconfig.json | 36 ++ packages/asset-system-editor/tsup.config.ts | 10 + 6 files changed, 967 insertions(+) create mode 100644 packages/asset-system-editor/package.json create mode 100644 packages/asset-system-editor/src/index.ts create mode 100644 packages/asset-system-editor/src/meta/AssetMetaFile.ts create mode 100644 packages/asset-system-editor/src/packing/AssetPacker.ts create mode 100644 packages/asset-system-editor/tsconfig.json create mode 100644 packages/asset-system-editor/tsup.config.ts diff --git a/packages/asset-system-editor/package.json b/packages/asset-system-editor/package.json new file mode 100644 index 00000000..24b45e75 --- /dev/null +++ b/packages/asset-system-editor/package.json @@ -0,0 +1,50 @@ +{ + "name": "@esengine/asset-system-editor", + "version": "1.0.0", + "description": "Editor-side asset management: meta files, packing, and bundling", + "type": "module", + "main": "dist/index.js", + "module": "dist/index.js", + "types": "dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsup", + "build:watch": "tsup --watch", + "clean": "rimraf dist", + "type-check": "tsc --noEmit" + }, + "keywords": [ + "ecs", + "asset", + "editor", + "bundle", + "packing" + ], + "author": "yhh", + "license": "MIT", + "dependencies": { + "@esengine/asset-system": "workspace:*" + }, + "devDependencies": { + "@esengine/build-config": "workspace:*", + "rimraf": "^5.0.0", + "tsup": "^8.0.0", + "typescript": "^5.8.3" + }, + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "https://github.com/esengine/ecs-framework.git", + "directory": "packages/asset-system-editor" + } +} diff --git a/packages/asset-system-editor/src/index.ts b/packages/asset-system-editor/src/index.ts new file mode 100644 index 00000000..4173d392 --- /dev/null +++ b/packages/asset-system-editor/src/index.ts @@ -0,0 +1,39 @@ +/** + * Asset System Editor + * 资产系统编辑器模块 + * + * Editor-side asset management: + * - Meta files (.meta) management + * - Asset packing and bundling + * - Import settings + * + * 编辑器端资产管理: + * - 元数据文件 (.meta) 管理 + * - 资产打包和捆绑 + * - 导入设置 + */ + +// Meta file management +export { + AssetMetaManager, + type IAssetMeta, + type IImportSettings, + type IMetaFileSystem, + generateGUID, + getMetaFilePath, + inferAssetType, + getDefaultImportSettings, + createAssetMeta, + serializeAssetMeta, + parseAssetMeta, + isValidGUID +} from './meta/AssetMetaFile'; + +// Asset packing +export { + AssetPacker, + collectSceneAssets, + type IPackingResult, + type IPackedBundle, + type IAssetFileReader +} from './packing/AssetPacker'; diff --git a/packages/asset-system-editor/src/meta/AssetMetaFile.ts b/packages/asset-system-editor/src/meta/AssetMetaFile.ts new file mode 100644 index 00000000..46b6cb29 --- /dev/null +++ b/packages/asset-system-editor/src/meta/AssetMetaFile.ts @@ -0,0 +1,424 @@ +/** + * Asset Meta File (.meta) Management + * 资产元数据文件 (.meta) 管理 + * + * Each asset file has a companion .meta file that stores: + * - GUID: Persistent unique identifier + * - Import settings: How to process the asset + * - Labels: User-defined tags + * + * 每个资产文件都有一个配套的 .meta 文件,存储: + * - GUID:持久化唯一标识符 + * - 导入设置:如何处理资产 + * - 标签:用户定义的标签 + */ + +import { AssetGUID, AssetType } from '@esengine/asset-system'; + +/** + * Meta file content structure + * 元数据文件内容结构 + */ +export interface IAssetMeta { + /** Persistent unique identifier | 持久化唯一标识符 */ + guid: AssetGUID; + /** Asset type | 资产类型 */ + type: AssetType; + /** Import settings | 导入设置 */ + importSettings?: IImportSettings; + /** User-defined labels | 用户定义的标签 */ + labels?: string[]; + /** Meta file version | 元数据文件版本 */ + version: number; + /** Last modified timestamp | 最后修改时间戳 */ + lastModified?: number; +} + +/** + * Import settings for different asset types + * 不同资产类型的导入设置 + */ +export interface IImportSettings { + // Texture settings | 纹理设置 + maxSize?: number; + compression?: 'none' | 'dxt' | 'etc2' | 'astc' | 'webp'; + generateMipmaps?: boolean; + filterMode?: 'point' | 'bilinear' | 'trilinear'; + wrapMode?: 'clamp' | 'repeat' | 'mirror'; + premultiplyAlpha?: boolean; + + // Audio settings | 音频设置 + audioFormat?: 'mp3' | 'ogg' | 'wav'; + sampleRate?: number; + channels?: 1 | 2; + normalize?: boolean; + + // General settings | 通用设置 + [key: string]: unknown; +} + +/** + * Generate a new UUID v4 + * 生成新的 UUID v4 + */ +export function generateGUID(): AssetGUID { + // Use crypto.randomUUID if available (modern browsers/Node 19+) + if (typeof crypto !== 'undefined' && crypto.randomUUID) { + return crypto.randomUUID(); + } + + // Fallback implementation + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + const v = c === 'x' ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} + +/** + * Get meta file path for an asset + * 获取资产的元数据文件路径 + */ +export function getMetaFilePath(assetPath: string): string { + return `${assetPath}.meta`; +} + +/** + * Infer asset type from file extension + * 根据文件扩展名推断资产类型 + */ +export function inferAssetType(path: string): AssetType { + const ext = path.split('.').pop()?.toLowerCase() || ''; + + const typeMap: Record = { + // Textures + png: 'texture', + jpg: 'texture', + jpeg: 'texture', + gif: 'texture', + webp: 'texture', + bmp: 'texture', + svg: 'texture', + + // Audio + mp3: 'audio', + wav: 'audio', + ogg: 'audio', + m4a: 'audio', + flac: 'audio', + + // Data + json: 'json', + txt: 'text', + xml: 'text', + csv: 'text', + + // Scenes and prefabs + ecs: 'scene', + prefab: 'prefab', + + // Fonts + ttf: 'font', + otf: 'font', + woff: 'font', + woff2: 'font', + + // Shaders + glsl: 'shader', + vert: 'shader', + frag: 'shader', + + // Custom types (plugins) + tilemap: 'tilemap', + tileset: 'tileset', + btree: 'behavior-tree', + bp: 'blueprint', + mat: 'material' + }; + + return typeMap[ext] || 'binary'; +} + +/** + * Get default import settings for asset type + * 获取资产类型的默认导入设置 + */ +export function getDefaultImportSettings(type: AssetType): IImportSettings { + switch (type) { + case 'texture': + return { + maxSize: 2048, + compression: 'none', + generateMipmaps: false, + filterMode: 'bilinear', + wrapMode: 'clamp', + premultiplyAlpha: false + }; + + case 'audio': + return { + audioFormat: 'mp3', + sampleRate: 44100, + channels: 2, + normalize: false + }; + + default: + return {}; + } +} + +/** + * Create a new meta file content + * 创建新的元数据文件内容 + */ +export function createAssetMeta(assetPath: string, overrides?: Partial): IAssetMeta { + const type = overrides?.type || inferAssetType(assetPath); + + return { + guid: overrides?.guid || generateGUID(), + type, + importSettings: overrides?.importSettings || getDefaultImportSettings(type), + labels: overrides?.labels || [], + version: 1, + lastModified: Date.now() + }; +} + +/** + * Serialize meta to JSON string + * 将元数据序列化为 JSON 字符串 + */ +export function serializeAssetMeta(meta: IAssetMeta): string { + return JSON.stringify(meta, null, 2); +} + +/** + * Parse meta from JSON string + * 从 JSON 字符串解析元数据 + */ +export function parseAssetMeta(json: string): IAssetMeta { + const meta = JSON.parse(json) as IAssetMeta; + + // Validate required fields + if (!meta.guid || typeof meta.guid !== 'string') { + throw new Error('Invalid meta file: missing or invalid guid'); + } + if (!meta.type || typeof meta.type !== 'string') { + throw new Error('Invalid meta file: missing or invalid type'); + } + + // Set defaults for optional fields + meta.version = meta.version || 1; + meta.labels = meta.labels || []; + meta.importSettings = meta.importSettings || {}; + + return meta; +} + +/** + * Validate GUID format (UUID v4) + * 验证 GUID 格式 (UUID v4) + */ +export function isValidGUID(guid: string): boolean { + const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; + return uuidRegex.test(guid); +} + +/** + * Asset Meta File Manager + * 资产元数据文件管理器 + * + * Handles reading/writing .meta files through a file system interface. + */ +export class AssetMetaManager { + private _cache = new Map(); + private _guidToPath = new Map(); + + /** + * File system interface for reading/writing files + * 用于读写文件的文件系统接口 + */ + private _fs: IMetaFileSystem | null = null; + + /** + * Set file system interface + * 设置文件系统接口 + */ + setFileSystem(fs: IMetaFileSystem): void { + this._fs = fs; + } + + /** + * Get or create meta for an asset + * 获取或创建资产的元数据 + */ + async getOrCreateMeta(assetPath: string): Promise { + // Check cache first + const cached = this._cache.get(assetPath); + if (cached) { + return cached; + } + + const metaPath = getMetaFilePath(assetPath); + + // Try to read existing meta file + if (this._fs) { + try { + if (await this._fs.exists(metaPath)) { + const content = await this._fs.readText(metaPath); + const meta = parseAssetMeta(content); + this._cache.set(assetPath, meta); + this._guidToPath.set(meta.guid, assetPath); + return meta; + } + } catch (e) { + console.warn(`Failed to read meta file: ${metaPath}`, e); + } + } + + // Create new meta + const meta = createAssetMeta(assetPath); + this._cache.set(assetPath, meta); + this._guidToPath.set(meta.guid, assetPath); + + // Save to file system + if (this._fs) { + try { + await this._fs.writeText(metaPath, serializeAssetMeta(meta)); + } catch (e) { + console.warn(`Failed to write meta file: ${metaPath}`, e); + } + } + + return meta; + } + + /** + * Get meta by GUID + * 根据 GUID 获取元数据 + */ + getMetaByGUID(guid: AssetGUID): IAssetMeta | undefined { + const path = this._guidToPath.get(guid); + return path ? this._cache.get(path) : undefined; + } + + /** + * Get asset path by GUID + * 根据 GUID 获取资产路径 + */ + getPathByGUID(guid: AssetGUID): string | undefined { + return this._guidToPath.get(guid); + } + + /** + * Get GUID by asset path + * 根据资产路径获取 GUID + */ + async getGUIDByPath(assetPath: string): Promise { + const meta = await this.getOrCreateMeta(assetPath); + return meta.guid; + } + + /** + * Update meta and save + * 更新元数据并保存 + */ + async updateMeta(assetPath: string, updates: Partial): Promise { + const meta = await this.getOrCreateMeta(assetPath); + + // Apply updates + Object.assign(meta, updates); + meta.lastModified = Date.now(); + meta.version++; + + // Update cache + this._cache.set(assetPath, meta); + + // Handle GUID change (rare, but possible) + if (updates.guid && updates.guid !== meta.guid) { + this._guidToPath.delete(meta.guid); + this._guidToPath.set(updates.guid, assetPath); + } + + // Save to file system + if (this._fs) { + const metaPath = getMetaFilePath(assetPath); + await this._fs.writeText(metaPath, serializeAssetMeta(meta)); + } + } + + /** + * Handle asset rename + * 处理资产重命名 + */ + async handleAssetRename(oldPath: string, newPath: string): Promise { + const meta = this._cache.get(oldPath); + if (meta) { + // Update cache with new path + this._cache.delete(oldPath); + this._cache.set(newPath, meta); + this._guidToPath.set(meta.guid, newPath); + + // Move meta file + if (this._fs) { + const oldMetaPath = getMetaFilePath(oldPath); + const newMetaPath = getMetaFilePath(newPath); + + if (await this._fs.exists(oldMetaPath)) { + const content = await this._fs.readText(oldMetaPath); + await this._fs.writeText(newMetaPath, content); + await this._fs.delete(oldMetaPath); + } + } + } + } + + /** + * Handle asset delete + * 处理资产删除 + */ + async handleAssetDelete(assetPath: string): Promise { + const meta = this._cache.get(assetPath); + if (meta) { + this._cache.delete(assetPath); + this._guidToPath.delete(meta.guid); + + // Delete meta file + if (this._fs) { + const metaPath = getMetaFilePath(assetPath); + if (await this._fs.exists(metaPath)) { + await this._fs.delete(metaPath); + } + } + } + } + + /** + * Clear cache + * 清除缓存 + */ + clear(): void { + this._cache.clear(); + this._guidToPath.clear(); + } + + /** + * Get all cached metas + * 获取所有缓存的元数据 + */ + getAllMetas(): Map { + return new Map(this._cache); + } +} + +/** + * File system interface for meta file operations + * 元数据文件操作的文件系统接口 + */ +export interface IMetaFileSystem { + exists(path: string): Promise; + readText(path: string): Promise; + writeText(path: string, content: string): Promise; + delete(path: string): Promise; +} diff --git a/packages/asset-system-editor/src/packing/AssetPacker.ts b/packages/asset-system-editor/src/packing/AssetPacker.ts new file mode 100644 index 00000000..61c89656 --- /dev/null +++ b/packages/asset-system-editor/src/packing/AssetPacker.ts @@ -0,0 +1,408 @@ +/** + * Asset Packer + * 资产打包器 + * + * Collects and packs assets into bundles for runtime loading. + * 收集并将资产打包成运行时加载的包。 + */ + +import { + AssetGUID, + AssetType, + IBundleManifest, + IBundleAssetInfo, + IRuntimeCatalog, + IRuntimeBundleInfo, + IRuntimeAssetLocation, + IAssetToPack, + IBundlePackOptions +} from '@esengine/asset-system'; +import { IAssetMeta } from '../meta/AssetMetaFile'; + +/** + * Packing result + * 打包结果 + */ +export interface IPackingResult { + /** Generated bundles | 生成的包 */ + bundles: IPackedBundle[]; + /** Runtime catalog | 运行时目录 */ + catalog: IRuntimeCatalog; + /** Total size in bytes | 总大小 */ + totalSize: number; + /** Number of assets packed | 打包的资产数量 */ + assetCount: number; + /** Packing duration in ms | 打包耗时 */ + duration: number; +} + +/** + * Packed bundle + * 已打包的包 + */ +export interface IPackedBundle { + /** Bundle name | 包名称 */ + name: string; + /** Bundle data | 包数据 */ + data: ArrayBuffer; + /** Bundle manifest | 包清单 */ + manifest: IBundleManifest; +} + +/** + * Asset file reader interface + * 资产文件读取器接口 + */ +export interface IAssetFileReader { + readBinary(path: string): Promise; + readText(path: string): Promise; + exists(path: string): Promise; +} + +/** + * Asset Packer + * 资产打包器 + */ +export class AssetPacker { + private _fileReader: IAssetFileReader | null = null; + private _assets: IAssetToPack[] = []; + private _metas = new Map(); + + /** + * Set file reader for loading asset data + * 设置用于加载资产数据的文件读取器 + */ + setFileReader(reader: IAssetFileReader): void { + this._fileReader = reader; + } + + /** + * Add asset to pack + * 添加要打包的资产 + */ + addAsset(asset: IAssetToPack, meta?: IAssetMeta): void { + this._assets.push(asset); + if (meta) { + this._metas.set(asset.guid, meta); + } + } + + /** + * Add multiple assets + * 添加多个资产 + */ + addAssets(assets: IAssetToPack[]): void { + for (const asset of assets) { + this.addAsset(asset); + } + } + + /** + * Clear all added assets + * 清除所有已添加的资产 + */ + clear(): void { + this._assets = []; + this._metas.clear(); + } + + /** + * Pack assets into bundles + * 将资产打包成包 + */ + async pack(options: IBundlePackOptions = { name: 'main' }): Promise { + const startTime = Date.now(); + + // Group assets for bundling + const groups = this._groupAssets(options); + + // Pack each group into a bundle + const bundles: IPackedBundle[] = []; + const catalogAssets: Record = {}; + const catalogBundles: Record = {}; + + for (const [bundleName, assets] of groups) { + const packed = await this._packBundle(bundleName, assets, options); + bundles.push(packed); + + // Add to catalog + catalogBundles[bundleName] = { + url: `assets/${bundleName}.bundle`, + size: packed.data.byteLength, + hash: await this._hashBuffer(packed.data), + preload: bundleName === 'core' || bundleName === 'main' + }; + + // Add asset locations + for (const assetInfo of packed.manifest.assets) { + catalogAssets[assetInfo.guid] = { + bundle: bundleName, + offset: assetInfo.offset, + size: assetInfo.size, + type: assetInfo.type, + name: assetInfo.name + }; + } + } + + // Create catalog + const catalog: IRuntimeCatalog = { + version: '1.0', + createdAt: Date.now(), + bundles: catalogBundles, + assets: catalogAssets + }; + + const totalSize = bundles.reduce((sum, b) => sum + b.data.byteLength, 0); + + return { + bundles, + catalog, + totalSize, + assetCount: this._assets.length, + duration: Date.now() - startTime + }; + } + + /** + * Pack assets by type (textures.bundle, audio.bundle, etc.) + * 按类型打包资产 + */ + async packByType(): Promise { + return this.pack({ + name: 'main', + groupByType: true + }); + } + + /** + * Group assets for bundling + * 分组资产以便打包 + */ + private _groupAssets(options: IBundlePackOptions): Map { + const groups = new Map(); + + if (options.groupByType) { + // Group by asset type + for (const asset of this._assets) { + const bundleName = this._getBundleNameForType(asset.type); + const group = groups.get(bundleName) || []; + group.push(asset); + groups.set(bundleName, group); + } + } else { + // Single bundle + groups.set(options.name, [...this._assets]); + } + + // Handle max size splitting + if (options.maxSize) { + const splitGroups = new Map(); + + for (const [name, assets] of groups) { + let currentSize = 0; + let partIndex = 0; + let currentGroup: IAssetToPack[] = []; + + for (const asset of assets) { + const assetSize = asset.data?.byteLength || 0; + + if (currentSize + assetSize > options.maxSize && currentGroup.length > 0) { + splitGroups.set(`${name}_${partIndex}`, currentGroup); + partIndex++; + currentGroup = []; + currentSize = 0; + } + + currentGroup.push(asset); + currentSize += assetSize; + } + + if (currentGroup.length > 0) { + const finalName = partIndex > 0 ? `${name}_${partIndex}` : name; + splitGroups.set(finalName, currentGroup); + } + } + + return splitGroups; + } + + return groups; + } + + /** + * Get bundle name for asset type + * 获取资产类型的包名称 + */ + private _getBundleNameForType(type: AssetType): string { + const typeGroups: Record = { + textures: ['texture'], + audio: ['audio'], + data: ['json', 'text', 'binary', 'scene', 'prefab'], + fonts: ['font'], + shaders: ['shader', 'material'], + tilemaps: ['tilemap', 'tileset'], + scripts: ['behavior-tree', 'blueprint'] + }; + + for (const [bundleName, types] of Object.entries(typeGroups)) { + if (types.includes(type)) { + return bundleName; + } + } + + return 'misc'; + } + + /** + * Pack a single bundle + * 打包单个包 + */ + private async _packBundle( + name: string, + assets: IAssetToPack[], + _options: IBundlePackOptions + ): Promise { + const assetInfos: IBundleAssetInfo[] = []; + const dataChunks: ArrayBuffer[] = []; + let currentOffset = 0; + + // Load and pack each asset + for (const asset of assets) { + let data = asset.data; + + // Load data if not provided + if (!data && this._fileReader) { + try { + data = await this._fileReader.readBinary(asset.path); + } catch (e) { + console.warn(`[AssetPacker] Failed to load asset: ${asset.path}`, e); + continue; + } + } + + if (!data) { + console.warn(`[AssetPacker] No data for asset: ${asset.guid}`); + continue; + } + + // Align to 4 bytes + const padding = (4 - (data.byteLength % 4)) % 4; + const paddedSize = data.byteLength + padding; + + assetInfos.push({ + guid: asset.guid, + name: asset.name, + type: asset.type, + offset: currentOffset, + size: data.byteLength + }); + + // Add data with padding + dataChunks.push(data); + if (padding > 0) { + dataChunks.push(new ArrayBuffer(padding)); + } + + currentOffset += paddedSize; + } + + // Combine all data + const totalSize = dataChunks.reduce((sum, chunk) => sum + chunk.byteLength, 0); + const bundleData = new Uint8Array(totalSize); + let offset = 0; + + for (const chunk of dataChunks) { + bundleData.set(new Uint8Array(chunk), offset); + offset += chunk.byteLength; + } + + // Create manifest + const manifest: IBundleManifest = { + name, + version: '1.0', + hash: await this._hashBuffer(bundleData.buffer), + compression: 'none', + size: bundleData.byteLength, + assets: assetInfos, + dependencies: [], + createdAt: Date.now() + }; + + return { + name, + data: bundleData.buffer, + manifest + }; + } + + /** + * Hash a buffer using SHA-256 + * 使用 SHA-256 哈希缓冲区 + */ + private async _hashBuffer(buffer: ArrayBuffer): Promise { + // Use Web Crypto API if available + if (typeof crypto !== 'undefined' && crypto.subtle) { + const hashBuffer = await crypto.subtle.digest('SHA-256', buffer); + const hashArray = Array.from(new Uint8Array(hashBuffer)); + return hashArray.map(b => b.toString(16).padStart(2, '0')).join('').slice(0, 16); + } + + // Fallback: simple hash + const view = new Uint8Array(buffer); + let hash = 0; + for (let i = 0; i < view.length; i++) { + hash = ((hash << 5) - hash) + view[i]; + hash = hash & hash; + } + return Math.abs(hash).toString(16).padStart(16, '0'); + } +} + +/** + * Collect assets referenced by a scene + * 收集场景引用的资产 + */ +export async function collectSceneAssets( + sceneData: unknown, + _metaManager: { getPathByGUID: (guid: AssetGUID) => string | undefined } +): Promise { + const guids = new Set(); + + // Recursively find all GUID references + function findGUIDs(obj: unknown): void { + if (!obj || typeof obj !== 'object') return; + + if (Array.isArray(obj)) { + for (const item of obj) { + findGUIDs(item); + } + return; + } + + const record = obj as Record; + + // Check for GUID fields + for (const [key, value] of Object.entries(record)) { + if (key.endsWith('Guid') || key.endsWith('GUID') || key === 'guid') { + if (typeof value === 'string' && isValidGUID(value)) { + guids.add(value); + } + } else if (typeof value === 'object') { + findGUIDs(value); + } + } + } + + findGUIDs(sceneData); + return Array.from(guids); +} + +/** + * Validate GUID format + * 验证 GUID 格式 + */ +function isValidGUID(guid: string): boolean { + const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; + return uuidRegex.test(guid); +} diff --git a/packages/asset-system-editor/tsconfig.json b/packages/asset-system-editor/tsconfig.json new file mode 100644 index 00000000..0a687de6 --- /dev/null +++ b/packages/asset-system-editor/tsconfig.json @@ -0,0 +1,36 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "declaration": true, + "declarationMap": true, + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": false, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "sourceMap": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "allowSyntheticDefaultImports": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"] +} diff --git a/packages/asset-system-editor/tsup.config.ts b/packages/asset-system-editor/tsup.config.ts new file mode 100644 index 00000000..0c49ea06 --- /dev/null +++ b/packages/asset-system-editor/tsup.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['src/index.ts'], + format: ['esm'], + dts: true, + clean: true, + sourcemap: true, + external: ['@esengine/asset-system'] +});