@datamoc/mw_games 0.7.0 → 0.7.2
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/CHANGELOG.md +964 -0
- package/README.md +43 -3
- package/dist/actors/Affix.d.ts +7 -1
- package/dist/actors/Affix.d.ts.map +1 -1
- package/dist/actors/Affix.js +4 -2
- package/dist/actors/Affix.js.map +1 -1
- package/dist/actors/StatBlock.d.ts +20 -0
- package/dist/actors/StatBlock.d.ts.map +1 -1
- package/dist/actors/StatBlock.js +14 -3
- package/dist/actors/StatBlock.js.map +1 -1
- package/dist/actors/index.d.ts +2 -2
- package/dist/actors/index.d.ts.map +1 -1
- package/dist/actors/index.js +1 -1
- package/dist/actors/index.js.map +1 -1
- package/dist/ai/index.d.ts +118 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +203 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/lua.d.ts +47 -0
- package/dist/ai/lua.d.ts.map +1 -0
- package/dist/ai/lua.js +195 -0
- package/dist/ai/lua.js.map +1 -0
- package/dist/ai/search.d.ts +59 -0
- package/dist/ai/search.d.ts.map +1 -0
- package/dist/ai/search.js +100 -0
- package/dist/ai/search.js.map +1 -0
- package/dist/board/Engine.d.ts +14 -0
- package/dist/board/Engine.d.ts.map +1 -1
- package/dist/board/Engine.js +33 -45
- package/dist/board/Engine.js.map +1 -1
- package/dist/board/index.d.ts +1 -1
- package/dist/board/index.d.ts.map +1 -1
- package/dist/board/index.js +1 -1
- package/dist/board/index.js.map +1 -1
- package/dist/core/Csv.d.ts +10 -0
- package/dist/core/Csv.d.ts.map +1 -1
- package/dist/core/Csv.js +34 -3
- package/dist/core/Csv.js.map +1 -1
- package/dist/core/Entity.d.ts +2 -2
- package/dist/core/Entity.d.ts.map +1 -1
- package/dist/core/Entity.js +18 -4
- package/dist/core/Entity.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mw_games.global.js +97 -97
- package/dist/mwl/actors.d.ts +3 -1
- package/dist/mwl/actors.d.ts.map +1 -1
- package/dist/mwl/actors.js +15 -2
- package/dist/mwl/actors.js.map +1 -1
- package/dist/mwl/catalog.d.ts.map +1 -1
- package/dist/mwl/catalog.js +16 -9
- package/dist/mwl/catalog.js.map +1 -1
- package/dist/mwl/compiler.d.ts +20 -0
- package/dist/mwl/compiler.d.ts.map +1 -1
- package/dist/mwl/compiler.js +76 -3
- package/dist/mwl/compiler.js.map +1 -1
- package/dist/mwl/conditions.d.ts +9 -0
- package/dist/mwl/conditions.d.ts.map +1 -0
- package/dist/mwl/conditions.js +162 -0
- package/dist/mwl/conditions.js.map +1 -0
- package/dist/mwl/content.d.ts +61 -0
- package/dist/mwl/content.d.ts.map +1 -1
- package/dist/mwl/content.js +95 -34
- package/dist/mwl/content.js.map +1 -1
- package/dist/mwl/expression.d.ts.map +1 -1
- package/dist/mwl/expression.js +16 -6
- package/dist/mwl/expression.js.map +1 -1
- package/dist/mwl/fengari.d.ts +8 -0
- package/dist/mwl/fengari.d.ts.map +1 -0
- package/dist/mwl/fengari.js +136 -0
- package/dist/mwl/fengari.js.map +1 -0
- package/dist/mwl/hooks.d.ts +1 -1
- package/dist/mwl/hooks.d.ts.map +1 -1
- package/dist/mwl/hooks.js.map +1 -1
- package/dist/mwl/index.d.ts +16 -7
- package/dist/mwl/index.d.ts.map +1 -1
- package/dist/mwl/index.js +7 -3
- package/dist/mwl/index.js.map +1 -1
- package/dist/mwl/persistence.d.ts.map +1 -1
- package/dist/mwl/persistence.js +10 -2
- package/dist/mwl/persistence.js.map +1 -1
- package/dist/mwl/readers.d.ts +18 -0
- package/dist/mwl/readers.d.ts.map +1 -0
- package/dist/mwl/readers.js +58 -0
- package/dist/mwl/readers.js.map +1 -0
- package/dist/mwl/report.d.ts +9 -0
- package/dist/mwl/report.d.ts.map +1 -0
- package/dist/mwl/report.js +36 -0
- package/dist/mwl/report.js.map +1 -0
- package/dist/mwl/runtime.d.ts +65 -2
- package/dist/mwl/runtime.d.ts.map +1 -1
- package/dist/mwl/runtime.js +245 -26
- package/dist/mwl/runtime.js.map +1 -1
- package/dist/mwl/schema.d.ts +13 -1
- package/dist/mwl/schema.d.ts.map +1 -1
- package/dist/mwl/schema.js +222 -7
- package/dist/mwl/schema.js.map +1 -1
- package/dist/mwl/scripts.d.ts +15 -0
- package/dist/mwl/scripts.d.ts.map +1 -0
- package/dist/mwl/scripts.js +23 -0
- package/dist/mwl/scripts.js.map +1 -0
- package/dist/mwl/utils.d.ts +8 -0
- package/dist/mwl/utils.d.ts.map +1 -0
- package/dist/mwl/utils.js +37 -0
- package/dist/mwl/utils.js.map +1 -0
- package/dist/two-d/render/Types2D.d.ts +19 -4
- package/dist/two-d/render/Types2D.d.ts.map +1 -1
- package/dist/two-d/render/Types2D.js +25 -0
- package/dist/two-d/render/Types2D.js.map +1 -1
- package/dist/two-d/render/index.d.ts +2 -2
- package/dist/two-d/render/index.d.ts.map +1 -1
- package/dist/two-d/render/index.js +1 -1
- package/dist/two-d/render/index.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +27 -6
- package/tools/extract-html.d.mts +18 -0
- package/tools/extract-html.mjs +235 -0
- package/tools/mwl.mjs +86 -16
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export function flattenNodes(roots) {
|
|
2
|
+
const result = [];
|
|
3
|
+
const visit = (node) => {
|
|
4
|
+
result.push(node);
|
|
5
|
+
node.children.forEach(visit);
|
|
6
|
+
};
|
|
7
|
+
roots.forEach(visit);
|
|
8
|
+
return result;
|
|
9
|
+
}
|
|
10
|
+
export function requiredAttribute(node, name) {
|
|
11
|
+
const value = node.attributes[name];
|
|
12
|
+
if (!value)
|
|
13
|
+
throw new Error(`MWL ${node.tag} is missing ${name}`);
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
export function numberAttribute(node, name) {
|
|
17
|
+
const value = node.attributes[name];
|
|
18
|
+
if (value === undefined)
|
|
19
|
+
return undefined;
|
|
20
|
+
const result = Number(value);
|
|
21
|
+
return Number.isFinite(result) ? result : undefined;
|
|
22
|
+
}
|
|
23
|
+
export function integerAttribute(node, name, fallback) {
|
|
24
|
+
const value = node.attributes[name];
|
|
25
|
+
if (value === undefined)
|
|
26
|
+
return fallback;
|
|
27
|
+
const result = Number.parseInt(value, 10);
|
|
28
|
+
return Number.isFinite(result) ? result : fallback;
|
|
29
|
+
}
|
|
30
|
+
export function booleanAttribute(node, name) {
|
|
31
|
+
const value = node.attributes[name];
|
|
32
|
+
return value === undefined ? undefined : value === 'true' || value === 'yes';
|
|
33
|
+
}
|
|
34
|
+
export function enumAttribute(value, allowed) {
|
|
35
|
+
return value !== undefined && allowed.includes(value) ? value : undefined;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/mwl/utils.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,YAAY,CAAC,KAAiC;IAC7D,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG,CAAC,IAAqB,EAAQ,EAAE;QAC7C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC,CAAC;IACF,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACrB,OAAO,MAAM,CAAC;AACf,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAqB,EAAE,IAAY;IACpE,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,GAAG,eAAe,IAAI,EAAE,CAAC,CAAC;IAClE,OAAO,KAAK,CAAC;AACd,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAqB,EAAE,IAAY;IAClE,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAqB,EAAE,IAAY,EAAE,QAAiB;IACtF,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1C,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAqB,EAAE,IAAY;IACnE,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACpC,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,aAAa,CAAmB,KAAyB,EAAE,OAAqB;IAC/F,OAAO,KAAK,KAAK,SAAS,IAAK,OAA6B,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,KAAW,CAAC,CAAC,CAAC,SAAS,CAAC;AACzG,CAAC"}
|
|
@@ -1,13 +1,28 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Container, Texture, Rectangle } from 'pixi.js';
|
|
2
2
|
/**
|
|
3
3
|
* The scene-graph container type a 2D game names in its own code - `Scene2D.stage` and any
|
|
4
4
|
* other public container field are typed this way rather than as `pixi.js`'s own `Container`,
|
|
5
5
|
* so naming the type does not require importing the renderer directly. It is the same object
|
|
6
6
|
* at runtime; only the public name a game writes down changes.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
/** Renderer facade class, usable in both type and value positions. */
|
|
9
|
+
export { Container as Container2D };
|
|
9
10
|
/** The texture type a 2D game names in its own code, for the same reason as `Container2D`. */
|
|
10
|
-
|
|
11
|
+
/** Renderer facade class, usable in both type and value positions. */
|
|
12
|
+
export { Texture as Texture2D };
|
|
13
|
+
/** Explicit value-position escape hatch for rectangle construction through the facade. */
|
|
14
|
+
/**
|
|
15
|
+
* Renderer facade class, usable in both type and value positions.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { Rectangle2D } from '@datamoc/mw_games/two-d/render';
|
|
20
|
+
|
|
21
|
+
* const hitArea = new Rectangle2D(0, 0, 32, 32);
|
|
22
|
+
* console.log(hitArea.width); // 32
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export { Rectangle as Rectangle2D };
|
|
11
26
|
/** A plain, renderer-free rectangle: the shape `TextureRegion.frame` and similar public
|
|
12
27
|
* fields use in place of `pixi.js`'s `Rectangle`. */
|
|
13
28
|
export interface Rect {
|
|
@@ -18,7 +33,7 @@ export interface Rect {
|
|
|
18
33
|
}
|
|
19
34
|
/** A texture together with the frame it was cut from - what `SpriteSheet.region` returns. */
|
|
20
35
|
export interface TextureRegion {
|
|
21
|
-
texture:
|
|
36
|
+
texture: Texture;
|
|
22
37
|
frame: Rect;
|
|
23
38
|
}
|
|
24
39
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Types2D.d.ts","sourceRoot":"","sources":["../../../src/two-d/render/Types2D.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"Types2D.d.ts","sourceRoot":"","sources":["../../../src/two-d/render/Types2D.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAExD;;;;;GAKG;AACH,sEAAsE;AACtE,OAAO,EAAE,SAAS,IAAI,WAAW,EAAE,CAAC;AAEpC,8FAA8F;AAC9F,sEAAsE;AACtE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,CAAC;AAEhC,0FAA0F;AAC1F;;;;;;;;;;GAUG;AACH,OAAO,EAAE,SAAS,IAAI,WAAW,EAAE,CAAC;AAEpC;qDACqD;AACrD,MAAM,WAAW,IAAI;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CACf;AAED,6FAA6F;AAC7F,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,IAAI,CAAC;CACZ;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAEjD"}
|
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
import { Container, Texture, Rectangle } from 'pixi.js';
|
|
2
|
+
/**
|
|
3
|
+
* The scene-graph container type a 2D game names in its own code - `Scene2D.stage` and any
|
|
4
|
+
* other public container field are typed this way rather than as `pixi.js`'s own `Container`,
|
|
5
|
+
* so naming the type does not require importing the renderer directly. It is the same object
|
|
6
|
+
* at runtime; only the public name a game writes down changes.
|
|
7
|
+
*/
|
|
8
|
+
/** Renderer facade class, usable in both type and value positions. */
|
|
9
|
+
export { Container as Container2D };
|
|
10
|
+
/** The texture type a 2D game names in its own code, for the same reason as `Container2D`. */
|
|
11
|
+
/** Renderer facade class, usable in both type and value positions. */
|
|
12
|
+
export { Texture as Texture2D };
|
|
13
|
+
/** Explicit value-position escape hatch for rectangle construction through the facade. */
|
|
14
|
+
/**
|
|
15
|
+
* Renderer facade class, usable in both type and value positions.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { Rectangle2D } from '@datamoc/mw_games/two-d/render';
|
|
20
|
+
|
|
21
|
+
* const hitArea = new Rectangle2D(0, 0, 32, 32);
|
|
22
|
+
* console.log(hitArea.width); // 32
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export { Rectangle as Rectangle2D };
|
|
1
26
|
/**
|
|
2
27
|
* Converts a `pixi.js` `Rectangle` to the plain `Rect` shape public APIs use. Internal to
|
|
3
28
|
* `two-d`; a game never constructs a `pixi.js` `Rectangle` to call this.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Types2D.js","sourceRoot":"","sources":["../../../src/two-d/render/Types2D.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Types2D.js","sourceRoot":"","sources":["../../../src/two-d/render/Types2D.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAExD;;;;;GAKG;AACH,sEAAsE;AACtE,OAAO,EAAE,SAAS,IAAI,WAAW,EAAE,CAAC;AAEpC,8FAA8F;AAC9F,sEAAsE;AACtE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,CAAC;AAEhC,0FAA0F;AAC1F;;;;;;;;;;GAUG;AACH,OAAO,EAAE,SAAS,IAAI,WAAW,EAAE,CAAC;AAiBpC;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,MAAM,CAAC,SAAoB;IAC1C,OAAO,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC;AAC7F,CAAC"}
|
|
@@ -29,8 +29,8 @@ export { blobIndex, autotileFrames, BLOB_SHAPES } from './Autotile.ts';
|
|
|
29
29
|
export type { NeighborMask } from './Autotile.ts';
|
|
30
30
|
export { inspectGraphicsCapabilities, detectWebGpu, RENDERING_DECISIONS } from './Capabilities.ts';
|
|
31
31
|
export type { GraphicsCapabilities, GraphicsProbe, GraphicsWorkload, RenderingDecision, WebGpuDetection, } from './Capabilities.ts';
|
|
32
|
-
export { rectOf } from './Types2D.ts';
|
|
33
|
-
export type {
|
|
32
|
+
export { Container2D, Rectangle2D, Texture2D, rectOf } from './Types2D.ts';
|
|
33
|
+
export type { Rect, TextureRegion } from './Types2D.ts';
|
|
34
34
|
export { Node2D, Shape2D, Text2D, Sprite2D, TiledSprite, Gradient } from './Shape2D.ts';
|
|
35
35
|
export { loadTiledMap } from './TiledMap.ts';
|
|
36
36
|
export type { TiledMapData, TiledTilesetData, TilesetSheet, LoadedTiledMap, TiledObject, TiledLayer, } from './TiledMap.ts';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/two-d/render/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC5G,YAAY,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChE,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC7D,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5D,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC3F,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACtD,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACzF,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE1E,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAEtF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAElF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAEpF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE9F,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACvE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,2BAA2B,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACnG,YAAY,EACX,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,GACf,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/two-d/render/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC5G,YAAY,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChE,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC7D,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5D,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC3F,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACtD,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACzF,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE1E,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAEtF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAElF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAEpF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE9F,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACvE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,2BAA2B,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACnG,YAAY,EACX,oBAAoB,EACpB,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,GACf,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3E,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExF,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,YAAY,EACX,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,WAAW,EACX,UAAU,GACV,MAAM,eAAe,CAAC"}
|
|
@@ -15,7 +15,7 @@ export { ActorAnimator } from './ActorAnimator.js';
|
|
|
15
15
|
export { StatusVisuals } from './StatusVisuals.js';
|
|
16
16
|
export { blobIndex, autotileFrames, BLOB_SHAPES } from './Autotile.js';
|
|
17
17
|
export { inspectGraphicsCapabilities, detectWebGpu, RENDERING_DECISIONS } from './Capabilities.js';
|
|
18
|
-
export { rectOf } from './Types2D.js';
|
|
18
|
+
export { Container2D, Rectangle2D, Texture2D, rectOf } from './Types2D.js';
|
|
19
19
|
export { Node2D, Shape2D, Text2D, Sprite2D, TiledSprite, Gradient } from './Shape2D.js';
|
|
20
20
|
export { loadTiledMap } from './TiledMap.js';
|
|
21
21
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/two-d/render/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG5G,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE5D,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAG3F,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEzF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG7C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGvE,OAAO,EAAE,2BAA2B,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AASnG,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/two-d/render/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG5G,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE5D,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAG3F,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEzF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG7C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGvE,OAAO,EAAE,2BAA2B,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AASnG,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3E,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExF,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/version.d.ts
CHANGED
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
* this from `package.json` automatically, chosen because this project's own build already
|
|
10
10
|
* has no step before `tsc`/`vite` that this would need to run ahead of.
|
|
11
11
|
*/
|
|
12
|
-
export declare const version = "0.7.
|
|
12
|
+
export declare const version = "0.7.2";
|
|
13
13
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
* this from `package.json` automatically, chosen because this project's own build already
|
|
10
10
|
* has no step before `tsc`/`vite` that this would need to run ahead of.
|
|
11
11
|
*/
|
|
12
|
-
export const version = '0.7.
|
|
12
|
+
export const version = '0.7.2';
|
|
13
13
|
//# sourceMappingURL=version.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datamoc/mw_games",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "A local-file game framework: renderer-free game logic, drawn through PixiJS in 2D or Babylon.js in 3D, with mobile and desktop packaging.",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -39,10 +39,13 @@
|
|
|
39
39
|
"files": [
|
|
40
40
|
"dist",
|
|
41
41
|
"tools/compile-resources.mjs",
|
|
42
|
+
"tools/extract-html.mjs",
|
|
43
|
+
"tools/extract-html.d.mts",
|
|
42
44
|
"tools/compress-dist.mjs",
|
|
43
45
|
"tools/compress-dist.d.mts",
|
|
44
46
|
"tools/mwl.mjs",
|
|
45
47
|
"LICENSE",
|
|
48
|
+
"CHANGELOG.md",
|
|
46
49
|
"README.md"
|
|
47
50
|
],
|
|
48
51
|
"exports": {
|
|
@@ -110,6 +113,18 @@
|
|
|
110
113
|
"types": "./dist/mwl/index.d.ts",
|
|
111
114
|
"import": "./dist/mwl/index.js"
|
|
112
115
|
},
|
|
116
|
+
"./mwl/fengari": {
|
|
117
|
+
"types": "./dist/mwl/fengari.d.ts",
|
|
118
|
+
"import": "./dist/mwl/fengari.js"
|
|
119
|
+
},
|
|
120
|
+
"./ai": {
|
|
121
|
+
"types": "./dist/ai/index.d.ts",
|
|
122
|
+
"import": "./dist/ai/index.js"
|
|
123
|
+
},
|
|
124
|
+
"./ai/lua": {
|
|
125
|
+
"types": "./dist/ai/lua.d.ts",
|
|
126
|
+
"import": "./dist/ai/lua.js"
|
|
127
|
+
},
|
|
113
128
|
"./tools/compile-resources": "./tools/compile-resources.mjs",
|
|
114
129
|
"./tools/compress-dist": "./tools/compress-dist.mjs",
|
|
115
130
|
"./two-d": {
|
|
@@ -149,15 +164,16 @@
|
|
|
149
164
|
"mwl": "npm run build:pkg && node tools/mwl.mjs",
|
|
150
165
|
"size:check": "node tools/bundle-size.mjs",
|
|
151
166
|
"size:update": "node tools/bundle-size.mjs --update",
|
|
152
|
-
"audit": "npm
|
|
167
|
+
"audit": "node tools/npm-audit.mjs",
|
|
153
168
|
"example": "vite --config examples/colour-transform/vite.config.ts",
|
|
154
169
|
"example:build": "vite build --config examples/colour-transform/vite.config.ts && node tools/emit-page.mjs examples/colour-transform",
|
|
155
170
|
"test": "node --test \"tests/**/*.test.ts\"",
|
|
156
|
-
"coverage": "node --test --experimental-test-coverage \"tests/**/*.test.ts\"",
|
|
157
|
-
"coverage:check": "node --test --experimental-test-coverage --test-coverage-lines=88 --test-coverage-branches=89 --test-coverage-functions=82 \"tests/**/*.test.ts\"",
|
|
171
|
+
"coverage": "node --test --experimental-test-coverage --test-coverage-exclude=src/two-d/Game.ts --test-coverage-exclude=src/two-d/render/ColorTransformBatcher.ts --test-coverage-exclude=src/two-d/render/Minimap.ts --test-coverage-exclude=src/three-d/Vox.ts --test-coverage-exclude=src/two-d/stage/DialogueStage.ts --test-coverage-exclude=src/two-d/stage/EventDialogue.ts --test-coverage-exclude=src/two-d/ui/** --test-coverage-exclude=tools/** \"tests/**/*.test.ts\"",
|
|
172
|
+
"coverage:check": "node --test --experimental-test-coverage --test-coverage-lines=88 --test-coverage-branches=89 --test-coverage-functions=82 --test-coverage-exclude=src/two-d/Game.ts --test-coverage-exclude=src/two-d/render/ColorTransformBatcher.ts --test-coverage-exclude=src/two-d/render/Minimap.ts --test-coverage-exclude=src/three-d/Vox.ts --test-coverage-exclude=src/two-d/stage/DialogueStage.ts --test-coverage-exclude=src/two-d/stage/EventDialogue.ts --test-coverage-exclude=src/two-d/ui/** --test-coverage-exclude=tools/** \"tests/**/*.test.ts\"",
|
|
158
173
|
"assets": "node tools/make-example-assets.mjs",
|
|
159
174
|
"examples:build": "npm run assets && node tools/build-all-examples.mjs",
|
|
160
175
|
"extract:rgssad": "node tools/extract-rgssad.mjs",
|
|
176
|
+
"extract:html": "node tools/extract-html.mjs",
|
|
161
177
|
"i18n:edit": "node tools/i18n-edit.mjs",
|
|
162
178
|
"i18n:check": "node tools/i18n-edit.mjs --check",
|
|
163
179
|
"example:ui": "vite --config examples/interface/vite.config.ts",
|
|
@@ -169,7 +185,7 @@
|
|
|
169
185
|
"example:village": "vite --config examples/village/vite.config.ts",
|
|
170
186
|
"example:village:build": "vite build --config examples/village/vite.config.ts && node tools/emit-page.mjs examples/village",
|
|
171
187
|
"example:battle": "vite --config examples/battle/vite.config.ts",
|
|
172
|
-
"example:battle:build": "vite build --config examples/battle/vite.config.ts && node tools/emit-page.mjs examples/battle",
|
|
188
|
+
"example:battle:build": "npm run mwl -- build examples/battle/content -o examples/battle/generated && vite build --config examples/battle/vite.config.ts && node tools/emit-page.mjs examples/battle",
|
|
173
189
|
"example:minigame": "vite --config examples/minigame/vite.config.ts",
|
|
174
190
|
"example:minigame:build": "vite build --config examples/minigame/vite.config.ts && node tools/emit-page.mjs examples/minigame",
|
|
175
191
|
"example:chess": "vite --config examples/chess/vite.config.ts",
|
|
@@ -198,6 +214,8 @@
|
|
|
198
214
|
"example:event-system:build": "vite build --config examples/event-system/vite.config.ts && node tools/emit-page.mjs examples/event-system",
|
|
199
215
|
"example:headless": "vite --config examples/headless/vite.config.ts",
|
|
200
216
|
"example:headless:build": "vite build --config examples/headless/vite.config.ts && node tools/emit-page.mjs examples/headless",
|
|
217
|
+
"example:mwl-content": "vite --config examples/mwl-content/vite.config.ts",
|
|
218
|
+
"example:mwl-content:build": "npm run mwl -- build examples/mwl-content/content -o examples/mwl-content/generated && vite build --config examples/mwl-content/vite.config.ts && node tools/emit-page.mjs examples/mwl-content",
|
|
201
219
|
"benchmark:browser": "npm run example:dungeon:build && node tools/benchmark-browser.mjs",
|
|
202
220
|
"benchmark:3d": "npm run example:3d:build && node tools/benchmark-browser.mjs examples/three-d/dist/index.html",
|
|
203
221
|
"benchmark:tower-defense": "npm run example:tower-defense:build && node tools/benchmark-browser.mjs examples/tower-defense/dist/index.html",
|
|
@@ -262,5 +280,8 @@
|
|
|
262
280
|
},
|
|
263
281
|
"main": "./dist/index.js",
|
|
264
282
|
"types": "./dist/index.d.ts",
|
|
265
|
-
"unpkg": "./dist/mw_games.global.js"
|
|
283
|
+
"unpkg": "./dist/mw_games.global.js",
|
|
284
|
+
"optionalDependencies": {
|
|
285
|
+
"fengari": "^0.1.5"
|
|
286
|
+
}
|
|
266
287
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ExtractedHtmlResource {
|
|
2
|
+
kind: 'script' | 'style' | 'json' | 'data-uri' | 'css-data-uri';
|
|
3
|
+
path: string;
|
|
4
|
+
mime: string;
|
|
5
|
+
bytes: number;
|
|
6
|
+
sourceOffset: number;
|
|
7
|
+
sourceValue: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ExtractHtmlResult {
|
|
11
|
+
output: string;
|
|
12
|
+
html: string;
|
|
13
|
+
resources: ExtractedHtmlResource[];
|
|
14
|
+
warnings: string[];
|
|
15
|
+
manifest: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function extractHtml(inputFile: string, outputDirectory?: string): Promise<ExtractHtmlResult>;
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import crypto from 'node:crypto';
|
|
5
|
+
|
|
6
|
+
const MIME_EXTENSIONS = {
|
|
7
|
+
'text/javascript': '.js',
|
|
8
|
+
'application/javascript': '.js',
|
|
9
|
+
'application/json': '.json',
|
|
10
|
+
'text/css': '.css',
|
|
11
|
+
'image/svg+xml': '.svg',
|
|
12
|
+
'image/png': '.png',
|
|
13
|
+
'image/jpeg': '.jpg',
|
|
14
|
+
'image/gif': '.gif',
|
|
15
|
+
'image/webp': '.webp',
|
|
16
|
+
'audio/wav': '.wav',
|
|
17
|
+
'audio/ogg': '.ogg',
|
|
18
|
+
'audio/mpeg': '.mp3',
|
|
19
|
+
'font/woff2': '.woff2',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Extract inline HTML resources without parsing the document through a DOM.
|
|
24
|
+
* This keeps the operation usable for large self-contained pages and preserves
|
|
25
|
+
* all unrelated bytes in the source as-is.
|
|
26
|
+
*/
|
|
27
|
+
export async function extractHtml(inputFile, outputDirectory) {
|
|
28
|
+
const source = await readFile(inputFile, 'utf8');
|
|
29
|
+
const output = resolve(outputDirectory ?? join(dirname(resolve(inputFile)), 'extracted'));
|
|
30
|
+
const assetDirectory = join(output, 'assets');
|
|
31
|
+
await mkdir(output, { recursive: true });
|
|
32
|
+
await rm(assetDirectory, { recursive: true, force: true });
|
|
33
|
+
await mkdir(assetDirectory, { recursive: true });
|
|
34
|
+
|
|
35
|
+
const resources = [];
|
|
36
|
+
const warnings = [];
|
|
37
|
+
const bySource = new Map();
|
|
38
|
+
let html = source;
|
|
39
|
+
const inlineBlocks = /<(script|style)(\b[^>]*)>([\s\S]*?)<\/\1\s*>/gi;
|
|
40
|
+
const dataUri = /(\b(?:src|href|poster|content)\s*=\s*["'])(data:([^"']+?))["']/gi;
|
|
41
|
+
const srcset = /(\bsrcset\s*=\s*["'])([^"']+)(["'])/gi;
|
|
42
|
+
const inlineMatches = [...source.matchAll(inlineBlocks)];
|
|
43
|
+
const dataMatches = [...source.matchAll(dataUri)].filter(
|
|
44
|
+
(match) =>
|
|
45
|
+
!inlineMatches.some((block) => match.index >= block.index && match.index < block.index + block[0].length),
|
|
46
|
+
);
|
|
47
|
+
const srcsetMatches = [...source.matchAll(srcset)].filter((match) => match[2].includes('data:'));
|
|
48
|
+
const occurrences = [...inlineMatches.filter((match) => match[3].trim()), ...dataMatches, ...srcsetMatches].sort(
|
|
49
|
+
(a, b) => a.index - b.index,
|
|
50
|
+
);
|
|
51
|
+
const order = new Map(occurrences.map((match, index) => [match.index, index + 1]));
|
|
52
|
+
let nextId = occurrences.length + 1;
|
|
53
|
+
const usedIds = new Set();
|
|
54
|
+
|
|
55
|
+
const writeResource = async ({ kind, mime, data, sourceOffset, sourceValue }) => {
|
|
56
|
+
const key = `${mime}\0${data.toString('base64')}`;
|
|
57
|
+
const existing = bySource.get(key);
|
|
58
|
+
if (existing) return existing.path;
|
|
59
|
+
const extension = MIME_EXTENSIONS[mime] ?? extensionForKind(kind);
|
|
60
|
+
let id = order.get(sourceOffset);
|
|
61
|
+
if (id === undefined || usedIds.has(id)) id = nextId++;
|
|
62
|
+
usedIds.add(id);
|
|
63
|
+
const filename = `inline-${String(id).padStart(4, '0')}${extension}`;
|
|
64
|
+
const relativePath = `assets/${filename}`;
|
|
65
|
+
await writeFile(join(assetDirectory, filename), data);
|
|
66
|
+
const resource = {
|
|
67
|
+
kind,
|
|
68
|
+
path: relativePath,
|
|
69
|
+
mime,
|
|
70
|
+
bytes: data.length,
|
|
71
|
+
sourceOffset,
|
|
72
|
+
sourceValue,
|
|
73
|
+
};
|
|
74
|
+
resources.push(resource);
|
|
75
|
+
bySource.set(key, resource);
|
|
76
|
+
return relativePath;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const replacements = [];
|
|
80
|
+
for (const match of inlineMatches) {
|
|
81
|
+
const tag = match[1].toLowerCase();
|
|
82
|
+
const attributes = match[2];
|
|
83
|
+
const body = match[3];
|
|
84
|
+
if (!body.trim()) continue;
|
|
85
|
+
const type = attributeValue(attributes, 'type');
|
|
86
|
+
const mime =
|
|
87
|
+
tag === 'style'
|
|
88
|
+
? 'text/css'
|
|
89
|
+
: type?.toLowerCase() === 'application/json'
|
|
90
|
+
? 'application/json'
|
|
91
|
+
: 'text/javascript';
|
|
92
|
+
const kind = tag === 'style' ? 'style' : mime === 'application/json' ? 'json' : 'script';
|
|
93
|
+
const path = await writeResource({
|
|
94
|
+
kind,
|
|
95
|
+
mime,
|
|
96
|
+
data: Buffer.from(body),
|
|
97
|
+
sourceOffset: match.index,
|
|
98
|
+
sourceValue: `<${tag}>`,
|
|
99
|
+
});
|
|
100
|
+
if (tag === 'style') {
|
|
101
|
+
let css = body;
|
|
102
|
+
const cssDataUri = /url\(\s*(["']?)(data:[^\)"']+)\1\s*\)/gi;
|
|
103
|
+
for (const cssMatch of [...body.matchAll(cssDataUri)]) {
|
|
104
|
+
const parsed = decodeDataUri(cssMatch[2]);
|
|
105
|
+
if (!parsed) {
|
|
106
|
+
warnings.push(`unsupported CSS data URI at offset ${match.index + cssMatch.index}`);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const assetPath = await writeResource({
|
|
110
|
+
kind: 'css-data-uri',
|
|
111
|
+
mime: parsed.mime,
|
|
112
|
+
data: parsed.data,
|
|
113
|
+
sourceOffset: match.index + cssMatch.index,
|
|
114
|
+
sourceValue: 'data:',
|
|
115
|
+
});
|
|
116
|
+
css = css.replace(cssMatch[2], `./${assetPath.slice('assets/'.length)}`);
|
|
117
|
+
}
|
|
118
|
+
if (css !== body) await writeFile(join(assetDirectory, path.slice('assets/'.length)), css);
|
|
119
|
+
}
|
|
120
|
+
if (kind === 'script' && type?.toLowerCase() === 'module' && /(?:^|[^\w])(?:import|export)\s/.test(body)) {
|
|
121
|
+
warnings.push(`inline module at offset ${match.index} was moved under assets/; verify relative imports`);
|
|
122
|
+
}
|
|
123
|
+
const replacement =
|
|
124
|
+
tag === 'style'
|
|
125
|
+
? `<link${copyStyleAttributes(attributes)} rel="stylesheet" href="./${path}">`
|
|
126
|
+
: `<script${copyScriptAttributes(attributes)} src="./${path}"></script>`;
|
|
127
|
+
replacements.push({ start: match.index, end: match.index + match[0].length, replacement });
|
|
128
|
+
}
|
|
129
|
+
for (const match of dataMatches) {
|
|
130
|
+
const parsed = decodeDataUri(match[2]);
|
|
131
|
+
if (!parsed) {
|
|
132
|
+
warnings.push(`unsupported data URI at offset ${match.index}`);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const path = await writeResource({
|
|
136
|
+
kind: 'data-uri',
|
|
137
|
+
mime: parsed.mime,
|
|
138
|
+
data: parsed.data,
|
|
139
|
+
sourceOffset: match.index,
|
|
140
|
+
sourceValue: 'data:',
|
|
141
|
+
});
|
|
142
|
+
replacements.push({
|
|
143
|
+
start: match.index + match[1].length,
|
|
144
|
+
end: match.index + match[0].length - 1,
|
|
145
|
+
replacement: `./${path}`,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
for (const match of srcsetMatches) {
|
|
149
|
+
const candidates = [];
|
|
150
|
+
for (const candidate of match[2].split(/,\s*(?=data:)/i)) {
|
|
151
|
+
const parts = candidate.trim().split(/\s+/);
|
|
152
|
+
const parsed = decodeDataUri(parts.shift() ?? '');
|
|
153
|
+
if (!parsed) {
|
|
154
|
+
warnings.push(`unsupported srcset data URI at offset ${match.index}`);
|
|
155
|
+
candidates.push(candidate);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const path = await writeResource({
|
|
159
|
+
kind: 'data-uri',
|
|
160
|
+
mime: parsed.mime,
|
|
161
|
+
data: parsed.data,
|
|
162
|
+
sourceOffset: match.index,
|
|
163
|
+
sourceValue: 'data:',
|
|
164
|
+
});
|
|
165
|
+
candidates.push([`./${path}`, ...parts].join(' '));
|
|
166
|
+
}
|
|
167
|
+
replacements.push({
|
|
168
|
+
start: match.index + match[1].length,
|
|
169
|
+
end: match.index + match[0].length - 1,
|
|
170
|
+
replacement: candidates.join(', '),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
for (const replacement of replacements.sort((a, b) => b.start - a.start))
|
|
174
|
+
html = html.slice(0, replacement.start) + replacement.replacement + html.slice(replacement.end);
|
|
175
|
+
|
|
176
|
+
resources.sort((a, b) => a.sourceOffset - b.sourceOffset || (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
177
|
+
const manifest = {
|
|
178
|
+
version: 1,
|
|
179
|
+
source: basename(inputFile),
|
|
180
|
+
resources,
|
|
181
|
+
warnings,
|
|
182
|
+
fingerprint: crypto.createHash('sha256').update(source).digest('hex'),
|
|
183
|
+
};
|
|
184
|
+
await writeFile(join(output, 'index.html'), html, 'utf8');
|
|
185
|
+
await writeFile(join(output, 'manifest.json'), `${JSON.stringify(manifest, null, '\t')}\n`, 'utf8');
|
|
186
|
+
return { output, html, resources, warnings, manifest };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function extensionForKind(kind) {
|
|
190
|
+
return kind === 'style' ? '.css' : kind === 'json' ? '.json' : '.js';
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function attributeValue(attributes, name) {
|
|
194
|
+
const match = attributes.match(new RegExp(`\\b${name}\\s*=\\s*[\\"']([^\\"']*)[\\"']`, 'i'));
|
|
195
|
+
return match?.[1];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function copyScriptAttributes(attributes) {
|
|
199
|
+
return attributes.replace(/\s+(?:src|type)\s*=\s*["'][^"']*["']/gi, '').replace(/\s+$/, '');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function copyStyleAttributes(attributes) {
|
|
203
|
+
return attributes.replace(/\s+type\s*=\s*["'][^"']*["']/gi, '').replace(/\s+$/, '');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function decodeDataUri(value) {
|
|
207
|
+
const comma = value.indexOf(',');
|
|
208
|
+
if (comma === -1) return null;
|
|
209
|
+
const header = value.slice(5, comma);
|
|
210
|
+
const payload = value.slice(comma + 1);
|
|
211
|
+
const fields = header.split(';');
|
|
212
|
+
const mime = fields.shift() || 'text/plain';
|
|
213
|
+
try {
|
|
214
|
+
return {
|
|
215
|
+
mime,
|
|
216
|
+
data: fields.includes('base64') ? Buffer.from(payload, 'base64') : Buffer.from(decodeURIComponent(payload)),
|
|
217
|
+
};
|
|
218
|
+
} catch {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
224
|
+
const input = process.argv[2];
|
|
225
|
+
const outputFlag = process.argv.indexOf('-o');
|
|
226
|
+
const output = outputFlag === -1 ? undefined : process.argv[outputFlag + 1];
|
|
227
|
+
if (!input || (outputFlag !== -1 && !output)) {
|
|
228
|
+
console.error('Usage: node tools/extract-html.mjs input.html [-o output-directory]');
|
|
229
|
+
process.exitCode = 2;
|
|
230
|
+
} else {
|
|
231
|
+
const result = await extractHtml(input, output);
|
|
232
|
+
console.log(`extracted ${result.resources.length} resource(s) into ${result.output}`);
|
|
233
|
+
for (const warning of result.warnings) console.warn(`warning: ${warning}`);
|
|
234
|
+
}
|
|
235
|
+
}
|