tyhuynh-laya-cmd 1.0.11 → 1.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- "use strict";const path=require("path"),fs=require("fs-extra"),{program:program}=require("commander");require("colors");const{loadProjectConfig:loadProjectConfig}=require("./src/config/ProjectConfig"),{loadStyles:loadStyles,invalidateCache:invalidateStyles}=require("./src/parsers/StylesParser"),{loadPageStyles:loadPageStyles,invalidateCache:invalidatePages}=require("./src/parsers/PageParser"),{generateUICode:generateUICode}=require("./src/generators/UICodeGen"),{generateAtlas:generateAtlas}=require("./src/generators/AtlasGen"),{collectFiles:collectFiles}=require("./src/utils/FileUtils");function autoDetectLayaDir(){const e=e=>{const o=path.join(e,".laya");return fs.existsSync(o)&&fs.statSync(o).isFile()};let o=process.cwd();if(e(o))return o;const t=path.join(o,"laya");if(e(t))return t;let a=null,r=o;for(;r!==a;){const o=path.join(r,"laya");if(e(o))return o;a=r,r=path.dirname(r)}return null}async function runUI(e){const{project:o,atlas:t,code:a,clear:r,watch:n}=e,s=a||!t&&!a,l=t||!t&&!a,c=path.resolve(o);fs.existsSync(c)||(console.error(`[ERROR] Project directory not found: ${c}`.red),process.exit(1)),n?(console.log("\n╔════════════════════════════════════════╗"),console.log("║ 🎨 UI Build Tool (tyhuynh-laya-cmd) ║"),console.log("╚════════════════════════════════════════╝")):console.log(`\n${"⚡ Custom LayaAir2 Build Tool".cyan.bold}`),console.log(`[UI] Project: ${c.gray}`),console.log(`[UI] Mode: ${[s&&"CODE",l&&"ATLAS"].filter(Boolean).join(" + ").yellow}`),r&&console.log(`[UI] Cache: ${"CLEARED".red}`),console.log(""),await build(c,{doCode:s,doAtlas:l,clear:r}),n&&await startWatchMode(c,{doCode:s,doAtlas:l})}async function build(e,{doCode:o,doAtlas:t,clear:a,hint:r={}}){const n=Date.now();let s;try{s=loadProjectConfig(e)}catch(e){return void console.error(`[ERROR] Cannot load .laya config: ${e.message}`.red)}const l=path.dirname(e),c=path.join(e,"pages"),i=path.join(l,s.codeExportPath,"layaMaxUI.ts"),d=path.join(e,".custom-cmd-cache"),p=path.join(d,"code-cache.json"),h=path.join(d,"atlas-cache.json"),u=o&&!r.atlasOnly,g=t&&!r.codeOnly,y=[],m=!!r&&Object.keys(r).length>0?()=>{}:e=>console.log(` ${e}`);u&&y.push(generateUICode({pagesDir:c,outputPath:i,cachePath:p,projectPath:l,resExportPath:path.join(l,s.resExportPath),clear:a,changedScenes:r.changedScenes||null,log:m}).then(e=>{console.log(`[UI] 📄 UI Code: ${String(e.built).green} built, ${e.skipped} skipped`)}).catch(e=>{console.error(`[UI] ${"❌ CODE ERROR".red}: ${e.message}`)})),g&&y.push((async()=>{try{const o=path.join(e,"styles.xml"),t=loadStyles(o);await generateAtlas({styleMap:t,projectConfig:s,assetDir:path.join(e,"assets"),outputDir:path.join(l,s.resExportPath),cachePath:h,clear:a,changedDirs:r.changedDirs||null,log:m}),console.log(`[UI] 🖼 Atlas: ${"done".green}`)}catch(e){console.error(`[UI] ${"❌ ATLAS ERROR".red}: ${e.message}`)}})()),await Promise.all(y);const f=((Date.now()-n)/1e3).toFixed(2),j=(new Date).toLocaleTimeString();console.log(`[UI] ✅ ${j} — Build complete in ${f}s\n`)}async function startWatchMode(e,{doCode:o,doAtlas:t}){let a;try{a=require("chokidar")}catch{console.error("[WATCH] chokidar not installed. Run: npm install chokidar".red),process.exit(1)}const r=path.join(e,"pages"),n=path.join(e,"assets"),s=path.join(e,"styles.xml"),l=path.join(e,"pageStyles.xml");console.log("[UI] 👀 Watching pages/ & assets/ — Ctrl+C để dừng"),console.log("[UI] .scene → code | image → atlas | .xml → full rebuild\n");let c=null,i=new Set,d=new Set,p=!1;function h(){clearTimeout(c),c=setTimeout(async()=>{const a=[...i],r=[...d],l=p;i.clear(),d.clear(),p=!1;const c=[...a,...r,...l?[s]:[]];if(0===c.length)return;if(console.log("\n[UI] 📝 Đã sửa:"),c.map(o=>path.relative(e,o).replace(/\\/g,"/")).forEach(e=>console.log(`[UI] • ${e}`)),l)return console.log("[UI] ↻ XML config changed — full rebuild..."),void await build(e,{doCode:o,doAtlas:t,clear:!1,hint:{}});const h=o&&a.length>0,u=t&&r.length>0;if(!h&&!u)return;let g=null;u&&(g=new Set(r.map(e=>path.relative(n,path.dirname(e)).replace(/\\/g,"/"))));let y=null;h&&(y=new Set(a)),await build(e,{doCode:o,doAtlas:t,clear:!1,hint:{codeOnly:h&&!u,atlasOnly:u&&!h,changedDirs:g,changedScenes:y}})},300)}function u(e){i.add(e),h()}function g(e){d.add(e),h()}function y(e){e===s&&invalidateStyles(),e===l&&invalidatePages(),p=!0,h()}const m={ignoreInitial:!0,usePolling:!1};o&&a.watch(path.join(r,"**","*.scene"),m).on("add",u).on("change",u).on("unlink",u).on("error",e=>console.error(`[WATCH ERROR] ${e}`.red)),t&&a.watch([`${n}/**/*.png`,`${n}/**/*.jpg`],m).on("add",g).on("change",g).on("unlink",g).on("error",e=>console.error(`[WATCH ERROR] ${e}`.red)),a.watch([s,l],m).on("add",y).on("change",y).on("error",e=>console.error(`[WATCH ERROR] ${e}`.red))}program.name("tyhuynh-laya-cmd").description("Custom LayaAir 2 fast incremental UI build tool").version("1.0.1"),program.command("ui").description("Export UI code and/or atlas").option("-p, --project <dir>","Path to laya/ directory (auto-detected if omitted)",null).option("-a, --atlas","Generate atlas sprite sheets",!1).option("-d, --code","Generate TypeScript UI code",!1).option("-c, --clear","Clear cache (force full rebuild)",!1).option("-w, --watch","Watch mode",!1).action(async e=>{e.project||(e.project=autoDetectLayaDir(),e.project||(console.error("[ERROR] Cannot find laya/ directory. Use -p <dir> to specify manually.".red),process.exit(1)),console.log(` Auto-detected: ${e.project.gray}`)),await runUI(e)}),program.command("migrate").description("Migrate stray assets from bin/ into laya/assets/ and update styles.xml").option("-p, --project <dir>","Path to laya/ directory (auto-detected if omitted)",null).option("--dry-run","Preview changes without writing anything",!1).action(e=>{const o=[];e.dryRun&&o.push("--dry-run"),e.project&&o.push("-p",e.project);const{spawnSync:t}=require("child_process"),a=require.resolve("./scripts/migrate-stray-assets.js"),r=t(process.execPath,[a,...o],{stdio:"inherit"});process.exit(r.status||0)}),program.parse(process.argv);
2
+ "use strict";const path=require("path"),fs=require("fs-extra"),{program:program}=require("commander");require("colors");const{loadProjectConfig:loadProjectConfig}=require("./src/config/ProjectConfig"),{loadStyles:loadStyles,invalidateCache:invalidateStyles}=require("./src/parsers/StylesParser"),{loadPageStyles:loadPageStyles,invalidateCache:invalidatePages}=require("./src/parsers/PageParser"),{generateUICode:generateUICode}=require("./src/generators/UICodeGen"),{generateAtlas:generateAtlas}=require("./src/generators/AtlasGen"),{generateGameConfig:generateGameConfig}=require("./src/generators/GameConfigGen"),{generateAni:generateAni}=require("./src/generators/AniGen"),{collectFiles:collectFiles}=require("./src/utils/FileUtils");function autoDetectLayaDir(){const e=e=>{const o=path.join(e,".laya");return fs.existsSync(o)&&fs.statSync(o).isFile()};let o=process.cwd();if(e(o))return o;const t=path.join(o,"laya");if(e(t))return t;let a=null,n=o;for(;n!==a;){const o=path.join(n,"laya");if(e(o))return o;a=n,n=path.dirname(n)}return null}async function runUI(e){const{project:o,atlas:t,code:a,clear:n,watch:r}=e,s=!!e.gameConfig,c=a||!t&&!a,i=t||!t&&!a,l=path.resolve(o);fs.existsSync(l)||(console.error(`[ERROR] Project directory not found: ${l}`.red),process.exit(1)),r?(console.log("\n╔════════════════════════════════════════╗"),console.log("║ 🎨 UI Build Tool (tyhuynh-laya-cmd) ║"),console.log("╚════════════════════════════════════════╝")):console.log(`\n${"⚡ Custom LayaAir2 Build Tool".cyan.bold}`),console.log(`[UI] Project: ${l.gray}`);const d=[c&&"CODE",i&&"ATLAS",s&&"GAME-CONFIG"].filter(Boolean).join(" + ");console.log(`[UI] Mode: ${d.yellow}`),n&&console.log(`[UI] Cache: ${"CLEARED".red}`),console.log(""),await build(l,{doCode:c,doAtlas:i,clear:n}),s&&await buildGameConfig(l),r&&await startWatchMode(l,{doCode:c,doAtlas:i,doGameConfig:s})}async function build(e,{doCode:o,doAtlas:t,clear:a,hint:n={}}){const r=Date.now();let s;try{s=loadProjectConfig(e)}catch(e){return void console.error(`[ERROR] Cannot load .laya config: ${e.message}`.red)}const c=path.dirname(e),i=path.join(e,"pages"),l=path.join(c,s.codeExportPath,"layaMaxUI.ts"),d=path.join(e,".custom-cmd-cache"),g=path.join(d,"code-cache.json"),p=path.join(d,"atlas-cache.json"),h=path.join(d,"ani-cache.json"),u=o&&!n.atlasOnly,y=t&&!n.codeOnly,f=[],m=!!n&&Object.keys(n).length>0?()=>{}:e=>console.log(` ${e}`);u&&f.push(generateUICode({pagesDir:i,outputPath:l,cachePath:g,projectPath:c,resExportPath:path.join(c,s.resExportPath),clear:a,changedScenes:n.changedScenes||null,log:m}).then(e=>{console.log(`[UI] 📄 UI Code: ${String(e.built).green} built, ${e.skipped} skipped`)}).catch(e=>{console.error(`[UI] ${"❌ CODE ERROR".red}: ${e.message}`)})),y&&f.push((async()=>{try{const o=path.join(e,"styles.xml"),t=loadStyles(o);await generateAtlas({styleMap:t,projectConfig:s,assetDir:path.join(e,"assets"),outputDir:path.join(c,s.resExportPath),cachePath:p,clear:a,changedDirs:n.changedDirs||null,log:m}),console.log(`[UI] 🖼 Atlas: ${"done".green}`)}catch(e){console.error(`[UI] ${"❌ ATLAS ERROR".red}: ${e.message}`)}})()),f.push(generateAni({pagesDir:i,outputDir:path.join(c,s.resExportPath),cachePath:h,clear:a,log:m}).then(e=>{e.copied>0&&console.log(`[UI] 🎞 Ani: ${String(e.copied).green} copied, ${e.skipped} skipped`)}).catch(e=>{console.error(`[UI] ${"❌ ANI ERROR".red}: ${e.message}`)})),await Promise.all(f);const C=((Date.now()-r)/1e3).toFixed(2),j=(new Date).toLocaleTimeString();console.log(`[UI] ✅ ${j} — Build complete in ${C}s\n`)}async function buildGameConfig(e){let o;try{o=loadProjectConfig(e)}catch(e){return void console.error(`[GameConfig] ${"❌ ERROR loading .laya".red}: ${e.message}`)}const t=path.dirname(e),a=path.join(e,"pages"),n=path.join(t,"src","GameConfig.ts");try{const e=await generateGameConfig({pagesDir:a,outputPath:n,projectConfig:o,log:()=>{}});e.written&&console.log(`[UI] ⚙ GameConfig: ${"Updated".green} (${e.total} scripts)`)}catch(e){console.error(`[UI] ${"❌ GAME-CONFIG ERROR".red}: ${e.message}`)}}async function startWatchMode(e,{doCode:o,doAtlas:t,doGameConfig:a}){let n;try{n=require("chokidar")}catch{console.error("[WATCH] chokidar not installed. Run: npm install chokidar".red),process.exit(1)}const r=path.join(e,"pages"),s=path.join(e,"assets"),c=path.join(e,"styles.xml"),i=path.join(e,"pageStyles.xml");console.log("[UI] 👀 Watching pages/ & assets/ — Ctrl+C để dừng"),console.log("[UI] .scene → code | image → atlas | .xml → full rebuild\n");let l=null,d=new Set,g=new Set,p=new Set,h=!1;function u(){clearTimeout(l),l=setTimeout(async()=>{const n=[...d],r=[...g],i=[...p],l=h;d.clear(),g.clear(),p.clear(),h=!1;const u=[...n,...r,...i,...l?[c]:[]];if(0===u.length)return;if(console.log("\n[UI] 📝 Đã sửa:"),u.map(o=>path.relative(e,o).replace(/\\/g,"/")).forEach(e=>console.log(`[UI] • ${e}`)),l)return console.log("[UI] ↻ XML config changed — full rebuild..."),void await build(e,{doCode:o,doAtlas:t,clear:!1,hint:{}});const y=o&&n.length>0,f=t&&i.length>0;if(!y&&!f)return;let m=null;f&&(m=new Set(i.map(e=>path.relative(s,path.dirname(e)).replace(/\\/g,"/"))));let C=null;y&&(C=new Set(n)),await build(e,{doCode:o,doAtlas:t,clear:!1,hint:{codeOnly:y&&!f,atlasOnly:f&&!y,changedDirs:m,changedScenes:C}}),a&&(n.length>0||r.length>0)&&await buildGameConfig(e)},300)}function y(e){d.add(e),u()}function f(e){g.add(e),u()}function m(e){p.add(e),u()}function C(e){e===c&&invalidateStyles(),e===i&&invalidatePages(),h=!0,u()}const j={ignoreInitial:!0,usePolling:!1};o&&n.watch(path.join(r,"**","*.scene"),j).on("add",y).on("change",y).on("unlink",y).on("error",e=>console.error(`[WATCH ERROR] ${e}`.red)),a&&n.watch([path.join(r,"**","*.scene"),path.join(r,"**","*.prefab")],j).on("add",e=>e.endsWith(".prefab")?f(e):y(e)).on("change",e=>e.endsWith(".prefab")?f(e):y(e)).on("unlink",e=>e.endsWith(".prefab")?f(e):y(e)).on("error",e=>console.error(`[WATCH ERROR] ${e}`.red)),t&&n.watch([`${s}/**/*.png`,`${s}/**/*.jpg`],j).on("add",m).on("change",m).on("unlink",m).on("error",e=>console.error(`[WATCH ERROR] ${e}`.red)),n.watch(`${r}/**/*.ani`,j).on("add",e=>{p.add(e),u()}).on("change",e=>{p.add(e),u()}).on("error",e=>console.error(`[WATCH ERROR] ${e}`.red)),n.watch([c,i],j).on("add",C).on("change",C).on("error",e=>console.error(`[WATCH ERROR] ${e}`.red))}async function runGameConfig(e){const o=path.resolve(e.project);let t;fs.existsSync(o)||(console.error(`[ERROR] Project directory not found: ${o}`.red),process.exit(1));try{t=loadProjectConfig(o)}catch(e){console.error(`[ERROR] Cannot load .laya config: ${e.message}`.red),process.exit(1)}const a=path.dirname(o),n=path.join(o,"pages"),r=e.output?path.resolve(e.output):path.join(a,"src","GameConfig.ts");console.log(`\n${"⚡ Custom LayaAir2 Build Tool".cyan.bold}`),console.log(`[GameConfig] Project: ${o.gray}`),console.log(`[GameConfig] Output: ${r.gray}`),console.log("");const s=Date.now();try{const e=await generateGameConfig({pagesDir:n,outputPath:r,projectConfig:t,log:e=>console.log(` ${e}`)}),o=((Date.now()-s)/1e3).toFixed(2),a=(new Date).toLocaleTimeString(),c=e.written?"Updated".green:"No changes".gray;console.log(`[GameConfig] ✅ ${a} — ${c} (${e.total} scripts) in ${o}s\n`)}catch(e){console.error(`[GameConfig] ${"❌ ERROR".red}: ${e.message}`),process.exit(1)}}program.name("tyhuynh-laya-cmd").description("Custom LayaAir 2 fast incremental UI build tool").version("1.0.1"),program.command("ui").description("Export UI code and/or atlas").option("-p, --project <dir>","Path to laya/ directory (auto-detected if omitted)",null).option("-a, --atlas","Generate atlas sprite sheets",!1).option("-d, --code","Generate TypeScript UI code",!1).option("-g, --game-config","Generate GameConfig.ts",!1).option("-c, --clear","Clear cache (force full rebuild)",!1).option("-w, --watch","Watch mode",!1).action(async e=>{e.project||(e.project=autoDetectLayaDir(),e.project||(console.error("[ERROR] Cannot find laya/ directory. Use -p <dir> to specify manually.".red),process.exit(1)),console.log(` Auto-detected: ${e.project.gray}`)),await runUI(e)}),program.command("migrate").description("Migrate stray assets from bin/ into laya/assets/ and update styles.xml").option("-p, --project <dir>","Path to laya/ directory (auto-detected if omitted)",null).option("--dry-run","Preview changes without writing anything",!1).action(e=>{const o=[];e.dryRun&&o.push("--dry-run"),e.project&&o.push("-p",e.project);const{spawnSync:t}=require("child_process"),a=require.resolve("./scripts/migrate-stray-assets.js"),n=t(process.execPath,[a,...o],{stdio:"inherit"});process.exit(n.status||0)}),program.command("game-config").description("Generate src/GameConfig.ts by scanning all .scene files for Script components").option("-p, --project <dir>","Path to laya/ directory (auto-detected if omitted)",null).option("-o, --output <file>","Output path for GameConfig.ts (default: <projectRoot>/src/GameConfig.ts)",null).action(async e=>{e.project||(e.project=autoDetectLayaDir(),e.project||(console.error("[ERROR] Cannot find laya/ directory. Use -p <dir> to specify manually.".red),process.exit(1)),console.log(` Auto-detected: ${e.project.gray}`)),await runGameConfig(e)}),program.parse(process.argv);
@@ -1 +1 @@
1
- "use strict";const{XMLParser:XMLParser}=require("fast-xml-parser"),fs=require("fs-extra"),path=require("path"),parser=new XMLParser({ignoreAttributes:!1,attributeNamePrefix:"_",allowBooleanAttributes:!0,trimValues:!0,parseTagValue:!0});function loadProjectConfig(e){const t=path.join(e,".laya");if(!fs.existsSync(t))throw new Error(`Không tìm thấy .laya config tại: ${t}`);const r=fs.readFileSync(t,"utf-8"),i=parser.parse(r).project||{},o=(e,t)=>{const r=i[e];return void 0!==r?r:t},a=o("boxTypes","Sprite,Box,List,Tab,RadioGroup,ViewStack,Panel,HBox,VBox,Tree"),s=o("pageTypes","View,Scene");return{projectDir:e,codeExportPath:String(o("codeExportPath","src/ui")).trim(),uiExportPath:String(o("uiExportPath","bin")).trim(),resExportPath:String(o("resExportPath","bin/")).trim(),codeType:Number(o("codeType",1)),uiType:Number(o("uiType",2)),designWidth:Number(o("designWidth",720)),designHeight:Number(o("designHeight",1280)),boxTypes:String(a).split(",").map(e=>e.trim()),pageTypes:String(s).split(",").map(e=>e.trim()),toJsonScene:!0===o("toJsonScene",!0)||"true"===o("toJsonScene","true"),scaleMode:String(o("scaleMode","fixedwidth")).trim(),picWidth:Number(o("picWidth",512)),picHeight:Number(o("picHeight",512)),textureWidth:Number(o("textureWidth",1024)),textureHeight:Number(o("textureHeight",1024)),scaleMode:String(o("scaleMode","fixedwidth")).trim()}}module.exports={loadProjectConfig:loadProjectConfig};
1
+ "use strict";const{XMLParser:XMLParser}=require("fast-xml-parser"),fs=require("fs-extra"),path=require("path"),parser=new XMLParser({ignoreAttributes:!1,attributeNamePrefix:"_",allowBooleanAttributes:!0,trimValues:!0,parseTagValue:!0});function loadProjectConfig(e){const t=path.join(e,".laya");if(!fs.existsSync(t))throw new Error(`Không tìm thấy .laya config tại: ${t}`);const r=fs.readFileSync(t,"utf-8"),i=parser.parse(r).project||{},o=(e,t)=>{const r=i[e];return void 0!==r?r:t},a=o("boxTypes","Sprite,Box,List,Tab,RadioGroup,ViewStack,Panel,HBox,VBox,Tree"),n=o("pageTypes","View,Scene"),s=(e,t)=>null==e?t:"boolean"==typeof e?e:"true"===String(e).trim().toLowerCase();return{projectDir:e,codeExportPath:String(o("codeExportPath","src/ui")).trim(),uiExportPath:String(o("uiExportPath","bin")).trim(),resExportPath:String(o("resExportPath","bin/")).trim(),codeType:Number(o("codeType",1)),uiType:Number(o("uiType",2)),designWidth:Number(o("designWidth",720)),designHeight:Number(o("designHeight",1280)),boxTypes:String(a).split(",").map(e=>e.trim()),pageTypes:String(n).split(",").map(e=>e.trim()),toJsonScene:s(o("toJsonScene",!0),!0),scaleMode:String(o("scaleMode","fixedwidth")).trim(),screenMode:String(o("screenMode","vertical")).trim(),alignV:String(o("alignV","middle")).trim(),alignH:String(o("alignH","center")).trim(),startScene:String(o("startScene","")).trim(),debugMode:s(o("debugMode",!1),!1),stat:s(o("stat",!0),!0),physicsDebug:s(o("physicsDebug",!0),!0),picWidth:Number(o("picWidth",512)),picHeight:Number(o("picHeight",512)),textureWidth:Number(o("textureWidth",1024)),textureHeight:Number(o("textureHeight",1024))}}module.exports={loadProjectConfig:loadProjectConfig};
@@ -0,0 +1 @@
1
+ "use strict";const path=require("path"),fs=require("fs-extra"),{getMtime:getMtime,collectFiles:collectFiles,writeIfChanged:writeIfChanged}=require("../utils/FileUtils");async function generateAni({pagesDir:e,outputDir:t,cachePath:i,clear:n=!1,log:r=console.log}){const s=collectFiles(e,".ani");if(0===s.length)return{copied:0,skipped:0};let c={};if(!n)try{c=fs.readJsonSync(i)}catch{}let a=0,l=0;for(const i of s){const s=path.relative(e,i).replace(/\\/g,"/"),o=path.join(t,s),p=getMtime(i);n||!c[s]||c[s]!==p||!fs.existsSync(o)?(fs.ensureDirSync(path.dirname(o)),fs.copyFileSync(i,o),c[s]=p,a++,r(`[AniGen] ✓ ${s}`)):l++}return fs.ensureDirSync(path.dirname(i)),writeIfChanged(i,JSON.stringify(c,null,2)),{copied:a,skipped:l}}module.exports={generateAni:generateAni};
@@ -0,0 +1 @@
1
+ "use strict";const path=require("path"),fs=require("fs-extra"),{collectFiles:collectFiles,writeIfChanged:writeIfChanged}=require("../utils/FileUtils");function _collectKeys(e,t){if(e){if("Script"===e.type&&"string"==typeof e.source&&e.source.trim()){const s=e.source.trim();s.startsWith("src/")&&t.add(s.slice(4))}if(e.props&&"string"==typeof e.props.runtime&&e.props.runtime.trim()){const s=e.props.runtime.trim();s.startsWith("Laya.")||t.add(s)}if(Array.isArray(e.child))for(const s of e.child)_collectKeys(s,t)}}function parseRegKeys(e){const t=new Set;let s;try{s=JSON.parse(fs.readFileSync(e,"utf-8"))}catch{return t}return _collectKeys(s,t),t}function regKeyToEntry(e){const t=path.basename(e,".ts"),s="./"+e.replace(/\.ts$/,"");return{regKey:e,className:t,importAlias:t,importPath:s}}function assignAliases(e){const t={};for(const s of e)t[s.className]=(t[s.className]||0)+1;const s={};for(const a of e)if(t[a.className]>1){const e=s[a.className]||0;a.importAlias=0===e?a.className:`${a.className}${e}`,s[a.className]=e+1}}async function generateGameConfig({pagesDir:e,outputPath:t,projectConfig:s,log:a=console.log}){const i=collectFiles(e,".scene"),n=collectFiles(e,".prefab"),o=[...i,...n];a(`[GameConfigGen] Scanning ${i.length} scene + ${n.length} prefab files...`);const r=new Set;for(const e of o)for(const t of parseRegKeys(e))r.add(t);a(`[GameConfigGen] Found ${r.size} unique script registrations`);const c=[...r].sort((e,t)=>e.localeCompare(t)).map(regKeyToEntry);assignAliases(c);const l=s||{},g=l.designWidth||720,f=l.designHeight||1280,m=l.scaleMode||"fixedwidth",p=l.screenMode||"vertical",u=l.alignV||"middle",d=l.alignH||"center",h=l.startScene||"",y=!0===l.debugMode?"true":"false",$=!1===l.stat?"false":"true",C=!1===l.physicsDebug?"false":"true",b=!1===l.toJsonScene?"false":"true",G=h?`"${h.replace(/\\/g,"/").trim()}"`:'""',N=["/**This class is automatically generated by LayaAirIDE, please do not make any modifications. */",...c.map(e=>e.importAlias!==e.className?`import ${e.importAlias} from "${e.importPath}"`:`import ${e.className} from "${e.importPath}"`),"/*"," * 游戏初始化配置;"," */","export default class GameConfig{",` static width:number=${g};`,` static height:number=${f};`,` static scaleMode:string="${m}";`,` static screenMode:string="${p}";`,` static alignV:string="${u}";`,` static alignH:string="${d}";`,` static startScene:any=${G};`,' static sceneRoot:string="";',` static debug:boolean=${y};`,` static stat:boolean=${$};`,` static physicsDebug:boolean=${C};`,` static exportSceneToJson:boolean=${b};`," constructor(){}"," static init(){"," var reg: Function = Laya.ClassUtils.regClass;",...c.map(e=>` reg("${e.regKey}",${e.importAlias});`)," }","}","GameConfig.init();",""].join("\n"),A=writeIfChanged(t,N);return a(A?`[GameConfigGen] ✓ Written: ${t}`:"[GameConfigGen] ✓ No changes detected — file up to date"),{written:A,total:c.length}}module.exports={generateGameConfig:generateGameConfig};
package/package.json CHANGED
@@ -1,44 +1,46 @@
1
- {
2
- "name": "tyhuynh-laya-cmd",
3
- "version": "1.0.11",
4
- "description": "Custom LayaAir 2 UI build tool - fast incremental atlas and UI code generation",
5
- "main": "dist/index.js",
6
- "bin": {
7
- "tyhuynh-laya-cmd": "./dist/index.js"
8
- },
9
- "scripts": {
10
- "prepublishOnly": "node build-dist.js",
11
- "build": "node index.js ui -p ../../client/laya -a -d",
12
- "build:clean": "node index.js ui -p ../../client/laya -a -d -c",
13
- "build:ui": "node index.js ui -p ../../client/laya -d",
14
- "build:atlas": "node index.js ui -p ../../client/laya -a",
15
- "watch": "node index.js ui -p ../../client/laya -a -d -w",
16
- "migrate": "node scripts/migrate-stray-assets.js -p ../../client/laya",
17
- "migrate:dry": "node scripts/migrate-stray-assets.js --dry-run -p ../../client/laya"
18
- },
19
- "keywords": [
20
- "layaair",
21
- "layaair2",
22
- "ui",
23
- "atlas",
24
- "build-tool",
25
- "game"
26
- ],
27
- "dependencies": {
28
- "chokidar": "^3.6.0",
29
- "colors": "^1.4.0",
30
- "commander": "^11.0.0",
31
- "fast-xml-parser": "4.0.0",
32
- "fs-extra": "^10.1.0",
33
- "image-size": "^0.9.7",
34
- "maxrects-packer": "^2.7.3",
35
- "sharp": "^0.30.7"
36
- },
37
- "engines": {
38
- "node": ">=12.0.0"
39
- },
40
- "license": "ISC",
41
- "devDependencies": {
42
- "terser": "^5.46.1"
43
- }
44
- }
1
+ {
2
+ "name": "tyhuynh-laya-cmd",
3
+ "version": "1.0.17",
4
+ "description": "Custom LayaAir 2 UI build tool - fast incremental atlas and UI code generation",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "tyhuynh-laya-cmd": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "prepublishOnly": "node build-dist.js",
11
+ "build": "node index.js ui -p ../client/laya -a -d",
12
+ "build:clean": "node index.js ui -p ../client/laya -a -d -c",
13
+ "build:ui": "node index.js ui -p ../client/laya -d",
14
+ "build:atlas": "node index.js ui -p ../client/laya -a",
15
+ "watch": "node index.js ui -p ../client/laya -a -d -g -w",
16
+ "migrate": "node scripts/migrate-stray-assets.js -p ../client/laya",
17
+ "migrate:dry": "node scripts/migrate-stray-assets.js --dry-run -p ../client/laya",
18
+ "game-config": "node index.js game-config -p ../client/laya",
19
+ "game-config:out": "node index.js game-config -p ../client/laya -o ../client/src/GameConfig.ts"
20
+ },
21
+ "keywords": [
22
+ "layaair",
23
+ "layaair2",
24
+ "ui",
25
+ "atlas",
26
+ "build-tool",
27
+ "game"
28
+ ],
29
+ "dependencies": {
30
+ "chokidar": "^3.6.0",
31
+ "colors": "^1.4.0",
32
+ "commander": "^11.0.0",
33
+ "fast-xml-parser": "4.0.0",
34
+ "fs-extra": "^10.1.0",
35
+ "image-size": "^0.9.7",
36
+ "maxrects-packer": "^2.7.3",
37
+ "sharp": "^0.30.7"
38
+ },
39
+ "engines": {
40
+ "node": ">=12.0.0"
41
+ },
42
+ "license": "ISC",
43
+ "devDependencies": {
44
+ "terser": "^5.46.1"
45
+ }
46
+ }