tyhuynh-laya-cmd 1.0.7 → 1.0.9
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
|
|
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);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";const{parseXmlFile:parseXmlFile}=require("../utils/XmlUtils"),{getMtime:getMtime}=require("../utils/FileUtils"),EXPORT_MODE_FILE="文件模式",EXPORT_MODE_SEPARATE="分离模式";let _cache=null;function loadPageStyles(e){const a=getMtime(e);if(_cache&&_cache.mtime===a&&_cache.path===e)return _cache.data;const t=parseXmlFile(e),i=t
|
|
1
|
+
"use strict";const{parseXmlFile:parseXmlFile}=require("../utils/XmlUtils"),{getMtime:getMtime}=require("../utils/FileUtils"),EXPORT_MODE_FILE="文件模式",EXPORT_MODE_SEPARATE="分离模式";let _cache=null;function loadPageStyles(e){const a=getMtime(e);if(_cache&&_cache.mtime===a&&_cache.path===e)return _cache.data;const t=parseXmlFile(e),i=t&&t.page&&t.page.item,c=[];if(!i)return _cache={mtime:a,path:e,data:c},c;const l=Array.isArray(i)?i:[i];for(const e of l)e.name&&c.push({name:e.name,ifExport:e.ifExport||"文件模式",aName:e.aName||"",props:e.props||""});return _cache={mtime:a,path:e,data:c},c}function invalidateCache(){_cache=null}module.exports={loadPageStyles:loadPageStyles,invalidateCache:invalidateCache,EXPORT_MODE_FILE:"文件模式",EXPORT_MODE_SEPARATE:"分离模式"};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";const{parseXmlFile:parseXmlFile}=require("../utils/XmlUtils"),{getMtime:getMtime}=require("../utils/FileUtils");let _cache=null;function parseProps(e){if(!e)return{};const t={},
|
|
1
|
+
"use strict";const{parseXmlFile:parseXmlFile}=require("../utils/XmlUtils"),{getMtime:getMtime}=require("../utils/FileUtils");let _cache=null;function parseProps(e){if(!e)return{};const t={},s=e.split("@@!@@");for(const e of s){const s=e.indexOf("=");if(-1===s)continue;const n=e.substring(0,s).trim();if(!n)continue;const i=e.substring(s+1),o=i.trim(),c=Number(o);t[n]=""!==o&&!isNaN(c)&&isFinite(c)?c:i}return t}function loadStyles(e){const t=getMtime(e);if(_cache&&_cache.mtime===t&&_cache.path===e)return _cache.data;const s=parseXmlFile(e),n=s&&s.res&&s.res.item,i=new Map;if(!n)return i;const o=Array.isArray(n)?n:[n];for(const e of o){const t=e.name;if(!t)continue;const s=e.props||"",n={name:t,type:e.type||"Image",compress:void 0!==e.compress?Number(e.compress):void 0,pack:void 0!==e.pack?Number(e.pack):void 0,quality:void 0!==e.quality?Number(e.quality):80,props:s,propsMap:parseProps(s),picType:void 0!==e.picType?Number(e.picType):void 0,scale:void 0!==e.scale?Number(e.scale):void 0};i.set(t,n)}return expandLocales(i),_cache={mtime:t,path:e,data:i},i}const LOCALE_SEGMENTS=["vi","cn","en","tw"];function expandLocales(e){const t=new RegExp(`/(${LOCALE_SEGMENTS.join("|")})/`),s=[...e.entries()];for(const[n,i]of s){const s=t.exec(n);if(!s)continue;const o=s[1],c=s.index+1,r=c+o.length;for(const t of LOCALE_SEGMENTS){if(t===o)continue;const s=n.substring(0,c)+t+n.substring(r);e.has(s)||e.set(s,{...i,name:s})}}return e}function groupByPack(e){const t=new Map;for(const s of e.values())0!==s.pack&&(t.has(s.pack)||t.set(s.pack,[]),t.get(s.pack).push(s));return t}function isDirectoryEntry(e){return!e.split("/").pop().includes(".")}function resolveStyle(e,t){const s=e.get(t);if(s)return s;const n=t.split("/");for(let t=n.length-2;t>=1;t--){const s=n.slice(0,t+1).join("/"),i=e.get(s);if(i&&isDirectoryEntry(i.name))return i}}function invalidateCache(){_cache=null}module.exports={loadStyles:loadStyles,expandLocales:expandLocales,resolveStyle:resolveStyle,groupByPack:groupByPack,parseProps:parseProps,invalidateCache:invalidateCache};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tyhuynh-laya-cmd",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "Custom LayaAir 2 UI build tool - fast incremental atlas and UI code generation",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -28,14 +28,14 @@
|
|
|
28
28
|
"chokidar": "^3.6.0",
|
|
29
29
|
"colors": "^1.4.0",
|
|
30
30
|
"commander": "^11.0.0",
|
|
31
|
-
"fast-xml-parser": "
|
|
32
|
-
"fs-extra": "^
|
|
33
|
-
"image-size": "^
|
|
31
|
+
"fast-xml-parser": "4.0.0",
|
|
32
|
+
"fs-extra": "^10.1.0",
|
|
33
|
+
"image-size": "^0.9.7",
|
|
34
34
|
"maxrects-packer": "^2.7.3",
|
|
35
|
-
"sharp": "^0.
|
|
35
|
+
"sharp": "^0.30.7"
|
|
36
36
|
},
|
|
37
37
|
"engines": {
|
|
38
|
-
"node": ">=
|
|
38
|
+
"node": ">=12.0.0"
|
|
39
39
|
},
|
|
40
40
|
"license": "ISC",
|
|
41
41
|
"devDependencies": {
|