Skip to content

Commit

Permalink
Release 1.0.0-beta.1
Browse files Browse the repository at this point in the history
  • Loading branch information
Amine Ben hammou committed Jul 1, 2023
1 parent 2a48182 commit 8235f65
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 26 deletions.
161 changes: 158 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,165 @@
# ts-perf

A library and command line tool to measure the compile time performance of Typescript code.

**Do not use, this is still a work in progress!**
A small library to measure the compile time performance of Typescript code.

[![Version](https://img.shields.io/npm/v/ts-perf?style=flat-square)](https://www.npmjs.com/package/ts-perf)
[![Tests Status](https://img.shields.io/github/actions/workflow/status/webneat/ts-perf/tests.yml?branch=main&style=flat-square)](https://github.com/webneat/ts-perf/actions?query=workflow:"Tests")
[![MIT](https://img.shields.io/npm/l/ts-perf?style=flat-square)](LICENSE)

# Contents



# Installation

Start by installing `ts-perf`

```bash
npm i -D ts-perf
# or
yarn add -D ts-perf
```

# Simple usages

## Measuring a file by path

Measuring how much time it takes Typescript compiler to parse and type-check a file:

```ts
import {measurePath} from 'ts-perf'

const durationInMiliseconds = await measurePath('path/to/file')
```

if there are compilation errors in the file, the `measurePath` function will throw the formatted error message.

For example, given the following `file.ts`

```ts
function add(x: number, y: number) {
return x + y
}
add('foo', 'bar')
```

if we run the following code

```ts
import {measurePath} from 'ts-perf'

(async () => {
try {
await measurePath('src/file.ts')
} catch (error) {
console.log(error);
}
})()
```

it will show the following error

```
file.ts:5:5 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
5 add('foo', 'bar')
~~~~~
```

**Note:** The generated error message is colored and formatted, ready to be passed to `console.log`

## Measuring a code snippet

if you want to measure the compilation performance of some code without creating a file, you can use `measureCode`

```ts
import {measureCode} from 'ts-perf'

const durationInMiliseconds = await measureCode(`
function add(x: number, y: number) {
return x + y
}
add('foo', 'bar')
`)
```

Similar to `measurePath`, `measureCode` will throw formatted compilation error if any.

**Adding syntax highlighting to code snippets**

if you are using VSCode, you can use the extension [es6-string-typescript](https://marketplace.visualstudio.com/items?itemName=HoodieCollin.es6-string-typescript) to add colors to code inside the template string

![Add syntax highlighting to code snippets](images/code-colors.png)

**Using import statements inside the code snippets**

You can use `import` statements inside the code snippets and they will be resolved relative normally (if you use `measureCode` inside the file `src/foo.ts`, `ts-perf` will evaluate the code snippet as if it was inside the file `src/foo__ts-perf.ts`, so all relative imports will work).

```ts
import {measureCode} from 'ts-perf'

(async () => {
try {
await measureCode(/*ts*/`
import {add} from './math'
add('foo', 2)
`)
} catch (error) {
console.log(error);
}
})()
```

## Writing performance tests for Typescript types

The main reason I made this library is to be able to write performance tests for [`just-types`](https://github.com/webNeat/just-types) and other custom utility types.

Writing a performance test can be as simple as doing

```ts
it('takes less than a second to typecheck the code', async () => {
expect(await measureCode(`some code using the custom type ...`)).toBeLessThan(1000)
})
```

# API reference

## measurePath

```ts
import { ProjectOptions } from 'ts-morph'
function measurePath(path: string, options?: ProjectOptions): Promise<number>
```

- `path`: Path to the Typescript file to measure.
- `options`: Optional options that will be passed to the `ts-morph` project instance. You can use it to specify the path to tsconfig file and other config options [check `ts-morph` docs for more details](https://ts-morph.com/setup/).

**Return:** A Promise that resolves to the duration of parsing and typechecking the file in miliseconds, or rejects with the compilation errors if any.

## measureCode

```ts
import { ProjectOptions } from 'ts-morph'
function measureCode(code: string, options?: ProjectOptions): Promise<number>
```

- `code`: The code snippet to measure.
- `options`: Optional options that will be passed to the `ts-morph` project instance. You can use it to specify the path to tsconfig file and other config options [check `ts-morph` docs for more details](https://ts-morph.com/setup/).

**Return:** A Promise that resolves to the duration of parsing and typechecking the code in miliseconds, or rejects with the compilation errors if any.

# Contributing

You can contribute to this library in many ways, including:

- **Reporting bugs**: Simply open an issue and describe the bug. Please include a code snippet to reproduce the bug, it really helps to solve the problem quickly.

- **Suggesting new features**: If you have a feature idea or a use case that is not covered, open an issue and we will discuss it. Do you already have an implementation for it? great, make a pull request and I will review it.

Those are just examples, any issue or pull request is welcome :)

# Changelog

**1.0.0-beta.1 (July 1st 2023)**

First beta version
Binary file added images/code-colors.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 3 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"author": "Amine Ben hammou",
"description": "A library and command line tool to measure the compile time performance of Typescript code.",
"license": "MIT",
"version": "1.0.0-alpha.0",
"version": "1.0.0-beta.1",
"repository": "webNeat/ts-perf",
"homepage": "https://github.com/webNeat/ts-perf",
"main": "dist/index.js",
Expand All @@ -18,14 +18,11 @@
"node": ">=16"
},
"scripts": {
"test": "tsc --noEmit",
"build": "rm -rf dist && tsc"
},
"dependencies": {
"@types/node": "^18.15.11",
"ts-morph": "^19.0.0",
"tslib": "^2.5.0",
"typescript": "^5.0.3",
"fast-glob": "^3.3.0",
"ts-morph": "^19.0.0"
"typescript": "^5.0.3"
}
}
41 changes: 41 additions & 0 deletions src/functions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Project, ProjectOptions, SourceFile } from 'ts-morph';

Check failure on line 1 in src/functions.ts

View workflow job for this annotation

GitHub Actions / publish

Property 'prepareStackTrace' does not exist on type 'ErrorConstructor'.

Check failure on line 1 in src/functions.ts

View workflow job for this annotation

GitHub Actions / publish

Property 'prepareStackTrace' does not exist on type 'ErrorConstructor'.

Check failure on line 1 in src/functions.ts

View workflow job for this annotation

GitHub Actions / publish

Parameter '_' implicitly has an 'any' type.

Check failure on line 1 in src/functions.ts

View workflow job for this annotation

GitHub Actions / publish

Parameter 'stack' implicitly has an 'any' type.

Check failure on line 1 in src/functions.ts

View workflow job for this annotation

GitHub Actions / publish

Property 'captureStackTrace' does not exist on type 'ErrorConstructor'.

Check failure on line 1 in src/functions.ts

View workflow job for this annotation

GitHub Actions / publish

Property 'prepareStackTrace' does not exist on type 'ErrorConstructor'.

export async function measureCode(code: string, options?: ProjectOptions) {
const path = addPathSuffix(getCallerFilePath(), '__ts-perf')
const project = new Project(options)
const file = project.createSourceFile(path, code)
return measure(project, file)
}

export async function measurePath(path: string, options?: ProjectOptions) {
const project = new Project(options)
const file = project.addSourceFileAtPath(path)
return measure(project, file)
}

export async function measure(project: Project, file: SourceFile) {
const start = performance.now()
const diagnostics = file.getPreEmitDiagnostics()
const duration = performance.now() - start
const error = project.formatDiagnosticsWithColorAndContext(diagnostics)
if (error) throw error
return duration
}

export function getCallerFilePath() {
const originalFunc = Error.prepareStackTrace;
Error.prepareStackTrace = function(_, stack) {
return stack;
};
const err = new Error();
Error.captureStackTrace(err, getCallerFilePath);
const stack = err.stack as any;
Error.prepareStackTrace = originalFunc;
return stack[2].getFileName();
}

export function addPathSuffix(path: string, suffix: string) {
const parts = path.split('.')
const extension = parts.pop()
return parts.join('.') + suffix + '.' + extension
}
12 changes: 1 addition & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1 @@
import { Project } from 'ts-morph';

export async function measure(path: string) {
const project = new Project();
const file = project.addSourceFileAtPath(path)
const start = performance.now()
const diagnostics = file.getPreEmitDiagnostics()
const duration = performance.now() - start
const error = project.formatDiagnosticsWithColorAndContext(diagnostics)
return [duration, error] as [number, string]
}
export {measurePath, measureCode} from './functions'
7 changes: 1 addition & 6 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,6 @@
mkdirp "^2.1.6"
path-browserify "^1.0.1"

"@types/node@^18.15.11":
version "18.16.18"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.18.tgz#85da09bafb66d4bc14f7c899185336d0c1736390"
integrity sha512-/aNaQZD0+iSBAGnvvN2Cx92HqE5sZCPZtx2TsK+4nvV23fFe09jVDvpArXr2j9DnYlzuU9WuoykDDc6wqvpNcw==

balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
Expand All @@ -62,7 +57,7 @@ code-block-writer@^12.0.0:
resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-12.0.0.tgz#4dd58946eb4234105aff7f0035977b2afdc2a770"
integrity sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==

fast-glob@^3.2.12, fast-glob@^3.3.0:
fast-glob@^3.2.12:
version "3.3.0"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.0.tgz#7c40cb491e1e2ed5664749e87bfb516dbe8727c0"
integrity sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==
Expand Down

0 comments on commit 8235f65

Please sign in to comment.