Skip to content

Commit

Permalink
More updates.
Browse files Browse the repository at this point in the history
  • Loading branch information
tjprescott committed Dec 5, 2023
1 parent 631285f commit 4002698
Showing 1 changed file with 80 additions and 59 deletions.
139 changes: 80 additions & 59 deletions docs/extending-typespec/basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ The following is a high level overview of the contents of a TypeSpec package. Th
- **src/lib.ts** - the TypeSpec library definition file
- **package.json** - metadata about your TypeSpec package

## Initial setup
## 1 - Initial setup

### 1. Initialize your package directory & package.json
### a. Initialize your package directory & package.json

Run the following commands:

Expand All @@ -37,25 +37,25 @@ Run the following commands:

After filling out the wizard, you will have a package.json file that defines your typespec library.

Unlike node libraries which support CommonJS (cjs), TypeSpec libraries must be Ecmascript Modules. So open your `package.json` and add the following top-level configuration key:
Unlike node libraries which support CommonJS (cjs), TypeSpec libraries must be Ecmascript Modules. Open your `package.json` and add the following top-level configuration key:

```jsonc
"type": "module"
```

### 2. Install TypeSpec dependencies
### b. Install TypeSpec dependencies

Run the following command:

```bash
npm install --save-peer @typespec/compiler
```

You may have need of other dependencies in the TypeSpec standard library depending on what you are doing. E.g. if you want to use the metadata found in `@typespec/openapi` you will need to install that as well.
You may have need of other dependencies in the TypeSpec standard library depending on what you are doing (e.g. if you want to use the metadata found in `@typespec/openapi` you will need to install that as well).

