parse-tmx 3.2.0 → 3.3.0

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.d.ts CHANGED
@@ -265,6 +265,11 @@ export interface TMXPropertyNode extends TMXNode<{
265
265
  _: string;
266
266
  }
267
267
  //#endregion
268
+ //#region src/models/tmx/node/TMXPropertiesElement.d.ts
269
+ export interface TMXPropertiesElement {
270
+ property: TMXPropertyNode[];
271
+ }
272
+ //#endregion
268
273
  //#region src/models/tmx/node/TMXPropertiesNode.d.ts
269
274
  export interface TMXPropertiesNode extends TMXNode<Record<string, never>, TMXPropertyNode> {}
270
275
  //#endregion
@@ -278,9 +283,7 @@ export interface TMXObjectNode extends TMXNode<TMXObjectShared, TMXDataNode | TM
278
283
  polygon?: TMXNode<{
279
284
  points: string;
280
285
  }>[];
281
- properties?: {
282
- property: TMXPropertyNode[];
283
- }[];
286
+ properties?: TMXPropertiesElement[];
284
287
  text?: TMXTextNode[];
285
288
  }
286
289
  //#endregion
@@ -288,9 +291,7 @@ export interface TMXObjectNode extends TMXNode<TMXObjectShared, TMXDataNode | TM
288
291
  export interface TMXTileNode extends TMXNode<TMXTileShared, TMXPropertiesNode> {
289
292
  animation?: Record<string, TMXNode<number>[]>[];
290
293
  objectgroup?: Record<string, TMXObjectNode[]>[];
291
- properties?: {
292
- property: TMXPropertyNode[];
293
- }[];
294
+ properties?: TMXPropertiesElement[];
294
295
  }
295
296
  //#endregion
296
297
  //#region src/models/tmx/node/TMXEmbeddedTilesetNode.d.ts
@@ -304,6 +305,9 @@ export declare const checkIsTMXEmbeddedTilesetNode: (node: TMXDataNode | TMXEmbe
304
305
  //#region src/services/cloneNodeWithType.d.ts
305
306
  export declare const cloneNodeWithType: <TParsed>(node: BaseTMXNode<unknown>) => TParsed;
306
307
  //#endregion
308
+ //#region src/services/decodeTileData.d.ts
309
+ export declare const decodeTileData: (nodeData: TMXDataNode | TMXEmbeddedTilesetNode) => Promise<number[]>;
310
+ //#endregion
307
311
  //#region src/services/getDecompressedBytes.d.ts
308
312
  export declare const getDecompressedBytes: (bytes: Uint8Array<ArrayBuffer>, compression: Compression.Gzip | Compression.Zlib) => Promise<Uint8Array<ArrayBuffer>>;
309
313
  //#endregion
@@ -315,26 +319,19 @@ export interface TMXLayerNode extends TMXNode<TMXLayerShared, TMXDataNode | TMXE
315
319
  data?: TMXDataNode[] | TMXEmbeddedTilesetNode[];
316
320
  image?: TMXImageNode[];
317
321
  object?: TMXObjectNode[];
318
- properties?: {
319
- property: TMXPropertyNode[];
320
- }[];
322
+ properties?: TMXPropertiesElement[];
321
323
  }
322
324
  //#endregion
325
+ //#region src/services/parseLayer.d.ts
326
+ export declare const parseLayer: (node: TMXLayerNode) => TMXLayerParsed;
327
+ //#endregion
323
328
  //#region src/models/tmx/node/TMXGroupLayerNode.d.ts
324
329
  export interface TMXGroupLayerNode extends TMXNode<TMXGroupLayerShared, TMXLayerNode> {
325
- properties?: {
326
- property: TMXPropertyNode[];
327
- }[];
330
+ properties?: TMXPropertiesElement[];
328
331
  }
329
332
  //#endregion
330
- //#region src/services/parseGroup.d.ts
331
- export declare const parseGroup: (node: TMXGroupLayerNode, expectedCount: number, translateFlips: boolean) => Promise<TMXGroupLayerParsed>;
332
- //#endregion
333
- //#region src/services/parseLayer.d.ts
334
- export declare const parseLayer: (node: TMXLayerNode) => TMXLayerParsed;
335
- //#endregion
336
333
  //#region src/services/parseNode.d.ts
