javonet-nodejs-sdk 2.6.7 → 2.6.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/handler/CreateClassInstanceHandler.cjs +35 -1
- package/dist/core/handler/Handler.cjs +28 -9
- package/dist/core/handler/LoadLibraryHandler.cjs +15 -9
- package/dist/core/handler/PassDelegateHandler.cjs +2 -2
- package/dist/core/interpreter/Interpreter.cjs +11 -33
- package/dist/core/protocol/CommandSerializer.cjs +3 -8
- package/dist/core/receiver/Receiver.cjs +6 -6
- package/dist/sdk/Activator.cjs +44 -0
- package/dist/sdk/ActivatorDetails.cjs +13 -3
- package/dist/sdk/ConfigRuntimeFactory.cjs +9 -0
- package/dist/sdk/InvocationContext.cjs +112 -66
- package/dist/sdk/Javonet.cjs +3 -0
- package/dist/sdk/RuntimeContext.cjs +8 -8
- package/dist/sdk/configuration/ConfigSourceResolver.cjs +43 -21
- package/dist/sdk/tools/ComplexTypeResolver.cjs +84 -34
- package/dist/types/core/handler/CreateClassInstanceHandler.d.ts +8 -0
- package/dist/types/core/handler/Handler.d.ts +2 -1
- package/dist/types/core/handler/PassDelegateHandler.d.ts +2 -2
- package/dist/types/core/interpreter/Interpreter.d.ts +2 -2
- package/dist/types/core/protocol/CommandSerializer.d.ts +3 -3
- package/dist/types/core/receiver/Receiver.d.ts +4 -4
- package/dist/types/sdk/Activator.d.ts +12 -0
- package/dist/types/sdk/ActivatorDetails.d.ts +5 -3
- package/dist/types/sdk/ConfigRuntimeFactory.d.ts +7 -0
- package/dist/types/sdk/InvocationContext.d.ts +19 -17
- package/dist/types/sdk/Javonet.d.ts +2 -1
- package/dist/types/sdk/RuntimeContext.d.ts +4 -3
- package/dist/types/sdk/configuration/ConfigSourceResolver.d.ts +21 -4
- package/dist/types/sdk/tools/ComplexTypeResolver.d.ts +21 -5
- package/dist/types/utils/CommandType.d.ts +1 -0
- package/dist/types/utils/Primitives.d.ts +5 -0
- package/dist/utils/CommandType.cjs +2 -1
- package/dist/utils/Primitives.cjs +201 -0
- package/lib/core/handler/CreateClassInstanceHandler.js +46 -1
- package/lib/core/handler/Handler.js +34 -9
- package/lib/core/handler/LoadLibraryHandler.js +28 -14
- package/lib/core/handler/PassDelegateHandler.js +2 -2
- package/lib/core/interpreter/Interpreter.js +11 -35
- package/lib/core/protocol/CommandSerializer.js +5 -10
- package/lib/core/receiver/Receiver.js +6 -6
- package/lib/sdk/Activator.js +22 -0
- package/lib/sdk/ActivatorDetails.js +18 -3
- package/lib/sdk/ConfigRuntimeFactory.js +10 -0
- package/lib/sdk/InvocationContext.js +133 -74
- package/lib/sdk/Javonet.js +2 -0
- package/lib/sdk/RuntimeContext.js +8 -8
- package/lib/sdk/configuration/ConfigSourceResolver.js +47 -14
- package/lib/sdk/tools/ComplexTypeResolver.js +104 -42
- package/lib/utils/CommandType.js +1 -0
- package/lib/utils/Primitives.js +193 -0
- package/package.json +4 -3
|
@@ -13,6 +13,7 @@ let _existsSync = null
|
|
|
13
13
|
let _resolve = null
|
|
14
14
|
|
|
15
15
|
const requireDynamic = getRequire(import.meta.url)
|
|
16
|
+
|
|
16
17
|
class LoadLibraryHandler extends AbstractHandler {
|
|
17
18
|
requiredParametersCount = 1
|
|
18
19
|
/** @type {string[]} */
|
|
@@ -29,9 +30,9 @@ class LoadLibraryHandler extends AbstractHandler {
|
|
|
29
30
|
if (command.payload.length < this.requiredParametersCount) {
|
|
30
31
|
throw new Error('Load Library parameters mismatch')
|
|
31
32
|
}
|
|
32
|
-
let { payload } = command
|
|
33
|
-
let [lib] = payload
|
|
34
33
|
|
|
34
|
+
const { payload } = command
|
|
35
|
+
const [lib] = payload
|
|
35
36
|
|
|
36
37
|
if (!lib) {
|
|
37
38
|
throw new Error('Cannot load module: Library path is required but was not provided')
|
|
@@ -46,33 +47,46 @@ class LoadLibraryHandler extends AbstractHandler {
|
|
|
46
47
|
_resolve = resolve
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
|
|
50
|
+
// Resolve and pick an existing path (relative or absolute)
|
|
51
|
+
const absolutePath = _resolve ? _resolve(lib) : lib
|
|
52
|
+
const candidatePaths = [lib, absolutePath]
|
|
53
|
+
const existingPath = candidatePaths.find(p => _existsSync && _existsSync(p))
|
|
50
54
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
if (!existingPath) {
|
|
56
|
+
throw new Error(`Cannot load module: Library not found: ${lib}`)
|
|
57
|
+
}
|
|
54
58
|
|
|
59
|
+
// Normalize to absolute path for deduplication
|
|
60
|
+
const normalizedPath = _resolve ? _resolve(existingPath) : existingPath
|
|
55
61
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
62
|
+
// ✅ Load only once per normalized absolute path
|
|
63
|
+
if (LoadLibraryHandler.loadedLibraries.includes(normalizedPath)) {
|
|
64
|
+
return 0
|
|
65
|
+
}
|
|
59
66
|
|
|
60
|
-
|
|
67
|
+
// Derive global name from file name (using normalized path)
|
|
68
|
+
const pathArray = normalizedPath.split(/[/\\]/)
|
|
69
|
+
let libraryName =
|
|
70
|
+
pathArray.length > 1 ? pathArray[pathArray.length - 1] : pathArray[0]
|
|
71
|
+
libraryName = libraryName.replace(/\.js$/i, '')
|
|
61
72
|
|
|
73
|
+
let moduleExports
|
|
62
74
|
try {
|
|
63
|
-
|
|
64
|
-
|
|
75
|
+
// Use the normalized path when requiring to keep behavior consistent
|
|
76
|
+
moduleExports = requireDynamic(normalizedPath)
|
|
77
|
+
LoadLibraryHandler.loadedLibraries.push(normalizedPath)
|
|
65
78
|
} catch (error) {
|
|
66
|
-
throw Error('Cannot load module: ' +
|
|
79
|
+
throw new Error('Cannot load module: ' + normalizedPath + '\n' + error)
|
|
67
80
|
}
|
|
81
|
+
|
|
68
82
|
// @ts-expect-error
|
|
69
83
|
global[libraryName] = moduleExports
|
|
70
84
|
|
|
71
85
|
for (const [key, value] of Object.entries(moduleExports)) {
|
|
72
|
-
// Here, `key` is the name of the export, and `value` is the exported type itself.
|
|
73
86
|
// @ts-expect-error
|
|
74
87
|
global[key] = value
|
|
75
88
|
}
|
|
89
|
+
|
|
76
90
|
return 0
|
|
77
91
|
}
|
|
78
92
|
|
|
@@ -113,9 +113,9 @@ class PassDelegateHandler extends AbstractHandler {
|
|
|
113
113
|
/**
|
|
114
114
|
* Creates a method call to execute the command.
|
|
115
115
|
* @param {Command} command - The command object.
|
|
116
|
-
* @returns {any} The response object.
|
|
116
|
+
* @returns {Promise<any>} The response object.
|
|
117
117
|
*/
|
|
118
|
-
createExecuteCall(command) {
|
|
118
|
+
async createExecuteCall(command) {
|
|
119
119
|
return this.interpreter?.execute(command, new InMemoryConnectionData())
|
|
120
120
|
}
|
|
121
121
|
|
|
@@ -21,7 +21,6 @@ let _Transmitter
|
|
|
21
21
|
/** @type {typeof import('../transmitter/TransmitterWebsocket.js').TransmitterWebsocket | typeof import('../transmitter/TransmitterWebsocketBrowser.js').TransmitterWebsocketBrowser} */
|
|
22
22
|
let _TransmitterWebsocket = isNodejsRuntime() ? TransmitterWebsocket : TransmitterWebsocketBrowser
|
|
23
23
|
|
|
24
|
-
|
|
25
24
|
const requireDynamic = getRequire(import.meta.url)
|
|
26
25
|
|
|
27
26
|
export class Interpreter {
|
|
@@ -40,21 +39,23 @@ export class Interpreter {
|
|
|
40
39
|
*
|
|
41
40
|
* @param {Command} command
|
|
42
41
|
* @param {IConnectionData} connectionData
|
|
43
|
-
* @returns {
|
|
42
|
+
* @returns {Promise<Command>}
|
|
44
43
|
*/
|
|
45
|
-
execute(command, connectionData) {
|
|
44
|
+
async execute(command, connectionData) {
|
|
46
45
|
try {
|
|
47
46
|
let messageByteArray = new CommandSerializer().serialize(command, connectionData)
|
|
48
47
|
|
|
49
|
-
if (!(messageByteArray instanceof Uint8Array)
|
|
50
|
-
throw new Error('Serialized message is
|
|
48
|
+
if (!(messageByteArray instanceof Uint8Array)) {
|
|
49
|
+
throw new Error('Serialized message is not Uint8Array')
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
/** @type {Promise<Uint8Array> | Uint8Array | undefined} */
|
|
54
53
|
let responseByteArray = undefined
|
|
55
54
|
|
|
56
55
|
if (!isNodejsRuntime() && connectionData.connectionType === ConnectionType.IN_MEMORY) {
|
|
57
|
-
throw new Error(
|
|
56
|
+
throw new Error(
|
|
57
|
+
'Nodejs Core Error: inMemory is only allowed in Nodejs runtime, not in browser'
|
|
58
|
+
)
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
if (
|
|
@@ -68,13 +69,7 @@ export class Interpreter {
|
|
|
68
69
|
if (!_Receiver) {
|
|
69
70
|
throw new Error('Nodejs Core Error: Receiver is undefined')
|
|
70
71
|
}
|
|
71
|
-
|
|
72
|
-
responseByteArray = messageByteArray.then((resolvedMessage) => {
|
|
73
|
-
return _Receiver.sendCommand(resolvedMessage)
|
|
74
|
-
})
|
|
75
|
-
} else if (messageByteArray instanceof Uint8Array) {
|
|
76
|
-
responseByteArray = _Receiver.sendCommand(messageByteArray)
|
|
77
|
-
}
|
|
72
|
+
responseByteArray = await _Receiver.sendCommand(messageByteArray)
|
|
78
73
|
} else if (
|
|
79
74
|
connectionData.connectionType === ConnectionType.IN_MEMORY ||
|
|
80
75
|
connectionData.connectionType === ConnectionType.TCP
|
|
@@ -86,34 +81,15 @@ export class Interpreter {
|
|
|
86
81
|
if (!_Transmitter) {
|
|
87
82
|
throw new Error('Nodejs Core Error: Transmitter is undefined')
|
|
88
83
|
}
|
|
89
|
-
|
|
90
|
-
responseByteArray = _Transmitter.sendCommand(messageByteArray)
|
|
91
|
-
} else {
|
|
92
|
-
responseByteArray = messageByteArray.then((resolvedMessage) => {
|
|
93
|
-
return _Transmitter.sendCommand(resolvedMessage)
|
|
94
|
-
})
|
|
95
|
-
}
|
|
84
|
+
responseByteArray = await _Transmitter.sendCommand(messageByteArray)
|
|
96
85
|
} else if (connectionData.connectionType === ConnectionType.WEB_SOCKET) {
|
|
97
|
-
|
|
98
|
-
responseByteArray = _TransmitterWebsocket.sendCommand(messageByteArray, connectionData)
|
|
99
|
-
} else {
|
|
100
|
-
responseByteArray = messageByteArray.then((resolvedMessage) => {
|
|
101
|
-
return _TransmitterWebsocket.sendCommand(resolvedMessage, connectionData)
|
|
102
|
-
})
|
|
103
|
-
}
|
|
86
|
+
responseByteArray = await _TransmitterWebsocket.sendCommand(messageByteArray, connectionData)
|
|
104
87
|
}
|
|
105
88
|
|
|
106
89
|
if (!responseByteArray) {
|
|
107
90
|
throw new Error('No response received from Transmitter')
|
|
108
91
|
}
|
|
109
|
-
|
|
110
|
-
if (responseByteArray instanceof Promise) {
|
|
111
|
-
return responseByteArray.then((resolvedResponse) => {
|
|
112
|
-
return new CommandDeserializer(resolvedResponse).deserialize()
|
|
113
|
-
})
|
|
114
|
-
} else {
|
|
115
|
-
return new CommandDeserializer(responseByteArray).deserialize()
|
|
116
|
-
}
|
|
92
|
+
return new CommandDeserializer(responseByteArray).deserialize()
|
|
117
93
|
} catch (error) {
|
|
118
94
|
throw error
|
|
119
95
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import { TypeSerializer } from './TypeSerializer.js'
|
|
2
3
|
import { ReferencesCache } from '../referenceCache/ReferencesCache.js'
|
|
3
4
|
import { Command } from '../../utils/Command.js'
|
|
@@ -11,26 +12,20 @@ import { TypesHandler } from '../../utils/TypesHandler.js'
|
|
|
11
12
|
class CommandSerializer {
|
|
12
13
|
/**
|
|
13
14
|
* Serializes the root command with connection data and optional runtime version.
|
|
14
|
-
* @param {
|
|
15
|
+
* @param {Command} rootCommand
|
|
15
16
|
* @param {IConnectionData} connectionData
|
|
16
17
|
* @param {number} runtimeVersion
|
|
17
|
-
* @returns {
|
|
18
|
+
* @returns {Uint8Array}
|
|
18
19
|
*/
|
|
19
20
|
serialize(rootCommand, connectionData, runtimeVersion = 0) {
|
|
21
|
+
/** @type {Array<Uint8Array>} */
|
|
20
22
|
const buffers = []
|
|
21
23
|
|
|
22
|
-
// Write runtime name and version
|
|
23
|
-
if (rootCommand instanceof Promise) {
|
|
24
|
-
return rootCommand.then(resolvedCommand => {
|
|
25
|
-
return this.serialize(resolvedCommand, connectionData, runtimeVersion)
|
|
26
|
-
})
|
|
27
|
-
}
|
|
28
|
-
|
|
29
24
|
buffers.push(Uint8Array.of(rootCommand.runtimeName, runtimeVersion))
|
|
30
25
|
|
|
31
26
|
// Write connection data or default zeros
|
|
32
27
|
if (connectionData) {
|
|
33
|
-
buffers.push(connectionData.serializeConnectionData())
|
|
28
|
+
buffers.push(Uint8Array.from(connectionData.serializeConnectionData()))
|
|
34
29
|
} else {
|
|
35
30
|
buffers.push(Uint8Array.of(0, 0, 0, 0, 0, 0, 0))
|
|
36
31
|
}
|
|
@@ -19,11 +19,11 @@ export class Receiver {
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* @param {Uint8Array} messageByteArray
|
|
22
|
-
* @returns {Promise<Uint8Array>
|
|
22
|
+
* @returns {Promise<Uint8Array>}
|
|
23
23
|
*/
|
|
24
|
-
static sendCommand(messageByteArray) {
|
|
24
|
+
static async sendCommand(messageByteArray) {
|
|
25
25
|
try {
|
|
26
|
-
let command = new Interpreter().process(messageByteArray)
|
|
26
|
+
let command = await new Interpreter().process(messageByteArray)
|
|
27
27
|
return new CommandSerializer().serialize(command, this.connectionData)
|
|
28
28
|
} catch (error) {
|
|
29
29
|
const exceptionCommand = ExceptionSerializer.serializeException(
|
|
@@ -36,12 +36,12 @@ export class Receiver {
|
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* @param {Uint8Array} messageByteArray
|
|
39
|
-
* @returns {Promise<Uint8Array>
|
|
39
|
+
* @returns {Promise<Uint8Array>}
|
|
40
40
|
*/
|
|
41
|
-
static heartBeat(messageByteArray) {
|
|
41
|
+
static async heartBeat(messageByteArray) {
|
|
42
42
|
let response = new Uint8Array(2)
|
|
43
43
|
response[0] = messageByteArray[11]
|
|
44
44
|
response[1] = messageByteArray[12] - 2
|
|
45
|
-
return response
|
|
45
|
+
return Promise.resolve(response)
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Details for activating a type with constructor arguments
|
|
3
|
+
*/
|
|
4
|
+
class Activator {
|
|
5
|
+
/**
|
|
6
|
+
* Create a new instance of a type
|
|
7
|
+
* @param {Function} Type - The constructor function/class
|
|
8
|
+
* @param {any[] | any} args - The arguments to pass to the constructor
|
|
9
|
+
* @returns {any} The new instance
|
|
10
|
+
*/
|
|
11
|
+
static createInstance(Type, args) {
|
|
12
|
+
if (args == null) {
|
|
13
|
+
args = []
|
|
14
|
+
}
|
|
15
|
+
if (!Array.isArray(args)) {
|
|
16
|
+
args = [args]
|
|
17
|
+
}
|
|
18
|
+
return new Type(...args)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { Activator }
|
|
@@ -2,13 +2,28 @@
|
|
|
2
2
|
* Details for activating a type with constructor arguments
|
|
3
3
|
*/
|
|
4
4
|
class ActivatorDetails {
|
|
5
|
+
/** @type {Function} */
|
|
6
|
+
Type
|
|
7
|
+
|
|
8
|
+
/** @type {any[]} */
|
|
9
|
+
arguments
|
|
10
|
+
|
|
5
11
|
/**
|
|
6
12
|
* @param {Function} type - The constructor function/class
|
|
7
|
-
* @param {any[]} [args] - Arguments to pass to constructor
|
|
13
|
+
* @param {any[]|any} [args] - Arguments to pass to constructor (array or single value)
|
|
8
14
|
*/
|
|
9
15
|
constructor(type, args = []) {
|
|
10
|
-
this.
|
|
11
|
-
|
|
16
|
+
this.Type = type
|
|
17
|
+
// Normalize args: ensure it's always an array
|
|
18
|
+
// Handles: undefined, null, single value, or array
|
|
19
|
+
if (args == null) {
|
|
20
|
+
this.arguments = []
|
|
21
|
+
} else if (Array.isArray(args)) {
|
|
22
|
+
this.arguments = args
|
|
23
|
+
} else {
|
|
24
|
+
// Single value - wrap in array
|
|
25
|
+
this.arguments = [args]
|
|
26
|
+
}
|
|
12
27
|
}
|
|
13
28
|
}
|
|
14
29
|
|
|
@@ -102,6 +102,16 @@ export class ConfigRuntimeFactory {
|
|
|
102
102
|
return this.#getRuntimeContext(RuntimeName.Nodejs, configName)
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Creates RuntimeContext instance to interact with the Php runtime.
|
|
107
|
+
* @param {string} [configName="default"] - The name of the configuration to use (optional).
|
|
108
|
+
* @return {RuntimeContext} a RuntimeContext instance for the Php runtime
|
|
109
|
+
* @see [Javonet Guides](https://www.javonet.com/guides/v2/javascript/foundations/runtime-context)
|
|
110
|
+
*/
|
|
111
|
+
php(configName = 'default') {
|
|
112
|
+
return this.#getRuntimeContext(RuntimeName.Php, configName)
|
|
113
|
+
}
|
|
114
|
+
|
|
105
115
|
/**
|
|
106
116
|
* Creates RuntimeContext instance to interact with the Python 2.7 runtime.
|
|
107
117
|
* @param {string} [configName="default"] - The name of the configuration to use (optional).
|
|
@@ -3,10 +3,10 @@ import { delegatesCacheInstance } from '../core/delegatesCache/DelegatesCache.js
|
|
|
3
3
|
import { Interpreter } from '../core/interpreter/Interpreter.js'
|
|
4
4
|
import { Command } from '../utils/Command.js'
|
|
5
5
|
import { CommandType } from '../utils/CommandType.js'
|
|
6
|
-
import { ConnectionType } from '../utils/ConnectionType.js'
|
|
7
6
|
import { ExceptionThrower } from '../utils/exception/ExceptionThrower.js'
|
|
8
7
|
import { RuntimeName } from '../utils/RuntimeName.js'
|
|
9
8
|
import { TypesHandler } from '../utils/TypesHandler.js'
|
|
9
|
+
import { v4 as uuidv4 } from 'uuid' // add lightweight uuid generation
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* @typedef {import('../types.d.ts').RuntimeName} RuntimeNameType
|
|
@@ -27,12 +27,17 @@ class InvocationContext {
|
|
|
27
27
|
#connectionData
|
|
28
28
|
/** @type {Command | null} */
|
|
29
29
|
#currentCommand = null
|
|
30
|
-
/** @type {Command |
|
|
30
|
+
/** @type {Command | null} */
|
|
31
31
|
#responseCommand = null
|
|
32
32
|
/** @type {boolean} */
|
|
33
33
|
#isExecuted = false
|
|
34
34
|
/** @type {Interpreter | null} */
|
|
35
35
|
#interpreter = null
|
|
36
|
+
/** @type {string | null} */
|
|
37
|
+
#guid = null
|
|
38
|
+
|
|
39
|
+
// Static map holding contexts waiting for materialization (guid -> InvocationContext)
|
|
40
|
+
static _invocationContexts = new Map()
|
|
36
41
|
|
|
37
42
|
/**
|
|
38
43
|
*
|
|
@@ -48,6 +53,15 @@ class InvocationContext {
|
|
|
48
53
|
this.#responseCommand = null
|
|
49
54
|
this.#isExecuted = isExecuted
|
|
50
55
|
this.#interpreter = null
|
|
56
|
+
this.#guid = uuidv4()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @returns {string} guid of this InvocationContext
|
|
61
|
+
*/
|
|
62
|
+
getGuid() {
|
|
63
|
+
// @ts-ignore
|
|
64
|
+
return this.#guid
|
|
51
65
|
}
|
|
52
66
|
|
|
53
67
|
/**
|
|
@@ -79,43 +93,31 @@ class InvocationContext {
|
|
|
79
93
|
// this.execute();
|
|
80
94
|
// }
|
|
81
95
|
//}
|
|
82
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Async iterator for InvocationContext arrays
|
|
98
|
+
* Use: for await (const item of invocationContext) { ... }
|
|
99
|
+
* @returns {AsyncGenerator<InvocationContext, void, unknown>}
|
|
100
|
+
*/
|
|
101
|
+
async *[Symbol.asyncIterator]() {
|
|
83
102
|
if (this.#currentCommand?.commandType !== CommandType.Reference) {
|
|
84
103
|
throw new Error('Object is not iterable')
|
|
85
104
|
}
|
|
86
|
-
let position = -1
|
|
87
|
-
/** @type {number} */
|
|
88
|
-
let arraySize = 0
|
|
89
|
-
/** @type {InvocationContext | Promise<InvocationContext>} */
|
|
90
|
-
const sizeCtx = /** @type {any} */ (this.getSize().execute())
|
|
91
|
-
if (sizeCtx instanceof Promise) {
|
|
92
|
-
sizeCtx.then((ctx) => {
|
|
93
|
-
arraySize = Number(ctx.getValue())
|
|
94
|
-
})
|
|
95
|
-
} else {
|
|
96
|
-
arraySize = Number(sizeCtx.getValue())
|
|
97
|
-
}
|
|
98
105
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
const sizeCtx = await this.getSize().execute()
|
|
107
|
+
const arraySize = Number(sizeCtx.getValue())
|
|
108
|
+
|
|
109
|
+
for (let position = 0; position < arraySize; position++) {
|
|
110
|
+
yield this.getIndex(position)
|
|
104
111
|
}
|
|
105
112
|
}
|
|
106
113
|
|
|
107
114
|
/**
|
|
108
115
|
* Executes the current command.
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* Commands are becoming nested through each invocation of methods on Invocation Context.
|
|
112
|
-
* Each invocation triggers the creation of new Invocation Context instance wrapping the current command with new parent command valid for invoked method.
|
|
113
|
-
* Developer can decide on any moment of the materialization for the context taking full control of the chunks of the expression being transferred and processed on target runtime.
|
|
114
|
-
* @returns {Promise<InvocationContext> | InvocationContext} the InvocationContext after executing the command.
|
|
115
|
-
* @see [Javonet Guides](https://www.javonet.com/guides/v2/javascript/foundations/execute-method)
|
|
116
|
+
* Returns the InvocationContext after executing the command.
|
|
117
|
+
* @returns {Promise<InvocationContext>}
|
|
116
118
|
* @method
|
|
117
119
|
*/
|
|
118
|
-
execute() {
|
|
120
|
+
async execute() {
|
|
119
121
|
if (this.#currentCommand === null) {
|
|
120
122
|
throw new Error('currentCommand is undefined in Invocation Context execute method')
|
|
121
123
|
}
|
|
@@ -124,28 +126,25 @@ class InvocationContext {
|
|
|
124
126
|
this.#interpreter = new Interpreter()
|
|
125
127
|
}
|
|
126
128
|
|
|
127
|
-
|
|
129
|
+
// Execute command on interpreter
|
|
130
|
+
this.#responseCommand = await this.#interpreter.execute(this.#currentCommand, this.#connectionData)
|
|
128
131
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
throw ExceptionThrower.throwException(resolvedResponse)
|
|
135
|
-
}
|
|
136
|
-
if (resolvedResponse.commandType === CommandType.CreateClassInstance) {
|
|
137
|
-
this.#currentCommand = resolvedResponse
|
|
138
|
-
this.#isExecuted = true
|
|
139
|
-
return this
|
|
140
|
-
}
|
|
141
|
-
return new InvocationContext(this.#runtimeName, this.#connectionData, resolvedResponse, true)
|
|
132
|
+
if (!this.#responseCommand) {
|
|
133
|
+
throw new Error('responseCommand is undefined in Invocation Context execute method')
|
|
134
|
+
}
|
|
135
|
+
if (this.#responseCommand.commandType === CommandType.Exception) {
|
|
136
|
+
throw ExceptionThrower.throwException(this.#responseCommand)
|
|
142
137
|
}
|
|
143
138
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
139
|
+
// Process UpdateInvocationContext commands (if any) coming from runtime
|
|
140
|
+
this.#responseCommand = this.#processUpdateInvocationContextCommands(this.#responseCommand)
|
|
141
|
+
|
|
142
|
+
if (this.#responseCommand.commandType === CommandType.CreateClassInstance) {
|
|
143
|
+
this.#currentCommand = this.#responseCommand
|
|
144
|
+
this.#isExecuted = true
|
|
145
|
+
return this
|
|
148
146
|
}
|
|
147
|
+
return new InvocationContext(this.#runtimeName, this.#connectionData, this.#responseCommand, true)
|
|
149
148
|
}
|
|
150
149
|
|
|
151
150
|
/**
|
|
@@ -191,14 +190,30 @@ class InvocationContext {
|
|
|
191
190
|
|
|
192
191
|
/**
|
|
193
192
|
* Creates a new instance of a class in the target runtime.
|
|
193
|
+
* Adds the newly created context to the static invocation contexts map and
|
|
194
|
+
* includes the context GUID as the first argument of CreateClassInstance command payload.
|
|
194
195
|
* @param {...any} args - The arguments to pass to the class constructor
|
|
195
196
|
* @returns {InvocationContext} A new InvocationContext instance that wraps the command to create the instance.
|
|
196
|
-
* @see [Javonet Guides](https://www.javonet.com/guides/v2/javascript/calling-methods/creating-instance-and-calling-instance-methods)
|
|
197
197
|
* @method
|
|
198
198
|
*/
|
|
199
199
|
createInstance(...args) {
|
|
200
|
-
|
|
201
|
-
|
|
200
|
+
const dummyCommand = new Command(this.#runtimeName, CommandType.CreateClassInstance, [
|
|
201
|
+
...args,
|
|
202
|
+
])
|
|
203
|
+
const createInstanceContext = new InvocationContext(this.#runtimeName, this.#connectionData, dummyCommand)
|
|
204
|
+
// include guid as first payload element followed by constructor args
|
|
205
|
+
let localCommand = new Command(this.#runtimeName, CommandType.CreateClassInstance, [
|
|
206
|
+
createInstanceContext.getGuid(),
|
|
207
|
+
...args,
|
|
208
|
+
])
|
|
209
|
+
|
|
210
|
+
// set current command for the new context
|
|
211
|
+
createInstanceContext.#currentCommand = this.#buildCommand(localCommand)
|
|
212
|
+
|
|
213
|
+
// register context for materialization
|
|
214
|
+
InvocationContext._invocationContexts.set(createInstanceContext.getGuid(), createInstanceContext)
|
|
215
|
+
|
|
216
|
+
return createInstanceContext
|
|
202
217
|
}
|
|
203
218
|
|
|
204
219
|
/**
|
|
@@ -402,29 +417,19 @@ class InvocationContext {
|
|
|
402
417
|
|
|
403
418
|
/**
|
|
404
419
|
* Retrieves the type of the object from the target runtime.
|
|
405
|
-
* @returns {Promise<string>
|
|
420
|
+
* @returns {Promise<string>} The type of the object.
|
|
406
421
|
* @see [Javonet Guides](https://www.javonet.com/guides/v2/javascript/type-handling/getting-object-type)
|
|
407
422
|
* @method
|
|
408
423
|
*/
|
|
409
|
-
getResultType() {
|
|
424
|
+
async getResultType() {
|
|
410
425
|
const localCommand = new Command(this.#runtimeName, CommandType.GetResultType, [])
|
|
411
426
|
const invocationContext = new InvocationContext(
|
|
412
427
|
this.#runtimeName,
|
|
413
428
|
this.#connectionData,
|
|
414
429
|
this.#buildCommand(localCommand)
|
|
415
430
|
)
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* @param {InvocationContext} invCtx
|
|
421
|
-
* @returns {string}
|
|
422
|
-
*/
|
|
423
|
-
const extract = (invCtx) => String(invCtx.getValue())
|
|
424
|
-
|
|
425
|
-
console.log(execCtx)
|
|
426
|
-
|
|
427
|
-
return execCtx instanceof Promise ? execCtx.then(extract) : extract(execCtx)
|
|
431
|
+
const execCtx = await invocationContext.execute()
|
|
432
|
+
return String(execCtx.getValue())
|
|
428
433
|
}
|
|
429
434
|
|
|
430
435
|
/**
|
|
@@ -439,10 +444,11 @@ class InvocationContext {
|
|
|
439
444
|
|
|
440
445
|
/**
|
|
441
446
|
* Retrieves an array from the target runtime.
|
|
447
|
+
* @async
|
|
442
448
|
* @returns {Promise<any[]>}
|
|
443
449
|
* @method
|
|
444
450
|
*/
|
|
445
|
-
retrieveArray() {
|
|
451
|
+
async retrieveArray() {
|
|
446
452
|
const localCommand = new Command(this.#runtimeName, CommandType.RetrieveArray, [])
|
|
447
453
|
const localInvCtx = new InvocationContext(
|
|
448
454
|
this.#runtimeName,
|
|
@@ -450,16 +456,27 @@ class InvocationContext {
|
|
|
450
456
|
this.#buildCommand(localCommand)
|
|
451
457
|
)
|
|
452
458
|
|
|
453
|
-
localInvCtx.execute()
|
|
459
|
+
await localInvCtx.execute()
|
|
460
|
+
|
|
461
|
+
const resolve = (/** @type {any} */ item) => {
|
|
462
|
+
return item?.commandType === CommandType.Reference ?
|
|
463
|
+
new InvocationContext(
|
|
464
|
+
this.#runtimeName,
|
|
465
|
+
this.#connectionData,
|
|
466
|
+
item
|
|
467
|
+
) : item
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
const respCommand = localInvCtx.#responseCommand
|
|
471
|
+
if (!respCommand) {
|
|
472
|
+
return []
|
|
473
|
+
}
|
|
454
474
|
|
|
455
|
-
|
|
456
|
-
return respCommand.payload
|
|
475
|
+
if (respCommand.payload) {
|
|
476
|
+
return respCommand.payload.map((/** @type {any} */ item) => resolve(item))
|
|
457
477
|
}
|
|
458
478
|
|
|
459
|
-
|
|
460
|
-
return localInvCtx.#responseCommand instanceof Promise
|
|
461
|
-
? localInvCtx.#responseCommand.then(extract)
|
|
462
|
-
: localInvCtx.#responseCommand?.payload
|
|
479
|
+
return respCommand.payload || []
|
|
463
480
|
}
|
|
464
481
|
|
|
465
482
|
/**
|
|
@@ -506,9 +523,8 @@ class InvocationContext {
|
|
|
506
523
|
for (let i = 0; i < newArray.length; i++) {
|
|
507
524
|
newArray[i] = typeof Object
|
|
508
525
|
}
|
|
509
|
-
const args = [delegatesCacheInstance.addDelegate(payloadItem), RuntimeName.Nodejs]
|
|
510
|
-
|
|
511
|
-
)
|
|
526
|
+
const args = [delegatesCacheInstance.addDelegate(payloadItem), RuntimeName.Nodejs]
|
|
527
|
+
args.push(...newArray)
|
|
512
528
|
return new Command(this.#runtimeName, CommandType.PassDelegate, args)
|
|
513
529
|
} else if (TypesHandler.isPrimitiveOrNullOrUndefined(payloadItem)) {
|
|
514
530
|
return new Command(this.#runtimeName, CommandType.Value, [payloadItem])
|
|
@@ -521,6 +537,49 @@ class InvocationContext {
|
|
|
521
537
|
)
|
|
522
538
|
}
|
|
523
539
|
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Process UpdateInvocationContext commands in the provided responseCommand payload.
|
|
543
|
+
* For each UpdateInvocationContext command, set the referenced InvocationContext's currentCommand to a Reference command,
|
|
544
|
+
* remove that InvocationContext from the static map and remove UpdateInvocationContext items from response payload.
|
|
545
|
+
* @param {Command} responseCommand
|
|
546
|
+
* @returns {Command}
|
|
547
|
+
*/
|
|
548
|
+
#processUpdateInvocationContextCommands(responseCommand) {
|
|
549
|
+
if (!responseCommand?.payload?.length) {
|
|
550
|
+
return responseCommand
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const commandsToUpdate = responseCommand.payload.filter(
|
|
554
|
+
(/** @type {unknown} */ item) => item instanceof Command && item.commandType === CommandType.UpdateInvocationContext
|
|
555
|
+
)
|
|
556
|
+
|
|
557
|
+
if (commandsToUpdate.length === 0) {
|
|
558
|
+
return responseCommand
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
const updatedPayload = new Set(responseCommand.payload)
|
|
562
|
+
|
|
563
|
+
for (const cmd of commandsToUpdate) {
|
|
564
|
+
if (cmd.payload?.length >= 2) {
|
|
565
|
+
const contextGuid = String(cmd.payload[0])
|
|
566
|
+
const instanceGuid = cmd.payload[1]
|
|
567
|
+
const invCtx = InvocationContext._invocationContexts.get(contextGuid)
|
|
568
|
+
|
|
569
|
+
if (invCtx) {
|
|
570
|
+
invCtx.#currentCommand = new Command(invCtx.#runtimeName, CommandType.Reference, [instanceGuid])
|
|
571
|
+
InvocationContext._invocationContexts.delete(contextGuid)
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
updatedPayload.delete(cmd)
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
return new Command(
|
|
578
|
+
responseCommand.runtimeName,
|
|
579
|
+
responseCommand.commandType,
|
|
580
|
+
Array.from(updatedPayload)
|
|
581
|
+
)
|
|
582
|
+
}
|
|
524
583
|
}
|
|
525
584
|
|
|
526
585
|
export { InvocationContext }
|
package/lib/sdk/Javonet.js
CHANGED
|
@@ -12,6 +12,7 @@ import { WsConnectionData } from '../utils/connectionData/WsConnectionData.js'
|
|
|
12
12
|
import { UtilsConst } from '../utils/UtilsConst.js'
|
|
13
13
|
import { ConfigSourceResolver } from './configuration/ConfigSourceResolver.js'
|
|
14
14
|
import { ConfigPriority } from './configuration/ConfigPriority.js'
|
|
15
|
+
import { ComplexTypeResolver } from './tools/ComplexTypeResolver.js'
|
|
15
16
|
|
|
16
17
|
/** @typedef {import('../types.d.ts').ConfigSource} ConfigSource */
|
|
17
18
|
|
|
@@ -132,4 +133,5 @@ export {
|
|
|
132
133
|
CommandSerializer,
|
|
133
134
|
CommandDeserializer,
|
|
134
135
|
ConfigPriority,
|
|
136
|
+
ComplexTypeResolver,
|
|
135
137
|
}
|