mmobeus-luadata 0.1.7__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.
Files changed (86) hide show
  1. mmobeus_luadata-0.1.7/.github/FUNDING.yml +1 -0
  2. mmobeus_luadata-0.1.7/.github/dependabot.yml +31 -0
  3. mmobeus_luadata-0.1.7/.github/workflows/ci.yml +63 -0
  4. mmobeus_luadata-0.1.7/.github/workflows/pages.yml +42 -0
  5. mmobeus_luadata-0.1.7/.github/workflows/release.yml +311 -0
  6. mmobeus_luadata-0.1.7/.gitignore +9 -0
  7. mmobeus_luadata-0.1.7/.golangci.yml +6 -0
  8. mmobeus_luadata-0.1.7/AGENTS.md +17 -0
  9. mmobeus_luadata-0.1.7/ARCHITECTURE.md +180 -0
  10. mmobeus_luadata-0.1.7/Cargo.lock +510 -0
  11. mmobeus_luadata-0.1.7/Cargo.toml +21 -0
  12. mmobeus_luadata-0.1.7/LICENSE +21 -0
  13. mmobeus_luadata-0.1.7/Makefile +122 -0
  14. mmobeus_luadata-0.1.7/PKG-INFO +10 -0
  15. mmobeus_luadata-0.1.7/README.md +446 -0
  16. mmobeus_luadata-0.1.7/go/.gitignore +2 -0
  17. mmobeus_luadata-0.1.7/go/go.mod +7 -0
  18. mmobeus_luadata-0.1.7/go/go.sum +3 -0
  19. mmobeus_luadata-0.1.7/go/internal/ffi/embed_darwin_amd64.go +10 -0
  20. mmobeus_luadata-0.1.7/go/internal/ffi/embed_darwin_arm64.go +10 -0
  21. mmobeus_luadata-0.1.7/go/internal/ffi/embed_linux_amd64.go +10 -0
  22. mmobeus_luadata-0.1.7/go/internal/ffi/embed_linux_arm64.go +10 -0
  23. mmobeus_luadata-0.1.7/go/internal/ffi/embed_windows_amd64.go +10 -0
  24. mmobeus_luadata-0.1.7/go/internal/ffi/ffi.go +138 -0
  25. mmobeus_luadata-0.1.7/go/internal/ffi/ffi_unix.go +9 -0
  26. mmobeus_luadata-0.1.7/go/internal/ffi/ffi_windows.go +16 -0
  27. mmobeus_luadata-0.1.7/go/internal/ffi/lib/darwin_amd64/libluadata.dylib +0 -0
  28. mmobeus_luadata-0.1.7/go/internal/ffi/lib/darwin_arm64/libluadata.dylib +0 -0
  29. mmobeus_luadata-0.1.7/go/internal/ffi/lib/windows_amd64/luadata.dll +0 -0
  30. mmobeus_luadata-0.1.7/go/luadata.go +115 -0
  31. mmobeus_luadata-0.1.7/go/luadata_test.go +473 -0
  32. mmobeus_luadata-0.1.7/go/options.go +55 -0
  33. mmobeus_luadata-0.1.7/npm/index.d.ts +40 -0
  34. mmobeus_luadata-0.1.7/npm/index.js +39 -0
  35. mmobeus_luadata-0.1.7/npm/package.json +30 -0
  36. mmobeus_luadata-0.1.7/pyproject.toml +23 -0
  37. mmobeus_luadata-0.1.7/python/Cargo.toml +14 -0
  38. mmobeus_luadata-0.1.7/python/src/lib.rs +187 -0
  39. mmobeus_luadata-0.1.7/python/tests/test_convert.py +341 -0
  40. mmobeus_luadata-0.1.7/python/uv.lock +226 -0
  41. mmobeus_luadata-0.1.7/scripts/prepare-release.sh +127 -0
  42. mmobeus_luadata-0.1.7/scripts/release.sh +166 -0
  43. mmobeus_luadata-0.1.7/scripts/validate-folder.sh +65 -0
  44. mmobeus_luadata-0.1.7/src/converter.rs +223 -0
  45. mmobeus_luadata-0.1.7/src/lexer.rs +279 -0
  46. mmobeus_luadata-0.1.7/src/lib.rs +11 -0
  47. mmobeus_luadata-0.1.7/src/options.rs +92 -0
  48. mmobeus_luadata-0.1.7/src/parser.rs +482 -0
  49. mmobeus_luadata-0.1.7/src/types.rs +134 -0
  50. mmobeus_luadata-0.1.7/testdata/invalid/bad_syntax.lua +1 -0
  51. mmobeus_luadata-0.1.7/testdata/invalid/missing_value.lua +1 -0
  52. mmobeus_luadata-0.1.7/testdata/invalid/unterminated_string.lua +1 -0
  53. mmobeus_luadata-0.1.7/testdata/invalid/unterminated_table.lua +1 -0
  54. mmobeus_luadata-0.1.7/testdata/valid/array.lua +1 -0
  55. mmobeus_luadata-0.1.7/testdata/valid/backup.lua.bak +2 -0
  56. mmobeus_luadata-0.1.7/testdata/valid/comments.lua +7 -0
  57. mmobeus_luadata-0.1.7/testdata/valid/nested.lua +8 -0
  58. mmobeus_luadata-0.1.7/testdata/valid/simple.lua +3 -0
  59. mmobeus_luadata-0.1.7/tests/integration_tests.rs +902 -0
  60. mmobeus_luadata-0.1.7/web/app.js +313 -0
  61. mmobeus_luadata-0.1.7/web/docs/gen/examples/01-hello-luadata/example.txt +46 -0
  62. mmobeus_luadata-0.1.7/web/docs/gen/examples/02-multiple-variables/example.txt +40 -0
  63. mmobeus_luadata-0.1.7/web/docs/gen/examples/03-nested-tables/example.txt +33 -0
  64. mmobeus_luadata-0.1.7/web/docs/gen/examples/04-data-types/example.txt +25 -0
  65. mmobeus_luadata-0.1.7/web/docs/gen/examples/05-comments/example.txt +22 -0
  66. mmobeus_luadata-0.1.7/web/docs/gen/examples/06-empty-tables/example.txt +28 -0
  67. mmobeus_luadata-0.1.7/web/docs/gen/examples/07-empty-table-modes/example.txt +66 -0
  68. mmobeus_luadata-0.1.7/web/docs/gen/examples/08-array-detection/example.txt +38 -0
  69. mmobeus_luadata-0.1.7/web/docs/gen/examples/09-array-mode-none/example.txt +44 -0
  70. mmobeus_luadata-0.1.7/web/docs/gen/examples/10-array-mode-index-only/example.txt +42 -0
  71. mmobeus_luadata-0.1.7/web/docs/gen/examples/11-array-mode-sparse/example.txt +67 -0
  72. mmobeus_luadata-0.1.7/web/docs/gen/examples/12-string-transform/example.txt +39 -0
  73. mmobeus_luadata-0.1.7/web/docs/gen/examples/13-string-transform-modes/example.txt +48 -0
  74. mmobeus_luadata-0.1.7/web/docs/gen/examples/14-typed-accessors/example.txt +59 -0
  75. mmobeus_luadata-0.1.7/web/docs/gen/examples/15-maybe-accessors/example.txt +41 -0
  76. mmobeus_luadata-0.1.7/web/docs/gen/examples/16-working-with-pairs/example.txt +49 -0
  77. mmobeus_luadata-0.1.7/web/docs/gen/examples/17-using-the-wasm-module/example.txt +40 -0
  78. mmobeus_luadata-0.1.7/web/docs/gen/examples/18-binary-strings/example.txt +50 -0
  79. mmobeus_luadata-0.1.7/web/docs/gen/go.mod +3 -0
  80. mmobeus_luadata-0.1.7/web/docs/gen/main.go +377 -0
  81. mmobeus_luadata-0.1.7/web/docs/gen/templates/example.html.tmpl +72 -0
  82. mmobeus_luadata-0.1.7/web/docs/gen/templates/index.html.tmpl +26 -0
  83. mmobeus_luadata-0.1.7/web/docs/gen/templates/interactive.js +199 -0
  84. mmobeus_luadata-0.1.7/web/docs/gen/templates/style.css +264 -0
  85. mmobeus_luadata-0.1.7/web/index.html +100 -0
  86. mmobeus_luadata-0.1.7/web/luadata.js +32 -0
