Skip to content

Commit

Permalink
Merge pull request #6 from webKrafters/ts-deploy
Browse files Browse the repository at this point in the history
ts specific deployment - wip
  • Loading branch information
steveswork authored May 8, 2024
2 parents 20c0a5c + 26189e1 commit d85baf9
Show file tree
Hide file tree
Showing 18 changed files with 198 additions and 201 deletions.
17 changes: 0 additions & 17 deletions index.js

This file was deleted.

2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module.exports = {
collectCoverageFrom: [ 'src/**/*.ts' ],
"coveragePathIgnorePatterns": [
"<rootDir>/src/\\$global.ts",
"<rootDir>/src/types.ts",
"<rootDir>/src/index.ts",
],
detectOpenHandles: true,
preset: 'ts-jest',
Expand Down
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@
"ts-node": "^10.9.2",
"typescript": "^5.4.2"
},
"files": [ "dist", "index.js", "logo.svg" ],
"files": [
"dist",
"logo.svg"
],
"homepage": "https://github.com/webKrafters/long-count/readme",
"keywords": [
"interval",
Expand All @@ -46,7 +49,7 @@
"timer"
],
"license": "MIT",
"main": "index.js",
"main": "dist/index.js",
"name": "@webkrafters/long-count",
"publishConfig": {
"access": "public"
Expand All @@ -63,5 +66,5 @@
"test:watch": "jest --updateSnapshot --watchAll"
},
"types": "dist/types.d.ts",
"version": "0.0.4"
"version": "1.0.0-rc.0"
}
157 changes: 24 additions & 133 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,144 +1,35 @@
import type { Delay, EventType, Options, VoidFn } from './types';
export type { default as TimerObservable } from './observable/index';

import { $global } from './$global';
export type { default as Timer } from './timer/index';

import TimerObservable from './observable/index';
export type { LongCounter, Interval } from './main';

import Timer from './timer/index';
export type Delay = BigInteger | Iterable<number> | IterableIterator<number> | number | string | undefined;

export type Opts = Partial<Options>;
export type DelayTypeName = 'BigInt' | 'Invalid' | 'Iterable' | 'Number' | 'String' | 'Undefined' | 'Uint8Array'

export type EventType = 'cycleEnding' | 'cycleStarted' | 'exit' | 'resume' | 'suspend';

let counter = 0;

const longCounterMap : {[ counterId : number ]: LongCounter } = {};

export const internal = {
current: Math.random(),
graceId: undefined,
gracePeriod: 1e4, // 10 seconds
is( envcode : number ) { return envcode && ( envcode === this.current || envcode === this.previous ) },
previous: undefined,
ttl: 1.08e7, // 3 hour cycle
unwatch() {
global.clearTimeout( this.graceId );
global.clearInterval( this.watchId );
this.graceId = this.watchId = undefined;
},
watch() {
if( this.watchId ) { throw new TypeError( 'Cannot begin new watch at this time. An exisitng watch is currently underway. Use the `unwatch()` method to disable it in order to begin a new watch.' ) }
const _this = this;
this.watchId = $global.setInterval(() => {
_this.previous = _this.current;
_this.current = Math.random();
_this.graceId = $global.setTimeout( () => {
_this.graceId = _this.previous = undefined;
}, this.gracePeriod );
}, this.ttl );
},
watchId: undefined
};
internal.watch();

