From b21d827215ddfe8325148e14368a6b6f8c15471c Mon Sep 17 00:00:00 2001 From: rrgoetz Date: Mon, 4 Nov 2024 08:50:20 -1000 Subject: [PATCH 1/7] Update grammar for load and activate * Allow for optional timetag so they can be used as immediate commands --- src/utilities/codemirror/sequence.grammar | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utilities/codemirror/sequence.grammar b/src/utilities/codemirror/sequence.grammar index 97a7ba72bb..8118fd5341 100644 --- a/src/utilities/codemirror/sequence.grammar +++ b/src/utilities/codemirror/sequence.grammar @@ -92,9 +92,9 @@ Command { Models? } -Activate { TimeTag activateDirective commonLoadActivate } +Activate { TimeTag? activateDirective commonLoadActivate } -Load { TimeTag loadDirective commonLoadActivate } +Load { TimeTag? loadDirective commonLoadActivate } commonLoadActivate { "(" SequenceName { String } ")" From 47869f0adbae959fe7b3053d36d20fa2687b5f69 Mon Sep 17 00:00:00 2001 From: rrgoetz Date: Mon, 4 Nov 2024 08:51:49 -1000 Subject: [PATCH 2/7] Add rtc load and activate to content assist --- .../sequence-editor/sequence-completion.ts | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/utilities/sequence-editor/sequence-completion.ts b/src/utilities/sequence-editor/sequence-completion.ts index 429bffff67..aafeb2c767 100644 --- a/src/utilities/sequence-editor/sequence-completion.ts +++ b/src/utilities/sequence-editor/sequence-completion.ts @@ -385,8 +385,8 @@ function generateHardwareCompletions(commandDictionary: CommandDictionary | null } function generateStepCompletion(cursor: CursorInfo): Completion[] { - // if cursor is at the LineComment/Description don't show the command completions list - if (cursor.isAtLineComment || !cursor.isBeforeHDWCommands || !cursor.isBeforeImmedOrHDWCommands) { + // if cursor is at the LineComment/Description after hardware commands don't show the command completions list + if (cursor.isAtLineComment || !cursor.isBeforeHDWCommands) { return []; } @@ -397,13 +397,13 @@ function generateStepCompletion(cursor: CursorInfo): Completion[] { view.dispatch({ changes: { from: Math.max(0, from + (!cursor.isAfterTimeTag || cursor.isAtSymbolBefore ? -1 : 0)), - insert: `${!cursor.isAfterTimeTag ? 'C ' : ''}@GROUND_EVENT("ground_event.name")`, + insert: `${!cursor.isAfterTimeTag && cursor.isBeforeImmedOrHDWCommands ? 'C ' : ''}@ACTIVATE("activate.name")`, to, }, }); }, - info: 'ground event command', - label: '@GROUND_EVENT', + info: 'activate command', + label: '@ACTIVATE', section: 'Ground Commands', type: 'function', }); @@ -413,29 +413,34 @@ function generateStepCompletion(cursor: CursorInfo): Completion[] { view.dispatch({ changes: { from: Math.max(0, from + (!cursor.isAfterTimeTag || cursor.isAtSymbolBefore ? -1 : 0)), - insert: `${!cursor.isAfterTimeTag ? 'C ' : ''}@GROUND_BLOCK("ground_block.name")`, + insert: `${!cursor.isAfterTimeTag && cursor.isBeforeImmedOrHDWCommands ? 'C ' : ''}@LOAD("load.name")`, to, }, }); }, - info: 'ground block command', - label: '@GROUND_BLOCK', + info: 'load command', + label: '@LOAD', section: 'Ground Commands', type: 'function', }); + // if after immediate commands don't show the command completions list below + if (!cursor.isBeforeImmedOrHDWCommands) { + return stepCompletion; + } + stepCompletion.push({ apply: (view, _completion, from: number, to: number) => { view.dispatch({ changes: { from: Math.max(0, from + (!cursor.isAfterTimeTag || cursor.isAtSymbolBefore ? -1 : 0)), - insert: `${!cursor.isAfterTimeTag ? 'C ' : ''}@ACTIVATE("activate.name")`, + insert: `${!cursor.isAfterTimeTag ? 'C ' : ''}@GROUND_EVENT("ground_event.name")`, to, }, }); }, - info: 'activate command', - label: '@ACTIVATE', + info: 'ground event command', + label: '@GROUND_EVENT', section: 'Ground Commands', type: 'function', }); @@ -445,13 +450,13 @@ function generateStepCompletion(cursor: CursorInfo): Completion[] { view.dispatch({ changes: { from: Math.max(0, from + (!cursor.isAfterTimeTag || cursor.isAtSymbolBefore ? -1 : 0)), - insert: `${!cursor.isAfterTimeTag ? 'C ' : ''}@LOAD("load.name")`, + insert: `${!cursor.isAfterTimeTag ? 'C ' : ''}@GROUND_BLOCK("ground_block.name")`, to, }, }); }, - info: 'load command', - label: '@LOAD', + info: 'ground block command', + label: '@GROUND_BLOCK', section: 'Ground Commands', type: 'function', }); From af4c51a1597f22c5b383d1ebbb10d36b09daee07 Mon Sep 17 00:00:00 2001 From: rrgoetz Date: Mon, 4 Nov 2024 08:52:10 -1000 Subject: [PATCH 3/7] Add linting for rtc load and activate --- .../sequence-editor/sequence-linter.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/utilities/sequence-editor/sequence-linter.ts b/src/utilities/sequence-editor/sequence-linter.ts index 2886e83b90..653e849fa4 100644 --- a/src/utilities/sequence-editor/sequence-linter.ts +++ b/src/utilities/sequence-editor/sequence-linter.ts @@ -129,7 +129,11 @@ export function sequenceLinter( if (commandsNode) { diagnostics.push( ...commandLinter( - commandsNode.getChildren(TOKEN_COMMAND), + [ + ...commandsNode.getChildren(TOKEN_COMMAND), + ...commandsNode.getChildren(TOKEN_LOAD), // TODO: remove in the library sequence PR because that check should validate load and activates + ...commandsNode.getChildren(TOKEN_ACTIVATE), // TODO: remove in the library sequence PR because that check should validate load and activates + ], docText, variableMap, commandDictionary, @@ -155,7 +159,11 @@ export function sequenceLinter( diagnostics.push( ...immediateCommandLinter( - treeNode.getChild('ImmediateCommands')?.getChildren(TOKEN_COMMAND) || [], + [ + ...(treeNode.getChild('ImmediateCommands')?.getChildren(TOKEN_COMMAND) || []), + ...(treeNode.getChild('ImmediateCommands')?.getChildren(TOKEN_LOAD) || []), + ...(treeNode.getChild('ImmediateCommands')?.getChildren(TOKEN_ACTIVATE) || []), + ], docText, variableMap, commandDictionary, @@ -693,6 +701,12 @@ function commandLinter( // Get the TimeTag node for the current command diagnostics.push(...validateTimeTags(command, text)); + // TODO: remove in the library sequence PR because that check should validate + // load and activates + if (command.name === TOKEN_ACTIVATE || command.name === TOKEN_LOAD) { + continue; + } + // Validate the command and push the generated diagnostics to the array diagnostics.push( ...validateCommand( From 21294a0e073c74703682f28604c9ee7a75911927 Mon Sep 17 00:00:00 2001 From: rrgoetz Date: Mon, 4 Nov 2024 08:52:45 -1000 Subject: [PATCH 4/7] export rtc load and activate and unit test --- .../sequence-editor/to-seq-json.test.ts | 43 +++++ src/utilities/sequence-editor/to-seq-json.ts | 152 +++++++++++++----- 2 files changed, 155 insertions(+), 40 deletions(-) diff --git a/src/utilities/sequence-editor/to-seq-json.test.ts b/src/utilities/sequence-editor/to-seq-json.test.ts index 6fa987bb36..2df852cd68 100644 --- a/src/utilities/sequence-editor/to-seq-json.test.ts +++ b/src/utilities/sequence-editor/to-seq-json.test.ts @@ -88,6 +88,49 @@ HDW_CMD`; expect(actual).toEqual(expectedJson); }); + it('immediate command', async () => { + const seq = `@IMMEDIATE +ECHO "hello" +# activate sequences +@LOAD("seqA") +@ACTIVATE("seqB") 10 #description`; + const id = 'test'; + const expectedJson = { + id: 'test', + immediate_commands: [ + { + args: [ + { + type: 'string', + value: 'hello', + }, + ], + stem: 'ECHO', + type: 'immediate_command', + }, + { + args: [], + sequence: 'seqA', + type: 'immediate_load', + }, + { + args: [ + { + type: 'number', + value: 10, + }, + ], + description: 'description', + sequence: 'seqB', + type: 'immediate_activate', + }, + ], + metadata: {}, + }; + const actual = JSON.parse(await sequenceToSeqJson(SeqLanguage.parser.parse(seq), seq, commandDictionary, id)); + expect(actual).toEqual(expectedJson); + }); + it('multiple hardware commands', async () => { const seq = `@HARDWARE HDW_CMD_1 diff --git a/src/utilities/sequence-editor/to-seq-json.ts b/src/utilities/sequence-editor/to-seq-json.ts index 0da3ef102a..d4b17e42f4 100644 --- a/src/utilities/sequence-editor/to-seq-json.ts +++ b/src/utilities/sequence-editor/to-seq-json.ts @@ -10,7 +10,9 @@ import type { GroundEvent, HardwareCommand, HexArgument, - ImmediateCommand, + ImmediateActivate, + ImmediateFswCommand, + ImmediateLoad, Load, Metadata, Model, @@ -24,7 +26,7 @@ import type { Time, VariableDeclaration, } from '@nasa-jpl/seq-json-schema/types'; -import { TOKEN_REPEAT_ARG } from '../../constants/seq-n-grammar-constants'; +import { TOKEN_ACTIVATE, TOKEN_COMMAND, TOKEN_LOAD, TOKEN_REPEAT_ARG } from '../../constants/seq-n-grammar-constants'; import { TimeTypes } from '../../enums/time'; import { removeEscapedQuotes, unquoteUnescape } from '../codemirror/codemirror-utils'; import { getBalancedDuration, getDurationTimeComponents, parseDurationString, validateTime } from '../time'; @@ -74,10 +76,8 @@ export async function sequenceToSeqJson( seqJson.steps = undefined; } seqJson.immediate_commands = - baseNode - .getChild('ImmediateCommands') - ?.getChildren('Command') - .map(command => parseImmediateCommand(command, text, commandDictionary)) ?? undefined; + parseImmediateCommand(baseNode.getChild('ImmediateCommands'), text, commandDictionary) ?? undefined; + seqJson.hardware_commands = baseNode .getChild('HardwareCommands') @@ -169,7 +169,13 @@ function parseGroundBlockEvent(stepNode: SyntaxNode, text: string): GroundBlock }; } -function parseActivateLoad(stepNode: SyntaxNode, text: string): Activate | Load { +function parseActivateLoad(stepNode: SyntaxNode, text: string): Activate | Load; +function parseActivateLoad(stepNode: SyntaxNode, text: string, isRTC: boolean): ImmediateActivate | ImmediateLoad; +function parseActivateLoad( + stepNode: SyntaxNode, + text: string, + isRTC?: boolean, +): Activate | Load | ImmediateActivate | ImmediateLoad { const time = parseTime(stepNode, text); const nameNode = stepNode.getChild('SequenceName'); @@ -186,17 +192,55 @@ function parseActivateLoad(stepNode: SyntaxNode, text: string): Activate | Load const metadata = parseMetadata(stepNode, text); const models = parseModel(stepNode, text); - return { - args, - description, - engine, - epoch, - metadata, - models, - sequence, - time, - type: stepNode.name === 'Load' ? 'load' : 'activate', - }; + if (stepNode.name === 'Activate') { + if (!isRTC) { + return { + args, + description, + engine, + epoch, + metadata, + models, + sequence, + time, + type: 'activate', + }; + } + return { + args, + description, + engine, + epoch, + metadata, + models, + sequence, + type: 'immediate_activate', + }; + } else { + if (!isRTC) { + return { + args, + description, + engine, + epoch, + metadata, + models, + sequence, + time, + type: 'load', + }; + } + return { + args, + description, + engine, + epoch, + metadata, + models, + sequence, + type: 'immediate_load', + }; + } } function parseEngine(stepNode: SyntaxNode, text: string): number | undefined { @@ -212,10 +256,10 @@ function parseEpoch(stepNode: SyntaxNode, text: string): string | undefined { function parseStep(child: SyntaxNode, text: string, commandDictionary: CommandDictionary | null): Step | null { switch (child.name) { case 'Command': - return parseCommand(child, text, commandDictionary); + return parseCommand(child, text, commandDictionary) as Command; case 'Activate': case 'Load': - return parseActivateLoad(child, text); + return parseActivateLoad(child, text) as Activate | Load; case 'GroundBlock': case 'GroundEvent': return parseGroundBlockEvent(child, text); @@ -638,7 +682,20 @@ function parseDescription(node: SyntaxNode, text: string): string | undefined { return removeEscapedQuotes(description); } -function parseCommand(commandNode: SyntaxNode, text: string, commandDictionary: CommandDictionary | null): Command { +function parseCommand(commandNode: SyntaxNode, text: string, commandDictionary: CommandDictionary | null): Command; +function parseCommand( + commandNode: SyntaxNode, + text: string, + commandDictionary: CommandDictionary | null, + isRTC: boolean, +): ImmediateFswCommand; + +function parseCommand( + commandNode: SyntaxNode, + text: string, + commandDictionary: CommandDictionary | null, + isRTC?: boolean, +): Command | ImmediateFswCommand { const time = parseTime(commandNode, text); const stemNode = commandNode.getChild('Stem'); @@ -651,37 +708,52 @@ function parseCommand(commandNode: SyntaxNode, text: string, commandDictionary: const metadata: Metadata | undefined = parseMetadata(commandNode, text); const models: Model[] | undefined = parseModel(commandNode, text); + if (!isRTC) { + return { + args, + description, + metadata, + models, + stem, + time, + type: 'command', + }; + } return { args, description, metadata, - models, stem, - time, - type: 'command', + type: 'immediate_command', }; } function parseImmediateCommand( - commandNode: SyntaxNode, + immediateCommandNode: SyntaxNode | null, text: string, commandDictionary: CommandDictionary | null, -): ImmediateCommand { - const stemNode = commandNode.getChild('Stem'); - const stem = stemNode ? text.slice(stemNode.from, stemNode.to) : 'UNKNOWN'; - - const argsNode = commandNode.getChild('Args'); - const args = argsNode ? parseArgs(argsNode, text, commandDictionary, stem) : []; - - const description = parseDescription(commandNode, text); - const metadata: Metadata | undefined = parseMetadata(commandNode, text); +): (ImmediateFswCommand | ImmediateLoad | ImmediateActivate)[] | undefined { + if (!immediateCommandNode) { + return undefined; + } - return { - args, - description, - metadata, - stem, - }; + const steps = [ + ...(immediateCommandNode.getChildren(TOKEN_COMMAND) || []), + ...(immediateCommandNode.getChildren(TOKEN_LOAD) || []), + ...(immediateCommandNode.getChildren(TOKEN_ACTIVATE) || []), + ]; + + return steps.map((step: SyntaxNode) => { + switch (step.name) { + case 'Command': + return parseCommand(step, text, commandDictionary, true); + case 'Load': + case 'Activate': + return parseActivateLoad(step, text, true); + default: + throw new Error(`Unexpected step type: ${step.name}`); + } + }); } function parseHardwareCommand(commandNode: SyntaxNode, text: string): HardwareCommand { From f25cbf17c5c2d00c8d6f748a6b6b0d678c6c6d38 Mon Sep 17 00:00:00 2001 From: rrgoetz Date: Wed, 6 Nov 2024 10:08:12 -1000 Subject: [PATCH 5/7] Import rtc load and activate from SeqJson * Support the new immediateActivate and immediateLoad objects in the SeqJson * Update the test --- .../sequence-editor/from-seq-json.test.ts | 25 +++++++++++ .../sequence-editor/from-seq-json.ts | 43 +++++++++++-------- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/utilities/sequence-editor/from-seq-json.test.ts b/src/utilities/sequence-editor/from-seq-json.test.ts index 9e83d1b548..68736f4fb8 100644 --- a/src/utilities/sequence-editor/from-seq-json.test.ts +++ b/src/utilities/sequence-editor/from-seq-json.test.ts @@ -461,16 +461,38 @@ C FSW_CMD_2 10 "ENUM" # fsw cmd 2 description description: 'immediate command', metadata: {}, stem: 'IC', + type: 'command', }, { args: [], stem: 'IC2', + type: 'command', }, { args: [], description: 'noop command, no arguments', metadata: { processor: 'VC1A' }, stem: 'NOOP', + type: 'command', + }, + { + args: [ + { + type: 'string', + value: 'hi', + }, + ], + description: 'description', + metadata: { + Key: 'Value', + }, + sequence: 'seqA', + type: 'load', + }, + { + description: 'description', + sequence: 'seqB', + type: 'activate', }, ], metadata: {}, @@ -484,6 +506,9 @@ IC "1" 2 3 # immediate command IC2 NOOP # noop command, no arguments @METADATA "processor" "VC1A" +@LOAD("seqA") "hi" # description +@METADATA "Key" "Value" +@ACTIVATE("seqB") # description `; expect(sequence).toEqual(expectedSequence); }); diff --git a/src/utilities/sequence-editor/from-seq-json.ts b/src/utilities/sequence-editor/from-seq-json.ts index 69fdbac0e0..160764e128 100644 --- a/src/utilities/sequence-editor/from-seq-json.ts +++ b/src/utilities/sequence-editor/from-seq-json.ts @@ -7,6 +7,9 @@ import type { GroundBlock, GroundEvent, HexArgument, + ImmediateActivate, + ImmediateFswCommand, + ImmediateLoad, Load, Metadata, Model, @@ -205,18 +208,22 @@ export async function seqJsonToSequence(input: string | null): Promise { if (seqJson.immediate_commands) { sequence.push(`\n`); sequence.push(`@IMMEDIATE\n`); - for (const icmd of seqJson.immediate_commands) { - const args = seqJsonArgsToSequence(icmd.args); - const description = icmd.description ? seqJsonDescriptionToSequence(icmd.description) : ''; - const metadata = icmd.metadata ? seqJsonMetadataToSequence(icmd.metadata) : ''; - let immediateString = `${icmd.stem}${args}${description}`; - // add a new line if on doesn't exit at the end of the immediateString - if (!immediateString.endsWith('\n')) { - immediateString += '\n'; + for (const rtc of seqJson.immediate_commands) { + switch (rtc.type) { + case 'command': { + // FSW Commands + sequence.push(commandToString(rtc)); + break; + } + case 'activate': + case 'load': { + sequence.push(loadOrActivateToString(rtc)); + break; + } + default: { + throw new Error(`Invalid immediate command type ${rtc.type}`); + } } - // Add metadata data if it exists - immediateString += metadata; - sequence.push(immediateString); } } @@ -250,14 +257,14 @@ export async function seqJsonToSequence(input: string | null): Promise { return sequence.join(''); } -function commandToString(step: Command) { - const time = seqJsonTimeToSequence(step.time); +function commandToString(step: Command | ImmediateFswCommand): string { + const time = 'time' in step ? `${seqJsonTimeToSequence(step.time)} ` : ''; const args = seqJsonArgsToSequence(step.args); const metadata = step.metadata ? seqJsonMetadataToSequence(step.metadata) : ''; - const models = step.models ? seqJsonModelsToSequence(step.models) : ''; + const models = 'models' in step ? (step.models ? seqJsonModelsToSequence(step.models) : '') : ''; const description = step.description ? seqJsonDescriptionToSequence(step.description) : ''; - let commandString = `${time} ${step.stem}${args}${description}`; + let commandString = `${time}${step.stem}${args}${description}`; // add a new line if on doesn't exit at the end of the commandString if (!commandString.endsWith('\n')) { commandString += '\n'; @@ -267,8 +274,8 @@ function commandToString(step: Command) { return commandString; } -function loadOrActivateToString(step: Activate | Load) { - const time = seqJsonTimeToSequence(step.time); +function loadOrActivateToString(step: Activate | Load | ImmediateActivate | ImmediateLoad) { + const time = 'time' in step ? `${seqJsonTimeToSequence(step.time)} ` : ''; const args = step.args ? seqJsonArgsToSequence(step.args) : ''; const metadata = step.metadata ? seqJsonMetadataToSequence(step.metadata) : ''; const models = step.models ? seqJsonModelsToSequence(step.models) : ''; @@ -276,7 +283,7 @@ function loadOrActivateToString(step: Activate | Load) { const epoch = step.epoch !== undefined ? `@EPOCH ${quoteEscape(step.epoch)}\n` : ''; const description = step.description ? seqJsonDescriptionToSequence(step.description) : ''; const stepType = `@${step.type === 'activate' ? 'ACTIVATE' : 'LOAD'}(${quoteEscape(step.sequence)})`; - let stepString = `${time} ${stepType}${args}${description}`; + let stepString = `${time}${stepType}${args}${description}`; if (!stepString.endsWith('\n')) { stepString += '\n'; } From 7b055eaef7cc4df03d7a9b8dfca40f3745b8e8cf Mon Sep 17 00:00:00 2001 From: rrgoetz Date: Wed, 6 Nov 2024 10:08:28 -1000 Subject: [PATCH 6/7] Update the json schema npm package --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index f17376c5e7..7db91b54af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@fontsource/jetbrains-mono": "^5.0.19", "@nasa-jpl/aerie-ampcs": "^1.0.5", - "@nasa-jpl/seq-json-schema": "^1.0.20", + "@nasa-jpl/seq-json-schema": "^1.2.0", "@nasa-jpl/stellar": "^1.1.18", "@streamparser/json": "^0.0.17", "@sveltejs/adapter-node": "5.0.1", @@ -1124,9 +1124,9 @@ } }, "node_modules/@nasa-jpl/seq-json-schema": { - "version": "1.0.20", - "resolved": "https://registry.npmjs.org/@nasa-jpl/seq-json-schema/-/seq-json-schema-1.0.20.tgz", - "integrity": "sha512-fEIxZ7xlV8y+ybCN5yd2bhgEXLx4gbysa5W6KfXSBq9hY2gpYlYJ1PTNr0JA+N7KRK36Wh1lQnFtYpHfI/Owxw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@nasa-jpl/seq-json-schema/-/seq-json-schema-1.2.0.tgz", + "integrity": "sha512-C1t2i7EJM1dyxLCMeDcwff+0jbW98mFo3mfC3YUhDvAc15HjQG2bJf1fVCsPZMuqsHxEHVi5WmvFScTUqgcJmQ==" }, "node_modules/@nasa-jpl/stellar": { "version": "1.1.18", diff --git a/package.json b/package.json index eb67b7dd6d..1f4a8e49b7 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "dependencies": { "@fontsource/jetbrains-mono": "^5.0.19", "@nasa-jpl/aerie-ampcs": "^1.0.5", - "@nasa-jpl/seq-json-schema": "^1.0.20", + "@nasa-jpl/seq-json-schema": "^1.2.0", "@nasa-jpl/stellar": "^1.1.18", "@streamparser/json": "^0.0.17", "@sveltejs/adapter-node": "5.0.1", From 460393272bca04b1ae3e8ae7f10ce526c7ef8b8b Mon Sep 17 00:00:00 2001 From: rrgoetz Date: Tue, 19 Nov 2024 10:02:46 -1000 Subject: [PATCH 7/7] Address Bryan PR reviews --- .../sequence-editor/from-seq-json.test.ts | 10 ++--- .../sequence-editor/from-seq-json.ts | 45 ++++++++++++++----- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/utilities/sequence-editor/from-seq-json.test.ts b/src/utilities/sequence-editor/from-seq-json.test.ts index 68736f4fb8..7f070554cd 100644 --- a/src/utilities/sequence-editor/from-seq-json.test.ts +++ b/src/utilities/sequence-editor/from-seq-json.test.ts @@ -461,19 +461,19 @@ C FSW_CMD_2 10 "ENUM" # fsw cmd 2 description description: 'immediate command', metadata: {}, stem: 'IC', - type: 'command', + type: 'immediate_command', }, { args: [], stem: 'IC2', - type: 'command', + type: 'immediate_command', }, { args: [], description: 'noop command, no arguments', metadata: { processor: 'VC1A' }, stem: 'NOOP', - type: 'command', + type: 'immediate_command', }, { args: [ @@ -487,12 +487,12 @@ C FSW_CMD_2 10 "ENUM" # fsw cmd 2 description Key: 'Value', }, sequence: 'seqA', - type: 'load', + type: 'immediate_load', }, { description: 'description', sequence: 'seqB', - type: 'activate', + type: 'immediate_activate', }, ], metadata: {}, diff --git a/src/utilities/sequence-editor/from-seq-json.ts b/src/utilities/sequence-editor/from-seq-json.ts index 160764e128..aa0540cff8 100644 --- a/src/utilities/sequence-editor/from-seq-json.ts +++ b/src/utilities/sequence-editor/from-seq-json.ts @@ -208,20 +208,20 @@ export async function seqJsonToSequence(input: string | null): Promise { if (seqJson.immediate_commands) { sequence.push(`\n`); sequence.push(`@IMMEDIATE\n`); - for (const rtc of seqJson.immediate_commands) { - switch (rtc.type) { - case 'command': { + for (const realTimeCommand of seqJson.immediate_commands) { + switch (realTimeCommand.type) { + case 'immediate_command': { // FSW Commands - sequence.push(commandToString(rtc)); + sequence.push(commandToString(realTimeCommand)); break; } - case 'activate': - case 'load': { - sequence.push(loadOrActivateToString(rtc)); + case 'immediate_activate': + case 'immediate_load': { + sequence.push(loadOrActivateToString(realTimeCommand)); break; } default: { - throw new Error(`Invalid immediate command type ${rtc.type}`); + throw new Error(`Invalid immediate command type ${realTimeCommand.type}`); } } } @@ -257,13 +257,23 @@ export async function seqJsonToSequence(input: string | null): Promise { return sequence.join(''); } +function isCommand(step: Command | ImmediateFswCommand): step is Command { + return (step as Command).time !== undefined; +} + function commandToString(step: Command | ImmediateFswCommand): string { - const time = 'time' in step ? `${seqJsonTimeToSequence(step.time)} ` : ''; const args = seqJsonArgsToSequence(step.args); const metadata = step.metadata ? seqJsonMetadataToSequence(step.metadata) : ''; - const models = 'models' in step ? (step.models ? seqJsonModelsToSequence(step.models) : '') : ''; const description = step.description ? seqJsonDescriptionToSequence(step.description) : ''; + // used for commands, ImmediateFswCommand doesn't support 'time' and 'models' + let time = ''; + let models = ''; + if (isCommand(step)) { + time = step.time ? `${seqJsonTimeToSequence(step.time)} ` : ''; + models = step.models ? (step.models ? seqJsonModelsToSequence(step.models) : '') : ''; + } + let commandString = `${time}${step.stem}${args}${description}`; // add a new line if on doesn't exit at the end of the commandString if (!commandString.endsWith('\n')) { @@ -275,14 +285,25 @@ function commandToString(step: Command | ImmediateFswCommand): string { } function loadOrActivateToString(step: Activate | Load | ImmediateActivate | ImmediateLoad) { - const time = 'time' in step ? `${seqJsonTimeToSequence(step.time)} ` : ''; + const time = (step as Activate | Load).time ? `${seqJsonTimeToSequence((step as Activate | Load).time)} ` : ''; const args = step.args ? seqJsonArgsToSequence(step.args) : ''; const metadata = step.metadata ? seqJsonMetadataToSequence(step.metadata) : ''; const models = step.models ? seqJsonModelsToSequence(step.models) : ''; const engine = step.engine !== undefined ? `@ENGINE ${step.engine.toString(10)}\n` : ''; const epoch = step.epoch !== undefined ? `@EPOCH ${quoteEscape(step.epoch)}\n` : ''; const description = step.description ? seqJsonDescriptionToSequence(step.description) : ''; - const stepType = `@${step.type === 'activate' ? 'ACTIVATE' : 'LOAD'}(${quoteEscape(step.sequence)})`; + let stepType = ''; + switch (step.type) { + case 'activate': + case 'immediate_activate': + stepType = '@ACTIVATE'; + break; + case 'load': + case 'immediate_load': + stepType = '@LOAD'; + break; + } + stepType += `(${quoteEscape(step.sequence)})`; let stepString = `${time}${stepType}${args}${description}`; if (!stepString.endsWith('\n')) { stepString += '\n';