Skip to content

Commit

Permalink
test language for extension features
Browse files Browse the repository at this point in the history
  • Loading branch information
kriskowal committed Nov 8, 2024
1 parent 09bb2c2 commit 42b8b18
Show file tree
Hide file tree
Showing 14 changed files with 352 additions and 27 deletions.
116 changes: 96 additions & 20 deletions packages/compartment-mapper/src/archive.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ const assignParserForLanguage = (options = {}) => {
const parserForLanguage = freeze(
assign(create(null), defaultParserForLanguage, parserForLanguageOption),
);
return { ...rest, parserForLanguage };
const languages = Object.keys(parserForLanguage);
return { ...rest, parserForLanguage, languages };
};

/**
Expand All @@ -61,12 +62,16 @@ export const makeAndHashArchive = async (
moduleLocation,
options = {},
) => {
const compartmentMap = await mapNodeModules(powers, moduleLocation, options);
return makeAndHashArchiveFromMap(
powers,
compartmentMap,
assignParserForLanguage(options),
);
const { parserForLanguage, languages, ...otherOptions } =
assignParserForLanguage(options);
const compartmentMap = await mapNodeModules(powers, moduleLocation, {
languages,
...otherOptions,
});
return makeAndHashArchiveFromMap(powers, compartmentMap, {
parserForLanguage,
...otherOptions,
});
};

/**
Expand All @@ -76,20 +81,35 @@ export const makeAndHashArchive = async (
* @returns {Promise<Uint8Array>}
*/
export const makeArchive = async (powers, moduleLocation, options = {}) => {
const { dev, tags, conditions = tags, commonDependencies, policy } = options;

const {
dev,
tags,
conditions = tags,
commonDependencies,
policy,
languageForExtension,
commonjsLanguageForExtension,
moduleLanguageForExtension,
parserForLanguage,
languages,
...otherOptions
} = assignParserForLanguage(options);
const compartmentMap = await mapNodeModules(powers, moduleLocation, {
dev,
conditions,
commonDependencies,
policy,
languageForExtension,
commonjsLanguageForExtension,
moduleLanguageForExtension,
languages,
});

return makeArchiveFromMap(
powers,
compartmentMap,
assignParserForLanguage(options),
);
return makeArchiveFromMap(powers, compartmentMap, {
parserForLanguage,
policy,
...otherOptions,
});
};

/**
Expand All @@ -99,16 +119,36 @@ export const makeArchive = async (powers, moduleLocation, options = {}) => {
* @returns {Promise<Uint8Array>}
*/
export const mapLocation = async (powers, moduleLocation, options = {}) => {
const { dev, tags, conditions = tags, commonDependencies, policy } = options;
const {
dev,
tags,
conditions = tags,
commonDependencies,
policy,
parserForLanguage,
languages,
languageForExtension,
commonjsLanguageForExtension,
moduleLanguageForExtension,
...otherOptions
} = assignParserForLanguage(options);

const compartmentMap = await mapNodeModules(powers, moduleLocation, {
dev,
conditions,
commonDependencies,
policy,
languages,
languageForExtension,
commonjsLanguageForExtension,
moduleLanguageForExtension,
});

return mapFromMap(powers, compartmentMap, assignParserForLanguage(options));
return mapFromMap(powers, compartmentMap, {
parserForLanguage,
policy,
...otherOptions,
});
};

/**
Expand All @@ -118,16 +158,36 @@ export const mapLocation = async (powers, moduleLocation, options = {}) => {
* @returns {Promise<string>}
*/
export const hashLocation = async (powers, moduleLocation, options = {}) => {
const { dev, tags, conditions = tags, commonDependencies, policy } = options;
const {
dev,
tags,
conditions = tags,
commonDependencies,
policy,
parserForLanguage,
languages,
languageForExtension,
commonjsLanguageForExtension,
moduleLanguageForExtension,
...otherOptions
} = assignParserForLanguage(options);

const compartmentMap = await mapNodeModules(powers, moduleLocation, {
dev,
conditions,
commonDependencies,
policy,
languages,
languageForExtension,
commonjsLanguageForExtension,
moduleLanguageForExtension,
});

return hashFromMap(powers, compartmentMap, assignParserForLanguage(options));
return hashFromMap(powers, compartmentMap, {
parserForLanguage,
policy,
...otherOptions,
});
};