337
- export declare const parseNode: <TNode extends TMXGroupLayerNode | TMXLayerNode, TParsedNode = TNode extends TMXLayerNode ? TMXLayerParsed : TMXGroupLayerParsed>(node: TNode, expectedCount: number, translateFlips: boolean) => Promise<TParsedNode>;
334
+ export declare const parseNode: <TNode extends TMXGroupLayerNode | TMXLayerNode, TParsedNode = TNode extends TMXLayerNode ? TMXLayerParsed : TMXGroupLayerParsed>(node: TNode, tileCount: number, translateFlips: boolean) => Promise<TParsedNode>;
338
335
  //#endregion
339
336
  //#region src/services/parseObject.d.ts
340
337
  export declare const parseObject: (node: TMXObjectNode) => TMXObjectParsed;
@@ -343,9 +340,7 @@ export declare const parseObject: (node: TMXObjectNode) => TMXObjectParsed;
343
340
  export declare const parseObjectShape: (node: TMXObjectNode) => Shape;
344
341
  //#endregion
345
342
  //#region src/services/parseProperties.d.ts
346
- export declare const parseProperties: (properties: {
347
- property: TMXPropertyNode[];
348
- }[]) => TMXPropertiesParsed;
343
+ export declare const parseProperties: (properties: TMXPropertiesElement[]) => TMXPropertiesParsed;
349
344
  //#endregion
350
345
  //#region src/services/parseTile.d.ts
351
346
  export declare const parseTile: (node: TMXTileNode) => TMXTileParsed;
@@ -354,7 +349,7 @@ export declare const parseTile: (node: TMXTileNode) => TMXTileParsed;
354
349
  export declare const parseTileId: (gid: number) => number;
355
350
  //#endregion
356
351
  //#region src/services/parseTileLayer.d.ts
357
- export declare const parseTileLayer: (node: TMXLayerNode, expectedCount: number, translateFlips: boolean) => Promise<TMXLayerParsed>;
352
+ export declare const parseTileLayer: (node: TMXLayerNode, tileCount: number, translateFlips: boolean) => Promise<TMXLayerParsed>;
358
353
  //#endregion
359
354
  //#region src/models/tmx/node/TMXExternalTilesetNode.d.ts
360
355
  export interface TMXExternalTilesetNode extends TMXNode<TMXExternalTilesetShared> {}
@@ -372,7 +367,7 @@ export declare const parseXmlString: <T extends object>(xmlString: string) => Pr
372
367
  export declare const parseXmlValue: (value: string) => boolean | number | string;
373
368
  //#endregion
374
369
  //#region src/services/unpackTileBytes.d.ts
375
- export declare const unpackTileBytes: (bytes: Uint8Array, expectedCount: number) => number[];
370
+ export declare const unpackTileBytes: (bytes: Uint8Array) => number[];
376
371
  //#endregion
377
372
  //#region src/models/tmx/node/TMXExportNode.d.ts
378
373
  export interface TMXExportNode extends TMXNode<TMXExportShared> {}
package/dist/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { InvalidOperationError, Operation, exhaustiveGuard, normalizeString, takeOne } from "@esposter/shared";
2
2
  import { parseStringPromise } from "@esposter/xml2js";
3
- import parseDataUrl from "data-urls";
4
3
  //#region src/models/tmx/node/TMXNodeType.ts
