UNPKG

@yantrix/codegen

Version:

Yantrix framework code generator API

1 lines 177 kB
{"version":3,"sources":["../src/index.ts","../src/core/InjectFunctionsProcess.ts","../src/core/modules/Java.ts","../src/core/shared.ts","../src/constants.ts","../src/core/modules/JavaScript/codegen.ts","../src/core/modules/JavaScript/JavaScriptCompiler/class/serializer.ts","../src/core/templates/JavaScript.ts","../src/utils/utils.ts","../src/core/modules/JavaScript/JavaScriptCompiler/context/core.ts","../src/core/modules/JavaScript/JavaScriptCompiler/context/serializer.ts","../src/core/modules/JavaScript/JavaScriptCompiler/expressions/core.ts","../src/core/modules/JavaScript/JavaScriptCompiler/expressions/functions.ts","../src/core/modules/JavaScript/JavaScriptCompiler/expressions/serializer.ts","../src/core/modules/JavaScript/JavaScriptCompiler/expressions/index.ts","../src/core/modules/JavaScript/JavaScriptCompiler/context/index.ts","../src/core/modules/JavaScript/JavaScriptCompiler/state/core.ts","../src/core/modules/JavaScript/JavaScriptCompiler/state/index.ts","../src/core/modules/JavaScript/JavaScriptCompiler/class/index.ts","../src/core/modules/JavaScript/JavaScriptCompiler/functions/core.ts","../src/core/modules/JavaScript/JavaScriptCompiler/functions/index.ts","../src/core/modules/JavaScript/JavaScriptCompiler/imports/core.ts","../src/core/modules/JavaScript/JavaScriptCompiler/imports/serializer.ts","../src/core/modules/JavaScript/JavaScriptCompiler/imports/index.ts","../src/core/modules/JavaScript/JavaScriptCompiler/dictionaries/core.ts","../src/core/modules/JavaScript/JavaScriptCompiler/dictionaries/serializer.ts","../src/core/modules/JavaScript/JavaScriptCompiler/dictionaries/index.ts","../src/core/modules/JavaScript/JavaScriptCompiler/events/functions.ts","../src/core/modules/JavaScript/JavaScriptCompiler/events/core.ts","../src/core/modules/JavaScript/JavaScriptCompiler/events/serializer.ts","../src/core/modules/JavaScript/JavaScriptCompiler/events/index.ts","../src/core/modules/JavaScript/JavaScriptCompiler/forks/core.ts","../src/core/modules/JavaScript/JavaScriptCompiler/forks/serializer.ts","../src/core/modules/JavaScript/JavaScriptCompiler/forks/index.ts","../src/core/modules/JavaScript/JavaScriptCompiler/index.ts","../src/core/modules/Python.ts","../src/core/templates/Python.ts","../src/core/modules/TypeScript/TypescriptCompiler/class/serializer.ts","../src/core/modules/TypeScript/TypescriptCompiler/class/index.ts","../src/core/modules/TypeScript/TypescriptCompiler/index.ts","../src/core/modules/TypeScript/codegen.ts","../src/core/modules/index.ts","../src/core/Codegen.ts","../src/types/common.ts"],"sourcesContent":["/**\n * @packageDocumentation\n *\n * The `@yantrix/codegen` package is a code generation engine for the Yantrix framework,\n * designed to transform extended Mermaid state diagrams into type-safe finite state machine implementations.\n *\n * You can check the supported languages and features [here](/integrations/100_language_support.html).\n *\n */\n\nimport { TStateDiagramMatrix } from '@yantrix/mermaid-parser';\nimport { YantrixParser } from '@yantrix/yantrix-parser';\nimport { CodegenCreator } from './core/Codegen.js';\nimport { ModuleNames } from './core/modules/index.js';\nimport { IGenerateOptions, TStateIncludingNotes } from './types/common.js';\n\nexport * from './core/modules/index.js';\nexport * from './types/common.js';\n\n/**\n * Main function that's used to asynchronously generate Yantrix FSMs.\n * @param diagram - The state diagram, processed by Mermaid & Yantrix Parsers (`mermaid-parser`, `yantrix-parser`)\n * @param options - Options for configuring the generation process, such as the output language and automata class name\n * @returns - A promise with the code of generated FSM as string\n */\nexport async function generateAutomataFromStateDiagram(diagram: TStateDiagramMatrix, options: IGenerateOptions): Promise<string> {\n\tconst { states, transitions, actionChains } = diagram;\n\tconst parserInstance = new YantrixParser();\n\n\tconst statesIncludingNotes = states.map((state) => {\n\t\tconst input = state.notes.flatMap(e => e.join('\\n')).join(' ');\n\t\tif (input === '')\n\t\t\treturn { ...state, notes: null };\n\t\treturn { ...state, notes: parserInstance.parse(input) } as TStateIncludingNotes;\n\t});\n\n\tlet constants: Record<string, any> | null = null;\n\n\tif (options?.constants) {\n\t\tconstants = JSON.parse(options.constants);\n\t}\n\n\tif (constants !== null) {\n\t\tObject.entries(constants).forEach(([key, value]) => {\n\t\t\tif (typeof value !== 'string' && typeof value !== 'number') {\n\t\t\t\tthrow new TypeError(`Invalid constant value type. Key: ${key}, value: ${JSON.stringify(value)}`);\n\t\t\t}\n\t\t});\n\t}\n\n\tconst creator = new CodegenCreator(\n\t\t{\n\t\t\tstates: statesIncludingNotes,\n\t\t\ttransitions,\n\t\t\tactionChains,\n\t\t},\n\t);\n\n\tconst codegen = await creator.createCodegen({\n\t\tlanguage: options.outLang ?? ModuleNames.TypeScript,\n\t\tconstants,\n\t\tfunctionFilePath: options.functionFilePath ?? null,\n\t});\n\n\treturn codegen.getCode(options);\n}\n","import path from 'node:path';\nimport { TNullable } from '@yantrix/utils';\nimport { TOutLang, TUserFunctionsDict } from '../types/common';\nimport { ModuleNames } from './modules';\n\nconst processFileTS = async (filePath: TNullable<string>): Promise<TUserFunctionsDict> => {\n\tif (!filePath) {\n\t\treturn {\n\t\t\tpath: null,\n\t\t};\n\t}\n\tconst fileExtension = path.extname(filePath);\n\n\tif (!['.js', '.ts'].includes(fileExtension)) {\n\t\tthrow new Error('Only .js or .ts files are supported');\n\t}\n\n\treturn {\n\t\tpath: filePath,\n\t};\n};\n\nconst processFileDict: Record<TOutLang, (filePath: TNullable<string>) => Promise<TUserFunctionsDict>> = {\n\t[ModuleNames.JavaScript]: processFileTS,\n\t[ModuleNames.TypeScript]: processFileTS,\n\t[ModuleNames.Python]: () => { throw new TypeError('Python is not supported yet inject functions'); },\n\t[ModuleNames.Java]: () => { throw new TypeError('Java is not supported yet inject functions'); },\n\n} as const;\n\nexport const processFile = (language: TOutLang) => {\n\tif (processFileDict[language]) {\n\t\treturn processFileDict[language];\n\t}\n\tthrow new TypeError(`Language ${language} is not supported`);\n};\n","import { BasicActionDictionary, BasicStateDictionary } from '@yantrix/automata';\nimport { StartState, TDiagramAction } from '@yantrix/mermaid-parser';\n\nimport { ICodegen, TGetCodeOptionsMap, TModuleParams, TStateDiagramMatrixIncludeNotes } from '../../types/common.js';\nimport { fillDictionaries } from '../shared.js';\nimport { ModuleNames } from './index';\n\nexport class JavaCodegen implements ICodegen<typeof ModuleNames.Java> {\n\tstateDictionary: BasicStateDictionary;\n\tactionDictionary: BasicActionDictionary;\n\tdiagram: TStateDiagramMatrixIncludeNotes;\n\thandlersDict: string[];\n\tinitialContext: string;\n\tinitialContextKeys: string[];\n\tchangeStateHandlers: string[];\n\tdictionaries: string[];\n\tprotected imports = {\n\t\t'@yantrix/automata': ['GenericAutomata'],\n\t};\n\n\tprivate package: string = 'org.example'; // base package name for all automata files\n\n\tconstructor({ diagram }: TModuleParams) {\n\t\tthis.actionDictionary = new BasicActionDictionary();\n\t\tthis.stateDictionary = new BasicStateDictionary();\n\t\tthis.diagram = diagram;\n\n\t\tthis.handlersDict = [];\n\t\tthis.changeStateHandlers = [];\n\t\tthis.dictionaries = [];\n\t\tthis.initialContextKeys = [];\n\n\t\tthis.initialContext = this.getInitialContext();\n\n\t\tfillDictionaries(diagram, this.stateDictionary, this.actionDictionary);\n\t\tthis.setupDictionaries();\n\t}\n\n\tpublic getCode(options: TGetCodeOptionsMap[typeof ModuleNames.Java]): string {\n\t\treturn `\n\t\t\t${this.getImports()}\n\t\t\t${this.getClassTemplate(options.className)}\n\t\t`;\n\t}\n\n\t// Package declaration and imports necessary for the automata to function\n\tgetImports(): string {\n\t\tconst lines: string[] = [\n\t\t\t`package ${this.package};`,\n\t\t\t`import java.util.Map;`,\n\t\t\t`import java.util.Objects;`,\n\t\t\t`import java.util.HashMap;`,\n\t\t\t`import java.util.function.Function;`,\n\t\t];\n\t\treturn lines.join('\\n');\n\t}\n\n\tgetDictionaries(): string {\n\t\treturn this.dictionaries.join('\\n');\n\t}\n\n\tpublic getActionToStateFromState(): string {\n\t\treturn `public final Map<TAutomataBaseState, Map<TAutomataBaseAction, AutomataStateTransitionResult>> stateTransitionMatrix =\n\t\t\tMap.ofEntries(\n\t\t\t\t${this.getStateTransitionMatrix()}\n\t\t\t);\n\t\t`;\n\t}\n\n\t// State transition matrix\n\tgetStateTransitionMatrix(): string {\n\t\treturn Object\n\t\t\t.entries(this.diagram.transitions)\n\t\t\t.map(([state, transitions]) => {\n\t\t\t\tconst value = this.stateDictionary.getStateValues({ keys: [state] })[0];\n\t\t\t\tif (!value)\n\t\t\t\t\tthrow new Error(`State ${state} not found`);\n\n\t\t\t\treturn `\n\t\t\t\tMap.entry(\n\t\t\t\t\tTAutomataBaseState.of(${value}L),\n\t\t\t\t\tMap.of(\n\t\t\t\t\t\t${this.getTransitions(transitions).join(',\\n')}\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t`;\n\t\t\t})\n\t\t\t.join(',\\n');\n\t}\n\n\tgetTransitions(transitions: Record<string, TDiagramAction>): string[] {\n\t\treturn Object\n\t\t\t.entries(transitions)\n\t\t\t.map(([state, transition]) => {\n\t\t\t\tconst newState = this.stateDictionary.getStateValues({ keys: [state] })[0];\n\t\t\t\treturn transition.actionsPath.map(({ action }) => {\n\t\t\t\t\tconst actionValue = this.actionDictionary.getActionValues({\n\t\t\t\t\t\tkeys: action,\n\t\t\t\t\t})[0];\n\t\t\t\t\tif (!actionValue)\n\t\t\t\t\t\tthrow new Error(`Action ${action} not found`);\n\t\t\t\t\tif (!newState)\n\t\t\t\t\t\tthrow new Error(`State ${state} not found`);\n\n\t\t\t\t\t// const ctx = this.getSubsyntaxContext(key);\n\n\t\t\t\t\treturn `\n\t\t\t\t\t\tTAutomataBaseAction.of(${actionValue}L),\n\t\t\t\t\t\tnew AutomataStateTransitionResult(\n\t\t\t\t\t\t\t\tTAutomataBaseState.of(${newState}L),\n\t\t\t\t\t\t\t\t(payloadContext) -> {\n\t\t\t\t\t\t\t\t\tvar prevContext = getDefaultContext(payloadContext);\n\t\t\t\t\t\t\t\t\treturn prevContext;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t)\n\t\t\t\t\t`;\n\t\t\t\t});\n\t\t\t})\n\t\t\t.flatMap(el => `${el.join(',\\n\\t')}`);\n\t}\n\n\tgetDefaultContext(): string {\n\t\treturn `\n private TAutomataBaseContext getDefaultContext(AutomataPayloadContext arg) {\n TAutomataBaseContext prevContext = arg.context();\n return prevContext;\n }\n `;\n\t}\n\n\t// Full class declaration with all dictionaries and handlers inside\n\tgetClassTemplate(className: string): string {\n\t\treturn `\n public final class ${className} {\n ${this.getDictionaries()}\n\t\t\t\t${this.getActionToStateFromState()}\n ${this.setupClassMembers()}\n ${this.getDefaultConstructor(className)}\n ${this.setupClassMembersAccessors()}\n\t\t\t\t${this.getDefaultContext()}\n ${this.dispatchMethod()}\n ${this.toStringMethod()}\n ${this.getTypes()}\n }\n `;\n\t}\n\n\t// Default constructor for the class\n\tprivate getDefaultConstructor(className: string): string {\n\t\treturn `\n public ${className}() {\n this.state = TAutomataBaseState.of(${this.getInitialState()}L);\n this.context = ${this.getInitialContext()};\n this.rootReducer = ${this.getRootReducer()};\n }\n `;\n\t}\n\n\t// Transforms codegen dictionaries into language-specific text representations\n\tprivate setupDictionaries(): void {\n\t\t// states dictionary text representation\n\t\tthis.dictionaries.push(`\n\t\tpublic static final Map<String, TAutomataBaseState> statesDictionary = Map.of(\n\t\t${Object\n\t\t\t.entries(this.stateDictionary.getDictionary())\n\t\t\t.map(([key, value]) => `\"${key}\", TAutomataBaseState.of(${value}L)`)\n\t\t\t.join(',\\n')}\n\t\t);\n\t\t`);\n\n\t\t// actions dictionary text representation\n\t\tthis.dictionaries.push(`\n\t\tpublic static final Map<String, TAutomataBaseAction> actionsDictionary = Map.of(\n\t\t${Object\n\t\t\t.entries(this.actionDictionary.getDictionary())\n\t\t\t.map(([key, value]) => `\"${key}\", TAutomataBaseAction.of(${value}L)`)\n\t\t\t.join(',\\n')}\n\t\t);\n\t\t`);\n\t}\n\n\t// Initial context is empty\n\tprivate getInitialContext(): string {\n\t\treturn 'new TAutomataBaseContext()';\n\t}\n\n\t// Fetches first state from list\n\tprivate getInitialState(): number | null | undefined {\n\t\treturn this.stateDictionary.getStateValues({ keys: [StartState] })[0];\n\t}\n\n\t// Root reducer function\n\tprivate getRootReducer(): string {\n\t\treturn `\n (obj) -> {\n if(obj.action == null || obj.payload == null) {\n return TAutomataStateContext.of(obj.state, obj.context);\n }\n\t\t\t\t${this.getRootReducerStateValidation()}\n\t\t\t\t${this.getRootReducerActionValidation()}\n AutomataStateTransitionResult res = stateTransitionMatrix.get(obj.state).get(obj.action);\n\t\t\t\treturn TAutomataStateContext.of(\n\t\t\t\t\t\tres.newState(),\n\t\t\t\t\t\tres.getNewContext().apply(new AutomataPayloadContext(obj.payload, obj.context))\n\t\t\t\t);\n }\n `;\n\t}\n\n\t// Checks if state can be found in dictionary for the automata\n\tprivate getRootReducerStateValidation(): string {\n\t\treturn `\n // state validation\n if(!stateTransitionMatrix.containsKey(obj.state)) {\n throw new RuntimeException(\"Invalid state, maybe machine isn't running\");\n }\n `;\n\t}\n\n\t// Checks if action can be found in dictionary for the automata & if the action is appropriate for the automata state\n\tprivate getRootReducerActionValidation(): string {\n\t\treturn `\n // action validation\n if(!stateTransitionMatrix.get(obj.state).containsKey(obj.action)) {\n return TAutomataStateContext.of(\n obj.state,\n obj.context\n );\n }\n `;\n\t}\n\n\tprivate setupClassMembers(): string {\n\t\treturn `\n private TAutomataBaseState state;\n private TAutomataBaseContext context;\n private IAutomataReducer rootReducer;\n `;\n\t}\n\n\tprivate setupClassMembersAccessors(): string {\n\t\treturn `\n public Map getStateTransitionMatrix() { return this.stateTransitionMatrix; }\n public TAutomataStateContext getContext() { return new TAutomataStateContext(this.state, this.context); }\n public IAutomataReducer getReducer() { return this.rootReducer; }\n\n public void setContext(TAutomataStateContext context) {\n this.state = context.state;\n this.context = context.context;\n }\n `;\n\t}\n\n\tprivate dispatchMethod(): string {\n\t\treturn `\n public TAutomataStateContext dispatch(TAutomataActionPayload action) {\n TAutomataStateContext reducedValue =\n this.rootReducer.apply(new TAutomataStateContextActionPayload(this.state, this.context, action.action, action.payload));\n this.setContext(reducedValue);\n return reducedValue;\n }\n `;\n\t}\n\n\tprivate toStringMethod(): string {\n\t\treturn `\n @Override\n public String toString() {\n return \"GeneratedAutomata{\" +\n \"statesDictionary=\" + statesDictionary +\n \", actionsDictionary=\" + actionsDictionary +\n \", stateTransitionMatrix=\" + stateTransitionMatrix +\n '}';\n }\n `;\n\t}\n\n\t// Types necessary for the automata\n\tprivate getTypes(): string {\n\t\treturn `\n public abstract static class TAutomataBaseType {\n protected Long value;\n public Long getValue() { return value; }\n\n @Override\n public boolean equals(Object o) {\n if (this == o) return true;\n if (o == null || getClass() != o.getClass()) return false;\n TAutomataBaseType that = (TAutomataBaseType) o;\n return Objects.equals(value, that.value);\n }\n\n @Override\n public int hashCode() {\n return Objects.hash(value);\n }\n }\n\n public static class TAutomataBaseState extends TAutomataBaseType {\n\n private TAutomataBaseState() {}\n private TAutomataBaseState(Long value) { this.value = value; }\n\n public static TAutomataBaseState of(Long value) { return new TAutomataBaseState(value); }\n\n }\n\n public static class TAutomataBaseAction extends TAutomataBaseType {\n\n private TAutomataBaseAction() {}\n private TAutomataBaseAction(Long value) { this.value = value; }\n\n public static TAutomataBaseAction of(Long value) { return new TAutomataBaseAction(value); }\n\n }\n\n public static class TAutomataBaseContext extends HashMap<String, Object> {\n public TAutomataBaseContext(Map<String, Object> map) { super(map); }\n\n private TAutomataBaseContext(TAutomataBasePayload payload) {\n super();\n this.putAll(payload);\n }\n\n public static TAutomataBaseContext fromPayload(TAutomataBasePayload payload) {\n return new TAutomataBaseContext(payload);\n }\n }\n\n public static class TAutomataBasePayload extends HashMap<String, Object> {\n }\n\n public record AutomataStateTransitionResult (\n TAutomataBaseState newState,\n Function<AutomataPayloadContext, TAutomataBaseContext> getNewContext\n ) {\n }\n\n public interface IAutomataReducer extends Function<TAutomataStateContextActionPayload, TAutomataStateContext> {}\n\n public record TAutomataStateContext(TAutomataBaseState state, TAutomataBaseContext context) {}\n public record TAutomataStateContextActionPayload(TAutomataBaseState state, TAutomataBaseContext context, TAutomataBaseAction action, TAutomataBasePayload payload) {}\n public record AutomataPayloadContext(TAutomataBasePayload payload,TAutomataBaseContext context) {}\n public record TAutomataActionPayload(TAutomataBaseAction action, TAutomataBasePayload payload) {}\n `;\n\t}\n}\n","import { BasicActionDictionary, BasicEventDictionary, BasicStateDictionary } from '@yantrix/automata';\nimport { ExpressionTypes, TRefereneceType } from '@yantrix/yantrix-parser';\n\nimport { ByPassAction } from '../constants.js';\nimport { TStateDiagramMatrixIncludeNotes } from '../types/common.js';\n\nexport function fillDictionaries(\n\tdiagram: TStateDiagramMatrixIncludeNotes,\n\tstateDictionary?: BasicStateDictionary,\n\tactionDictionary?: BasicActionDictionary,\n\teventDictionary?: BasicEventDictionary,\n): void {\n\t// fill state dictionary\n\tif (stateDictionary) {\n\t\tconst stateKeys = diagram.states.map(s => s.id);\n\t\tstateDictionary.addStates({ keys: stateKeys });\n\t}\n\n\t// fill action dictionary\n\tif (actionDictionary) {\n\t\tfor (const state of diagram.states) {\n\t\t\tfor (const path of state.actionsPath.map(p => p.action)) {\n\t\t\t\tconst firstAction = path[0]!;\n\t\t\t\tconst isUniqueAction = actionDictionary.getActionValues({ keys: [firstAction] })[0] === null;\n\t\t\t\tif (!isUniqueAction) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tactionDictionary.addActions({ keys: [firstAction] });\n\t\t\t}\n\t\t}\n\t}\n\n\t// fill event dictionary\n\tif (eventDictionary) {\n\t\tfor (const state of diagram.states) {\n\t\t\tconst emittedEventsKeys = state.notes?.emit.map(event => event.identifier);\n\t\t\tif (emittedEventsKeys && emittedEventsKeys.length > 0) {\n\t\t\t\tconst uniqueKeys = emittedEventsKeys.filter(e => eventDictionary.getEventValues({ keys: [e] })[0] == null);\n\t\t\t\teventDictionary.addEvents({ keys: uniqueKeys });\n\t\t\t}\n\n\t\t\tconst subscribedEventsKeys = state.notes?.subscribe.map(event => event.identifier);\n\t\t\tif (subscribedEventsKeys && subscribedEventsKeys.length > 0) {\n\t\t\t\tconst uniqueKeys = subscribedEventsKeys.filter(e => eventDictionary.getEventValues({ keys: [e] })[0] == null);\n\t\t\t\teventDictionary.addEvents({ keys: uniqueKeys });\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * @description\n * Finds all states with \"byPass\" note and returns array of their IDs.\n * \"byPass\" note should have one transition to the next state.\n * If there are more than one transition then error is thrown.\n * If there is no transition then error is thrown.\n * If state is not found in the dictionary then error is thrown.\n * @param {TStateDiagramMatrixIncludeNotes} diagram\n * @param {BasicStateDictionary} stateDictionary\n * @returns {number[]}\n */\nexport function getStatesByPass(diagram: TStateDiagramMatrixIncludeNotes, stateDictionary: BasicStateDictionary) {\n\tconst byPassed: number[] = [];\n\n\tdiagram.states.forEach((state) => {\n\t\tif (state.notes?.byPass) {\n\t\t\tconst actionChains = diagram.actionChains[state.id];\n\n\t\t\tif (!actionChains) throw new Error(`ByPassed state ${state.id} doesn\\'t have transition`);\n\t\t\tconst byPassAction = actionChains[ByPassAction];\n\n\t\t\tif (!byPassAction) {\n\t\t\t\tthrow new Error(`ByPass action ${ByPassAction} not found for state ${state.id}`);\n\t\t\t}\n\n\t\t\tbyPassAction.chains.forEach(({ chain }) => {\n\t\t\t\tif (byPassAction.chains.length > 1 && chain.length === 0) {\n\t\t\t\t\tthrow new Error(`ByPass action ${ByPassAction} should have more than one transition`);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tconst value = stateDictionary.getStateValues({ keys: [state.id] })[0];\n\t\t\tif (!value) throw new Error(`State ${state.id} not found`);\n\n\t\t\tbyPassed.push(value);\n\t\t}\n\t});\n\n\treturn byPassed;\n}\n\nexport const pathRecord: Record<TRefereneceType, string> = {\n\t[ExpressionTypes.Constant]: 'constant',\n\t[ExpressionTypes.Context]: 'prevContext',\n\t[ExpressionTypes.Payload]: 'payload',\n};\n","export const ByPassAction = '[-]';\nexport const DEFAULT_USER_FUNCTIONS_NAMESPACE = 'userFunctions';\n","import { BasicActionDictionary, BasicEventDictionary, BasicStateDictionary } from '@yantrix/automata';\nimport { TNullable } from '@yantrix/utils';\nimport { TDefine, TInjectIdent } from '@yantrix/yantrix-parser';\nimport { DEFAULT_USER_FUNCTIONS_NAMESPACE } from '../../../constants';\nimport {\n\tICodegen,\n\tTConstants,\n\tTExpressionRecord,\n\tTGetCodeOptionsMap,\n\tTModuleParams,\n\tTStateDiagramMatrixIncludeNotes,\n} from '../../../types/common';\nimport { fillDictionaries, getStatesByPass } from '../../shared';\nimport { ModuleNames } from '../index';\nimport { JavaScriptCompiler } from './JavaScriptCompiler';\nimport { TImports } from './JavaScriptCompiler/imports';\n\nexport class JavaScriptCodegen implements ICodegen<typeof ModuleNames.JavaScript> {\n\tstateDictionary: BasicStateDictionary;\n\tactionDictionary: BasicActionDictionary;\n\teventDictionary: BasicEventDictionary;\n\tdiagram: TStateDiagramMatrixIncludeNotes;\n\thandlersDict: string[];\n\n\tdefines: TDefine[];\n\tinjects: TInjectIdent[];\n\n\tinitialContextKeys: string[];\n\tchangeStateHandlers: string[];\n\tdependencyGraph: Map<string, Set<string>>;\n\tconstants: TConstants | null;\n\texpressions: TExpressionRecord;\n\tinjectedPath: TNullable<string> = null;\n\n\tdictionaries: string[];\n\tprotected importNamespaces: TNullable<TImports> = {};\n\tprotected imports: TImports = {\n\t\t'@yantrix/core': [\n\t\t\t'GenericAutomata',\n\t\t\t'FunctionDictionary',\n\t\t\t'EventDictionary as GlobalEventDictionary',\n\t\t\t'AutomataEventAdapter',\n\t\t\t'BasicEventBus',\n\t\t\t'builtInFunctions',\n\t\t\t'internalFunctions',\n\t\t],\n\t};\n\n\tconstructor({ diagram, constants, injectedFunctions }: TModuleParams) {\n\t\tthis.stateDictionary = new BasicStateDictionary();\n\t\tthis.actionDictionary = new BasicActionDictionary();\n\t\tthis.eventDictionary = new BasicEventDictionary();\n\n\t\tthis.diagram = diagram;\n\n\t\tthis.constants = constants;\n\n\t\tthis.defines = diagram.states.flatMap(state => state.notes?.defines ?? []);\n\t\tthis.injects = diagram.states.flatMap(state => state.notes?.inject ?? []);\n\n\t\tthis.expressions = JavaScriptCompiler.expressions.functions.setupExpressions({\n\t\t\tconstants: this.constants,\n\t\t});\n\n\t\tconst buildDependencyGraphResult = JavaScriptCompiler.imports.functions.buildDependencyGraph({\n\t\t\tdependencyGraph: new Map(),\n\t\t\tdiagram: this.diagram,\n\t\t\timports: this.imports,\n\t\t});\n\t\tthis.imports = buildDependencyGraphResult.imports;\n\n\t\tthis.dependencyGraph = buildDependencyGraphResult.dependencyGraph;\n\n\t\tthis.handlersDict = [];\n\t\tthis.changeStateHandlers = [];\n\t\tthis.dictionaries = [];\n\t\tthis.initialContextKeys = [];\n\n\t\tif (injectedFunctions.path) {\n\t\t\tthis.importNamespaces = {\n\t\t\t\t[injectedFunctions.path]: [DEFAULT_USER_FUNCTIONS_NAMESPACE],\n\t\t\t};\n\t\t\tthis.injectedPath = injectedFunctions.path;\n\t\t}\n\n\t\tfillDictionaries(diagram, this.stateDictionary, this.actionDictionary, this.eventDictionary);\n\n\t\tthis.dictionaries = JavaScriptCompiler.dictionaries.functions.setupDictionaries({\n\t\t\tdependencyGraph: this.dependencyGraph,\n\t\t\tdiagram: this.diagram,\n\t\t\texpressionRecord: this.expressions,\n\t\t\tactionDictionary: this.actionDictionary,\n\t\t\tstateDictionary: this.stateDictionary,\n\t\t\teventDictionary: this.eventDictionary,\n\t\t\tinjectedFunctions,\n\t\t\timports: this.imports,\n\t\t});\n\t}\n\n\tpublic getCode(options: TGetCodeOptionsMap[typeof ModuleNames.JavaScript]) {\n\t\tconst props = {\n\t\t\timports: this.imports,\n\t\t\timportNamespaces: this.importNamespaces,\n\t\t\tdictionaries: this.dictionaries,\n\t\t\tdiagram: this.diagram,\n\t\t\tstateDictionary: this.stateDictionary,\n\t\t\tactionDictionary: this.actionDictionary,\n\t\t\teventDictionary: this.eventDictionary,\n\t\t\texpressions: this.expressions,\n\t\t\tbyPassedList: getStatesByPass(this.diagram, this.stateDictionary),\n\t\t\tdictionariesSerializer: JavaScriptCompiler.dictionaries.serializer,\n\t\t\tclassSerializer: JavaScriptCompiler.class.serializer,\n\t\t\tclassName: options.className,\n\t\t\tdefines: this.defines,\n\t\t\tinjectedPath: this.injectedPath,\n\t\t\tinjects: this.injects,\n\t\t};\n\t\treturn `\n\t\t\t${JavaScriptCompiler.imports.serializer.getImportsCode(props)}\n\t\t\t${JavaScriptCompiler.imports.serializer.importAll(props)}\n\t\t\t${JavaScriptCompiler.functions.serializer(props)}\n\t\t\t${JavaScriptCompiler.dictionaries.serializer.getDictionariesCode(props)}\n\t\t\t${JavaScriptCompiler.events.serializer.getEventAdapterCode(props)}\n\t\t\t${JavaScriptCompiler.events.serializer.getCreateEventBusFunctionCode()}\n\t\t\t${JavaScriptCompiler.dictionaries.serializer.getActionsMap(props)}\n\t\t\t${JavaScriptCompiler.dictionaries.serializer.getStatesMap(props)}\n\t\t\t${JavaScriptCompiler.dictionaries.serializer.getSerializedSetByPassed(props)}\n\t\t\t${JavaScriptCompiler.context.serializer.getDefaultContext(props)}\n\t\t\t${JavaScriptCompiler.context.serializer.getStateReducerCode(props)}\n\t\t\t${JavaScriptCompiler.forks.serializer.getPredicatesCode(props)}\n\t\t\t${JavaScriptCompiler.dictionaries.serializer.getActionToStateFromState(props)}\n\t\t\t${JavaScriptCompiler.class.serializer.getClassTemplate(props)}\n\t\t\t${JavaScriptCompiler.dictionaries.serializer.getAutomataEpochCounterCode()}\n\t\t\t${JavaScriptCompiler.dictionaries.serializer.getAutomataInternalsRegisterCode(props)}\n\t\t\t${JavaScriptCompiler.dictionaries.serializer.getFunctionDictionaryInternalRegisterCode()}\n\t\t\t${JavaScriptCompiler.dictionaries.serializer.getFunctionDictionaryBuiltInRegisterCode()}\n\t\t`;\n\t}\n}\n","import { BasicActionDictionary, BasicEventDictionary, BasicStateDictionary } from '@yantrix/automata';\nimport { StartState } from '@yantrix/mermaid-parser';\nimport { ByPassAction } from '../../../../../constants';\nimport { TExpressionRecord, TStateDiagramMatrixIncludeNotes } from '../../../../../types/common';\nimport { replaceFileContents } from '../../../../../utils/utils';\nimport { context } from '../context';\nimport { state } from '../state';\n\nexport function getClassTemplate(props: {\n\tclassName: string;\n\tdiagram: TStateDiagramMatrixIncludeNotes;\n\tstateDictionary: BasicStateDictionary;\n\teventDictionary: BasicEventDictionary;\n\tactionDictionary: BasicActionDictionary;\n\texpressions: TExpressionRecord;\n\tclassSerializer: typeof classSerializer;\n}) {\n\tconst { diagram } = props;\n\n\tconst initialState = state.functions.getInitialState({\n\t\tdiagram,\n\t});\n\n\tconst stateValue = props.stateDictionary.getStateValues({ keys: [initialState] })[0];\n\n\tif (stateValue === null) {\n\t\tthrow new Error('GetClassTemplate: Invalid state');\n\t}\n\n\tconst a = context.functions.getInitialContextShape({\n\t\tdiagram,\n\t\tstateName: StartState,\n\t});\n\tconst b = context.functions.getInitialContextShape({\n\t\tdiagram,\n\t\tstateName: initialState,\n\t});\n\n\tconst initialContext = Object.assign({}, a, b);\n\n\treturn replaceFileContents(\n\n\t\t{\n\t\t\t'%CLASSNAME%': props.className,\n\t\t\t'%ID%': `'${props.className}_${Date.now()}'`,\n\t\t\t'%ACTIONS_MAP%': 'actionsMap',\n\t\t\t'%STATES_MAP%': 'statesMap',\n\t\t\t'%GET_STATE%': props.classSerializer.getGetStateFunc().toString(),\n\t\t\t'%HAS_STATE%': props.classSerializer.getHasStateFunc({ className: props.className }).toString(),\n\t\t\t'%GET_ACTION%': props.classSerializer.getGetActionFunc().toString(),\n\t\t\t'%CREATE_ACTION%': props.classSerializer.getCreateActionFunc({ className: props.className }).toString(),\n\t\t\t'%STATE%': (stateValue ?? -1).toString(),\n\t\t\t'%CONTEXT%': JSON.stringify(initialContext),\n\t\t\t'%REDUCER%': props.classSerializer.getRootReducer().toString(),\n\t\t\t'%STATE_VALIDATOR%': props.classSerializer.getStateValidator().toString(),\n\t\t\t'%ACTION_VALIDATOR%': props.classSerializer.getActionValidator().toString(),\n\t\t\t'%FUNCTION_REGISTRY%': 'functionDictionary',\n\t\t\t'%EVENT_DICTIONARY%': 'GlobalEventDictionary',\n\t\t\t'%IS_KEY_OF%': props.classSerializer.getIsKeyOf().toString(),\n\t\t},\n\t);\n}\n\nexport function getHasStateFunc(props: { className: string }) {\n\treturn `(instance, state) => instance.state === ${props.className}.getState(state)`;\n}\n\nexport function getGetStateFunc() {\n\treturn `(state) => statesDictionary[state]`;\n}\n\nexport function getGetActionFunc() {\n\treturn `(action) => actionsDictionary[action];`;\n}\n\nexport function getCreateActionFunc(props: { className: string }) {\n\treturn `\n\t\t(action, payload) => {\n\t\t\tconst actionId = ${props.className}.getAction(action);\n\t\t\treturn {\n\t\t\t\taction: actionId,\n\t\t\t\tpayload,\n\t\t\t}\n\t\t}`;\n}\n\nexport function getActionValidator() {\n\treturn `(a) => Object.values(actionsDictionary).includes(a)`;\n}\n\nexport function getRootReducer() {\n\treturn `({ action, context, payload, state }) => {\n\t\t\t\t\tif (!action || payload === null) return { state, context };\n\n\t\t\t\t\t${getRootReducerStateValidation()}\n\t\t\t\t\t${getRootReducerActionValidation()}\n\n\t\t\t\t\tconst getNew = (action,state,context,payload) => {\n\t\t\t\t\t\tthis.lastAction = action;\n\n\t\t\t\t\t\tconst actionMove = actionToStateFromStateDict[state][action];\n\t\t\t\t\t\tconst newStateObject = { state: actionMove.state[0] }\n\t\t\t\t\t\tconst contextWithInitial = getDefaultContext(context,payload)\n\n\n\t\t\t\t\t\t${getRootReducerNewStatePredicateResolution()}\n\n\t\t\t\t\t\tconst newState = newStateObject.state;\n\t\t\t\t\t\tconst newContextFunc = reducer[newState]\n\n\t\t\t\t\t\tif(typeof newContextFunc !== 'function') {\n\t\t\t\t\t\t\tthrow new Error('Invalid newContextFunc')\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn {state:newState, context: newContextFunc(contextWithInitial, payload, this.getFunctionRegistry(), this)};\n\n\t\t\t\t\t}\n\n\t\t\t\t\tlet localCtx = getNew(action,state,context,payload)\n\n\t\t\t\t\twhile(byPassedStates.has(localCtx.state)) {\n\t\t\t\t\t\tlocalCtx = getNew(actionsDictionary['${ByPassAction}'], localCtx.state, localCtx.context, {})\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.incrementCycle(); // increment automata local cycle counter\n\t\t\t\t\tincrementEpoch(); // increment global epoch counter\n\n\t\t\t\t\treturn localCtx\n\n \t\t\t\t}`;\n}\n\nexport function getRootReducerNewStatePredicateResolution() {\n\treturn `\n\t\t\tif(actionMove.state.length > 1 && actionMove.predicate != null) {\n\t\t\t\t// determine new state from predicate\n\t\t\t\tconst resolvedPredicateValue = actionMove.predicate(contextWithInitial, payload, functionDictionary);\n\t\t\t\tif(resolvedPredicateValue == null) return { state, context };\n\t\t\t\tnewStateObject.state = resolvedPredicateValue;\n\t\t\t}\n\t\t`;\n}\n\nexport function getRootReducerStateValidation() {\n\treturn `${getRootReducerStateValidationHead()} ${getRootReducerStateValidationError()}`;\n}\n\nexport function getRootReducerStateValidationHead() {\n\treturn `if (!this.isKeyOf(state, actionToStateFromStateDict))`;\n}\n\nexport function getRootReducerStateValidationError() {\n\treturn `throw new Error(\"Invalid state, maybe machine isn't running.\")`;\n}\n\nexport function getRootReducerActionValidation() {\n\treturn `if (!this.isKeyOf(action, actionToStateFromStateDict[state])) return { state, context };`;\n}\n\nexport function getStateValidator() {\n\treturn `(s) => Object.values(statesDictionary).includes(s)`;\n}\n\nexport function getIsKeyOf() {\n\treturn `(key, obj) => key in obj`;\n}\n\nexport const classSerializer = {\n\tgetClassTemplate,\n\tgetStateValidator,\n\tgetHasStateFunc,\n\tgetGetStateFunc,\n\tgetGetActionFunc,\n\tgetCreateActionFunc,\n\tgetActionValidator,\n\tgetRootReducer,\n\tgetRootReducerStateValidation,\n\tgetRootReducerStateValidationHead,\n\tgetRootReducerStateValidationError,\n\tgetRootReducerActionValidation,\n\tgetIsKeyOf,\n} as const;\n","export const JavaScriptTemplate = `\nexport class %CLASSNAME% extends GenericAutomata {\n\n static id = %ID%;\n static actions = %ACTIONS_MAP%;\n static states = %STATES_MAP%;\n static getState = %GET_STATE%;\n static hasState = %HAS_STATE%;\n static getAction = %GET_ACTION%;\n static createAction = %CREATE_ACTION%;\n\n constructor() {\n super(eventAdapter);\n this.init({\n state: %STATE%,\n context:%CONTEXT%,\n rootReducer: %REDUCER%,\n stateValidator: %STATE_VALIDATOR%,\n actionValidator: %ACTION_VALIDATOR%,\n functionRegistry: %FUNCTION_REGISTRY%\n });\n }\n\n isKeyOf = %IS_KEY_OF%;\n}\n\nexport default %CLASSNAME%;`;\n","import { JavaScriptTemplate } from '../core/templates/JavaScript';\n\nexport function replaceFileContents(replacementMap: Record<string, string>): string {\n\tlet res = JavaScriptTemplate;\n\tObject.entries(replacementMap).forEach(([template, str]) => {\n\t\tres = res.replaceAll(template, str);\n\t});\n\treturn res;\n}\n\n/**\n * Преобразует ключи объекта в число\n */\nexport function convertKeysToNumberString(obj: object): string {\n\tif (typeof obj !== 'object' || obj === null)\n\t\treturn JSON.stringify(obj);\n\n\tlet result = '{';\n\tlet first = true;\n\tfor (const [key, value] of Object.entries(obj)) {\n\t\tif (!first)\n\t\t\tresult += ',';\n\t\tfirst = false;\n\t\tresult += `${Number(key)}:${convertKeysToNumberString(value)}`;\n\t}\n\tresult += '}';\n\treturn result;\n}\n","import { TStateDiagramMatrixIncludeNotes } from '../../../../../types/common';\n\nexport function getInitialContextShape(props: {\n\tdiagram: TStateDiagramMatrixIncludeNotes;\n\tstateName: string;\n}) {\n\tconst states = props.diagram.states.filter(state => state.id === props.stateName);\n\n\tif (states.length) {\n\t\treturn states.reduce(\n\t\t\t(acc, curr) => {\n\t\t\t\tcurr.notes?.contextDescription.forEach((el) => {\n\t\t\t\t\tel.context.forEach((el) => {\n\t\t\t\t\t\tacc[el.keyItem.identifier] = null;\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t\treturn acc;\n\t\t\t},\n\t\t\t{} as Record<string, null>,\n\t\t);\n\t}\n\n\treturn null;\n};\n","import { BasicActionDictionary, BasicStateDictionary } from '@yantrix/automata';\nimport { StartState } from '@yantrix/mermaid-parser';\nimport {\n\tExpressionTypes,\n\tisContextWithReducer,\n\tisKeyItemReference,\n\tisKeyItemWithExpression,\n\tTContextItem,\n\tTKeyItems,\n} from '@yantrix/yantrix-parser';\nimport { TExpressionRecord, TStateDiagramMatrixIncludeNotes } from '../../../../../types/common';\nimport { pathRecord } from '../../../../shared';\nimport { expressions } from '../expressions';\n\nfunction getStateReducerCode(props: {\n\tdiagram: TStateDiagramMatrixIncludeNotes;\n\tstateDictionary: BasicStateDictionary;\n\tactionDictionary: BasicActionDictionary;\n\texpressions: TExpressionRecord;\n}) {\n\treturn `const reducer = {\n\t\t${getStateToContext(props).join(',\\n\\t')}\n\t}`;\n}\n\nfunction getContextItem(props: {\n\tctx: TContextItem;\n\texpressions: TExpressionRecord;\n}) {\n\tif (isContextWithReducer(props.ctx)) {\n\t\tconst { context, reducer } = props.ctx;\n\n\t\treturn getBoundValues({\n\t\t\texpressions: props.expressions,\n\t\t\tarr: mapReducerItems({ reducer, expressions: props.expressions }),\n\t\t\tcontext,\n\t\t});\n\t} else {\n\t\tconst { context } = props.ctx;\n\t\treturn context.map(({ keyItem }) => {\n\t\t\tconst { identifier } = keyItem;\n\t\t\tif (isKeyItemWithExpression(keyItem)) {\n\t\t\t\tconst expressionValue = expressions.functions.getExpressionValue({\n\t\t\t\t\texpression: keyItem.expression,\n\t\t\t\t\texpressionRecord: props.expressions,\n\t\t\t\t});\n\n\t\t\t\treturn `${identifier}: ${expressions.serializer.getDefaultPropertyContext('prevContext', identifier, expressionValue)}`;\n\t\t\t} else {\n\t\t\t\treturn `${identifier}: ${expressions.serializer.getDefaultPropertyContext('prevContext', identifier)}`;\n\t\t\t}\n\t\t});\n\t}\n};\n\nfunction mapReducerItems(props: {\n\treducer: TKeyItems<'reducer'>;\n\tsourcePath?: string;\n\texpressions: TExpressionRecord;\n}) {\n\treturn props.reducer\n\t\t.map(({ keyItem }) => {\n\t\t\tif (isKeyItemReference(keyItem)) {\n\t\t\t\tconst { expressionType, identifier: boundIdentifier } = keyItem;\n\t\t\t\tconst path = props.sourcePath ?? pathRecord[expressionType];\n\n\t\t\t\tif (keyItem.expressionType === ExpressionTypes.Constant) {\n\t\t\t\t\tconst expressionValueRight = expressions.functions.getExpressionValue({\n\t\t\t\t\t\texpression: keyItem,\n\t\t\t\t\t\texpressionRecord: props.expressions,\n\t\t\t\t\t});\n\t\t\t\t\treturn `(function(){\n\t\t\t\t\t\t\treturn ${expressionValueRight}\n\t\t\t\t\t\t\t}())`;\n\t\t\t\t}\n\n\t\t\t\tif (isKeyItemWithExpression(keyItem)) {\n\t\t\t\t\tconst { expression } = keyItem;\n\n\t\t\t\t\tconst expressionValueRight = expressions.functions.getExpressionValue({\n\t\t\t\t\t\texpression,\n\t\t\t\t\t\texpressionRecord: props.expressions,\n\t\t\t\t\t});\n\n\t\t\t\t\treturn expressions.serializer.getDefaultPropertyContext(path, boundIdentifier, expressionValueRight);\n\t\t\t\t}\n\n\t\t\t\treturn expressions.serializer.getDefaultPropertyContext(path, boundIdentifier);\n\t\t\t} else {\n\t\t\t\tconst { expression } = keyItem;\n\n\t\t\t\tconst expressionValueRight = expressions.functions.getExpressionValue({\n\t\t\t\t\texpression,\n\t\t\t\t\texpressionRecord: props.expressions,\n\t\t\t\t});\n\t\t\t\treturn `(function(){\n\t\t\t\t\t\treturn ${expressionValueRight}\n\t\t\t\t\t}())`;\n\t\t\t}\n\t\t});\n}\n\nfunction getBoundValues(props: {\n\texpressions: TExpressionRecord;\n\tarr: string[];\n\tcontext: any;\n}) {\n\treturn props.arr\n\t\t.map((el, index) => {\n\t\t\tconst item = props.context[index];\n\t\t\tif (!item) {\n\t\t\t\tthrow new Error('Unexpected index bound property');\n\t\t\t}\n\t\t\tconst { keyItem } = item;\n\t\t\tconst { identifier: targetProperty } = keyItem;\n\n\t\t\tif (isKeyItemWithExpression(keyItem)) {\n\t\t\t\tconst { expression } = keyItem;\n\n\t\t\t\tconst expressionValueRight = expressions.functions.getExpressionValue({\n\t\t\t\t\texpression,\n\t\t\t\t\texpressionRecord: props.expressions,\n\t\t\t\t});\n\n\t\t\t\treturn `${targetProperty}: (function(){\n\t\t\tconst boundValue = ${el}\n\t\t\tif(boundValue !== null){\n\t\t\t\treturn boundValue\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn ${expressionValueRight}\n\t\t\t}\n\n\t\t}())`;\n\t\t\t} else {\n\t\t\t\treturn `${targetProperty}: (function(){\n\t\t\tconst boundValue = ${el}\n\n\t\t\treturn boundValue\n\n\t\t}())`;\n\t\t\t}\n\t\t});\n}\n\nfunction getContextTransition(props: {\n\tvalue: number;\n\tstateDictionary: BasicStateDictionary;\n\tdiagram: TStateDiagramMatrixIncludeNotes;\n\texpressions: TExpressionRecord;\n}) {\n\tconst stateFromDict = props.stateDictionary.getStateKeys({ states: [props.value] })[0];\n\n\tif (stateFromDict === null) {\n\t\tthrow new Error(`Invalid state - ${props.value}`);\n\t}\n\n\tconst diagramState = props.diagram.states.find((diagramState) => {\n\t\treturn diagramState.id === stateFromDict;\n\t});\n\n\tif (!diagramState) {\n\t\tthrow new Error(`Invalid state - ${props.value}`);\n\t}\n\n\tconst ctxRes: string[] = [];\n\n\tdiagramState.notes?.contextDescription.forEach((ctx) => {\n\t\tconst newContext = getContextItem({\n\t\t\tctx,\n\t\t\texpressions: props.expressions,\n\t\t});\n\n\t\tctxRes.push(...newContext);\n\t});\n\n\tif (ctxRes.length === 0) return 'prevContext';\n\n\treturn `{${ctxRes.join(',\\n\\t')}}`;\n};\n\nfunction getStateToContext(props: {\n\tdiagram: TStateDiagramMatrixIncludeNotes;\n\tstateDictionary: BasicStateDictionary;\n\tactionDictionary: BasicActionDictionary;\n\texpressions: TExpressionRecord;\n}) {\n\treturn props.diagram.states.map((state) => {\n\t\tconst stateValue = props.stateDictionary.getStateValues({ keys: [state.id] })[0];\n\n\t\tif (!stateValue) {\n\t\t\tthrow new Error('Invalid state');\n\t\t}\n\n\t\treturn `${stateValue}: (prevContext, payload, functionDictionary, automata) => {\n\n\t\t\t\treturn ${getContextTransition({\n\t\t\t\t\tvalue: stateValue,\n\t\t\t\t\tstateDictionary: props.stateDictionary,\n\t\t\t\t\tdiagram: props.diagram,\n\t\t\t\t\texpressions: props.expressions,\n\t\t\t\t})}\n\t\t\t}`;\n\t});\n}\n\nfunction getDefaultContext(props: {\n\tstateDictionary: BasicStateDictionary;\n\tdiagram: TStateDiagramMatrixIncludeNotes;\n\texpressions: TExpressionRecord;\n}) {\n\tconst state = props.stateDictionary.getStateValues({ keys: [StartState] })[0];\n\n\tif (state) {\n\t\tconst ctx = getContextTransition({\n\t\t\tdiagram: props.diagram,\n\t\t\texpressions: props.expressions,\n\t\t\tstateDictionary: props.stateDictionary,\n\t\t\tvalue: state,\n\t\t});\n\n\t\treturn `const getDefaultContext = (prevContext, payload) => {\n\t\t\t\tconst ctx = ${ctx}\n\t\t\t\treturn Object.assign({}, prevContext, ctx);\n\t\t\t}\n\t\t\t`;\n\t}\n\n\treturn `const getDefaultContext = (prevContext, payload) => {\n\t\t\t\treturn prevContext\n\t\t}`;\n}\n\nexport const contextSerializer = {\n\tgetStateReducerCode,\n\tgetContextItem,\n\tmapReducerItems,\n\tgetBoundValues,\n\tgetStateToContext,\n\tgetDefaultContext,\n};\n","import {\n\tExpressionTypes,\n\tisKeyItemReference,\n\tisKeyItemWithExpression,\n\tmaxNestedFuncLevel,\n\tTExpression,\n\tTExpressionDefineMap,\n\tTExpressionFunction,\n\tTMappedKeys,\n} from '@yantrix/yantrix-parser';\nimport { TConstants, TExpressionRecord } from '../../../../../types/common';\nimport { pathRecord } from '../../../../shared';\nimport { getFunctionBody } from './functions';\nimport { expressionsSerializer } from './serializer';\n\nexport function setupExpressions(props: {\n\tconstants: TConstants | null;\n}): TExpressionRecord {\n\tconst expressionRecord: TExpressionRecord = {\n\t\t[ExpressionTypes.ArrayDeclaration]: () => '[]',\n\t\t[ExpressionTypes.Constant]: ({ identifier }) => {\n\t\t\tif (props.constants === null) {\n\t\t\t\tthrow new Error('Missing dictionary with constants');\n\t\t\t}\n\n\t\t\tif (props.constants[identifier] === undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`The identifier is missing in the const dictionary: ${identifier}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (typeof props.constants[identifier] === 'string')\n\t\t\t\treturn `\"${props.constants[identifier]}\"`;\n\n\t\t\treturn `${props.constants[identifier]}`;\n\t\t},\n\t\t[ExpressionTypes.Function]: () => {\n\t\t\treturn 'null';\n\t\t},\n\t\t[ExpressionTypes.DecimalDeclaration]: ({ NumberDeclaration }) => {\n\t\t\treturn `${NumberDeclaration}`;\n\t\t},\n\t\t[ExpressionTypes.IntegerDeclaration]: ({ NumberDeclaration }) => {\n\t\t\treturn `${NumberDeclaration}`;\n\t\t},\n\t\t[ExpressionTypes.StringDeclaration]: ({ StringDeclaration }) => {\n\t\t\treturn `'${StringDeclaration}'`;\n\t\t},\n\t\t[ExpressionTypes.Context]: ({ identifier }) => {\n\t\t\treturn `prevContext === null || (prevContext === undefined || prevContext['${identifier}'] === undefined) ? null : prevContext['${identifier}']`;\n\t\t},\n\t\t[ExpressionTypes.Payload]: ({ identifier }) => {\n\t\t\treturn `payload === null || (payload === undefined || payload['${identifier}'] === undefined) ? null : payload['${identifier}']`;\n\t\t},\n\t} as const;\n\n\texpressionRecord[ExpressionTypes.Function] = (func) => {\n\t\tlet currentRecLevel = 0;\n\t\tconst recursive = (func: TExpressionFunction) => {\n\t\t\tconst { FunctionDeclaration } = func;\n\t\t\tconst { FunctionName, Arguments } = FunctionDeclaration;\n\n\t\t\tconst res: string[] = [];\n\n\t\t\tif (currentRecLevel < maxNestedFuncLevel) {\n\t\t\t\tArguments.forEach((item) => {\n\t\t\t\t\tif (isKeyItemReference(item)) {\n\t\t\t\t\t\tconst { expressionType, identifier } = item;\n\t\t\t\t\t\tconst path = pathRecord[expressionType];\n\t\t\t\t\t\tif (isKeyItemWithExpression(item)) {\n\t\t\t\t\t\t\tconst { expression } = item;\n\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\texpression.expressionType\n\t\t\t\t\t\t\t\t=== ExpressionTypes.Function\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tcurrentRecLevel++;\n\t\t\t\t\t\t\t\tres.push(recursive(expression));\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst valueExpression\n\t\t\t\t\t\t\t\t= getExpressionValue({\n\t\t\t\t\t\t\t\t\texpressionRecord,\n\t\t\t\t\t\t\t\t\texpression,\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tres.push(\n\t\t\t\t\t\t\t\t`${expressionsSerializer.getDefaultPropertyContext(path, identifier, valueExpression)}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\titem.expressionType\n\t\t\t\t\t\t\t\t=== ExpressionTypes.Constant\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tconst expressionValueRight\n\t\t\t\t\t\t\t\t\t= getExpressionValue({\n\t\t\t\t\t\t\t\t\t\texpressionRecord,\n\t\t\t\t\t\t\t\t\t\texpression: item,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tres.push(expressionValueRight);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tres.push(\n\t\t\t\t\t\t\t\t\t`${expressionsSerializer.getDefaultPropertyContext(path, identifier)}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\titem.expressionType === ExpressionTypes.Function\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tres.push(recursive(item));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst valueExpression\n\t\t\t\t\t\t\t\t= getExpressionValue({\n\t\t\t\t\t\t\t\t\texpressionRecord,\n\t\t\t\t\t\t\t\t\texpression: item,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tres.push(valueExpression);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Max level of nested functions reached ${maxNestedFuncLevel}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn expressionsSerializer.getFunctionFromDictionary(FunctionName).concat(\n\t\t\t\t`(${res.join(',')})`,\n\t\t\t);\n\t\t};\n\n\t\tconst res = recursive(func);\n\t\treturn res;\n\t};\n\n\treturn expressionRecord;\n}\n\nexport function getExpressionValue<T extends TMappedKeys>(props: {\n\texpressionRecord: TExpressionRecord;\n\texpression: TExpression<T>;\n}) {\n\treturn props.expressionRecord[props.expression.expressionType](props.expression);\n}\n\nexport function getExpressionValueDefine(props: {\n\texpressions: TExpressionRecord;\n\texpression: TExpressionDefineMap;\n}) {\n\tswitch (props.expression.expressionType) {\n\t\tcase ExpressionTypes.Identifier:\n\t\t\treturn props.expression.identifier;\n\t\tcase ExpressionTypes.Function:\n\t\t\treturn getFunctionBody({\n\t\t\t\texpression: props.expression,\n\t\t\t\texpressions: props.expressions,\n\t\t\t});\n\t\tdefault:\n\t\t\treturn getExpressionValue({\n\t\t\t\texpressionRecord: props.expressions,\n\t\t\t\texpression: props.expression,\n\t\t\t});\n\t}\n}\n","import { builtInFunctions, ReservedInternalFunctionNames } from '@yantrix/functions';\nimport { TNullable } from '@yantrix/utils';\nimport { ExpressionTypes, TDefine, TExpressionDefineMap } from '@yantrix/yantrix-parser';\nimport { DEFAULT_USER_FUNCTIONS_NAMESPACE } from '../../../../../constants';\nimport { TExpressionRecord, TStateDiagramMatrixIncludeNotes, TUserFunctionsDict } from '../../../../../types/common';\nimport { TDictionaries } from '../dictionaries';\nimport { TDependencyGraph } from '../imports';\nimport { getExpressionValueDefine } from './core';\n\nexport function getFunctionBody(props: {\n\texpressions: TExpressionRecord;\n\texpression: TExpressionDefineMap;\n}): string {\n\tif (props.expression.expressionType === ExpressionTypes.Function) {\n\t\tconst { FunctionName, Arguments } = props.expression.FunctionDeclaration;\n\n\t\t// If function name is one of internals - the only argument will be automata itself\n\t\tif (ReservedInternalFunctionNames.includes(FunctionName)) {\n\t\t\treturn `(function() {\n\t\t\t\tconst func = functionD