diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 52193b406..d468d345c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -676,6 +676,43 @@ importers:
specifier: 'catalog:'
version: 3.1.1(@types/debug@4.1.12)(@types/node@20.17.30)(tsx@4.19.3)(yaml@2.7.1)
+ samples/livr-emitter:
+ dependencies:
+ '@alloy-js/core':
+ specifier: workspace:~
+ version: link:../../packages/core
+ '@alloy-js/java':
+ specifier: workspace:~
+ version: link:../../packages/java
+ '@alloy-js/json':
+ specifier: workspace:~
+ version: link:../../packages/json
+ '@alloy-js/typescript':
+ specifier: workspace:~
+ version: link:../../packages/typescript
+ devDependencies:
+ '@alloy-js/cli':
+ specifier: workspace:~
+ version: link:../../packages/cli
+ '@alloy-js/rollup-plugin':
+ specifier: workspace:~
+ version: link:../../packages/rollup-plugin
+ '@rollup/plugin-typescript':
+ specifier: 'catalog:'
+ version: 12.1.2(rollup@4.39.0)(tslib@2.8.1)(typescript@5.8.3)
+ '@types/node':
+ specifier: 'catalog:'
+ version: 20.17.30
+ concurrently:
+ specifier: 'catalog:'
+ version: 9.1.2
+ typescript:
+ specifier: 'catalog:'
+ version: 5.8.3
+ vitest:
+ specifier: 'catalog:'
+ version: 3.1.1(@types/debug@4.1.12)(@types/node@20.17.30)(tsx@4.19.3)(yaml@2.7.1)
+
packages:
'@actions/github@6.0.0':
@@ -919,152 +956,102 @@ packages:
'@esbuild/aix-ppc64@0.25.2':
resolution: {integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==}
engines: {node: '>=18'}
- cpu: [ppc64]
- os: [aix]
'@esbuild/android-arm64@0.25.2':
resolution: {integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==}
engines: {node: '>=18'}
- cpu: [arm64]
- os: [android]
'@esbuild/android-arm@0.25.2':
resolution: {integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==}
engines: {node: '>=18'}
- cpu: [arm]
- os: [android]
'@esbuild/android-x64@0.25.2':
resolution: {integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==}
engines: {node: '>=18'}
- cpu: [x64]
- os: [android]
'@esbuild/darwin-arm64@0.25.2':
resolution: {integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==}
engines: {node: '>=18'}
- cpu: [arm64]
- os: [darwin]
'@esbuild/darwin-x64@0.25.2':
resolution: {integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==}
engines: {node: '>=18'}
- cpu: [x64]
- os: [darwin]
'@esbuild/freebsd-arm64@0.25.2':
resolution: {integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==}
engines: {node: '>=18'}
- cpu: [arm64]
- os: [freebsd]
'@esbuild/freebsd-x64@0.25.2':
resolution: {integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==}
engines: {node: '>=18'}
- cpu: [x64]
- os: [freebsd]
'@esbuild/linux-arm64@0.25.2':
resolution: {integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==}
engines: {node: '>=18'}
- cpu: [arm64]
- os: [linux]
'@esbuild/linux-arm@0.25.2':
resolution: {integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==}
engines: {node: '>=18'}
- cpu: [arm]
- os: [linux]
'@esbuild/linux-ia32@0.25.2':
resolution: {integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==}
engines: {node: '>=18'}
- cpu: [ia32]
- os: [linux]
'@esbuild/linux-loong64@0.25.2':
resolution: {integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==}
engines: {node: '>=18'}
- cpu: [loong64]
- os: [linux]
'@esbuild/linux-mips64el@0.25.2':
resolution: {integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==}
engines: {node: '>=18'}
- cpu: [mips64el]
- os: [linux]
'@esbuild/linux-ppc64@0.25.2':
resolution: {integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==}
engines: {node: '>=18'}
- cpu: [ppc64]
- os: [linux]
'@esbuild/linux-riscv64@0.25.2':
resolution: {integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==}
engines: {node: '>=18'}
- cpu: [riscv64]
- os: [linux]
'@esbuild/linux-s390x@0.25.2':
resolution: {integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==}
engines: {node: '>=18'}
- cpu: [s390x]
- os: [linux]
'@esbuild/linux-x64@0.25.2':
resolution: {integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==}
engines: {node: '>=18'}
- cpu: [x64]
- os: [linux]
'@esbuild/netbsd-arm64@0.25.2':
resolution: {integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==}
engines: {node: '>=18'}
- cpu: [arm64]
- os: [netbsd]
'@esbuild/netbsd-x64@0.25.2':
resolution: {integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==}
engines: {node: '>=18'}
- cpu: [x64]
- os: [netbsd]
'@esbuild/openbsd-arm64@0.25.2':
resolution: {integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==}
engines: {node: '>=18'}
- cpu: [arm64]
- os: [openbsd]
'@esbuild/openbsd-x64@0.25.2':
resolution: {integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==}
engines: {node: '>=18'}
- cpu: [x64]
- os: [openbsd]
'@esbuild/sunos-x64@0.25.2':
resolution: {integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==}
engines: {node: '>=18'}
- cpu: [x64]
- os: [sunos]
'@esbuild/win32-arm64@0.25.2':
resolution: {integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==}
engines: {node: '>=18'}
- cpu: [arm64]
- os: [win32]
'@esbuild/win32-ia32@0.25.2':
resolution: {integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==}
engines: {node: '>=18'}
- cpu: [ia32]
- os: [win32]
'@esbuild/win32-x64@0.25.2':
resolution: {integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==}
engines: {node: '>=18'}
- cpu: [x64]
- os: [win32]
'@eslint-community/eslint-utils@4.5.1':
resolution: {integrity: sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==}
@@ -1150,217 +1137,141 @@ packages:
'@img/sharp-darwin-arm64@0.33.5':
resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm64]
- os: [darwin]
'@img/sharp-darwin-arm64@0.34.1':
resolution: {integrity: sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm64]
- os: [darwin]
'@img/sharp-darwin-x64@0.33.5':
resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [darwin]
'@img/sharp-darwin-x64@0.34.1':
resolution: {integrity: sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [darwin]
'@img/sharp-libvips-darwin-arm64@1.0.4':
resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==}
- cpu: [arm64]
- os: [darwin]
'@img/sharp-libvips-darwin-arm64@1.1.0':
resolution: {integrity: sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==}
- cpu: [arm64]
- os: [darwin]
'@img/sharp-libvips-darwin-x64@1.0.4':
resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==}
- cpu: [x64]
- os: [darwin]
'@img/sharp-libvips-darwin-x64@1.1.0':
resolution: {integrity: sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==}
- cpu: [x64]
- os: [darwin]
'@img/sharp-libvips-linux-arm64@1.0.4':
resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==}
- cpu: [arm64]
- os: [linux]
'@img/sharp-libvips-linux-arm64@1.1.0':
resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==}
- cpu: [arm64]
- os: [linux]
'@img/sharp-libvips-linux-arm@1.0.5':
resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
- cpu: [arm]
- os: [linux]
'@img/sharp-libvips-linux-arm@1.1.0':
resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==}
- cpu: [arm]
- os: [linux]
'@img/sharp-libvips-linux-ppc64@1.1.0':
resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==}
- cpu: [ppc64]
- os: [linux]
'@img/sharp-libvips-linux-s390x@1.0.4':
resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==}
- cpu: [s390x]
- os: [linux]
'@img/sharp-libvips-linux-s390x@1.1.0':
resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==}
- cpu: [s390x]
- os: [linux]
'@img/sharp-libvips-linux-x64@1.0.4':
resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
- cpu: [x64]
- os: [linux]
'@img/sharp-libvips-linux-x64@1.1.0':
resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==}
- cpu: [x64]
- os: [linux]
'@img/sharp-libvips-linuxmusl-arm64@1.0.4':
resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==}
- cpu: [arm64]
- os: [linux]
'@img/sharp-libvips-linuxmusl-arm64@1.1.0':
resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==}
- cpu: [arm64]
- os: [linux]
'@img/sharp-libvips-linuxmusl-x64@1.0.4':
resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==}
- cpu: [x64]
- os: [linux]
'@img/sharp-libvips-linuxmusl-x64@1.1.0':
resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==}
- cpu: [x64]
- os: [linux]
'@img/sharp-linux-arm64@0.33.5':
resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm64]
- os: [linux]
'@img/sharp-linux-arm64@0.34.1':
resolution: {integrity: sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm64]
- os: [linux]
'@img/sharp-linux-arm@0.33.5':
resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm]
- os: [linux]
'@img/sharp-linux-arm@0.34.1':
resolution: {integrity: sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm]
- os: [linux]
'@img/sharp-linux-s390x@0.33.5':
resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [s390x]
- os: [linux]
'@img/sharp-linux-s390x@0.34.1':
resolution: {integrity: sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [s390x]
- os: [linux]
'@img/sharp-linux-x64@0.33.5':
resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [linux]
'@img/sharp-linux-x64@0.34.1':
resolution: {integrity: sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [linux]
'@img/sharp-linuxmusl-arm64@0.33.5':
resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm64]
- os: [linux]
'@img/sharp-linuxmusl-arm64@0.34.1':
resolution: {integrity: sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [arm64]
- os: [linux]
'@img/sharp-linuxmusl-x64@0.33.5':
resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [linux]
'@img/sharp-linuxmusl-x64@0.34.1':
resolution: {integrity: sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [linux]
'@img/sharp-wasm32@0.33.5':
resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [wasm32]
'@img/sharp-wasm32@0.34.1':
resolution: {integrity: sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [wasm32]
'@img/sharp-win32-ia32@0.33.5':
resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [ia32]
- os: [win32]
'@img/sharp-win32-ia32@0.34.1':
resolution: {integrity: sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [ia32]
- os: [win32]
'@img/sharp-win32-x64@0.33.5':
resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [win32]
'@img/sharp-win32-x64@0.34.1':
resolution: {integrity: sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
- cpu: [x64]
- os: [win32]
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
@@ -1635,31 +1546,21 @@ packages:
'@pagefind/darwin-arm64@1.3.0':
resolution: {integrity: sha512-365BEGl6ChOsauRjyVpBjXybflXAOvoMROw3TucAROHIcdBvXk9/2AmEvGFU0r75+vdQI4LJdJdpH4Y6Yqaj4A==}
- cpu: [arm64]
- os: [darwin]
'@pagefind/darwin-x64@1.3.0':
resolution: {integrity: sha512-zlGHA23uuXmS8z3XxEGmbHpWDxXfPZ47QS06tGUq0HDcZjXjXHeLG+cboOy828QIV5FXsm9MjfkP5e4ZNbOkow==}
- cpu: [x64]
- os: [darwin]
'@pagefind/default-ui@1.3.0':
resolution: {integrity: sha512-CGKT9ccd3+oRK6STXGgfH+m0DbOKayX6QGlq38TfE1ZfUcPc5+ulTuzDbZUnMo+bubsEOIypm4Pl2iEyzZ1cNg==}
'@pagefind/linux-arm64@1.3.0':
resolution: {integrity: sha512-8lsxNAiBRUk72JvetSBXs4WRpYrQrVJXjlRRnOL6UCdBN9Nlsz0t7hWstRk36+JqHpGWOKYiuHLzGYqYAqoOnQ==}
- cpu: [arm64]
- os: [linux]
'@pagefind/linux-x64@1.3.0':
resolution: {integrity: sha512-hAvqdPJv7A20Ucb6FQGE6jhjqy+vZ6pf+s2tFMNtMBG+fzcdc91uTw7aP/1Vo5plD0dAOHwdxfkyw0ugal4kcQ==}
- cpu: [x64]
- os: [linux]
'@pagefind/windows-x64@1.3.0':
resolution: {integrity: sha512-BR1bIRWOMqkf8IoU576YDhij1Wd/Zf2kX/kCI0b2qzCKC8wcc2GQJaaRMCpzvCCrmliO4vtJ6RITp/AnoYUUmQ==}
- cpu: [x64]
- os: [win32]
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
@@ -1711,103 +1612,63 @@ packages:
'@rollup/rollup-android-arm-eabi@4.39.0':
resolution: {integrity: sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA==}
- cpu: [arm]
- os: [android]
'@rollup/rollup-android-arm64@4.39.0':
resolution: {integrity: sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==}
- cpu: [arm64]
- os: [android]
'@rollup/rollup-darwin-arm64@4.39.0':
resolution: {integrity: sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==}
- cpu: [arm64]
- os: [darwin]
'@rollup/rollup-darwin-x64@4.39.0':
resolution: {integrity: sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==}
- cpu: [x64]
- os: [darwin]
'@rollup/rollup-freebsd-arm64@4.39.0':
resolution: {integrity: sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==}
- cpu: [arm64]
- os: [freebsd]
'@rollup/rollup-freebsd-x64@4.39.0':
resolution: {integrity: sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==}
- cpu: [x64]
- os: [freebsd]
'@rollup/rollup-linux-arm-gnueabihf@4.39.0':
resolution: {integrity: sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==}
- cpu: [arm]
- os: [linux]
'@rollup/rollup-linux-arm-musleabihf@4.39.0':
resolution: {integrity: sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==}
- cpu: [arm]
- os: [linux]
'@rollup/rollup-linux-arm64-gnu@4.39.0':
resolution: {integrity: sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==}
- cpu: [arm64]
- os: [linux]
'@rollup/rollup-linux-arm64-musl@4.39.0':
resolution: {integrity: sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==}
- cpu: [arm64]
- os: [linux]
'@rollup/rollup-linux-loongarch64-gnu@4.39.0':
resolution: {integrity: sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==}
- cpu: [loong64]
- os: [linux]
'@rollup/rollup-linux-powerpc64le-gnu@4.39.0':
resolution: {integrity: sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==}
- cpu: [ppc64]
- os: [linux]
'@rollup/rollup-linux-riscv64-gnu@4.39.0':
resolution: {integrity: sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==}
- cpu: [riscv64]
- os: [linux]
'@rollup/rollup-linux-riscv64-musl@4.39.0':
resolution: {integrity: sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==}
- cpu: [riscv64]
- os: [linux]
'@rollup/rollup-linux-s390x-gnu@4.39.0':
resolution: {integrity: sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==}
- cpu: [s390x]
- os: [linux]
'@rollup/rollup-linux-x64-gnu@4.39.0':
resolution: {integrity: sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==}
- cpu: [x64]
- os: [linux]
'@rollup/rollup-linux-x64-musl@4.39.0':
resolution: {integrity: sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==}
- cpu: [x64]
- os: [linux]
'@rollup/rollup-win32-arm64-msvc@4.39.0':
resolution: {integrity: sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==}
- cpu: [arm64]
- os: [win32]
'@rollup/rollup-win32-ia32-msvc@4.39.0':
resolution: {integrity: sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==}
- cpu: [ia32]
- os: [win32]
'@rollup/rollup-win32-x64-msvc@4.39.0':
resolution: {integrity: sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==}
- cpu: [x64]
- os: [win32]
'@rushstack/node-core-library@5.10.0':
resolution: {integrity: sha512-2pPLCuS/3x7DCd7liZkqOewGM0OzLyCacdvOe8j6Yrx9LkETGnxul1t7603bIaB8nUAooORcct9fFDOQMbWAgw==}
@@ -2683,7 +2544,6 @@ packages:
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
- os: [darwin]
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
@@ -6014,7 +5874,7 @@ snapshots:
'@types/sax@1.2.7':
dependencies:
- '@types/node': 17.0.45
+ '@types/node': 20.17.30
'@types/unist@2.0.11': {}
diff --git a/samples/livr-emitter/alloy-output/rules.json b/samples/livr-emitter/alloy-output/rules.json
new file mode 100644
index 000000000..c2874bb74
--- /dev/null
+++ b/samples/livr-emitter/alloy-output/rules.json
@@ -0,0 +1,105 @@
+{
+ "name": [
+ "required",
+ "string",
+ {
+ "max_length": 50
+ }
+ ],
+ "lastName": [
+ "string",
+ {
+ "length_between": [2, 50]
+ }
+ ],
+ "email": [
+ "required",
+ "email"
+ ],
+ "age": [
+ "integer",
+ {
+ "min_number": 18
+ },
+ {
+ "max_number": 99
+ }
+ ],
+ "address": [
+ "required",
+ {
+ "nested_object": {
+ "street": "string",
+ "city": "required",
+ "zip": [
+ "required",
+ "positive_integer"
+ ],
+ "geo": {
+ "nested_object": {
+ "lat": "decimal",
+ "lng": "decimal"
+ }
+ }
+ }
+ }
+ ],
+ "phones": [
+ {
+ "list_of": [
+ "string",
+ {
+ "max_length": 15
+ }
+ ]
+ }
+ ],
+ "preferences": {
+ "variable_object": [
+ "type",
+ {
+ "email": {
+ "frequency": {
+ "one_of": ["daily", "weekly", "monthly"]
+ }
+ },
+ "sms": {
+ "time": "string"
+ }
+ }
+ ]
+ },
+ "tags": [
+ {
+ "list_of": "string"
+ }
+ ],
+ "website": "url",
+ "created_at": "iso_date",
+ "status": {
+ "one_of": ["active", "inactive", "pending"]
+ },
+ "password": [
+ "required",
+ {
+ "min_length": 8
+ }
+ ],
+ "confirm_password": [
+ "required",
+ {
+ "equal_to_field": "password"
+ }
+ ],
+ "contact": {
+ "or": [
+ ["email"],
+ [
+ "string",
+ {
+ "max_length": 15
+ }
+ ]
+ ]
+ }
+}
\ No newline at end of file
diff --git a/samples/livr-emitter/package.json b/samples/livr-emitter/package.json
new file mode 100644
index 000000000..3aefc258f
--- /dev/null
+++ b/samples/livr-emitter/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "@alloy-js/sample-livr-emitter",
+ "private": "true",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "build": "alloy build",
+ "clean": "rimraf dist/ .temp/",
+ "watch": "alloy build --watch"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "MIT",
+ "dependencies": {
+ "@alloy-js/core": "workspace:~",
+ "@alloy-js/json": "workspace:~",
+ "@alloy-js/typescript": "workspace:~",
+ "@alloy-js/java": "workspace:~"
+ },
+ "devDependencies": {
+ "@alloy-js/cli": "workspace:~",
+ "@alloy-js/rollup-plugin": "workspace:~",
+ "@rollup/plugin-typescript": "catalog:",
+ "@types/node": "catalog:",
+ "concurrently": "catalog:",
+ "typescript": "catalog:",
+ "vitest": "catalog:"
+ },
+ "type": "module"
+}
diff --git a/samples/livr-emitter/src/component/Rule.tsx b/samples/livr-emitter/src/component/Rule.tsx
new file mode 100644
index 000000000..a65ce592d
--- /dev/null
+++ b/samples/livr-emitter/src/component/Rule.tsx
@@ -0,0 +1,29 @@
+// src/component/Rule.tsx
+import { For } from "@alloy-js/core";
+import * as jsn from "@alloy-js/json";
+import { LIVRFieldRules } from "../schema.js";
+import { RuleProperty } from "./RuleProperty.jsx";
+
+interface RuleProps {
+ rule: LIVRFieldRules;
+}
+
+export function Rule(props: RuleProps) {
+ const { rule } = props;
+
+ if (Array.isArray(rule)) {
+ // Array of rules: output as array of processed rules, with commas
+ return (
+
+
+ {(r) => }
+
+
+ );
+ }
+ if (typeof rule === "object" && rule !== null && "rule" in rule) {
+ return ;
+ }
+ // Fallback: output as JSON
+ return ;
+}
diff --git a/samples/livr-emitter/src/component/RuleProperty.tsx b/samples/livr-emitter/src/component/RuleProperty.tsx
new file mode 100644
index 000000000..baa7fe5c6
--- /dev/null
+++ b/samples/livr-emitter/src/component/RuleProperty.tsx
@@ -0,0 +1,177 @@
+// RuleProperty.tsx
+import { For } from "@alloy-js/core";
+import * as jsn from "@alloy-js/json";
+import {
+ ListOfDifferentObjectsRule,
+ ListOfObjectsRule,
+ ListOfRule,
+ LIVRRule,
+ LIVRSchema,
+ NestedObjectRule,
+ OrRule,
+ VariableObjectRule,
+} from "../schema.js";
+import { Rule } from "./Rule.jsx"; // for recursion
+
+interface RulePropertyProps {
+ rule: LIVRRule;
+}
+
+function renderSimpleRule(rule: LIVRRule) {
+ // Render simple rules as string literals
+ return ;
+}
+
+function renderSimpleObjectRule(name: string, jsValue: any) {
+ // Render simple object rules as { rule: value }
+ return (
+
+
+
+
+
+ );
+}
+
+function renderSchema(schema: LIVRSchema) {
+ return (
+
+
+ {([field, fieldRules]) => (
+
+
+
+ )}
+
+
+ );
+}
+
+function renderNestedObjectRule(rule: NestedObjectRule) {
+ // Render nested object rules as { nested_object: { ... } }
+ return (
+
+
+ {renderSchema(rule.schema)}
+
+
+ );
+}
+
+function renderOrRule(rule: OrRule) {
+ // Render OR rules as { or: [ ... ] }
+ return (
+
+
+
+
+ {(alt) => }
+
+
+
+
+ );
+}
+
+function renderSelectorBasedRules(
+ rule: VariableObjectRule | ListOfDifferentObjectsRule,
+) {
+ return (
+
+
+
+
+
+
+ {([field, schema]) => (
+
+ {renderSchema(schema)}
+
+ )}
+
+
+
+
+
+ );
+}
+
+function renderListOfRule(rule: ListOfRule) {
+ return (
+
+
+
+
+
+ );
+}
+
+function renderListOfObjectsRule(rule: ListOfObjectsRule) {
+ return (
+
+
+ {renderSchema(rule.schema)}
+
+
+ );
+}
+
+export function RuleProperty(props: RulePropertyProps) {
+ const { rule } = props;
+
+ switch (rule.rule) {
+ case "required":
+ case "not_empty":
+ case "not_empty_list":
+ case "any_object":
+ case "string":
+ case "integer":
+ case "positive_integer":
+ case "decimal":
+ case "positive_decimal":
+ case "email":
+ case "url":
+ case "iso_date":
+ case "trim":
+ case "to_lc":
+ case "to_uc":
+ return renderSimpleRule(rule);
+ case "nested_object":
+ return renderNestedObjectRule(rule);
+ case "or":
+ return renderOrRule(rule);
+ case "variable_object":
+ return renderSelectorBasedRules(rule);
+ case "list_of":
+ return renderListOfRule(rule);
+ case "list_of_objects":
+ return renderListOfObjectsRule(rule);
+ case "list_of_different_objects":
+ return renderSelectorBasedRules(rule);
+ case "max_length":
+ case "min_length":
+ case "length_equal":
+ return renderSimpleObjectRule(rule.rule, rule.length);
+ case "length_between":
+ return renderSimpleObjectRule(rule.rule, rule.range);
+ case "max_number":
+ case "min_number":
+ case "eq":
+ return renderSimpleObjectRule(rule.rule, rule.value);
+ case "number_between":
+ return renderSimpleObjectRule(rule.rule, rule.range);
+ case "equal_to_field":
+ return renderSimpleObjectRule(rule.rule, rule.field);
+ case "one_of":
+ return renderSimpleObjectRule(rule.rule, rule.values);
+ case "like":
+ return renderSimpleObjectRule(rule.rule, rule.pattern);
+ case "remove":
+ case "leave_only":
+ return renderSimpleObjectRule(rule.rule, rule.characters);
+ case "default":
+ return renderSimpleObjectRule(rule.rule, rule.value);
+ default:
+ return ;
+ }
+}
diff --git a/samples/livr-emitter/src/context/livr.ts b/samples/livr-emitter/src/context/livr.ts
new file mode 100644
index 000000000..40c323b3a
--- /dev/null
+++ b/samples/livr-emitter/src/context/livr.ts
@@ -0,0 +1,22 @@
+import {
+ createContext,
+ useContext,
+ type ComponentContext,
+} from "@alloy-js/core";
+import { LIVRSchema } from "../schema.js";
+
+interface LIVRContext {
+ schema: LIVRSchema;
+}
+
+// Add explicit return type annotation
+export const LIVRContext: ComponentContext =
+ createContext();
+
+export function useLivr(): LIVRContext {
+ return useContext(LIVRContext)!;
+}
+
+export function createLIVRContext(schema: LIVRSchema): LIVRContext {
+ return { schema };
+}
diff --git a/samples/livr-emitter/src/index.tsx b/samples/livr-emitter/src/index.tsx
new file mode 100644
index 000000000..a003b3370
--- /dev/null
+++ b/samples/livr-emitter/src/index.tsx
@@ -0,0 +1,27 @@
+import { For, Output, render, writeOutput } from "@alloy-js/core";
+import * as jsn from "@alloy-js/json";
+import { Rule } from "./component/Rule.js";
+import { LIVRContext, createLIVRContext } from "./context/livr.js";
+import { livrApi } from "./schema.js";
+
+// Main function to emit LIVR schema as JSON
+const output = render(
+ ,
+);
+
+// Write the output to disk
+writeOutput(output, "./alloy-output");
diff --git a/samples/livr-emitter/src/schema.ts b/samples/livr-emitter/src/schema.ts
new file mode 100644
index 000000000..9ce511c1f
--- /dev/null
+++ b/samples/livr-emitter/src/schema.ts
@@ -0,0 +1,290 @@
+/**
+ * Base interface for all LIVR rules.
+ * Extend and discriminate with `rule` property.
+ */
+interface LIVRRuleBase {
+ rule: string;
+ error_code?: string;
+}
+
+// --- Common rules ---
+export interface RequiredRule extends LIVRRuleBase {
+ rule: "required";
+ error_code?: "REQUIRED";
+}
+export interface NotEmptyRule extends LIVRRuleBase {
+ rule: "not_empty";
+ error_code?: "CANNOT_BE_EMPTY";
+}
+export interface NotEmptyList extends LIVRRuleBase {
+ rule: "not_empty_list";
+ error_code?: "CANNOT_BE_EMPTY" | "FORMAT_ERROR";
+}
+export interface AnyObject extends LIVRRuleBase {
+ rule: "any_object";
+ error_code?: "FORMAT_ERROR";
+}
+
+// --- String rules ---
+export interface StringRule extends LIVRRuleBase {
+ rule: "string";
+}
+export interface EqRule extends LIVRRuleBase {
+ rule: "eq";
+ value: string;
+ error_code?: "NOT_ALLOWED_VALUE";
+}
+export interface OneOfRule extends LIVRRuleBase {
+ rule: "one_of";
+ values: string[];
+ error_code?: "NOT_ALLOWED_VALUE";
+}
+export interface MinLengthRule extends LIVRRuleBase {
+ rule: "min_length";
+ length: number;
+ error_code?: "TOO_SHORT";
+}
+export interface MaxLengthRule extends LIVRRuleBase {
+ rule: "max_length";
+ length: number;
+ error_code?: "TOO_LONG";
+}
+export interface LengthBetweenRule extends LIVRRuleBase {
+ rule: "length_between";
+ range: [number, number]; // [min, max]
+ error_code?: "TOO_SHORT" | "TOO_LONG";
+}
+export interface LengthEqualRule extends LIVRRuleBase {
+ rule: "length_equal";
+ length: number;
+ error_code?: "TOO_SHORT" | "TOO_LONG";
+}
+export interface LikeRule extends LIVRRuleBase {
+ rule: "like";
+ pattern: string;
+ error_code?: "WRONG_FORMAT";
+}
+
+// --- Numeric rules ---
+export interface IntegerRule extends LIVRRuleBase {
+ rule: "integer";
+ error_code?: "NOT_INTEGER";
+}
+export interface PositiveIntegerRule extends LIVRRuleBase {
+ rule: "positive_integer";
+ error_code?: "NOT_POSITIVE_INTEGER";
+}
+export interface DecimalRule extends LIVRRuleBase {
+ rule: "decimal";
+ error_code?: "NOT_DECIMAL";
+}
+export interface PositiveDecimalRule extends LIVRRuleBase {
+ rule: "positive_decimal";
+ error_code?: "NOT_POSITIVE_DECIMAL";
+}
+export interface MaxNumberRule extends LIVRRuleBase {
+ rule: "max_number";
+ value: number;
+ error_code?: "TOO_HIGH" | "NOT_NUMBER";
+}
+export interface MinNumberRule extends LIVRRuleBase {
+ rule: "min_number";
+ value: number;
+ error_code?: "TOO_LOW" | "NOT_NUMBER";
+}
+export interface NumberBetweenRule extends LIVRRuleBase {
+ rule: "number_between";
+ range: [number, number]; // [min, max]
+ error_code?: "TOO_LOW" | "TOO_HIGH" | "NOT_NUMBER";
+}
+
+// --- Special rules ---
+export interface EmailRule extends LIVRRuleBase {
+ rule: "email";
+ error_code?: "WRONG_EMAIL";
+}
+export interface UrlRule extends LIVRRuleBase {
+ rule: "url";
+ error_code?: "WRONG_URL";
+}
+export interface IsoDateRule extends LIVRRuleBase {
+ rule: "iso_date";
+ error_code?: "WRONG_DATE";
+}
+export interface EqualToFieldRule extends LIVRRuleBase {
+ rule: "equal_to_field";
+ field: string;
+ error_code?: "FIELDS_NOT_EQUAL";
+}
+// --- Meta rules ---
+export interface NestedObjectRule extends LIVRRuleBase {
+ rule: "nested_object";
+ schema: LIVRSchema;
+ error_code?: "FORMAT_ERROR";
+}
+export interface VariableObjectRule extends LIVRRuleBase {
+ rule: "variable_object";
+ selectorField: string;
+ cases: { [key: string]: LIVRSchema };
+ error_code?: "FORMAT_ERROR";
+}
+export interface ListOfRule extends LIVRRuleBase {
+ rule: "list_of";
+ rules: LIVRFieldRules;
+}
+export interface ListOfObjectsRule extends LIVRRuleBase {
+ rule: "list_of_objects";
+ schema: LIVRSchema;
+}
+export interface ListOfDifferentObjectsRule extends LIVRRuleBase {
+ rule: "list_of_different_objects";
+ selectorField: string;
+ cases: { [key: string]: LIVRSchema };
+}
+export interface OrRule extends LIVRRuleBase {
+ rule: "or";
+ /**
+ * Each alternative is either:
+ * - a single rule (as an object)
+ * - or an array of rules (if several in a chain)
+ */
+ alternatives: (LIVRRule | LIVRRule[])[];
+}
+
+// --- Modifier rules ---
+export interface TrimRule extends LIVRRuleBase {
+ rule: "trim";
+}
+export interface ToLowerCaseRule extends LIVRRuleBase {
+ rule: "to_lc";
+}
+export interface ToUpperCaseRule extends LIVRRuleBase {
+ rule: "to_uc";
+}
+export interface RemoveRule extends LIVRRuleBase {
+ rule: "remove";
+ characters: string;
+}
+export interface LeaveOnlyRule extends LIVRRuleBase {
+ rule: "leave_only";
+ characters: string;
+}
+export interface DefaultRule extends LIVRRuleBase {
+ rule: "default";
+ value: string | number | boolean;
+}
+// --- Main rule type: union of all rule interfaces ---
+
+export type LIVRRule =
+ | RequiredRule
+ | NotEmptyRule
+ | NotEmptyList
+ | AnyObject
+ | StringRule
+ | EqRule
+ | OneOfRule
+ | MinLengthRule
+ | MaxLengthRule
+ | LengthBetweenRule
+ | LengthEqualRule
+ | LikeRule
+ | IntegerRule
+ | PositiveIntegerRule
+ | DecimalRule
+ | PositiveDecimalRule
+ | MaxNumberRule
+ | MinNumberRule
+ | NumberBetweenRule
+ | EmailRule
+ | UrlRule
+ | IsoDateRule
+ | EqualToFieldRule
+ | NestedObjectRule
+ | VariableObjectRule
+ | ListOfRule
+ | ListOfObjectsRule
+ | ListOfDifferentObjectsRule
+ | OrRule
+ | TrimRule
+ | ToLowerCaseRule
+ | ToUpperCaseRule
+ | RemoveRule
+ | LeaveOnlyRule
+ | DefaultRule;
+
+// LIVR field rules: typically an array, but can be a single rule.
+export type LIVRFieldRules = LIVRRule | LIVRRule[];
+
+// A LIVR validation schema: field name -> rules
+export interface LIVRSchema {
+ [field: string]: LIVRFieldRules;
+}
+
+// Define a complete sample LIVR schema
+export const livrApi: LIVRSchema = {
+ name: [
+ { rule: "required" },
+ { rule: "string" },
+ { rule: "max_length", length: 50 },
+ ],
+ lastName: [{ rule: "string" }, { rule: "length_between", range: [2, 50] }],
+ email: [{ rule: "required" }, { rule: "email" }],
+ age: [
+ { rule: "integer" },
+ { rule: "min_number", value: 18 },
+ { rule: "max_number", value: 99 },
+ ],
+ address: [
+ { rule: "required" },
+ {
+ rule: "nested_object",
+ schema: {
+ street: { rule: "string" },
+ city: { rule: "required" },
+ zip: [{ rule: "required" }, { rule: "positive_integer" }],
+ geo: {
+ rule: "nested_object",
+ schema: {
+ lat: { rule: "decimal" },
+ lng: { rule: "decimal" },
+ },
+ },
+ },
+ },
+ ],
+ phones: [
+ {
+ rule: "list_of",
+ rules: [{ rule: "string" }, { rule: "max_length", length: 15 }],
+ },
+ ],
+ preferences: {
+ rule: "variable_object",
+ selectorField: "type",
+ cases: {
+ email: {
+ frequency: { rule: "one_of", values: ["daily", "weekly", "monthly"] },
+ },
+ sms: {
+ time: { rule: "string" },
+ },
+ },
+ },
+ tags: [{ rule: "list_of", rules: { rule: "string" } }],
+ website: { rule: "url" },
+ created_at: { rule: "iso_date" },
+ status: { rule: "one_of", values: ["active", "inactive", "pending"] },
+ password: [{ rule: "required" }, { rule: "min_length", length: 8 }],
+ confirm_password: [
+ { rule: "required" },
+ { rule: "equal_to_field", field: "password" },
+ ],
+ // Example of the "or" rule
+ contact: {
+ rule: "or",
+ alternatives: [
+ [{ rule: "email" }],
+ [{ rule: "string" }, { rule: "max_length", length: 15 }],
+ ],
+ },
+};
diff --git a/samples/livr-emitter/tsconfig.json b/samples/livr-emitter/tsconfig.json
new file mode 100644
index 000000000..ec994c238
--- /dev/null
+++ b/samples/livr-emitter/tsconfig.json
@@ -0,0 +1,14 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "compilerOptions": {
+ "emitDeclarationOnly": true,
+ "declaration": true,
+ "outDir": "dist"
+ },
+ "references": [
+ { "path": "../../packages/core" },
+ { "path": "../../packages/typescript" }
+ ],
+ "include": ["src/**/*.ts", "src/**/*.tsx", "test/**/*.ts", "test/**/*.tsx"],
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/samples/livr-emitter/vitest.config.ts b/samples/livr-emitter/vitest.config.ts
new file mode 100644
index 000000000..f05f0ab40
--- /dev/null
+++ b/samples/livr-emitter/vitest.config.ts
@@ -0,0 +1,14 @@
+import alloyPlugin from "@alloy-js/rollup-plugin";
+import { defineConfig } from "vitest/config";
+
+export default defineConfig({
+ test: {
+ include: ["test/**/*.ts", "test/**/*.tsx"],
+ exclude: ["test/**/*.util.ts", "test/**/*.d.ts"],
+ },
+ esbuild: {
+ jsx: "preserve",
+ sourcemap: "both",
+ },
+ plugins: [alloyPlugin()],
+});