Files
moli/moli-core/tests/fixtures/text-modules.js
ldm0 d9290e87ad feat(modules): support native text module imports
Support type: text through the shared module map, Window, child Documents and workers. Export UTF-8 decoded strings without executing their contents, preserve typed-module identity, and carry text request metadata through network, preload and Service Worker loaders. Regressions cover static/dynamic import sharing, BOM and invalid UTF-8, CORS, integrity, worker environments and unsupported-type rejection.

Extracted from development commit a6de018613.
Base: main (62e527cd34).

Validation (32 build jobs and test threads): cargo fmt --all; cargo clippy --workspace --all-targets --all-features -- -D warnings; cargo nextest run --no-fail-fast.
     Summary [ 146.817s] 22203 tests run: 22203 passed (9 slow), 20 skipped
2026-11-03 06:30:06 +08:00

66 lines
3.7 KiB
JavaScript

async function textModuleProbe() {
const result = {checks: 0, failures: []};
const check = (name, actual, expected = true) => {
result.checks++;
if (actual !== expected) result.failures.push({name, actual, expected});
};
const text = url => import(url, {with: {type: 'text'}});
const cases = [
['empty', 'data:,', ''],
['unicode', 'data:text/plain;charset=windows-1250,%C5%9B%C4%87%C4%85%C5%BC%C5%BA%F0%9F%98%80', 'śćążź😀'],
['utf8-bom', 'data:application/octet-stream,%EF%BB%BFhello', 'hello'],
['utf16-bom', 'data:text/plain;charset=utf-16,%FF%FEa%00', '\uFFFD\uFFFDa\0'],
['replacement', 'data:text/plain,%ED%A0%80%FF', '\uFFFD\uFFFD\uFFFD\uFFFD'],
['nul-and-lines', 'data:text/plain,a%00b%0D%0Ac%0Dd', 'a\0b\r\nc\rd'],
['wasm-mime', 'data:application/wasm;base64,AGFzbQEAAAA=', '\0asm\u0001\0\0\0'],
['json-mime', 'data:application/json,%7B%22answer%22%3A42%7D', '{"answer":42}'],
['source-is-inert', 'data:text/javascript,globalThis.textModuleExecuted%3Dtrue%3B', 'globalThis.textModuleExecuted=true;'],
];
for (const [name, url, expected] of cases) {
try {
const [first, second] = await Promise.all([text(url), text(url)]);
check(name + ':value', first.default, expected);
check(name + ':identity', first === second && first === await text(url));
check(name + ':namespace', Object.getPrototypeOf(first) === null && !Object.isExtensible(first));
check(name + ':exports', Object.keys(first).join(','), 'default');
} catch (error) { check(name + ':load', error.name, 'fulfilled'); }
}
check('inert', globalThis.textModuleExecuted === undefined);
for (const firstType of ['json', 'text']) {
const url = 'data:application/json,%7B%22answer%22%3A42%7D#' + firstType;
try {
const secondType = firstType === 'json' ? 'text' : 'json';
const first = await import(url, {with: {type: firstType}});
const second = await import(url, {with: {type: secondType}});
const json = firstType === 'json' ? first : second;
const string = firstType === 'text' ? first : second;
check(firstType + ':json', json.default.answer, 42);
check(firstType + ':text', string.default, '{"answer":42}');
check(firstType + ':separate-records', json !== string);
} catch (error) { check(firstType + ':distinct-types', error.name, 'fulfilled'); }
}
for (const textFirst of [false, true]) {
const url = 'data:application/octet-stream,opaque#' + textFirst;
const wrong = () => import(url).then(() => 'fulfilled', error => error.name);
try {
if (textFirst) check('text-before-wrong', (await text(url)).default, 'opaque');
check('untyped-rejected:' + textFirst, await wrong(), 'TypeError');
check('text-after-wrong:' + textFirst, (await text(url)).default, 'opaque');
} catch (error) { check('untyped-isolation:' + textFirst, error.name, 'fulfilled'); }
}
try {
const url = 'data:text/plain,leaf';
const graph = 'data:text/javascript,' + encodeURIComponent(
'export {default} from ' + JSON.stringify(url) + ' with {type:"text"};');
check('static-reexport', (await import(graph)).default, 'leaf');
const missing = 'data:text/javascript,' + encodeURIComponent(
'import {missing} from ' + JSON.stringify(url) + ' with {type:"text"};');
check('no-named-export', await import(missing).then(() => 'fulfilled', e => e.name), 'SyntaxError');
} catch (error) { check('static-graph', error.name, 'fulfilled'); }
for (const type of ['Text', '', 'javascript-or-wasm']) {
check('invalid-type:' + type,
await import('data:text/plain,blocked', {with: {type}}).then(() => 'fulfilled', e => e.name), 'TypeError');
}
return result;
}