From b10326ba56011526dc0a8cb5398fd4ac31a65db7 Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Sat, 3 Jan 2026 20:40:40 +0300 Subject: [PATCH 1/4] Restructure `Parser.verify` to `Parser.getExtensions` --- src/asset/core/parser.js | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/asset/core/parser.js b/src/asset/core/parser.js index 70007691..4b5c8558 100644 --- a/src/asset/core/parser.js +++ b/src/asset/core/parser.js @@ -1,3 +1,4 @@ +/** @import { Constructor } from '../../reflect/index.js' */ import { throws } from '../../logger/index.js' /** @@ -6,6 +7,19 @@ import { throws } from '../../logger/index.js' */ export class Parser { + /** + * @readonly + * @type {Constructor} + */ + asset + + /** + * @param {Constructor} asset + */ + constructor(asset) { + this.asset = asset + } + /** * @param {Response} _response * @returns {Promise} @@ -17,12 +31,11 @@ export class Parser { } /** - * @param {string} _extension - * @returns {boolean} + * @returns {string[]} */ - verify(_extension) { - throws(`Implement the method \`verify\` on \`${this.constructor.name}\``) + getExtensions() { + throws(`Implement the method \`getExtensions\` on \`${this.constructor.name}\``) - return false + return [] } } From 0de1f77398a99617c472ea7fc8934cda140d3420 Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Sat, 3 Jan 2026 20:41:29 +0300 Subject: [PATCH 2/4] Add `Parsers` --- src/asset/resources/assetserver.js | 73 +++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/src/asset/resources/assetserver.js b/src/asset/resources/assetserver.js index ac9042d4..752bd02f 100644 --- a/src/asset/resources/assetserver.js +++ b/src/asset/resources/assetserver.js @@ -1,11 +1,82 @@ /** @import { TypeId, Constructor } from '../../reflect/index.js' */ /** @import { AssetId } from '../types/index.js' */ import { typeid } from '../../reflect/index.js' -import { assert } from '../../logger/index.js' +import { assert, warn } from '../../logger/index.js' import { getFileExtension, swapRemove } from '../../utils/index.js' import { Assets, Handle, Parser } from '../core/index.js' import { AssetLoadSuccess, AssetLoadFail } from '../events/index.js' +/** + * @typedef {number} ParserId + */ +export class Parsers { + + /** + * @private + * @type {Parser[]} + */ + parsers = [] + + /** + * @private + * @type {Map>} + */ + extensions = new Map() + + /** + * @template T + * @param {Parser} parser + */ + add(parser) { + const id = this.parsers.length + const typeId = typeid(parser.asset) + const extensions = parser.getExtensions() + + this.parsers.push(parser) + + for (let i = 0; i < extensions.length; i++) { + const extension = extensions[i] + const extensionMap = this.extensions.get(extension) + + if (extensionMap) { + if (extensionMap.has(typeId)) { + warn(`Overriding a parser already present with asset type \`${typeId}\` and with extension "${extension}"".`) + } + + extensionMap.set(typeId, id) + } else { + this.extensions.set(extension, new Map([[typeId, id]])) + } + } + } + + /** + * @template T + * @param {TypeId} type + * @param {string} extension + * @returns {Parser} + * @throws {string} + */ + get(type, extension) { + const extensions = this.extensions.get(extension) + + if (!extensions) { + throw 'The given extension does not have a parser registered' + } + + const parserId = extensions.get(type) + + if (parserId === undefined) { + throw 'The given asset type does not support the given extension' + } + + const parser = this.parsers[parserId] + + assert(parser, 'Internal error: The givk&en parser index is invalid.') + + return /** @type {Parser} */(parser) + } +} export class AssetServer { /** From a3c3ec9f8e429e2505d22fafce57d8be1e258326 Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Sat, 3 Jan 2026 20:42:09 +0300 Subject: [PATCH 3/4] Modfy `AssetServer` to use `Parsers` --- src/asset/resources/assetserver.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/asset/resources/assetserver.js b/src/asset/resources/assetserver.js index 752bd02f..ddd5d8ad 100644 --- a/src/asset/resources/assetserver.js +++ b/src/asset/resources/assetserver.js @@ -89,9 +89,9 @@ export class AssetServer { /** * @private * @readonly - * @type {Map>} + * @type {Parsers} */ - parsers = new Map() + parsers = new Parsers() /** * @private @@ -140,7 +140,7 @@ export class AssetServer { * @param {Parser} parser */ registerParser(type, parser) { - this.parsers.set(typeid(type), parser) + this.parsers.add(parser) } /** @@ -222,15 +222,7 @@ export class AssetServer { */ async internalFetch(assetId, typeId, path) { const extension = getFileExtension(path) - const parser = this.parsers.get(typeId) - - if (!parser) { - throw 'No parser registered for the asset type.' - } - - if (!parser.verify(extension)) { - throw `The extension "${extension}" is not supported by \`${parser.constructor.name}\`` - } + const parser = this.parsers.get(typeId, extension) const response = await fetch(path) From b2c490cc49687f660780acfd3ce94eb5b98b8eca Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Sat, 3 Jan 2026 20:45:21 +0300 Subject: [PATCH 4/4] Update dependents and tests --- src/asset/tests/assetserver.test.js | 16 ++++++++-------- src/audio/resources/parser.js | 27 ++++++--------------------- src/render-core/resources/image.js | 13 ++++++++----- 3 files changed, 22 insertions(+), 34 deletions(-) diff --git a/src/asset/tests/assetserver.test.js b/src/asset/tests/assetserver.test.js index ff6c2eca..ffbf01fa 100644 --- a/src/asset/tests/assetserver.test.js +++ b/src/asset/tests/assetserver.test.js @@ -1,6 +1,6 @@ -import { deepStrictEqual, notDeepStrictEqual, strictEqual } from "assert"; +import { deepStrictEqual, notDeepStrictEqual } from "assert"; import test, { describe,todo } from "node:test"; -import { Assets, AssetServer, LoadState, Parser } from "../index.js"; +import { Assets, AssetServer, Parser } from "../index.js"; class Text { inner = '' @@ -16,11 +16,14 @@ class Text { * @extends {Parser} */ class TextParser extends Parser { + constructor(){ + super(Text) + } /** - * @param {string} extension + * @override */ - verify(extension){ - return extension === 'txt' + getExtensions(){ + return ['txt'] } /** @@ -50,9 +53,6 @@ describe('Testing `AssetServer`', () => { // simulates `unloadDroppedAssets` server.dropAssetInfo(handle1.id()) - // TODO: Remove when handles are unique - // handles arent unique yet, so this ensures handle is at a different index - const handle3 = server.load(Text,"/assets/text/sample2.txt") const handle2 = server.load(Text,"/assets/text/sample.txt") notDeepStrictEqual(handle1.id(),handle2.id()) diff --git a/src/audio/resources/parser.js b/src/audio/resources/parser.js index cccffb29..0c88b333 100644 --- a/src/audio/resources/parser.js +++ b/src/audio/resources/parser.js @@ -6,12 +6,6 @@ import { Audio } from '../assets/index.js' */ export class AudioParser extends Parser { - /** - * @private - * @type {Set} - */ - extensions - /** * @private * @type {OfflineAudioContext} @@ -25,17 +19,8 @@ export class AudioParser extends Parser { sampleRate: 44100, length: 512 }) { - super() + super(Audio) this.decoder = new OfflineAudioContext(options) - this.extensions = this.getExtensions() - } - - /** - * @inheritdoc - * @param {string} extension - */ - verify(extension) { - return this.extensions.has(extension) } /** @@ -52,19 +37,19 @@ export class AudioParser extends Parser { // audio capabilities const audio = document.createElement('audio') - const extensions = new Set() + const extensions = [] if (audio.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, '')) { - extensions.add('ogg') + extensions.push('ogg') } if (audio.canPlayType('audio/mpeg;').replace(/^no$/, '')) { - extensions.add('mp3') + extensions.push('mp3') } if (audio.canPlayType('audio/wav; codecs="1"').replace(/^no$/, '')) { - extensions.add('wav') + extensions.push('wav') } if (audio.canPlayType('audio/x-m4a;').replace(/^no$/, '') || audio.canPlayType('audio/aac;').replace(/^no$/, '')) { - extensions.add('m4a') + extensions.push('m4a') } return extensions diff --git a/src/render-core/resources/image.js b/src/render-core/resources/image.js index bf8042bc..c9140258 100644 --- a/src/render-core/resources/image.js +++ b/src/render-core/resources/image.js @@ -7,11 +7,14 @@ import { Vector2 } from '../../math/index.js' */ export class ImageParser extends Parser { - /** - * @param {string} _extension - */ - verify(_extension) { - return true + constructor() { + super(Image) + } + + getExtensions() { + + // TODO: Actually get the supported image formats + return ['png', 'jpeg'] } /**