From ff2c98a296d811c823f56bb4cb8d1f60344dcadc Mon Sep 17 00:00:00 2001 From: pan Date: Mon, 27 Jul 2026 16:17:06 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E5=88=A0=E9=99=A4=E6=95=B4=E4=B8=AA?= =?UTF-8?q?=20pixelhero-config-editor=20=E6=89=A9=E5=B1=95=E7=9B=AE?= =?UTF-8?q?=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除了该扩展的所有文件,包括配置编辑器源码、测试用例、构建配置、国际化文件等所有相关内容 --- extensions/pixelhero-config-editor/.gitignore | 3 - .../__tests__/.gitignore | 1 - .../__tests__/buildSkillDesc.test.ts | 25 - .../__tests__/fixtures/heroSet.sample.ts | 13 - .../__tests__/fixtures/skillSet.sample.ts | 16 - .../__tests__/parser.test.ts | 47 - .../__tests__/recordValue.serializer.test.ts | 44 - .../__tests__/tsConfigFile.test.ts | 101 -- .../__tests__/validation.test.ts | 67 - .../esbuild.config.mjs | 29 - extensions/pixelhero-config-editor/i18n/en.js | 4 - extensions/pixelhero-config-editor/i18n/zh.js | 4 - .../pixelhero-config-editor/package-lock.json | 1312 ----------------- .../pixelhero-config-editor/package.json | 48 - .../src/io/TsConfigFile.ts | 110 -- .../pixelhero-config-editor/src/io/parser.ts | 65 - .../src/io/recordValue.ts | 15 - .../src/io/serializer.ts | 32 - .../pixelhero-config-editor/src/main/index.ts | 48 - .../pixelhero-config-editor/src/main/store.ts | 85 -- .../src/panels/default/app.ts | 38 - .../src/panels/default/index.ts | 14 - .../src/shared/desc/buildSkillDesc.ts | 63 - .../src/shared/schema/enums.ts | 55 - .../src/shared/schema/field.ts | 14 - .../src/shared/schema/hero.ts | 33 - .../src/shared/schema/registry.ts | 10 - .../src/shared/schema/skill.ts | 41 - .../src/shared/schema/types.ts | 31 - .../src/shared/validation/index.ts | 107 -- .../static/style/default/index.css | 7 - .../static/template/default/index.html | 1 - .../pixelhero-config-editor/tsconfig.json | 15 - 33 files changed, 2498 deletions(-) delete mode 100644 extensions/pixelhero-config-editor/.gitignore delete mode 100644 extensions/pixelhero-config-editor/__tests__/.gitignore delete mode 100644 extensions/pixelhero-config-editor/__tests__/buildSkillDesc.test.ts delete mode 100644 extensions/pixelhero-config-editor/__tests__/fixtures/heroSet.sample.ts delete mode 100644 extensions/pixelhero-config-editor/__tests__/fixtures/skillSet.sample.ts delete mode 100644 extensions/pixelhero-config-editor/__tests__/parser.test.ts delete mode 100644 extensions/pixelhero-config-editor/__tests__/recordValue.serializer.test.ts delete mode 100644 extensions/pixelhero-config-editor/__tests__/tsConfigFile.test.ts delete mode 100644 extensions/pixelhero-config-editor/__tests__/validation.test.ts delete mode 100644 extensions/pixelhero-config-editor/esbuild.config.mjs delete mode 100644 extensions/pixelhero-config-editor/i18n/en.js delete mode 100644 extensions/pixelhero-config-editor/i18n/zh.js delete mode 100644 extensions/pixelhero-config-editor/package-lock.json delete mode 100644 extensions/pixelhero-config-editor/package.json delete mode 100644 extensions/pixelhero-config-editor/src/io/TsConfigFile.ts delete mode 100644 extensions/pixelhero-config-editor/src/io/parser.ts delete mode 100644 extensions/pixelhero-config-editor/src/io/recordValue.ts delete mode 100644 extensions/pixelhero-config-editor/src/io/serializer.ts delete mode 100644 extensions/pixelhero-config-editor/src/main/index.ts delete mode 100644 extensions/pixelhero-config-editor/src/main/store.ts delete mode 100644 extensions/pixelhero-config-editor/src/panels/default/app.ts delete mode 100644 extensions/pixelhero-config-editor/src/panels/default/index.ts delete mode 100644 extensions/pixelhero-config-editor/src/shared/desc/buildSkillDesc.ts delete mode 100644 extensions/pixelhero-config-editor/src/shared/schema/enums.ts delete mode 100644 extensions/pixelhero-config-editor/src/shared/schema/field.ts delete mode 100644 extensions/pixelhero-config-editor/src/shared/schema/hero.ts delete mode 100644 extensions/pixelhero-config-editor/src/shared/schema/registry.ts delete mode 100644 extensions/pixelhero-config-editor/src/shared/schema/skill.ts delete mode 100644 extensions/pixelhero-config-editor/src/shared/schema/types.ts delete mode 100644 extensions/pixelhero-config-editor/src/shared/validation/index.ts delete mode 100644 extensions/pixelhero-config-editor/static/style/default/index.css delete mode 100644 extensions/pixelhero-config-editor/static/template/default/index.html delete mode 100644 extensions/pixelhero-config-editor/tsconfig.json diff --git a/extensions/pixelhero-config-editor/.gitignore b/extensions/pixelhero-config-editor/.gitignore deleted file mode 100644 index a7bdcfa6..00000000 --- a/extensions/pixelhero-config-editor/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules/ -dist/ -*.bak diff --git a/extensions/pixelhero-config-editor/__tests__/.gitignore b/extensions/pixelhero-config-editor/__tests__/.gitignore deleted file mode 100644 index 3018b3a6..00000000 --- a/extensions/pixelhero-config-editor/__tests__/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.tmp/ diff --git a/extensions/pixelhero-config-editor/__tests__/buildSkillDesc.test.ts b/extensions/pixelhero-config-editor/__tests__/buildSkillDesc.test.ts deleted file mode 100644 index 0ae3be92..00000000 --- a/extensions/pixelhero-config-editor/__tests__/buildSkillDesc.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { test } from 'node:test'; -import assert from 'node:assert/strict'; -import { buildSkillDesc } from '../src/shared/desc/buildSkillDesc'; -import { RecordValue } from '../src/io/recordValue'; - -const skillSet: Record = { - 6301: { kind: 'obj', props: { name: { kind: 'str', value: '护盾' }, kind: { kind: 'enumRef', qualifier: 'SkillKind', member: 'Shield' }, ap: { kind: 'num', value: 4 } } }, -}; -const fieldSet: Record = { - 7015: { kind: 'obj', props: { name: { kind: 'str', value: '死亡强化' }, info: { kind: 'str', value: '死亡触发技能次数+1' } } }, -}; -const hero: RecordValue = { kind: 'obj', props: { - atked: { kind: 'arr', items: [{ kind: 'obj', props: { s_uuid: { kind: 'num', value: 6301 }, t_num: { kind: 'num', value: 3 }, overrides: { kind: 'obj', props: { ap: { kind: 'num', value: 4 } } } } }] }, - field: { kind: 'arr', items: [{ kind: 'num', value: 7015 }] }, -} }; - -test('renders atked trigger with shield effect', () => { - const out = buildSkillDesc(hero, skillSet, fieldSet); - assert.match(out, /受击3次:护盾/); - assert.match(out, /护盾4次/); -}); -test('renders field aura', () => { - const out = buildSkillDesc(hero, skillSet, fieldSet); - assert.match(out, /场上存活:死亡强化 死亡触发技能次数\+1/); -}); diff --git a/extensions/pixelhero-config-editor/__tests__/fixtures/heroSet.sample.ts b/extensions/pixelhero-config-editor/__tests__/fixtures/heroSet.sample.ts deleted file mode 100644 index c1420e40..00000000 --- a/extensions/pixelhero-config-editor/__tests__/fixtures/heroSet.sample.ts +++ /dev/null @@ -1,13 +0,0 @@ -// 测试夹具:镜像真实 heroSet.ts 片段(speed 表达式 + 枚举引用 + 触发槽 + 驻场 + 复活) -export const HeroInfo: Record = { - 5011:{uuid:5011,name:"小铁卫",path:"hk1", fac:FacSet.HERO,pool_lv:1,lv:1,type:HType.Melee,hp:400,ap:20, - skills:{6001:{uuid:6001,lv:1,cd:AtkSpeedSet[AtkSpeedLv.Slow3].cd,ccd:0}}, - atked:[{s_uuid:6301,t_num:3,overrides:{TGroup:TGroup.Self,ap:4}}], - field:[7015], - revive:{s_uuid:6501,r_num:1,upr:0.3}, - info:"每受击3次为自身添加4层护盾"}, - 6001:{uuid:6001,name:"兽人战士",path:"m1", fac:FacSet.MON,lv:1,type:HType.Melee,hp:220,ap:10,speed:70, - skills:{6005:{uuid:6005,lv:1,cd:AtkSpeedSet[AtkSpeedLv.VerySlow1].cd,ccd:0}},info:"基础近战位怪"}, -}; - -export const HeroList: number[] = [5011]; diff --git a/extensions/pixelhero-config-editor/__tests__/fixtures/skillSet.sample.ts b/extensions/pixelhero-config-editor/__tests__/fixtures/skillSet.sample.ts deleted file mode 100644 index 881fb27f..00000000 --- a/extensions/pixelhero-config-editor/__tests__/fixtures/skillSet.sample.ts +++ /dev/null @@ -1,16 +0,0 @@ -// 测试夹具:镜像真实 SkillSet.ts 片段(含 SkillSet + FieldSkillSet) -export const SkillSet: Record = { - 6001:{uuid:6001,name:"火球",sp_name:"atk_1",icon:"Stat_Attack_01",TGroup:TGroup.Enemy,act:"atk", - DTType:DTType.single,ap:100,hit_count:1,hitcd:0.2,speed:720,with:0,ready:0.2, - IType:IType.Melee,RType:RType.bezier,EType:EType.collision,info:"造成攻击力100%的伤害"}, - 6301:{uuid:6301,name:"护盾",sp_name:"buff_wind",icon:"Stat_Defense",TGroup:TGroup.Self,act:"atk", - DTType:DTType.single,kind:SkillKind.Shield,ap:3,hit_count:1,hitcd:0.2,speed:720,with:0,ready:0.2, - IType:IType.support,RType:RType.fixed,EType:EType.animationEnd,info:"添加护盾"}, - 6501:{uuid:6501,name:"复活",sp_name:"buff_wind",icon:"Stat_HolyDamage",TGroup:TGroup.Self,act:"atk", - DTType:DTType.single,kind:SkillKind.Support,ap:50,hit_count:3,hitcd:0.2,speed:720,with:0,ready:0.2, - IType:IType.support,RType:RType.fixed,EType:EType.animationEnd,info:"复活百分比"}, -}; - -export const FieldSkillSet: Record = { - 7015:{uuid:7015,name:"死亡强化",icon:"Stat_PoisonChanceIncrease",type:FieldSkillType.DeadCount,value:1,info:"死亡触发技能次数+1"}, -}; diff --git a/extensions/pixelhero-config-editor/__tests__/parser.test.ts b/extensions/pixelhero-config-editor/__tests__/parser.test.ts deleted file mode 100644 index 13cd1d37..00000000 --- a/extensions/pixelhero-config-editor/__tests__/parser.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { test } from 'node:test'; -import assert from 'node:assert/strict'; -import * as ts from 'typescript'; -import { parseExpression, findExportObjectLiteral } from '../src/io/parser'; - -function parse(text: string): ts.Expression { - const src = ts.createSourceFile('x.ts', `const _ = ${text};`, ts.ScriptTarget.Latest, true); - const decl = src.statements[0] as ts.VariableStatement; - return decl.declarationList.declarations[0].initializer!; -} - -test('num / str / bool', () => { - assert.deepEqual(parseExpression(parse('400')), { kind: 'num', value: 400 }); - assert.deepEqual(parseExpression(parse('"小铁卫"')), { kind: 'str', value: '小铁卫' }); - assert.deepEqual(parseExpression(parse('true')), { kind: 'bool', value: true }); -}); -test('enumRef: FacSet.HERO', () => { - assert.deepEqual(parseExpression(parse('FacSet.HERO')), { kind: 'enumRef', qualifier: 'FacSet', member: 'HERO' }); -}); -test('speed: AtkSpeedSet[AtkSpeedLv.Slow3].cd', () => { - assert.deepEqual(parseExpression(parse('AtkSpeedSet[AtkSpeedLv.Slow3].cd')), { kind: 'speed', level: 'Slow3' }); -}); -test('non-Speed two-segment access falls back to enumRef', () => { - assert.deepEqual(parseExpression(parse('Foo.bar')), { kind: 'enumRef', qualifier: 'Foo', member: 'bar' }); -}); -test('arr', () => { - assert.deepEqual(parseExpression(parse('[1,2,3]')), { kind: 'arr', items: [ - { kind: 'num', value: 1 }, { kind: 'num', value: 2 }, { kind: 'num', value: 3 }] }); -}); -test('obj with numeric + identifier keys', () => { - const v = parseExpression(parse('{6001:{uuid:6001},name:"x"}')); - assert.equal(v.kind, 'obj'); - assert.deepEqual(v.props['6001'], { kind: 'obj', props: { uuid: { kind: 'num', value: 6001 } } }); - assert.deepEqual(v.props['name'], { kind: 'str', value: 'x' }); -}); -test('raw: unsupported expression preserved verbatim', () => { - const v = parseExpression(parse('a + b')); - assert.equal(v.kind, 'raw'); - assert.equal((v as any).text, 'a + b'); -}); -test('findExportObjectLiteral locates HeroInfo', () => { - const src = ts.createSourceFile('x.ts', - `export const HeroInfo: Record = { 5011:{uuid:5011} };`, ts.ScriptTarget.Latest, true); - const node = findExportObjectLiteral(src, 'HeroInfo'); - assert.ok(node); - assert.equal(node!.properties.length, 1); -}); diff --git a/extensions/pixelhero-config-editor/__tests__/recordValue.serializer.test.ts b/extensions/pixelhero-config-editor/__tests__/recordValue.serializer.test.ts deleted file mode 100644 index d4763688..00000000 --- a/extensions/pixelhero-config-editor/__tests__/recordValue.serializer.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { test } from 'node:test'; -import assert from 'node:assert/strict'; -import { serializeValue, serializeEntry } from '../src/io/serializer'; -import { RecordValue } from '../src/io/recordValue'; - -test('serializeValue: num/str/bool', () => { - assert.equal(serializeValue({ kind: 'num', value: 400 }), '400'); - assert.equal(serializeValue({ kind: 'str', value: '小铁卫' }), '"小铁卫"'); - assert.equal(serializeValue({ kind: 'bool', value: true }), 'true'); -}); -test('serializeValue: enumRef', () => { - const v: RecordValue = { kind: 'enumRef', qualifier: 'FacSet', member: 'HERO' }; - assert.equal(serializeValue(v), 'FacSet.HERO'); -}); -test('serializeValue: speed', () => { - const v: RecordValue = { kind: 'speed', level: 'Slow3' }; - assert.equal(serializeValue(v), 'AtkSpeedSet[AtkSpeedLv.Slow3].cd'); -}); -test('serializeValue: arr', () => { - const v: RecordValue = { kind: 'arr', items: [{ kind: 'num', value: 1 }, { kind: 'num', value: 2 }] }; - assert.equal(serializeValue(v), '[1,2]'); -}); -test('serializeValue: obj', () => { - const v: RecordValue = { kind: 'obj', props: { a: { kind: 'num', value: 1 }, b: { kind: 'str', value: 'x' } } }; - assert.equal(serializeValue(v), '{a:1,b:"x"}'); -}); -test('serializeValue: raw passthrough', () => { - const v: RecordValue = { kind: 'raw', text: 'a + b' }; - assert.equal(serializeValue(v), 'a + b'); -}); -test('serializeEntry: all-scalar one line with trailing comma', () => { - const v: RecordValue = { kind: 'obj', props: { uuid: { kind: 'num', value: 1 }, name: { kind: 'str', value: 'x' } } }; - assert.equal(serializeEntry('1', v), '1:{uuid:1,name:"x"},'); -}); -test('serializeEntry: nested on continuation lines', () => { - const v: RecordValue = { kind: 'obj', props: { - uuid: { kind: 'num', value: 5011 }, - skills: { kind: 'obj', props: { 6001: { kind: 'obj', props: { uuid: { kind: 'num', value: 6001 } } } } }, - } }; - const out = serializeEntry('5011', v); - assert.match(out, /^5011:\{uuid:5011,$/m); // 首行:键 + 标量 - assert.match(out, / skills:\{6001:\{uuid:6001\}\},$/m); // 续行 8 空格 - assert.match(out, /^ \},$/m); // 闭合 4 空格 -}); diff --git a/extensions/pixelhero-config-editor/__tests__/tsConfigFile.test.ts b/extensions/pixelhero-config-editor/__tests__/tsConfigFile.test.ts deleted file mode 100644 index 555da535..00000000 --- a/extensions/pixelhero-config-editor/__tests__/tsConfigFile.test.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { test } from 'node:test'; -import assert from 'node:assert/strict'; -import { readFileSync, copyFileSync, mkdtempSync, readdirSync } from 'node:fs'; -import { tmpdir } from 'node:os'; -import { fileURLToPath } from 'node:url'; -import { dirname, join } from 'node:path'; -import { TsConfigFile } from '../src/io/TsConfigFile'; - -const here = dirname(fileURLToPath(import.meta.url)); -const fixture = join(here, 'fixtures', 'heroSet.sample.ts'); - -test('load + getKeys', () => { - const f = new TsConfigFile(fixture, 'HeroInfo'); - f.load(); - assert.deepEqual(f.getKeys(), ['5011', '6001']); -}); -test('read returns structured value with speed/enumRef preserved', () => { - const f = new TsConfigFile(fixture, 'HeroInfo'); - f.load(); - const v = f.read('5011')!; - assert.equal(v.kind, 'obj'); - assert.deepEqual(v.props['fac'], { kind: 'enumRef', qualifier: 'FacSet', member: 'HERO' }); - const skill = v.props['skills'].props['6001']; - assert.deepEqual(skill.props['cd'], { kind: 'speed', level: 'Slow3' }); -}); -test('getText after load equals original file (no mutation on load)', () => { - const f = new TsConfigFile(fixture, 'HeroInfo'); - f.load(); - assert.equal(f.getText(), readFileSync(fixture, 'utf8')); -}); -test('read missing key returns null', () => { - const f = new TsConfigFile(fixture, 'HeroInfo'); - f.load(); - assert.equal(f.read('9999'), null); -}); - -function withTempFixture(): { dir: string; file: string } { - const dir = mkdtempSync(join(tmpdir(), 'phcfg-')); - const file = join(dir, 'heroSet.sample.ts'); - copyFileSync(fixture, file); - return { dir, file }; -} - -test('patch updates one entry; reload reads new value; other entries intact', () => { - const { file } = withTempFixture(); - const f = new TsConfigFile(file, 'HeroInfo'); f.load(); - const v = f.read('5011')!; - v.props['ap'] = { kind: 'num', value: 99 }; - f.patch('5011', v); - assert.equal(f.isDirty(), true); - assert.equal(f.save().ok, true); - const f2 = new TsConfigFile(file, 'HeroInfo'); f2.load(); - assert.deepEqual(f2.read('5011')!.props['ap'], { kind: 'num', value: 99 }); - assert.equal(f2.read('6001')!.props['name'].value, '兽人战士'); // 另一条未破坏 -}); - -test('patch preserves speed + enumRef on reload', () => { - const { file } = withTempFixture(); - const f = new TsConfigFile(file, 'HeroInfo'); f.load(); - const v = f.read('5011')!; - v.props['hp'] = { kind: 'num', value: 500 }; - f.patch('5011', v); f.save(); - const f2 = new TsConfigFile(file, 'HeroInfo'); f2.load(); - const again = f2.read('5011')!; - assert.deepEqual(again.props['fac'], { kind: 'enumRef', qualifier: 'FacSet', member: 'HERO' }); - assert.deepEqual(again.props['skills'].props['6001'].props['cd'], { kind: 'speed', level: 'Slow3' }); -}); - -test('add appends entry readable after save+reload', () => { - const { file } = withTempFixture(); - const f = new TsConfigFile(file, 'HeroInfo'); f.load(); - f.add('5099', { kind: 'obj', props: { uuid: { kind: 'num', value: 5099 }, name: { kind: 'str', value: '新英雄' } } }); - f.save(); - const f2 = new TsConfigFile(file, 'HeroInfo'); f2.load(); - assert.ok(f2.getKeys().includes('5099')); - assert.equal(f2.read('5099')!.props['name'].value, '新英雄'); -}); - -test('delete removes entry', () => { - const { file } = withTempFixture(); - const f = new TsConfigFile(file, 'HeroInfo'); f.load(); - f.delete('6001'); f.save(); - const f2 = new TsConfigFile(file, 'HeroInfo'); f2.load(); - assert.ok(!f2.getKeys().includes('6001')); - assert.ok(f2.getKeys().includes('5011')); -}); - -test('save writes a .bak backup of the pre-save file', () => { - const { file } = withTempFixture(); - const f = new TsConfigFile(file, 'HeroInfo'); f.load(); - const v = f.read('5011')!; v.props['hp'] = { kind: 'num', value: 1 }; f.patch('5011', v); - f.save(); - assert.equal(readFileSync(file + '.bak', 'utf8'), readFileSync(fixture, 'utf8')); -}); - -test('save with no edits is a no-op (ok, no .bak written)', () => { - const { file, dir } = withTempFixture(); - const f = new TsConfigFile(file, 'HeroInfo'); f.load(); - assert.equal(f.save().ok, true); - assert.equal(readdirSync(dir).some(p => p.endsWith('.bak')), false); -}); diff --git a/extensions/pixelhero-config-editor/__tests__/validation.test.ts b/extensions/pixelhero-config-editor/__tests__/validation.test.ts deleted file mode 100644 index 5def95d3..00000000 --- a/extensions/pixelhero-config-editor/__tests__/validation.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { test } from 'node:test'; -import assert from 'node:assert/strict'; -import { validate } from '../src/shared/validation'; -import { RecordValue } from '../src/io/recordValue'; - -const ctx = { - hasSkill: (u: number) => [6001, 6301, 6501].includes(u), - hasField: (u: number) => [7015].includes(u), - hasHero: (u: number) => [5011, 6001].includes(u), - heroListKeys: new Set(['5011']), -}; - -function heroObj(extra: Record = {}): RecordValue { - return { kind: 'obj', props: { - uuid: { kind: 'num', value: 5011 }, name: { kind: 'str', value: 'x' }, path: { kind: 'str', value: 'p' }, - fac: { kind: 'enumRef', qualifier: 'FacSet', member: 'HERO' }, lv: { kind: 'num', value: 1 }, - type: { kind: 'enumRef', qualifier: 'HType', member: 'Melee' }, hp: { kind: 'num', value: 400 }, - ap: { kind: 'num', value: 20 }, - skills: { kind: 'obj', props: { 6001: { kind: 'obj', props: { uuid: { kind: 'num', value: 6001 }, lv: { kind: 'num', value: 1 }, cd: { kind: 'speed', level: 'Slow3' }, ccd: { kind: 'num', value: 0 } } } } }, - info: { kind: 'str', value: 'ok' }, - ...extra, - } }; -} - -test('valid hero → no errors', () => { - const issues = validate('hero', new Map([['5011', heroObj()]]), ctx); - assert.equal(issues.filter(i => i.severity === 'error').length, 0); -}); -test('duplicate uuid → error', () => { - // 两条记录携带相同的 uuid 字段值(Map 键不同,uuid 字段相同) - const dup = heroObj(); // uuid=5011 - const issues = validate('hero', new Map([['5011', heroObj()], ['5012', dup]]), ctx); - assert.ok(issues.some(i => i.severity === 'error' && i.code === 'dup-uuid')); -}); -test('missing required field → error', () => { - const h = heroObj(); delete h.props['name']; - const issues = validate('hero', new Map([['5011', h]]), ctx); - assert.ok(issues.some(i => i.code === 'missing-required' && i.fieldPath === 'name')); -}); -test('trigger slot references missing skill → error', () => { - const h = heroObj({ atked: { kind: 'arr', items: [{ kind: 'obj', props: { - s_uuid: { kind: 'num', value: 9999 }, t_num: { kind: 'num', value: 3 } } }] } }); - const issues = validate('hero', new Map([['5011', h]]), ctx); - assert.ok(issues.some(i => i.code === 'dangling-ref')); -}); -test('field list references missing field skill → error', () => { - const h = heroObj({ field: { kind: 'arr', items: [{ kind: 'num', value: 8888 }] } }); - const issues = validate('hero', new Map([['5011', h]]), ctx); - assert.ok(issues.some(i => i.code === 'dangling-ref')); -}); -test('HeroList/hero consistency: fac=HERO entry missing from HeroList → error', () => { - const ctx2 = { ...ctx, heroListKeys: new Set([]) }; - const issues = validate('hero', new Map([['5011', heroObj()]]), ctx2); - assert.ok(issues.some(i => i.code === 'herolist-inconsistent')); -}); -test('invalid enum value → error', () => { - const h = heroObj({ fac: { kind: 'enumRef', qualifier: 'FacSet', member: 'NOPE' } }); - const issues = validate('hero', new Map([['5011', h]]), ctx); - assert.ok(issues.some(i => i.code === 'bad-enum')); -}); -test('unknown overrides key → error', () => { - const h = heroObj({ atked: { kind: 'arr', items: [{ kind: 'obj', props: { - s_uuid: { kind: 'num', value: 6301 }, t_num: { kind: 'num', value: 3 }, - overrides: { kind: 'obj', props: { bogus: { kind: 'num', value: 1 } } } } }] } }); - const issues = validate('hero', new Map([['5011', h]]), ctx); - assert.ok(issues.some(i => i.code === 'bad-override-key')); -}); diff --git a/extensions/pixelhero-config-editor/esbuild.config.mjs b/extensions/pixelhero-config-editor/esbuild.config.mjs deleted file mode 100644 index 034f4f75..00000000 --- a/extensions/pixelhero-config-editor/esbuild.config.mjs +++ /dev/null @@ -1,29 +0,0 @@ -import { build, context } from 'esbuild'; -import { readFileSync } from 'fs'; -import { join } from 'path'; - -const watch = process.argv.includes('--watch'); - -const common = { - bundle: true, - sourcemap: false, - logLevel: 'info', - alias: { 'vue': 'vue/dist/vue.esm-bundler.js' }, -}; - -// 面板进程在 Cocos 的 Electron 渲染层运行,可访问 Node 内建(fs/path),但 vue 必须 -// 打进浏览器侧 IIFE。因此面板项用 platform:'browser' + 把 node: 内建标为 external, -// 交由运行时解析;这样 esbuild 既不抱怨,又保持 plan 的"运行时读 static 文件"语义。 -const entries = [ - { entryPoints: ['src/main/index.ts'], outfile: 'dist/main.js', platform: 'node', format: 'cjs', external: [] }, - { entryPoints: ['src/panels/default/index.ts'], outfile: 'dist/panels/default.js', platform: 'browser', format: 'iife', external: ['node:fs', 'node:path'] }, -]; - -if (watch) { - for (const e of entries) { - const ctx = await context({ ...common, ...e }); - await ctx.watch(); - } -} else { - for (const e of entries) await build({ ...common, ...e }); -} diff --git a/extensions/pixelhero-config-editor/i18n/en.js b/extensions/pixelhero-config-editor/i18n/en.js deleted file mode 100644 index afc2d813..00000000 --- a/extensions/pixelhero-config-editor/i18n/en.js +++ /dev/null @@ -1,4 +0,0 @@ -exports.en = { - 'pixelhero-config-editor': { description: 'Hero/Skill Config Editor', title: 'Hero/Skill Config' }, - 'menu': { 'panel/英雄技能配置': 'Hero/Skill Config' }, -}; diff --git a/extensions/pixelhero-config-editor/i18n/zh.js b/extensions/pixelhero-config-editor/i18n/zh.js deleted file mode 100644 index 63e28ef4..00000000 --- a/extensions/pixelhero-config-editor/i18n/zh.js +++ /dev/null @@ -1,4 +0,0 @@ -exports.zh = { - 'pixelhero-config-editor': { description: '英雄/技能配置编辑器', title: '英雄/技能配置' }, - 'menu': { 'panel/英雄技能配置': '英雄技能配置' }, -}; diff --git a/extensions/pixelhero-config-editor/package-lock.json b/extensions/pixelhero-config-editor/package-lock.json deleted file mode 100644 index c6506cd3..00000000 --- a/extensions/pixelhero-config-editor/package-lock.json +++ /dev/null @@ -1,1312 +0,0 @@ -{ - "name": "pixelhero-config-editor", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "pixelhero-config-editor", - "version": "0.1.0", - "dependencies": { - "typescript": "^5.4.0", - "vue": "^3.4.0" - }, - "devDependencies": { - "@types/node": "^20.0.0", - "esbuild": "^0.20.0", - "fs-extra": "^11.0.0", - "tsx": "^4.7.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", - "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", - "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", - "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", - "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "20.19.43", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", - "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@vue/compiler-core": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.38.tgz", - "integrity": "sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.7", - "@vue/shared": "3.5.38", - "entities": "^7.0.1", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-dom": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.38.tgz", - "integrity": "sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==", - "license": "MIT", - "dependencies": { - "@vue/compiler-core": "3.5.38", - "@vue/shared": "3.5.38" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.38.tgz", - "integrity": "sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.7", - "@vue/compiler-core": "3.5.38", - "@vue/compiler-dom": "3.5.38", - "@vue/compiler-ssr": "3.5.38", - "@vue/shared": "3.5.38", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.21", - "postcss": "^8.5.15", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-ssr": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.38.tgz", - "integrity": "sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==", - "license": "MIT", - "dependencies": { - "@vue/compiler-dom": "3.5.38", - "@vue/shared": "3.5.38" - } - }, - "node_modules/@vue/reactivity": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.38.tgz", - "integrity": "sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==", - "license": "MIT", - "dependencies": { - "@vue/shared": "3.5.38" - } - }, - "node_modules/@vue/runtime-core": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.38.tgz", - "integrity": "sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==", - "license": "MIT", - "dependencies": { - "@vue/reactivity": "3.5.38", - "@vue/shared": "3.5.38" - } - }, - "node_modules/@vue/runtime-dom": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.38.tgz", - "integrity": "sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==", - "license": "MIT", - "dependencies": { - "@vue/reactivity": "3.5.38", - "@vue/runtime-core": "3.5.38", - "@vue/shared": "3.5.38", - "csstype": "^3.2.3" - } - }, - "node_modules/@vue/server-renderer": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.38.tgz", - "integrity": "sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==", - "license": "MIT", - "dependencies": { - "@vue/compiler-ssr": "3.5.38", - "@vue/shared": "3.5.38" - }, - "peerDependencies": { - "vue": "3.5.38" - } - }, - "node_modules/@vue/shared": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.38.tgz", - "integrity": "sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==", - "license": "MIT" - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" - }, - "node_modules/entities": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", - "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" - } - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "license": "MIT" - }, - "node_modules/fs-extra": { - "version": "11.3.5", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", - "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/jsonfile": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", - "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/nanoid": { - "version": "3.3.14", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.14.tgz", - "integrity": "sha512-U9kYi5bpVMEI31yC8iw4bJJp0avcHXA0W8/wNfLfnvJYzihQo2ZRPYPvpAAd570HAcCBjCTN7vnr+v4StKl1IQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.12", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tsx": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz", - "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.28.0" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", - "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", - "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", - "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", - "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", - "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", - "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", - "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", - "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", - "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", - "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", - "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-loong64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", - "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", - "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", - "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", - "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-s390x": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", - "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", - "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", - "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", - "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/sunos-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", - "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", - "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", - "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", - "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/esbuild": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", - "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.1", - "@esbuild/android-arm": "0.28.1", - "@esbuild/android-arm64": "0.28.1", - "@esbuild/android-x64": "0.28.1", - "@esbuild/darwin-arm64": "0.28.1", - "@esbuild/darwin-x64": "0.28.1", - "@esbuild/freebsd-arm64": "0.28.1", - "@esbuild/freebsd-x64": "0.28.1", - "@esbuild/linux-arm": "0.28.1", - "@esbuild/linux-arm64": "0.28.1", - "@esbuild/linux-ia32": "0.28.1", - "@esbuild/linux-loong64": "0.28.1", - "@esbuild/linux-mips64el": "0.28.1", - "@esbuild/linux-ppc64": "0.28.1", - "@esbuild/linux-riscv64": "0.28.1", - "@esbuild/linux-s390x": "0.28.1", - "@esbuild/linux-x64": "0.28.1", - "@esbuild/netbsd-arm64": "0.28.1", - "@esbuild/netbsd-x64": "0.28.1", - "@esbuild/openbsd-arm64": "0.28.1", - "@esbuild/openbsd-x64": "0.28.1", - "@esbuild/openharmony-arm64": "0.28.1", - "@esbuild/sunos-x64": "0.28.1", - "@esbuild/win32-arm64": "0.28.1", - "@esbuild/win32-ia32": "0.28.1", - "@esbuild/win32-x64": "0.28.1" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/vue": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.38.tgz", - "integrity": "sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==", - "license": "MIT", - "dependencies": { - "@vue/compiler-dom": "3.5.38", - "@vue/compiler-sfc": "3.5.38", - "@vue/runtime-dom": "3.5.38", - "@vue/server-renderer": "3.5.38", - "@vue/shared": "3.5.38" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - } - } -} diff --git a/extensions/pixelhero-config-editor/package.json b/extensions/pixelhero-config-editor/package.json deleted file mode 100644 index 8be767e8..00000000 --- a/extensions/pixelhero-config-editor/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "package_version": 2, - "name": "pixelhero-config-editor", - "version": "0.1.0", - "description": "英雄/技能配置编辑器", - "main": "./dist/main.js", - "author": "pixelhero", - "editor": ">=3.8.0", - "scripts": { - "build": "node esbuild.config.mjs", - "watch": "node esbuild.config.mjs --watch", - "test": "tsx --test __tests__/*.test.ts" - }, - "panels": { - "default": { - "title": "英雄/技能配置", - "type": "dockable", - "main": "./dist/panels/default.js", - "size": { "width": 960, "height": 640, "min-width": 640, "min-height": 480 } - } - }, - "contributions": { - "menu": [ - { "path": "PixelHero/英雄技能配置", "message": "open-panel" } - ], - "messages": { - "open-panel": { "methods": ["open-panel"] }, - "query-schema": { "methods": ["query-schema"] }, - "query-enums": { "methods": ["query-enums"] }, - "query-keys": { "methods": ["query-keys"] }, - "query-record": { "methods": ["query-record"] }, - "query-preview-desc": { "methods": ["query-preview-desc"] }, - "validate": { "methods": ["validate"] }, - "save-record": { "methods": ["save-record"] }, - "revert-record": { "methods": ["revert-record"] } - } - }, - "dependencies": { - "typescript": "^5.4.0", - "vue": "^3.4.0" - }, - "devDependencies": { - "@types/node": "^20.0.0", - "esbuild": "^0.20.0", - "fs-extra": "^11.0.0", - "tsx": "^4.7.0" - } -} diff --git a/extensions/pixelhero-config-editor/src/io/TsConfigFile.ts b/extensions/pixelhero-config-editor/src/io/TsConfigFile.ts deleted file mode 100644 index b8ee5215..00000000 --- a/extensions/pixelhero-config-editor/src/io/TsConfigFile.ts +++ /dev/null @@ -1,110 +0,0 @@ -import * as fs from 'node:fs'; -import * as ts from 'typescript'; -import { RecordValue } from './recordValue'; -import { findExportObjectLiteral, parseExpression } from './parser'; -import { serializeEntry } from './serializer'; - -/** - * 以"条目级 AST 区间替换"方式读写一个 `export const : Record = {...}` 配置文件。 - * 保留符号表达式(speed)与枚举引用(enumRef),未识别表达式原样保留(raw)。 - * save() 纯逻辑:仅做 fs 读写 + 语法校验(写 .bak);asset-db 刷新由主进程在 save 成功后调用。 - */ -export class TsConfigFile { - private sourceText = ''; - private sourceFile!: ts.SourceFile; - private targetNode!: ts.ObjectLiteralExpression; - private dirty = false; - - constructor(public readonly filePath: string, public readonly exportName: string) {} - - load(): void { - this.sourceText = fs.readFileSync(this.filePath, 'utf8'); - this.reparse(); - this.dirty = false; - } - - private reparse(): void { - // 第 4 参数 setParentNodes 必须为 true,否则 node.getStart()/getEnd() 不可用。 - this.sourceFile = ts.createSourceFile(this.filePath, this.sourceText, ts.ScriptTarget.Latest, true); - const node = findExportObjectLiteral(this.sourceFile, this.exportName); - if (!node) throw new Error(`export const ${this.exportName} not found or not an object literal in ${this.filePath}`); - this.targetNode = node; - } - - getKeys(): string[] { - return this.targetNode.properties.map(p => (p.name as ts.PropertyName).getText()); - } - - read(key: string): RecordValue | null { - const entry = this.findEntry(key); - if (!entry) return null; - return parseExpression(entry.initializer); - } - - private findEntry(key: string): ts.PropertyAssignment | undefined { - return this.targetNode.properties.find(p => (p.name as ts.PropertyName).getText() === key) as ts.PropertyAssignment | undefined; - } - - getText(): string { return this.sourceText; } - isDirty(): boolean { return this.dirty; } - - patch(key: string, value: RecordValue): void { - const entry = this.findEntry(key); - const newText = serializeEntry(key, value); - if (entry) { - const { start, end } = this.entrySpan(entry); - this.sourceText = this.sourceText.slice(0, start) + newText + this.sourceText.slice(end); - } else { - this.insertEntry(newText); - } - this.reparse(); - this.dirty = true; - } - - add(key: string, value: RecordValue): void { - if (this.findEntry(key)) throw new Error(`key ${key} already exists`); - this.insertEntry(serializeEntry(key, value)); - this.reparse(); - this.dirty = true; - } - - delete(key: string): void { - const entry = this.findEntry(key); - if (!entry) return; - const { start, end } = this.entrySpan(entry); - this.sourceText = this.sourceText.slice(0, start) + this.sourceText.slice(end); - this.reparse(); - this.dirty = true; - } - - save(): { ok: true } | { ok: false; error: string } { - if (!this.dirty) return { ok: true }; - const check = ts.createSourceFile(this.filePath, this.sourceText, ts.ScriptTarget.Latest, true); - if (check.parseDiagnostics.length > 0) { - const msg = check.parseDiagnostics.map(d => ts.flattenDiagnosticMessageText(d.messageText, '\n')).join('; '); - return { ok: false, error: `syntax error after edit: ${msg}` }; - } - // .bak 取自磁盘原始内容(落盘前的当前文件),保证可回滚。 - fs.writeFileSync(this.filePath + '.bak', fs.readFileSync(this.filePath)); - fs.writeFileSync(this.filePath, this.sourceText); - this.dirty = false; - return { ok: true }; - } - - /** 条目文本区间:从 key 词法起始(不含前导缩进 trivia,避免吞掉上一行换行)到尾随逗号止。 */ - private entrySpan(entry: ts.PropertyAssignment): { start: number; end: number } { - const start = entry.getStart(); - let end = entry.getEnd(); - const comma = /^\s*,/.exec(this.sourceText.slice(end)); - if (comma) end += comma[0].length; - return { start, end }; - } - - /** 在闭合 `}` 前追加一条新记录(4 空格缩进)。 */ - private insertEntry(entryText: string): void { - const closeBrace = this.targetNode.getLastToken(); - if (!closeBrace) throw new Error('object literal has no closing brace'); - const pos = closeBrace.getStart(); - this.sourceText = this.sourceText.slice(0, pos) + ` ${entryText}\n ` + this.sourceText.slice(pos); - } -} diff --git a/extensions/pixelhero-config-editor/src/io/parser.ts b/extensions/pixelhero-config-editor/src/io/parser.ts deleted file mode 100644 index 0bb14221..00000000 --- a/extensions/pixelhero-config-editor/src/io/parser.ts +++ /dev/null @@ -1,65 +0,0 @@ -import * as ts from 'typescript'; -import { RecordValue } from './recordValue'; - -/** 在 SourceFile 中查找 `export const = {...}`,返回其对象字面量节点。 */ -export function findExportObjectLiteral(src: ts.SourceFile, name: string): ts.ObjectLiteralExpression | null { - let result: ts.ObjectLiteralExpression | null = null; - const visit = (node: ts.Node) => { - if (result) return; - if (ts.isVariableStatement(node)) { - for (const d of node.declarationList.declarations) { - if (d.name.getText() === name && d.initializer && ts.isObjectLiteralExpression(d.initializer)) { - result = d.initializer; - return; - } - } - } - ts.forEachChild(node, visit); - }; - visit(src); - return result; -} - -/** 识别 `AtkSpeedSet[AtkSpeedLv.].cd`,否则 null。 */ -function tryParseSpeedExpr(node: ts.PropertyAccessExpression): RecordValue | null { - if (node.name.text !== 'cd') return null; - const inner = node.expression; - if (!ts.isElementAccessExpression(inner)) return null; - if (!ts.isIdentifier(inner.expression) || inner.expression.text !== 'AtkSpeedSet') return null; - const arg = inner.argumentExpression; - if (!ts.isPropertyAccessExpression(arg)) return null; - if (!ts.isIdentifier(arg.expression) || arg.expression.text !== 'AtkSpeedLv') return null; - return { kind: 'speed', level: arg.name.text }; -} - -export function parseExpression(node: ts.Expression): RecordValue { - if (ts.isNumericLiteral(node)) return { kind: 'num', value: Number(node.text) }; - if (ts.isStringLiteral(node)) return { kind: 'str', value: node.text }; - if (node.kind === ts.SyntaxKind.TrueKeyword) return { kind: 'bool', value: true }; - if (node.kind === ts.SyntaxKind.FalseKeyword) return { kind: 'bool', value: false }; - - if (ts.isPropertyAccessExpression(node)) { - const speed = tryParseSpeedExpr(node); - if (speed) return speed; - if (ts.isIdentifier(node.expression)) { - return { kind: 'enumRef', qualifier: node.expression.text, member: node.name.text }; - } - return { kind: 'raw', text: node.getText() }; // 多级 a.b.c 等 - } - - if (ts.isArrayLiteralExpression(node)) { - return { kind: 'arr', items: node.elements.map(e => parseExpression(e)) }; - } - - if (ts.isObjectLiteralExpression(node)) { - const props: Record = {}; - for (const m of node.properties) { - if (ts.isPropertyAssignment(m)) { - props[m.name.getText()] = parseExpression(m.initializer); - } - } - return { kind: 'obj', props }; - } - - return { kind: 'raw', text: node.getText() }; // 二元/模板/调用/其他元素访问 -} diff --git a/extensions/pixelhero-config-editor/src/io/recordValue.ts b/extensions/pixelhero-config-editor/src/io/recordValue.ts deleted file mode 100644 index a70953fe..00000000 --- a/extensions/pixelhero-config-editor/src/io/recordValue.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** IO 层对配置对象字面量值的结构化表示。零依赖。 */ -export type RecordValue = - | { kind: 'num'; value: number } - | { kind: 'str'; value: string } - | { kind: 'bool'; value: boolean } - | { kind: 'enumRef'; qualifier: string; member: string } // 如 FacSet.HERO - | { kind: 'speed'; level: string } // AtkSpeedSet[AtkSpeedLv.X].cd - | { kind: 'obj'; props: Record } - | { kind: 'arr'; items: RecordValue[] } - | { kind: 'raw'; text: string }; // 未识别表达式,原样保留 - -export function isScalar(v: RecordValue): boolean { - return v.kind === 'num' || v.kind === 'str' || v.kind === 'bool' - || v.kind === 'enumRef' || v.kind === 'speed' || v.kind === 'raw'; -} diff --git a/extensions/pixelhero-config-editor/src/io/serializer.ts b/extensions/pixelhero-config-editor/src/io/serializer.ts deleted file mode 100644 index af2956b6..00000000 --- a/extensions/pixelhero-config-editor/src/io/serializer.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { RecordValue, isScalar } from './recordValue'; - -export function serializeValue(v: RecordValue): string { - switch (v.kind) { - case 'num': return String(v.value); - case 'str': return JSON.stringify(v.value); - case 'bool': return String(v.value); - case 'enumRef': return `${v.qualifier}.${v.member}`; - case 'speed': return `AtkSpeedSet[AtkSpeedLv.${v.level}].cd`; - case 'arr': return `[${v.items.map(serializeValue).join(',')}]`; - case 'obj': { - const body = Object.entries(v.props).map(([k, val]) => `${k}:${serializeValue(val)}`).join(','); - return `{${body}}`; - } - case 'raw': return v.text; - } -} - -/** 序列化一条顶层记录。首行无缩进(缩进由调用处保留的 trivia 提供);嵌套字段 8 空格续行;闭合 4 空格。 */ -export function serializeEntry(key: string, obj: RecordValue): string { - if (obj.kind !== 'obj') return `${key}:${serializeValue(obj)},`; - const props = obj.props; - const keys = Object.keys(props); - const scalars = keys.filter(k => isScalar(props[k])); - const nested = keys.filter(k => !isScalar(props[k])); - const scalarTxt = scalars.map(k => `${k}:${serializeValue(props[k])}`).join(','); - if (nested.length === 0) return `${key}:{${scalarTxt}},`; - const lines = [`${key}:{${scalarTxt},`]; - for (const k of nested) lines.push(` ${k}:${serializeValue(props[k])},`); - lines.push(' },'); - return lines.join('\n'); -} diff --git a/extensions/pixelhero-config-editor/src/main/index.ts b/extensions/pixelhero-config-editor/src/main/index.ts deleted file mode 100644 index 797efba4..00000000 --- a/extensions/pixelhero-config-editor/src/main/index.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { store } from './store'; - -/** - * Cocos Creator 3.8 扩展主进程入口。 - * 关键约定(与官方 first/message 文档一致): - * - 处理函数必须挂在 `methods` 对象里(Cocos 读取 module.exports.methods), - * methods 的 key 必须与 package.json 中 contributions.messages[*].methods 引用的名字一致。 - * - 生命周期钩子为 `load`/`unload`(不是 onLoad)。 - * - 处理函数直接接收消息参数(无 event),返回值即 Editor.Message.request 的 resolve 结果。 - */ -function load() { - store.reloadAll(); -} -function unload() { - // 进程级单例随扩展卸载自然销毁,无需显式清理。 -} - -const methods: Record any> = { - 'open-panel'() { - Editor.Panel.open('pixelhero-config-editor'); - }, - 'query-schema'(id?: string) { - return store.querySchema(id as any); - }, - 'query-enums'() { - return store.queryEnums(); - }, - 'query-keys'(id: string) { - return store.queryKeys(id as any); - }, - 'query-record'(id: string, key: string) { - return store.queryRecord(id as any, key); - }, - 'query-preview-desc'(hero: any) { - return store.queryPreviewDesc(hero); - }, - 'validate'(id: string) { - return store.validate(id as any); - }, - 'save-record'(id: string, key: string, value: any) { - return store.saveRecord(id as any, key, value); - }, - 'revert-record'(id: string, key: string) { - return store.revertRecord(id as any, key); - }, -}; - -module.exports = { methods, load, unload }; diff --git a/extensions/pixelhero-config-editor/src/main/store.ts b/extensions/pixelhero-config-editor/src/main/store.ts deleted file mode 100644 index 2d0fdd63..00000000 --- a/extensions/pixelhero-config-editor/src/main/store.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { join } from 'node:path'; -import { TsConfigFile } from '../io/TsConfigFile'; -import { allSchemas } from '../shared/schema/registry'; -import { ENUMS } from '../shared/schema/enums'; -import { validate, ValidationContext } from '../shared/validation'; -import { buildSkillDesc } from '../shared/desc/buildSkillDesc'; -import { RecordValue } from '../io/recordValue'; -import { TableId } from '../shared/schema/types'; - -/** 游戏配置目录(相对项目根)。主进程用 Editor.Project.path 解析到项目根的 assets 配置目录。 */ -const CONFIG_DIR = join(Editor.Project.path, 'assets/script/game/common/config'); - -interface Entry { file: TsConfigFile; } -const tables: Partial> = {}; -// skill 与 field 共享 SkillSet.ts,但用不同 exportName 的 TsConfigFile 实例 -const fileCache: Record = {}; - -function getTable(id: TableId): Entry { - if (tables[id]) return tables[id]!; - const schema = allSchemas().find(s => s.id === id)!; - const cacheKey = `${schema.sourceFile}:${schema.exportName}`; - let file = fileCache[cacheKey]; - if (!file) { file = new TsConfigFile(join(CONFIG_DIR, schema.sourceFile), schema.exportName); file.load(); fileCache[cacheKey] = file; } - const entry = { file }; - tables[id] = entry; - return entry; -} - -function recordsOf(id: TableId): Map { - const { file } = getTable(id); - const m = new Map(); - for (const k of file.getKeys()) { const v = file.read(k); if (v) m.set(k, v); } - return m; -} - -function buildContext(): ValidationContext { - const hero = recordsOf('hero'); - const skill = recordsOf('skill'); - const field = recordsOf('field'); - const heroKeys = Array.from(hero.keys()).map(Number); - const skillKeys = Array.from(skill.keys()).map(Number); - const fieldKeys = Array.from(field.keys()).map(Number); - // HeroList 读取(hero 表的 listExportName) - const heroList = new TsConfigFile(join(CONFIG_DIR, 'heroSet.ts'), 'HeroList'); - heroList.load(); - const listRaw = heroList.getText(); - const heroListKeys = new Set( - (listRaw.match(/HeroList[\s\S]*?=\s*\[([^\]]*)\]/)?.[1].match(/-?\d+/g) ?? []).map(String) - ); - return { - hasHero: (u) => heroKeys.includes(u), - hasSkill: (u) => skillKeys.includes(u), - hasField: (u) => fieldKeys.includes(u), - heroListKeys, - }; -} - -export const store = { - queryEnums: () => ENUMS, - querySchema: (id?: TableId) => id ? allSchemas().find(s => s.id === id) : allSchemas(), - queryKeys: (id: TableId) => getTable(id).file.getKeys(), - queryRecord: (id: TableId, key: string) => getTable(id).file.read(key), - queryPreviewDesc: (hero: RecordValue) => { - const skill = recordsOf('skill'); const field = recordsOf('field'); - const skillSet: Record = {}; - for (const [k, v] of skill) skillSet[Number(k)] = v; - const fieldSet: Record = {}; - for (const [k, v] of field) fieldSet[Number(k)] = v; - return buildSkillDesc(hero, skillSet, fieldSet); - }, - validate: (id: TableId) => validate(id, recordsOf(id), buildContext()), - saveRecord: (id: TableId, key: string, value: RecordValue) => { - // 先在副本上试写并校验 - const { file } = getTable(id); - file.patch(key, value); - const issues = validate(id, recordsOf(id), buildContext()).filter(i => i.key === key && i.severity === 'error'); - if (issues.length) { file.load(); return { ok: false as const, issues }; } // 回滚内存 - const r = file.save(); - if (!r.ok) { file.load(); return { ok: false as const, issues: [] }; } - void Editor.Message.request('asset-db', 'refresh-asset', `db://assets/script/game/common/config/${allSchemas().find(s => s.id === id)!.sourceFile}`); - return { ok: true as const, issues: [] }; - }, - revertRecord: (id: TableId, key: string) => { getTable(id).file.load(); return getTable(id).file.read(key); }, - reloadAll: () => { for (const k of Object.keys(fileCache)) fileCache[k].load(); }, -}; diff --git a/extensions/pixelhero-config-editor/src/panels/default/app.ts b/extensions/pixelhero-config-editor/src/panels/default/app.ts deleted file mode 100644 index f17f4ce4..00000000 --- a/extensions/pixelhero-config-editor/src/panels/default/app.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { createApp, defineComponent, reactive } from 'vue'; - -export const App = defineComponent({ - setup() { - const state = reactive({ table: 'hero' as string, keys: [] as string[], picked: '' as string, detail: '' as string }); - async function load() { - const keys = await Editor.Message.request('pixelhero-config-editor', 'query-keys', state.table); - state.keys = keys || []; - state.picked = ''; state.detail = ''; - } - async function pick(k: string) { - state.picked = k; - const v = await Editor.Message.request('pixelhero-config-editor', 'query-record', state.table, k); - state.detail = JSON.stringify(v, null, 2); - } - load(); - return { state, load, pick }; - }, - template: ` -
-
- - - 共 {{ state.keys.length }} 条(端到端 IPC 已打通) -
-
    -
  • {{ k }}
  • -
