ts-raii-scope
Version:
TypeScript RAII proof of concept
96 lines (95 loc) • 3.22 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const raiiScope_1 = require("./raiiScope");
class ScopeStack {
constructor() {
this._syncStack = [];
// key: scope, value: was saved by client
this._asyncScopes = new Map();
}
enterScope(isAsync, scope) {
if (!scope) {
scope = new raiiScope_1.RaiiScope();
}
else if (this.findSyncStackIndex(scope) !== -1) {
throw new Error('Scope is already in stack');
}
else if (this._asyncScopes.has(scope)) {
throw new Error('Scope is already in async scopes set');
}
this._syncStack.push(scope);
if (isAsync) {
this._asyncScopes.set(scope, false);
}
return scope;
}
exitScope(scope) {
const syncIndex = this.findSyncStackIndex(scope);
if (syncIndex === -1) {
throw new Error('Scope is not in stack');
}
const scopesAbove = this._syncStack.length - 1 - syncIndex;
if (scopesAbove > 0) {
throw new Error(`Can't exit scope because there are ${scopesAbove} scopes above.`);
}
this._syncStack.splice(syncIndex, 1);
const asyncScopeSaved = this._asyncScopes.get(scope);
if (asyncScopeSaved === false) {
console.warn('Async scope exited not being saved in method');
}
if (asyncScopeSaved === undefined) {
return scope.dispose();
}
}
// noinspection JSUnusedGlobalSymbols
asyncScopeDone(scope) {
const syncIndex = this.findSyncStackIndex(scope);
if (syncIndex !== -1) {
throw new Error('Scope from sync stack passed as async');
}
if (!this._asyncScopes.has(scope)) {
throw new Error('Async scope not found');
}
this._asyncScopes.delete(scope);
return scope.dispose();
}
// noinspection JSUnusedGlobalSymbols
/**
* Call from sync methods
*/
pushToTopScope(resource) {
const topScope = this.getTopScope();
if (this._asyncScopes.has(topScope)) {
throw new Error('In order to push to async scope, save it using saveCurrentAsyncScope() ' +
'in your method variable and push resources to it');
}
return topScope.push(resource);
}
// noinspection JSUnusedGlobalSymbols
/**
* Call inside async method to keep scope in local variable
*/
saveCurrentAsyncScope() {
const scope = this.getTopScope();
if (!this._asyncScopes.has(scope)) {
throw new Error('Current scope is not async');
}
this._asyncScopes.set(scope, true);
return scope;
}
getTopScope() {
if (this._syncStack.length > 0) {
return this._syncStack[this._syncStack.length - 1];
}
throw new Error('Sync scopes stack is empty');
}
findSyncStackIndex(scope) {
for (let i = this._syncStack.length - 1; i >= 0; --i) {
if (this._syncStack[i] === scope) {
return i;
}
}
return -1;
}
}
exports.scopeStack = new ScopeStack();