/**
Expand All @@ -144,18 +204,34 @@ export const writeArchive = async (
moduleLocation,
options = {},
) => {
const { dev, tags, conditions = tags, commonDependencies, policy } = options;
const {
dev,
tags,
conditions = tags,
commonDependencies,
policy,
parserForLanguage,
languages,
languageForExtension,
commonjsLanguageForExtension,
moduleLanguageForExtension,
...otherOptions
} = assignParserForLanguage(options);
const compartmentMap = await mapNodeModules(readPowers, moduleLocation, {
dev,
conditions,
commonDependencies,
policy,
languageForExtension,
commonjsLanguageForExtension,
moduleLanguageForExtension,
languages,
});
return writeArchiveFromMap(
write,
readPowers,
archiveLocation,
compartmentMap,
assignParserForLanguage(options),
{ policy, parserForLanguage, ...otherOptions },
);
};
15 changes: 10 additions & 5 deletions packages/compartment-mapper/src/import.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ const assignParserForLanguage = (options = {}) => {
const parserForLanguage = freeze(
assign(create(null), defaultParserForLanguage, parserForLanguageOption),
);
return { ...rest, parserForLanguage };
const languages = Object.keys(parserForLanguage);
return { ...rest, parserForLanguage, languages };
};

/**
Expand Down Expand Up @@ -77,15 +78,16 @@ export const loadLocation = async (
tags,
commonDependencies,
policy,
parserForLanguage,
languages,
languageForExtension,
commonjsLanguageForExtension,
moduleLanguageForExtension,
} = options;
...otherOptions
} = assignParserForLanguage(options);
// conditions are not present in SyncArchiveOptions
const conditions =
'conditions' in options ? options.conditions || tags : tags;
const parserForLanguage = assignParserForLanguage(options);
const languages = Object.keys(parserForLanguage);
const compartmentMap = await mapNodeModules(readPowers, moduleLocation, {
dev,
conditions,
Expand All @@ -96,7 +98,10 @@ export const loadLocation = async (
moduleLanguageForExtension,
languages,
});
return loadFromMap(readPowers, compartmentMap, parserForLanguage);
return loadFromMap(readPowers, compartmentMap, {
parserForLanguage,
...otherOptions,
});
};

/**
Expand Down
8 changes: 8 additions & 0 deletions packages/compartment-mapper/src/map-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ const makeExtensionParser = (
) {
language = languageForModuleSpecifier[specifier];
} else {
// We should revisit this design decision:
// Defaulting the language to the extension conflates those namespaces.
// So, a transform keyed by extension can be used to coerce a language
// (e.g., .mts to mjs) as a shorthand for configuring a parser for that
// extension that pre-processes the file before handing off to the
// parser.
// But, this forces us to support the case of using weird language
// names like pre-mjs-json as valid, unconfigured extensions.
language = languageForExtension[extension] || extension;
}

Expand Down
4 changes: 2 additions & 2 deletions packages/compartment-mapper/src/node-modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ const inferParsers = (descriptor, location, languageOptions) => {
throw Error(
`Cannot interpret parser map ${JSON.stringify(
packageLanguageForExtension,
)} of package at ${location}, must be an object mapping file extensions to corresponding languages (mjs for ECMAScript modules, cjs for CommonJS modules, or json for JSON modules`,
)} of package at ${location}, must be an object mapping file extensions to corresponding languages (for example, mjs for ECMAScript modules, cjs for CommonJS modules, or json for JSON modules`,
);
}
const invalidLanguages = values(packageLanguageForExtension).filter(
Expand All @@ -247,7 +247,7 @@ const inferParsers = (descriptor, location, languageOptions) => {
throw Error(
`Cannot interpret parser map language values ${JSON.stringify(
invalidLanguages,
)} of package at ${location}, must be an object mapping file extensions to corresponding languages (mjs for ECMAScript modules, cjs for CommonJS modules, or json for JSON modules`,
)} of package at ${location}, must be an object mapping file extensions to corresponding languages (for example, mjs for ECMAScript modules, cjs for CommonJS modules, or json for JSON modules`,
);
}

Expand Down
1 change: 1 addition & 0 deletions packages/compartment-mapper/src/parse-json.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const textDecoder = new TextDecoder();
/** @type {ParseFn} */
export const parseJson = (bytes, _specifier, location, _packageLocation) => {
const source = textDecoder.decode(bytes);
/** @type {Array<string>} */
const imports = freeze([]);

/**
Expand Down
45 changes: 45 additions & 0 deletions packages/compartment-mapper/test/_parse-jsonp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/** @module Provides joke language support for importing JSONP modules. */

/**
* @import {ParseFn, ParserImplementation} from '../src/types.js'
*/

const textDecoder = new TextDecoder();

/** @type {ParseFn} */
export const parseJsonp = (bytes, _specifier, _location, _packageLocation) => {
// Presumes that all JSONP module bytes are retrieved with ?callback=exports.
const source = textDecoder.decode(bytes);
const imports = harden([]);

/**
* @param {object} exports
*/
const execute = exports => {
const compartment = new Compartment({
__options__: true,
globals: harden({
exports(value) {
exports.default = value;
},
}),
});
compartment.evaluate(source);
};
return {
parser: 'jsonp',
bytes,
record: harden({
imports,
exports: ['default'],
execute,
}),
};
};

/** @type {ParserImplementation} */
export default {
parse: parseJsonp,
heuristicImports: false,
synchronous: true,
};

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 42b8b18

Please sign in to comment.