Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ jobs:
cache-dependency-path: "typescript/package-lock.json"
- run: npm ci
- run: npm run build-all
- run: npm test
34 changes: 32 additions & 2 deletions typescript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,30 @@ Install TypeChat:
npm install typechat
```

TypeChat supports both native ECMAScript modules (ESM) and CommonJS. Use `import`
in an ESM application:

```js
import { createJsonTranslator } from "typechat";
import { createTypeScriptJsonValidator } from "typechat/ts";
```

Or use `require` in a CommonJS application:

```js
const { createJsonTranslator } = require("typechat");
const { createTypeScriptJsonValidator } = require("typechat/ts");
```

The `typechat`, `typechat/ts`, `typechat/zod`, and `typechat/interactive` entry points
select the matching JavaScript build and TypeScript declarations automatically.
Both builds target ES2021 and require Node.js 22.19.0 or newer.

For compatibility with earlier CommonJS-only releases, native ESM default imports
(`import typechat from "typechat"`) and dynamic imports' `.default` properties remain
supported for all four entry points. Default imports also preserve the exported
TypeScript types, such as `typechat.Result<T>`.

You can also build TypeChat from source:

```sh
Expand All @@ -33,8 +57,14 @@ npm install
npm run build
```

Run the test suite with `npm test`. The Zod schema tests also compile their generated
TypeScript schema text to check for syntax errors and unresolved type references.
The build emits CommonJS JavaScript and declarations in `dist`, and native ESM
JavaScript and declarations in `dist/esm`.

Run the test suite with `npm test`. Package tests verify named and default imports,
both module formats, and their declaration resolution using only the files included
in the npm package.
The Zod schema tests also compile their generated TypeScript schema text to check
for syntax errors and unresolved type references.

To see TypeChat in action, we recommend exploring the [TypeChat example projects](https://github.com/microsoft/TypeChat/tree/main/typescript/examples). You can try them on your local machine or in a GitHub Codespace.

Expand Down
58 changes: 51 additions & 7 deletions typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,66 @@
"url": "https://github.com/microsoft/TypeChat/issues"
},
"scripts": {
"build": "tsc -p src",
"test": "npm run build && tsc -p test && node --test out/validate.test.js out/zod.test.js out/program.test.js tests/model.test.mjs tests/examples.test.mjs",
"build-all": "npm run build --workspaces",
"build": "npm run build:cjs && npm run build:esm",
"build:cjs": "tsc -p src",
"build:esm": "tsc -p src/tsconfig.esm.json && node -e \"require('fs').writeFileSync('dist/esm/package.json', JSON.stringify({ type: 'module' }))\"",
"test": "npm run build && tsc -p test && node --test out/validate.test.js out/zod.test.js out/program.test.js tests/model.test.mjs tests/examples.test.mjs tests/package.test.mjs",
"build-all": "npm run build && npm run build --workspaces",
"prepare": "npm run build-all",
"prepublishOnly": "node -e \"require('fs').copyFileSync('../SECURITY.md','SECURITY.md')\"",
"postpublish": "node -e \"require('fs').unlinkSync('SECURITY.md')\"",
"publish-package": "npm publish",
"publish-package:dry-run": "npm publish --dry-run"
},
"type": "commonjs",
"main": "./dist/index.js",
"module": "./dist/esm/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": "./dist/index.js",
"./ts": "./dist/ts/index.js",
"./zod": "./dist/zod/index.js",
"./interactive": "./dist/interactive/index.js"
".": {
"import": {
"types": "./dist/esm/index.d.mts",
"default": "./dist/esm/index.mjs"
},
"require": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"default": "./dist/index.js"
},
"./ts": {
"import": {
"types": "./dist/esm/ts/index.d.mts",
"default": "./dist/esm/ts/index.mjs"
},
"require": {
"types": "./dist/ts/index.d.ts",
"default": "./dist/ts/index.js"
},
"default": "./dist/ts/index.js"
},
"./zod": {
"import": {
"types": "./dist/esm/zod/index.d.mts",
"default": "./dist/esm/zod/index.mjs"
},
"require": {
"types": "./dist/zod/index.d.ts",
"default": "./dist/zod/index.js"
},
"default": "./dist/zod/index.js"
},
"./interactive": {
"import": {
"types": "./dist/esm/interactive/index.d.mts",
"default": "./dist/esm/interactive/index.mjs"
},
"require": {
"types": "./dist/interactive/index.d.ts",
"default": "./dist/interactive/index.js"
},
"default": "./dist/interactive/index.js"
}
},
"engines": {
"node": ">=22.19.0"
Expand Down
2 changes: 2 additions & 0 deletions typescript/src/index.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './index.js';
export * as default from './index.js';
6 changes: 3 additions & 3 deletions typescript/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './result';
export * from './model';
export * from './typechat';
export * from './result.js';
export * from './model.js';
export * from './typechat.js';
2 changes: 2 additions & 0 deletions typescript/src/interactive/index.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './index.js';
export * as default from './index.js';
2 changes: 1 addition & 1 deletion typescript/src/interactive/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './interactive';
export * from './interactive.js';
2 changes: 1 addition & 1 deletion typescript/src/model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Result, success, error } from "./result";
import { Result, success, error } from "./result.js";

/**
* Represents a section of an LLM prompt with an associated role. TypeChat uses the "user" role for
Expand Down
2 changes: 2 additions & 0 deletions typescript/src/ts/index.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './index.js';
export * as default from './index.js';
4 changes: 2 additions & 2 deletions typescript/src/ts/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './validate';
export * from './program';
export * from './validate.js';
export * from './program.js';
8 changes: 4 additions & 4 deletions typescript/src/ts/program.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Result, error, success } from "../result";
import { TypeChatLanguageModel } from "../model";
import { createTypeScriptJsonValidator } from "./validate";
import { TypeChatJsonTranslator, createJsonTranslator } from "../typechat";
import { Result, error, success } from "../result.js";
import { TypeChatLanguageModel } from "../model.js";
import { createTypeScriptJsonValidator } from "./validate.js";
import { TypeChatJsonTranslator, createJsonTranslator } from "../typechat.js";

const programSchemaText = `// A program consists of a sequence of function calls that are evaluated in order.
export type Program = {
Expand Down
25 changes: 6 additions & 19 deletions typescript/src/ts/validate.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,10 @@
import { createRequire } from 'node:module';
import { Result, success, error } from '../result';
import { TypeChatJsonValidator } from "../typechat";

// TypeScript 7 ships as an ES module, while this package is emitted as CommonJS. Node's
// `require(esm)` support (Node >=22.12) lets us load it synchronously, and `resolution-mode`
// makes the TypeScript compiler resolve the ESM-only types from a CommonJS file.
// TODO: Revisit these `typescript/unstable/*` imports once a stable API is available.
type SyncModule = typeof import('typescript/unstable/sync', { with: { 'resolution-mode': 'import' } });
type FileSystemModule = typeof import('typescript/unstable/fs', { with: { 'resolution-mode': 'import' } });
type AstIsModule = typeof import('typescript/unstable/ast/is', { with: { 'resolution-mode': 'import' } });

type Checker = InstanceType<SyncModule['Checker']>;
type Diagnostic = import('typescript/unstable/sync', { with: { 'resolution-mode': 'import' } }).Diagnostic;
type SourceFile = import('typescript/unstable/ast', { with: { 'resolution-mode': 'import' } }).SourceFile;

const requireEsm = createRequire(__filename);
const { API, NodeBuilderFlags, SymbolFlags }: SyncModule = requireEsm('typescript/unstable/sync');
const { createVirtualFileSystem }: FileSystemModule = requireEsm('typescript/unstable/fs');
const { isTypeReferenceNode, isVariableStatement }: AstIsModule = requireEsm('typescript/unstable/ast/is');
import { API, NodeBuilderFlags, SymbolFlags, type Checker, type Diagnostic } from 'typescript/unstable/sync';
import { createVirtualFileSystem } from 'typescript/unstable/fs';
import type { SourceFile } from 'typescript/unstable/ast';
import { isTypeReferenceNode, isVariableStatement } from 'typescript/unstable/ast/is';
import { Result, success, error } from '../result.js';
import { TypeChatJsonValidator } from "../typechat.js";

const libText = `interface Array<T> { length: number, [n: number]: T }
interface Object { toString(): string }
Expand Down
9 changes: 9 additions & 0 deletions typescript/src/tsconfig.esm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "es2022",
"moduleResolution": "bundler",
"outDir": "../dist/esm"
},
"include": ["./**/*.ts", "./**/*.mts"]
}
5 changes: 3 additions & 2 deletions typescript/src/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
"compilerOptions": {
"target": "es2021",
"lib": ["es2021"],
"module": "node16",
"module": "node20",
"types": ["node"],
"esModuleInterop": true,
"outDir": "../dist",
"skipLibCheck": true,
"strict": true,
"exactOptionalPropertyTypes": true,
"declaration": true
}
},
"include": ["./**/*.ts"]
}
4 changes: 2 additions & 2 deletions typescript/src/typechat.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Result, success, error } from "./result";
import { TypeChatLanguageModel, PromptSection, PromptContent } from "./model";
import { Result, success, error } from "./result.js";
import { TypeChatLanguageModel, PromptSection, PromptContent } from "./model.js";

/**
* Represents an object that can translate natural language requests in JSON objects of the given type.
Expand Down
2 changes: 2 additions & 0 deletions typescript/src/zod/index.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './index.js';
export * as default from './index.js';
2 changes: 1 addition & 1 deletion typescript/src/zod/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './validate';
export * from './validate.js';
4 changes: 2 additions & 2 deletions typescript/src/zod/validate.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { z } from "zod";
import { success, error } from '../result';
import { TypeChatJsonValidator } from '../typechat';
import { success, error } from '../result.js';
import { TypeChatJsonValidator } from '../typechat.js';

/**
* Returns a JSON validator for a given Zod schema. The schema is supplied as an object where each property provides
Expand Down
Loading
Loading