@codexo/exojs-ldtk 0.15.3 → 0.16.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.
Files changed (67) hide show
  1. package/README.md +38 -20
  2. package/dist/esm/LdtkData.d.ts +59 -14
  3. package/dist/esm/LdtkData.d.ts.map +1 -0
  4. package/dist/esm/LdtkData.js +8 -16
  5. package/dist/esm/LdtkData.js.map +1 -1
  6. package/dist/esm/LdtkMap.d.ts +25 -6
  7. package/dist/esm/LdtkMap.d.ts.map +1 -0
  8. package/dist/esm/LdtkMap.js +88 -63
  9. package/dist/esm/LdtkMap.js.map +1 -1
  10. package/dist/esm/LdtkProject.d.ts +107 -0
  11. package/dist/esm/LdtkProject.d.ts.map +1 -0
  12. package/dist/esm/LdtkProject.js +136 -0
  13. package/dist/esm/LdtkProject.js.map +1 -0
  14. package/dist/esm/index.d.ts +1 -0
  15. package/dist/esm/index.d.ts.map +1 -0
  16. package/dist/esm/index.js +11 -7
  17. package/dist/esm/ldtkExtension.d.ts +9 -5
  18. package/dist/esm/ldtkExtension.d.ts.map +1 -0
  19. package/dist/esm/ldtkExtension.js +25 -22
  20. package/dist/esm/ldtkExtension.js.map +1 -1
  21. package/dist/esm/ldtkLevelEntries.d.ts +4 -3
  22. package/dist/esm/ldtkLevelEntries.d.ts.map +1 -0
  23. package/dist/esm/ldtkLevelEntries.js +30 -26
  24. package/dist/esm/ldtkLevelEntries.js.map +1 -1
  25. package/dist/esm/ldtkParallax.d.ts +22 -0
  26. package/dist/esm/ldtkParallax.d.ts.map +1 -0
  27. package/dist/esm/ldtkParallax.js +22 -0
  28. package/dist/esm/ldtkParallax.js.map +1 -0
  29. package/dist/esm/ldtkToMapWorld.d.ts +20 -0
  30. package/dist/esm/ldtkToMapWorld.d.ts.map +1 -0
  31. package/dist/esm/ldtkToMapWorld.js +76 -0
  32. package/dist/esm/ldtkToMapWorld.js.map +1 -0
  33. package/dist/esm/ldtkToTileMap.d.ts +48 -10
  34. package/dist/esm/ldtkToTileMap.d.ts.map +1 -0
  35. package/dist/esm/ldtkToTileMap.js +410 -387
  36. package/dist/esm/ldtkToTileMap.js.map +1 -1
  37. package/dist/esm/ldtkTypes.d.ts +47 -0
  38. package/dist/esm/ldtkTypes.d.ts.map +1 -0
  39. package/dist/esm/ldtkTypes.js +57 -0
  40. package/dist/esm/ldtkTypes.js.map +1 -0
  41. package/dist/esm/loadLdtkMap.d.ts +30 -5
  42. package/dist/esm/loadLdtkMap.d.ts.map +1 -0
  43. package/dist/esm/loadLdtkMap.js +139 -133
  44. package/dist/esm/loadLdtkMap.js.map +1 -1
  45. package/dist/esm/loadLdtkProject.d.ts +17 -0
  46. package/dist/esm/loadLdtkProject.d.ts.map +1 -0
  47. package/dist/esm/loadLdtkProject.js +31 -0
  48. package/dist/esm/loadLdtkProject.js.map +1 -0
  49. package/dist/esm/public.d.ts +24 -9
  50. package/dist/esm/public.d.ts.map +1 -0
  51. package/dist/esm/public.js +11 -0
  52. package/dist/esm/url.d.ts +16 -0
  53. package/dist/esm/url.d.ts.map +1 -0
  54. package/dist/esm/url.js +31 -0
  55. package/dist/esm/url.js.map +1 -0
  56. package/dist/esm/validate.d.ts +27 -0
  57. package/dist/esm/validate.d.ts.map +1 -0
  58. package/dist/esm/validate.js +327 -0
  59. package/dist/esm/validate.js.map +1 -0
  60. package/package.json +10 -18
  61. package/dist/esm/index.js.map +0 -1
  62. package/dist/esm/ldtkBinding.d.ts +0 -22
  63. package/dist/esm/ldtkBinding.js +0 -31
  64. package/dist/esm/ldtkBinding.js.map +0 -1
  65. package/dist/esm/register.d.ts +0 -1
  66. package/dist/esm/register.js +0 -17
  67. package/dist/esm/register.js.map +0 -1
@@ -0,0 +1,31 @@
1
+ import { validateLdtkData } from "./validate.js";
2
+ import { LdtkProject } from "./LdtkProject.js";
3
+ import { loadLdtkTileset } from "./loadLdtkMap.js";
4
+ import { Asset } from "@codexo/exojs";
5
+
6
+ //#region src/loadLdtkProject.ts
7
+ /**
8
+ * Read and validate a `.ldtk` document and load every tileset atlas it
9
+ * references, without touching any level payload.
10
+ *
11
+ * External `.ldtkl` levels are deliberately left unfetched - that is the whole
12
+ * point of {@link LdtkProject}: the world layout arrives, the levels arrive
13
+ * when a level runtime asks for them.
14
+ *
15
+ * @throws {import('./validate').LdtkFormatError} for a structurally invalid
16
+ * document, or a tileset whose declared atlas cannot hold a single tile. An
17
+ * embed-atlas tileset (`relPath = null`) is skipped with a warning instead.
18
+ * @internal
19
+ */
20
+ const loadLdtkProject = async (context) => {
21
+ const source = context.source;
22
+ const data = validateLdtkData(await context.dependencies.load(Asset.type("json", source)), source);
23
+ const tilesetEntries = await Promise.all(data.defs.tilesets.map(async (def) => [def.uid, await loadLdtkTileset(def, source, context)]));
24
+ const tilesets = /* @__PURE__ */ new Map();
25
+ for (const [uid, tileset] of tilesetEntries) if (tileset !== null) tilesets.set(uid, tileset);
26
+ return new LdtkProject(source, data, tilesets);
27
+ };
28
+
29
+ //#endregion
30
+ export { loadLdtkProject };
31
+ //# sourceMappingURL=loadLdtkProject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadLdtkProject.js","names":[],"sources":["../../src/loadLdtkProject.ts"],"sourcesContent":["import type { AssetFactoryContext } from '@codexo/exojs';\nimport { Asset } from '@codexo/exojs';\nimport type { TileSet } from '@codexo/exojs-tilemap';\n\nimport { LdtkProject } from './LdtkProject';\nimport { loadLdtkTileset } from './loadLdtkMap';\nimport { validateLdtkData } from './validate';\n\n/**\n * Read and validate a `.ldtk` document and load every tileset atlas it\n * references, without touching any level payload.\n *\n * External `.ldtkl` levels are deliberately left unfetched - that is the whole\n * point of {@link LdtkProject}: the world layout arrives, the levels arrive\n * when a level runtime asks for them.\n *\n * @throws {import('./validate').LdtkFormatError} for a structurally invalid\n * document, or a tileset whose declared atlas cannot hold a single tile. An\n * embed-atlas tileset (`relPath = null`) is skipped with a warning instead.\n * @internal\n */\nexport const loadLdtkProject = async (context: AssetFactoryContext): Promise<LdtkProject> => {\n const source = context.source;\n const data = validateLdtkData(await context.dependencies.load(Asset.type('json', source)), source);\n\n const tilesetEntries = await Promise.all(data.defs.tilesets.map(async def => [def.uid, await loadLdtkTileset(def, source, context)] as const));\n\n const tilesets = new Map<number, TileSet>();\n\n for (const [uid, tileset] of tilesetEntries) {\n if (tileset !== null) tilesets.set(uid, tileset);\n }\n\n return new LdtkProject(source, data, tilesets);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAqBA,MAAa,kBAAkB,OAAO,YAAuD;CAC3F,MAAM,SAAS,QAAQ;CACvB,MAAM,OAAO,iBAAiB,MAAM,QAAQ,aAAa,KAAK,MAAM,KAAK,QAAQ,MAAM,CAAC,GAAG,MAAM;CAEjG,MAAM,iBAAiB,MAAM,QAAQ,IAAI,KAAK,KAAK,SAAS,IAAI,OAAM,QAAO,CAAC,IAAI,KAAK,MAAM,gBAAgB,KAAK,QAAQ,OAAO,CAAC,CAAU,CAAC;CAE7I,MAAM,2BAAW,IAAI,IAAqB;CAE1C,KAAK,MAAM,CAAC,KAAK,YAAY,gBAC3B,IAAI,YAAY,MAAM,SAAS,IAAI,KAAK,OAAO;CAGjD,OAAO,IAAI,YAAY,QAAQ,MAAM,QAAQ;AAC/C"}
@@ -1,24 +1,39 @@
1
- export { ldtkMapBinding } from './ldtkBinding';
2
1
  export { ldtkExtension } from './ldtkExtension';
