Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion src/engine/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -1061,7 +1061,25 @@ class Runtime extends EventEmitter {
* @param {ExtensionMetadata} extensionInfo - information about the extension (id, blocks, etc.)
* @private
*/
_registerExtensionPrimitives (extensionInfo) {
async _registerExtensionPrimitives (extensionInfo) {

// If the extension requires other extensions, load them first.
if (Array.isArray(extensionInfo.requiredExtensions)) {
for (const extensionId of extensionInfo.requiredExtensions) {
if (
this.extensionManager.isCoreExtension(extensionId) ||
this.extensionManager.isBuiltinExtension(extensionId) ||
await this.extensionManager.securityManager.canLoadExtensionFromProject(extensionId)
) {
this.extensionManager.loadExtensionURL(extensionId);
} else {
console.warn(
`Failed to load required extension: ${extensionId} for extension: ${extensionInfo.id}`
);
}
}
}

const categoryInfo = {
id: extensionInfo.id,
name: maybeFormatMessage(extensionInfo.name),
Expand Down
29 changes: 27 additions & 2 deletions src/extension-support/extension-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@ const defaultBuiltinExtensions = {
tw: () => require('../extensions/tw')
};

const coreExtensions = [
'motion',
'looks',
'sound',
'events',
'control',
'sensing',
'operators',
'variables',
'json',
'procedures',
'comments'
];

/**
* @typedef {object} ArgumentInfo - Information about an extension block argument
* @property {ArgumentType} type - the type of value this argument can take
Expand Down Expand Up @@ -126,6 +140,7 @@ class ExtensionManager {
this.asyncExtensionsLoadedCallbacks = [];

this.builtinExtensions = Object.assign({}, defaultBuiltinExtensions);
this.coreExtensions = coreExtensions;

dispatch.setService('extensions', createExtensionService(this)).catch(e => {
log.error(`ExtensionManager was unable to register extension service: ${JSON.stringify(e)}`);
Expand Down Expand Up @@ -153,6 +168,16 @@ class ExtensionManager {
return Object.prototype.hasOwnProperty.call(this.builtinExtensions, extensionId);
}

/**
* Determine whether an extension with a given ID is registered as a core extension in the VM, such as motion.
* Note that custom extensions or extensions that don't load on startup will return false here.
* @param {string} extensionId
* @returns {boolean}
*/
isCoreExtension (extensionId) {
return this.coreExtensions.includes(extensionId);
}

/**
* Synchronously load an internal extension (core or non-core) by ID. This call will
* fail if the provided id is not does not match an internal extension.
Expand Down Expand Up @@ -207,8 +232,8 @@ class ExtensionManager {
return;
}

if (this.isExtensionURLLoaded(extensionURL)) {
// Extension is already loaded.
if (this.isExtensionURLLoaded(extensionURL) || this.isCoreExtension(extensionURL)) {
// Extension is already loaded or is a core extension.
return;
}

Expand Down
Loading