See [dependency section](#defining-dependencies) for information on how to define your dependencies.

### 2. Define your main files
### c. Define your main files

Your package.json needs to refer to two main files: your node module main file, and your TypeSpec main. The node module main file is the `"main"` key in your package.json file, and defines the entrypoint for your library when consumed as a node library, and must reference a js file. The TypeSpec main defines the entrypoint for your library when consumed from a TypeSpec program, and may reference either a js file (when your library doesn't contain any typespec types) or a TypeSpec file.

Expand All @@ -64,7 +64,7 @@ Your package.json needs to refer to two main files: your node module main file,
"tspMain": "lib/main.tsp"
```

### 3. Install and initialize TypeScript
### d. Install and initialize TypeScript

Run the following commands:

Expand All @@ -83,7 +83,7 @@ This will create `tsconfig.json`. But we need to make a couple changes to this.
"outDir": "./dist",
```

### 4. Create `lib.ts`
### e. Create `lib.ts`

Open `./src/lib.ts` and create your library definition that registers your library with the TypeSpec compiler and defines any diagnostics your library will emit. Make sure to export the library definition as `$lib`.

Expand All @@ -107,7 +107,7 @@ export const { reportDiagnostic, createDiagnostic, createStateSymbol } = $lib;

Diagnostics are used for linters and decorators which are covered in subsequent topics.

### 5. Create `index.ts`
### f. Create `index.ts`

Open `./src/index.ts` and import your library definition:

Expand All @@ -116,19 +116,32 @@ Open `./src/index.ts` and import your library definition:
export { $lib } from "./lib.js";
```

### 6. Build TypeScript
### g. Build TypeScript

TypeSpec can only import JavaScript files, so any time changes are made to TypeScript sources, they need to be compiled before they are visible to TypeSpec. To do so, run `npx tsc -p .` in your library's root directory. You can also run `npx tsc -p . --watch` if you would like to re-run the TypeScript compiler whenever files are changed.

### 7. Add your main TypeSpec file
Alternatively, you can add these as scripts in your `package.json` to make them easier to invoke. Consider adding the following:

```jsonc
"scripts": {
"clean": "rimraf ./dist ./temp",
"build": "tsc -p .",
"watch": "tsc -p . --watch",
"test": "mocha"
}
```

You can then run `npm run build` or `npm run watch` to build or watch your library.

### h. Add your main TypeSpec file

Open `./lib/main.tsp` and import your JS entrypoint. This ensures that when typespec imports your library, the code to define the library is run. In later topics when we add decorators, this import will ensure those get exposed as well.

```typespec
import "../dist/index.js";
```

## Adding TypeSpec types to your library
## 2. Adding TypeSpec types to your library

Open `./lib/main.tsp` and add any types you want to be available when users import this library. It is also strongly recommended you put these types in a namespace that corresponds with the library name. For example, your `./lib/main.tsp` file might look like:

Expand All @@ -142,7 +155,7 @@ model Person {
}
```

## Defining Dependencies
## 3. Defining Dependencies

Defining dependencies in a TypeSpec library should be following these rules:

Expand Down Expand Up @@ -174,57 +187,24 @@ TypeSpec libraries are defined using `peerDependencies` so we don't end-up with
}
```

## Publishing your TypeSpec library

To publish to the public npm registry, follow [their documentation](https://docs.npmjs.com/creating-and-publishing-unscoped-public-packages).

## Importing your TypeSpec library

Once your TypeSpec library is published, your users can install and use it just like any of the TypeSpec standard libraries. First, they have to install it:

```bash
npm install $packageName
```

Next, they import it into their TypeSpec program and use the namespace (if desired):

```typespec
import "MyLibrary";
using MyLibrary;
model Employee extends Person {
job: string;
}
```

## Next steps

TypeSpec libraries can contain more than just types. Read the subsequent topics for more details on how to write [decorators](./create-decorators.md), [emitters](./emitters-basics.md) and [linters](./linters.md).

## Testing
## 4. Testing your TypeSpec library

TypeSpec provides a testing framework to help testing libraries. Examples here are shown using `mocha` but any other JS test framework can be used.

### Add devDependencies
### a. Add devDependencies

Verify that you have the following in your `package.json`:

```
...,
"devDependencies": {
"@types/node": "~18.11.9",
...,
// if you want to include the mocha test framework
"@types/mocha": "~10.0.1",
"mocha": "~10.2.0",
"mocha-junit-reporter": "~2.2.1",
"mocha-multi-reporters": "~1.5.1",
...
}
...
"devDependencies": {
"@types/node": "~18.11.9",
"@types/mocha": "~10.0.1",
"mocha": "~10.2.0",
"source-map-support": "^0.5.21"
}
```

### Define the testing library
### b. Define the testing library

The first step is to define how your library can be loaded from the test framework. This will let your library to be reused by other library test.

Expand Down Expand Up @@ -261,7 +241,7 @@ export const MyTestLibrary = createTestLibrary({
}
```

### Define the test host and test runner for your library
### c. Define the test host and test runner for your library

Define some of the test framework base pieces that will be used in the tests. There are 2 functions:

Expand All @@ -286,9 +266,9 @@ export async function createMyTestRunner() {
}
```

### Write tests
### d. Write tests

After setting up that infrastructure you can start writing tests.
After setting up that infrastructure you can start writing tests. For tests to be recognized by mocha the file names must follow the following format: `<name>.test.ts`

```ts
import { createMyTestRunner } from "./test-host.js";
Expand Down Expand Up @@ -318,7 +298,7 @@ describe("my library", () => {
});
```

#### `@test` decorator
#### e. `@test` decorator

The `@test` decorator is a decorator loaded in the test environment. It can be used to collect any decorable type.
When using the `compile` method it will return a `Record<string, Type>` which is a map of all the types annoted with the `@test` decorator.
Expand All @@ -335,3 +315,44 @@ const { Foo, CustomName } = await runner.compile(`
Foo; // type of: model Foo {}
CustomName; // type of : Bar.name
```

#### f. Install the mocha test explorer for VSCode (optional)

If you are using VSCode, you can install the [mocha test explorer](https://marketplace.visualstudio.com/items?itemName=hbenl.vscode-mocha-test-adapter) to run your tests from the editor. This will also allow you easily debug into your tests.

After installing the extension, you need to add a `.mocharc.yaml` file at the root of your project.

```yaml
timeout: 5000
require: source-map-support/register
spec: "dist/test/**/*.test.js"
```
You should now be able to discover, run and debug into your tests from the test explorer.
## 5. Publishing your TypeSpec library
To publish to the public npm registry, follow [their documentation](https://docs.npmjs.com/creating-and-publishing-unscoped-public-packages).
## 6. Importing your TypeSpec library
Once your TypeSpec library is published, your users can install and use it just like any of the TypeSpec standard libraries. First, they have to install it:
```bash
npm install $packageName
```

Next, they import it into their TypeSpec program and use the namespace (if desired):

```typespec
import "MyLibrary";
using MyLibrary;
model Employee extends Person {
job: string;
}
```

## 7. Next steps

TypeSpec libraries can contain more than just types. Read the subsequent topics for more details on how to write [decorators](./create-decorators.md), [emitters](./emitters-basics.md) and [linters](./linters.md).

0 comments on commit 4002698

Please sign in to comment.