Skip to content

Commit

Permalink
Change source code to TypeScript (#8)
Browse files Browse the repository at this point in the history
* Change source code to TypeScript

* update build system

* update tests

* update typescript build
  • Loading branch information
mathiasvr authored Jul 31, 2019
1 parent c02e36b commit bd686ae
Show file tree
Hide file tree
Showing 9 changed files with 4,592 additions and 7,222 deletions.
5 changes: 0 additions & 5 deletions bili.config.js

This file was deleted.

11,423 changes: 4,291 additions & 7,132 deletions package-lock.json

Large diffs are not rendered by default.

28 changes: 18 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
"name": "tiny-timer",
"version": "1.3.0",
"description": "Small countdown timer and stopwatch module.",
"main": "dist/tiny-timer.cjs.js",
"module": "dist/tiny-timer.es.js",
"source": "src/tiny-timer.ts",
"main": "dist/tiny-timer.js",
"module": "dist/tiny-timer.mjs",
"types": "dist/tiny-timer.d.ts",
"scripts": {
"clean:dist": "del-cli dist/*",
"build": "npm run clean:dist && bili",
"prepublish": "npm run build",
"test": "standard src/*.js && tape test.js"
"build": "rimraf dist/* && microbundle --target=node --format=es,cjs --external=events",
"test": "npm run lint && tape test.js && npm run test-ts",
"test-ts": "ts-node -O '{\"esModuleInterop\": true, \"module\": \"commonjs\"}' test-ts.ts",
"lint": "tslint --project .",
"prepare": "npm run build",
"prepublishOnly": "npm test"
},
"keywords": [
"countdown",
Expand All @@ -29,10 +33,14 @@
},
"homepage": "https://github.com/mathiasvr/tiny-timer#readme",
"devDependencies": {
"bili": "^3.1.2",
"del-cli": "^1.1.0",
"standard": "*",
"tape": "^4.6.0"
"@types/node": "^12.6.2",
"@types/tape": "^4.2.33",
"microbundle": "^0.11.0",
"rimraf": "^2.6.3",
"tape": "^4.11.0",
"ts-node": "^8.3.0",
"tslint": "^5.18.0",
"typescript": "^3.5.3"
},
"dependencies": {},
"files": [
Expand Down
75 changes: 0 additions & 75 deletions src/index.js

This file was deleted.

80 changes: 80 additions & 0 deletions src/tiny-timer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { EventEmitter } from 'events'

type Status = 'running' | 'paused' | 'stopped'

class Timer extends EventEmitter {
private _interval: number
private _stopwatch: boolean
private _duration: number = 0
private _endTime: number = 0
private _pauseTime: number = 0
private _status: Status = 'stopped'
private _timeoutID?: NodeJS.Timeout

constructor ({ interval = 1000, stopwatch = false } = {}) {
super()
this._interval = interval
this._stopwatch = stopwatch
}

public start (duration: number, interval?: number) {
if (this.status !== 'stopped') return
if (duration == null) throw new TypeError('Must provide duration parameter')
this._duration = duration
this._endTime = Date.now() + duration
this._changeStatus('running')
this.emit('tick', this._stopwatch ? 0 : this._duration)
this._timeoutID = setInterval(this.tick, interval || this._interval)
}

public stop () {
if (this._timeoutID) clearInterval(this._timeoutID)
this._changeStatus('stopped')
}

public pause () {
if (this.status !== 'running') return
this._pauseTime = Date.now()
this._changeStatus('paused')
}

public resume () {
if (this.status !== 'paused') return
this._endTime += Date.now() - this._pauseTime
this._pauseTime = 0
this._changeStatus('running')
}

private _changeStatus (status: Status) {
this._status = status
this.emit('statusChanged', this.status)
}

private tick = () => {
if (this.status === 'paused') return
if (Date.now() >= this._endTime) {
this.stop()
this.emit('tick', this._stopwatch ? this._duration : 0)
this.emit('done')
} else {
this.emit('tick', this.time)
}
}

get time () {
if (this.status === 'stopped') return 0
const time = this.status === 'paused' ? this._pauseTime : Date.now()
const left = this._endTime - time
return this._stopwatch ? this._duration - left : left
}

get duration () {
return this._duration
}

get status () {
return this._status
}
}

export default Timer
165 changes: 165 additions & 0 deletions test-ts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// NOTE: This is mostly the same as test.js,
// but is included to test TypeScript type errors.

import test from 'tape'
import Timer from '.'

test('countdown ticks', { timeout: 500 }, (t) => {
const timer = new Timer({ interval: 10 })
let lastms = 51

timer.on('tick', (ms) => {
if (lastms === 51) t.equal(ms, 50, 'first update should be 50')
t.ok(ms < lastms, 'time decreasing')
lastms = ms
})

timer.on('done', () => {
t.equal(lastms, 0, 'last update should be 0')
t.end()
})

timer.start(50)
})

test('stopwatch ticks', { timeout: 500 }, (t) => {
const timer = new Timer({ interval: 10, stopwatch: true })
let lastms = -1

timer.on('tick', (ms) => {
if (lastms === -1) t.equal(ms, 0, 'first update should be 0')
t.ok(ms > lastms, 'time increasing')
lastms = ms
})

timer.on('done', () => {
t.equal(lastms, 50, 'last update should be 50')
t.end()
})

timer.start(50)
})

test('stop', (t) => {
const timer = new Timer({ interval: 10 })

timer.on('done', () => t.fail())

setTimeout(() => {
t.equal(timer.status, 'stopped')
t.end()
}, 100)

timer.start(50)
t.equal(timer.status, 'running')
timer.stop()
})

test('pause and resume', (t) => {
const timer = new Timer({ interval: 10 })
const startTime = Date.now()

timer.on('done', () => {
t.ok(Date.now() - startTime > 100, 'paused for at least 100ms')
t.end()
})

setTimeout(() => {
t.equal(timer.status, 'paused')
timer.resume()
}, 100)

timer.start(50)
t.equal(timer.status, 'running')
timer.pause()
})

test('state transition', (t) => {
const timer = new Timer({ interval: 10 })
t.equal(timer.status, 'stopped')
timer.stop()
t.equal(timer.status, 'stopped')
timer.pause()
t.equal(timer.status, 'stopped')
timer.resume()
t.equal(timer.status, 'stopped')
timer.start(20)
t.equal(timer.status, 'running')
timer.pause()
t.equal(timer.status, 'paused')
timer.resume()
t.equal(timer.status, 'running')
timer.stop()
t.equal(timer.status, 'stopped')
timer.start(20)
t.equal(timer.status, 'running')
timer.pause()
timer.stop()
t.equal(timer.status, 'stopped')
timer.start(20)
timer.on('done', () => {
t.equal(timer.status, 'stopped')
t.end()
})
})

test('duration property', (t) => {
const timer = new Timer({ interval: 10 })
timer.on('done', () => {
t.equal(timer.duration, 50, 'correct last duration')
t.end()
})

timer.start(50)
t.equal(timer.duration, 50, 'correct duration')
})

test('time property', (t) => {
const run = (stopwatch: boolean) => {
const timer = new Timer({ interval: 10, stopwatch })
timer.on('tick', (ms) => {
const time = timer.time
// TODO: last ms and time is not equal in stopwatch mode
// because we stop the timer before calling tick to ensure
// that .time won't be less than 0 or greater than duration
if (stopwatch && ms === 50) return
t.ok(time > ms - 5 && time < ms + 5, 'time should be around the ms param')
})

timer.on('done', () => {
t.equal(timer.time, 0)
if (stopwatch) t.end()
})

t.equal(timer.time, 0)
timer.start(50)

const rtime = timer.time
timer.pause()
const ptime = timer.time

t.equal(rtime, ptime)

setTimeout(() => {
t.equal(ptime, timer.time)
timer.resume()
}, 20)
}

run(false)
run(true)
})

test('override interval', (t) => {
const timer = new Timer({ interval: 1000 })
let ticks = 0

timer.on('tick', (ms) => ticks++)

timer.on('done', (ms) => {
t.ok(ticks > 5, 'should do extra tick events')
t.end()
})

timer.start(100, 10)
})
6 changes: 6 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,9 @@ test('override interval', function (t) {

timer.start(100, 10)
})

test('argument errors', function (t) {
const timer = new Timer()
t.throws(() => timer.start(), TypeError, 'Throw TypeError')
t.end()
})
Loading

0 comments on commit bd686ae

Please sign in to comment.