shapecraft 1.0.0
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/CLAUDE.md +227 -0
- package/README.md +22 -0
- package/apps/cli/node_modules/.bin/prettier +21 -0
- package/apps/cli/node_modules/.bin/tsc +21 -0
- package/apps/cli/node_modules/.bin/tsserver +21 -0
- package/apps/cli/node_modules/.bin/tsx +21 -0
- package/apps/cli/node_modules/.bin/vitest +21 -0
- package/apps/cli/package.json +47 -0
- package/apps/cli/src/index.ts +98 -0
- package/apps/cli/tsconfig.cjs.json +10 -0
- package/apps/cli/tsconfig.esm.json +10 -0
- package/apps/cli/tsconfig.json +22 -0
- package/package.json +16 -0
- package/packages/core/node_modules/.bin/prettier +21 -0
- package/packages/core/node_modules/.bin/tsc +21 -0
- package/packages/core/node_modules/.bin/tsserver +21 -0
- package/packages/core/node_modules/.bin/tsx +21 -0
- package/packages/core/node_modules/.bin/vitest +21 -0
- package/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/packages/core/package.json +44 -0
- package/packages/core/src/common/array.test.ts +19 -0
- package/packages/core/src/common/array.ts +15 -0
- package/packages/core/src/common/index.ts +5 -0
- package/packages/core/src/common/is.ts +23 -0
- package/packages/core/src/common/object.ts +35 -0
- package/packages/core/src/common/phantom.ts +1 -0
- package/packages/core/src/common/result.ts +43 -0
- package/packages/core/src/common/string.ts +28 -0
- package/packages/core/src/common/types.ts +34 -0
- package/packages/core/src/index.ts +1 -0
- package/packages/core/src/shape/annotate.ts +139 -0
- package/packages/core/src/shape/annotation.ts +47 -0
- package/packages/core/src/shape/base.ts +71 -0
- package/packages/core/src/shape/builder.test.ts +728 -0
- package/packages/core/src/shape/builder.ts +475 -0
- package/packages/core/src/shape/error.ts +4 -0
- package/packages/core/src/shape/index.ts +3 -0
- package/packages/core/src/shape/number.ts +118 -0
- package/packages/core/src/shape/shape.test.ts +792 -0
- package/packages/core/src/shape/shape.ts +377 -0
- package/packages/core/src/shape/tags.ts +14 -0
- package/packages/core/src/shape/transforms/index.ts +3 -0
- package/packages/core/src/shape/transforms/json-schema/index.ts +2 -0
- package/packages/core/src/shape/transforms/json-schema/transform.test.ts +850 -0
- package/packages/core/src/shape/transforms/json-schema/transform.ts +882 -0
- package/packages/core/src/shape/transforms/json-schema/types.ts +132 -0
- package/packages/core/src/shape/transforms/sql/dialects/dialect.ts +89 -0
- package/packages/core/src/shape/transforms/sql/dialects/index.ts +14 -0
- package/packages/core/src/shape/transforms/sql/dialects/postgres.ts +392 -0
- package/packages/core/src/shape/transforms/sql/dialects/sqlite.ts +333 -0
- package/packages/core/src/shape/transforms/sql/from-sql.test.ts +704 -0
- package/packages/core/src/shape/transforms/sql/from-sql.ts +210 -0
- package/packages/core/src/shape/transforms/sql/index.ts +3 -0
- package/packages/core/src/shape/transforms/sql/options.ts +6 -0
- package/packages/core/src/shape/transforms/sql/parser/check-decoder.ts +457 -0
- package/packages/core/src/shape/transforms/sql/parser/create-domain.ts +105 -0
- package/packages/core/src/shape/transforms/sql/parser/create-table.ts +809 -0
- package/packages/core/src/shape/transforms/sql/parser/create-type.ts +91 -0
- package/packages/core/src/shape/transforms/sql/parser/cursor.ts +179 -0
- package/packages/core/src/shape/transforms/sql/parser/default-decoder.ts +129 -0
- package/packages/core/src/shape/transforms/sql/parser/lexer.ts +289 -0
- package/packages/core/src/shape/transforms/sql/parser/pg-types.ts +247 -0
- package/packages/core/src/shape/transforms/sql/parser/sqlite-types.ts +103 -0
- package/packages/core/src/shape/transforms/sql/parser/statements.ts +127 -0
- package/packages/core/src/shape/transforms/sql/parser/type-spec.ts +159 -0
- package/packages/core/src/shape/transforms/sql/transform.sqlite.test.ts +448 -0
- package/packages/core/src/shape/transforms/sql/transform.test.ts +880 -0
- package/packages/core/src/shape/transforms/sql/transform.ts +295 -0
- package/packages/core/src/shape/transforms/typescript/index.ts +1 -0
- package/packages/core/src/shape/transforms/typescript/transform.ts +211 -0
- package/packages/core/src/shape/tuple.test.ts +171 -0
- package/packages/core/src/shape/validate.ts +413 -0
- package/packages/core/tsconfig.cjs.json +11 -0
- package/packages/core/tsconfig.esm.json +10 -0
- package/packages/core/tsconfig.json +23 -0
- package/packages/samples/node_modules/.bin/prettier +21 -0
- package/packages/samples/node_modules/.bin/tsc +21 -0
- package/packages/samples/node_modules/.bin/tsserver +21 -0
- package/packages/samples/node_modules/.bin/tsx +21 -0
- package/packages/samples/node_modules/.bin/vitest +21 -0
- package/packages/samples/package.json +47 -0
- package/packages/samples/src/blog.ts +49 -0
- package/packages/samples/src/config.ts +50 -0
- package/packages/samples/src/ecommerce.ts +65 -0
- package/packages/samples/src/embeddings.ts +43 -0
- package/packages/samples/src/events.ts +52 -0
- package/packages/samples/src/geometry.ts +62 -0
- package/packages/samples/src/index.ts +9 -0
- package/packages/samples/src/relational.ts +17 -0
- package/packages/samples/src/tuples.ts +67 -0
- package/packages/samples/src/user.ts +9 -0
- package/packages/samples/tsconfig.cjs.json +11 -0
- package/packages/samples/tsconfig.esm.json +10 -0
- package/packages/samples/tsconfig.json +23 -0
- package/pnpm-workspace.yaml +3 -0
- package/test-data/json-schema/address.json +35 -0
- package/test-data/json-schema/array-of-things.json +36 -0
- package/test-data/json-schema/basic.json +21 -0
- package/test-data/json-schema/blog-post.json +29 -0
- package/test-data/json-schema/calendar.json +48 -0
- package/test-data/json-schema/complex-object-with-nested-properties.json +41 -0
- package/test-data/json-schema/ecommerce-complex.json +344 -0
- package/test-data/json-schema/ecommerce-system.json +27 -0
- package/test-data/json-schema/enumerated-values.json +11 -0
- package/test-data/json-schema/fstab-entry.json +92 -0
- package/test-data/json-schema/geographical-location.json +20 -0
- package/test-data/json-schema/health-record.json +41 -0
- package/test-data/json-schema/job-posting.json +33 -0
- package/test-data/json-schema/movie.json +35 -0
- package/test-data/json-schema/regular-expression-pattern.json +12 -0
- package/test-data/json-schema/user-profile.json +33 -0
- package/test-data/sql/ecommerce.sql +641 -0
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Repository layout
|
|
6
|
+
|
|
7
|
+
pnpm workspace (`pnpm-workspace.yaml`) with three members:
|
|
8
|
+
|
|
9
|
+
- `packages/core` — `@shapecraft/core`, the shape/type-validation library. This is where ~all real code lives.
|
|
10
|
+
- `packages/samples` — `@shapecraft/samples`, hand-written `B.mapping`/`B.module` examples (`user`, `relational`, `blog`, `ecommerce`, `geometry`, `events`, `config`, `embeddings`) used as fixtures for the transforms.
|
|
11
|
+
- `apps/cli` — `@shapecraft/cli`, a [`citty`](https://github.com/unjs/citty)-based CLI. Currently exposes a single `transform` subcommand: reads a JSON Schema file, runs `fromJSONSchema` → `toSQL` (default) or `toTypescript`, and prints (or writes with `--output`) the result.
|
|
12
|
+
|
|
13
|
+
The root `package.json` has no production deps; it just fans scripts out to the workspace. `pnpm-workspace.yaml` globs both `packages/*` and `apps/*`.
|
|
14
|
+
|
|
15
|
+
## Commands
|
|
16
|
+
|
|
17
|
+
From the repo root:
|
|
18
|
+
|
|
19
|
+
- `pnpm run check` — recursive `tsc --noEmit` across all workspace packages.
|
|
20
|
+
- `pnpm run test` — recursive `vitest --passWithNoTests` across all workspace packages.
|
|
21
|
+
- `pnpm run format` — recursive `prettier --experimental-ternaries ./src --write`.
|
|
22
|
+
- `pnpm run cli` — runs `apps/cli/src/index.ts` via `./apps/cli/node_modules/.bin/tsx` (the path is hard-coded; don't replace with bare `tsx`).
|
|
23
|
+
|
|
24
|
+
Per-package (run inside `packages/core`, `packages/samples`, or `apps/cli`):
|
|
25
|
+
|
|
26
|
+
- `pnpm test` — `vitest --passWithNoTests` (interactive watch). For a single file: `pnpm test path/to/file.test.ts`. For one test: `pnpm test -t "test name"`.
|
|
27
|
+
- `pnpm run check` — type-check only (`tsc -p ./tsconfig.json --noEmit`).
|
|
28
|
+
- `pnpm run format` — prettier (note: the project uses `--experimental-ternaries`).
|
|
29
|
+
- `pnpm run build` — emits dual ESM/CJS (`tsc -p tsconfig.esm.json && tsc -p tsconfig.cjs.json`). The CLI package omits this script.
|
|
30
|
+
|
|
31
|
+
The recursive root scripts use `pnpm run -recursive -filter "./packages/**" -filter "./apps/**" <script>` — keep that filter shape if you add new workspaces.
|
|
32
|
+
|
|
33
|
+
## Build outputs
|
|
34
|
+
|
|
35
|
+
Each package ships **dual ESM/CJS** via two configs:
|
|
36
|
+
|
|
37
|
+
- `tsconfig.esm.json` → `dist/esm` (module: esnext)
|
|
38
|
+
- `tsconfig.cjs.json` → `dist/cjs` (module: commonjs, moduleResolution: node10)
|
|
39
|
+
|
|
40
|
+
Both extend `tsconfig.json` and exclude `*.test.ts`; the CJS config additionally excludes `*.sample.ts`. `package.json` `publishConfig.exports` wires the dual entry points, and `packages/core` and `packages/samples` have a `build` script that runs both `tsc` invocations.
|
|
41
|
+
|
|
42
|
+
The dev `main` field points at `./src/index.ts` so workspace consumers (e.g. `apps/cli` depending on `@shapecraft/core` via `workspace:*`) get TS sources directly. Only `publishConfig` switches to `dist/` — don't add a top-level `main: dist/...` or you'll break in-repo consumers.
|
|
43
|
+
|
|
44
|
+
## TypeScript strictness
|
|
45
|
+
|
|
46
|
+
`packages/core/tsconfig.json` enables: `strict`, `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, `isolatedModules`, `noUncheckedSideEffectImports`, `moduleDetection: force`. New code is expected to type-check under all of these — in particular, `exactOptionalPropertyTypes` means `{ x?: T }` and `{ x?: T | undefined }` are different, and `noUncheckedIndexedAccess` means indexed access returns `T | undefined`.
|
|
47
|
+
|
|
48
|
+
## Core architecture: the shape system
|
|
49
|
+
|
|
50
|
+
Everything in `packages/core/src/` is in service of one idea: a shape value is both a TypeScript type carrier and a runtime descriptor that can validate, parse, and translate data. The shape code lives in `packages/core/src/shape/`:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
shape/
|
|
54
|
+
base.ts phantom-typed shape carrier
|
|
55
|
+
annotation.ts Annotation type (optional/min/max/unique/uniqueItems/primary/
|
|
56
|
+
autoIncrement/pattern/format/foreign/default/title/description/
|
|
57
|
+
comment/uuidVersion/meta)
|
|
58
|
+
shape.ts the `shapes` namespace + `annotate` namespace
|
|
59
|
+
— constructors, Shape union, InferShapeOut, validate/is/parse, auto
|
|
60
|
+
builder.ts the `B` namespace — fluent builder wrappers around `shapes`
|
|
61
|
+
error.ts ValidationError type
|
|
62
|
+
number.ts number-tag inference, widening rules, cast-compatibility
|
|
63
|
+
tags.ts NumberTag / IntTag / FloatTag string literal unions
|
|
64
|
+
transforms/
|
|
65
|
+
json-schema/ toJSONSchema / fromJSONSchema (with `x-shapecraft` meta)
|
|
66
|
+
sql/ toSQL — emits PostgreSQL DDL from a mapping (table) or module (schema)
|
|
67
|
+
typescript/ toTypescript — emits TS type declarations from a shape
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Supporting utilities are in `packages/core/src/common/`:
|
|
71
|
+
|
|
72
|
+
- `phantom.ts` (`PhantomType = any`)
|
|
73
|
+
- `result.ts` (`R.Result<T, E>` + `R.ok` / `R.err` / `R.isOk` / `R.isErr` / `R.isResult`)
|
|
74
|
+
- `is.ts` (`isPlainObject`, `isNumeric`, `isSafeNumber`, `isSafeFloat`)
|
|
75
|
+
- `object.ts` (`remapObjectValues`, `remapObjectEntries`)
|
|
76
|
+
- `array.ts` (`range`, `uniqueBy`)
|
|
77
|
+
- `string.ts` (`repeat`, `forceString`)
|
|
78
|
+
- `types.ts` (`Tuple`, `Arrayish`, `Prettify`, `LooseRecord`, `Binary`, `UnionToTuple`)
|
|
79
|
+
|
|
80
|
+
### 1. `base.ts` — phantom-typed shape carrier
|
|
81
|
+
|
|
82
|
+
Every shape is a runtime object of the form:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
{ type: "<kind>", _shape: true, anno: Annotation, input: <ctor arg>, _: { output } }
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The `_` field is a **phantom**: `PhantomType = any` at runtime (see `common/phantom.ts`), but its TS type carries the shape's `output` (the inferred runtime type). Nothing reads `_` at runtime — it exists purely so the type system can recover `Output` from a `Shape` value. `input` *is* read at runtime (it holds the child shape for `array`, the record for `mapping` and `module`, the `[key, value]` tuple for `record`, the `{ dims, format }` for `vector`, the variants for `union`, the literal value for `literal(...)`, etc.).
|
|
89
|
+
|
|
90
|
+
`createBaseWithPhantom` (scalars; `input: null`) and `createBaseWithInput` (containers; carries a concrete `input`) are the two ways shapes get built.
|
|
91
|
+
|
|
92
|
+
### 2. `shape.ts` — the `shapes` namespace
|
|
93
|
+
|
|
94
|
+
Constructors:
|
|
95
|
+
|
|
96
|
+
- Scalars: `string()`, `boolean()`, `notDefined()` (= undefined), `nil()` (= null), `unknown()`, `date()`, `binary()` (`Uint8Array | number[]`).
|
|
97
|
+
- Numbers: `number()` plus tagged variants `int()`, `int8/16/32/64`, `uint8/16/32/64`, `float()`, `float32/64`. Each carries `tag: NumberTag`; `validate` enforces the tag via `numberTagCanBeCastedTo` (see `number.ts` — widening is allowed, narrowing is not, ints and floats don't mix except via the open-ended `number` tag).
|
|
98
|
+
- Literals: `literal(value)` for `string | number | boolean` — produces a shape with `literal: true` and `input` set to the value. The inferred output type is narrowed to the literal.
|
|
99
|
+
- Containers: `array(item)`, `mapping(record)`, `record(keyShape, valueShape)`, `vector(dims, format?)` (defaults to `number()`), `union(...of)` — `union` is overloaded and also accepts a single array for `const` inference: `union([a, b])`.
|
|
100
|
+
- `module(rec)` — top-level container of named `ShapeMapping`s. Conceptually a schema/database of tables; consumed by `toSQL` to emit multi-table DDL with FK-aware topological sort, and by `toTypescript` to emit a `namespace`.
|
|
101
|
+
- `auto(input, options?)` — infers a shape from a runtime value. Walks plain objects/arrays recursively, picks a number tag from the value, and (per options) optionally produces literal shapes for strings/numbers/booleans. Arrays of numbers collapse to `array(number)` with the merged tag.
|
|
102
|
+
|
|
103
|
+
Type utilities:
|
|
104
|
+
|
|
105
|
+
- `Shape` — discriminated union of every shape interface (including `ShapeModule` and `ShapeBinary`).
|
|
106
|
+
- `ShapeKeyable` — `ShapeString | ShapeNumber | ShapeBoolean` (what `record` keys allow).
|
|
107
|
+
- `ShapeWithLength` — `ShapeString | ShapeNumber | ShapeArray` (what `min`/`max` accept).
|
|
108
|
+
- `InferShapeOut<S>` — `S["_"]["output"]`. The central type-to-runtime-type bridge.
|
|
109
|
+
- `Annotated<S, A>`, `MakeLiteral<S>`, `IsOptional<S>` — internal helpers used by the constructors and by `ShapeMapping`'s split-required-vs-optional output type.
|
|
110
|
+
|
|
111
|
+
`ShapeMapping`'s output type splits required vs. optional keys based on `IsOptional<Rec[P]>` (which reads `anno.optional`), so `annotate.optional(...)` on a field at the value level produces an optional property in the inferred type. The split-and-recombine pattern with `Prettify` flattens the intersection for nicer IDE display.
|
|
112
|
+
|
|
113
|
+
Runtime entry points (all in `shapes`):
|
|
114
|
+
|
|
115
|
+
- `validate(shape, input): ValidationError[]` — returns errors with a `path: PropertyKey[]` trail. Empty array means valid. Handles `module` by requiring every named mapping (table) to be present and valid.
|
|
116
|
+
- `is(shape, input): input is InferShapeOut<S>` — type predicate built on `validate`.
|
|
117
|
+
- `parse(shape, input): R.Result<InferShapeOut<S>, ValidationError[]>` — runs `autoCast` *first*, then validates. `autoCast` coerces strings into numbers/booleans/dates/JSON when the target shape calls for it, and recursively casts values inside mappings/records. So `parse(number(), "42")` succeeds with `42`; `validate(number(), "42")` does not.
|
|
118
|
+
|
|
119
|
+
### 3. `annotation.ts` + `annotate` namespace (in `shape.ts`)
|
|
120
|
+
|
|
121
|
+
`Annotation` models:
|
|
122
|
+
|
|
123
|
+
- Constraints used at validation time: `optional`, `min`, `max`, `pattern` (`string | RegExp`).
|
|
124
|
+
- Constraints surfaced only via transforms: `unique`, `uniqueItems` (array-element uniqueness), `primary`, `autoIncrement`, `format`, `foreign: { table, column }`, `default`, `uuidVersion`.
|
|
125
|
+
- Documentation/metadata: `title`, `description`, `comment`, `meta: Record<string, any>`.
|
|
126
|
+
|
|
127
|
+
The `annotate` helpers — `as`, `optional`, `unique`, `uniqueItems`, `primary`, `autoIncremented`, `foreign(table, column)`, `defaulted`, `described`, `titled`, `commented`, `min(n)`, `max(n)`, `pattern(p)`, `format(f)`, `uuid(version?)`, `meta(rec)` — all wrap `annotate.as(shape, anno)` which merges into the existing `shape.anno`. `uuid` is sugar that sets `pattern` to a UUID regex (versioned if `version` is supplied) and records the version in `uuidVersion`. `meta` deep-merges into `anno.meta` rather than replacing it.
|
|
128
|
+
|
|
129
|
+
`min`/`max` are validated against length for `string`/`array`, against value for `number`. `pattern` is validated against the string via `new RegExp(...)`/`.test(...)`. `unique`, `uniqueItems`, `primary`, `autoIncrement`, `foreign`, `default`, `format`, `title`, `description`, `comment`, `meta`, `uuidVersion` are metadata only at the moment — `validate` does not check them, but `toJSONSchema`, `toSQL`, and `toTypescript` consume them (e.g. `primary` → `PRIMARY KEY`, `autoIncrement` → `GENERATED ALWAYS AS IDENTITY`, `uniqueItems` on a non-jsonb array → emits a `shapecraft_array_is_unique` helper function and a `CHECK`, etc.).
|
|
130
|
+
|
|
131
|
+
When extending the annotation model: add to the `Annotation` type, add a helper to `annotate`, wire it through `validate` if it should affect runtime checking, wire it through `toJSONSchema`/`fromJSONSchema` if it should round-trip through JSON Schema, wire it through `toSQL`/`toTypescript` if it should appear in those outputs, and (if it should affect the inferred output type) thread it through `shapes.ShapeMapping` / a new `Is<...>` utility analogous to `IsOptional`.
|
|
132
|
+
|
|
133
|
+
### 4. `builder.ts` — the `B` namespace
|
|
134
|
+
|
|
135
|
+
`B` is a parallel, fluent surface over `shapes` for ergonomic definitions:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
const userShape = B.mapping({
|
|
139
|
+
id: B.uint32().primary().autoIncrement(),
|
|
140
|
+
email: B.string().regex(/.+@.+/).optional(),
|
|
141
|
+
tags: B.array(B.string()).min(1).max(10).uniqueItems(),
|
|
142
|
+
}).shape; // .shape gets you the underlying shapes.Shape
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Each builder wraps a `shapes.Shape` and exposes:
|
|
146
|
+
|
|
147
|
+
- `.shape`, `.type` — accessors.
|
|
148
|
+
- `.is(x)`, `.parse(x)` — runtime entry points.
|
|
149
|
+
- Annotation methods, each returning a *new* builder with the merged annotation: `optional()`, `unique()`, `primary()`, `default(v)`, `title(t)`, `describe(t)`, `comment(t)`, `autoIncrement()`, `foreign(table, column)`, `references(targetBuilder, field)` (type-safe FK: picks a field from another builder's mapping whose column type matches this builder's `type`), `meta(rec)`.
|
|
150
|
+
- Transform methods: `.toJSONSchema()`, `.toSQL()`, `.toTypescript()`.
|
|
151
|
+
|
|
152
|
+
Three specialized builders extend the base:
|
|
153
|
+
|
|
154
|
+
- `ShapeBuilderForString` — adds `min`, `max`, `regex`, `format`, `uuid(version?)`.
|
|
155
|
+
- `ShapeBuilderForNumber` — adds `min`, `max`.
|
|
156
|
+
- `ShapeBuilderForArray` — adds `min`, `max`, `uniqueItems`.
|
|
157
|
+
|
|
158
|
+
`createBuilder(shape)` dispatches on `shape.type` to pick the right specialized builder. `B.module({ name: B.mapping(...) })` wraps `shapes.module` to define a multi-table schema.
|
|
159
|
+
|
|
160
|
+
If you add a new shape kind to `shapes`, also add a `B.<kind>(...)` constructor; if you add a new annotation, add a method on the appropriate builder interface and (if it should be a transform) thread it through the transform methods.
|
|
161
|
+
|
|
162
|
+
### 5. `transforms/json-schema/` — JSON Schema bridge
|
|
163
|
+
|
|
164
|
+
`toJSONSchema(shape)` and `fromJSONSchema(schema)` round-trip shapes through Draft-compatible JSON Schema. Shape-specific information that JSON Schema can't natively express (number tags, vector dims, the `date`/`binary`/`undefined` distinction, top-level optional, `unique`/`primary`/`foreign`) is preserved on an `x-shapecraft` meta object (`ShapecraftMeta` in `transforms/json-schema/types.ts`).
|
|
165
|
+
|
|
166
|
+
Notable behaviors: integer-tag numbers emit `type: "integer"` with the natural `minimum`/`maximum` for the tag plus the user's `anno.min`/`max` intersected in; `record` with a number key shape emits a numeric `propertyNames.pattern`; literal scalars and literal-only unions emit `const`/`enum`; `date` → `string + format: date-time`; `binary` → `string + contentEncoding: base64`.
|
|
167
|
+
|
|
168
|
+
### 6. `transforms/sql/` — PostgreSQL DDL emitter
|
|
169
|
+
|
|
170
|
+
`toSQL(shape): R.Result<string, string[]>` accepts a `ShapeMapping` (single table) or a `ShapeModule` (multi-table schema) and emits PostgreSQL DDL. Top-level mappings require `anno.title` (used as the table name). Integer tags map to `smallint`/`integer`/`bigint`/`numeric(20,0)`; floats to `real`/`double precision`; `date` → `timestamptz`; `binary` → `bytea`; `vector` → `vector(N)` (pgvector); records/mappings/unknown values fall back to `jsonb`. Unions of string literals emit either a named `CREATE TYPE … AS ENUM` (when the union has a `title`) or a `text` column with a `CHECK … IN (…)` constraint. `min`/`max` on integers intersects with the natural tag range to decide whether a `CHECK` is needed beyond the column type's implicit bounds. `uniqueItems: true` on a non-jsonb array column emits a `shapecraft_array_is_unique` SQL function once (in the prelude) and a `CHECK` referencing it. `autoIncrement` becomes `GENERATED ALWAYS AS IDENTITY` (and errors on non-int / `uint64`). For `module`, tables are topologically sorted by `foreign` references; FK cycles return an error.
|
|
171
|
+
|
|
172
|
+
### 7. `transforms/typescript/` — TS type emitter
|
|
173
|
+
|
|
174
|
+
`toTypescript(shape): string` produces TS type declarations. Top-level `module` emits `export namespace <Title> { … }` when titled; top-level titled `mapping` emits `export type <Title> = { … }`; bare shapes emit an inline type. Annotation hints surface as comments: `description`, `comment`, `primary`, `pattern`, `format`, `min`/`max`, `foreign`, `unique`/`uniqueItems`, `default`. Unions of differently-formatted strings collapse to `string` at the type level, but their `format` annotations are lifted into a single hint comment so the information isn't lost.
|
|
175
|
+
|
|
176
|
+
### Usage shape
|
|
177
|
+
|
|
178
|
+
Using the `shapes` namespace directly:
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
const myShape = shapes.mapping({
|
|
182
|
+
foo: annotate.optional(shapes.union(shapes.string(), shapes.number())),
|
|
183
|
+
bar: shapes.record(shapes.string(), shapes.number()),
|
|
184
|
+
baz: shapes.unknown(),
|
|
185
|
+
});
|
|
186
|
+
type T = shapes.InferShapeOut<typeof myShape>;
|
|
187
|
+
// { foo?: string | number; bar: Record<string, number>; baz: unknown }
|
|
188
|
+
|
|
189
|
+
const result = shapes.parse(myShape, someInput); // R.Result<T, ValidationError[]>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Equivalent via `B`:
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
const myShape = B.mapping({
|
|
196
|
+
foo: B.union(B.string(), B.number()).optional(),
|
|
197
|
+
bar: B.record(B.string(), B.number()),
|
|
198
|
+
baz: B.unknown(),
|
|
199
|
+
});
|
|
200
|
+
type T = shapes.InferShapeOut<typeof myShape.shape>;
|
|
201
|
+
const result = myShape.parse(someInput);
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Multi-table schema via `B.module` (see `packages/samples/src/blog.ts` and `relational.ts` for full examples):
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
const User = B.mapping({
|
|
208
|
+
id: B.uint64().primary().autoIncrement(),
|
|
209
|
+
email: B.string(),
|
|
210
|
+
}).title("User");
|
|
211
|
+
|
|
212
|
+
const Post = B.mapping({
|
|
213
|
+
id: B.uint64().primary().autoIncrement(),
|
|
214
|
+
author: B.uint64().references(User, "id"),
|
|
215
|
+
title: B.string().min(1).max(200),
|
|
216
|
+
}).title("Post");
|
|
217
|
+
|
|
218
|
+
const schema = B.module({ User, Post });
|
|
219
|
+
const sql = schema.toSQL(); // R.Result<string, string[]>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Style notes pulled from the existing code
|
|
223
|
+
|
|
224
|
+
- The `package.json` scripts in `packages/core` and `packages/samples` are written with `"test": "vitest --passWithNoTests","check":` on one line — valid JSON, just unusual formatting. If you reformat package.json, preserve the script values.
|
|
225
|
+
- Prettier is invoked with `--experimental-ternaries`; formatted ternary blocks (see `IsOptional` in `shape.ts`, or the dispatch in `transforms/json-schema/transform.ts`) will look unusual. Don't "fix" them.
|
|
226
|
+
- `.~undo-tree~` files are local editor state (Emacs undo-tree). They're gitignored — ignore them when searching.
|
|
227
|
+
- `test-data/json-schema/` holds reference JSON Schemas used as fixtures by the JSON-Schema transform tests and as inputs for `pnpm run cli transform`.
|
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# shapecraft
|
|
2
|
+
- type validations
|
|
3
|
+
- schema definitions
|
|
4
|
+
- ... WIP
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## Example
|
|
8
|
+
```typescript
|
|
9
|
+
|
|
10
|
+
const myShape = shapes.mapping({
|
|
11
|
+
foo: annotate.optional(shapes.union(shapes.string(), shapes.number())),
|
|
12
|
+
bar: shapes.record(shapes.string(), shapes.number()),
|
|
13
|
+
baz: shapes.unknown()
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Project Structure
|
|
19
|
+
- `./packages` - shared packages
|
|
20
|
+
- `./apps` - runnable programs
|
|
21
|
+
- `./packages/core` - the core shape library
|
|
22
|
+
- `./apps/cli` - command-line interface (WIP)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/prettier@3.8.3/node_modules/prettier/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/prettier@3.8.3/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/prettier@3.8.3/node_modules/prettier/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/prettier@3.8.3/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../prettier/bin/prettier.cjs" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../prettier/bin/prettier.cjs" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../typescript/bin/tsc" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../typescript/bin/tsserver" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/tsx@4.22.0/node_modules/tsx/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/tsx@4.22.0/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/tsx@4.22.0/node_modules/tsx/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/tsx@4.22.0/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../tsx/dist/cli.mjs" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../tsx/dist/cli.mjs" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/vitest@4.1.6_@types+node@25.8.0_vite@8.0.13_@types+node@25.8.0_esbuild@0.28.0_tsx@4.22.0_/node_modules/vitest/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/vitest@4.1.6_@types+node@25.8.0_vite@8.0.13_@types+node@25.8.0_esbuild@0.28.0_tsx@4.22.0_/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/vitest@4.1.6_@types+node@25.8.0_vite@8.0.13_@types+node@25.8.0_esbuild@0.28.0_tsx@4.22.0_/node_modules/vitest/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/vitest@4.1.6_@types+node@25.8.0_vite@8.0.13_@types+node@25.8.0_esbuild@0.28.0_tsx@4.22.0_/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../vitest/vitest.mjs" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../vitest/vitest.mjs" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shapecraft/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "./src/index.ts",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "vitest --passWithNoTests",
|
|
8
|
+
"check": "tsc -p ./tsconfig.json --noEmit",
|
|
9
|
+
"format": "prettier --experimental-ternaries ./src --write"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [],
|
|
12
|
+
"author": "",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"packageManager": "pnpm@10.33.2",
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@shapecraft/core": "workspace:*",
|
|
17
|
+
"citty": "^0.2.2"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^25.8.0",
|
|
21
|
+
"prettier": "^3.8.3",
|
|
22
|
+
"tsx": "^4.22.0",
|
|
23
|
+
"typescript": "^6.0.3",
|
|
24
|
+
"vitest": "^4.1.6"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"main": "./dist/cjs/index.js",
|
|
28
|
+
"types": "./dist/cjs/index.d.ts",
|
|
29
|
+
"typings": "./dist/cjs/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"import": {
|
|
33
|
+
"types": "./dist/esm/index.d.ts",
|
|
34
|
+
"default": "./dist/esm/index.js"
|
|
35
|
+
},
|
|
36
|
+
"require": {
|
|
37
|
+
"types": "./dist/cjs/index.d.ts",
|
|
38
|
+
"default": "./dist/cjs/index.js"
|
|
39
|
+
},
|
|
40
|
+
"default": {
|
|
41
|
+
"types": "./dist/cjs/index.d.ts",
|
|
42
|
+
"default": "./dist/cjs/index.js"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fromJSONSchema,
|
|
3
|
+
fromSQL,
|
|
4
|
+
shapes,
|
|
5
|
+
SQLDialect,
|
|
6
|
+
toSQL,
|
|
7
|
+
toTypescript,
|
|
8
|
+
} from "@shapecraft/core";
|
|
9
|
+
import { defineCommand, runMain } from "citty";
|
|
10
|
+
import fs from "fs";
|
|
11
|
+
|
|
12
|
+
const cmdTransform = defineCommand({
|
|
13
|
+
args: {
|
|
14
|
+
input: {
|
|
15
|
+
type: "positional",
|
|
16
|
+
required: true,
|
|
17
|
+
},
|
|
18
|
+
output: {
|
|
19
|
+
type: "string",
|
|
20
|
+
required: false,
|
|
21
|
+
},
|
|
22
|
+
format: {
|
|
23
|
+
type: "enum",
|
|
24
|
+
options: ["sql", "typescript"],
|
|
25
|
+
default: "sql",
|
|
26
|
+
required: false,
|
|
27
|
+
},
|
|
28
|
+
dialect: {
|
|
29
|
+
type: "enum",
|
|
30
|
+
options: ["postgres", "sqlite"],
|
|
31
|
+
default: "postgres",
|
|
32
|
+
required: false,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
run: (ctx) => {
|
|
36
|
+
const contents = fs.readFileSync(ctx.args.input, "utf-8");
|
|
37
|
+
const dialect = ctx.args.dialect as SQLDialect;
|
|
38
|
+
|
|
39
|
+
let shape: shapes.Shape | null = null;
|
|
40
|
+
let errors: string[] | null = null;
|
|
41
|
+
let output: string = "";
|
|
42
|
+
|
|
43
|
+
if (ctx.args.input.toLowerCase().endsWith(".sql")) {
|
|
44
|
+
const parsed = fromSQL(contents, { dialect });
|
|
45
|
+
if (parsed.ok) {
|
|
46
|
+
shape = parsed.value;
|
|
47
|
+
} else {
|
|
48
|
+
errors = parsed.error;
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
shape = fromJSONSchema(JSON.parse(contents));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (shape) {
|
|
55
|
+
switch (ctx.args.format) {
|
|
56
|
+
case "typescript":
|
|
57
|
+
{
|
|
58
|
+
output = toTypescript(shape);
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
default:
|
|
62
|
+
case "sql":
|
|
63
|
+
{
|
|
64
|
+
const sql = toSQL(shape, { dialect });
|
|
65
|
+
if (sql.ok) {
|
|
66
|
+
output = sql.value;
|
|
67
|
+
} else {
|
|
68
|
+
errors = sql.error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!errors) {
|
|
76
|
+
if (ctx.args.output) {
|
|
77
|
+
fs.writeFileSync(ctx.args.output, output, "utf-8");
|
|
78
|
+
console.log(`Wrote to: ${ctx.args.output}`);
|
|
79
|
+
} else {
|
|
80
|
+
console.log(output);
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
console.error(`Error!`);
|
|
84
|
+
console.error(`total errors: ${errors.length}`);
|
|
85
|
+
for (const err of errors) {
|
|
86
|
+
console.error(`- ${err}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
runMain(
|
|
93
|
+
defineCommand({
|
|
94
|
+
subCommands: {
|
|
95
|
+
transform: cmdTransform,
|
|
96
|
+
},
|
|
97
|
+
}),
|
|
98
|
+
);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"outDir": "./dist/esm",
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"target": "esnext",
|
|
6
|
+
"lib": ["esnext"],
|
|
7
|
+
"types": ["node"],
|
|
8
|
+
"sourceMap": true,
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"declarationMap": true,
|
|
11
|
+
"noUncheckedIndexedAccess": true,
|
|
12
|
+
"exactOptionalPropertyTypes": true,
|
|
13
|
+
"strict": true,
|
|
14
|
+
"isolatedModules": true,
|
|
15
|
+
"esModuleInterop": true,
|
|
16
|
+
"noUncheckedSideEffectImports": true,
|
|
17
|
+
"moduleDetection": "force",
|
|
18
|
+
"skipLibCheck": true
|
|
19
|
+
},
|
|
20
|
+
"include": ["./src/**/*.ts"],
|
|
21
|
+
"exclude": ["dist", "node_modules"]
|
|
22
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "shapecraft",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"keywords": [],
|
|
7
|
+
"author": "",
|
|
8
|
+
"license": "ISC",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"cli": "./apps/cli/node_modules/.bin/tsx ./apps/cli/src/index.ts",
|
|
11
|
+
"check": "pnpm run -recursive -filter \"./packages/**\" -filter \"./apps/**\" check",
|
|
12
|
+
"test": "pnpm run -recursive -filter \"./packages/**\" -filter \"./apps/**\" test",
|
|
13
|
+
"format": "pnpm run -recursive -filter \"./packages/**\" -filter \"./apps/**\" format",
|
|
14
|
+
"build": "pnpm run -recursive -filter \"./packages/**\" build"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/prettier@3.8.3/node_modules/prettier/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/prettier@3.8.3/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/prettier@3.8.3/node_modules/prettier/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/prettier@3.8.3/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../prettier/bin/prettier.cjs" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../prettier/bin/prettier.cjs" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../typescript/bin/tsc" "$@"
|
|
21
|
+
fi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
|
3
|
+
|
|
4
|
+
case `uname` in
|
|
5
|
+
*CYGWIN*|*MINGW*|*MSYS*)
|
|
6
|
+
if command -v cygpath > /dev/null 2>&1; then
|
|
7
|
+
basedir=`cygpath -w "$basedir"`
|
|
8
|
+
fi
|
|
9
|
+
;;
|
|
10
|
+
esac
|
|
11
|
+
|
|
12
|
+
if [ -z "$NODE_PATH" ]; then
|
|
13
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules"
|
|
14
|
+
else
|
|
15
|
+
export NODE_PATH="/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/typescript@6.0.3/node_modules:/home/ianertson/workspace/shapecraft/node_modules/.pnpm/node_modules:$NODE_PATH"
|
|
16
|
+
fi
|
|
17
|
+
if [ -x "$basedir/node" ]; then
|
|
18
|
+
exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
|
|
19
|
+
else
|
|
20
|
+
exec node "$basedir/../typescript/bin/tsserver" "$@"
|
|
21
|
+
fi
|