2
+ export { LdtkMapAssetType, ldtkMapType, LdtkProjectAssetType, ldtkProjectType } from './ldtkTypes';
3
3
  export { LdtkMap } from './LdtkMap';
4
+ export type { LdtkRuntimeOptions } from './LdtkProject';
5
+ export { LdtkProject } from './LdtkProject';
6
+ export { ldtkToMapWorld } from './ldtkToMapWorld';
4
7
  export type { LdtkToTileMapOptions } from './ldtkToTileMap';
5
- export { getLdtkIntGridValueAt, ldtkIntGridCsvProperty, ldtkIntGridValuesProperty, ldtkToTileMap, } from './ldtkToTileMap';
6
- export type { LdtkData, LdtkDefs, LdtkEntityInstance, LdtkFieldInstance, LdtkIntGridValueDef, LdtkLayerDef, LdtkLayerInstance, LdtkLayerType, LdtkLevel, LdtkTileData, LdtkTilesetDef, LdtkWorldData, LdtkWorldLayout, } from './LdtkData';
7
- export { ldtkFlipNone, ldtkFlipX, ldtkFlipXy, ldtkFlipY } from './LdtkData';
8
- export type { ChunkCoord, EllipseObject, ObjectLayerOptions, ObjectPoint, ObjectQuery, ObjectSchema, PackedTile, PointObject, PolygonObject, PolylineObject, ReadonlyTileChunk, RectangleObject, ResolvedTile, TileDefinition, TileLayerOptions, TileMapObject, TileMapObjectKind, TileMapOptions, TileMapViewOptions, TileObject, TileProperties, TilePropertyObjectRef, TilePropertyPoint, TilePropertyTileRef, TilePropertyValue, TileSetOptions, TileTransform, } from '@codexo/exojs-tilemap';
9
- export { ObjectKind, ObjectLayer, TILE_TRANSFORM_IDENTITY, TileLayer, TileMap, tilemapExtension, TileMapView, TilePropertyKind, TileSet, } from '@codexo/exojs-tilemap';
8
+ export { createLdtkIntGridCellSource, getLdtkIntGridValueAt, ldtkIntGridCsvProperty, ldtkIntGridValuesProperty, ldtkToTileMap } from './ldtkToTileMap';
9
+ export type { LdtkData, LdtkDefs, LdtkEntityInstance, LdtkFieldInstance, LdtkIntGridValueDef, LdtkLayerDef, LdtkLayerInstance, LdtkLayerType, LdtkLevel, LdtkLevelNeighbour, LdtkTileData, LdtkTilesetDef, LdtkWorldData, LdtkWorldLayout, } from './LdtkData';
10
+ export { LDTK_FLIP_NONE, LDTK_FLIP_X, LDTK_FLIP_XY, LDTK_FLIP_Y } from './LdtkData';
11
+ export { LdtkFormatError } from './validate';
12
+ export type { ChunkCoord, EllipseObject, MapBounds, MapLevel, MapLevelCancelOptions, MapLevelLoadContext, MapLevelLoadOptions, MapLevelNeighbour, MapLevelProvider, MapObjectDescriptor, MapObjectFactories, MapObjectFactory, MapObjectSpawnerOptions, MapSpawnErrorReason, MapSpawnOptions, MapWorldOptions, MapWorldRuntimeOptions, ObjectLayerOptions, ObjectPoint, ObjectQuery, ObjectSchema, PackedTile, PointObject, PolygonObject, PolylineObject, ReadonlyTileChunk, RectangleObject, ResolvedTile, TileDefinition, TileLayerOptions, TileMapObject, TileMapObjectKind, TileMapOptions, TileMapViewOptions, TileObject, TileProperties, TilePropertyObjectRef, TilePropertyPoint, TilePropertyTileRef, TilePropertyValue, TileSetOptions, TileTransform, UnknownMapObjectPolicy, } from '@codexo/exojs-tilemap';
13
+ export { MapLevelRuntime, MapLevelSide, mapObjectDescriptor, mapObjectDescriptors, MapObjectSpawner, MapSpawnError, MapSpawnSession, MapWorld, MapWorldRuntime, ObjectKind, ObjectLayer, TILE_TRANSFORM_IDENTITY, TileLayer, TileMap, tilemapExtension, TileMapView, TilePropertyKind, TileSet, } from '@codexo/exojs-tilemap';
10
14
  import type { LdtkMap } from './LdtkMap';
