diff --git a/hogvm/__tests__/__snapshots__/typeof.hoge b/hogvm/__tests__/__snapshots__/typeof.hoge new file mode 100644 index 00000000000..873e6d46efb --- /dev/null +++ b/hogvm/__tests__/__snapshots__/typeof.hoge @@ -0,0 +1,5 @@ +["_H", 1, 52, "test", 1, 0, 11, 36, 0, 2, "typeof", 1, 2, "print", 1, 35, 31, 38, 53, 0, 32, "hello world", 36, 0, 54, +1, 35, 33, 123, 36, 0, 54, 1, 35, 34, 1.23, 36, 0, 54, 1, 35, 29, 36, 0, 54, 1, 35, 30, 36, 0, 54, 1, 35, 31, 36, 0, 54, +1, 35, 42, 0, 36, 0, 54, 1, 35, 43, 0, 36, 0, 54, 1, 35, 33, 1, 33, 2, 33, 3, 44, 3, 36, 0, 54, 1, 35, 52, "lambda", 0, +0, 6, 33, 2, 33, 1, 6, 38, 53, 0, 36, 0, 54, 1, 35, 32, "2021-01-01T00:00:00Z", 2, "toDateTime", 1, 36, 0, 54, 1, 35, +32, "2021-01-01", 2, "toDate", 1, 36, 0, 54, 1, 35, 32, "BigError", 32, "message", 2, "Error", 2, 36, 0, 54, 1, 35, 35] diff --git a/hogvm/__tests__/__snapshots__/typeof.stdout b/hogvm/__tests__/__snapshots__/typeof.stdout new file mode 100644 index 00000000000..ea10db20005 --- /dev/null +++ b/hogvm/__tests__/__snapshots__/typeof.stdout @@ -0,0 +1,13 @@ +string +integer +float +boolean +boolean +null +object +array +tuple +function +datetime +date +error diff --git a/hogvm/__tests__/typeof.hog b/hogvm/__tests__/typeof.hog new file mode 100644 index 00000000000..2ad529cbaaa --- /dev/null +++ b/hogvm/__tests__/typeof.hog @@ -0,0 +1,17 @@ +fun test(obj) { + print(typeof(obj)) +} + +test('hello world') +test(123) +test(1.23) +test(true) +test(false) +test(null) +test({}) +test([]) +test((1,2,3)) +test(() -> 1 + 2) +test(toDateTime('2021-01-01T00:00:00Z')) +test(toDate('2021-01-01')) +test(Error('BigError', 'message')) diff --git a/hogvm/python/stl/__init__.py b/hogvm/python/stl/__init__.py index fb69d9f477d..feaae8a899a 100644 --- a/hogvm/python/stl/__init__.py +++ b/hogvm/python/stl/__init__.py @@ -314,6 +314,34 @@ def _formatDateTime(args: list[Any], team: Optional["Team"], stdout: Optional[li return formatDateTime(args[0], args[1], args[2] if len(args) > 2 else None) +def _typeof(args: list[Any], team: Optional["Team"], stdout: Optional[list[str]], timeout: float) -> str: + if args[0] is None: + return "null" + elif is_hog_datetime(args[0]): + return "datetime" + elif is_hog_date(args[0]): + return "date" + elif is_hog_error(args[0]): + return "error" + elif is_hog_callable(args[0]) or is_hog_closure(args[0]): + return "function" + elif isinstance(args[0], list): + return "array" + elif isinstance(args[0], tuple): + return "tuple" + elif isinstance(args[0], dict): + return "object" + elif args[0] is True or args[0] is False: + return "boolean" + elif isinstance(args[0], int): + return "integer" + elif isinstance(args[0], float): + return "float" + elif isinstance(args[0], str): + return "string" + return "unknown" + + STL: dict[str, STLFunction] = { "concat": STLFunction( fn=lambda args, team, stdout, timeout: "".join( @@ -424,6 +452,7 @@ STL: dict[str, STLFunction] = { minArgs=0, maxArgs=2, ), + "typeof": STLFunction(fn=_typeof, minArgs=1, maxArgs=1), # only in python, async function in nodejs "sleep": STLFunction(fn=sleep, minArgs=1, maxArgs=1), "run": STLFunction(fn=run, minArgs=1, maxArgs=1), diff --git a/hogvm/typescript/package.json b/hogvm/typescript/package.json index d1bebac9b8e..31cb1a812ec 100644 --- a/hogvm/typescript/package.json +++ b/hogvm/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@posthog/hogvm", - "version": "1.0.42", + "version": "1.0.43", "description": "PostHog Hog Virtual Machine", "types": "dist/index.d.ts", "source": "src/index.ts", diff --git a/hogvm/typescript/src/stl/stl.ts b/hogvm/typescript/src/stl/stl.ts index 332e79da60e..1e828273090 100644 --- a/hogvm/typescript/src/stl/stl.ts +++ b/hogvm/typescript/src/stl/stl.ts @@ -591,6 +591,37 @@ export const STL: Record = { minArgs: 0, maxArgs: 2, }, + typeof: { + fn: (args) => { + if (args[0] === null || args[0] === undefined) { + return 'null' + } else if (isHogDateTime(args[0])) { + return 'datetime' + } else if (isHogDate(args[0])) { + return 'date' + } else if (isHogError(args[0])) { + return 'error' + } else if (isHogCallable(args[0]) || isHogClosure(args[0])) { + return 'function' + } else if (Array.isArray(args[0])) { + if ((args[0] as any).__isHogTuple) { + return 'tuple' + } + return 'array' + } else if (typeof args[0] === 'object') { + return 'object' + } else if (typeof args[0] === 'number') { + return Number.isInteger(args[0]) ? 'integer' : 'float' + } else if (typeof args[0] === 'string') { + return 'string' + } else if (typeof args[0] === 'boolean') { + return 'boolean' + } + return 'unknown' + }, + minArgs: 1, + maxArgs: 1, + }, } export const ASYNC_STL: Record = { diff --git a/package.json b/package.json index ff0c2031dff..8e811c720c5 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "@medv/finder": "^3.1.0", "@microlink/react-json-view": "^1.21.3", "@monaco-editor/react": "4.6.0", - "@posthog/hogvm": "^1.0.42", + "@posthog/hogvm": "^1.0.43", "@posthog/icons": "0.7.3", "@posthog/plugin-scaffold": "^1.4.4", "@react-hook/size": "^2.1.2", diff --git a/plugin-server/package.json b/plugin-server/package.json index 654e9886b65..e78a741b1f1 100644 --- a/plugin-server/package.json +++ b/plugin-server/package.json @@ -53,7 +53,7 @@ "@maxmind/geoip2-node": "^3.4.0", "@posthog/clickhouse": "^1.7.0", "@posthog/cyclotron": "file:../rust/cyclotron-node", - "@posthog/hogvm": "^1.0.42", + "@posthog/hogvm": "^1.0.43", "@posthog/plugin-scaffold": "1.4.4", "@sentry/node": "^7.49.0", "@sentry/profiling-node": "^0.3.0", diff --git a/plugin-server/pnpm-lock.yaml b/plugin-server/pnpm-lock.yaml index 1149bb05088..d3709d54436 100644 --- a/plugin-server/pnpm-lock.yaml +++ b/plugin-server/pnpm-lock.yaml @@ -47,8 +47,8 @@ dependencies: specifier: file:../rust/cyclotron-node version: file:../rust/cyclotron-node '@posthog/hogvm': - specifier: ^1.0.42 - version: 1.0.42(luxon@3.4.4) + specifier: ^1.0.43 + version: 1.0.43(luxon@3.4.4) '@posthog/plugin-scaffold': specifier: 1.4.4 version: 1.4.4 @@ -3116,8 +3116,8 @@ packages: engines: {node: '>=12'} dev: false - /@posthog/hogvm@1.0.42(luxon@3.4.4): - resolution: {integrity: sha512-vrIl2XVtlBqkPOmF65pd8WYFFnv+Mtc2kgmJga9CDo8obsn/aMcYf4UrKNcXsK9XAz4vxw7ItwcgrD/Hb6WjuQ==} + /@posthog/hogvm@1.0.43(luxon@3.4.4): + resolution: {integrity: sha512-VjZ7uwxlWB5XoZNoH/xhxv3SVikvrcMuTV+LjV7j6Ddw1pFDvWlebMHNLgtrUZKChrs+ZhOOE6KWk5qPDv48bg==} peerDependencies: luxon: ^3.4.4 dependencies: diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 50be2444d44..b61f61ad48f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,8 +53,8 @@ dependencies: specifier: 4.6.0 version: 4.6.0(monaco-editor@0.49.0)(react-dom@18.2.0)(react@18.2.0) '@posthog/hogvm': - specifier: ^1.0.42 - version: 1.0.42(luxon@3.5.0) + specifier: ^1.0.43 + version: 1.0.43(luxon@3.5.0) '@posthog/icons': specifier: 0.7.3 version: 0.7.3(react-dom@18.2.0)(react@18.2.0) @@ -5414,8 +5414,8 @@ packages: resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==} dev: false - /@posthog/hogvm@1.0.42(luxon@3.5.0): - resolution: {integrity: sha512-vrIl2XVtlBqkPOmF65pd8WYFFnv+Mtc2kgmJga9CDo8obsn/aMcYf4UrKNcXsK9XAz4vxw7ItwcgrD/Hb6WjuQ==} + /@posthog/hogvm@1.0.43(luxon@3.5.0): + resolution: {integrity: sha512-VjZ7uwxlWB5XoZNoH/xhxv3SVikvrcMuTV+LjV7j6Ddw1pFDvWlebMHNLgtrUZKChrs+ZhOOE6KWk5qPDv48bg==} peerDependencies: luxon: ^3.4.4 dependencies: