triangulum 0.40.2__tar.gz
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.
- triangulum-0.40.2/.gitignore +10 -0
- triangulum-0.40.2/PKG-INFO +87 -0
- triangulum-0.40.2/README.md +75 -0
- triangulum-0.40.2/hatch_build.py +134 -0
- triangulum-0.40.2/pyproject.toml +45 -0
- triangulum-0.40.2/src/triangulum/__init__.py +13 -0
- triangulum-0.40.2/src/triangulum/errors.py +13 -0
- triangulum-0.40.2/src/triangulum/executor.py +73 -0
- triangulum-0.40.2/src/triangulum/js/.gitkeep +0 -0
- triangulum-0.40.2/src/triangulum/js/single-validation.js +176291 -0
- triangulum-0.40.2/src/triangulum/validation.py +84 -0
- triangulum-0.40.2/tasks.py +94 -0
- triangulum-0.40.2/tests/conftest.py +32 -0
- triangulum-0.40.2/tests/factories.py +137 -0
- triangulum-0.40.2/tests/test_executor.py +54 -0
- triangulum-0.40.2/tests/test_validation.py +185 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: triangulum
|
|
3
|
+
Version: 0.40.2
|
|
4
|
+
Summary: Triangulum is the CodeZero validation layer
|
|
5
|
+
Project-URL: Homepage, https://github.com/code0-tech/triangulum
|
|
6
|
+
Project-URL: Changelog, https://github.com/code0-tech/triangulum/releases
|
|
7
|
+
Author: CodeZero
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Requires-Dist: tucana>=0.0.83
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# Triangulum Python Package
|
|
14
|
+
|
|
15
|
+
Python bindings for the [Triangulum](https://github.com/code0-tech/triangulum) validation layer. This package wraps the TypeScript library and a bundled [Bun](https://bun.sh) runtime to validate flows using the TypeScript compiler.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install triangulum # or: uv add triangulum
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Platform specific wheels with a bundled bun binary are published for:
|
|
24
|
+
|
|
25
|
+
- `macosx_11_0_arm64` (macOS Apple Silicon)
|
|
26
|
+
- `macosx_10_12_x86_64` (macOS Intel)
|
|
27
|
+
- `manylinux_2_17_x86_64` (Linux x64)
|
|
28
|
+
- `musllinux_1_2_x86_64` (Linux x64 musl)
|
|
29
|
+
- `manylinux_2_17_aarch64` (Linux ARM64)
|
|
30
|
+
- `musllinux_1_2_aarch64` (Linux ARM64 musl)
|
|
31
|
+
|
|
32
|
+
For any other platform pip falls back to the pure python wheel, which requires `bun` on `PATH`.
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from triangulum import Validation
|
|
38
|
+
|
|
39
|
+
result = Validation(flow, function_definitions, data_types).validate()
|
|
40
|
+
|
|
41
|
+
result.is_valid # => True / False
|
|
42
|
+
result.return_type # => "void"
|
|
43
|
+
result.diagnostics # => [Diagnostic, ...]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The arguments are [Tucana](https://github.com/code0-tech/tucana) protobuf messages:
|
|
47
|
+
|
|
48
|
+
- `flow` — `tucana.generated.shared.flow_pb2.ValidationFlow`
|
|
49
|
+
- `function_definitions` — `list[tucana.generated.shared.function_pb2.FunctionDefinition]`
|
|
50
|
+
- `data_types` — `list[tucana.generated.shared.data_type_pb2.DefinitionDataType]`
|
|
51
|
+
|
|
52
|
+
### Diagnostics
|
|
53
|
+
|
|
54
|
+
Each diagnostic contains:
|
|
55
|
+
|
|
56
|
+
| Field | Description |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `message` | Human-readable error description |
|
|
59
|
+
| `code` | TypeScript diagnostic code |
|
|
60
|
+
| `severity` | `"error"` or `"warning"` |
|
|
61
|
+
| `node_id` | ID of the node that caused the error |
|
|
62
|
+
| `parameter_index` | Index of the parameter that caused the error |
|
|
63
|
+
|
|
64
|
+
## Development
|
|
65
|
+
|
|
66
|
+
Prerequisites: [Bun](https://bun.sh) installed locally, and the TypeScript package built in the repository root (`npm ci && npm run build`, plus `npm ci` in `entrypoint/`).
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
cd python
|
|
70
|
+
uv sync
|
|
71
|
+
uv run python tasks.py entrypoints # bundles the TypeScript entrypoint into JS
|
|
72
|
+
uv run pytest
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Building wheels
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
uv run python tasks.py wheels
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
This bundles the entrypoint, downloads the bun binaries (with SHA256 checksum verification) for all supported platforms and writes the sdist, the pure python wheel and one wheel per platform to `dist/`.
|
|
82
|
+
|
|
83
|
+
Bun's version and checksums live in [`bun.json`](../bun.json) in the repository root, shared with the ruby gem.
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
See [LICENSE](../LICENSE).
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Triangulum Python Package
|
|
2
|
+
|
|
3
|
+
Python bindings for the [Triangulum](https://github.com/code0-tech/triangulum) validation layer. This package wraps the TypeScript library and a bundled [Bun](https://bun.sh) runtime to validate flows using the TypeScript compiler.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install triangulum # or: uv add triangulum
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Platform specific wheels with a bundled bun binary are published for:
|
|
12
|
+
|
|
13
|
+
- `macosx_11_0_arm64` (macOS Apple Silicon)
|
|
14
|
+
- `macosx_10_12_x86_64` (macOS Intel)
|
|
15
|
+
- `manylinux_2_17_x86_64` (Linux x64)
|
|
16
|
+
- `musllinux_1_2_x86_64` (Linux x64 musl)
|
|
17
|
+
- `manylinux_2_17_aarch64` (Linux ARM64)
|
|
18
|
+
- `musllinux_1_2_aarch64` (Linux ARM64 musl)
|
|
19
|
+
|
|
20
|
+
For any other platform pip falls back to the pure python wheel, which requires `bun` on `PATH`.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from triangulum import Validation
|
|
26
|
+
|
|
27
|
+
result = Validation(flow, function_definitions, data_types).validate()
|
|
28
|
+
|
|
29
|
+
result.is_valid # => True / False
|
|
30
|
+
result.return_type # => "void"
|
|
31
|
+
result.diagnostics # => [Diagnostic, ...]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The arguments are [Tucana](https://github.com/code0-tech/tucana) protobuf messages:
|
|
35
|
+
|
|
36
|
+
- `flow` — `tucana.generated.shared.flow_pb2.ValidationFlow`
|
|
37
|
+
- `function_definitions` — `list[tucana.generated.shared.function_pb2.FunctionDefinition]`
|
|
38
|
+
- `data_types` — `list[tucana.generated.shared.data_type_pb2.DefinitionDataType]`
|
|
39
|
+
|
|
40
|
+
### Diagnostics
|
|
41
|
+
|
|
42
|
+
Each diagnostic contains:
|
|
43
|
+
|
|
44
|
+
| Field | Description |
|
|
45
|
+
|---|---|
|
|
46
|
+
| `message` | Human-readable error description |
|
|
47
|
+
| `code` | TypeScript diagnostic code |
|
|
48
|
+
| `severity` | `"error"` or `"warning"` |
|
|
49
|
+
| `node_id` | ID of the node that caused the error |
|
|
50
|
+
| `parameter_index` | Index of the parameter that caused the error |
|
|
51
|
+
|
|
52
|
+
## Development
|
|
53
|
+
|
|
54
|
+
Prerequisites: [Bun](https://bun.sh) installed locally, and the TypeScript package built in the repository root (`npm ci && npm run build`, plus `npm ci` in `entrypoint/`).
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
cd python
|
|
58
|
+
uv sync
|
|
59
|
+
uv run python tasks.py entrypoints # bundles the TypeScript entrypoint into JS
|
|
60
|
+
uv run pytest
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Building wheels
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
uv run python tasks.py wheels
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
This bundles the entrypoint, downloads the bun binaries (with SHA256 checksum verification) for all supported platforms and writes the sdist, the pure python wheel and one wheel per platform to `dist/`.
|
|
70
|
+
|
|
71
|
+
Bun's version and checksums live in [`bun.json`](../bun.json) in the repository root, shared with the ruby gem.
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
See [LICENSE](../LICENSE).
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""Wheel build hook that bundles a platform specific bun binary.
|
|
2
|
+
|
|
3
|
+
The pure python wheel built without ``TRIANGULUM_WHEEL_PLATFORM`` expects ``bun``
|
|
4
|
+
on ``PATH``. Setting the variable to one of the keys of :data:`BUN_PLATFORMS`
|
|
5
|
+
produces a platform specific wheel with the matching bun binary embedded at
|
|
6
|
+
``triangulum/exe/bun``, which mirrors the platform gems built by ``gem/``.
|
|
7
|
+
|
|
8
|
+
Binaries are not downloaded during the build; run ``python tasks.py download``
|
|
9
|
+
first (``tasks.py wheels`` does both).
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import hashlib
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import shutil
|
|
16
|
+
import stat
|
|
17
|
+
import urllib.request
|
|
18
|
+
import zipfile
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
|
22
|
+
|
|
23
|
+
HERE = Path(__file__).parent
|
|
24
|
+
|
|
25
|
+
# Bun release metadata is shared with the ruby gem, see <repo root>/bun.json.
|
|
26
|
+
# It only exists in a repository checkout, not in the published sdist, so the
|
|
27
|
+
# metadata is loaded lazily and only platform wheels depend on it.
|
|
28
|
+
BUN_METADATA_PATH = HERE.parent / "bun.json"
|
|
29
|
+
|
|
30
|
+
VENDOR_DIR = HERE / "vendor" / "exe"
|
|
31
|
+
|
|
32
|
+
ENTRYPOINTS = ("single-validation",)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _load_metadata():
|
|
36
|
+
if not BUN_METADATA_PATH.is_file():
|
|
37
|
+
raise RuntimeError(
|
|
38
|
+
f"{BUN_METADATA_PATH} not found. Platform wheels can only be built "
|
|
39
|
+
f"from a triangulum repository checkout."
|
|
40
|
+
)
|
|
41
|
+
return json.loads(BUN_METADATA_PATH.read_text())
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def bun_version():
|
|
45
|
+
return _load_metadata()["version"]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def bun_platforms():
|
|
49
|
+
"""wheel platform tag => (bun release zip filename, sha256 checksum)"""
|
|
50
|
+
return {p["wheel"]: (p["zip"], p["sha256"]) for p in _load_metadata()["platforms"]}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def bun_download_url(filename):
|
|
54
|
+
return f"https://github.com/oven-sh/bun/releases/download/bun-{bun_version()}/{filename}"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def bun_path(platform):
|
|
58
|
+
return VENDOR_DIR / platform / "bun"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def download_bun(platform):
|
|
62
|
+
"""Download and extract the bun binary for ``platform``, verifying its checksum."""
|
|
63
|
+
zip_filename, expected_checksum = bun_platforms()[platform]
|
|
64
|
+
destination = bun_path(platform)
|
|
65
|
+
|
|
66
|
+
if destination.is_file():
|
|
67
|
+
return destination
|
|
68
|
+
|
|
69
|
+
url = bun_download_url(zip_filename)
|
|
70
|
+
print(f"Downloading {destination} from {url} ...")
|
|
71
|
+
|
|
72
|
+
with urllib.request.urlopen(url) as response:
|
|
73
|
+
zip_data = response.read()
|
|
74
|
+
|
|
75
|
+
actual_checksum = hashlib.sha256(zip_data).hexdigest()
|
|
76
|
+
if actual_checksum != expected_checksum:
|
|
77
|
+
raise RuntimeError(
|
|
78
|
+
f"Checksum mismatch for {zip_filename}: "
|
|
79
|
+
f"expected {expected_checksum}, got {actual_checksum}"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
83
|
+
tmp_zip = destination.with_suffix(".zip")
|
|
84
|
+
tmp_zip.write_bytes(zip_data)
|
|
85
|
+
try:
|
|
86
|
+
with zipfile.ZipFile(tmp_zip) as archive:
|
|
87
|
+
entry = next(
|
|
88
|
+
(e for e in archive.namelist() if Path(e).name == "bun"),
|
|
89
|
+
None,
|
|
90
|
+
)
|
|
91
|
+
if entry is None:
|
|
92
|
+
raise RuntimeError(f"bun binary not found in {zip_filename}")
|
|
93
|
+
|
|
94
|
+
with archive.open(entry) as source, destination.open("wb") as target:
|
|
95
|
+
shutil.copyfileobj(source, target)
|
|
96
|
+
finally:
|
|
97
|
+
tmp_zip.unlink()
|
|
98
|
+
|
|
99
|
+
destination.chmod(destination.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
100
|
+
|
|
101
|
+
return destination
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class CustomBuildHook(BuildHookInterface):
|
|
105
|
+
def initialize(self, version, build_data):
|
|
106
|
+
# An editable install is used for development, where the entrypoints are
|
|
107
|
+
# bundled separately via `python tasks.py entrypoints`.
|
|
108
|
+
for entrypoint in ENTRYPOINTS if version != "editable" else ():
|
|
109
|
+
bundle = HERE / "src" / "triangulum" / "js" / f"{entrypoint}.js"
|
|
110
|
+
if not bundle.is_file():
|
|
111
|
+
raise RuntimeError(
|
|
112
|
+
f"{bundle} is missing. Run `python tasks.py entrypoints` before building."
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
platform = os.environ.get("TRIANGULUM_WHEEL_PLATFORM")
|
|
116
|
+
if not platform:
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
platforms = bun_platforms()
|
|
120
|
+
if platform not in platforms:
|
|
121
|
+
raise RuntimeError(
|
|
122
|
+
f"Unknown TRIANGULUM_WHEEL_PLATFORM {platform!r}, "
|
|
123
|
+
f"expected one of {', '.join(sorted(platforms))}"
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
binary = bun_path(platform)
|
|
127
|
+
if not binary.is_file():
|
|
128
|
+
raise RuntimeError(
|
|
129
|
+
f"{binary} is missing. Run `python tasks.py download` before building."
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
build_data["pure_python"] = False
|
|
133
|
+
build_data["tag"] = f"py3-none-{platform}"
|
|
134
|
+
build_data["force_include"][str(binary)] = "triangulum/exe/bun"
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "triangulum"
|
|
7
|
+
version = "0.40.2"
|
|
8
|
+
description = "Triangulum is the CodeZero validation layer"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [{ name = "CodeZero" }]
|
|
13
|
+
dependencies = [
|
|
14
|
+
"tucana>=0.0.83",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.urls]
|
|
18
|
+
Homepage = "https://github.com/code0-tech/triangulum"
|
|
19
|
+
Changelog = "https://github.com/code0-tech/triangulum/releases"
|
|
20
|
+
|
|
21
|
+
[dependency-groups]
|
|
22
|
+
dev = [
|
|
23
|
+
"build>=1.2",
|
|
24
|
+
"hatchling>=1.27",
|
|
25
|
+
"pytest>=8.0",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[tool.hatch.build]
|
|
29
|
+
# The bundled JS entrypoints are gitignored build artifacts, but belong into the
|
|
30
|
+
# sdist and every wheel.
|
|
31
|
+
artifacts = ["src/triangulum/js/*.js"]
|
|
32
|
+
|
|
33
|
+
[tool.hatch.build.targets.wheel]
|
|
34
|
+
packages = ["src/triangulum"]
|
|
35
|
+
|
|
36
|
+
[tool.hatch.build.targets.wheel.hooks.custom]
|
|
37
|
+
path = "hatch_build.py"
|
|
38
|
+
|
|
39
|
+
[tool.hatch.build.targets.sdist]
|
|
40
|
+
include = ["src/triangulum", "tests", "hatch_build.py", "tasks.py", "README.md"]
|
|
41
|
+
|
|
42
|
+
[tool.pytest.ini_options]
|
|
43
|
+
# Project root on sys.path so ``import tests.factories`` resolves.
|
|
44
|
+
pythonpath = ["."]
|
|
45
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Python bindings for the Triangulum validation layer."""
|
|
2
|
+
|
|
3
|
+
from triangulum.errors import BunNotFound, Error, TriangulumFailed
|
|
4
|
+
from triangulum.validation import Diagnostic, Result, Validation
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"BunNotFound",
|
|
8
|
+
"Diagnostic",
|
|
9
|
+
"Error",
|
|
10
|
+
"Result",
|
|
11
|
+
"TriangulumFailed",
|
|
12
|
+
"Validation",
|
|
13
|
+
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Exceptions raised by triangulum."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Error(Exception):
|
|
5
|
+
"""Base class for every triangulum error."""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TriangulumFailed(Error):
|
|
9
|
+
"""The bun subprocess exited with a failure."""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BunNotFound(Error):
|
|
13
|
+
"""No bun executable is available to run the entrypoints with."""
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Runs the bundled TypeScript entrypoints through bun."""
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
import shutil
|
|
5
|
+
import subprocess
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from triangulum.errors import BunNotFound, TriangulumFailed
|
|
9
|
+
|
|
10
|
+
JS_DIR = Path(__file__).parent / "js"
|
|
11
|
+
|
|
12
|
+
# Platform wheels embed the matching bun binary here, see hatch_build.py. The
|
|
13
|
+
# pure python wheel does not, and falls back to bun on PATH.
|
|
14
|
+
BUNDLED_BUN = Path(__file__).parent / "exe" / "bun"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def bun():
|
|
18
|
+
"""Path to the bun executable to run the entrypoints with."""
|
|
19
|
+
if BUNDLED_BUN.is_file():
|
|
20
|
+
return str(BUNDLED_BUN)
|
|
21
|
+
|
|
22
|
+
found = shutil.which("bun")
|
|
23
|
+
if found is None:
|
|
24
|
+
raise BunNotFound(
|
|
25
|
+
"No bundled bun binary found and no 'bun' on PATH. Install bun "
|
|
26
|
+
"(https://bun.sh) or use a platform specific triangulum wheel."
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
return found
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def run_ts_triangulum(entrypoint, payload):
|
|
33
|
+
"""Run ``entrypoint`` with ``payload`` on stdin and return its stdout."""
|
|
34
|
+
process = subprocess.run(
|
|
35
|
+
[bun(), "run", str(entrypoint)],
|
|
36
|
+
input=payload,
|
|
37
|
+
capture_output=True,
|
|
38
|
+
text=True,
|
|
39
|
+
check=False,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
if process.returncode != 0:
|
|
43
|
+
if process.returncode < 0:
|
|
44
|
+
status_info = f"SIGNAL: {-process.returncode}"
|
|
45
|
+
else:
|
|
46
|
+
status_info = f"STATUS: {process.returncode}"
|
|
47
|
+
|
|
48
|
+
raise TriangulumFailed(
|
|
49
|
+
f"{status_info}\n\nOUT:\n{process.stdout}\n\nERR:\n{process.stderr}"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
return process.stdout
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _encode(message):
|
|
56
|
+
return base64.b64encode(message.SerializeToString()).decode("ascii")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def serialize_input(flow, function_definitions, data_types):
|
|
60
|
+
"""Serialize the protobuf messages into the entrypoint's stdin format.
|
|
61
|
+
|
|
62
|
+
One base64 encoded message per line, the three groups separated by an empty
|
|
63
|
+
line. Mirrors ``Triangulum::Validation#serialize_input`` in the ruby gem.
|
|
64
|
+
"""
|
|
65
|
+
lines = [_encode(flow), ""]
|
|
66
|
+
|
|
67
|
+
lines += [_encode(fd) for fd in function_definitions]
|
|
68
|
+
lines.append("")
|
|
69
|
+
|
|
70
|
+
lines += [_encode(dt) for dt in data_types]
|
|
71
|
+
lines.append("")
|
|
72
|
+
|
|
73
|
+
return "\n".join(lines)
|
|
File without changes
|