@shivaedev/build 0.0.0 → 0.1.1
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.
- package/CHANGELOG.md +19 -0
- package/LICENSE +21 -0
- package/README.md +215 -1
- package/dist/BuildFailure.d.ts +9 -0
- package/dist/BuildFailure.d.ts.map +1 -0
- package/dist/BuildFailure.js +4 -0
- package/dist/BuildFailure.js.map +1 -0
- package/dist/adapters/appTestConfig.d.ts +4 -0
- package/dist/adapters/appTestConfig.d.ts.map +1 -0
- package/dist/adapters/appTestConfig.js +17 -0
- package/dist/adapters/appTestConfig.js.map +1 -0
- package/dist/adapters/appViteConfig.d.ts +26 -0
- package/dist/adapters/appViteConfig.d.ts.map +1 -0
- package/dist/adapters/appViteConfig.js +18 -0
- package/dist/adapters/appViteConfig.js.map +1 -0
- package/dist/adapters/bundleCheck.d.ts +3 -0
- package/dist/adapters/bundleCheck.d.ts.map +1 -0
- package/dist/adapters/bundleCheck.js +53 -0
- package/dist/adapters/bundleCheck.js.map +1 -0
- package/dist/adapters/copiedCode.d.ts +9 -0
- package/dist/adapters/copiedCode.d.ts.map +1 -0
- package/dist/adapters/copiedCode.js +84 -0
- package/dist/adapters/copiedCode.js.map +1 -0
- package/dist/adapters/failuresOf.d.ts +5 -0
- package/dist/adapters/failuresOf.d.ts.map +1 -0
- package/dist/adapters/failuresOf.js +29 -0
- package/dist/adapters/failuresOf.js.map +1 -0
- package/dist/adapters/isReadonlyProperty.d.ts +10 -0
- package/dist/adapters/isReadonlyProperty.d.ts.map +1 -0
- package/dist/adapters/isReadonlyProperty.js +7 -0
- package/dist/adapters/isReadonlyProperty.js.map +1 -0
- package/dist/adapters/moduleCalls.d.ts +10 -0
- package/dist/adapters/moduleCalls.d.ts.map +1 -0
- package/dist/adapters/moduleCalls.js +47 -0
- package/dist/adapters/moduleCalls.js.map +1 -0
- package/dist/adapters/moduleFacts.d.ts +4 -0
- package/dist/adapters/moduleFacts.d.ts.map +1 -0
- package/dist/adapters/moduleFacts.js +63 -0
- package/dist/adapters/moduleFacts.js.map +1 -0
- package/dist/adapters/objectForm.d.ts +8 -0
- package/dist/adapters/objectForm.d.ts.map +1 -0
- package/dist/adapters/objectForm.js +66 -0
- package/dist/adapters/objectForm.js.map +1 -0
- package/dist/adapters/operationFacts.d.ts +10 -0
- package/dist/adapters/operationFacts.d.ts.map +1 -0
- package/dist/adapters/operationFacts.js +72 -0
- package/dist/adapters/operationFacts.js.map +1 -0
- package/dist/adapters/runNode.d.ts +6 -0
- package/dist/adapters/runNode.d.ts.map +1 -0
- package/dist/adapters/runNode.js +14 -0
- package/dist/adapters/runNode.js.map +1 -0
- package/dist/adapters/typeReading.d.ts +15 -0
- package/dist/adapters/typeReading.d.ts.map +1 -0
- package/dist/adapters/typeReading.js +46 -0
- package/dist/adapters/typeReading.js.map +1 -0
- package/dist/adapters/typeScript.d.ts +15 -0
- package/dist/adapters/typeScript.d.ts.map +1 -0
- package/dist/adapters/typeScript.js +81 -0
- package/dist/adapters/typeScript.js.map +1 -0
- package/dist/adapters/unionForm.d.ts +7 -0
- package/dist/adapters/unionForm.d.ts.map +1 -0
- package/dist/adapters/unionForm.js +78 -0
- package/dist/adapters/unionForm.js.map +1 -0
- package/dist/adapters/vitePlugin.d.ts +7 -0
- package/dist/adapters/vitePlugin.d.ts.map +1 -0
- package/dist/adapters/vitePlugin.js +88 -0
- package/dist/adapters/vitePlugin.js.map +1 -0
- package/dist/adapters/vitePort.d.ts +2 -0
- package/dist/adapters/vitePort.d.ts.map +1 -0
- package/dist/adapters/vitePort.js +5 -0
- package/dist/adapters/vitePort.js.map +1 -0
- package/dist/adapters/vitest/setup.d.ts +3 -0
- package/dist/adapters/vitest/setup.d.ts.map +1 -0
- package/dist/adapters/vitest/setup.js +11 -0
- package/dist/adapters/vitest/setup.js.map +1 -0
- package/dist/adapters/wireForm.d.ts +5 -0
- package/dist/adapters/wireForm.d.ts.map +1 -0
- package/dist/adapters/wireForm.js +91 -0
- package/dist/adapters/wireForm.js.map +1 -0
- package/dist/byText.d.ts +2 -0
- package/dist/byText.d.ts.map +1 -0
- package/dist/byText.js +8 -0
- package/dist/byText.js.map +1 -0
- package/dist/cache.d.ts +4 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +19 -0
- package/dist/cache.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +11 -0
- package/dist/cli.js.map +1 -0
- package/dist/code.d.ts +11 -0
- package/dist/code.d.ts.map +1 -0
- package/dist/code.js +11 -0
- package/dist/code.js.map +1 -0
- package/dist/command.d.ts +6 -0
- package/dist/command.d.ts.map +1 -0
- package/dist/command.js +28 -0
- package/dist/command.js.map +1 -0
- package/dist/emit.d.ts +23 -0
- package/dist/emit.d.ts.map +1 -0
- package/dist/emit.js +69 -0
- package/dist/emit.js.map +1 -0
- package/dist/facts.d.ts +92 -0
- package/dist/facts.d.ts.map +1 -0
- package/dist/facts.js +3 -0
- package/dist/facts.js.map +1 -0
- package/dist/files.d.ts +4 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +18 -0
- package/dist/files.js.map +1 -0
- package/dist/formCode.d.ts +6 -0
- package/dist/formCode.d.ts.map +1 -0
- package/dist/formCode.js +46 -0
- package/dist/formCode.js.map +1 -0
- package/dist/generate.d.ts +7 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +69 -0
- package/dist/generate.js.map +1 -0
- package/dist/generateRound.d.ts +14 -0
- package/dist/generateRound.d.ts.map +1 -0
- package/dist/generateRound.js +44 -0
- package/dist/generateRound.js.map +1 -0
- package/dist/importNames.d.ts +7 -0
- package/dist/importNames.d.ts.map +1 -0
- package/dist/importNames.js +57 -0
- package/dist/importNames.js.map +1 -0
- package/dist/inputs.d.ts +15 -0
- package/dist/inputs.d.ts.map +1 -0
- package/dist/inputs.js +64 -0
- package/dist/inputs.js.map +1 -0
- package/dist/ownerOf.d.ts +7 -0
- package/dist/ownerOf.d.ts.map +1 -0
- package/dist/ownerOf.js +30 -0
- package/dist/ownerOf.js.map +1 -0
- package/dist/packageScope.d.ts +13 -0
- package/dist/packageScope.d.ts.map +1 -0
- package/dist/packageScope.js +28 -0
- package/dist/packageScope.js.map +1 -0
- package/dist/plan.d.ts +12 -0
- package/dist/plan.d.ts.map +1 -0
- package/dist/plan.js +115 -0
- package/dist/plan.js.map +1 -0
- package/dist/project.d.ts +11 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.js +24 -0
- package/dist/project.js.map +1 -0
- package/dist/rejections.d.ts +11 -0
- package/dist/rejections.d.ts.map +1 -0
- package/dist/rejections.js +46 -0
- package/dist/rejections.js.map +1 -0
- package/dist/report.d.ts +22 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +20 -0
- package/dist/report.js.map +1 -0
- package/dist/serverCode.d.ts +20 -0
- package/dist/serverCode.d.ts.map +1 -0
- package/dist/serverCode.js +90 -0
- package/dist/serverCode.js.map +1 -0
- package/dist/settleOrphans.d.ts +5 -0
- package/dist/settleOrphans.d.ts.map +1 -0
- package/dist/settleOrphans.js +43 -0
- package/dist/settleOrphans.js.map +1 -0
- package/dist/specifiers.d.ts +4 -0
- package/dist/specifiers.d.ts.map +1 -0
- package/dist/specifiers.js +52 -0
- package/dist/specifiers.js.map +1 -0
- package/package.json +82 -5
- package/src/BuildFailure.ts +5 -0
- package/src/adapters/appTestConfig.ts +18 -0
- package/src/adapters/appViteConfig.ts +31 -0
- package/src/adapters/bundleCheck.ts +57 -0
- package/src/adapters/copiedCode.ts +103 -0
- package/src/adapters/failuresOf.ts +31 -0
- package/src/adapters/isReadonlyProperty.ts +21 -0
- package/src/adapters/moduleCalls.ts +58 -0
- package/src/adapters/moduleFacts.ts +66 -0
- package/src/adapters/objectForm.ts +74 -0
- package/src/adapters/operationFacts.ts +85 -0
- package/src/adapters/runNode.ts +15 -0
- package/src/adapters/typeReading.ts +63 -0
- package/src/adapters/typeScript.ts +101 -0
- package/src/adapters/unionForm.ts +88 -0
- package/src/adapters/vitePlugin.ts +103 -0
- package/src/adapters/vitePort.ts +5 -0
- package/src/adapters/vitest/setup.ts +12 -0
- package/src/adapters/wireForm.ts +98 -0
- package/src/byText.ts +7 -0
- package/src/cache.ts +28 -0
- package/src/cli.ts +16 -0
- package/src/code.ts +23 -0
- package/src/command.ts +42 -0
- package/src/emit.ts +117 -0
- package/src/facts.ts +70 -0
- package/src/files.ts +24 -0
- package/src/formCode.ts +59 -0
- package/src/generate.ts +86 -0
- package/src/generateRound.ts +60 -0
- package/src/importNames.ts +61 -0
- package/src/inputs.ts +82 -0
- package/src/ownerOf.ts +40 -0
- package/src/packageScope.ts +35 -0
- package/src/plan.ts +138 -0
- package/src/project.ts +30 -0
- package/src/rejections.ts +57 -0
- package/src/report.ts +39 -0
- package/src/serverCode.ts +139 -0
- package/src/settleOrphans.ts +58 -0
- package/src/specifiers.ts +55 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.1 - 2026-11-11
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- The README's examples name a module file after its export, as in `src/modules/notes/Notes.ts` and `#generated/modules/notes/Notes.ts`, and import operations from the module's `server/` folder, as applications write them.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Generating no longer leaves an empty `.<file>.XXXXXX` folder beside every file it writes, under `src/generated` and in `node_modules/.cache/@shivaedev/build`. Each write still replaces the file in one rename, and its temporary folder is removed when the write ends, also when it fails or is interrupted. Folders left by earlier versions stay until you delete them.
|
|
12
|
+
|
|
13
|
+
## 0.1.0 - 2026-11-11
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- The package is published. `appViteConfig` from `@shivaedev/build/adapters/appViteConfig.ts` and `appTestConfig` from `@shivaedev/build/adapters/appTestConfig.ts` give an application its Vite and Vitest configuration with the generator built in: `vite build` and the dev server generate first, and Vitest generates in its global setup before any test file loads.
|
|
18
|
+
- `appViteConfig` runs the bundle check by default, so a build whose browser bundle reaches server code fails; its fourth argument names server-only packages with `serverOnly`. An application whose browser still imports old-form contracts or operation files passes `{ bundleCheck: false }`. The option is temporary: it exists for applications still on the old operation form and goes away with that form.
|
|
19
|
+
- The `shivaedev-build` command runs from source inside a workspace before any build.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ShivaeDev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,217 @@
|
|
|
1
1
|
# @shivaedev/build
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An application's build setup: one import for its Vite configuration and one for its Vitest configuration. Its generator reads each defined module's `run` types and writes the wire the server encodes with and the browser decodes with, so an operation is written once, as its business logic, and the browser receives exactly what the type says. Its Vite plugin and Vitest setup run the generator wherever the files are read, and a build whose browser bundle reaches server code fails.
|
|
4
|
+
|
|
5
|
+
## Why you want this
|
|
6
|
+
|
|
7
|
+
An operation written as `payload` and `*run` has its success and rejections only as types, and types are erased. Without a generator, an application restates them as schemas by hand, and the copy drifts. With it, the module passes the generated wire and the browser imports the generated contract:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { defineModule } from "@shivaedev/contract/defineModule.ts";
|
|
11
|
+
import { notesWire } from "#generated/modules/notes/Notes.ts";
|
|
12
|
+
import { Create } from "#modules/notes/server/Create.ts";
|
|
13
|
+
import { List } from "#modules/notes/server/List.ts";
|
|
14
|
+
import { NotesStore } from "#modules/notes/server/Store.ts";
|
|
15
|
+
|
|
16
|
+
export const Notes = defineModule({ name: "notes", operations: [List, Create], requires: [NotesStore], wire: notesWire });
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
shivaedev-build generate
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
src/generated/modules/notes/Notes.ts: written
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Using it
|
|
28
|
+
|
|
29
|
+
### How to think about it
|
|
30
|
+
|
|
31
|
+
`generate` finds every file of the project's tsconfig that calls `defineModule`, builds one TypeScript program for them and writes one file per module at `src/generated/<the module file's path under src>`. There is no list of modules to keep. The generated files are not committed, so a project runs `generate` before anything that reads them; a run whose inputs have not changed is cheap. Inside Vite and Vitest the plugin and the global setup run it; the command line covers everything else, such as a type check.
|
|
32
|
+
|
|
33
|
+
The generator never guesses. Each type `run` returns maps to the one schema whose `Type` is exactly that type, or the run stops with a refusal that says what to write instead. The compiler then checks the generated wire against `run` on every type check, through [`@shivaedev/contract`'s module checks](https://github.com/ShivaeDev/platform/tree/main/packages/contract#the-wire-and-the-browsers-contract), so a file that went stale is usually a compile error on the module that names the operation, including a success type that gains or loses an optional property at any struct position the check walks. One change is not: an optional property that only one side has on a `Schema.Struct` behind another schema, such as a transformation, a brand or `Schema.suspend`, still type-checks and is dropped on the wire or never sent. `generate --check` is the guard against it.
|
|
34
|
+
|
|
35
|
+
### Set up an application
|
|
36
|
+
|
|
37
|
+
An application's `vite.config.ts` and `vitest.config.ts` each import one function and pass only what is the application's own, such as its Vite plugins and the host routes its dev server forwards:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
41
|
+
import react from "@vitejs/plugin-react";
|
|
42
|
+
import { appViteConfig } from "@shivaedev/build/adapters/appViteConfig.ts";
|
|
43
|
+
|
|
44
|
+
export default appViteConfig([tailwindcss(), react()], [], ["/health"]);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { appTestConfig } from "@shivaedev/build/adapters/appTestConfig.ts";
|
|
49
|
+
|
|
50
|
+
export default appTestConfig();
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`appViteConfig` adds the generator's Vite plugin and the bundle check to the application's plugins, so `vite build` and the dev server generate first and a browser bundle that reaches server code fails the build. The dev server listens on `127.0.0.1` at the port in `VITE_PORT`, then 5173, and forwards `/api/auth`, `/rpc` and every path in the third argument to the application host on `127.0.0.1` at the port in `PORT`, then 3000, keeping the Host header the browser sent. The fourth argument overrides either port, as in `{ webPort: 5273, apiPort: 3100 }`, and names the packages the bundle check treats as server-only, as in `{ serverOnly: ["pg-boss"] }`. Path resolution follows the tsconfig.
|
|
54
|
+
|
|
55
|
+
`appTestConfig` builds on Quality's [`testProjects`](https://github.com/ShivaeDev/platform/tree/main/packages/quality#readme), resolves imports for the browser and for the server, inlines the `@shivaedev` packages for the test server and generates as Vitest's global setup, before any test file loads. Its second argument goes to `testProjects`, so `appTestConfig([], { connectionBudget: 84, connectionsPerWorker: 14 })` or `appTestConfig([], { maxWorkers: 4 })` sizes the test workers. The second argument of `appViteConfig` and the first of `appTestConfig` add export conditions for development inside a workspace, such as `["@shivaedev/source"]`; a published application passes none.
|
|
56
|
+
|
|
57
|
+
An application whose browser still imports contracts or operation files of the old operation form passes `{ bundleCheck: false }` in the fourth argument of `appViteConfig`, and its build then generates without checking the bundle. The option is temporary: it exists for applications still on the old operation form and goes away with that form.
|
|
58
|
+
|
|
59
|
+
The application's `package.json` runs the generator before anything that reads the files without Vite, and `prepare` makes `pnpm install` write them in a fresh checkout:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"scripts": {
|
|
64
|
+
"generate": "shivaedev-build generate",
|
|
65
|
+
"prepare": "pnpm generate",
|
|
66
|
+
"typecheck": "pnpm generate && tsc --noEmit"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
pnpm does not run `prepare` on a production install (`pnpm install --prod`), so a production install without development dependencies succeeds without the generator; the files must already be written, as `pnpm build` writes them through the Vite plugin. The folder's contents stay out of Git except a README that names the command, and `quality lint` runs the `generate` script before it reads the sources, so no configuration names the folder:
|
|
72
|
+
|
|
73
|
+
```gitignore
|
|
74
|
+
src/generated/*
|
|
75
|
+
!src/generated/README.md
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Generate the files
|
|
79
|
+
|
|
80
|
+
Run the command in the folder that holds the project's `tsconfig.json`:
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
shivaedev-build generate
|
|
84
|
+
shivaedev-build generate --check
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`generate` writes each file that is missing or differs, and reports every module as `written`, `current` (derived again and equal to the file) or `unchanged, from the cache`. A generated file whose first line names a module file that is gone or no longer defines a module, because it was renamed or deleted, is removed and reported as `removed`; a file under `src/generated` that the generator did not write is left alone. `--check` writes nothing and exits 1 listing each missing, stale or orphaned file with "run `pnpm generate`". A refusal exits 1 with its message, and the refused module's file is not written. For the same inputs the output is byte for byte the same.
|
|
88
|
+
|
|
89
|
+
A workspace package can run the generator from source before anything is built:
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
node --conditions=@shivaedev/source packages/build/src/cli.ts generate
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Generate inside Vite and Vitest
|
|
96
|
+
|
|
97
|
+
The dev server, the build and the tests read the generated files through Vite, so the plugin and the global setup generate before they do:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { buildPlugin } from "@shivaedev/build/adapters/vitePlugin.ts";
|
|
101
|
+
|
|
102
|
+
export default {
|
|
103
|
+
plugins: [buildPlugin({ serverOnly: ["pg-boss"] })],
|
|
104
|
+
test: { globalSetup: ["@shivaedev/build/adapters/vitest/setup.ts"] },
|
|
105
|
+
};
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`buildPlugin` generates when `vite build` or the dev server starts, in the folder Vite runs in. A refusal stops the build, or keeps the dev server from starting, with the generator's message. While the dev server runs, a change to a file that went into any module's last run, such as an operation's `run`, generates again: each rewritten file's importers are invalidated in Vite's module graph and the browser reloads. A file under `src` that calls `defineModule` and no run has read yet, such as a module file created while the dev server runs, generates too, and when the run writes a generated file that did not exist the browser reloads, so a page that failed to resolve its `#generated/...` import loads without a restart. A refusal then prints the generator's message in the terminal and shows it in the browser's error overlay, and the module's last file stays in place until the next run succeeds.
|
|
109
|
+
|
|
110
|
+
The global setup generates once before Vitest loads any test file, and a refusal stops the run before a test starts. Runs that start at once, such as two Vitest processes on one project, each generate and leave the files correct, because every file is written whole through a rename.
|
|
111
|
+
|
|
112
|
+
### Server code in the browser bundle
|
|
113
|
+
|
|
114
|
+
With a generated client the browser never needs a module or its operations, so the plugin fails a client build whose module graph holds server code. It reads the bundler's module graph, from each client entry, and stops at the nearest module that is:
|
|
115
|
+
|
|
116
|
+
- a module file, one that imports `defineModule` from `@shivaedev/contract/defineModule.ts`;
|
|
117
|
+
- an operation file, one that imports `query` or `command` from `@shivaedev/contract/operation.ts`;
|
|
118
|
+
- a file under a `server/` folder;
|
|
119
|
+
- a Node builtin;
|
|
120
|
+
- `effect/sql`, imported from outside Effect (Effect's own index re-exports modules that import it, which do not count);
|
|
121
|
+
- part of a package listed in `serverOnly`.
|
|
122
|
+
|
|
123
|
+
The build fails with the import chain from the client entry to that module:
|
|
124
|
+
|
|
125
|
+
```text
|
|
126
|
+
Server code reached the browser bundle: src/modules/notes/Notes.ts is a module file: it calls defineModule. The import chain from the client entry:
|
|
127
|
+
index.html
|
|
128
|
+
→ src/client.ts
|
|
129
|
+
→ src/screens/notes.ts
|
|
130
|
+
→ src/modules/notes/Notes.ts
|
|
131
|
+
The browser reaches a defined module through its generated client in src/generated and imports no server code.
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The browser imports `Notes` from `#generated/modules/notes/Notes.ts` instead.
|
|
135
|
+
|
|
136
|
+
### The generated file
|
|
137
|
+
|
|
138
|
+
For the module above, the file starts with a line saying it is generated from `src/modules/notes/Notes.ts`, must not be edited and is not committed. It exports the module's wire, named after the module's `name`, the browser's contract under the module's own export name, built by `clientContract`, and a closing `ClientMatchesModule` assertion:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
export const notesWire = {
|
|
142
|
+
create: { rejections: { TitleTaken }, success: NoteCard },
|
|
143
|
+
list: { rejections: { Unauthorized }, success: Schema.Array(Schema.Struct({ id: Schema.Number, title: Schema.String })) },
|
|
144
|
+
} as const;
|
|
145
|
+
|
|
146
|
+
export const Notes = clientContract({
|
|
147
|
+
commands: {
|
|
148
|
+
create: { invalidates: () => [notes.list] },
|
|
149
|
+
},
|
|
150
|
+
name: "notes",
|
|
151
|
+
payloads: {
|
|
152
|
+
create: NoteFields,
|
|
153
|
+
},
|
|
154
|
+
queries: {
|
|
155
|
+
list: { reads: () => [notes.list] },
|
|
156
|
+
},
|
|
157
|
+
wire: notesWire,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
export const notesMatchModule: ClientMatchesModule<typeof Notes, typeof NotesModule> = true;
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Payloads, `reads`, `readsCollections`, `invalidates` and the module's `middleware`, `subject` and `keyScope` are copied as written, with the imports they use. Two imports that share a name get distinct local names, so a `NoteMissing` from one file and a `NoteMissing` from another both fit. A value declared in the operation's own file, or imported there by a relative path, is refused, because the generated file cannot import it: move it to a module the operation imports through a package import such as `#modules/notes/model.ts`.
|
|
164
|
+
|
|
165
|
+
### What `run` may return
|
|
166
|
+
|
|
167
|
+
| `run` returns | The wire carries |
|
|
168
|
+
| -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
169
|
+
| `string`, `number`, `boolean`, `bigint`, `null`, `undefined`, `void` | `Schema.String`, `Schema.Number`, `Schema.Boolean`, `Schema.BigInt`, `Schema.Null`, `Schema.Undefined`, `Schema.Void` |
|
|
170
|
+
| string, number and boolean literals and their unions | `Schema.Literal`, `Schema.Literals` |
|
|
171
|
+
| `T[]` and `readonly T[]` | `Schema.Array`, wrapped in `Schema.mutable` when mutable |
|
|
172
|
+
| tuples of required elements, readonly or mutable | `Schema.Tuple`, wrapped in `Schema.mutable` when mutable |
|
|
173
|
+
| plain objects, interfaces and type literals | `Schema.Struct`, with `Schema.optionalKey` for an optional property and `Schema.mutableKey` for a property that is not readonly |
|
|
174
|
+
| string-keyed records | `Schema.Record(Schema.String, …)` |
|
|
175
|
+
| a union of objects told apart by one literal property | `Schema.Union` |
|
|
176
|
+
| `T \| null` | `Schema.NullOr` |
|
|
177
|
+
| `Date`, `DateTime.Utc`, `Option<T>` | `Schema.Date`, `Schema.DateTimeUtc`, `Schema.Option` |
|
|
178
|
+
| an instance of an exported Schema class | that class, imported from its module |
|
|
179
|
+
|
|
180
|
+
Effect RPC encodes with `Schema.toCodecJson`, so a `Date` travels as an ISO string and arrives as a `Date`, a `bigint` travels as a string, and `NaN` and the infinities travel as strings. Each of these arrives equal to what `run` returned and of the same class. One value does not: `-0` arrives as `0`, because JSON has no `-0`.
|
|
181
|
+
|
|
182
|
+
A class instance and a same-shaped interface are told apart by declaration: a helper typed to return an interface with the fields of a Schema class is written as a struct, and an instance of the class as the class.
|
|
183
|
+
|
|
184
|
+
An optional property is written with `?` under `exactOptionalPropertyTypes`, such as `flag?: boolean` or `reviewedAt?: Date | null`, and an absent key is the only way to leave it out.
|
|
185
|
+
|
|
186
|
+
Anything else is refused, such as a `Map`, a class that is not a Schema class or not exported, a function, `any`, `string | number`, an enum, a branded type, a type that contains itself, a tuple with optional or rest elements, a record whose keys are not `string`, `null | undefined` (the wire would turn one into the other), a property typed `T | undefined`, or an optional property typed `T | undefined`:
|
|
187
|
+
|
|
188
|
+
```text
|
|
189
|
+
refused.returnsMap: run returns Map<string, number> at success, which has no exact wire form; return a plain object, an array or a string-keyed record
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The path after `at` points into the returned value, such as `success.summary`.
|
|
193
|
+
|
|
194
|
+
### Rejections
|
|
195
|
+
|
|
196
|
+
An operation's rejections are the tagged failures of its `run` and, for a query, of its read policy, each the exported class it is raised as and imported from the module that declares it. Two classes of the same shape and tag are different rejections: the generated file imports the one `run` raises. A failure that states `isRetryable`, a `SchemaError`, a `QueryReadDenied` and the automatic `InternalServerError` and `ServiceUnavailable` are left out, and nothing adds a `Conflict`. Any failure class with an `isRetryable` property is infrastructure and reaches the browser as one of the two automatic failures, so never put `isRetryable` on a rejection the browser should receive. A failure without a `_tag`, whose class is not exported, or whose class is not a Schema class, such as a `Data.TaggedError`, is refused:
|
|
197
|
+
|
|
198
|
+
```text
|
|
199
|
+
refused.failsUntagged: run fails with string, which has no _tag; fail with an exported tagged error class instead
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Staying current
|
|
203
|
+
|
|
204
|
+
Each module's inputs are the contents of every project file in its import graph, its tsconfig and the files it extends, the project's declaration files, which can declare global types, the lockfile, which stands in for installed packages, and the generator's own code and TypeScript's version. They are recorded under `node_modules/.cache/@shivaedev/build/`. A run whose inputs are unchanged builds no program and reports the module as unchanged; a generated file removed meanwhile comes back from the cache. Files are written only when their content differs, through a fresh file renamed into place, so a reader never sees half a file.
|
|
205
|
+
|
|
206
|
+
A run in the dev server after a save that changes a module's inputs builds a program again, and later programs of one process reuse the declaration files the first one parsed. On a developer laptop, the first run takes about 0.8 s and each regeneration about 0.15 s for this package's fixture notes module of seven operations; for the starter's notes module written as a defined module, nine operations over SQL, identity and rate limiting, the first run takes about 1.4 s and each regeneration about 0.4 s.
|
|
207
|
+
|
|
208
|
+
A run that builds a program takes the machine-wide [heavy lock](https://github.com/ShivaeDev/platform/tree/main/packages/heavy-lock), so it waits while another heavy run holds it; an unchanged run does not.
|
|
209
|
+
|
|
210
|
+
`ClientMatchesModule` compares payloads, successes and rejections. A changed `invalidates`, `reads` or key scope changes the module's inputs, so `generate --check` reports the file stale and the next `generate` writes the change.
|
|
211
|
+
|
|
212
|
+
### Limits
|
|
213
|
+
|
|
214
|
+
- The plugin and the global setup take Vite's and Vitest's root as the project folder, the one that holds `tsconfig.json`.
|
|
215
|
+
- It reads types through TypeScript 6's API, while this repository type-checks with TypeScript 7; a disagreement between the two shows as a compile error on the module.
|
|
216
|
+
- An invalid `Date` cannot be encoded, so the caller gets `InternalServerError`.
|
|
217
|
+
- A module file must lie under `src`, define exactly one module and export it as a const.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare const BuildFailure_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
2
|
+
readonly _tag: "BuildFailure";
|
|
3
|
+
} & Readonly<A>;
|
|
4
|
+
export declare class BuildFailure extends BuildFailure_base<{
|
|
5
|
+
readonly message: string;
|
|
6
|
+
}> {
|
|
7
|
+
}
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=BuildFailure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BuildFailure.d.ts","sourceRoot":"","sources":["../src/BuildFailure.ts"],"names":[],"mappings":";;;AAEA,qBAAa,YAAa,SAAQ,kBAAiC;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB,CAAC;CAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BuildFailure.js","sourceRoot":"","sources":["../src/BuildFailure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,MAAM,OAAO,YAAa,SAAQ,IAAI,CAAC,WAAW,CAAC,cAAc,CAE/D;CAAG"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ViteUserConfig } from "vitest/config";
|
|
2
|
+
import { type TestProjectsOptions } from "@shivaedev/quality/adapters/testProjects.ts";
|
|
3
|
+
export declare function appTestConfig(conditions?: string[], options?: TestProjectsOptions): ViteUserConfig;
|
|
4
|
+
//# sourceMappingURL=appTestConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appTestConfig.d.ts","sourceRoot":"","sources":["../../src/adapters/appTestConfig.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,6CAA6C,CAAC;AAErG,wBAAgB,aAAa,CAAC,UAAU,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,mBAAwB,GAAG,cAAc,CAa1G"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { testProjects } from "@shivaedev/quality/adapters/testProjects.ts";
|
|
3
|
+
export function appTestConfig(conditions = [], options = {}) {
|
|
4
|
+
const server = { resolve: { conditions: [...conditions, "node", "development|production"] } };
|
|
5
|
+
return {
|
|
6
|
+
// Vitest loads the global setup in its own environment, which needs the application's conditions to find the generator's sources.
|
|
7
|
+
environments: { "__vitest__": server },
|
|
8
|
+
resolve: { conditions: [...conditions, "module", "browser", "development|production"] },
|
|
9
|
+
ssr: server,
|
|
10
|
+
test: {
|
|
11
|
+
...testProjects(options),
|
|
12
|
+
globalSetup: [fileURLToPath(import.meta.resolve("#adapters/vitest/setup.ts"))],
|
|
13
|
+
server: { deps: { inline: [/^@shivaedev\//u] } },
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=appTestConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appTestConfig.js","sourceRoot":"","sources":["../../src/adapters/appTestConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAA4B,YAAY,EAAE,MAAM,6CAA6C,CAAC;AAErG,MAAM,UAAU,aAAa,CAAC,UAAU,GAAa,EAAE,EAAE,OAAO,GAAwB,EAAE;IACzF,MAAM,MAAM,GAAG,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,CAAC,GAAG,UAAU,EAAE,MAAM,EAAE,wBAAwB,CAAC,EAAE,EAAE,CAAC;IAC9F,OAAO;QACN,kIAAkI;QAClI,YAAY,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE;QACtC,OAAO,EAAE,EAAE,UAAU,EAAE,CAAC,GAAG,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,wBAAwB,CAAC,EAAE;QACvF,GAAG,EAAE,MAAM;QACX,IAAI,EAAE;YACL,GAAG,YAAY,CAAC,OAAO,CAAC;YACxB,WAAW,EAAE,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,CAAC;YAC9E,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,gBAAgB,CAAC,EAAE,EAAE;SAChD;KACD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PluginOption } from "vite";
|
|
2
|
+
import { type BuildPluginOptions } from "#adapters/vitePlugin.ts";
|
|
3
|
+
export interface AppViteOptions extends BuildPluginOptions {
|
|
4
|
+
readonly apiPort?: number;
|
|
5
|
+
readonly webPort?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function appViteConfig(plugins: PluginOption[], conditions?: string[], proxyPaths?: string[], { webPort, apiPort, ...build }?: AppViteOptions): {
|
|
8
|
+
plugins: PluginOption[];
|
|
9
|
+
resolve: {
|
|
10
|
+
conditions: string[];
|
|
11
|
+
tsconfigPaths: boolean;
|
|
12
|
+
};
|
|
13
|
+
server: {
|
|
14
|
+
host: string;
|
|
15
|
+
port: number;
|
|
16
|
+
proxy: {
|
|
17
|
+
[k: string]: {
|
|
18
|
+
changeOrigin: boolean;
|
|
19
|
+
target: string;
|
|
20
|
+
ws: boolean;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
strictPort: boolean;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=appViteConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appViteConfig.d.ts","sourceRoot":"","sources":["../../src/adapters/appViteConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,EAAE,KAAK,kBAAkB,EAAe,MAAM,yBAAyB,CAAC;AAG/E,MAAM,WAAW,cAAe,SAAQ,kBAAkB;IACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,aAAa,CAC5B,OAAO,EAAE,YAAY,EAAE,EACvB,UAAU,GAAE,MAAM,EAAO,EACzB,UAAU,GAAE,MAAM,EAAO,EACzB,EAAE,OAAqC,EAAE,OAAgC,EAAE,GAAG,KAAK,EAAE,GAAE,cAAmB;;;;;;;QAMxG,IAAI;QACJ,IAAI;QACJ,KAAK;;;;;;;QAML,UAAU;;EAGZ"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { buildPlugin } from "#adapters/vitePlugin.ts";
|
|
2
|
+
import { vitePort } from "#adapters/vitePort.ts";
|
|
3
|
+
export function appViteConfig(plugins, conditions = [], proxyPaths = [], { webPort = vitePort("VITE_PORT", 5173), apiPort = vitePort("PORT", 3000), ...build } = {}) {
|
|
4
|
+
return {
|
|
5
|
+
plugins: [...plugins, ...buildPlugin(build)],
|
|
6
|
+
resolve: { conditions, tsconfigPaths: true },
|
|
7
|
+
server: {
|
|
8
|
+
host: "127.0.0.1",
|
|
9
|
+
port: webPort,
|
|
10
|
+
proxy: Object.fromEntries(["/api/auth", "/rpc", ...proxyPaths].map((path) => [
|
|
11
|
+
path,
|
|
12
|
+
{ changeOrigin: false, target: `http://127.0.0.1:${apiPort}`, ws: path === "/rpc" },
|
|
13
|
+
])),
|
|
14
|
+
strictPort: true,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=appViteConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appViteConfig.js","sourceRoot":"","sources":["../../src/adapters/appViteConfig.ts"],"names":[],"mappings":"AACA,OAAO,EAA2B,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAOjD,MAAM,UAAU,aAAa,CAC5B,OAAuB,EACvB,UAAU,GAAa,EAAE,EACzB,UAAU,GAAa,EAAE,EACzB,EAAE,OAAO,GAAG,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,KAAK,EAAE,GAAmB,EAAE;IAE1G,OAAO;QACN,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5C,OAAO,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,IAAI,EAAE;QAC5C,MAAM,EAAE;YACP,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,MAAM,CAAC,WAAW,CACxB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;gBAClD,IAAI;gBACJ,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,OAAO,EAAE,EAAE,EAAE,EAAE,IAAI,KAAK,MAAM,EAAE;aACnF,CAAC,CACF;YACD,UAAU,EAAE,IAAI;SAChB;KACD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundleCheck.d.ts","sourceRoot":"","sources":["../../src/adapters/bundleCheck.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAU,MAAM,MAAM,CAAC;AAkC3C,wBAAgB,WAAW,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAmBjE"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { isBuiltin } from "node:module";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { Option } from "effect";
|
|
4
|
+
import { runNode } from "#adapters/runNode.ts";
|
|
5
|
+
import { serverCodeIn } from "#serverCode.ts";
|
|
6
|
+
const BROWSER_EXTERNAL = "__vite-browser-external:";
|
|
7
|
+
function graphOf(context) {
|
|
8
|
+
const modules = new Map();
|
|
9
|
+
const entries = [];
|
|
10
|
+
for (const id of context.getModuleIds()) {
|
|
11
|
+
const info = context.getModuleInfo(id);
|
|
12
|
+
if (info !== null) {
|
|
13
|
+
if (info.isEntry) {
|
|
14
|
+
entries.push(id);
|
|
15
|
+
}
|
|
16
|
+
const bare = id.startsWith(BROWSER_EXTERNAL) ? id.slice(BROWSER_EXTERNAL.length) : id;
|
|
17
|
+
modules.set(id, { builtin: isBuiltin(bare), imports: [...info.importedIds, ...info.dynamicallyImportedIds] });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return { entries, modules };
|
|
21
|
+
}
|
|
22
|
+
async function markersFrom(context, root) {
|
|
23
|
+
const importer = join(root, "index.html");
|
|
24
|
+
async function resolved(specifier) {
|
|
25
|
+
return Option.fromNullishOr((await context.resolve(specifier, importer))?.id);
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
defineModule: await resolved("@shivaedev/contract/defineModule.ts"),
|
|
29
|
+
operation: await resolved("@shivaedev/contract/operation.ts"),
|
|
30
|
+
sql: Option.map(await resolved("effect/sql"), dirname),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function bundleCheck(serverOnly) {
|
|
34
|
+
let root = ".";
|
|
35
|
+
return {
|
|
36
|
+
apply: "build",
|
|
37
|
+
applyToEnvironment: (environment) => environment.config.consumer === "client",
|
|
38
|
+
async buildEnd(error) {
|
|
39
|
+
if (error !== undefined) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const found = await runNode(serverCodeIn(graphOf(this), await markersFrom(this, root), { root, serverOnly }));
|
|
43
|
+
if (Option.isSome(found)) {
|
|
44
|
+
this.error(found.value);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
configResolved(resolved) {
|
|
48
|
+
root = resolved.root;
|
|
49
|
+
},
|
|
50
|
+
name: "shivaedev:build-bundle-check",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=bundleCheck.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundleCheck.js","sourceRoot":"","sources":["../../src/adapters/bundleCheck.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import type { CodePart } from "#facts.ts";
|
|
3
|
+
export interface Copying {
|
|
4
|
+
readonly checker: ts.TypeChecker;
|
|
5
|
+
readonly label: string;
|
|
6
|
+
readonly refuse: (message: string) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function copiedCode(copying: Copying, node: ts.Node): readonly CodePart[];
|
|
9
|
+
//# sourceMappingURL=copiedCode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copiedCode.d.ts","sourceRoot":"","sources":["../../src/adapters/copiedCode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,WAAW,CAAC;AAEtD,MAAM,WAAW,OAAO;IACvB,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC;IAEjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAwED,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,SAAS,QAAQ,EAAE,CAsB/E"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
const LOCAL_DECLARATIONS = new Set([
|
|
3
|
+
ts.SyntaxKind.VariableDeclaration,
|
|
4
|
+
ts.SyntaxKind.FunctionDeclaration,
|
|
5
|
+
ts.SyntaxKind.ClassDeclaration,
|
|
6
|
+
ts.SyntaxKind.InterfaceDeclaration,
|
|
7
|
+
ts.SyntaxKind.TypeAliasDeclaration,
|
|
8
|
+
ts.SyntaxKind.EnumDeclaration,
|
|
9
|
+
ts.SyntaxKind.ModuleDeclaration,
|
|
10
|
+
ts.SyntaxKind.Parameter,
|
|
11
|
+
ts.SyntaxKind.BindingElement,
|
|
12
|
+
]);
|
|
13
|
+
function importBinding(declaration) {
|
|
14
|
+
return ts.isImportSpecifier(declaration) || ts.isImportClause(declaration) || ts.isNamespaceImport(declaration) ? declaration : undefined;
|
|
15
|
+
}
|
|
16
|
+
function clauseOf(binding) {
|
|
17
|
+
if (ts.isImportClause(binding)) {
|
|
18
|
+
return binding;
|
|
19
|
+
}
|
|
20
|
+
return ts.isNamespaceImport(binding) ? binding.parent : binding.parent.parent;
|
|
21
|
+
}
|
|
22
|
+
function importedName(binding) {
|
|
23
|
+
if (ts.isImportClause(binding)) {
|
|
24
|
+
return "default";
|
|
25
|
+
}
|
|
26
|
+
return ts.isNamespaceImport(binding) ? "*" : (binding.propertyName ?? binding.name).text;
|
|
27
|
+
}
|
|
28
|
+
function importFact(copying, binding, local) {
|
|
29
|
+
const clause = clauseOf(binding);
|
|
30
|
+
const declaration = clause.parent;
|
|
31
|
+
if (!ts.isStringLiteral(declaration.moduleSpecifier)) {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
const specifier = declaration.moduleSpecifier.text;
|
|
35
|
+
const file = declaration.getSourceFile().fileName;
|
|
36
|
+
if (specifier.startsWith(".")) {
|
|
37
|
+
copying.refuse(`${copying.label} imports ${local} by the relative path "${specifier}" in ${file}; import it through a package import, such as a # specifier, so the generated file can import it too`);
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
const name = importedName(binding);
|
|
41
|
+
const target = copying.checker.getSymbolAtLocation(declaration.moduleSpecifier)?.valueDeclaration?.getSourceFile().fileName;
|
|
42
|
+
const typeOnly = clause.isTypeOnly || (ts.isImportSpecifier(binding) && binding.isTypeOnly);
|
|
43
|
+
return { local, name, specifier, target, typeOnly, writtenIn: file };
|
|
44
|
+
}
|
|
45
|
+
function referenceOf(copying, node, identifier) {
|
|
46
|
+
const symbol = ts.isShorthandPropertyAssignment(identifier.parent)
|
|
47
|
+
? copying.checker.getShorthandAssignmentValueSymbol(identifier.parent)
|
|
48
|
+
: copying.checker.getSymbolAtLocation(identifier);
|
|
49
|
+
const declaration = symbol?.declarations?.[0];
|
|
50
|
+
if (declaration === undefined) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
const binding = importBinding(declaration);
|
|
54
|
+
if (binding !== undefined) {
|
|
55
|
+
return importFact(copying, binding, identifier.text);
|
|
56
|
+
}
|
|
57
|
+
const inside = declaration.pos >= node.pos && declaration.end <= node.end;
|
|
58
|
+
const sameFile = declaration.getSourceFile() === node.getSourceFile();
|
|
59
|
+
return sameFile && !inside && LOCAL_DECLARATIONS.has(declaration.kind) ? "local" : undefined;
|
|
60
|
+
}
|
|
61
|
+
// The code as written, with each imported name kept as its import, so the generated file can import and rename it.
|
|
62
|
+
export function copiedCode(copying, node) {
|
|
63
|
+
const source = node.getSourceFile();
|
|
64
|
+
const parts = [];
|
|
65
|
+
let position = node.getStart(source);
|
|
66
|
+
function visit(child) {
|
|
67
|
+
if (ts.isIdentifier(child)) {
|
|
68
|
+
const reference = referenceOf(copying, node, child);
|
|
69
|
+
if (reference === "local") {
|
|
70
|
+
copying.refuse(`${copying.label} uses ${child.text}, which is declared in ${source.fileName}; move it to a module the operation imports it from, such as the module's model file`);
|
|
71
|
+
}
|
|
72
|
+
else if (reference !== undefined) {
|
|
73
|
+
const shorthand = ts.isShorthandPropertyAssignment(child.parent) ? `${child.text}: ` : "";
|
|
74
|
+
parts.push(source.text.slice(position, child.getStart(source)) + shorthand, reference);
|
|
75
|
+
position = child.end;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
ts.forEachChild(child, visit);
|
|
79
|
+
}
|
|
80
|
+
visit(node);
|
|
81
|
+
parts.push(source.text.slice(position, node.end));
|
|
82
|
+
return parts.filter((part) => part !== "");
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=copiedCode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copiedCode.js","sourceRoot":"","sources":["../../src/adapters/copiedCode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { type TypeReading } from "#adapters/typeReading.ts";
|
|
3
|
+
import type { Failure } from "#facts.ts";
|
|
4
|
+
export declare function failuresOf(reading: TypeReading, errors: readonly ts.Type[]): readonly Failure[];
|
|
5
|
+
//# sourceMappingURL=failuresOf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"failuresOf.d.ts","sourceRoot":"","sources":["../../src/adapters/failuresOf.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAgC,KAAK,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC1F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0BzC,wBAAgB,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,IAAI,EAAE,GAAG,SAAS,OAAO,EAAE,CAE/F"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { declaredClass, isSchemaClass } from "#adapters/typeReading.ts";
|
|
3
|
+
function failureOf(reading, member) {
|
|
4
|
+
if (member.flags & ts.TypeFlags.Never) {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
if (member.getProperty("isRetryable") !== undefined) {
|
|
8
|
+
return { kind: "retryable" };
|
|
9
|
+
}
|
|
10
|
+
const text = reading.checker.typeToString(member);
|
|
11
|
+
const tagProperty = member.getProperty("_tag");
|
|
12
|
+
const tag = tagProperty === undefined ? undefined : reading.checker.getTypeOfSymbol(tagProperty);
|
|
13
|
+
if (tag === undefined || !tag.isStringLiteral()) {
|
|
14
|
+
return { kind: "untagged", text };
|
|
15
|
+
}
|
|
16
|
+
// Object.assign(new NoteChanged(...), { cause }) raises a NoteChanged whose type is an intersection.
|
|
17
|
+
const parts = member.isIntersection() ? member.types : [member];
|
|
18
|
+
const symbol = parts.map((part) => part.getSymbol()).find((candidate) => candidate !== undefined && candidate.flags & ts.SymbolFlags.Class);
|
|
19
|
+
const declared = symbol === undefined ? undefined : declaredClass(reading, symbol);
|
|
20
|
+
if (symbol === undefined || declared?.exportName === undefined) {
|
|
21
|
+
return { kind: "unexported", tag: tag.value, text };
|
|
22
|
+
}
|
|
23
|
+
return { declared, kind: "class", schema: isSchemaClass(reading, symbol), tag: tag.value };
|
|
24
|
+
}
|
|
25
|
+
// A rejection is the class run raises, so each failure keeps the declaration it came from, never just its shape.
|
|
26
|
+
export function failuresOf(reading, errors) {
|
|
27
|
+
return errors.flatMap((error) => (error.isUnion() ? error.types : [error])).flatMap((member) => failureOf(reading, member) ?? []);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=failuresOf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"failuresOf.js","sourceRoot":"","sources":["../../src/adapters/failuresOf.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,aAAa,EAAoB,MAAM,0BAA0B,CAAC;AAG1F,SAAS,SAAS,CAAC,OAAoB,EAAE,MAAe;IACvD,IAAI,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACvC,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,IAAI,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,KAAK,SAAS,EAAE,CAAC;QACrD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAC9B,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAG,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;IACjG,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,EAAE,CAAC;QACjD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IACnC,CAAC;IACD,qGAAqG;IACrG,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAChE,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC5I,MAAM,QAAQ,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACnF,IAAI,MAAM,KAAK,SAAS,IAAI,QAAQ,EAAE,UAAU,KAAK,SAAS,EAAE,CAAC;QAChE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;IACrD,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC;AAC5F,CAAC;AAED,iHAAiH;AACjH,MAAM,UAAU,UAAU,CAAC,OAAoB,EAAE,MAA0B;IAC1E,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;AACnI,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
declare module "typescript" {
|
|
3
|
+
function getCheckFlags(symbol: ts.Symbol): number;
|
|
4
|
+
function getDeclarationModifierFlagsFromSymbol(symbol: ts.Symbol): ts.ModifierFlags;
|
|
5
|
+
interface TypeChecker {
|
|
6
|
+
getExactOptionalProperties: (type: ts.Type) => ts.Symbol[];
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export declare function isReadonlyProperty(property: ts.Symbol): boolean;
|
|
10
|
+
//# sourceMappingURL=isReadonlyProperty.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isReadonlyProperty.d.ts","sourceRoot":"","sources":["../../src/adapters/isReadonlyProperty.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAK5B,OAAO,QAAQ,YAAY,CAAC;IAC3B,SAAS,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC;IAClD,SAAS,qCAAqC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,GAAG,EAAE,CAAC,aAAa,CAAC;IACpF,UAAU,WAAW;QACpB,0BAA0B,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,MAAM,EAAE,CAAC;KAC3D;CACD;AAID,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,EAAE,CAAC,MAAM,GAAG,OAAO,CAK/D"}
|