From 8a1111dc1975af4e223847548bad7e2242697fad Mon Sep 17 00:00:00 2001 From: Jason Gwartz Date: Sun, 17 Mar 2024 09:57:15 +0000 Subject: [PATCH 1/2] Add README, and basic example --- README.md | 100 ++++ examples/basic-intro/config.pkl | 3 + examples/basic-intro/generated/config.pkl.ts | 26 + examples/basic-intro/index.ts | 10 + examples/basic-intro/package-lock.json | 490 +++++++++++++++++++ examples/basic-intro/package.json | 14 + 6 files changed, 643 insertions(+) create mode 100644 README.md create mode 100644 examples/basic-intro/config.pkl create mode 100644 examples/basic-intro/generated/config.pkl.ts create mode 100644 examples/basic-intro/index.ts create mode 100644 examples/basic-intro/package-lock.json create mode 100644 examples/basic-intro/package.json diff --git a/README.md b/README.md new file mode 100644 index 0000000..76ad932 --- /dev/null +++ b/README.md @@ -0,0 +1,100 @@ +> [!CAUTION] +> +> # THIS LIBRARY IS CURRENTLY PRE-RELEASE +> +> `pkl-typescript` is currently major version `v0`, and **breaking changes will happen** between versions. +> +> Please read the section [Roadmap](#roadmap) below to learn more. + +# Pkl Bindings for TypeScript + +This library exposes TypeScript language bindings for the Pkl configuration language. + +These language bindings are made up of: + +- an "evaluator", that can execute Pkl code and deserialise the result into JavaScript runtime objects +- the `pkl-gen-typescript` CLI, that can analyse a Pkl schema and generate matching TypeScript definitions + +Together, this allows you to embed Pkl into your TypeScript application, complete with code generation for full type safety and ease of use. + +## Getting Started + +First, install `pkl-typescript` from NPM: + +```bash +npm install @pkl-community/pkl-typescript +``` + +Then, generate a TypeScript file from your Pkl schema (eg. for a file called "config.pkl"): + +```bash +npx pkl-gen-typescript config.pkl -o ./generated +``` + +Lastly, in your TypeScript code, you can import the generated types and loader code: + +```typescript +import { type Config, loadFromPath } from "./generated/config.pkl.ts"; + +const config: Config = await loadFromPath("config.pkl"); +``` + +See more example usage in the [examples directory](./examples/). + +### Note on Schemas vs. Configs + +`pkl-gen-typescript` generates a TypeScript file based on Pkl's **type information** only, _not_ Pkl's runtime values. For example, a Pkl file with `x: String = "hello"` would produce the TypeScript type `x: string`. +Conversely, the evaluator (used by the `loadFromPath(string)` function) evaluates a Pkl module that **renders values**. + +You may choose to have your Pkl schemas and values defined in separate Pkl files (eg. `schema.pkl` and `config.pkl`, where `config.pkl` starts with `amends "schema.pkl"`). In such a case, you would pass `schema.pkl` to `pkl-gen-typescript`, but then evaluate `config.pkl` at runtime (ie. `await loadFromPath("config.pkl")`). + +## Roadmap + +This library is currently in pre-release: we believe it is usable and productive in its current state, but not feature-complete, and not yet API-stable. + +We will keep the major version at `v0` until we are ready to commit to stability in: + +- the evaluator API (as provided by the `@pkl-community/pkl-typescript` NPM package) +- the TypeScript type definitions generated by `pkl-gen-typescript` + +Until then, minor and patch releases may contain breaking changes. + +> [!WARNING] +> **We strongly recommend** you regenerate your generated TypeScript code (with `pkl-gen-typescript`) **every time you upgrade** `@pkl-community/pkl-typescript`. If you don't, you may end up with unexpected runtime errors from type mismatches. + +## Appendix + +### Type Mappings + +When code-generating TypeScript type definitions from Pkl schemas, each Pkl type is converted to an associated TypeScript type, as per the table below. While in pre-release, these mappings are subject to change! + +| Pkl type | TypeScript type | +| ---------------- | -------------------------- | +| Null | `null` | +| Boolean | `boolean` | +| String | `string` | +| Int | `number` | +| Int8 | `number` | +| Int16 | `number` | +| Int32 | `number` | +| UInt | `number` | +| UInt8 | `number` | +| UInt16 | `number` | +| UInt32 | `number` | +| Float | `number` | +| Number | `number` | +| List | `Array` | +| Listing | `Array` | +| Map | `Map` | +| Mapping | `Map` | +| Set | `Set` | +| Pair | `pklTypescript.Pair` | +| Dynamic | `pklTypescript.Dynamic` | +| DataSize | `pklTypescript.DataSize` | +| Duration | `pklTypescript.Duration` | +| IntSeq | `pklTypescript.IntSeq` | +| Class | `interface` | +| TypeAlias | `typealias` | +| Any | `pklTypescript.Any` | +| Unions (A\|B\|C) | `A\|B\|C` | +| Regex | `pklTypescript.Regex` | diff --git a/examples/basic-intro/config.pkl b/examples/basic-intro/config.pkl new file mode 100644 index 0000000..0862aa0 --- /dev/null +++ b/examples/basic-intro/config.pkl @@ -0,0 +1,3 @@ +firstName: String = "Phillip" +lastName: String = "Pklton" +age: Int8 = 76 diff --git a/examples/basic-intro/generated/config.pkl.ts b/examples/basic-intro/generated/config.pkl.ts new file mode 100644 index 0000000..307439a --- /dev/null +++ b/examples/basic-intro/generated/config.pkl.ts @@ -0,0 +1,26 @@ +// This file was generated by `pkl-typescript` from Pkl module `config`. +// DO NOT EDIT. +import * as pklTypescript from "@pkl-community/pkl-typescript" + +// Ref: Module root. +export interface Config { + firstName: string + + lastName: string + + age: number +} + +// LoadFromPath loads the pkl module at the given path and evaluates it into a Config +export const loadFromPath = async (path: string): Promise => { + const evaluator = await pklTypescript.newEvaluator(pklTypescript.PreconfiguredOptions); + try { + const result = await load(evaluator, pklTypescript.FileSource(path)); + return result + } finally { + evaluator.close() + } +}; + +export const load = (evaluator: pklTypescript.Evaluator, source: pklTypescript.ModuleSource): Promise => + evaluator.evaluateModule(source) as Promise; diff --git a/examples/basic-intro/index.ts b/examples/basic-intro/index.ts new file mode 100644 index 0000000..7f7a838 --- /dev/null +++ b/examples/basic-intro/index.ts @@ -0,0 +1,10 @@ +import { type Config, loadFromPath } from "./generated/config.pkl"; + +const main = async () => { + const config: Config = await loadFromPath("config.pkl"); + console.log( + `Hello, ${config.firstName} ${config.lastName}! I hear you are ${config.age} years old.` + ); +}; + +main(); diff --git a/examples/basic-intro/package-lock.json b/examples/basic-intro/package-lock.json new file mode 100644 index 0000000..0d55c1a --- /dev/null +++ b/examples/basic-intro/package-lock.json @@ -0,0 +1,490 @@ +{ + "name": "basic-intro", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "basic-intro", + "version": "0.0.1", + "dependencies": { + "pkl-typescript": "file:../..", + "tsx": "^4.7.1", + "typescript": "^5.3.3" + } + }, + "../..": { + "name": "@pkl-community/pkl-typescript", + "version": "0.0.2", + "license": "Apache-2.0", + "dependencies": { + "chalk": "^4.1.2", + "cmd-ts": "^0.13.0", + "consola": "^3.2.3", + "msgpackr": "^1.10.1" + }, + "bin": { + "pkl-gen-typescript": "bin/pkl-gen-typescript.ts" + }, + "devDependencies": { + "@jest/globals": "^29.7.0", + "@types/node": "^18.19.18", + "@typescript-eslint/eslint-plugin": "^5.48.0", + "@typescript-eslint/parser": "^5.48.0", + "eslint": "^8.31.0", + "jest": "^29.7.0", + "ts-jest": "^29.1.2", + "tsx": "^4.7.1", + "typescript": "^4.9.4" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", + "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/pkl-typescript": { + "resolved": "../..", + "link": true + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/tsx": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.1.tgz", + "integrity": "sha512-8d6VuibXHtlN5E3zFkgY8u4DX7Y3Z27zvvPKVmLon/D4AjuKzarkUBTLDBgj9iTQ0hg5xM7c/mYiRVM+HETf0g==", + "dependencies": { + "esbuild": "~0.19.10", + "get-tsconfig": "^4.7.2" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/examples/basic-intro/package.json b/examples/basic-intro/package.json new file mode 100644 index 0000000..8326281 --- /dev/null +++ b/examples/basic-intro/package.json @@ -0,0 +1,14 @@ +{ + "name": "basic-intro", + "version": "0.0.1", + "module": "./index.ts", + "dependencies": { + "pkl-typescript": "file:../..", + "tsx": "^4.7.1", + "typescript": "^5.3.3" + }, + "scripts": { + "gen-config": "pkl-gen-typescript ./config.pkl -o ./generated", + "start": "tsx ./index.ts" + } +} From 01b4c818b86f364d82516af1e75a98738a37f848 Mon Sep 17 00:00:00 2001 From: Jason Gwartz Date: Sat, 30 Mar 2024 07:44:59 -0400 Subject: [PATCH 2/2] Add note about current known limitations --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 76ad932..bf9bb80 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,13 @@ Until then, minor and patch releases may contain breaking changes. > [!WARNING] > **We strongly recommend** you regenerate your generated TypeScript code (with `pkl-gen-typescript`) **every time you upgrade** `@pkl-community/pkl-typescript`. If you don't, you may end up with unexpected runtime errors from type mismatches. +### Known Current Limitations + +- **Inlined imports**: Imported Pkl types are inlined into the output TypeScript file. For example, if `foo.pkl` has an import like `import "bar.pkl"`, and you run `pkl-gen-typescript foo.pkl`, the resulting `foo.pkl.ts` file will include all types defined in `foo.pkl` _as well as_ all types defined in `bar.pkl`. This means that the resulting TypeScript generated files (in a multi-file codegen) will match the set of input root files, not the file structure of the source Pkl files. This behaviour may create unintended name conflicts; these can be resolved using the `@typescript.Name { value = "..." }` annotation. It may also cause duplication (eg. if the same shared Pkl library file is imported in two schemas); TypeScript's structural typing (where equivalent type shapes can be used interchangeably) should mean that any duplicate types can be safely used as each other. +- **Regex deserialisation**: Pkl's `Regex` type will be decoded as a `pklTypescript.Regex` object, which contains a `.pattern` property. Pkl uses Java's regular expression syntax, which may not always be perfectly compatible with JavaScript's regular expression syntax. If you want to use your Pkl `Regex` as a JavaScript `RegExp`, and you are confident that the expression will behave the same way in JavaScript as in Pkl, you can instantiate a new `RegExp` using the `pklTypescript.Regex.pattern` property, eg. `const myConfigRegexp = new RegExp(myConfig.someRegex.pattern)`. +- **IntSeq deserialisation**: Pkl's `IntSeq` type is intended to be used internally within a Pkl program to create a range loop. It is unlikely to be useful as a property type in JavaScript, and is therefore decoded into a custom `pklTypescript.IntSeq` type with signature `{ start: number; end: number: step: number }` - it is _not_ decoded into an array containing the ranged values. If you have a use-case to use `IntSeq` as an array of ranged values in a TypeScript program, please file a GitHub Issue. +- **Duration and DataSize APIs**: Pkl has a rich API for many of its custom types, but two of note (that are not common in standard libraries of other languages) are `Duration` and `DataSize`, which include convenience APIs for eg. converting between units or summing values. These types are decoded into `pklTypescript.DataSize`/`pklTypescript.Duration` types (each of which have a `value` and `unit` property), and do not yet have the convenience APIs from Pkl. + ## Appendix ### Type Mappings