diff --git a/cocoscreator_projects/scripts/lib/paths.mjs b/cocoscreator_projects/scripts/lib/paths.mjs new file mode 100644 index 0000000..721620e --- /dev/null +++ b/cocoscreator_projects/scripts/lib/paths.mjs @@ -0,0 +1,27 @@ +import { fileURLToPath } from 'node:url'; +import { dirname, join, resolve } from 'node:path'; +import { readFileSync, readdirSync, existsSync } from 'node:fs'; + +// 本文件位于 /scripts/lib/paths.mjs → 上溯两级为 monorepo 根 +export const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..'); +export const HOST_PROJECT = join(ROOT, 'YouleNexus'); +export const FRAMEWORK_SRC = join(HOST_PROJECT, 'assets', 'framework'); +export const GAMES_DIR = join(ROOT, 'games'); +export const SEED_DIR = join(ROOT, 'templates', 'game-seed'); + +export function readCreatorVersion(projectDir) { + try { + const pkg = JSON.parse(readFileSync(join(projectDir, 'package.json'), 'utf8')); + return pkg?.creator?.version ?? null; + } catch { + return null; + } +} + +export function listGameProjects(gamesDir = GAMES_DIR) { + if (!existsSync(gamesDir)) return []; + return readdirSync(gamesDir, { withFileTypes: true }) + .filter((d) => d.isDirectory()) + .map((d) => join(gamesDir, d.name)) + .filter((dir) => existsSync(join(dir, 'package.json'))); +} diff --git a/cocoscreator_projects/scripts/test/helpers.mjs b/cocoscreator_projects/scripts/test/helpers.mjs new file mode 100644 index 0000000..6238a69 --- /dev/null +++ b/cocoscreator_projects/scripts/test/helpers.mjs @@ -0,0 +1,47 @@ +import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; + +// 构造一个临时 monorepo:YouleNexus(host) + framework 真源 + 空 games/ +export function makeTempMonorepo() { + const root = mkdtempSync(join(tmpdir(), 'youle-mono-')); + const host = join(root, 'YouleNexus'); + const framework = join(host, 'assets', 'framework'); + mkdirSync(framework, { recursive: true }); + writeFileSync( + join(host, 'package.json'), + JSON.stringify({ name: 'YouleNexus', uuid: 'host-uuid', creator: { version: '3.8.8' } }, null, 2) + ); + writeFileSync(join(framework, 'README.md'), '# framework src\n'); + const games = join(root, 'games'); + mkdirSync(games, { recursive: true }); + return { root, host, framework, games }; +} + +// 在 gamesDir 下造一个子游戏工程(含 package.json) +export function makeGameProject(gamesDir, name, version = '3.8.8') { + const dir = join(gamesDir, name); + mkdirSync(join(dir, 'assets'), { recursive: true }); + writeFileSync( + join(dir, 'package.json'), + JSON.stringify({ name, uuid: `${name}-uuid`, creator: { version } }, null, 2) + ); + return dir; +} + +// 造一个最小种子工程 +export function makeSeed(root) { + const seed = join(root, 'templates', 'game-seed'); + mkdirSync(join(seed, 'assets'), { recursive: true }); + mkdirSync(join(seed, 'settings'), { recursive: true }); + writeFileSync( + join(seed, 'package.json'), + JSON.stringify({ name: 'game-seed', uuid: 'seed-uuid', creator: { version: '3.8.8' } }, null, 2) + ); + writeFileSync(join(seed, 'settings', 'v2.json'), '{}\n'); + return seed; +} + +export function cleanup(root) { + rmSync(root, { recursive: true, force: true }); +} diff --git a/cocoscreator_projects/scripts/test/paths.test.mjs b/cocoscreator_projects/scripts/test/paths.test.mjs new file mode 100644 index 0000000..aba17da --- /dev/null +++ b/cocoscreator_projects/scripts/test/paths.test.mjs @@ -0,0 +1,44 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { join } from 'node:path'; +import { writeFileSync, mkdirSync } from 'node:fs'; +import { makeTempMonorepo, makeGameProject, cleanup } from './helpers.mjs'; +import { readCreatorVersion, listGameProjects } from '../lib/paths.mjs'; + +test('readCreatorVersion 读取 package.json 的 creator.version', () => { + const mono = makeTempMonorepo(); + try { + assert.equal(readCreatorVersion(mono.host), '3.8.8'); + } finally { + cleanup(mono.root); + } +}); + +test('readCreatorVersion 缺字段返回 null', () => { + const mono = makeTempMonorepo(); + try { + const dir = makeGameProject(mono.games, 'nover'); + // 覆写成无 creator 字段 + writeFileSync(join(dir, 'package.json'), JSON.stringify({ name: 'nover' })); + assert.equal(readCreatorVersion(dir), null); + } finally { + cleanup(mono.root); + } +}); + +test('listGameProjects 只列出含 package.json 的子目录', () => { + const mono = makeTempMonorepo(); + try { + makeGameProject(mono.games, 'doudizhu'); + makeGameProject(mono.games, 'niuniu'); + mkdirSync(join(mono.games, 'not-a-project')); // 无 package.json,应被忽略 + const found = listGameProjects(mono.games).map((p) => p.split(/[\\/]/).pop()).sort(); + assert.deepEqual(found, ['doudizhu', 'niuniu']); + } finally { + cleanup(mono.root); + } +}); + +test('listGameProjects 对不存在的目录返回空数组', () => { + assert.deepEqual(listGameProjects('/no/such/dir'), []); +});