Skip to content

Commit

Permalink
Introduce new parameter --post-compile, to allow custom script after …
Browse files Browse the repository at this point in the history
…typescript compilation (#22)

* chore: git ignore jetbrains ide config folder

* feat: introduce new argument post-compile

* feat: await the post compile script execution after tsc in one shot mode

* feat: await the post compile script execution after tsc in watch mode

* refactor: move post compile logic inside a dedicated function

* test: cover case of a post-compile script with cjs
  • Loading branch information
Palaxx committed Apr 10, 2024
1 parent a5dff7d commit b166c91
Show file tree
Hide file tree
Showing 17 changed files with 213 additions and 5 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Expand Up @@ -133,3 +133,6 @@ dist
.tsimp
.test-watch*
coverage-*

# Jetbrains ide config
.idea
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -96,6 +96,7 @@ Note the use of `incremental: true`, which speed up compilation massively.
* `--pattern` or `-p`, run tests matching the given glob pattern
* `--reporter` or `-r`, set up a reporter, use a colon to set a file destination. Default: `spec`.
* `--no-typescript` or `-T`, disable automatic TypeScript compilation if `tsconfig.json` is found.
* `--post-compile` or `-P`, the path to a file that will be executed after each typescript compilation.

## Reporters

Expand Down
1 change: 1 addition & 0 deletions borp.js
Expand Up @@ -33,6 +33,7 @@ const args = parseArgs({
'expose-gc': { type: 'boolean' },
help: { type: 'boolean', short: 'h' },
'no-typescript': { type: 'boolean', short: 'T' },
'post-compile': { type: 'string', short: 'P' },
reporter: {
type: 'string',
short: 'r',
Expand Down
3 changes: 3 additions & 0 deletions fixtures/ts-cjs-post-compile/package.json
@@ -0,0 +1,3 @@
{
"type": "commonjs"
}
1 change: 1 addition & 0 deletions fixtures/ts-cjs-post-compile/postCompile.ts
@@ -0,0 +1 @@
console.log('Doing stuff')
4 changes: 4 additions & 0 deletions fixtures/ts-cjs-post-compile/src/add.ts
@@ -0,0 +1,4 @@

export function add (x: number, y: number): number {
return x + y
}
7 changes: 7 additions & 0 deletions fixtures/ts-cjs-post-compile/test/add.test.ts
@@ -0,0 +1,7 @@
import { test } from 'node:test'
import { add } from '../src/add.js'
import { strictEqual } from 'node:assert'

test('add', () => {
strictEqual(add(1, 2), 3)
})
7 changes: 7 additions & 0 deletions fixtures/ts-cjs-post-compile/test/add2.test.ts
@@ -0,0 +1,7 @@
import { test } from 'node:test'
import { add } from '../src/add.js'
import { strictEqual } from 'node:assert'

test('add2', () => {
strictEqual(add(3, 2), 5)
})
24 changes: 24 additions & 0 deletions fixtures/ts-cjs-post-compile/tsconfig.json
@@ -0,0 +1,24 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"outDir": "dist",
"sourceMap": true,
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"strict": true,
"resolveJsonModule": true,
"removeComments": true,
"newLine": "lf",
"noUnusedLocals": true,
"noFallthroughCasesInSwitch": true,
"isolatedModules": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"lib": [
"ESNext"
],
"incremental": true
}
}
2 changes: 2 additions & 0 deletions fixtures/ts-esm-post-compile/postCompile.ts
@@ -0,0 +1,2 @@

console.log('Doing stuff')
4 changes: 4 additions & 0 deletions fixtures/ts-esm-post-compile/src/add.ts
@@ -0,0 +1,4 @@

export function add (x: number, y: number): number {
return x + y
}
7 changes: 7 additions & 0 deletions fixtures/ts-esm-post-compile/test/add.test.ts
@@ -0,0 +1,7 @@
import { test } from 'node:test'
import { add } from '../src/add.js'
import { strictEqual } from 'node:assert'

test('add', () => {
strictEqual(add(1, 2), 3)
})
7 changes: 7 additions & 0 deletions fixtures/ts-esm-post-compile/test/add2.test.ts
@@ -0,0 +1,7 @@
import { test } from 'node:test'
import { add } from '../src/add.js'
import { strictEqual } from 'node:assert'

test('add2', () => {
strictEqual(add(3, 2), 5)
})
24 changes: 24 additions & 0 deletions fixtures/ts-esm-post-compile/tsconfig.json
@@ -0,0 +1,24 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"outDir": "dist",
"sourceMap": true,
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"strict": true,
"resolveJsonModule": true,
"removeComments": true,
"newLine": "lf",
"noUnusedLocals": true,
"noFallthroughCasesInSwitch": true,
"isolatedModules": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"lib": [
"ESNext"
],
"incremental": true
}
}
39 changes: 34 additions & 5 deletions lib/run.js
Expand Up @@ -29,11 +29,35 @@ export default async function runWithTypeScript (config) {
let tscPath
const typescriptCliArgs = []

let postCompileFn = async () => {}

if (config['post-compile']) {
postCompileFn = async (outDir) => {
const postCompileFile = join(outDir ?? '', config['post-compile']).replace(/\.ts$/, '.js')
const postCompileStart = Date.now()
const { stdout } = await execa('node', [postCompileFile], { cwd: dirname(tsconfigPath) })
pushable.push({
type: 'test:diagnostic',
data: {
nesting: 0,
message: `Post compile hook complete (${Date.now() - postCompileStart}ms)`,
details: stdout,
typescriptCliArgs
}
})
}
}

if (tsconfigPath && config.typescript !== false) {
const tsconfig = JSON.parse(await readFile(tsconfigPath))
const _require = createRequire(tsconfigPath)
const typescriptPathCWD = _require.resolve('typescript')
tscPath = join(typescriptPathCWD, '..', '..', 'bin', 'tsc')
const outDir = tsconfig.compilerOptions.outDir
if (outDir) {
prefix = join(dirname(tsconfigPath), outDir)
}

if (tscPath) {
// This will throw if we cannot find the `tsc` binary
await access(tscPath)
Expand All @@ -54,12 +78,10 @@ export default async function runWithTypeScript (config) {
typescriptCliArgs
}
})

await postCompileFn(outDir)
}
}
const outDir = tsconfig.compilerOptions.outDir
if (outDir) {
prefix = join(dirname(tsconfigPath), outDir)
}
}