5
4
  let TMXNodeType = /* @__PURE__ */ function(TMXNodeType) {
6
5
  TMXNodeType["Data"] = "data";
@@ -55,17 +54,9 @@ var TMXParsed = class {
55
54
  //#endregion
56
55
  //#region src/services/cloneNodeWithType.ts
57
56
  const cloneNodeWithType = (node) => {
58
- const parsed = structuredClone(node.$);
59
- parsed.type = node["#name"];
60
- return parsed;
61
- };
62
- //#endregion
63
- //#region src/services/parseGroup.ts
64
- const parseGroup = async (node, expectedCount, translateFlips) => {
65
- const { $$ } = node;
66
- const group = cloneNodeWithType(node);
67
- group.layers = await Promise.all($$.map((l) => parseNode(l, expectedCount, translateFlips)));
68
- return group;
57
+ const attributes = structuredClone(node.$);
58
+ attributes.type = node["#name"];
59
+ return attributes;
69
60
  };
70
61
  //#endregion
71
62
  //#region src/models/Flipped.ts
@@ -143,7 +134,7 @@ const parseLayer = (node) => {
143
134
  const { image, object, properties } = node;
144
135
  const layer = cloneNodeWithType(node);
145
136
  if (image) layer.image = structuredClone(takeOne(image).$);
146
- if (object) layer.objects = object.map((o) => parseObject(o));
137
+ if (object) layer.objects = object.map((objectNode) => parseObject(objectNode));
147
138
  if (properties) layer.properties = parseProperties(properties);
148
139
  return layer;
149
140
  };
@@ -173,63 +164,64 @@ const getDecompressedBytes = async (bytes, compression) => {
173
164
  };
174
165
  //#endregion
175
166
  //#region src/services/unpackTileBytes.ts
176
- const unpackTileBytes = (bytes, expectedCount) => {
177
- if (bytes.byteLength !== expectedCount) throw new InvalidOperationError(Operation.Read, "TMXLayer", `expected ${expectedCount} bytes of tile data, received ${bytes.byteLength}`);
167
+ const unpackTileBytes = (bytes) => {
168
+ if (bytes.byteLength % Uint32Array.BYTES_PER_ELEMENT !== 0) throw new InvalidOperationError(Operation.Read, "TMXLayer", `expected whole ${Uint32Array.BYTES_PER_ELEMENT}-byte tiles, received ${bytes.byteLength} bytes`);
178
169
  const unpackedTiles = [];
179
170
  const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
180
- for (let i = 0; i < expectedCount; i += 4) unpackedTiles.push(dataView.getUint32(i, true));
171
+ for (let byteIndex = 0; byteIndex < bytes.byteLength; byteIndex += Uint32Array.BYTES_PER_ELEMENT) unpackedTiles.push(dataView.getUint32(byteIndex, true));
181
172
  return unpackedTiles;
182
173
  };
183
174
  //#endregion
175
+ //#region src/services/decodeTileData.ts
176
+ const decodeTileData = async (nodeData) => {
177
+ if (checkIsTMXEmbeddedTilesetNode(nodeData)) return nodeData.tile?.map(({ $ }) => $.gid ?? 0) ?? [];
178
+ const { $, _ } = nodeData;
179
+ const { compression, encoding } = $;
180
+ const layerData = normalizeString(_);
181
+ switch (encoding) {
182
+ case "base64": {
183
+ const bytes = Uint8Array.fromBase64(layerData);
184
+ switch (compression) {
185
+ case "gzip":
186
+ case "zlib": return unpackTileBytes(await getDecompressedBytes(bytes, compression));
187
+ case void 0: return unpackTileBytes(bytes);
188
+ default: return exhaustiveGuard(compression);
189
+ }
190
+ }
191
+ case "csv": return layerData.split(",").map(Number);
192
+ default: return exhaustiveGuard(encoding);
193
+ }
194
+ };
195
+ //#endregion
184
196
  //#region src/services/parseTileLayer.ts
185
- const parseTileLayer = async (node, expectedCount, translateFlips) => {
197
+ const parseTileLayer = async (node, tileCount, translateFlips) => {
186
198
  const { data, properties } = node;
187
199
  if (!data) throw new InvalidOperationError(Operation.Read, "TMXLayer", "data is missing");
188
200
  const layer = cloneNodeWithType(node);
189
201
  if (properties) layer.properties = parseProperties(properties);
190
202
  const nodeData = takeOne(data);
191
- if (checkIsTMXEmbeddedTilesetNode(nodeData)) layer.data = nodeData.tile?.map(({ $ }) => $.gid ?? 0) ?? [];
192
- else {
193
- const { $, _ } = nodeData;
194
- const { compression, encoding } = $;
195
- const layerData = normalizeString(_);
196
- switch (encoding) {
197
- case "base64": {
198
- const bytes = Uint8Array.fromBase64(layerData);
199
- switch (compression) {
200
- case "gzip":
201
- case "zlib":
202
- layer.data = unpackTileBytes(await getDecompressedBytes(bytes, compression), expectedCount);
203
- break;
204
- case void 0:
205
- layer.data = unpackTileBytes(bytes, expectedCount);
206
- break;
207
- default: exhaustiveGuard(compression);
208
- }
209
- break;
210
- }
211
- case "csv":
212
- layer.data = layerData.split(",").map(Number);
213
- break;
214
- default: exhaustiveGuard(encoding);
215
- }
216
- }
203
+ const tiles = await decodeTileData(nodeData);
204
+ if (tiles.length !== tileCount) throw new InvalidOperationError(Operation.Read, "TMXLayer", `expected ${tileCount} tiles, received ${tiles.length}`);
217
205
  if (translateFlips) {
218
- layer.data ??= [];
219
- layer.flips = layer.data.map((gid) => parseFlips(gid));
220
- layer.data = layer.data.map((gid) => parseTileId(gid));
221
- }
206
+ layer.data = tiles.map((gid) => parseTileId(gid));
207
+ layer.flips = tiles.map((gid) => parseFlips(gid));
208
+ } else layer.data = tiles;
222
209
  return layer;
223
210
  };
224
211
  //#endregion
225
212
  //#region src/services/parseNode.ts
226
- const parseNode = (node, expectedCount, translateFlips) => {
213
+ const parseGroup = async (node, tileCount, translateFlips) => {
214
+ const group = cloneNodeWithType(node);
215
+ group.layers = await Promise.all(node.$$.map((layerNode) => parseNode(layerNode, tileCount, translateFlips)));
216
+ return group;
217
+ };
218
+ const parseNode = (node, tileCount, translateFlips) => {
227
219
  const tmxNodeType = node["#name"];
228
220
  switch (tmxNodeType) {
229
- case "group": return parseGroup(node, expectedCount, translateFlips);
221
+ case "group": return parseGroup(node, tileCount, translateFlips);
230
222
  case "imagelayer":
231
223
  case "objectgroup": return Promise.resolve(parseLayer(node));
232
- case "layer": return parseTileLayer(node, expectedCount, translateFlips);
224
+ case "layer": return parseTileLayer(node, tileCount, translateFlips);
233
225
  default: throw new InvalidOperationError(Operation.Read, parseNode.name, tmxNodeType);
234
226
  }
235
227
  };
@@ -251,17 +243,15 @@ const parseTile = (node) => {
251
243
  const parseTileset = (node) => {
252
244
  if (checkIsExternalTileset(node.$)) return structuredClone(node.$);
253
245
  const { $, $$, tile } = node;
254
- for (const childNode of $$) {
255
- if (childNode["#name"] !== "image") continue;
256
- const image = structuredClone(childNode.$);
257
- const tiles = tile?.map((t) => parseTile(t)) ?? [];
258
- return {
259
- ...$,
260
- image,
261
- tiles
262
- };
263
- }
264
- throw new InvalidOperationError(Operation.Read, parseTileset.name, $.name);
246
+ const imageNode = $$.find((childNode) => childNode["#name"] === "image");
247
+ if (!imageNode) throw new InvalidOperationError(Operation.Read, parseTileset.name, $.name);
248
+ const image = structuredClone(imageNode.$);
249
+ const tiles = tile?.map((tileNode) => parseTile(tileNode)) ?? [];
250
+ return {
251
+ ...$,
252
+ image,
253
+ tiles
254
+ };
265
255
  };
266
256
  //#endregion
267
257
  //#region src/services/parseXmlValue.ts
@@ -274,20 +264,17 @@ const parseXmlValue = (value) => {
274
264
  };
275
265
  //#endregion
276
266
  //#region src/services/parseXmlString.ts
277
- const parseXmlString = (xmlString) => {
278
- const xml = parseDataUrl(xmlString) ?? xmlString;
279
- return parseStringPromise(xml, {
280
- attrValueProcessors: [(value) => parseXmlValue(value)],
281
- explicitChildren: true,
282
- preserveChildrenOrder: true
283
- });
284
- };
267
+ const parseXmlString = (xmlString) => parseStringPromise(xmlString, {
268
+ attrValueProcessors: [(value) => parseXmlValue(value)],
269
+ explicitChildren: true,
270
+ preserveChildrenOrder: true
271
+ });
285
272
  //#endregion
286
273
  //#region src/parseTmx.ts
287
274
  const parseTmx = async (xmlString, translateFlips = false) => {
288
275
  const { map: { $, $$ } } = await parseXmlString(xmlString);
289
276
  const map = new TMXMapParsed($);
290
- const expectedCount = map.width * map.height * 4;
277
+ const tileCount = map.width * map.height;
291
278
  for (const node of $$) {
292
279
  const tmxNodeType = node["#name"];
293
280
  switch (tmxNodeType) {
@@ -304,7 +291,7 @@ const parseTmx = async (xmlString, translateFlips = false) => {
304
291
  case "imagelayer":
305
292
  case "layer":
306
293
  case "objectgroup": {
307
- const layer = await parseNode(node, expectedCount, translateFlips);
294
+ const layer = await parseNode(node, tileCount, translateFlips);
308
295
  map.layers.push(layer);
309
296
  break;
310
297
  }
@@ -327,4 +314,4 @@ var BaseTMXNode = class {
327
314
  $;
328
315
  };
329
316
  //#endregion
330
- export { BaseTMXNode, Compression, Encoding, Flipped, Flippeds, Shape, TMXMapParsed, TMXMapShared, TMXNodeType, TMXParsed, checkIsExternalTileset, checkIsTMXEmbeddedTilesetNode, cloneNodeWithType, getDecompressedBytes, parseFlips, parseGroup, parseLayer, parseNode, parseObject, parseObjectShape, parseProperties, parseTile, parseTileId, parseTileLayer, parseTileset, parseTmx, parseXmlString, parseXmlValue, unpackTileBytes };
317
+ export { BaseTMXNode, Compression, Encoding, Flipped, Flippeds, Shape, TMXMapParsed, TMXMapShared, TMXNodeType, TMXParsed, checkIsExternalTileset, checkIsTMXEmbeddedTilesetNode, cloneNodeWithType, decodeTileData, getDecompressedBytes, parseFlips, parseLayer, parseNode, parseObject, parseObjectShape, parseProperties, parseTile, parseTileId, parseTileLayer, parseTileset, parseTmx, parseXmlString, parseXmlValue, unpackTileBytes };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "parse-tmx",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "description": "A parser for tmx.",
5
5
  "keywords": [
6
6
  "game-development",
@@ -52,19 +52,16 @@
52
52
  "typecheck": "tsc"
53
53
  },
54
54
  "dependencies": {
55
- "@esposter/shared": "3.2.0",
56
- "@esposter/xml2js": "3.2.0",
57
- "data-urls": "^7.0.0"
55
+ "@esposter/shared": "3.3.0",
56
+ "@esposter/xml2js": "3.3.0"
58
57
  },
59
58
  "devDependencies": {
60
59
  "@arethetypeswrong/core": "^0.18.5",
61
- "@esposter/configuration": "3.2.0",
62
- "@types/data-urls": "^3.0.5",
63
- "@types/xml2js": "^0.4.14",
60
+ "@esposter/configuration": "3.3.0",
64
61
  "publint": "^0.3.24",
65
62
  "tsdown": "^0.23.0",
66
63
  "type-fest": "^5.10.0",
67
- "vitest": "^5.0.1"
64
+ "vitest": "^5.0.2"
68
65
  },
69
- "gitHead": "bc055ed2f154eff219a355016a6b586962dbfa9c"
66
+ "gitHead": "5854a00717502d8de96adc8b44d3621ab85f9b57"
70
67
  }