Skip to content

Commit

Permalink
Release 1.0.0-beta.2
Browse files Browse the repository at this point in the history
  • Loading branch information
Amine Ben hammou committed Jul 1, 2023
1 parent 78d7ab1 commit 4a6812d
Show file tree
Hide file tree
Showing 14 changed files with 434 additions and 75 deletions.
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"semi": false,
"printWidth": 155,
"singleQuote": true,
"trailingComma": "es5",
"bracketSpacing": true
}
71 changes: 41 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,16 @@ A small library to measure the compile time performance of Typescript code.

# Contents


- [Installation](#installation)
- [Use cases](#use-cases)
- [Measuring a file by path](#measuring-a-file-by-path)
- [Measuring a code snippet](#measuring-a-code-snippet)
- [Writing performance tests for Typescript types](#writing-performance-tests-for-typescript-types)
- [API reference](#api-reference)
- [measurePath](#measure-path)
- [measureCode](#measure-code)
- [Contributing](#contributing)
- [Changelog](#changelog)

# Installation

Expand All @@ -20,7 +29,7 @@ npm i -D ts-perf
yarn add -D ts-perf
```

# Simple usages
# Use cases

## Measuring a file by path

Expand All @@ -29,7 +38,7 @@ Measuring how much time it takes Typescript compiler to parse and type-check a f
```ts
import {measurePath} from 'ts-perf'

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

if there are compilation errors in the file, the `measurePath` function will throw the formatted error message.
Expand All @@ -48,13 +57,11 @@ if we run the following code
```ts
import {measurePath} from 'ts-perf'

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

it will show the following error
Expand All @@ -75,14 +82,16 @@ if you want to measure the compilation performance of some code without creating
```ts
import {measureCode} from 'ts-perf'

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

This will create a virtual file `temp.ts` with the provided code and measure it. It's equivalent to creating the file manually then calling `measurePath` with its path.

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

**Adding syntax highlighting to code snippets**
Expand All @@ -93,21 +102,19 @@ if you are using VSCode, you can use the extension [es6-string-typescript](https

**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).
You can use `import` statements inside the code snippets and they will be resolved relative to the provided path (To make thing easier, you can provide `__filename` as path and use imports relative to the current file).

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

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

## Writing performance tests for Typescript types
Expand All @@ -118,7 +125,8 @@ 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)
const ms = measureCode(`some code using the custom type ...`)
expect(ms).toBeLessThan(1000)
})
```

Expand All @@ -127,24 +135,21 @@ it('takes less than a second to typecheck the code', async () => {
## measurePath

```ts
import { ProjectOptions } from 'ts-morph'
function measurePath(path: string, options?: ProjectOptions): Promise<number>
function measurePath(path: string): 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>
function measureCode(path: string, code: string): number
```

- `path`: Path to the Typescript file.
- `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.

Expand All @@ -160,6 +165,12 @@ Those are just examples, any issue or pull request is welcome :)

# Changelog

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

- Make the functions synchronous.
- Use the `typescript` Compiler API directly instead of `ts-morph`.
- Add simple tests.

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

First beta version
- First beta version.
Binary file modified 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.
10 changes: 7 additions & 3 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-beta.1",
"version": "1.0.0-beta.2",
"repository": "webNeat/ts-perf",
"homepage": "https://github.com/webNeat/ts-perf",
"main": "dist/index.js",
Expand All @@ -18,13 +18,17 @@
"node": ">=16"
},
"scripts": {
"test": "echo 'TODO'",
"test": "tsx tests/run.ts",
"build": "rm -rf dist && tsc"
},
"dependencies": {
"@types/node": "^20.3.3",
"ts-morph": "^19.0.0",
"tslib": "^2.5.0",
"typescript": "^5.0.3"
},
"devDependencies": {
"just-types": "^2.0.0-alpha.2",
"prettier": "^2.8.8",
"tsx": "^3.12.7"
}
}
41 changes: 0 additions & 41 deletions src/functions.ts

This file was deleted.

43 changes: 42 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,42 @@
export {measurePath, measureCode} from './functions'
import * as ts from 'typescript'
import { normalize } from 'path'

export function measureCode(path: string, code: string) {
const sourceFile = ts.createSourceFile(path, code, ts.ScriptTarget.ES2015, true)
const host = addSourceFileToHost(ts.createCompilerHost({}), path, sourceFile)
const program = ts.createProgram([path], { noEmitOnError: true }, host)
return measure(program, sourceFile)
}

export function measurePath(filePath: string) {
const program = ts.createProgram([filePath], { noEmitOnError: true })
const sourceFile = program.getSourceFile(filePath)
if (!sourceFile) {
throw new Error(`No source file found at path: ${filePath}`)
}
return measure(program, sourceFile)
}

function measure(program: ts.Program, sourceFile: ts.SourceFile) {
const start = performance.now()
const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile)
const duration = performance.now() - start
if (diagnostics.length > 0) {
const error = ts.formatDiagnosticsWithColorAndContext(diagnostics, {
getCanonicalFileName: normalize,
getCurrentDirectory: ts.sys.getCurrentDirectory,
getNewLine: () => ts.sys.newLine,
})
throw new Error(error)
}
return duration
}

function addSourceFileToHost(host: ts.CompilerHost, path: string, sourceFile: ts.SourceFile) {
const getSourceFile = host.getSourceFile
host.getSourceFile = (filename, languageVersion) => {
if (filename === path) return sourceFile
return getSourceFile(filename, languageVersion)
}
return host
}
3 changes: 3 additions & 0 deletions tests/computation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { add } from './math'

console.log(add(1, 2))
Empty file added tests/empty.ts
Empty file.
3 changes: 3 additions & 0 deletions tests/heavy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { tuple } from 'just-types'

const x: tuple.Permutation<[1, 2, 3, 4, 5, 6, 7]> = [1, 4, 7, 2, 6, 3, 5]
3 changes: 3 additions & 0 deletions tests/math.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function add(x: number, y: number) {
return x + y
}
88 changes: 88 additions & 0 deletions tests/run.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import assert from 'assert'
import { test } from './utils'
import { measurePath, measureCode } from '../src'

test('measurePath: empty file', () => {
const duration = measurePath('tests/empty.ts')
console.log(duration)
assert.equal(duration < 500, true)
})

test('measurePath: simple file', () => {
const duration = measurePath('tests/math.ts')
console.log(duration)
assert.equal(duration < 500, true)
})

test('measurePath: file importing other files', () => {
const duration = measurePath('tests/computation.ts')
console.log(duration)
assert.equal(duration < 500, true)
})

test('measurePath: heavy types', () => {
const duration = measurePath('tests/heavy.ts')
console.log(duration)
assert.equal(duration > 300, true)
assert.equal(duration < 2_000, true)
})

test('measurePath: file with errors', () => {
assert.throws(() => measurePath('tests/wrong.ts'))
})

test('measureCode: empty code', () => {
const duration = measureCode(__filename, '')
console.log(duration)
assert.equal(duration < 500, true)
})

test('measureCode: simple code', () => {
const duration = measureCode(
__filename,
/*ts*/ `
export function add(x: number, y: number) {
return x + y
}
`
)
console.log(duration)
assert.equal(duration < 500, true)
})

test('measureCode: file importing other files', () => {
const duration = measureCode(
__filename,
/*ts*/ `
import { add } from './math'
console.log(add(1, 2))
`
)
console.log(duration)
assert.equal(duration < 500, true)
})

test('measureCode: heavy types', () => {
const duration = measureCode(
__filename,
/*ts*/ `
import { tuple } from 'just-types'
const x: tuple.Permutation<[1, 2, 3, 4, 5, 6, 7]> = [1, 4, 7, 2, 6, 3, 5]
`
)
console.log(duration)
assert.equal(duration > 300, true)
assert.equal(duration < 2_000, true)
})

test('measureCode: file with errors', () => {
assert.throws(() =>
measureCode(
__filename,
/*ts*/ `
import { add } from './math'
console.log(add('foo', 2))
`
)
)
})
10 changes: 10 additions & 0 deletions tests/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export function test(name: string, fn: () => any) {
try {
fn()
console.log(`✅`, name)
} catch (err) {
console.error(`❌`, name)
console.error(err)
process.exit(1)
}
}
3 changes: 3 additions & 0 deletions tests/wrong.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { add } from './math'

console.log(add('foo', 2))
Loading

0 comments on commit 4a6812d

Please sign in to comment.