mirror of
https://github.com/motajs/template.git
synced 2026-11-01 06:04:30 +08:00
218 lines
7.7 KiB
TypeScript
218 lines
7.7 KiB
TypeScript
import {
|
|
mkdtemp,
|
|
mkdir,
|
|
readFile,
|
|
rm,
|
|
stat,
|
|
writeFile
|
|
} from 'node:fs/promises';
|
|
import { tmpdir } from 'node:os';
|
|
import { dirname, join } from 'node:path';
|
|
import { afterEach, describe, expect, it } from 'vitest';
|
|
import { buildContent } from '../build-resource';
|
|
|
|
const tempDirs: string[] = [];
|
|
|
|
/** 创建独立的临时 fixture 根目录,并登记以便用例结束后统一清理 */
|
|
async function createRoot() {
|
|
const root = await mkdtemp(join(tmpdir(), 'mota-content-filter-'));
|
|
tempDirs.push(root);
|
|
return root;
|
|
}
|
|
|
|
/** 在 fixture 的源目录下写入文件,必要时创建父目录 */
|
|
async function writeSource(
|
|
root: string,
|
|
name: string,
|
|
content: string | Buffer
|
|
) {
|
|
const file = join(root, 'src', name);
|
|
await mkdir(dirname(file), { recursive: true });
|
|
await writeFile(file, content);
|
|
return file;
|
|
}
|
|
|
|
/** 以空字符集执行一次 content 构建 */
|
|
function buildFixture(root: string) {
|
|
return buildContent({
|
|
sourceDir: join(root, 'src'),
|
|
outputDir: join(root, 'out'),
|
|
chars: ''
|
|
});
|
|
}
|
|
|
|
/** 读取输出目录中的文本文件 */
|
|
function readOutput(root: string, name: string) {
|
|
return readFile(join(root, 'out', name), 'utf-8');
|
|
}
|
|
|
|
/** 判断输出目录中是否存在指定文件 */
|
|
async function outputExists(root: string, name: string) {
|
|
try {
|
|
await stat(join(root, 'out', name));
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
afterEach(async () => {
|
|
const dirs = tempDirs.splice(0);
|
|
await Promise.all(
|
|
dirs.map(dir => rm(dir, { recursive: true, force: true }))
|
|
);
|
|
});
|
|
|
|
describe('buildContent', () => {
|
|
// 根目录的 jsonc 必须去掉整行注释并压成纯 JSON,后缀保持不变
|
|
it('minifies a root jsonc file', async () => {
|
|
const root = await createRoot();
|
|
await writeSource(
|
|
root,
|
|
'core.jsonc',
|
|
'// Type: IGameCore\n// --- SYSTEM PREFIX END --- //\n{ "floorId": "MT0" }\n'
|
|
);
|
|
|
|
const stats = await buildFixture(root);
|
|
const output = await readOutput(root, 'core.jsonc');
|
|
|
|
expect(JSON.parse(output)).toEqual({ floorId: 'MT0' });
|
|
expect(output).not.toContain('//');
|
|
expect(stats.jsonc).toBe(1);
|
|
});
|
|
|
|
// 根目录即使出现 .list.jsonc 也必须全量输出,根调用显式跳过清单过滤
|
|
it('keeps every root file even when a root list exists', async () => {
|
|
const root = await createRoot();
|
|
await writeSource(root, '.list.jsonc', '["core"]\n');
|
|
await writeSource(root, 'core.jsonc', '{ "value": 1 }\n');
|
|
await writeSource(root, 'other.jsonc', '{ "value": 2 }\n');
|
|
|
|
await buildFixture(root);
|
|
|
|
expect(await outputExists(root, 'core.jsonc')).toBe(true);
|
|
expect(await outputExists(root, 'other.jsonc')).toBe(true);
|
|
expect(await outputExists(root, '.list.jsonc')).toBe(true);
|
|
});
|
|
|
|
// defaults 目录即使存在 .list.jsonc 也必须全量输出并压缩
|
|
it('keeps every defaults file even when a defaults list exists', async () => {
|
|
const root = await createRoot();
|
|
await writeSource(root, 'defaults/.list.jsonc', '["env"]\n');
|
|
await writeSource(
|
|
root,
|
|
'defaults/env.jsonc',
|
|
'// Type: env\n{ "value": 1 }\n'
|
|
);
|
|
await writeSource(root, 'defaults/other.jsonc', '{ "value": 2 }\n');
|
|
|
|
await buildFixture(root);
|
|
|
|
expect(await outputExists(root, 'defaults/env.jsonc')).toBe(true);
|
|
expect(await outputExists(root, 'defaults/other.jsonc')).toBe(true);
|
|
expect(await outputExists(root, 'defaults/.list.jsonc')).toBe(true);
|
|
expect(await readOutput(root, 'defaults/other.jsonc')).not.toContain(
|
|
'//'
|
|
);
|
|
expect(
|
|
JSON.parse(await readOutput(root, 'defaults/.list.jsonc'))
|
|
).toEqual(['env']);
|
|
});
|
|
|
|
// maps 清单带注释时先剥离注释,再按清单保留文件并剔除未引用文件
|
|
it('filters a maps directory by its list', async () => {
|
|
const root = await createRoot();
|
|
await writeSource(
|
|
root,
|
|
'maps/.list.jsonc',
|
|
'// Type: string[], without .jsonc suffix\n// --- SYSTEM PREFIX END --- //\n["keep"]\n'
|
|
);
|
|
await writeSource(root, 'maps/keep.jsonc', '{ "value": "keep" }\n');
|
|
await writeSource(root, 'maps/drop.jsonc', '{ "value": "drop" }\n');
|
|
|
|
await buildFixture(root);
|
|
|
|
expect(await outputExists(root, 'maps/keep.jsonc')).toBe(true);
|
|
expect(await outputExists(root, 'maps/drop.jsonc')).toBe(false);
|
|
expect(await outputExists(root, 'maps/.list.jsonc')).toBe(true);
|
|
const list = await readOutput(root, 'maps/.list.jsonc');
|
|
expect(list).not.toContain('//');
|
|
expect(JSON.parse(list)).toEqual(['keep']);
|
|
});
|
|
|
|
// texture 清单是对象形态且使用完整文件名,命中文件按字节原样拷贝
|
|
it('filters a texture directory by object list and full file name', async () => {
|
|
const root = await createRoot();
|
|
await writeSource(
|
|
root,
|
|
'texture/.list.jsonc',
|
|
'{"textures":[{"type":"grid","source":"a.png"}]}\n'
|
|
);
|
|
const bytes = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x01, 0x02]);
|
|
await writeSource(root, 'texture/a.png', bytes);
|
|
await writeSource(root, 'texture/b.png', Buffer.from([0x03]));
|
|
|
|
await buildFixture(root);
|
|
|
|
expect(await outputExists(root, 'texture/a.png')).toBe(true);
|
|
expect(await outputExists(root, 'texture/b.png')).toBe(false);
|
|
const output = await readFile(join(root, 'out', 'texture', 'a.png'));
|
|
expect(Buffer.compare(output, bytes)).toBe(0);
|
|
});
|
|
|
|
// font 清单按完整文件名保留,未引用文件被剔除
|
|
it('filters a font directory by its list', async () => {
|
|
const root = await createRoot();
|
|
await writeSource(root, 'font/.list.jsonc', '["ok.fake"]\n');
|
|
await writeSource(root, 'font/ok.fake', 'ok');
|
|
await writeSource(root, 'font/skip.fake', 'skip');
|
|
|
|
await buildFixture(root);
|
|
|
|
expect(await outputExists(root, 'font/ok.fake')).toBe(true);
|
|
expect(await outputExists(root, 'font/skip.fake')).toBe(false);
|
|
});
|
|
|
|
// 没有清单的非 defaults 子文件夹必须全量输出
|
|
it('keeps every file in a sub directory without a list', async () => {
|
|
const root = await createRoot();
|
|
await writeSource(
|
|
root,
|
|
'extra/free.jsonc',
|
|
'// Type: free\n{ "value": 1 }\n'
|
|
);
|
|
await writeSource(root, 'extra/free.txt', 'free');
|
|
|
|
await buildFixture(root);
|
|
|
|
expect(await outputExists(root, 'extra/free.txt')).toBe(true);
|
|
expect(await readOutput(root, 'extra/free.jsonc')).not.toContain('//');
|
|
});
|
|
|
|
// 根目录的非 jsonc 文件按原样拷贝
|
|
it('copies a root non-jsonc file verbatim', async () => {
|
|
const root = await createRoot();
|
|
const source = 'export const item = 1;\n';
|
|
await writeSource(root, 'item.ts', source);
|
|
|
|
await buildFixture(root);
|
|
|
|
expect(await readOutput(root, 'item.ts')).toBe(source);
|
|
});
|
|
|
|
// 统计结果必须与实际输出文件数一致
|
|
it('reports stats matching the emitted files', async () => {
|
|
const root = await createRoot();
|
|
await writeSource(root, 'core.jsonc', '{ "value": 1 }\n');
|
|
await writeSource(root, 'maps/.list.jsonc', '["keep"]\n');
|
|
await writeSource(root, 'maps/keep.jsonc', '{ "value": 2 }\n');
|
|
await writeSource(root, 'maps/drop.jsonc', '{ "value": 3 }\n');
|
|
|
|
const stats = await buildFixture(root);
|
|
|
|
expect(stats.files).toBe(3);
|
|
expect(stats.jsonc).toBe(3);
|
|
expect(stats.fonts).toBe(0);
|
|
});
|
|
});
|