// TODO remove those and create a new object
Expand Down Expand Up @@ -90,10 +112,15 @@ export default async function runWithTypeScript (config) {
if (config.watch) {
typescriptCliArgs.push('--watch')
p = deferred()
let outDir = ''
if (config['post-compile'] && tsconfigPath) {
const tsconfig = JSON.parse(await readFile(tsconfigPath))
outDir = tsconfig.compilerOptions.outDir
}
let start = Date.now()
tscChild = execa('node', [tscPath, ...typescriptCliArgs], { cwd })
tscChild.stdout.setEncoding('utf8')
tscChild.stdout.on('data', (data) => {
tscChild.stdout.on('data', async (data) => {
if (data.includes('File change detected')) {
start = Date.now()
} else if (data.includes('Watching for file changes')) {
Expand All @@ -106,6 +133,8 @@ export default async function runWithTypeScript (config) {
}
})

await postCompileFn(outDir)

p.resolve()
}
if (data.includes('error TS')) {
Expand Down
23 changes: 23 additions & 0 deletions test/cli.test.js
Expand Up @@ -88,3 +88,26 @@ test('gh reporter', async () => {

strictEqual(stdout.indexOf('::notice') >= 0, true)
})

test('Post compile script should be executed when --post-compile is sent with esm', async () => {
const cwd = join(import.meta.url, '..', 'fixtures', 'ts-esm-post-compile')
const { stdout } = await execa('node', [
borp,
'--post-compile=postCompile.ts'
], {
cwd
})

strictEqual(stdout.indexOf('Post compile hook complete') >= 0, true, 'Post compile message should be found in stdout')
})

test('Post compile script should be executed when --post-compile is sent with cjs', async () => {
const { stdout } = await execa('node', [
borp,
'--post-compile=postCompile.ts'
], {
cwd: join(import.meta.url, '..', 'fixtures', 'ts-cjs-post-compile')
})

strictEqual(stdout.indexOf('Post compile hook complete') >= 0, true, 'Post compile message should be found in stdout')
})
61 changes: 61 additions & 0 deletions test/watch.test.js
Expand Up @@ -109,3 +109,64 @@ test('add', () => {

await completed
})

test('watch with post compile hook should call the hook the right number of times', async (t) => {
const { strictEqual, completed, ok } = tspl(t, { plan: 2 })

const dir = path.resolve(await mkdtemp('.test-watch-with-post-compile-hook'))
await cp(join(import.meta.url, '..', 'fixtures', 'ts-esm-post-compile'), dir, {
recursive: true
})

const controller = new AbortController()
t.after(async () => {
controller.abort()
try {
await rm(dir, { recursive: true, retryDelay: 100, maxRetries: 10 })
} catch {}
})

const config = {
'post-compile': 'postCompile.ts',
files: [],
cwd: dir,
signal: controller.signal,
watch: true
}

const stream = await runWithTypeScript(config)

const fn = (test) => {
if (test.type === 'test:fail') {
strictEqual(test.data.name, 'add')
stream.removeListener('data', fn)
}
}
stream.on('data', fn)

let postCompileEventCount = 0
const diagnosticListenerFn = (test) => {
if (test.type === 'test:diagnostic' && test.data.message.includes('Post compile hook complete')) {
if (++postCompileEventCount === 2) {
ok(true, 'Post compile hook ran twice')
stream.removeListener('data', diagnosticListenerFn)
}
}
}

stream.on('data', diagnosticListenerFn)

const toWrite = `
import { test } from 'node:test'
import { add } from '../src/add.js'
import { strictEqual } from 'node:assert'
test('add', () => {
strictEqual(add(1, 2), 4)
})
`
const file = path.join(dir, 'test', 'add.test.ts')
await writeFile(file, toWrite)

await completed
})

0 comments on commit b166c91

Please sign in to comment.