Skip to content

Commit

Permalink
Merge JavaScript functions. (#207)
Browse files Browse the repository at this point in the history
  • Loading branch information
benmusson authored Dec 8, 2024
1 parent ce7af72 commit 4d7f150
Show file tree
Hide file tree
Showing 42 changed files with 934 additions and 385 deletions.
5 changes: 5 additions & 0 deletions .changeset/brave-zoos-leave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@embr-modules/periscope': patch
---

(Scripting) Added `system.perspective.runJavaScriptBlocking()` and `system.perspective.runJavaScriptAsync()` functions.
5 changes: 5 additions & 0 deletions .changeset/eight-guests-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@embr-js/utils': minor
---

(BREAKING) `toFunction` now throws an error if function parsing fails. This is a breaking change from the previous behavior.
6 changes: 6 additions & 0 deletions .changeset/famous-hotels-care.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@embr-js/utils': minor
---

(`toFunction`) Add support for `async` function parsing.
(`isAsyncFunction`) Add utility function for matching `async` functions.
5 changes: 5 additions & 0 deletions .changeset/green-crews-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@embr-jvm/core-common': minor
---

(BREAKING) `PyArgOverloadBuilder` now works with KTypes instead of KClasses. This is to allow for nullability checks (KType contains nullability information).
1 change: 1 addition & 0 deletions .ignition-container.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0aea4786559d872348974f18cb5af77e21147ca7c7d3001a8c8b705e24f67f7c,http://localhost:51307
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ package com.mussonindustrial.embr.common.scripting

import com.inductiveautomation.ignition.common.TypeUtilities
import com.inductiveautomation.ignition.common.script.PyArgParser
import kotlin.jvm.optionals.getOrNull
import kotlin.reflect.javaType
import org.python.core.Py
import org.python.core.PyObject

class PyArgOverload(
val name: String,
private val functions: Map<FunctionSignature, (args: Array<Any>) -> Any?>
private val functions: Map<FunctionSignature, (args: Array<Any?>) -> Any?>
) {
@OptIn(ExperimentalStdlibApi::class)
fun call(
args: Array<PyObject>,
keywords: Array<String>,
Expand All @@ -20,20 +23,30 @@ class PyArgOverload(
args,
keywords,
signatures.map { it.name }.toTypedArray(),
signatures.map { it.type.java }.toTypedArray(),
signatures.map { it.type.javaType as Class<*> }.toTypedArray(),
this.name,
)

functions.forEach { f ->
val signature = f.key
val function = f.value
if (signature.parameters.all { argParser.containsKey(it.name) }) {
if (
signature.parameters.all {
argParser.containsKey(it.name) || it.type.isMarkedNullable
}
) {
return function(
signature.parameters
.map {
val pyValue = argParser.getPyObject(it.name).get()
val jValue = TypeUtilities.pyToJava(pyValue)
TypeUtilities.coerce(jValue, it.type.java)
val pyValue = argParser.getPyObject(it.name).getOrNull()
if (pyValue != null) {
val jValue = TypeUtilities.pyToJava(pyValue)
return@map TypeUtilities.coerce(
jValue,
it.type.javaType as Class<*>
)
}
return@map null
}
.toTypedArray(),
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.mussonindustrial.embr.common.scripting

import kotlin.reflect.KClass
import kotlin.reflect.KType

data class FunctionParameter<T : Any>(val name: String, val type: KClass<T>)
data class FunctionParameter(val name: String, val type: KType)

data class FunctionSignature(val parameters: List<FunctionParameter<*>>)
data class FunctionSignature(val parameters: List<FunctionParameter>)

class PyArgOverloadBuilder {
private val functions = mutableMapOf<FunctionSignature, (args: Array<Any>) -> Any?>()
private val functions = mutableMapOf<FunctionSignature, (args: Array<Any?>) -> Any?>()
private var name = "anonymous"

fun setName(name: String): PyArgOverloadBuilder {
Expand All @@ -16,8 +16,8 @@ class PyArgOverloadBuilder {
}

fun addOverload(
function: (args: Array<Any>) -> Any?,
vararg args: Pair<String, KClass<*>>,
function: (args: Array<Any?>) -> Any?,
vararg args: Pair<String, KType>,
): PyArgOverloadBuilder {
val signature =
FunctionSignature(
Expand Down
7 changes: 4 additions & 3 deletions libraries/javascript/utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
export { default as isAsyncFunction } from './isAsyncFunction'
export { default as isCSSVar } from './isCSSVar'
export { default as isFunction } from './isFunction'
export { default as readCSSVar } from './readCSSVar'
export {
default as toFunction,
type UserScript,
type UserScriptParams,
default as toFunction,
type UserScript,
type UserScriptParams,
} from './toFunction'
export { default as transformProps, type PropTransform } from './transformProps'
1 change: 1 addition & 0 deletions libraries/javascript/utils/src/isAsyncFunction/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './isAsyncFunction'
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { it, expect, describe } from 'vitest'

import isFunction from '../../../../../libraries/javascript/utils/src/isAsyncFunction/isAsyncFunction'
import isAsyncFunction from '../../../../../libraries/javascript/utils/src/isAsyncFunction/isAsyncFunction'

describe('isAsyncFunction', () => {
it('false if no arrow function', async () => {
expect(isAsyncFunction('no arrow function here')).toBe(false)
})

it('true if async arrow function', async () => {
expect(isAsyncFunction('async () => arrow function here')).toBe(true)
})

it('true if arrow function with extra spaces', async () => {
expect(isFunction(' async () => arrow function here ')).toBe(
true
)
})

it('true if arrow function with new lines', async () => {
expect(
isFunction(` async () => arrow
function here `)
).toBe(true)
})

it('true if arrow function parameters', async () => {
expect(
isFunction(
' async(parameter1, parameter2) => arrow function here '
)
).toBe(true)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const expression = /^\s*async\s*\(([^)]*?)\)\s*=>/
export default function isAsyncFunction(string: string): boolean {
return expression.test(string)
}
4 changes: 2 additions & 2 deletions libraries/javascript/utils/src/isFunction/isFunction.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const expression = /^[\s\S]*?\(([^)]*?)\)[\s\S]*?=>[\s\S]?([\s\S]*)$/
const expression = /^\s*(?:async\s*)?\(([^)]*?)\)\s*=>\s*([\s\S]*)$/
export default function isFunction(string: string): boolean {
return expression.test(string)
return expression.test(string)
}
Loading

0 comments on commit 4d7f150

Please sign in to comment.