standalone regenerators, block migrations

This commit is contained in:
Loren Norman 2025-07-25 15:32:20 -04:00
parent 65fd5959bc
commit 37600d82f1
6 changed files with 82 additions and 122 deletions

View file

@ -1,64 +0,0 @@
// deprecated: use feeds/set_value
export default {
type: "action_publish",
bytecodeKey: "publishAction",
name: "Publish to Feed",
colour: "0",
description: "Sends the given value to the specified Feed.",
connections: {
mode: "statement",
output: "expression",
next: 'expression'
},
template: `
📈 Publish |CENTER
...value: %VALUE
...to: %FEED
`,
inputs: {
VALUE: {
description: "The value to write to the Feed.",
check: "expression",
shadow: 'io_text'
},
FEED: {
description: "The Feed to write to.",
check: "expression",
shadow: 'feed_selector'
},
},
generators: {
json: (block, generator) => {
const payload = {
publishAction: {
feed: JSON.parse(generator.valueToCode(block, 'FEED', 0) || null),
value: JSON.parse(generator.valueToCode(block, 'VALUE', 0) || null)
}
}
return JSON.stringify(payload)
}
},
regenerators: {
json: (blockObject, helpers) => {
const payload = blockObject.publishAction
// migrating to a new block
return {
type: "feed_set_value",
fields: {
FEED_KEY: payload.feed.feed.key,
},
inputs: {
VALUE: helpers.expressionToBlock(payload.value, { shadow: 'io_text' }),
}
}
}
}
}

View file

@ -1,53 +0,0 @@
// deprecated: use feeds/get_value
export default {
type: "feed_selector",
bytecodeKey: "feed",
name: "Feed",
colour: 300,
description: "The last value of this feed or component, always a String",
mixins: ['replaceDropdownOptions'],
extensions: ['populateFeedDropdown'],
connections: {
mode: "value",
output: "expression",
},
template: "Feed: %FEED_KEY",
fields: {
FEED_KEY: {
description: "A listing of the User's Feeds to select from.",
options: [
[ "Loading Feeds...", "" ],
]
}
},
generators: {
json: block => {
const
key = block.getFieldValue('FEED_KEY'),
payload = JSON.stringify({
feed: { key }
})
return [ payload, 0 ]
}
},
regenerators: {
json: blockObject => {
const payload = blockObject.feed
// migrating to a new block
return {
type: "feed_get_value",
fields: {
FEED_KEY: payload.key
}
}
}
}
}

View file

@ -0,0 +1,38 @@
// These are for blocks that have been replaced with new blocks, but still
// exist in the database. The block definition gets removed, but a new
// regenerator is written here to catch those legacy blocks and "port" them
// to the new block when they are loaded.
export default {
// becomes feed_set_value
action_publish: {
json: (blockObject, helpers) => {
const payload = blockObject.publishAction
return {
type: "feed_set_value",
fields: {
FEED_KEY: payload.feed.feed.key,
},
inputs: {
VALUE: helpers.expressionToBlock(payload.value, { shadow: 'io_text' }),
}
}
}
},
// becomes feed_get_value
feed_selector: {
json: blockObject => {
const payload = blockObject.feed
return {
type: "feed_get_value",
fields: {
FEED_KEY: payload.key
}
}
}
}
}

View file

@ -60,14 +60,23 @@ DefinitionSet.load = async function(appLocation) {
enabledBlocks = reject(rawDefinitions.blocks, "definition.disabled"),
definitionSet = new DefinitionSet()
// TODO: fields
// TODO: shadows
// TODO: inputs
// TODO: process fields
// TODO: process shadows
// TODO: process inputs
// process mixins
definitionSet.mixins = rawDefinitions.mixins
// process extensions
definitionSet.extensions = rawDefinitions.extensions
// process mutators
definitionSet.mutators = rawDefinitions.mutators
// process standalone regenerators
forEach(rawDefinitions.regenerators, (regenerators, blockType) => {
definitionSet.regenerators[blockType] = regenerators
})
// process blocks
forEach(enabledBlocks, ({ definition, path }) => {
const blockDef = BlockDefinition.parseRawDefinition(definition, path, definitionSet)
definitionSet.blocks.push(blockDef)
@ -110,15 +119,24 @@ DefinitionSet.load = async function(appLocation) {
definitionSet.mutators[blockDef.type] = mutator
}
if(definitionSet.generators[blockDef.type]) {
throw new Error(`Generator already present for block: ${blockDef.type}`)
}
definitionSet.generators[blockDef.type] = blockDef.generators
if(definitionSet.regenerators[blockDef.type]) {
throw new Error(`Regenerator already present for block: ${blockDef.type}`)
}
definitionSet.regenerators[blockDef.type] = blockDef.regenerators
})
// process toolbox
forEach(rawDefinitions.toolboxes, rawToolboxDef => {
const toolboxDef = ToolboxDefinition.parseRawDefinition(rawToolboxDef, definitionSet)
definitionSet.toolboxes.push(toolboxDef)
})
// process workspace
forEach(rawDefinitions.workspaces, rawWorkspaceDef => {
const workspaceDef = WorkspaceDefinition.parseRawDefinition(rawWorkspaceDef, definitionSet)
definitionSet.workspaces.push(workspaceDef)

View file

@ -30,13 +30,15 @@ const BYTECODE_BLOCK_TYPE_MAP = {
negate: 'io_logic_negate',
setVariable: 'io_variables_set',
getVariable: 'io_variables_get',
feed: 'feed_selector',
getFeedValue: 'feed_get_value',
setFeedValue: 'feed_set_value',
publishAction: 'action_publish',
webhookAction: 'action_webhook',
emailAction: 'action_email',
smsAction: 'action_sms',
// removed blocks that have migration regenerators
// see: app/regenerators/migrations.js
feed: 'feed_selector',
publishAction: 'action_publish',
}
const lookupRegenerator = expressionName => {

View file

@ -11,6 +11,7 @@ const
EXTENSION_LOCATION = `extensions/`,
MIXIN_LOCATION = `mixins/`,
MUTATOR_LOCATION = `mutators/`,
REGENERATOR_LOCATION = `regenerators/`,
TOOLBOX_LOCATION = `toolbox/`,
WORKSPACE_LOCATION = `workspace/`,
@ -62,6 +63,23 @@ export const DefinitionLoader = {
))
},
loadRegenerators: async (appLocation=APP_LOCATION) => {
const jsfiles = await glob(`./${appLocation}/${REGENERATOR_LOCATION}**/*.js`, { ignore: EXAMPLE_FILES })
// loads app/regenerators/*.js into object like:
// { blockType: { json: Function }}
let regenerators = {}
await Promise.all(jsfiles.map( async filePath => {
const regeneratorsFromFile = (await import(`${PROJECT_ROOT}/${filePath}`)).default
regenerators = {
...regenerators,
...regeneratorsFromFile
}
}))
return regenerators
},
loadBlocks: async (appLocation=APP_LOCATION) => {
// get the file listing
const
@ -101,6 +119,7 @@ export const DefinitionLoader = {
mutators: await DefinitionLoader.loadMutators(options.source),
mixins: await DefinitionLoader.loadMixins(options.source),
extensions: await DefinitionLoader.loadExtensions(options.source),
regenerators: await DefinitionLoader.loadRegenerators(options.source),
blocks: await DefinitionLoader.loadBlocks(options.source),
toolboxes: await DefinitionLoader.loadToolboxes(options.source),
workspaces: await DefinitionLoader.loadWorkspaces(options.source),