@@ -0,0 +1 @@
1
+ github: [mmobeus]
@@ -0,0 +1,31 @@
1
+ version: 2
2
+ updates:
3
+ # Go modules
4
+ - package-ecosystem: 'gomod'
5
+ directory: '/'
6
+ schedule:
7
+ interval: 'weekly'
8
+ day: 'monday'
9
+ time: '09:00'
10
+ open-pull-requests-limit: 5
11
+ labels:
12
+ - 'dependencies'
13
+ - 'go'
14
+ commit-message:
15
+ prefix: 'chore'
16
+ include: 'scope'
17
+
18
+ # GitHub Actions
19
+ - package-ecosystem: 'github-actions'
20
+ directory: '/'
21
+ schedule:
22
+ interval: 'weekly'
23
+ day: 'monday'
24
+ time: '09:00'
25
+ open-pull-requests-limit: 5
26
+ labels:
27
+ - 'dependencies'
28
+ - 'ci/cd'
29
+ commit-message:
30
+ prefix: 'ci'
31
+ include: 'scope'
@@ -0,0 +1,63 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ rust:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v6.0.2
13
+
14
+ - uses: dtolnay/rust-toolchain@stable
15
+ with:
16
+ components: clippy, rustfmt
17
+
18
+ - name: Check formatting
19
+ run: cargo fmt --all -- --check
20
+
21
+ - name: Clippy
22
+ run: cargo clippy --workspace -- -D warnings
23
+
24
+ - name: Test core library
25
+ run: cargo test -p luadata
26
+
27
+ - name: Check Python module
28
+ run: cargo check -p luadata_python
29
+
30
+ - name: Check WASM module
31
+ run: cargo check -p luadata-wasm
32
+
33
+ - name: Build CLI
34
+ run: cargo build -p luadata_cli --release
35
+
36
+ - name: Validate testdata
37
+ run: |
38
+ ./target/release/luadata validate testdata/valid/simple.lua
39
+ ./target/release/luadata validate testdata/valid/array.lua
40
+ ./target/release/luadata validate testdata/valid/nested.lua
41
+ ./target/release/luadata validate testdata/valid/comments.lua
42
+
43
+ go:
44
+ runs-on: ubuntu-latest
45
+ steps:
46
+ - uses: actions/checkout@v6.0.2
47
+
48
+ - uses: dtolnay/rust-toolchain@stable
49
+
50
+ - uses: actions/setup-go@v6.3.0
51
+ with:
52
+ go-version-file: go/go.mod
53
+
54
+ - name: Build Rust cdylib
55
+ run: |
56
+ cargo build -p luadata_clib --release
57
+ mkdir -p bin/clib
58
+ cp target/release/libluadata_clib.so bin/clib/libluadata.so
59
+
60
+ - name: Test Go wrapper
61
+ run: |
62
+ LUADATA_LIB_PATH=${{ github.workspace }}/bin/clib/libluadata.so \
63
+ go test -C go -v ./...
@@ -0,0 +1,42 @@
1
+ name: Deploy to GitHub Pages
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v[0-9]+.[0-9]+.[0-9]+"
7
+
8
+ permissions:
9
+ pages: write
10
+ id-token: write
11
+
12
+ concurrency:
13
+ group: pages
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ deploy:
18
+ runs-on: ubuntu-latest
19
+ environment:
20
+ name: github-pages
21
+ url: ${{ steps.deployment.outputs.page_url }}
22
+ steps:
23
+ - uses: actions/checkout@v6.0.2
24
+
25
+ - uses: dtolnay/rust-toolchain@stable
26
+
27
+ - uses: actions/setup-go@v6.3.0
28
+ with:
29
+ go-version-file: web/docs/gen/go.mod
30
+
31
+ - name: Install wasm-pack
32
+ run: cargo install wasm-pack
33
+
34
+ - name: Build site
35
+ run: make build-site SITE_VERSION=${{ github.ref_name }}
36
+
37
+ - uses: actions/upload-pages-artifact@v4
38
+ with:
39
+ path: bin/web
40
+
41
+ - id: deployment
42
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,311 @@
1
+ name: Release
2
+
3
+ concurrency:
4
+ group: release
5
+ cancel-in-progress: false
6
+
7
+ on:
8
+ push:
9
+ tags:
10
+ - "v*-rc.*"
11
+
12
+ jobs:
13
+ build-clib:
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ include:
18
+ - target: x86_64-unknown-linux-gnu
19
+ runner: ubuntu-latest
20
+ platform: linux_amd64
21
+ lib_name: libluadata_clib.so
22
+ - target: aarch64-unknown-linux-gnu
23
+ runner: ubuntu-24.04-arm
24
+ platform: linux_arm64
25
+ lib_name: libluadata_clib.so
26
+ - target: x86_64-apple-darwin
27
+ runner: macos-15-intel
28
+ platform: darwin_amd64
29
+ lib_name: libluadata_clib.dylib
30
+ - target: aarch64-apple-darwin
31
+ runner: macos-latest
32
+ platform: darwin_arm64
33
+ lib_name: libluadata_clib.dylib
34
+ - target: x86_64-pc-windows-msvc
35
+ runner: windows-latest
36
+ platform: windows_amd64
37
+ lib_name: luadata_clib.dll
38
+
39
+ runs-on: ${{ matrix.runner }}
40
+
41
+ steps:
42
+ - uses: actions/checkout@v6.0.2
43
+
44
+ - uses: dtolnay/rust-toolchain@stable
45
+ with:
46
+ targets: ${{ matrix.target }}
47
+
48
+ - name: Build cdylib
49
+ run: cargo build -p luadata_clib --release --target ${{ matrix.target }}
50
+
51
+ - name: Upload shared library
52
+ uses: actions/upload-artifact@v4
53
+ with:
54
+ name: clib-${{ matrix.platform }}
55
+ path: target/${{ matrix.target }}/release/${{ matrix.lib_name }}
56
+
57
+ test-and-release:
58
+ needs: build-clib
59
+ runs-on: ubuntu-latest
60
+ permissions:
61
+ contents: write
62
+ outputs:
63
+ release_tag: ${{ steps.release_tag.outputs.tag }}
64
+
65
+ steps:
66
+ - uses: actions/checkout@v6.0.2
67
+ with:
68
+ fetch-depth: 0
69
+
70
+ - uses: dtolnay/rust-toolchain@stable
71
+
72
+ - uses: actions/setup-go@v6.3.0
73
+ with:
74
+ go-version-file: go/go.mod
75
+
76
+ - name: Test Rust
77
+ run: cargo test -p luadata
78
+
79
+ - name: Download all shared libraries
80
+ uses: actions/download-artifact@v4
81
+ with:
82
+ pattern: clib-*
83
+ path: clib-artifacts
84
+
85
+ - name: Test Go wrapper
86
+ run: |
87
+ LUADATA_LIB_PATH=${{ github.workspace }}/clib-artifacts/clib-linux_amd64/libluadata_clib.so \
88
+ go test -C go -v ./...
89
+
90
+ - name: Compute release tag
91
+ id: release_tag
92
+ run: |
93
+ RC_TAG="${{ github.ref_name }}"
94
+ RELEASE_TAG="${RC_TAG%%-rc.*}"
95
+ echo "tag=${RELEASE_TAG}" >> "$GITHUB_OUTPUT"
96
+
97
+ - name: Prepare release branch and tag
98
+ run: bash scripts/prepare-release.sh "${{ steps.release_tag.outputs.tag }}" clib-artifacts
99
+
100
+ - name: Rename artifacts with platform
101
+ run: |
102
+ for dir in clib-artifacts/clib-*; do
103
+ platform="${dir##*clib-}"
104
+ for file in "$dir"/*; do
105
+ base="$(basename "$file")"
106
+ name="${base%.*}"
107
+ ext="${base##*.}"
108
+ mv "$file" "$dir/${name}-${platform}.${ext}"
109
+ done
110
+ done
111
+
112
+ - name: Create GitHub Release
113
+ env:
114
+ GH_TOKEN: ${{ github.token }}
115
+ run: |
116
+ gh release create "${{ steps.release_tag.outputs.tag }}" \
117
+ --title "${{ steps.release_tag.outputs.tag }}" \
118
+ --generate-notes \
119
+ clib-artifacts/clib-*/*
120
+
121
+ build-python-wheels:
122
+ needs: test-and-release
123
+ strategy:
124
+ fail-fast: false
125
+ matrix:
126
+ include:
127
+ - runner: ubuntu-latest
128
+ target: x86_64-unknown-linux-gnu
129
+ maturin_args: ""
130
+ - runner: ubuntu-24.04-arm
131
+ target: aarch64-unknown-linux-gnu
132
+ maturin_args: ""
133
+ - runner: macos-15-intel
134
+ target: x86_64-apple-darwin
135
+ maturin_args: ""
136
+ - runner: macos-latest
137
+ target: aarch64-apple-darwin
138
+ maturin_args: ""
139
+ - runner: windows-latest
140
+ target: x86_64-pc-windows-msvc
141
+ maturin_args: ""
142
+
143
+ runs-on: ${{ matrix.runner }}
144
+
145
+ steps:
146
+ - uses: actions/checkout@v6.0.2
147
+ with:
148
+ ref: ${{ needs.test-and-release.outputs.release_tag }}
149
+
150
+ - uses: dtolnay/rust-toolchain@stable
151
+ with:
152
+ targets: ${{ matrix.target }}
153
+
154
+ - uses: actions/setup-python@v5
155
+ with:
156
+ python-version: "3.12"
157
+
158
+ - name: Install maturin
159
+ run: pip install maturin
160
+
161
+ - name: Build wheel
162
+ run: |
163
+ cd python
164
+ maturin build --release --target ${{ matrix.target }} --out ../wheels/ ${{ matrix.maturin_args }}
165
+
166
+ - name: Upload wheel
167
+ uses: actions/upload-artifact@v4
168
+ with:
169
+ name: python-wheel-${{ matrix.target }}
170
+ path: wheels/*.whl
171
+
172
+ build-python-sdist:
173
+ needs: test-and-release
174
+ runs-on: ubuntu-latest
175
+ steps:
176
+ - uses: actions/checkout@v6.0.2
177
+ with:
178
+ ref: ${{ needs.test-and-release.outputs.release_tag }}
179
+
180
+ - name: Build sdist
181
+ uses: PyO3/maturin-action@v1
182
+ with:
183
+ command: sdist
184
+ args: --out wheels/ -m python/Cargo.toml
185
+
186
+ - name: Upload sdist
187
+ uses: actions/upload-artifact@v4
188
+ with:
189
+ name: python-sdist
190
+ path: wheels/*.tar.gz
191
+
192
+ publish-python:
193
+ needs: [build-python-wheels, build-python-sdist]
194
+ runs-on: ubuntu-latest
195
+ permissions:
196
+ id-token: write
197
+ environment: pypi
198
+
199
+ steps:
200
+ - name: Download all wheels and sdist
201
+ uses: actions/download-artifact@v4
202
+ with:
203
+ pattern: python-*
204
+ path: dist
205
+ merge-multiple: true
206
+
207
+ - name: List packages
208
+ run: ls -la dist/
209
+
210
+ - name: Publish to PyPI
211
+ uses: pypa/gh-action-pypi-publish@release/v1
212
+ with:
213
+ packages-dir: dist/
214
+
215
+ publish-npm:
216
+ needs: test-and-release
217
+ runs-on: ubuntu-latest
218
+ permissions:
219
+ contents: read
220
+ id-token: write
221
+ environment: npm
222
+
223
+ steps:
224
+ - uses: actions/checkout@v6.0.2
225
+ with:
226
+ ref: ${{ needs.test-and-release.outputs.release_tag }}
227
+
228
+ - uses: dtolnay/rust-toolchain@stable
229
+ with:
230
+ targets: wasm32-unknown-unknown
231
+
232
+ - name: Install wasm-pack
233
+ run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
234
+
235
+ - uses: actions/setup-node@v4
236
+ with:
237
+ node-version: "22"
238
+ registry-url: "https://registry.npmjs.org"
239
+
240
+ - name: Build WASM into npm package
241
+ run: |
242
+ wasm-pack build wasm --target bundler --out-dir ../npm/wasm
243
+ rm -f npm/wasm/package.json npm/wasm/.gitignore
244
+
245
+ - name: Publish to npm
246
+ working-directory: npm
247
+ run: npm publish --access public
248
+
249
+ publish-crates:
250
+ needs: test-and-release
251
+ runs-on: ubuntu-latest
252
+ permissions:
253
+ contents: read
254
+ id-token: write
255
+ environment: crates-io
256
+
257
+ steps:
258
+ - uses: actions/checkout@v6.0.2
259
+ with:
260
+ ref: ${{ needs.test-and-release.outputs.release_tag }}
261
+
262
+ - uses: dtolnay/rust-toolchain@stable
263
+
264
+ - name: Authenticate with crates.io
265
+ id: auth
266
+ uses: rust-lang/crates-io-auth-action@v1
267
+
268
+ - name: Publish to crates.io
269
+ run: cargo publish -p luadata
270
+ env:
271
+ CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
272
+
273
+ bump-main-version:
274
+ needs: test-and-release
275
+ runs-on: ubuntu-latest
276
+ permissions:
277
+ contents: write
278
+ pull-requests: write
279
+
280
+ steps:
281
+ - uses: actions/checkout@v6.0.2
282
+ with:
283
+ ref: main
284
+
285
+ - uses: dtolnay/rust-toolchain@stable
286
+
287
+ - name: Bump version files
288
+ run: |
289
+ TAG="${{ needs.test-and-release.outputs.release_tag }}"
290
+ VERSION="${TAG#v}"
291
+ sed -i "s/^version = \".*\"/version = \"${VERSION}\"/" Cargo.toml
292
+ sed -i "s/\"version\": \".*\"/\"version\": \"${VERSION}\"/" npm/package.json
293
+ cargo generate-lockfile
294
+ echo "VERSION=${VERSION}" >> "$GITHUB_ENV"
295
+
296
+ - name: Create PR
297
+ env:
298
+ GH_TOKEN: ${{ github.token }}
299
+ run: |
300
+ BRANCH="version-bump/v${VERSION}"
301
+ git config user.name "github-actions[bot]"
302
+ git config user.email "github-actions[bot]@users.noreply.github.com"
303
+ git checkout -b "$BRANCH"
304
+ git add Cargo.toml npm/package.json Cargo.lock
305
+ git commit -m "Bump version to ${VERSION} after release"
306
+ git push origin "$BRANCH"
307
+ gh pr create \
308
+ --base main \
309
+ --head "$BRANCH" \
310
+ --title "Bump version to ${VERSION}" \
311
+ --body "Automated version bump after release of v${VERSION}."
@@ -0,0 +1,9 @@
1
+ # Build outputs
2
+ bin/
3
+ target/
4
+ wheels/
5
+ .venv/
6
+ .claude
7
+
8
+ # wasm-pack output inside npm package (built at release time)
9
+ npm/wasm/
@@ -0,0 +1,6 @@
1
+ version: "2"
2
+
3
+ formatters:
4
+ enable:
5
+ - gofumpt
6
+ - goimports
@@ -0,0 +1,17 @@
1
+ # Agents
2
+
3
+ ## Building
4
+
5
+ - **Always use Make targets** (`make build`, `make build-clib`, etc.) instead of running `cargo build` or `go build` directly.
6
+ - All build outputs go under `bin/` (`bin/cli/` for the CLI, `bin/clib/` for the shared library, `bin/web/` for WASM + static assets).
7
+ - The Rust workspace root is `Cargo.toml`. Crates: `luadata` (core lib in `src/`), `clib/`, `cli/`, `python/`, `wasm/`.
8
+ - The Go wrapper lives in `go/` with its own `go.mod` (`github.com/mmobeus/luadata/go`).
9
+ - For local Go development, run `make build-clib` first, then set `LUADATA_LIB_PATH` to `bin/clib/libluadata.dylib` (or `.so`).
10
+ - `go/lib/` is gitignored — shared libraries are embedded only at release time via CI.
11
+ - To verify compilation only: `cargo check --workspace` for Rust, `go build ./...` (from `go/` dir) for Go.
12
+
13
+ ## Testing
14
+
15
+ - `make test-rust` — runs Rust core library tests
16
+ - `make test-go` — builds cdylib, then runs Go wrapper tests with it
17
+ - `make test` — runs both
@@ -0,0 +1,180 @@
1
+ # Architecture
2
+
3
+ luadata is a Lua data parser written in Rust, with bindings for Go, Python,
4
+ WebAssembly, and a standalone CLI. This document describes the architecture and
5
+ the reasoning behind it.
6
+
7
+ ## Overview
8
+
9
+ ```
10
+ Rust core library (src/)
11
+ ├── cdylib (clib/) → C shared library (.so/.dylib/.dll)
12
+ │ └── exports: LuaDataToJSON, LuaDataFree
13
+ ├── PyO3 module (python/) → native Python extension
14
+ ├── wasm-bindgen (wasm/) → WebAssembly module (~124KB)
15
+ └── CLI binary (cli/) → luadata tojson / validate
16
+
17
+ Go wrapper (go/)
18
+ ├── Uses purego to load the Rust cdylib at runtime (no CGO)
19
+ ├── Embeds platform-specific shared libs via go:embed + build tags
20
+ └── Exposes TextToJSON, FileToJSON, ToJSON, ReaderToJSON
21
+ ```
22
+
23
+ All language bindings share the same Rust parser — there is exactly one
24
+ implementation of the lexer, parser, and JSON converter.
25
+
26
+ ## Why Rust as source of truth
27
+
28
+ Before the rewrite, luadata was a pure Go library. Go served the core use case
29
+ well, but adding Python and WebAssembly support exposed limitations:
30
+
31
+ - **WASM size**: Go's WASM binary was ~3.2MB (runtime overhead). The Rust WASM
32
+ module is ~124KB — roughly 25x smaller.
33
+ - **Python integration**: The Go approach required building a CGO shared library
34
+ and loading it via ctypes, with manual JSON-envelope marshalling. Rust/PyO3
35
+ compiles directly to a native Python extension with native types.
36
+ - **Single parser**: Maintaining one parser instead of porting logic across
37
+ languages eliminates behavioral drift between platforms.
38
+ - **Go compatibility**: The main objection to Rust was that Go consumers would
39
+ need CGO. With [purego](https://github.com/ebitengine/purego), Go loads the
40
+ Rust shared library at runtime with `CGO_ENABLED=0` — no C toolchain required.
41
+
42
+ ## Repository structure
43
+
44
+ ```
45
+ luadata/
46
+ ├── src/ Rust core library
47
+ │ ├── lib.rs Module exports
48
+ │ ├── lexer.rs Hand-written character-by-character lexer
49
+ │ ├── parser.rs Recursive descent parser
50
+ │ ├── converter.rs Lua → JSON conversion
51
+ │ ├── options.rs ParseConfig, ArrayMode, EmptyTableMode, StringTransform
52
+ │ └── types.rs Key, Value, KeyValuePairs, RawValue, RawKey
53
+ ├── cli/ CLI binary (clap)
54
+ │ └── src/main.rs tojson + validate subcommands
55
+ ├── clib/ C shared library (cdylib)
56
+ │ └── src/lib.rs LuaDataToJSON / LuaDataFree FFI exports
57
+ ├── python/ PyO3 Python module
58
+ │ ├── src/lib.rs lua_to_json / lua_to_dict
59
+ │ ├── pyproject.toml Package: mmobeus-luadata
60
+ │ └── tests/ pytest suite
61
+ ├── wasm/ wasm-bindgen module
62
+ │ └── src/lib.rs convertLuaDataToJson (JS name)
63
+ ├── npm/ npm package (mmobeus-luadata)
64
+ │ ├── package.json Package metadata
65
+ │ ├── index.js ES module wrapper: init() + convert()
66
+ │ ├── index.d.ts TypeScript type definitions
67
+ │ └── wasm/ (built at release time, gitignored)
68
+ ├── go/ Pure Go wrapper (no CGO)
69
+ │ ├── luadata.go Public API: TextToJSON, FileToJSON, etc.
70
+ │ ├── options.go Functional options: WithArrayMode, etc.
71
+ │ ├── luadata_test.go Go test suite
72
+ │ └── internal/ffi/ purego FFI bridge
73
+ │ ├── ffi.go Call(), init, library loading
74
+ │ ├── ffi_unix.go purego.Dlopen (darwin/linux)
75
+ │ ├── ffi_windows.go syscall.LoadLibrary
76
+ │ └── embed_dev.go Empty embed (dev); replaced on release branch
77
+ ├── web/ Browser interface
78
+ │ ├── index.html Live converter UI
79
+ │ ├── luadata.js ES module wrapper: init() + convert()
80
+ │ ├── app.js UI logic
81
+ │ └── docs/gen/ "Luadata by Example" generator
82
+ ├── testdata/ Shared test fixtures
83
+ │ ├── valid/ .lua files that must parse
84
+ │ └── invalid/ .lua files that must fail
85
+ ├── scripts/
86
+ │ ├── release.sh Tag RC on main
87
+ │ ├── prepare-release.sh Stage libs + generate embeds on release branch
88
+ │ └── validate-folder.sh Validate testdata against CLI
89
+ ├── Cargo.toml Workspace root
90
+ └── Makefile Build, test, lint, release targets
91
+ ```
92
+
93
+ ## Release workflow
94
+
95
+ Development happens on `main`. The `go/internal/ffi/lib/` directory is
96
+ gitignored — local development uses `make build-clib` to populate it, or sets
97
+ `LUADATA_LIB_PATH` to point at a locally-built shared library.
98
+
99
+ ### Cutting a release
100
+
101
+ 1. **Tag RC on main**: `make release` (or `make release BUMP=minor`, etc.) tags
102
+ the current commit as `v<version>-rc.1` and pushes the tag.
103
+
104
+ 2. **CI cross-compiles**: The `release.yml` workflow triggers on `v*-rc.*` tags.
105
+ It builds the Rust cdylib for five platforms:
106
+ - `darwin_amd64`, `darwin_arm64`
107
+ - `linux_amd64`, `linux_arm64`
108
+ - `windows_amd64`
109
+
110
+ 3. **CI tests**: Rust tests and Go tests (using the freshly-built Linux library)
111
+ run in the same workflow.
112
+
113
+ 4. **Prepare release branch**: `scripts/prepare-release.sh` copies the
114
+ cross-compiled shared libraries into `go/internal/ffi/lib/<platform>/`,
115
+ generates platform-specific `go:embed` files (replacing `embed_dev.go`), and
116
+ commits everything to the `release` branch with the final version tag.
117
+
118
+ 5. **GitHub Release**: CI creates a GitHub Release with shared library artifacts.
119
+
120
+ 6. **Publish to registries**: After the release succeeds, three publish jobs run
121
+ in parallel — all using OIDC trusted publishing (no stored secrets):
122
+ - **PyPI**: Builds platform-specific wheels (same five platforms as clib) plus
123
+ an sdist, then publishes `mmobeus-luadata` via `pypa/gh-action-pypi-publish`.
124
+ - **npm**: Builds the WASM module with wasm-pack, packages it with the JS/TS
125
+ wrapper from `npm/`, and publishes `mmobeus-luadata`.
126
+ - **crates.io**: Publishes the `luadata` core crate via
127
+ `rust-lang/crates-io-auth-action` for OIDC token exchange.
128
+
129
+ ### Go consumer model
130
+
131
+ Go consumers install with:
132
+
133
+ ```
134
+ go get github.com/mmobeus/luadata/go@v0.5.0
135
+ ```
136
+
137
+ This resolves to the `release` branch commit, which contains the embedded shared
138
+ libraries. At runtime, the Go wrapper extracts the platform-appropriate library
139
+ to a temp file and loads it via purego. No CGO is involved at any point.
140
+
141
+ On `main`, `embed_dev.go` provides an empty `EmbeddedLib` byte slice. If
142
+ `LUADATA_LIB_PATH` is set, the FFI layer loads the library from that path
143
+ instead — this is the local development path.
144
+
145
+ ## Key design decisions
146
+
147
+ ### purego FFI
148
+
149
+ The Go wrapper uses [purego](https://github.com/ebitengine/purego) to call the
150
+ Rust shared library. purego uses assembly trampolines to make C function calls
151
+ from pure Go — no CGO, no C compiler, no `CGO_ENABLED=1`. This means:
152
+
153
+ - `go get` works without a C toolchain
154
+ - Cross-compilation works (libraries are pre-built per platform)
155
+ - The Go module is a normal Go package from the consumer's perspective
156
+
157
+ ### internal/ffi for platform isolation
158
+
159
+ Platform-specific code (library loading, embed directives) lives in
160
+ `go/internal/ffi/` behind build tags. The public API in `go/luadata.go` is
161
+ platform-agnostic and delegates to `ffi.Call()`.
162
+
163
+ ### runtime.KeepAlive for GC safety
164
+
165
+ When passing Go byte slices to the Rust FFI as C pointers, `runtime.KeepAlive`
166
+ ensures the Go garbage collector doesn't collect the backing memory while Rust
167
+ is reading it.
168
+
169
+ ### Null-terminated C strings for UTF-8 correctness
170
+
171
+ The FFI boundary uses null-terminated C strings (`*const c_char` on the Rust
172
+ side). The Go wrapper converts Go strings to null-terminated byte slices before
173
+ passing them. This avoids length-prefix mismatches and ensures Rust's `CStr`
174
+ can safely interpret the data as UTF-8.
175
+
176
+ ### JSON envelope for FFI results
177
+
178
+ The clib returns results as a JSON envelope: `{"result":"..."}` on success,
179
+ `{"error":"..."}` on failure. This keeps the FFI surface minimal (two functions:
180
+ `LuaDataToJSON` and `LuaDataFree`) while supporting structured error reporting.