15
+ import type { LdtkProject } from './LdtkProject';
11
16
  declare module '@codexo/exojs' {
12
- interface ExtensionTypeMap {
13
- /** `.ldtk` path-only loads resolve to {@link LdtkMap}. */
14
- ldtk: LdtkMap;
17
+ interface ExtensionKindMap {
18
+ /** `.ldtk` bare-path loads resolve to the `ldtkMap` type ({@link LdtkMap}). */
19
+ ldtk: 'ldtkMap';
15
20
  }
16
21
  interface AssetDefinitions {
22
+ ldtkProject: {
23
+ resource: LdtkProject;
24
+ config: {
25
+ source: string;
26
+ };
27
+ /** See `ldtkMap` - `ldtkProjectType` keeps the default leaf too. */
28
+ isValue: true;
29
+ };
17
30
  ldtkMap: {
18
31
  resource: LdtkMap;
19
32
  config: {
20
33
  source: string;
21
34
  };
35
+ isValue: true;
22
36
  };
23
37
  }
24
38
  }
39
+ //# sourceMappingURL=public.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/public.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnG,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGvJ,YAAY,EACV,QAAQ,EACR,QAAQ,EACR,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,SAAS,EACT,kBAAkB,EAClB,YAAY,EACZ,cAAc,EACd,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGpF,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAK7C,YAAY,EACV,UAAU,EACV,aAAa,EACb,SAAS,EACT,QAAQ,EACR,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,uBAAuB,EACvB,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,YAAY,EACZ,UAAU,EACV,WAAW,EACX,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,UAAU,EACV,cAAc,EACd,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,EACb,eAAe,EACf,QAAQ,EACR,eAAe,EACf,UAAU,EACV,WAAW,EACX,uBAAuB,EACvB,SAAS,EACT,OAAO,EACP,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,OAAO,GACR,MAAM,uBAAuB,CAAC;AAG/B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,gBAAgB;QACxB,+EAA+E;QAC/E,IAAI,EAAE,SAAS,CAAC;KACjB;IACD,UAAU,gBAAgB;QACxB,WAAW,EAAE;YACX,QAAQ,EAAE,WAAW,CAAC;YACtB,MAAM,EAAE;gBAAE,MAAM,EAAE,MAAM,CAAA;aAAE,CAAC;YAC3B,oEAAoE;YACpE,OAAO,EAAE,IAAI,CAAC;SACf,CAAC;QACF,OAAO,EAAE;YACP,QAAQ,EAAE,OAAO,CAAC;YAClB,MAAM,EAAE;gBAAE,MAAM,EAAE,MAAM,CAAA;aAAE,CAAC;YAG3B,OAAO,EAAE,IAAI,CAAC;SACf,CAAC;KACH;CACF"}
@@ -0,0 +1,11 @@
1
+ import { LDTK_FLIP_NONE, LDTK_FLIP_X, LDTK_FLIP_XY, LDTK_FLIP_Y } from "./LdtkData.js";
2
+ import { createLdtkIntGridCellSource, getLdtkIntGridValueAt, ldtkIntGridCsvProperty, ldtkIntGridValuesProperty, ldtkToTileMap } from "./ldtkToTileMap.js";
3
+ import { ldtkToMapWorld } from "./ldtkToMapWorld.js";
4
+ import { LdtkMap } from "./LdtkMap.js";
5
+ import { LdtkFormatError } from "./validate.js";
6
+ import { LdtkProject } from "./LdtkProject.js";
7
+ import { LdtkMapAssetType, LdtkProjectAssetType, ldtkMapType, ldtkProjectType } from "./ldtkTypes.js";
8
+ import { ldtkExtension } from "./ldtkExtension.js";
9
+ import { MapLevelRuntime, MapLevelSide as MapLevelSide$1, MapObjectSpawner, MapSpawnError, MapSpawnSession, MapWorld as MapWorld$1, MapWorldRuntime as MapWorldRuntime$1, ObjectKind, ObjectLayer as ObjectLayer$1, TILE_TRANSFORM_IDENTITY, TileLayer as TileLayer$1, TileMap as TileMap$1, TileMapView, TilePropertyKind as TilePropertyKind$1, TileSet as TileSet$1, mapObjectDescriptor, mapObjectDescriptors, tilemapExtension as tilemapExtension$1 } from "@codexo/exojs-tilemap";
10
+
11
+ export { LDTK_FLIP_NONE, LDTK_FLIP_X, LDTK_FLIP_XY, LDTK_FLIP_Y, LdtkFormatError, LdtkMap, LdtkMapAssetType, LdtkProject, LdtkProjectAssetType, MapLevelRuntime, MapLevelSide$1 as MapLevelSide, MapObjectSpawner, MapSpawnError, MapSpawnSession, MapWorld$1 as MapWorld, MapWorldRuntime$1 as MapWorldRuntime, ObjectKind, ObjectLayer$1 as ObjectLayer, TILE_TRANSFORM_IDENTITY, TileLayer$1 as TileLayer, TileMap$1 as TileMap, TileMapView, TilePropertyKind$1 as TilePropertyKind, TileSet$1 as TileSet, createLdtkIntGridCellSource, getLdtkIntGridValueAt, ldtkExtension, ldtkIntGridCsvProperty, ldtkIntGridValuesProperty, ldtkMapType, ldtkProjectType, ldtkToMapWorld, ldtkToTileMap, mapObjectDescriptor, mapObjectDescriptors, tilemapExtension$1 as tilemapExtension };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Resolves `ref` (a path read from an LDtk file, e.g. a tileset `relPath` or a
3
+ * level `externalRelPath`) relative to `base` (the resolved location of the
4
+ * file that referenced it).
5
+ *
6
+ * - If `ref` is already absolute (scheme, protocol- or root-relative, or a
7
+ * `data:`/`blob:` URL), it is returned unchanged.
8
+ * - If `base` is an absolute URL, standard `new URL(ref, base)` resolution is
9
+ * used.
10
+ * - Otherwise both are relative ExoJS asset paths; `../`/`./` segments are
11
+ * collapsed via a synthetic origin and the result is returned relative again.
12
+ *
13
+ * @internal
14
+ */
15
+ export declare const resolveLdtkUrl: (ref: string, base: string) => string;
16
+ //# sourceMappingURL=url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../src/url.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,EAAE,MAAM,MAAM,KAAG,MAgB1D,CAAC"}
@@ -0,0 +1,31 @@
1
+ //#region src/url.ts
2
+ /** Matches references that are already absolute and must not be re-resolved: scheme:, protocol-relative `//`, root-relative `/`, and data/blob URLs. */
3
+ const ABSOLUTE_REF = /^(?:[a-z][a-z\d+.-]*:|\/\/|\/)/i;
4
+ /** Matches a base that is itself an absolute URL with a scheme. */
5
+ const ABSOLUTE_BASE = /^[a-z][a-z\d+.-]*:/i;
6
+ /** Synthetic origin used to borrow `URL`'s `../`/`./` collapsing for relative bases. */
7
+ const SYNTHETIC_ORIGIN = "https://exojs.invalid/";
8
+ /**
9
+ * Resolves `ref` (a path read from an LDtk file, e.g. a tileset `relPath` or a
10
+ * level `externalRelPath`) relative to `base` (the resolved location of the
11
+ * file that referenced it).
12
+ *
13
+ * - If `ref` is already absolute (scheme, protocol- or root-relative, or a
14
+ * `data:`/`blob:` URL), it is returned unchanged.
15
+ * - If `base` is an absolute URL, standard `new URL(ref, base)` resolution is
16
+ * used.
17
+ * - Otherwise both are relative ExoJS asset paths; `../`/`./` segments are
18
+ * collapsed via a synthetic origin and the result is returned relative again.
19
+ *
20
+ * @internal
21
+ */
22
+ const resolveLdtkUrl = (ref, base) => {
23
+ if (ABSOLUTE_REF.test(ref)) return ref;
24
+ if (ABSOLUTE_BASE.test(base)) return new URL(ref, base).href;
25
+ const relative = new URL(ref, SYNTHETIC_ORIGIN + base.replace(/^\/+/, "")).href.slice(22);
26
+ return base.startsWith("/") ? `/${relative}` : relative;
27
+ };
28
+
29
+ //#endregion
30
+ export { resolveLdtkUrl };
31
+ //# sourceMappingURL=url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.js","names":[],"sources":["../../src/url.ts"],"sourcesContent":["// Relative-path resolution for LDtk source references (.ldtk → tileset image,\n// .ldtk → external .ldtkl level). LDtk stores every cross-file reference as a\n// path relative to the file that contains it; ExoJS asset sources are themselves\n// often relative (resolved against an asset root configured outside the Loader),\n// so plain `new URL(ref, base)` cannot be used directly when `base` has no\n// scheme - it throws `Invalid URL`. Mirrors the Tiled adapter's `resolveTiledUrl`.\n\n/** Matches references that are already absolute and must not be re-resolved: scheme:, protocol-relative `//`, root-relative `/`, and data/blob URLs. */\nconst ABSOLUTE_REF = /^(?:[a-z][a-z\\d+.-]*:|\\/\\/|\\/)/i;\n\n/** Matches a base that is itself an absolute URL with a scheme. */\nconst ABSOLUTE_BASE = /^[a-z][a-z\\d+.-]*:/i;\n\n/** Synthetic origin used to borrow `URL`'s `../`/`./` collapsing for relative bases. */\nconst SYNTHETIC_ORIGIN = 'https://exojs.invalid/';\n\n/**\n * Resolves `ref` (a path read from an LDtk file, e.g. a tileset `relPath` or a\n * level `externalRelPath`) relative to `base` (the resolved location of the\n * file that referenced it).\n *\n * - If `ref` is already absolute (scheme, protocol- or root-relative, or a\n * `data:`/`blob:` URL), it is returned unchanged.\n * - If `base` is an absolute URL, standard `new URL(ref, base)` resolution is\n * used.\n * - Otherwise both are relative ExoJS asset paths; `../`/`./` segments are\n * collapsed via a synthetic origin and the result is returned relative again.\n *\n * @internal\n */\nexport const resolveLdtkUrl = (ref: string, base: string): string => {\n if (ABSOLUTE_REF.test(ref)) {\n return ref;\n }\n\n if (ABSOLUTE_BASE.test(base)) {\n return new URL(ref, base).href;\n }\n\n const resolved = new URL(ref, SYNTHETIC_ORIGIN + base.replace(/^\\/+/, ''));\n const relative = resolved.href.slice(SYNTHETIC_ORIGIN.length);\n\n // A root-relative base must produce a root-relative result again - dropping\n // the leading slash would make the browser re-resolve the reference against\n // the document base URL (e.g. `/site/assets/x.png` → `/site/site/assets/...`).\n return base.startsWith('/') ? `/${relative}` : relative;\n};\n"],"mappings":";;AAQA,MAAM,eAAe;;AAGrB,MAAM,gBAAgB;;AAGtB,MAAM,mBAAmB;;;;;;;;;;;;;;;AAgBzB,MAAa,kBAAkB,KAAa,SAAyB;CACnE,IAAI,aAAa,KAAK,GAAG,GACvB,OAAO;CAGT,IAAI,cAAc,KAAK,IAAI,GACzB,OAAO,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC;CAI5B,MAAM,WAAW,IADI,IAAI,KAAK,mBAAmB,KAAK,QAAQ,QAAQ,EAAE,CAChD,CAAC,CAAC,KAAK,MAAM,EAAuB;CAK5D,OAAO,KAAK,WAAW,GAAG,IAAI,IAAI,aAAa;AACjD"}
@@ -0,0 +1,27 @@
1
+ import type { LdtkData, LdtkLevel } from './LdtkData';
2
+ /**
3
+ * Thrown when an LDtk JSON document does not match the expected shape.
4
+ * `source` is the URL of the file being parsed; `path` is a JSON-path-like
5
+ * pointer (e.g. `levels[0].layerInstances[1].gridTiles[0].px`) to the
6
+ * offending value, or `''` for the document root.
7
+ */
8
+ export declare class LdtkFormatError extends Error {
9
+ readonly source: string;
10
+ readonly path: string;
11
+ constructor(source: string, path: string, message: string);
12
+ }
13
+ /**
14
+ * Validate the root of a `.ldtk` file and return it typed as {@link LdtkData}.
15
+ * Throws {@link LdtkFormatError} on any structural problem, naming the source
16
+ * URL and the property path of the offending value.
17
+ * @internal
18
+ */
19
+ export declare const validateLdtkData: (raw: unknown, source: string) => LdtkData;
20
+ /**
21
+ * Validate an external `.ldtkl` payload and return it typed as
22
+ * {@link LdtkLevel}. Paths in a thrown {@link LdtkFormatError} are relative to
23
+ * the level object, since that object is the root of the `.ldtkl` file.
24
+ * @internal
25
+ */
26
+ export declare const validateLdtkLevelData: (raw: unknown, source: string) => LdtkLevel;
27
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/validate.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,QAAQ,EAAiB,SAAS,EAAmB,MAAM,YAAY,CAAC;AAEtF;;;;;GAKG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,IAAI,EAAE,MAAM,CAAC;gBAEV,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAMjE;AAyYD;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,KAAK,OAAO,EAAE,QAAQ,MAAM,KAAG,QAgB/D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAI,KAAK,OAAO,EAAE,QAAQ,MAAM,KAAG,SAIpE,CAAC"}
@@ -0,0 +1,327 @@
1
+ //#region src/validate.ts
2
+ /**
3
+ * Thrown when an LDtk JSON document does not match the expected shape.
4
+ * `source` is the URL of the file being parsed; `path` is a JSON-path-like
5
+ * pointer (e.g. `levels[0].layerInstances[1].gridTiles[0].px`) to the
6
+ * offending value, or `''` for the document root.
7
+ */
8
+ var LdtkFormatError = class extends Error {
9
+ source;
10
+ path;
11
+ constructor(source, path, message) {
12
+ super(`Invalid LDtk data in "${source}" at ${path === "" ? "<root>" : path}: ${message}`);
13
+ this.name = "LdtkFormatError";
14
+ this.source = source;
15
+ this.path = path;
16
+ }
17
+ };
18
+ const describeValue = (value) => {
19
+ if (value === null) return "null";
20
+ if (value === void 0) return "undefined";
21
+ if (Array.isArray(value)) return "an array";
22
+ return typeof value;
23
+ };
24
+ const joinPath = (path, key) => {
25
+ if (typeof key === "number") return `${path}[${key}]`;
26
+ return path === "" ? key : `${path}.${key}`;
27
+ };
28
+ const expectObject = (value, source, path) => {
29
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw new LdtkFormatError(source, path, `expected an object, got ${describeValue(value)}`);
30
+ return value;
31
+ };
32
+ const expectArray = (value, source, path) => {
33
+ if (!Array.isArray(value)) throw new LdtkFormatError(source, path, `expected an array, got ${describeValue(value)}`);
34
+ return value;
35
+ };
36
+ const expectString = (value, source, path) => {
37
+ if (typeof value !== "string") throw new LdtkFormatError(source, path, `expected a string, got ${describeValue(value)}`);
38
+ return value;
39
+ };
40
+ const expectNumber = (value, source, path) => {
41
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new LdtkFormatError(source, path, `expected a finite number, got ${describeValue(value)}`);
42
+ return value;
43
+ };
44
+ const expectInteger = (value, source, path) => {
45
+ const n = expectNumber(value, source, path);
46
+ if (!Number.isInteger(n)) throw new LdtkFormatError(source, path, `expected an integer, got ${n}`);
47
+ return n;
48
+ };
49
+ const expectNonNegativeInteger = (value, source, path) => {
50
+ const n = expectInteger(value, source, path);
51
+ if (n < 0) throw new LdtkFormatError(source, path, `expected a non-negative integer, got ${n}`);
52
+ return n;
53
+ };
54
+ const expectPositiveInteger = (value, source, path) => {
55
+ const n = expectInteger(value, source, path);
56
+ if (n <= 0) throw new LdtkFormatError(source, path, `expected a positive integer, got ${n}`);
57
+ return n;
58
+ };
59
+ const expectBoolean = (value, source, path) => {
60
+ if (typeof value !== "boolean") throw new LdtkFormatError(source, path, `expected a boolean, got ${describeValue(value)}`);
61
+ };
62
+ /** `[x, y]` pixel/grid pairs (`px`, `src`, `__pivot`) are always two finite numbers. */
63
+ const expectNumberPair = (value, source, path) => {
64
+ const pair = expectArray(value, source, path);
65
+ if (pair.length !== 2) throw new LdtkFormatError(source, path, `expected a pair of numbers, got ${pair.length} entries`);
66
+ expectNumber(pair[0], source, joinPath(path, 0));
67
+ expectNumber(pair[1], source, joinPath(path, 1));
68
+ };
69
+ const optionalNumber = (obj, key, source, path) => {
70
+ if (obj[key] !== void 0) expectNumber(obj[key], source, joinPath(path, key));
71
+ };
72
+ const optionalNonNegativeInteger = (obj, key, source, path) => {
73
+ if (obj[key] !== void 0) expectNonNegativeInteger(obj[key], source, joinPath(path, key));
74
+ };
75
+ /**
76
+ * LDtk writes an unset optional as an explicit `null` rather than omitting the
77
+ * key, so a validator that only tolerates `undefined` rejects the files the
78
+ * editor actually produces.
79
+ */
80
+ const nullableString = (obj, key, source, path) => {
81
+ if (obj[key] !== void 0 && obj[key] !== null) expectString(obj[key], source, joinPath(path, key));
82
+ };
83
+ /** See {@link nullableString}. */
84
+ const nullableInteger = (obj, key, source, path) => {
85
+ if (obj[key] !== void 0 && obj[key] !== null) expectInteger(obj[key], source, joinPath(path, key));
86
+ };
87
+ const optionalBoolean = (obj, key, source, path) => {
88
+ if (obj[key] !== void 0) expectBoolean(obj[key], source, joinPath(path, key));
89
+ };
90
+ const eachEntry = (value, source, path, visit) => {
91
+ const array = expectArray(value, source, path);
92
+ for (let i = 0; i < array.length; i++) visit(array[i], joinPath(path, i));
93
+ };
94
+ const LAYER_TYPES = [
95
+ "Tiles",
96
+ "IntGrid",
97
+ "Entities",
98
+ "AutoLayer"
99
+ ];
100
+ const WORLD_LAYOUTS = [
101
+ "Free",
102
+ "GridVania",
103
+ "LinearHorizontal",
104
+ "LinearVertical"
105
+ ];
106
+ const validateLayerType = (value, source, path) => {
107
+ const type = expectString(value, source, path);
108
+ if (!LAYER_TYPES.includes(type)) throw new LdtkFormatError(source, path, `unknown layer type "${type}" (expected one of ${LAYER_TYPES.join(", ")})`);
109
+ };
110
+ const validateTilesetDef = (raw, source, path) => {
111
+ const def = expectObject(raw, source, path);
112
+ expectInteger(def.uid, source, joinPath(path, "uid"));
113
+ expectString(def.identifier, source, joinPath(path, "identifier"));
114
+ const relPathPath = joinPath(path, "relPath");
115
+ if (def.relPath !== null) expectString(def.relPath, source, relPathPath);
116
+ expectPositiveInteger(def.tileGridSize, source, joinPath(path, "tileGridSize"));
117
+ expectNonNegativeInteger(def.pxWid, source, joinPath(path, "pxWid"));
118
+ expectNonNegativeInteger(def.pxHei, source, joinPath(path, "pxHei"));
119
+ optionalNonNegativeInteger(def, "spacing", source, path);
120
+ optionalNonNegativeInteger(def, "padding", source, path);
121
+ };
122
+ const validateIntGridValueDef = (raw, source, path) => {
123
+ const value = expectObject(raw, source, path);
124
+ expectNumber(value.value, source, joinPath(path, "value"));
125
+ const identifierPath = joinPath(path, "identifier");
126
+ if (value.identifier !== null) expectString(value.identifier, source, identifierPath);
127
+ expectString(value.color, source, joinPath(path, "color"));
128
+ };
129
+ const validateLayerDef = (raw, source, path) => {
130
+ const def = expectObject(raw, source, path);
131
+ expectInteger(def.uid, source, joinPath(path, "uid"));
132
+ expectString(def.identifier, source, joinPath(path, "identifier"));
133
+ validateLayerType(def.type, source, joinPath(path, "type"));
134
+ expectNonNegativeInteger(def.gridSize, source, joinPath(path, "gridSize"));
135
+ optionalNumber(def, "pxOffsetX", source, path);
136
+ optionalNumber(def, "pxOffsetY", source, path);
137
+ optionalNumber(def, "parallaxFactorX", source, path);
138
+ optionalNumber(def, "parallaxFactorY", source, path);
139
+ optionalBoolean(def, "parallaxScaling", source, path);
140
+ if (def.intGridValues !== void 0) eachEntry(def.intGridValues, source, joinPath(path, "intGridValues"), (item, itemPath) => validateIntGridValueDef(item, source, itemPath));
141
+ };
142
+ const validateDefs = (raw, source, path) => {
143
+ const defs = expectObject(raw, source, path);
144
+ eachEntry(defs.tilesets, source, joinPath(path, "tilesets"), (item, itemPath) => validateTilesetDef(item, source, itemPath));
145
+ eachEntry(defs.layers, source, joinPath(path, "layers"), (item, itemPath) => validateLayerDef(item, source, itemPath));
146
+ };
147
+ /**
148
+ * Validate one field-instance `__value` against the shape its `__type` declares.
149
+ *
150
+ * `null` is LDtk's "not set" and always passes - the conversion drops the
151
+ * property. Everything else is checked here because the conversion pass casts
152
+ * rather than probes: a `Point` whose value is not `{cx, cy}` used to reach the
153
+ * runtime as a point with `undefined` coordinates, indistinguishable from a
154
+ * genuine one until something read it.
155
+ *
156
+ * A `__type` this package does not model (a future LDtk field type, or an
157
+ * `Array<T>` element type of one) is left unchecked: forward compatibility
158
+ * matters more than rejecting a value the conversion already skips.
159
+ */
160
+ const validateFieldValue = (typeName, value, source, path) => {
161
+ if (value === null || value === void 0) return;
162
+ switch (typeName) {
163
+ case "Int":
164
+ expectInteger(value, source, path);
165
+ return;
166
+ case "Float":
167
+ expectNumber(value, source, path);
168
+ return;
169
+ case "Bool":
170
+ expectBoolean(value, source, path);
171
+ return;
172
+ case "String":
173
+ case "Multilines":
174
+ case "Color":
175
+ case "FilePath":
176
+ case "Enum":
177
+ expectString(value, source, path);
178
+ return;
179
+ case "Point": {
180
+ const point = expectObject(value, source, path);
181
+ expectNumber(point.cx, source, joinPath(path, "cx"));
182
+ expectNumber(point.cy, source, joinPath(path, "cy"));
183
+ return;
184
+ }
185
+ case "EntityRef": {
186
+ const ref = expectObject(value, source, path);
187
+ for (const key of [
188
+ "entityIid",
189
+ "layerIid",
190
+ "levelIid",
191
+ "worldIid"
192
+ ]) expectString(ref[key], source, joinPath(path, key));
193
+ return;
194
+ }
195
+ case "Tile": {
196
+ const tile = expectObject(value, source, path);
197
+ expectInteger(tile.tilesetUid, source, joinPath(path, "tilesetUid"));
198
+ for (const key of [
199
+ "x",
200
+ "y",
201
+ "w",
202
+ "h"
203
+ ]) expectNumber(tile[key], source, joinPath(path, key));
204
+ return;
205
+ }
206
+ default: if (typeName.startsWith("Array<") && typeName.endsWith(">")) {
207
+ const elementType = typeName.slice(6, -1);
208
+ eachEntry(value, source, path, (item, itemPath) => validateFieldValue(elementType, item, source, itemPath));
209
+ }
210
+ }
211
+ };
212
+ /**
213
+ * A field instance is validated down to its identifier, declared type and the
214
+ * shape of `__value` that type implies - see {@link validateFieldValue}.
215
+ */
216
+ const validateFieldInstance = (raw, source, path) => {
217
+ const field = expectObject(raw, source, path);
218
+ expectString(field.__identifier, source, joinPath(path, "__identifier"));
219
+ const typeName = expectString(field.__type, source, joinPath(path, "__type"));
220
+ validateFieldValue(typeName, field.__value, source, joinPath(path, "__value"));
221
+ };
222
+ const validateFieldInstances = (value, source, path) => {
223
+ eachEntry(value, source, path, (item, itemPath) => validateFieldInstance(item, source, itemPath));
224
+ };
225
+ const validateTile = (raw, source, path) => {
226
+ const tile = expectObject(raw, source, path);
227
+ expectNumberPair(tile.px, source, joinPath(path, "px"));
228
+ expectNumberPair(tile.src, source, joinPath(path, "src"));
229
+ expectNumber(tile.f, source, joinPath(path, "f"));
230
+ expectNumber(tile.t, source, joinPath(path, "t"));
231
+ };
232
+ const validateTiles = (value, source, path) => {
233
+ eachEntry(value, source, path, (item, itemPath) => validateTile(item, source, itemPath));
234
+ };
235
+ const validateEntityInstance = (raw, source, path) => {
236
+ const entity = expectObject(raw, source, path);
237
+ expectString(entity.__identifier, source, joinPath(path, "__identifier"));
238
+ expectString(entity.__type, source, joinPath(path, "__type"));
239
+ expectNumberPair(entity.px, source, joinPath(path, "px"));
240
+ expectNumber(entity.width, source, joinPath(path, "width"));
241
+ expectNumber(entity.height, source, joinPath(path, "height"));
242
+ expectNumberPair(entity.__pivot, source, joinPath(path, "__pivot"));
243
+ expectString(entity.iid, source, joinPath(path, "iid"));
244
+ expectInteger(entity.defUid, source, joinPath(path, "defUid"));
245
+ validateFieldInstances(entity.fieldInstances, source, joinPath(path, "fieldInstances"));
246
+ };
247
+ const validateLayerInstance = (raw, source, path) => {
248
+ const layer = expectObject(raw, source, path);
249
+ expectString(layer.__identifier, source, joinPath(path, "__identifier"));
250
+ validateLayerType(layer.__type, source, joinPath(path, "__type"));
251
+ expectNonNegativeInteger(layer.__cWid, source, joinPath(path, "__cWid"));
252
+ expectNonNegativeInteger(layer.__cHei, source, joinPath(path, "__cHei"));
253
+ expectNonNegativeInteger(layer.__gridSize, source, joinPath(path, "__gridSize"));
254
+ expectInteger(layer.layerDefUid, source, joinPath(path, "layerDefUid"));
255
+ expectInteger(layer.levelId, source, joinPath(path, "levelId"));
256
+ expectBoolean(layer.visible, source, joinPath(path, "visible"));
257
+ expectString(layer.iid, source, joinPath(path, "iid"));
258
+ nullableInteger(layer, "__tilesetDefUid", source, path);
259
+ if (layer.gridTiles !== void 0) validateTiles(layer.gridTiles, source, joinPath(path, "gridTiles"));
260
+ if (layer.autoLayerTiles !== void 0) validateTiles(layer.autoLayerTiles, source, joinPath(path, "autoLayerTiles"));
261
+ if (layer.entityInstances !== void 0) eachEntry(layer.entityInstances, source, joinPath(path, "entityInstances"), (item, itemPath) => validateEntityInstance(item, source, itemPath));
262
+ if (layer.intGridCsv !== void 0) eachEntry(layer.intGridCsv, source, joinPath(path, "intGridCsv"), (item, itemPath) => expectNumber(item, source, itemPath));
263
+ optionalNumber(layer, "pxOffsetX", source, path);
264
+ optionalNumber(layer, "pxOffsetY", source, path);
265
+ optionalNumber(layer, "opacity", source, path);
266
+ };
267
+ const validateLevel = (raw, source, path) => {
268
+ const level = expectObject(raw, source, path);
269
+ expectString(level.identifier, source, joinPath(path, "identifier"));
270
+ expectInteger(level.uid, source, joinPath(path, "uid"));
271
+ expectString(level.iid, source, joinPath(path, "iid"));
272
+ expectNumber(level.worldX, source, joinPath(path, "worldX"));
273
+ expectNumber(level.worldY, source, joinPath(path, "worldY"));
274
+ expectNumber(level.pxWid, source, joinPath(path, "pxWid"));
275
+ expectNumber(level.pxHei, source, joinPath(path, "pxHei"));
276
+ nullableString(level, "externalRelPath", source, path);
277
+ if (level.__neighbours !== void 0 && level.__neighbours !== null) eachEntry(level.__neighbours, source, joinPath(path, "__neighbours"), (item, itemPath) => {
278
+ const neighbour = expectObject(item, source, itemPath);
279
+ expectString(neighbour.levelIid, source, joinPath(itemPath, "levelIid"));
280
+ expectString(neighbour.dir, source, joinPath(itemPath, "dir"));
281
+ });
282
+ if (level.fieldInstances !== void 0) validateFieldInstances(level.fieldInstances, source, joinPath(path, "fieldInstances"));
283
+ const layerInstancesPath = joinPath(path, "layerInstances");
284
+ if (level.layerInstances !== null) eachEntry(level.layerInstances, source, layerInstancesPath, (item, itemPath) => validateLayerInstance(item, source, itemPath));
285
+ };
286
+ const validateWorld = (raw, source, path) => {
287
+ const world = expectObject(raw, source, path);
288
+ expectString(world.identifier, source, joinPath(path, "identifier"));
289
+ expectString(world.iid, source, joinPath(path, "iid"));
290
+ expectNumber(world.worldGridWidth, source, joinPath(path, "worldGridWidth"));
291
+ expectNumber(world.worldGridHeight, source, joinPath(path, "worldGridHeight"));
292
+ const layoutPath = joinPath(path, "worldLayout");
293
+ if (world.worldLayout !== null) {
294
+ const layout = expectString(world.worldLayout, source, layoutPath);
295
+ if (!WORLD_LAYOUTS.includes(layout)) throw new LdtkFormatError(source, layoutPath, `unknown world layout "${layout}" (expected one of ${WORLD_LAYOUTS.join(", ")} or null)`);
296
+ }
297
+ eachEntry(world.levels, source, joinPath(path, "levels"), (item, itemPath) => validateLevel(item, source, itemPath));
298
+ };
299
+ /**
300
+ * Validate the root of a `.ldtk` file and return it typed as {@link LdtkData}.
301
+ * Throws {@link LdtkFormatError} on any structural problem, naming the source
302
+ * URL and the property path of the offending value.
303
+ * @internal
304
+ */
305
+ const validateLdtkData = (raw, source) => {
306
+ const root = expectObject(raw, source, "");
307
+ expectString(root.jsonVersion, source, "jsonVersion");
308
+ optionalNumber(root, "defaultGridSize", source, "");
309
+ validateDefs(root.defs, source, "defs");
310
+ eachEntry(root.levels, source, "levels", (item, itemPath) => validateLevel(item, source, itemPath));
311
+ if (root.worlds !== void 0) eachEntry(root.worlds, source, "worlds", (item, itemPath) => validateWorld(item, source, itemPath));
312
+ return raw;
313
+ };
314
+ /**
315
+ * Validate an external `.ldtkl` payload and return it typed as
316
+ * {@link LdtkLevel}. Paths in a thrown {@link LdtkFormatError} are relative to
317
+ * the level object, since that object is the root of the `.ldtkl` file.
318
+ * @internal
319
+ */
320
+ const validateLdtkLevelData = (raw, source) => {
321
+ validateLevel(raw, source, "");
322
+ return raw;
323
+ };
324
+
325
+ //#endregion
326
+ export { LdtkFormatError, validateLdtkData, validateLdtkLevelData };
327
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","names":[],"sources":["../../src/validate.ts"],"sourcesContent":["// Runtime validation for LDtk JSON (`.ldtk` / `.ldtkl`) documents. Both entry\n// points take `unknown` (the result of `JSON.parse`) and either return the same\n// value typed as `LdtkData` / `LdtkLevel`, or throw an {@link LdtkFormatError}\n// carrying the source URL and a JSON-path-like pointer to the offending value.\n//\n// Deliberately leaner than the Tiled adapter's `validate.ts`: it checks the\n// fields declared as required by this package's `LdtkData` model plus the\n// optional ones the adapter actually reads, and nothing else. Field-instance\n// `__value`s are checked against the shape their `__type` declares, because the\n// conversion pass casts rather than probes; a `__type` this package does not\n// model is left alone so a future LDtk field type still loads.\n//\n// Unlike the Tiled validator, this one asserts in place and hands the caller\n// back the very object it was given rather than rebuilding a normalised copy.\n// That keeps `LdtkMap.data` byte-for-byte what LDtk wrote, matching the\n// \"unknown fields are not stripped at parse time\" contract documented on\n// `LdtkData`.\n\nimport type { LdtkData, LdtkLayerType, LdtkLevel, LdtkWorldLayout } from './LdtkData';\n\n/**\n * Thrown when an LDtk JSON document does not match the expected shape.\n * `source` is the URL of the file being parsed; `path` is a JSON-path-like\n * pointer (e.g. `levels[0].layerInstances[1].gridTiles[0].px`) to the\n * offending value, or `''` for the document root.\n */\nexport class LdtkFormatError extends Error {\n public readonly source: string;\n public readonly path: string;\n\n public constructor(source: string, path: string, message: string) {\n super(`Invalid LDtk data in \"${source}\" at ${path === '' ? '<root>' : path}: ${message}`);\n this.name = 'LdtkFormatError';\n this.source = source;\n this.path = path;\n }\n}\n\n// ── Primitive helpers ────────────────────────────────────────────────────────\n\nconst describeValue = (value: unknown): string => {\n if (value === null) return 'null';\n if (value === undefined) return 'undefined';\n if (Array.isArray(value)) return 'an array';\n return typeof value;\n};\n\nconst joinPath = (path: string, key: string | number): string => {\n if (typeof key === 'number') return `${path}[${key}]`;\n return path === '' ? key : `${path}.${key}`;\n};\n\nconst expectObject = (value: unknown, source: string, path: string): Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new LdtkFormatError(source, path, `expected an object, got ${describeValue(value)}`);\n }\n return value as Record<string, unknown>;\n};\n\nconst expectArray = (value: unknown, source: string, path: string): readonly unknown[] => {\n if (!Array.isArray(value)) {\n throw new LdtkFormatError(source, path, `expected an array, got ${describeValue(value)}`);\n }\n return value as readonly unknown[];\n};\n\nconst expectString = (value: unknown, source: string, path: string): string => {\n if (typeof value !== 'string') {\n throw new LdtkFormatError(source, path, `expected a string, got ${describeValue(value)}`);\n }\n return value;\n};\n\nconst expectNumber = (value: unknown, source: string, path: string): number => {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new LdtkFormatError(source, path, `expected a finite number, got ${describeValue(value)}`);\n }\n return value;\n};\n\nconst expectInteger = (value: unknown, source: string, path: string): number => {\n const n = expectNumber(value, source, path);\n if (!Number.isInteger(n)) {\n throw new LdtkFormatError(source, path, `expected an integer, got ${n}`);\n }\n return n;\n};\n\nconst expectNonNegativeInteger = (value: unknown, source: string, path: string): number => {\n const n = expectInteger(value, source, path);\n if (n < 0) {\n throw new LdtkFormatError(source, path, `expected a non-negative integer, got ${n}`);\n }\n return n;\n};\n\nconst expectPositiveInteger = (value: unknown, source: string, path: string): number => {\n const n = expectInteger(value, source, path);\n if (n <= 0) {\n throw new LdtkFormatError(source, path, `expected a positive integer, got ${n}`);\n }\n return n;\n};\n\nconst expectBoolean = (value: unknown, source: string, path: string): void => {\n if (typeof value !== 'boolean') {\n throw new LdtkFormatError(source, path, `expected a boolean, got ${describeValue(value)}`);\n }\n};\n\n/** `[x, y]` pixel/grid pairs (`px`, `src`, `__pivot`) are always two finite numbers. */\nconst expectNumberPair = (value: unknown, source: string, path: string): void => {\n const pair = expectArray(value, source, path);\n if (pair.length !== 2) {\n throw new LdtkFormatError(source, path, `expected a pair of numbers, got ${pair.length} entries`);\n }\n expectNumber(pair[0], source, joinPath(path, 0));\n expectNumber(pair[1], source, joinPath(path, 1));\n};\n\nconst optionalNumber = (obj: Record<string, unknown>, key: string, source: string, path: string): void => {\n if (obj[key] !== undefined) expectNumber(obj[key], source, joinPath(path, key));\n};\n\nconst optionalNonNegativeInteger = (obj: Record<string, unknown>, key: string, source: string, path: string): void => {\n if (obj[key] !== undefined) expectNonNegativeInteger(obj[key], source, joinPath(path, key));\n};\n\n/**\n * LDtk writes an unset optional as an explicit `null` rather than omitting the\n * key, so a validator that only tolerates `undefined` rejects the files the\n * editor actually produces.\n */\nconst nullableString = (obj: Record<string, unknown>, key: string, source: string, path: string): void => {\n if (obj[key] !== undefined && obj[key] !== null) expectString(obj[key], source, joinPath(path, key));\n};\n\n/** See {@link nullableString}. */\nconst nullableInteger = (obj: Record<string, unknown>, key: string, source: string, path: string): void => {\n if (obj[key] !== undefined && obj[key] !== null) expectInteger(obj[key], source, joinPath(path, key));\n};\n\nconst optionalBoolean = (obj: Record<string, unknown>, key: string, source: string, path: string): void => {\n if (obj[key] !== undefined) expectBoolean(obj[key], source, joinPath(path, key));\n};\n\nconst eachEntry = (value: unknown, source: string, path: string, visit: (item: unknown, itemPath: string) => void): void => {\n const array = expectArray(value, source, path);\n for (let i = 0; i < array.length; i++) {\n visit(array[i], joinPath(path, i));\n }\n};\n\n// ── Definitions ──────────────────────────────────────────────────────────────\n\nconst LAYER_TYPES: readonly LdtkLayerType[] = ['Tiles', 'IntGrid', 'Entities', 'AutoLayer'];\nconst WORLD_LAYOUTS: readonly LdtkWorldLayout[] = ['Free', 'GridVania', 'LinearHorizontal', 'LinearVertical'];\n\nconst validateLayerType = (value: unknown, source: string, path: string): void => {\n const type = expectString(value, source, path);\n if (!LAYER_TYPES.includes(type as LdtkLayerType)) {\n throw new LdtkFormatError(source, path, `unknown layer type \"${type}\" (expected one of ${LAYER_TYPES.join(', ')})`);\n }\n};\n\nconst validateTilesetDef = (raw: unknown, source: string, path: string): void => {\n const def = expectObject(raw, source, path);\n\n expectInteger(def.uid, source, joinPath(path, 'uid'));\n expectString(def.identifier, source, joinPath(path, 'identifier'));\n\n // `relPath` is null for an embedded (\"embed atlas\") tileset, which the loader\n // skips - anything other than a string or null is malformed.\n const relPathPath = joinPath(path, 'relPath');\n if (def.relPath !== null) expectString(def.relPath, source, relPathPath);\n\n // A zero or negative grid size would make the loader's column arithmetic\n // divide by zero and yield a non-finite tile count.\n expectPositiveInteger(def.tileGridSize, source, joinPath(path, 'tileGridSize'));\n expectNonNegativeInteger(def.pxWid, source, joinPath(path, 'pxWid'));\n expectNonNegativeInteger(def.pxHei, source, joinPath(path, 'pxHei'));\n optionalNonNegativeInteger(def, 'spacing', source, path);\n optionalNonNegativeInteger(def, 'padding', source, path);\n};\n\nconst validateIntGridValueDef = (raw: unknown, source: string, path: string): void => {\n const value = expectObject(raw, source, path);\n\n expectNumber(value.value, source, joinPath(path, 'value'));\n const identifierPath = joinPath(path, 'identifier');\n if (value.identifier !== null) expectString(value.identifier, source, identifierPath);\n expectString(value.color, source, joinPath(path, 'color'));\n};\n\nconst validateLayerDef = (raw: unknown, source: string, path: string): void => {\n const def = expectObject(raw, source, path);\n\n expectInteger(def.uid, source, joinPath(path, 'uid'));\n expectString(def.identifier, source, joinPath(path, 'identifier'));\n validateLayerType(def.type, source, joinPath(path, 'type'));\n expectNonNegativeInteger(def.gridSize, source, joinPath(path, 'gridSize'));\n optionalNumber(def, 'pxOffsetX', source, path);\n optionalNumber(def, 'pxOffsetY', source, path);\n optionalNumber(def, 'parallaxFactorX', source, path);\n optionalNumber(def, 'parallaxFactorY', source, path);\n optionalBoolean(def, 'parallaxScaling', source, path);\n\n if (def.intGridValues !== undefined) {\n eachEntry(def.intGridValues, source, joinPath(path, 'intGridValues'), (item, itemPath) => validateIntGridValueDef(item, source, itemPath));\n }\n};\n\nconst validateDefs = (raw: unknown, source: string, path: string): void => {\n const defs = expectObject(raw, source, path);\n\n eachEntry(defs.tilesets, source, joinPath(path, 'tilesets'), (item, itemPath) => validateTilesetDef(item, source, itemPath));\n eachEntry(defs.layers, source, joinPath(path, 'layers'), (item, itemPath) => validateLayerDef(item, source, itemPath));\n};\n\n// ── Instances ────────────────────────────────────────────────────────────────\n\n/**\n * Validate one field-instance `__value` against the shape its `__type` declares.\n *\n * `null` is LDtk's \"not set\" and always passes - the conversion drops the\n * property. Everything else is checked here because the conversion pass casts\n * rather than probes: a `Point` whose value is not `{cx, cy}` used to reach the\n * runtime as a point with `undefined` coordinates, indistinguishable from a\n * genuine one until something read it.\n *\n * A `__type` this package does not model (a future LDtk field type, or an\n * `Array<T>` element type of one) is left unchecked: forward compatibility\n * matters more than rejecting a value the conversion already skips.\n */\nconst validateFieldValue = (typeName: string, value: unknown, source: string, path: string): void => {\n if (value === null || value === undefined) return;\n\n switch (typeName) {\n case 'Int':\n expectInteger(value, source, path);\n return;\n\n case 'Float':\n expectNumber(value, source, path);\n return;\n\n case 'Bool':\n expectBoolean(value, source, path);\n return;\n\n case 'String':\n case 'Multilines':\n case 'Color':\n case 'FilePath':\n case 'Enum':\n expectString(value, source, path);\n return;\n\n case 'Point': {\n const point = expectObject(value, source, path);\n\n expectNumber(point.cx, source, joinPath(path, 'cx'));\n expectNumber(point.cy, source, joinPath(path, 'cy'));\n\n return;\n }\n\n case 'EntityRef': {\n const ref = expectObject(value, source, path);\n\n for (const key of ['entityIid', 'layerIid', 'levelIid', 'worldIid'] as const) {\n expectString(ref[key], source, joinPath(path, key));\n }\n\n return;\n }\n\n case 'Tile': {\n const tile = expectObject(value, source, path);\n\n expectInteger(tile.tilesetUid, source, joinPath(path, 'tilesetUid'));\n\n for (const key of ['x', 'y', 'w', 'h'] as const) {\n expectNumber(tile[key], source, joinPath(path, key));\n }\n\n return;\n }\n\n default:\n if (typeName.startsWith('Array<') && typeName.endsWith('>')) {\n const elementType = typeName.slice('Array<'.length, -1);\n\n eachEntry(value, source, path, (item, itemPath) => validateFieldValue(elementType, item, source, itemPath));\n }\n }\n};\n\n/**\n * A field instance is validated down to its identifier, declared type and the\n * shape of `__value` that type implies - see {@link validateFieldValue}.\n */\nconst validateFieldInstance = (raw: unknown, source: string, path: string): void => {\n const field = expectObject(raw, source, path);\n\n expectString(field.__identifier, source, joinPath(path, '__identifier'));\n\n const typeName = expectString(field.__type, source, joinPath(path, '__type'));\n\n validateFieldValue(typeName, field.__value, source, joinPath(path, '__value'));\n};\n\nconst validateFieldInstances = (value: unknown, source: string, path: string): void => {\n eachEntry(value, source, path, (item, itemPath) => validateFieldInstance(item, source, itemPath));\n};\n\nconst validateTile = (raw: unknown, source: string, path: string): void => {\n const tile = expectObject(raw, source, path);\n\n expectNumberPair(tile.px, source, joinPath(path, 'px'));\n expectNumberPair(tile.src, source, joinPath(path, 'src'));\n expectNumber(tile.f, source, joinPath(path, 'f'));\n expectNumber(tile.t, source, joinPath(path, 't'));\n};\n\nconst validateTiles = (value: unknown, source: string, path: string): void => {\n eachEntry(value, source, path, (item, itemPath) => validateTile(item, source, itemPath));\n};\n\nconst validateEntityInstance = (raw: unknown, source: string, path: string): void => {\n const entity = expectObject(raw, source, path);\n\n expectString(entity.__identifier, source, joinPath(path, '__identifier'));\n expectString(entity.__type, source, joinPath(path, '__type'));\n expectNumberPair(entity.px, source, joinPath(path, 'px'));\n expectNumber(entity.width, source, joinPath(path, 'width'));\n expectNumber(entity.height, source, joinPath(path, 'height'));\n expectNumberPair(entity.__pivot, source, joinPath(path, '__pivot'));\n expectString(entity.iid, source, joinPath(path, 'iid'));\n expectInteger(entity.defUid, source, joinPath(path, 'defUid'));\n validateFieldInstances(entity.fieldInstances, source, joinPath(path, 'fieldInstances'));\n};\n\nconst validateLayerInstance = (raw: unknown, source: string, path: string): void => {\n const layer = expectObject(raw, source, path);\n\n expectString(layer.__identifier, source, joinPath(path, '__identifier'));\n validateLayerType(layer.__type, source, joinPath(path, '__type'));\n expectNonNegativeInteger(layer.__cWid, source, joinPath(path, '__cWid'));\n expectNonNegativeInteger(layer.__cHei, source, joinPath(path, '__cHei'));\n expectNonNegativeInteger(layer.__gridSize, source, joinPath(path, '__gridSize'));\n expectInteger(layer.layerDefUid, source, joinPath(path, 'layerDefUid'));\n expectInteger(layer.levelId, source, joinPath(path, 'levelId'));\n expectBoolean(layer.visible, source, joinPath(path, 'visible'));\n expectString(layer.iid, source, joinPath(path, 'iid'));\n\n nullableInteger(layer, '__tilesetDefUid', source, path);\n if (layer.gridTiles !== undefined) {\n validateTiles(layer.gridTiles, source, joinPath(path, 'gridTiles'));\n }\n if (layer.autoLayerTiles !== undefined) {\n validateTiles(layer.autoLayerTiles, source, joinPath(path, 'autoLayerTiles'));\n }\n if (layer.entityInstances !== undefined) {\n eachEntry(layer.entityInstances, source, joinPath(path, 'entityInstances'), (item, itemPath) => validateEntityInstance(item, source, itemPath));\n }\n if (layer.intGridCsv !== undefined) {\n eachEntry(layer.intGridCsv, source, joinPath(path, 'intGridCsv'), (item, itemPath) => expectNumber(item, source, itemPath));\n }\n optionalNumber(layer, 'pxOffsetX', source, path);\n optionalNumber(layer, 'pxOffsetY', source, path);\n optionalNumber(layer, 'opacity', source, path);\n};\n\nconst validateLevel = (raw: unknown, source: string, path: string): void => {\n const level = expectObject(raw, source, path);\n\n expectString(level.identifier, source, joinPath(path, 'identifier'));\n expectInteger(level.uid, source, joinPath(path, 'uid'));\n expectString(level.iid, source, joinPath(path, 'iid'));\n expectNumber(level.worldX, source, joinPath(path, 'worldX'));\n expectNumber(level.worldY, source, joinPath(path, 'worldY'));\n expectNumber(level.pxWid, source, joinPath(path, 'pxWid'));\n expectNumber(level.pxHei, source, joinPath(path, 'pxHei'));\n nullableString(level, 'externalRelPath', source, path);\n\n // Same explicit-null rule as the fields above: an isolated level can arrive\n // with a null here rather than an empty array.\n if (level.__neighbours !== undefined && level.__neighbours !== null) {\n eachEntry(level.__neighbours, source, joinPath(path, '__neighbours'), (item, itemPath) => {\n const neighbour = expectObject(item, source, itemPath);\n expectString(neighbour.levelIid, source, joinPath(itemPath, 'levelIid'));\n expectString(neighbour.dir, source, joinPath(itemPath, 'dir'));\n });\n }\n\n if (level.fieldInstances !== undefined) {\n validateFieldInstances(level.fieldInstances, source, joinPath(path, 'fieldInstances'));\n }\n\n // `null` marks a level whose layers live in a separate `.ldtkl` file; the\n // loader resolves those before conversion.\n const layerInstancesPath = joinPath(path, 'layerInstances');\n if (level.layerInstances !== null) {\n eachEntry(level.layerInstances, source, layerInstancesPath, (item, itemPath) => validateLayerInstance(item, source, itemPath));\n }\n};\n\nconst validateWorld = (raw: unknown, source: string, path: string): void => {\n const world = expectObject(raw, source, path);\n\n expectString(world.identifier, source, joinPath(path, 'identifier'));\n expectString(world.iid, source, joinPath(path, 'iid'));\n expectNumber(world.worldGridWidth, source, joinPath(path, 'worldGridWidth'));\n expectNumber(world.worldGridHeight, source, joinPath(path, 'worldGridHeight'));\n\n const layoutPath = joinPath(path, 'worldLayout');\n if (world.worldLayout !== null) {\n const layout = expectString(world.worldLayout, source, layoutPath);\n if (!WORLD_LAYOUTS.includes(layout as LdtkWorldLayout)) {\n throw new LdtkFormatError(source, layoutPath, `unknown world layout \"${layout}\" (expected one of ${WORLD_LAYOUTS.join(', ')} or null)`);\n }\n }\n\n eachEntry(world.levels, source, joinPath(path, 'levels'), (item, itemPath) => validateLevel(item, source, itemPath));\n};\n\n// ── Entry points ─────────────────────────────────────────────────────────────\n\n/**\n * Validate the root of a `.ldtk` file and return it typed as {@link LdtkData}.\n * Throws {@link LdtkFormatError} on any structural problem, naming the source\n * URL and the property path of the offending value.\n * @internal\n */\nexport const validateLdtkData = (raw: unknown, source: string): LdtkData => {\n const root = expectObject(raw, source, '');\n\n expectString(root.jsonVersion, source, 'jsonVersion');\n optionalNumber(root, 'defaultGridSize', source, '');\n validateDefs(root.defs, source, 'defs');\n\n // Both root shapes carry `levels`: it holds every level in a single-world\n // document and is present-but-empty once `worlds[]` is used.\n eachEntry(root.levels, source, 'levels', (item, itemPath) => validateLevel(item, source, itemPath));\n\n if (root.worlds !== undefined) {\n eachEntry(root.worlds, source, 'worlds', (item, itemPath) => validateWorld(item, source, itemPath));\n }\n\n return raw as LdtkData;\n};\n\n/**\n * Validate an external `.ldtkl` payload and return it typed as\n * {@link LdtkLevel}. Paths in a thrown {@link LdtkFormatError} are relative to\n * the level object, since that object is the root of the `.ldtkl` file.\n * @internal\n */\nexport const validateLdtkLevelData = (raw: unknown, source: string): LdtkLevel => {\n validateLevel(raw, source, '');\n\n return raw as LdtkLevel;\n};\n"],"mappings":"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"}