-
{{ state.detail }}
-
- `, -}); - -export function mount(el: HTMLElement) { createApp(App).mount(el); } diff --git a/extensions/pixelhero-config-editor/src/panels/default/index.ts b/extensions/pixelhero-config-editor/src/panels/default/index.ts deleted file mode 100644 index 915f69d9..00000000 --- a/extensions/pixelhero-config-editor/src/panels/default/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { readFileSync } from 'node:fs'; -import { join } from 'node:path'; -import { mount } from './app'; - -const template = readFileSync(join(__dirname, '../../../static/template/default/index.html'), 'utf-8'); -const style = readFileSync(join(__dirname, '../../../static/style/default/index.css'), 'utf-8'); - -module.exports = Editor.Panel.define({ - template, - style, - $: { app: '#app' }, - ready() { mount(this.$.app); }, - close() { /* Vue 卸载随面板进程退出自动清理 */ }, -}); diff --git a/extensions/pixelhero-config-editor/src/shared/desc/buildSkillDesc.ts b/extensions/pixelhero-config-editor/src/shared/desc/buildSkillDesc.ts deleted file mode 100644 index 7732a2f3..00000000 --- a/extensions/pixelhero-config-editor/src/shared/desc/buildSkillDesc.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { RecordValue } from '../../io/recordValue'; - -const TRIGGER_KEYS = ['call', 'dead', 'fstart', 'fend', 'atking', 'atked'] as const; -const TRIGGER_DESC: Record = { - call: '召唤时', dead: '死亡时', fstart: '战斗开始时', fend: '战斗结束时', - field: '场上存活', atking: '攻击n次', atked: '受击n次', revive: '复活时', -}; - -function num(v: RecordValue | undefined): number | undefined { return v && v.kind === 'num' ? v.value : undefined; } -function str(v: RecordValue | undefined): string | undefined { return v && v.kind === 'str' ? v.value : undefined; } -function member(v: RecordValue | undefined): string | undefined { return v && v.kind === 'enumRef' ? v.member : undefined; } - -function buildEffect(merged: RecordValue): string { - if (merged.kind !== 'obj') return ''; - const kind = member(merged.props['kind']); - const ap = num(merged.props['ap']) ?? 0; - const parts: string[] = []; - if (kind === 'Heal') parts.push(`治疗伙伴${ap}`); - else if (kind === 'Shield') parts.push(`护盾${ap}次`); - else if (kind === 'Gold') parts.push(`金币+${num(merged.props['gold']) ?? 0}`); - else if (kind === 'Support') parts.push(String(str(merged.props['info']) ?? '')); - else { // Damage / undefined - parts.push(`伤害${ap}%`); - if ((num(merged.props['hit_count']) ?? 1) > 1) parts.push(`${num(merged.props['hit_count'])}段`); - if (num(merged.props['crt'])) parts.push(`暴击+${num(merged.props['crt'])}%`); - if (num(merged.props['stun'])) parts.push(`击晕+${num(merged.props['stun'])}%`); - } - return parts.join(' '); -} - -/** 合并 overrides 到 base(浅合并对象 props) */ -function merge(base: RecordValue, overrides: RecordValue | undefined): RecordValue { - if (!overrides || overrides.kind !== 'obj' || base.kind !== 'obj') return base; - return { kind: 'obj', props: { ...base.props, ...overrides.props } }; -} - -export function buildSkillDesc(hero: RecordValue, skillSet: Record, fieldSet: Record): string { - if (hero.kind !== 'obj') return ''; - const lines: string[] = []; - for (const key of TRIGGER_KEYS) { - const arr = hero.props[key]; - if (!arr || arr.kind !== 'arr') continue; - const tpl = TRIGGER_DESC[key] ?? key; - for (const it of arr.items) { - if (it.kind !== 'obj') continue; - const su = num(it.props['s_uuid']); if (su === undefined) continue; - const base = skillSet[su]; if (!base) continue; - const merged = merge(base, it.props['overrides']); - const trigger = tpl.includes('n') ? tpl.replace('n', String(num(it.props['t_num']) ?? '')) : tpl; - lines.push(`${trigger}:${str(base.props['name'])} ${buildEffect(merged)}`); - } - } - const fl = hero.props['field']; - if (fl && fl.kind === 'arr') { - for (const it of fl.items) { const u = num(it); if (u === undefined) continue; const fs = fieldSet[u]; if (fs) lines.push(`${TRIGGER_DESC.field}:${str(fs.props['name'])} ${str(fs.props['info'])}`); } - } - const rv = hero.props['revive']; - if (rv && rv.kind === 'obj') { - const su = num(rv.props['s_uuid']); const base = su !== undefined ? skillSet[su] : undefined; - if (base) lines.push(`${TRIGGER_DESC.revive} : ${str(base.props['name'])} ${buildEffect(merge(base, undefined))}`); - } - return lines.join('\n'); -} diff --git a/extensions/pixelhero-config-editor/src/shared/schema/enums.ts b/extensions/pixelhero-config-editor/src/shared/schema/enums.ts deleted file mode 100644 index 24fd231e..00000000 --- a/extensions/pixelhero-config-editor/src/shared/schema/enums.ts +++ /dev/null @@ -1,55 +0,0 @@ -export interface EnumMember { label: string; value: number | string; } -export interface EnumDef { qualifier: string; members: EnumMember[]; } - -export const ENUMS: Record = { - HType: { qualifier: 'HType', members: [ - { label: '近战 Melee', value: 0 }, { label: '中程 Mid', value: 1 }, { label: '远程 Long', value: 2 } ] }, - FacSet: { qualifier: 'FacSet', members: [ - { label: '英雄 HERO', value: 0 }, { label: '怪物 MON', value: 1 } ] }, - TGroup: { qualifier: 'TGroup', members: [ - { label: '自身 Self', value: 0 }, { label: '友方含己 Ally', value: 1 }, - { label: '友方 Team', value: 2 }, { label: '敌方 Enemy', value: 3 }, { label: '全体 All', value: 4 } ] }, - DTType: { qualifier: 'DTType', members: [ - { label: '单体 single', value: 0 }, { label: '范围 range', value: 1 }, { label: '3x3 aoe_grid', value: 2 } ] }, - SkillKind: { qualifier: 'SkillKind', members: [ - { label: '伤害 Damage', value: 0 }, { label: '治疗 Heal', value: 1 }, { label: '护盾 Shield', value: 2 }, - { label: '辅助 Support', value: 3 }, { label: '金币 Gold', value: 4 } ] }, - DType: { qualifier: 'DType', members: [ - { label: '物理 ATK', value: 0 }, { label: '冰 ICE', value: 1 }, { label: '火 FIRE', value: 2 }, { label: '风 WIND', value: 3 } ] }, - IType: { qualifier: 'IType', members: [ - { label: '近战 Melee', value: 0 }, { label: '远程 remote', value: 1 }, { label: '辅助 support', value: 2 } ] }, - RType: { qualifier: 'RType', members: [ - { label: '直线 linear', value: 0 }, { label: '贝塞尔 bezier', value: 1 }, - { label: '固定起点 fixed', value: 2 }, { label: '固定终点 fixedEnd', value: 3 } ] }, - EType: { qualifier: 'EType', members: [ - { label: '动画结束 animationEnd', value: 0 }, { label: '时间结束 timeEnd', value: 1 }, { label: '碰撞 collision', value: 2 } ] }, - FieldSkillType: { qualifier: 'FieldSkillType', members: [ - { label: '召唤次数 SummonCount', value: 1 }, { label: '死亡次数 DeadCount', value: 2 }, - { label: '开场次数 StartCount', value: 3 }, { label: '结束次数 EndCount', value: 4 }, - { label: '每波金币 WaveGold', value: 5 }, { label: '卖出金币 SellGold', value: 6 }, - { label: '战后回复 WaveHeal', value: 7 }, { label: '英雄攻击 HeroAtk', value: 8 }, - { label: '英雄击晕 HeroStun', value: 9 }, { label: '英雄暴击 HeroCrit', value: 10 }, - { label: '英雄暴伤 HeroCritDamage', value: 11 }, { label: '英雄攻速 HeroSpeed', value: 12 }, - { label: '购买优惠 BuyDiscount', value: 13 }, { label: '刷新优惠 RefreshDiscount', value: 14 }, - { label: '英雄生命 HeroHp', value: 16 }, { label: '英雄风怒 HeroWindFury', value: 17 }, - { label: '英雄穿刺 HeroPuncture', value: 18 }, { label: '攻击次数 AtkCount', value: 19 }, - { label: '受击次数 BeAtkCount', value: 20 } ] }, - AtkSpeedLv: { qualifier: 'AtkSpeedLv', members: [ - { label: '极速++ VeryFast1', value: 1 }, { label: '极速+ VeryFast2', value: 2 }, { label: '极速 VeryFast3', value: 3 }, - { label: '快速++ Fast1', value: 4 }, { label: '快速+ Fast2', value: 5 }, { label: '快速 Fast3', value: 6 }, - { label: '中速++ Normal1', value: 7 }, { label: '中速+ Normal2', value: 8 }, { label: '中速 Normal3', value: 9 }, - { label: '一般+ Mid1', value: 10 }, { label: '一般 Mid2', value: 11 }, { label: '一般- Mid3', value: 12 }, - { label: '慢 Slow1', value: 13 }, { label: '慢+ Slow2', value: 14 }, { label: '慢++ Slow3', value: 15 }, - { label: '很慢 VerySlow1', value: 16 }, { label: '很慢+ VerySlow2', value: 17 }, { label: '很慢++ VerySlow3', value: 18 } ] }, - Attrs: { qualifier: 'Attrs', members: [ - { label: 'ap', value: 'ap' }, { label: 'hp', value: 'hp' }, { label: 'hp_max', value: 'hp_max' }, - { label: 'critical', value: 'critical' }, { label: 'critical_damage', value: 'critical_damage' }, - { label: 'stun_chance', value: 'stun_chance' }, { label: 'puncture_chance', value: 'puncture_chance' }, - { label: 'wfuny', value: 'wfuny' }, { label: 'freeze_chance', value: 'freeze_chance' }, - { label: 'knockback_chance', value: 'knockback_chance' } ] }, -}; - -/** qualifier(如 'FacSet')→ 对应 enumId(如 'FacSet')。当前两者同名。 */ -export const QUALIFIER_TO_ID: Record = Object.fromEntries( - Object.entries(ENUMS).map(([id, def]) => [def.qualifier, id]) -); diff --git a/extensions/pixelhero-config-editor/src/shared/schema/field.ts b/extensions/pixelhero-config-editor/src/shared/schema/field.ts deleted file mode 100644 index c96d0543..00000000 --- a/extensions/pixelhero-config-editor/src/shared/schema/field.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { TableSchema } from './types'; -export const fieldSchema: TableSchema = { - id: 'field', label: '驻场技能', - sourceFile: 'SkillSet.ts', exportName: 'FieldSkillSet', - idSegments: [{ label: '驻场技能', min: 7000, max: 7999 }], - fields: [ - { key: 'uuid', label: 'UUID', type: 'number', required: true, group: '基础' }, - { key: 'name', label: '名称', type: 'string', required: true, group: '基础' }, - { key: 'icon', label: '图标', type: 'string', required: true, group: '基础' }, - { key: 'type', label: '类型', type: 'enum', enumRef: 'FieldSkillType', required: true, group: '效果' }, - { key: 'value', label: '数值', type: 'number', required: true, group: '效果' }, - { key: 'info', label: '描述', type: 'string', required: true, group: '基础' }, - ], -}; diff --git a/extensions/pixelhero-config-editor/src/shared/schema/hero.ts b/extensions/pixelhero-config-editor/src/shared/schema/hero.ts deleted file mode 100644 index b6fadad8..00000000 --- a/extensions/pixelhero-config-editor/src/shared/schema/hero.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { TableSchema } from './types'; -export const heroSchema: TableSchema = { - id: 'hero', label: '英雄/怪物', - sourceFile: 'heroSet.ts', exportName: 'HeroInfo', listExportName: 'HeroList', - idSegments: [ - { label: '英雄', min: 5000, max: 5999 }, - { label: '怪物', min: 6000, max: 6999 }, - ], - fields: [ - { key: 'uuid', label: 'UUID', type: 'number', required: true, group: '基础' }, - { key: 'name', label: '名称', type: 'string', required: true, group: '基础' }, - { key: 'path', label: '资源路径', type: 'string', required: true, group: '基础' }, - { key: 'icon', label: '图标', type: 'string', group: '基础' }, - { key: 'fac', label: '阵营', type: 'enum', enumRef: 'FacSet', required: true, group: '基础' }, - { key: 'pool_lv', label: '卡片等级', type: 'number', group: '基础' }, - { key: 'lv', label: '英雄等级', type: 'number', required: true, default: 1, group: '基础' }, - { key: 'type', label: '攻击定位', type: 'enum', enumRef: 'HType', required: true, group: '基础' }, - { key: 'hp', label: '生命上限', type: 'number', required: true, group: '基础' }, - { key: 'ap', label: '攻击力', type: 'number', required: true, group: '基础' }, - { key: 'dis', label: '攻击距离', type: 'number', group: '基础' }, - { key: 'speed', label: '移动速度', type: 'number', group: '基础' }, - { key: 'skills', label: '携带技能', type: 'skillMap', required: true, group: '技能' }, - { key: 'call', label: '召唤触发', type: 'triggerSlots', group: '触发技能' }, - { key: 'dead', label: '死亡触发', type: 'triggerSlots', group: '触发技能' }, - { key: 'fstart', label: '战斗开始触发', type: 'triggerSlots', group: '触发技能' }, - { key: 'fend', label: '战斗结束触发', type: 'triggerSlots', group: '触发技能' }, - { key: 'atking', label: '攻击触发', type: 'triggerSlots', group: '触发技能' }, - { key: 'atked', label: '受击触发', type: 'triggerSlots', group: '触发技能' }, - { key: 'field', label: '驻场技能', type: 'fieldList', group: '触发技能' }, - { key: 'revive', label: '复活触发', type: 'reviveSlot', group: '触发技能' }, - { key: 'info', label: '描述文案', type: 'string', required: true, group: '基础' }, - ], -}; diff --git a/extensions/pixelhero-config-editor/src/shared/schema/registry.ts b/extensions/pixelhero-config-editor/src/shared/schema/registry.ts deleted file mode 100644 index c395febc..00000000 --- a/extensions/pixelhero-config-editor/src/shared/schema/registry.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { TableId, TableSchema } from './types'; -import { heroSchema } from './hero'; -import { skillSchema } from './skill'; -import { fieldSchema } from './field'; - -export const REGISTRY: Record = { - hero: heroSchema, skill: skillSchema, field: fieldSchema, -}; -export function getSchema(id: TableId): TableSchema { return REGISTRY[id]; } -export function allSchemas(): TableSchema[] { return Object.values(REGISTRY); } diff --git a/extensions/pixelhero-config-editor/src/shared/schema/skill.ts b/extensions/pixelhero-config-editor/src/shared/schema/skill.ts deleted file mode 100644 index d453ca80..00000000 --- a/extensions/pixelhero-config-editor/src/shared/schema/skill.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { TableSchema } from './types'; -export const skillSchema: TableSchema = { - id: 'skill', label: '技能', - sourceFile: 'SkillSet.ts', exportName: 'SkillSet', - idSegments: [{ label: '技能', min: 6000, max: 6999 }], - fields: [ - { key: 'uuid', label: 'UUID', type: 'number', required: true, group: '基础' }, - { key: 'name', label: '名称', type: 'string', required: true, group: '基础' }, - { key: 'sp_name', label: '特效名', type: 'string', required: true, group: '基础' }, - { key: 'icon', label: '图标ID', type: 'string', required: true, group: '基础' }, - { key: 'act', label: '执行动画', type: 'string', required: true, group: '基础' }, - { key: 'TGroup', label: '目标群体', type: 'enum', enumRef: 'TGroup', required: true, group: '目标' }, - { key: 'DTType', label: '伤害类型', type: 'enum', enumRef: 'DTType', required: true, group: '目标' }, - { key: 'IType', label: '技能类型', type: 'enum', enumRef: 'IType', required: true, group: '目标' }, - { key: 'RType', label: '运行类型', type: 'enum', enumRef: 'RType', required: true, group: '目标' }, - { key: 'EType', label: '结束条件', type: 'enum', enumRef: 'EType', required: true, group: '目标' }, - { key: 'kind', label: '主效果', type: 'enum', enumRef: 'SkillKind', group: '目标' }, - { key: 'ap', label: 'ap(伤害%/护盾次)', type: 'number', required: true, group: '数值' }, - { key: 'gold', label: '金币值', type: 'number', group: '数值' }, - { key: 'hit_count', label: '可命中次数', type: 'number', required: true, group: '数值' }, - { key: 'hitcd', label: '伤害间隔', type: 'number', required: true, group: '数值' }, - { key: 'speed', label: '移动速度', type: 'number', required: true, group: '数值' }, - { key: 'ready', label: '前摇时间', type: 'number', required: true, group: '数值' }, - { key: 'with', label: '宽度', type: 'number', default: 0, group: '数值' }, - { key: 'readyAnm', label: '前摇动画', type: 'string', group: '动画' }, - { key: 'endAnm', label: '结束动画', type: 'string', group: '动画' }, - { key: 'DAnm', label: '命中动画ID', type: 'string', group: '动画' }, - { key: 'EAnm', label: '结束动画ID', type: 'number', group: '动画' }, - { key: 'crt', label: '额外暴击率', type: 'number', group: '高级' }, - { key: 'stun', label: '额外击晕概率', type: 'number', group: '高级' }, - { key: 'frz', label: '额外冰冻概率', type: 'number', group: '高级' }, - { key: 'bck', label: '额外击退概率', type: 'number', group: '高级' }, - { key: 'buff_type', label: 'Buff类型', type: 'enum', enumRef: 'Attrs', group: '高级' }, - { key: 'call_hero', label: '召唤英雄', type: 'ref', refTable: 'hero', group: '高级' }, - { key: 'time', label: '持续时间', type: 'number', group: '高级' }, - { key: 'bezier_start_y', label: '贝塞尔起始Y', type: 'number', group: '高级' }, - { key: 'bezier_mid_y', label: '贝塞尔中点Y', type: 'number', group: '高级' }, - { key: 'bezier_arc', label: '贝塞尔弧度', type: 'number', group: '高级' }, - { key: 'info', label: '描述', type: 'string', required: true, group: '基础' }, - ], -}; diff --git a/extensions/pixelhero-config-editor/src/shared/schema/types.ts b/extensions/pixelhero-config-editor/src/shared/schema/types.ts deleted file mode 100644 index 6664717d..00000000 --- a/extensions/pixelhero-config-editor/src/shared/schema/types.ts +++ /dev/null @@ -1,31 +0,0 @@ -export type TableId = 'hero' | 'skill' | 'field'; - -export type FieldType = - | 'number' | 'string' | 'boolean' - | 'enum' // 下拉,选项来自 enumRef - | 'ref' // 引用另一表 uuid - | 'speedExpr' // 攻速符号表达式 - | 'skillMap' | 'triggerSlots' | 'fieldList' | 'reviveSlot' | 'overrides'; - -export interface FieldSchema { - key: string; - label: string; - type: FieldType; - required?: boolean; - default?: unknown; - group?: string; - enumRef?: string; // type='enum' - refTable?: TableId; // type='ref' -} - -export interface IdSegment { label: string; min: number; max: number; } - -export interface TableSchema { - id: TableId; - label: string; - sourceFile: string; // 相对 assets/script/game/common/config/ - exportName: string; // 'HeroInfo' | 'SkillSet' | 'FieldSkillSet' - listExportName?: string; // 'HeroList'(仅 hero) - idSegments: IdSegment[]; - fields: FieldSchema[]; -} diff --git a/extensions/pixelhero-config-editor/src/shared/validation/index.ts b/extensions/pixelhero-config-editor/src/shared/validation/index.ts deleted file mode 100644 index d40b6f20..00000000 --- a/extensions/pixelhero-config-editor/src/shared/validation/index.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { RecordValue } from '../../io/recordValue'; -import { TableId } from '../schema/types'; -import { ENUMS } from '../schema/enums'; - -export type Severity = 'error' | 'warn'; -export interface Issue { - tableId: TableId; key: string; fieldPath: string; - severity: Severity; code: string; message: string; -} -export interface ValidationContext { - hasSkill: (u: number) => boolean; - hasField: (u: number) => boolean; - hasHero: (u: number) => boolean; - heroListKeys: Set; -} - -const OVERRIDE_KEYS = new Set(['TGroup', 'ap', 'gold', 'hit_count', 'hitcd', 'crt', 'frz', 'stun', 'bck', 'buff_type', 'call_hero']); -const TRIGGER_ARRAY_KEYS = ['call', 'dead', 'fstart', 'fend', 'atking', 'atked']; - -function num(v: RecordValue | undefined): number | undefined { - return v && v.kind === 'num' ? v.value : undefined; -} -function isKnownEnum(qualifier: string, member: string): boolean { - const def = ENUMS[qualifier] ?? Object.values(ENUMS).find(e => e.qualifier === qualifier); - return !!def && def.members.some(m => String(m.value) === member || m.label.split(' ').pop() === member); -} - -export function validate(tableId: TableId, records: Map, ctx: ValidationContext): Issue[] { - const issues: Issue[] = []; - // 跟踪 uuid 字段值(而非 Map 键)—— JS Map 会折叠重复键,但两条记录可能携带相同的 uuid 字段值。 - const seenUuids = new Set(); - - for (const [key, rec] of records) { - const push = (fieldPath: string, severity: Severity, code: string, message: string) => - issues.push({ tableId, key, fieldPath, severity, code, message }); - - if (rec.kind !== 'obj') { push('', 'error', 'not-object', '记录不是对象'); continue; } - const p = rec.props; - - const uVal = num(p['uuid']); - if (uVal !== undefined) { - const uKey = String(uVal); - if (seenUuids.has(uKey)) push('uuid', 'error', 'dup-uuid', `重复 uuid: ${uKey}`); - seenUuids.add(uKey); - } - - // 必填(按表最小集合) - const required: Record = { - hero: ['uuid', 'name', 'path', 'fac', 'lv', 'type', 'hp', 'ap', 'skills', 'info'], - skill: ['uuid', 'name', 'sp_name', 'icon', 'act', 'TGroup', 'DTType', 'IType', 'RType', 'EType', 'ap', 'hit_count', 'hitcd', 'speed', 'ready', 'info'], - field: ['uuid', 'name', 'icon', 'type', 'value', 'info'], - }; - for (const f of required[tableId]) { - if (p[f] === undefined) push(f, 'error', 'missing-required', `缺少必填字段 ${f}`); - } - - // 枚举值合法 - for (const [f, v] of Object.entries(p)) { - if (v.kind === 'enumRef' && !isKnownEnum(v.qualifier, v.member)) { - push(f, 'error', 'bad-enum', `非法枚举值 ${v.qualifier}.${v.member}`); - } - } - - if (tableId === 'hero') { - // 触发槽数组引用 + overrides 键 - for (const tk of TRIGGER_ARRAY_KEYS) { - const arr = p[tk]; - if (!arr || arr.kind !== 'arr') continue; - for (const it of arr.items) { - if (it.kind !== 'obj') continue; - const su = num(it.props['s_uuid']); - if (su !== undefined && !ctx.hasSkill(su)) push(tk, 'error', 'dangling-ref', `引用了不存在的技能 ${su}`); - const ov = it.props['overrides']; - if (ov && ov.kind === 'obj') { - for (const k of Object.keys(ov.props)) { - if (!OVERRIDE_KEYS.has(k)) push(`${tk}.overrides`, 'error', 'bad-override-key', `非法覆盖键 ${k}`); - } - } - } - } - // field 列表 - const fl = p['field']; - if (fl && fl.kind === 'arr') { - for (const it of fl.items) { const u = num(it); if (u !== undefined && !ctx.hasField(u)) push('field', 'error', 'dangling-ref', `引用了不存在的驻场技能 ${u}`); } - } - // revive - const rv = p['revive']; - if (rv && rv.kind === 'obj') { - const su = num(rv.props['s_uuid']); if (su !== undefined && !ctx.hasSkill(su)) push('revive', 'error', 'dangling-ref', `引用了不存在的技能 ${su}`); - } - // call_hero(技能表里的 ref 也用 hasHero) - } - if (tableId === 'skill') { - const ch = num(p['call_hero']); if (ch !== undefined && !ctx.hasHero(ch)) push('call_hero', 'error', 'dangling-ref', `引用了不存在的英雄 ${ch}`); - } - - // HeroList 一致性(仅 hero 表) - if (tableId === 'hero') { - const u = num(p['uuid']); const fac = p['fac']; - const isHero = fac && fac.kind === 'enumRef' && fac.member === 'HERO'; - if (isHero && u !== undefined && !ctx.heroListKeys.has(String(u))) { - push('uuid', 'error', 'herolist-inconsistent', `英雄 ${u} 不在 HeroList 中`); - } - } - } - return issues; -} diff --git a/extensions/pixelhero-config-editor/static/style/default/index.css b/extensions/pixelhero-config-editor/static/style/default/index.css deleted file mode 100644 index 2d1e15a9..00000000 --- a/extensions/pixelhero-config-editor/static/style/default/index.css +++ /dev/null @@ -1,7 +0,0 @@ -#app { color: var(--color-font-normal); font-size: 12px; } -.row { margin: 6px 0; } -button { margin-right: 8px; } -ul { list-style: none; padding: 0; max-height: 360px; overflow:auto; } -li { padding: 3px 6px; cursor: pointer; } -li:hover { background: var(--color-hover-bg); } -.err { color: var(--color-warn); } diff --git a/extensions/pixelhero-config-editor/static/template/default/index.html b/extensions/pixelhero-config-editor/static/template/default/index.html deleted file mode 100644 index 41ca5532..00000000 --- a/extensions/pixelhero-config-editor/static/template/default/index.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/extensions/pixelhero-config-editor/tsconfig.json b/extensions/pixelhero-config-editor/tsconfig.json deleted file mode 100644 index 6304674c..00000000 --- a/extensions/pixelhero-config-editor/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "CommonJS", - "moduleResolution": "node", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "resolveJsonModule": true, - "experimentalDecorators": true, - "types": ["node"], - "lib": ["ES2020", "DOM"] - }, - "include": ["src/**/*", "__tests__/**/*"] -}