@openfairygui/cli 0.2.0-alpha.29 → 0.2.0-alpha.30

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.
Files changed (2) hide show
  1. package/dist/cli.mjs +151 -14
  2. package/package.json +4 -4
package/dist/cli.mjs CHANGED
@@ -1314,6 +1314,7 @@ var Package = class extends ExtensibleProperty {
1314
1314
  publishPackageCount: 0,
1315
1315
  genCode: false,
1316
1316
  codePath: "",
1317
+ resourceFolders: [],
1317
1318
  resources: new RefSet(),
1318
1319
  atlases: new RefSet(),
1319
1320
  dependencies: new RefSet()
@@ -1373,6 +1374,12 @@ var Package = class extends ExtensibleProperty {
1373
1374
  setCodePath(path) {
1374
1375
  return this.set("codePath", path);
1375
1376
  }
1377
+ listResourceFolders() {
1378
+ return this.get("resourceFolders").map((folder) => ({ ...folder }));
1379
+ }
1380
+ setResourceFolders(folders) {
1381
+ return this.set("resourceFolders", folders.map((folder) => ({ ...folder })));
1382
+ }
1376
1383
  addResource(resource) {
1377
1384
  return this.addRef("resources", resource);
1378
1385
  }
@@ -9837,6 +9844,20 @@ var Document = class Document {
9837
9844
  }
9838
9845
  };
9839
9846
  //#endregion
9847
+ //#region ../core/src/utils/resource-folder.ts
9848
+ function normalizeResourceFolderPath(value) {
9849
+ const segments = value.replace(/\\/g, "/").split("/").filter(Boolean);
9850
+ return segments.length > 0 ? `/${segments.join("/")}/` : "/";
9851
+ }
9852
+ function resourceFolderParentPath(value) {
9853
+ const segments = normalizeResourceFolderPath(value).split("/").filter(Boolean);
9854
+ segments.pop();
9855
+ return segments.length > 0 ? `/${segments.join("/")}/` : "/";
9856
+ }
9857
+ function resourceFolderName(value) {
9858
+ return normalizeResourceFolderPath(value).split("/").filter(Boolean).pop() ?? "";
9859
+ }
9860
+ //#endregion
9840
9861
  //#region ../core/src/io/project-xml-protocol.ts
9841
9862
  const mergeAttrs = (...parts) => Object.assign({}, ...parts);
9842
9863
  const mergeChildren = (...parts) => Object.assign({}, ...parts);
@@ -9876,6 +9897,13 @@ const PACKAGE_RESOURCE_BASE_ATTRS = {
9876
9897
  exported: { canonical: "exported" },
9877
9898
  favorite: { canonical: "favorite" }
9878
9899
  };
9900
+ const PACKAGE_RESOURCE_FOLDER_ATTRS = {
9901
+ id: PACKAGE_RESOURCE_BASE_ATTRS.id,
9902
+ name: PACKAGE_RESOURCE_BASE_ATTRS.name,
9903
+ path: PACKAGE_RESOURCE_BASE_ATTRS.path,
9904
+ favorite: PACKAGE_RESOURCE_BASE_ATTRS.favorite,
9905
+ atlas: { canonical: "atlas" }
9906
+ };
9879
9907
  const PACKAGE_IMAGE_RESOURCE_ATTRS = {
9880
9908
  atlas: { canonical: "atlas" },
9881
9909
  scale: { canonical: "scale" },
@@ -10264,6 +10292,7 @@ const BRANCH_DESCRIPTION_NODE = defineNode(BRANCH_DESCRIPTION_ATTRS);
10264
10292
  const PACKAGE_PUBLISH_ATLAS_NODE = defineNode(PACKAGE_PUBLISH_ATLAS_ATTRS);
10265
10293
  const PACKAGE_PUBLISH_NODE = defineNode(PACKAGE_PUBLISH_ATTRS, { atlas: PACKAGE_PUBLISH_ATLAS_NODE });
10266
10294
  const PACKAGE_RESOURCE_NODE = defineNode(PACKAGE_RESOURCE_BASE_ATTRS);
10295
+ const PACKAGE_RESOURCE_FOLDER_NODE = defineNode(PACKAGE_RESOURCE_FOLDER_ATTRS);
10267
10296
  const PACKAGE_IMAGE_RESOURCE_NODE = defineNode(PACKAGE_IMAGE_RESOURCE_ATTRS);
10268
10297
  const PACKAGE_FONT_RESOURCE_NODE = defineNode(PACKAGE_FONT_RESOURCE_ATTRS);
10269
10298
  const PACKAGE_MOVIE_CLIP_RESOURCE_NODE = defineNode(PACKAGE_MOVIE_CLIP_RESOURCE_ATTRS);
@@ -10356,6 +10385,7 @@ const PROJECT_XML_PROTOCOL = {
10356
10385
  packagePublish: PACKAGE_PUBLISH_NODE,
10357
10386
  packagePublishAtlas: PACKAGE_PUBLISH_ATLAS_NODE,
10358
10387
  packageResource: PACKAGE_RESOURCE_NODE,
10388
+ packageResourceFolder: PACKAGE_RESOURCE_FOLDER_NODE,
10359
10389
  packageImageResource: PACKAGE_IMAGE_RESOURCE_NODE,
10360
10390
  packageFontResource: PACKAGE_FONT_RESOURCE_NODE,
10361
10391
  packageMovieClipResource: PACKAGE_MOVIE_CLIP_RESOURCE_NODE,
@@ -12294,9 +12324,10 @@ function readImageSize(data) {
12294
12324
  return readPngSize(data) ?? readJpegSize(data);
12295
12325
  }
12296
12326
  function getOrderedPackageResourceItems(xmlContent) {
12297
- const packageEntry = parseXMLPreserveOrder(xmlContent).find((entry) => "packageDescription" in entry);
12298
- if (!packageEntry) return [];
12299
- const resourcesEntry = (Array.isArray(packageEntry.packageDescription) ? packageEntry.packageDescription : []).find((entry) => "resources" in entry);
12327
+ const descriptionEntry = parseXMLPreserveOrder(xmlContent).find((entry) => "packageDescription" in entry || "branchDescription" in entry);
12328
+ if (!descriptionEntry) return [];
12329
+ const description = "packageDescription" in descriptionEntry ? descriptionEntry.packageDescription : descriptionEntry.branchDescription;
12330
+ const resourcesEntry = (Array.isArray(description) ? description : []).find((entry) => "resources" in entry);
12300
12331
  if (!resourcesEntry) return [];
12301
12332
  return (Array.isArray(resourcesEntry.resources) ? resourcesEntry.resources : []).flatMap((entry) => {
12302
12333
  const tagName = Object.keys(entry).find((key) => key !== ":@" && key !== "#text");
@@ -12466,13 +12497,16 @@ var ProjectReader = class {
12466
12497
  pkg.setCodePath(readXmlAttr(publish, PROJECT_XML_PROTOCOL.packagePublish.attrs.codePath) || "");
12467
12498
  }
12468
12499
  if (pkg.getId()) ctx.packageMap.set(pkg.getId(), pkg);
12500
+ const packageDir = branchName ? fs.join(ctx.basePath, `assets_${branchName}`, dirName) : fs.join(ctx.basePath, "assets", dirName);
12469
12501
  const resources = desc.resources;
12502
+ const orderedResources = getOrderedPackageResourceItems(content);
12503
+ const folderEntries = orderedResources.length > 0 ? orderedResources.filter((entry) => entry.tagName === "folder").map((entry) => entry.attrs) : ensureArray(resources?.folder).map((entry) => getXmlNode(entry)).filter((entry) => !!entry);
12504
+ await this._readPackageFolders(pkg, packageDir, branchName, folderEntries);
12470
12505
  if (!resources) return;
12471
- const packageDir = branchName ? fs.join(ctx.basePath, `assets_${branchName}`, dirName) : fs.join(ctx.basePath, "assets", dirName);
12472
12506
  const createdResources = [];
12473
- const orderedResources = getOrderedPackageResourceItems(content);
12474
12507
  if (orderedResources.length > 0) {
12475
12508
  for (const { tagName, attrs } of orderedResources) {
12509
+ if (tagName === "folder") continue;
12476
12510
  const resource = this._createResourceFromXML(ctx, pkg, tagName, attrs, packageDir, branchName);
12477
12511
  if (resource) createdResources.push(resource);
12478
12512
  }
@@ -12503,6 +12537,40 @@ var ProjectReader = class {
12503
12537
  await this._hydratePackageImageSizes(createdResources, packageDir);
12504
12538
  if (options.hydrateResourceBytes) await this._hydratePackageResourceBytes(ctx.document, createdResources, packageDir);
12505
12539
  }
12540
+ async _readPackageFolders(pkg, packageDir, branch, metadataEntries) {
12541
+ const metadata = new Map(metadataEntries.map((attrs) => {
12542
+ return [normalizeResourceFolderPath(`${readXmlAttr(attrs, PROJECT_XML_PROTOCOL.packageResourceFolder.attrs.path) ?? "/"}/${readXmlAttr(attrs, PROJECT_XML_PROTOCOL.packageResourceFolder.attrs.name) ?? ""}`), attrs];
12543
+ }));
12544
+ const folders = pkg.listResourceFolders();
12545
+ const visit = async (directory, parentPath, entries) => {
12546
+ let names = entries;
12547
+ if (!names) try {
12548
+ names = await this._fs.readdir(directory);
12549
+ } catch {
12550
+ return;
12551
+ }
12552
+ for (const name of [...names].sort((left, right) => left.localeCompare(right))) {
12553
+ const childDirectory = this._fs.join(directory, name);
12554
+ let childEntries;
12555
+ try {
12556
+ childEntries = await this._fs.readdir(childDirectory);
12557
+ } catch {
12558
+ continue;
12559
+ }
12560
+ const path = normalizeResourceFolderPath(`${parentPath}/${name}`);
12561
+ const attrs = metadata.get(path);
12562
+ folders.push({
12563
+ branch,
12564
+ path,
12565
+ favorite: parseBool(readXmlAttr(attrs ?? {}, PROJECT_XML_PROTOCOL.packageResourceFolder.attrs.favorite)),
12566
+ atlas: readXmlAttr(attrs ?? {}, PROJECT_XML_PROTOCOL.packageResourceFolder.attrs.atlas) ?? ""
12567
+ });
12568
+ await visit(childDirectory, path, childEntries);
12569
+ }
12570
+ };
12571
+ await visit(packageDir, "/");
12572
+ pkg.setResourceFolders(folders);
12573
+ }
12506
12574
  async _hydratePackageImageSizes(resources, packageDir) {
12507
12575
  const fs = this._fs;
12508
12576
  for (const resource of resources) {
@@ -14099,6 +14167,7 @@ var ProjectWriter = class {
14099
14167
  const root = doc.getRoot();
14100
14168
  const basePath = fs.dirname(projectPath);
14101
14169
  const currentSourceFilePaths = /* @__PURE__ */ new Set();
14170
+ const currentResourceFolderPaths = /* @__PURE__ */ new Set();
14102
14171
  const staleSourceFilePaths = new Set((options.staleSourceFiles ?? []).map((source) => this._projectSourceFilePath(basePath, source)));
14103
14172
  for (const pkg of root.listPackages()) this._assertPackageOutputTargets(pkg);
14104
14173
  const fairyXml = `<?xml version="1.0" encoding="utf-8"?>\n<projectDescription id="${root.getProjectId()}" type="${this._projectTypeName(root.getProjectType())}" version="${root.getVersion() || "3.0"}"/>\n`;
@@ -14113,23 +14182,31 @@ var ProjectWriter = class {
14113
14182
  })) if (settings[key]) await fs.writeFile(fs.join(settingsPath, fileName), JSON.stringify(settings[key], null, " "));
14114
14183
  const assetsPath = fs.join(basePath, "assets");
14115
14184
  await fs.mkdir(assetsPath);
14116
- for (const pkg of root.listPackages()) await this._writePackage(doc, pkg, assetsPath, currentSourceFilePaths);
14185
+ for (const pkg of root.listPackages()) await this._writePackage(doc, pkg, assetsPath, currentSourceFilePaths, currentResourceFolderPaths);
14117
14186
  await this._removeStaleSourceFiles(currentSourceFilePaths, staleSourceFilePaths);
14187
+ await this._removeStaleResourceFolders(currentResourceFolderPaths, new Set((options.staleResourceFolders ?? []).map((folder) => this._projectResourceFolderPath(basePath, folder))));
14118
14188
  }
14119
- async _writePackage(_doc, pkg, assetsPath, currentSourceFilePaths) {
14189
+ async _writePackage(_doc, pkg, assetsPath, currentSourceFilePaths, currentResourceFolderPaths) {
14120
14190
  const fs = this._fs;
14121
14191
  this._assertSafePathSegment(pkg.getName(), "package name");
14122
14192
  const pkgDir = fs.join(assetsPath, pkg.getName());
14123
14193
  await fs.mkdir(pkgDir);
14124
14194
  const basePath = fs.dirname(assetsPath);
14125
14195
  const resourcesByBranch = /* @__PURE__ */ new Map();
14196
+ const foldersByBranch = /* @__PURE__ */ new Map();
14126
14197
  for (const res of pkg.listResources()) {
14127
14198
  const branchName = res.getBranch?.() ?? "";
14128
14199
  const bucket = resourcesByBranch.get(branchName) ?? [];
14129
14200
  bucket.push(res);
14130
14201
  resourcesByBranch.set(branchName, bucket);
14131
14202
  }
14203
+ for (const folder of pkg.listResourceFolders()) {
14204
+ const bucket = foldersByBranch.get(folder.branch) ?? [];
14205
+ bucket.push(folder);
14206
+ foldersByBranch.set(folder.branch, bucket);
14207
+ }
14132
14208
  const mainResources = resourcesByBranch.get("") ?? [];
14209
+ const mainFolders = foldersByBranch.get("") ?? [];
14133
14210
  const publishName = pkg.getPublishName() || pkg.getName();
14134
14211
  const publishPath = pkg.getPublishPath();
14135
14212
  const publishBranchPath = pkg.getPublishBranchPath();
@@ -14138,7 +14215,7 @@ var ProjectWriter = class {
14138
14215
  const codePath = pkg.getCodePath();
14139
14216
  const packageDescriptionAttrs = {};
14140
14217
  writeXmlAttr(packageDescriptionAttrs, PROJECT_XML_PROTOCOL.packageDescription.attrs.id, pkg.getId());
14141
- if (pkg.listResources().some((resource) => resource.getFavorite?.())) writeXmlAttr(packageDescriptionAttrs, PROJECT_XML_PROTOCOL.packageDescription.attrs.hasFavorites, "true");
14218
+ if (pkg.listResources().some((resource) => resource.getFavorite?.()) || pkg.listResourceFolders().some((folder) => folder.favorite)) writeXmlAttr(packageDescriptionAttrs, PROJECT_XML_PROTOCOL.packageDescription.attrs.hasFavorites, "true");
14142
14219
  const compressPNG = pkg.getCompressPNG();
14143
14220
  if (compressPNG !== null) writeXmlAttr(packageDescriptionAttrs, PROJECT_XML_PROTOCOL.packageDescription.attrs.compressPNG, compressPNG ? "true" : "false");
14144
14221
  const jpegQuality = pkg.getJpegQuality();
@@ -14159,21 +14236,26 @@ var ProjectWriter = class {
14159
14236
  });
14160
14237
  if (publishAtlases.length > 0) publishAttrs.atlas = publishAtlases;
14161
14238
  const packageDescriptorPath = fs.join(pkgDir, "package.xml");
14162
- await fs.writeFile(packageDescriptorPath, this._renderPackageDescriptionXml(packageDescriptionAttrs, mainResources, publishAttrs));
14239
+ await fs.writeFile(packageDescriptorPath, this._renderPackageDescriptionXml(packageDescriptionAttrs, mainFolders, mainResources, publishAttrs));
14163
14240
  currentSourceFilePaths.add(packageDescriptorPath);
14241
+ await this._writeResourceFolders(mainFolders, pkgDir, currentResourceFolderPaths);
14164
14242
  for (const comp of mainResources.filter((resource) => resource.propertyType === "Component")) {
14165
14243
  currentSourceFilePaths.add(fs.join(pkgDir, this._componentSourceRelativePath(comp)));
14166
14244
  await writeComponent(this._fs, comp, pkgDir, this._componentSourceRelativePath(comp));
14167
14245
  }
14168
14246
  await this._writeResourceSourceFiles(mainResources, pkgDir, currentSourceFilePaths);
14169
- for (const [branchName, branchResources] of resourcesByBranch) {
14247
+ const branchNames = new Set([...resourcesByBranch.keys(), ...foldersByBranch.keys()]);
14248
+ for (const branchName of branchNames) {
14170
14249
  if (!branchName) continue;
14250
+ const branchResources = resourcesByBranch.get(branchName) ?? [];
14251
+ const branchFolders = foldersByBranch.get(branchName) ?? [];
14171
14252
  this._assertSafePathSegment(branchName, "branch name");
14172
14253
  const branchPkgDir = fs.join(basePath, `assets_${branchName}`, pkg.getName());
14173
14254
  await fs.mkdir(branchPkgDir);
14174
14255
  const branchDescriptorPath = fs.join(branchPkgDir, "package_branch.xml");
14175
- await fs.writeFile(branchDescriptorPath, this._renderBranchDescriptionXml(branchResources));
14256
+ await fs.writeFile(branchDescriptorPath, this._renderBranchDescriptionXml(branchFolders, branchResources));
14176
14257
  currentSourceFilePaths.add(branchDescriptorPath);
14258
+ await this._writeResourceFolders(branchFolders, branchPkgDir, currentResourceFolderPaths);
14177
14259
  for (const comp of branchResources.filter((resource) => resource.propertyType === "Component")) {
14178
14260
  currentSourceFilePaths.add(fs.join(branchPkgDir, this._componentSourceRelativePath(comp)));
14179
14261
  await writeComponent(this._fs, comp, branchPkgDir, this._componentSourceRelativePath(comp));
@@ -14181,6 +14263,14 @@ var ProjectWriter = class {
14181
14263
  await this._writeResourceSourceFiles(branchResources, branchPkgDir, currentSourceFilePaths);
14182
14264
  }
14183
14265
  }
14266
+ async _writeResourceFolders(folders, packageDir, currentResourceFolderPaths) {
14267
+ for (const folder of folders) {
14268
+ const relativePath = this._normalizeSourceRelativePath(folder.path);
14269
+ const targetPath = this._fs.join(packageDir, relativePath);
14270
+ await this._fs.mkdir(targetPath);
14271
+ currentResourceFolderPaths.add(targetPath);
14272
+ }
14273
+ }
14184
14274
  async _writeResourceSourceFiles(resources, packageDir, currentSourceFilePaths) {
14185
14275
  const fs = this._fs;
14186
14276
  for (const resource of resources) {
@@ -14208,18 +14298,41 @@ var ProjectWriter = class {
14208
14298
  await fs.unlink(filePath);
14209
14299
  }
14210
14300
  }
14301
+ async _removeStaleResourceFolders(currentResourceFolderPaths, staleResourceFolderPaths) {
14302
+ const candidates = [...staleResourceFolderPaths].filter((folderPath) => !currentResourceFolderPaths.has(folderPath)).sort((left, right) => right.length - left.length);
14303
+ if (candidates.length === 0) return;
14304
+ if (!this._fs.rmdir) throw new Error("Project resource folder cleanup requires a FileSystem.rmdir() implementation.");
14305
+ for (const folderPath of candidates) {
14306
+ if (!await this._fs.exists(folderPath)) continue;
14307
+ await this._fs.rmdir(folderPath);
14308
+ }
14309
+ }
14211
14310
  _assertPackageOutputTargets(pkg) {
14212
14311
  this._assertSafePathSegment(pkg.getName(), "package name");
14213
14312
  const resourcesByBranch = /* @__PURE__ */ new Map();
14313
+ const foldersByBranch = /* @__PURE__ */ new Map();
14214
14314
  for (const resource of pkg.listResources()) {
14215
14315
  const branchName = resource.getBranch?.() ?? "";
14216
14316
  const bucket = resourcesByBranch.get(branchName) ?? [];
14217
14317
  bucket.push(resource);
14218
14318
  resourcesByBranch.set(branchName, bucket);
14219
14319
  }
14220
- for (const [branchName, resources] of resourcesByBranch) {
14320
+ for (const folder of pkg.listResourceFolders()) {
14321
+ const bucket = foldersByBranch.get(folder.branch) ?? [];
14322
+ bucket.push(folder);
14323
+ foldersByBranch.set(folder.branch, bucket);
14324
+ }
14325
+ for (const branchName of new Set([...resourcesByBranch.keys(), ...foldersByBranch.keys()])) {
14326
+ const resources = resourcesByBranch.get(branchName) ?? [];
14221
14327
  if (branchName) this._assertSafePathSegment(branchName, "branch name");
14222
14328
  const targets = new Map([[branchName ? "package_branch.xml" : "package.xml", "package descriptor"]]);
14329
+ for (const folder of foldersByBranch.get(branchName) ?? []) {
14330
+ const target = this._normalizeSourceRelativePath(folder.path);
14331
+ if (!target) throw new Error(`Package "${pkg.getName()}" cannot declare the resource root as a folder.`);
14332
+ const previous = targets.get(target);
14333
+ if (previous) throw new Error(`Package "${pkg.getName()}" output "${target}" conflicts with ${previous}.`);
14334
+ targets.set(target, `resource folder "${folder.path}"`);
14335
+ }
14223
14336
  for (const resource of resources) {
14224
14337
  const target = resource.propertyType === "Component" ? this._componentSourceRelativePath(resource) : this._resourceSourceRelativePath(resource, this._resourceFileName(resource));
14225
14338
  if (!target) continue;
@@ -14237,6 +14350,13 @@ var ProjectWriter = class {
14237
14350
  const assetRoot = source.branch ? `assets_${source.branch}` : "assets";
14238
14351
  return this._fs.join(basePath, assetRoot, source.packageName, relativePath);
14239
14352
  }
14353
+ _projectResourceFolderPath(basePath, folder) {
14354
+ this._assertSafePathSegment(folder.packageName, "resource folder package name");
14355
+ if (folder.branch) this._assertSafePathSegment(folder.branch, "resource folder branch name");
14356
+ const relativePath = this._normalizeSourceRelativePath(folder.path);
14357
+ const assetRoot = folder.branch ? `assets_${folder.branch}` : "assets";
14358
+ return this._fs.join(basePath, assetRoot, folder.packageName, relativePath);
14359
+ }
14240
14360
  _resourceSourceRelativePath(resource, fileName) {
14241
14361
  if (!fileName) return "";
14242
14362
  this._assertSafePathSegment(fileName, "resource file name");
@@ -14258,12 +14378,13 @@ var ProjectWriter = class {
14258
14378
  if (segments.some((segment) => segment === "." || segment === ".." || segment.includes(":"))) throw new Error(`Invalid project source path "${value}".`);
14259
14379
  return segments.join("/");
14260
14380
  }
14261
- _renderPackageDescriptionXml(packageDescriptionAttrs, resources, publishAttrs) {
14381
+ _renderPackageDescriptionXml(packageDescriptionAttrs, folders, resources, publishAttrs) {
14262
14382
  const publishNodeAttrs = Object.fromEntries(Object.entries(publishAttrs).filter(([key]) => key !== "atlas"));
14263
14383
  const lines = [
14264
14384
  "<?xml version=\"1.0\" encoding=\"utf-8\"?>",
14265
14385
  `<packageDescription${renderXmlAttrs(packageDescriptionAttrs)}>`,
14266
14386
  " <resources>",
14387
+ ...this._renderPackageResourceFolderLines(folders, " "),
14267
14388
  ...this._renderPackageResourceLines(resources, " "),
14268
14389
  " </resources>",
14269
14390
  ` <publish${renderXmlAttrs(publishNodeAttrs)}>`
@@ -14274,16 +14395,29 @@ var ProjectWriter = class {
14274
14395
  lines.push("</packageDescription>");
14275
14396
  return `${lines.join("\n")}\n`;
14276
14397
  }
14277
- _renderBranchDescriptionXml(resources) {
14398
+ _renderBranchDescriptionXml(folders, resources) {
14278
14399
  return `${[
14279
14400
  "<?xml version=\"1.0\" encoding=\"utf-8\"?>",
14280
14401
  "<branchDescription>",
14281
14402
  " <resources>",
14403
+ ...this._renderPackageResourceFolderLines(folders, " "),
14282
14404
  ...this._renderPackageResourceLines(resources, " "),
14283
14405
  " </resources>",
14284
14406
  "</branchDescription>"
14285
14407
  ].join("\n")}\n`;
14286
14408
  }
14409
+ _renderPackageResourceFolderLines(folders, indent) {
14410
+ return [...folders].filter((folder) => folder.favorite || folder.atlas).sort((left, right) => left.path.localeCompare(right.path)).map((folder) => {
14411
+ const attrs = {};
14412
+ const id = folder.branch ? `/:${folder.branch}${folder.path}` : folder.path;
14413
+ writeXmlAttr(attrs, PROJECT_XML_PROTOCOL.packageResourceFolder.attrs.id, id);
14414
+ writeXmlAttr(attrs, PROJECT_XML_PROTOCOL.packageResourceFolder.attrs.name, resourceFolderName(folder.path));
14415
+ writeXmlAttr(attrs, PROJECT_XML_PROTOCOL.packageResourceFolder.attrs.path, resourceFolderParentPath(folder.path));
14416
+ if (folder.favorite) writeXmlAttr(attrs, PROJECT_XML_PROTOCOL.packageResourceFolder.attrs.favorite, "true");
14417
+ if (folder.atlas) writeXmlAttr(attrs, PROJECT_XML_PROTOCOL.packageResourceFolder.attrs.atlas, folder.atlas);
14418
+ return `${indent}<folder${renderXmlAttrs(attrs)}/>`;
14419
+ });
14420
+ }
14287
14421
  _renderPackageResourceLines(resources, indent) {
14288
14422
  return this._orderedPackageResources(resources).map((resource) => {
14289
14423
  const serialized = this._serializePackageResourceEntry(resource);
@@ -26308,6 +26442,9 @@ var NodeIO = class extends PlatformIO {
26308
26442
  async unlink(filePath) {
26309
26443
  await fs$1.unlink(filePath);
26310
26444
  },
26445
+ async rmdir(dirPath) {
26446
+ await fs$1.rmdir(dirPath);
26447
+ },
26311
26448
  join(...paths) {
26312
26449
  return path$1.join(...paths);
26313
26450
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfairygui/cli",
3
- "version": "0.2.0-alpha.29",
3
+ "version": "0.2.0-alpha.30",
4
4
  "description": "FairyGUI Headless Authoring SDK — command-line interface.",
5
5
  "author": "OpenFairyGUI Contributors",
6
6
  "license": "MIT",
@@ -33,13 +33,13 @@
33
33
  "restore"
34
34
  ],
35
35
  "devDependencies": {
36
- "@openfairygui/core": "0.2.0-alpha.29",
37
- "@openfairygui/functions": "0.2.0-alpha.29"
36
+ "@openfairygui/core": "0.2.0-alpha.30",
37
+ "@openfairygui/functions": "0.2.0-alpha.30"
38
38
  },
39
39
  "dependencies": {
40
40
  "commander": "^14.0.2",
41
41
  "jiti": "^2.7.0",
42
- "@openfairygui/backend": "0.2.0-alpha.29"
42
+ "@openfairygui/backend": "0.2.0-alpha.30"
43
43
  },
44
44
  "optionalDependencies": {
45
45
  "sharp": ">=0.33.0"