export class LongCounter extends TimerObservable {
#id : number;
#timer : Timer;
constructor( timer : Timer ) {
super();
this.#timer = timer;
this.#id = ++counter;
longCounterMap[ this.#id ] = this;
}
get expired() { return this.#timer === undefined };
get id() { return this.#id }
get timeRemaining() { return this.#timer?.currentWaitTime }
protected set timer( timer ) { this.#timer = timer }
addEventListener( eventType : EventType, listener : VoidFn ) {
this.#timer &&
this.observers[ eventType ].add( listener ) &&
this.#timer.addEventListener( eventType, listener );
}
cancel() {
delete longCounterMap[ this.id ];
if( !this.#timer ) { return }
if( this.#timer.disposed ) {
this.#timer = undefined;
return;
}
// preempts exit listeners
for( let listener of this.observers.exit ) {
this.#timer.removeEventListener( 'exit', listener );
}
this.#timer.exit();
this.#timer = undefined;
}
dispatchEvent( eventType : EventType, ...args : Array<any> ) {
this.#timer?.dispatchEvent( eventType, ...args );
}
removeEventListener( eventType : EventType, listener : VoidFn ) {
this.#timer &&
this.observers[ eventType ].delete( listener ) &&
this.#timer.removeEventListener( eventType, listener );
};
valueOf() { return this.id }
}

export class Interval extends LongCounter {
constructor( timer : Timer ) { super( timer ) }
updateTimer ( timer : Timer, internalCode : number ) {
if( !internal.is( internalCode ) ) {
throw new SyntaxError( `Following operation cannot be completed using the following code: ${ internalCode }.` );
}
for( let [ eventType, listeners ] of Object.entries( this.observers ) ) {
for( let listener of listeners ) {
timer.addEventListener( eventType as EventType, listener );
}
}
this.cancel();
this.timer = timer;
longCounterMap[ this.id ] = this;
}
export interface ITimerObservable {
addEventListener( eventType : EventType, listener : VoidFn ) : void;
dispatchEvent( eventType : EventType, ...args : Array<any> ) : void;
removeEventListener( eventType : EventType, listener : VoidFn ) : void
}

/** @param longCounter - LongCounter instance or LongCounter.id property value */
const endLongCount = <T extends number | LongCounter>( longCounter : T ) => ( (
typeof longCounter === 'number'
? longCounterMap[ longCounter ]
: longCounter
) as LongCounter )?.cancel();

/** @param longCounter - LongCounter instance or LongCounter.id property value */
export const clearInterval = endLongCount;

/** @param longCounter - LongCounter instance or LongCounter.id property value */
export const clearTimeout = endLongCount;
export type MyInteger = Uint8Array|number;

/** @param options - Options object or Options.immediate property value */
const resolveTimerOptions = <T extends boolean | Opts>( options : T ) : Opts => (
typeof options === 'boolean' ? { immediate: options } : options
);
export type ObserverMap = {[ K in EventType ]: Set<VoidFn>};

/** @param options - Options.immediate property value */
export function setInterval( fn : VoidFn, delay? : Delay, options? : boolean, ...args : Array<any> ) : Interval;
/** @param options - Options object */
export function setInterval( fn : VoidFn, delay? : Delay, options? : Opts, ...args : Array<any> ) : Interval;
/** @param options - Options object or Options.immediate property value */
export function setInterval( fn : VoidFn, delay : Delay = undefined, options : boolean | Opts = false , ...args : Array<any> ) {
const tOptions = resolveTimerOptions( options );
const interval = new Interval( new Timer( fn, delay, tOptions, ...args ) );
interval.addEventListener( 'exit', () => interval.updateTimer(
new Timer( fn, delay, { ...tOptions, immediate : false }, ...args ),
internal.current
) );
return interval;
export interface Options {
immediate? : boolean, // set true to invoke timer handler once follwoing timer instantiation and then once following the delay window
maxTimeoutDelay? : number // allows for declaring max timeout delay value allowed by the target platform
};

/** @param options - Options.immediate property value */
export function setTimeout( fn : VoidFn, delay? : Delay, options? : boolean, ...args : Array<any> ) : LongCounter;
/** @param options - Options object */
export function setTimeout( fn : VoidFn, delay? : Delay, options? : Opts, ...args : Array<any> ) : LongCounter;
/** @param options - Options object or Options.immediate property value */
export function setTimeout( fn : VoidFn, delay : Delay = undefined, options : boolean | Opts = false, ...args : Array<any> ) {
const counter = new LongCounter( new Timer( fn, delay, resolveTimerOptions( options ), ...args ) );
counter.addEventListener( 'exit', counter.cancel.bind( counter ) );
return counter;
};
export type VoidFn = ( ...args: Array<any> ) => void;

export {
clearInterval,
clearTimeout,
setInterval,
setTimeout
} from './main';
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @ts-nocheck

import Timer from './timer';
import { internal, setInterval, setTimeout } from '.';
import { internal, setInterval, setTimeout } from './main';

jest.mock( './timer' );

Expand Down
10 changes: 5 additions & 5 deletions src/index.test.ts → src/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MAX_SET_TIMEOUT_DELAY } from './constants';
import * as main from './index';
import * as main from './main';

import TimerObservable from './observable';
import Timer from './timer';
Expand Down Expand Up @@ -275,7 +275,7 @@ describe( 'internal caller passcode', () => {
test( 'watch automatically starts at module load', () => {
jest.isolateModules(() => {
jest.useFakeTimers();
const { internal } = require( './index' );
const { internal } = require( './main' );
expect( internal.watchId ).toBeDefined();
internal.unwatch(); // turn off the watch
expect( internal.watchId ).toBeUndefined();
Expand All @@ -285,7 +285,7 @@ describe( 'internal caller passcode', () => {
test( 'updates every `$ttl` milliseconds', () => {
jest.isolateModules(() => {
jest.useFakeTimers();
const { internal } = require( './index' );
const { internal } = require( './main' );
const currentPassCode = internal.current;
jest.advanceTimersByTime( internal.ttl - 10 );
expect( internal.current ).toBe( currentPassCode );
Expand All @@ -299,7 +299,7 @@ describe( 'internal caller passcode', () => {
test( 'grants old passcode a 10-second grace period', () => {
jest.isolateModules(() => {
jest.useFakeTimers();
const internal = require( './index' ).internal;
const internal = require( './main' ).internal;
const currentPassCode = internal.current;
jest.advanceTimersByTime( internal.ttl );
expect( internal.current ).not.toBe( currentPassCode );
Expand All @@ -318,7 +318,7 @@ describe( 'internal caller passcode', () => {
test( 'throws a `TypeError` on attempt to call the `watch()` method while currently under watch', () => {
jest.isolateModules(() => {
jest.useFakeTimers();
const { internal } = require( './index' );
const { internal } = require( './main' );
try { internal.watch() } catch( e ) {
expect( e.constructor ).toEqual( TypeError );
expect( e.message ).toEqual(
Expand Down
Loading

0 comments on commit d85baf9

Please sign in to comment.