diff --git a/.gitignore b/.gitignore
index 2b2e74b..294c324 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@
/.idea/
/test/tests/decorators.js
/test/tests/decorators.legacy.js
+/playground/dist/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 901d1a2..bb4ed49 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
For changes before version 0.4.0, please see the commit history
+## [0.10.2] - 2020-12-08
+
+### Added
+- @canceled decorator
+
## [0.10.1] - 2020-12-07
### Updated
diff --git a/README.md b/README.md
index 5c96a29..c4af229 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,7 @@
- [@async](#asynctimeout-number)
- [@listen](#listensignal-abortsignalstringsymbol)
- [@cancel](#cancelreason-string-signal-abortsignalstringsymbol)
+ - [@canceled](#canceledonrejectederr-scope-context-function)
- [@timeout](#timeoutms-number)
- [@innerWeight](#innerweightweight-number)
- [@label](#labellabel-string)
@@ -520,6 +521,9 @@ If this argument not specified or null, the internal default AbortController wil
### @cancel([reason: String], [signal: AbortSignal|String|Symbol])
Emits the cancel signal before the target function invoking.
+### @canceled([onRejected(err, scope, context): Function])
+Catches rejections with CanceledError errors
+
````javascript
import cpFetch from "cpFetch";
@@ -634,6 +638,12 @@ innerWeight decorator
### CPromise.label : function
label decorator
+**Kind**: static property of [CPromise
](#module_CPromise)
+
+
+### CPromise.canceled : function
+label decorator
+
**Kind**: static property of [CPromise
](#module_CPromise)
diff --git a/jsdoc2md/README.hbs.md b/jsdoc2md/README.hbs.md
index 8c7266a..7d3432b 100644
--- a/jsdoc2md/README.hbs.md
+++ b/jsdoc2md/README.hbs.md
@@ -23,6 +23,7 @@
- [@async](#asynctimeout-number)
- [@listen](#listensignal-abortsignalstringsymbol)
- [@cancel](#cancelreason-string-signal-abortsignalstringsymbol)
+ - [@canceled](#canceledonrejectederr-scope-context-function)
- [@timeout](#timeoutms-number)
- [@innerWeight](#innerweightweight-number)
- [@label](#labellabel-string)
@@ -520,6 +521,9 @@ If this argument not specified or null, the internal default AbortController wil
### @cancel([reason: String], [signal: AbortSignal|String|Symbol])
Emits the cancel signal before the target function invoking.
+### @canceled([onRejected(err, scope, context): Function])
+Catches rejections with CanceledError errors
+
````javascript
import cpFetch from "cpFetch";
diff --git a/lib/c-promise.js b/lib/c-promise.js
index a7eedf4..442386e 100644
--- a/lib/c-promise.js
+++ b/lib/c-promise.js
@@ -7,7 +7,7 @@
* @typedef {String|Symbol} EventType
*/
const {CanceledError} = require('./canceled-error');
-const {E_REASON_CANCELED, E_REASON_TIMEOUT, E_REASON_DISPOSED}= CanceledError;
+const {E_REASON_CANCELED, E_REASON_TIMEOUT, E_REASON_DISPOSED} = CanceledError;
const {AbortController, AbortControllerEx, isAbortSignal, isAbortController} = require('./abort-controller');
const {validateOptions, validators} = require('./validator');
const {
@@ -100,7 +100,7 @@ class CPromise extends Promise {
}
}
- let {label, weight, timeout, signal, nativeController= false} = options || {};
+ let {label, weight, timeout, signal, nativeController = false} = options || {};
let resolve, reject;
@@ -469,10 +469,10 @@ class CPromise extends Promise {
*/
get signal() {
- const shadow= this[_shadow];
+ const shadow = this[_shadow];
if (this[_shadow].controller) return this[_shadow].controller.signal;
- return (this[_shadow].controller = new (shadow.nativeController? AbortController : AbortControllerEx)()).signal;
+ return (this[_shadow].controller = new (shadow.nativeController ? AbortController : AbortControllerEx)()).signal;
}
/**
@@ -588,7 +588,8 @@ class CPromise extends Promise {
const resolve = () => {
if (isRejected) {
shadow.value = value;
- shadow.isCanceled && !shadow.leafsCount && super.then(null, () => {});
+ shadow.isCanceled && !shadow.leafsCount && super.then(null, () => {
+ });
this.emit('done', value);
shadow.reject(value);
} else {
@@ -1621,8 +1622,8 @@ const decorators = {
decorator.descriptor = {
value: function (...args) {
- let promise = CPromise.resolveGenerator(originalFn, {
- context,
+ let promise = context.resolveGenerator(originalFn, {
+ context: this,
args
});
@@ -1701,6 +1702,26 @@ const decorators = {
return fn.apply(this, arguments);
}
+ return decorator;
+ },
+
+ canceled: (decorator, [arg0]) => {
+ if (arg0 != null && typeof arg0 !== 'function') {
+ throw TypeError(`@canceled decorator expects a function as the first argument`);
+ }
+
+ const fn = decorator.descriptor.value;
+
+ decorator.descriptor.value = function () {
+ const result = fn.apply(this, arguments);
+
+ if (!(result instanceof CPromise)) {
+ throw TypeError(`@canceled decorator can only be used for async function only, that returns CPromise instance`);
+ }
+
+ return result.canceled((err, scope)=> arg0.call(this, err, scope, this));
+ }
+
return decorator;
}
};
@@ -1752,63 +1773,68 @@ Object.defineProperties(CPromise, {
CPromise: {value: CPromise}
})
-exports.CPromise= CPromise;
+exports.CPromise = CPromise;
/**
* CanceledError class
* @type {CanceledError}
*/
-exports.CanceledError= CanceledError;
+exports.CanceledError = CanceledError;
/**
* Refers to the AbortController class (native if available)
* @type {AbortController|AbortControllerEx}
*/
-exports.AbortController= AbortController;
+exports.AbortController = AbortController;
/**
* AbortControllerEx class
* @type {AbortControllerEx}
*/
-exports.AbortControllerEx= AbortControllerEx;
+exports.AbortControllerEx = AbortControllerEx;
/**
* Generic cancellation reason
*/
-exports.E_REASON_CANCELED= E_REASON_CANCELED;
+exports.E_REASON_CANCELED = E_REASON_CANCELED;
/**
* Cancellation reason for the case when the instance will be disposed
*/
-exports.E_REASON_DISPOSED= E_REASON_DISPOSED;
+exports.E_REASON_DISPOSED = E_REASON_DISPOSED;
/**
* Timeout cancellation reason
*/
-exports.E_REASON_TIMEOUT= E_REASON_TIMEOUT;
+exports.E_REASON_TIMEOUT = E_REASON_TIMEOUT;
/**
* async decorator
* @type {Function}
*/
-exports.async= CPromise.async;
+exports.async = CPromise.async;
/**
* listen decorator
* @type {Function}
*/
-exports.listen= CPromise.listen;
+exports.listen = CPromise.listen;
/**
* cancel decorator
* @type {Function}
*/
-exports.cancel= CPromise.cancel;
+exports.cancel = CPromise.cancel;
/**
* timeout decorator
* @type {Function}
*/
-exports.timeout= CPromise.timeout;
+exports.timeout = CPromise.timeout;
/**
* innerWeight decorator
* @type {Function}
*/
-exports.innerWeight= CPromise.innerWeight;
+exports.innerWeight = CPromise.innerWeight;
+/**
+ * label decorator
+ * @type {Function}
+ */
+exports.label = CPromise.label;
/**
* label decorator
* @type {Function}
*/
-exports.label= CPromise.label;
+exports.canceled = CPromise.canceled;
diff --git a/playground/dist/decorators.build.js b/playground/dist/decorators.build.js
deleted file mode 100644
index a6491c3..0000000
--- a/playground/dist/decorators.build.js
+++ /dev/null
@@ -1,554 +0,0 @@
-'use strict';
-
-function _toArray(arr) {
- return _arrayWithHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableRest();
-}
-
-function _arrayWithHoles(arr) {
- if (Array.isArray(arr)) return arr;
-}
-
-function _iterableToArray(iter) {
- if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
-}
-
-function _unsupportedIterableToArray(o, minLen) {
- if (!o) return;
- if (typeof o === "string") return _arrayLikeToArray(o, minLen);
- var n = Object.prototype.toString.call(o).slice(8, -1);
- if (n === "Object" && o.constructor) n = o.constructor.name;
- if (n === "Map" || n === "Set") return Array.from(o);
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
-}
-
-function _arrayLikeToArray(arr, len) {
- if (len == null || len > arr.length) len = arr.length;
-
- for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
-
- return arr2;
-}
-
-function _nonIterableRest() {
- throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
-}
-
-function _toPrimitive(input, hint) {
- if (typeof input !== "object" || input === null) return input;
- var prim = input[Symbol.toPrimitive];
-
- if (prim !== undefined) {
- var res = prim.call(input, hint || "default");
- if (typeof res !== "object") return res;
- throw new TypeError("@@toPrimitive must return a primitive value.");
- }
-
- return (hint === "string" ? String : Number)(input);
-}
-
-function _toPropertyKey(arg) {
- var key = _toPrimitive(arg, "string");
-
- return typeof key === "symbol" ? key : String(key);
-}
-
-function _decorate(decorators, factory, superClass, mixins) {
- var api = _getDecoratorsApi();
-
- if (mixins) {
- for (var i = 0; i < mixins.length; i++) {
- api = mixins[i](api);
- }
- }
-
- var r = factory(function initialize(O) {
- api.initializeInstanceElements(O, decorated.elements);
- }, superClass);
- var decorated = api.decorateClass(_coalesceClassElements(r.d.map(_createElementDescriptor)), decorators);
- api.initializeClassElements(r.F, decorated.elements);
- return api.runClassFinishers(r.F, decorated.finishers);
-}
-
-function _getDecoratorsApi() {
- _getDecoratorsApi = function () {
- return api;
- };
-
- var api = {
- elementsDefinitionOrder: [["method"], ["field"]],
- initializeInstanceElements: function (O, elements) {
- ["method", "field"].forEach(function (kind) {
- elements.forEach(function (element) {
- if (element.kind === kind && element.placement === "own") {
- this.defineClassElement(O, element);
- }
- }, this);
- }, this);
- },
- initializeClassElements: function (F, elements) {
- var proto = F.prototype;
- ["method", "field"].forEach(function (kind) {
- elements.forEach(function (element) {
- var placement = element.placement;
-
- if (element.kind === kind && (placement === "static" || placement === "prototype")) {
- var receiver = placement === "static" ? F : proto;
- this.defineClassElement(receiver, element);
- }
- }, this);
- }, this);
- },
- defineClassElement: function (receiver, element) {
- var descriptor = element.descriptor;
-
- if (element.kind === "field") {
- var initializer = element.initializer;
- descriptor = {
- enumerable: descriptor.enumerable,
- writable: descriptor.writable,
- configurable: descriptor.configurable,
- value: initializer === void 0 ? void 0 : initializer.call(receiver)
- };
- }
-
- Object.defineProperty(receiver, element.key, descriptor);
- },
- decorateClass: function (elements, decorators) {
- var newElements = [];
- var finishers = [];
- var placements = {
- static: [],
- prototype: [],
- own: []
- };
- elements.forEach(function (element) {
- this.addElementPlacement(element, placements);
- }, this);
- elements.forEach(function (element) {
- if (!_hasDecorators(element)) return newElements.push(element);
- var elementFinishersExtras = this.decorateElement(element, placements);
- newElements.push(elementFinishersExtras.element);
- newElements.push.apply(newElements, elementFinishersExtras.extras);
- finishers.push.apply(finishers, elementFinishersExtras.finishers);
- }, this);
-
- if (!decorators) {
- return {
- elements: newElements,
- finishers: finishers
- };
- }
-
- var result = this.decorateConstructor(newElements, decorators);
- finishers.push.apply(finishers, result.finishers);
- result.finishers = finishers;
- return result;
- },
- addElementPlacement: function (element, placements, silent) {
- var keys = placements[element.placement];
-
- if (!silent && keys.indexOf(element.key) !== -1) {
- throw new TypeError("Duplicated element (" + element.key + ")");
- }
-
- keys.push(element.key);
- },
- decorateElement: function (element, placements) {
- var extras = [];
- var finishers = [];
-
- for (var decorators = element.decorators, i = decorators.length - 1; i >= 0; i--) {
- var keys = placements[element.placement];
- keys.splice(keys.indexOf(element.key), 1);
- var elementObject = this.fromElementDescriptor(element);
- var elementFinisherExtras = this.toElementFinisherExtras((0, decorators[i])(elementObject) || elementObject);
- element = elementFinisherExtras.element;
- this.addElementPlacement(element, placements);
-
- if (elementFinisherExtras.finisher) {
- finishers.push(elementFinisherExtras.finisher);
- }
-
- var newExtras = elementFinisherExtras.extras;
-
- if (newExtras) {
- for (var j = 0; j < newExtras.length; j++) {
- this.addElementPlacement(newExtras[j], placements);
- }
-
- extras.push.apply(extras, newExtras);
- }
- }
-
- return {
- element: element,
- finishers: finishers,
- extras: extras
- };
- },
- decorateConstructor: function (elements, decorators) {
- var finishers = [];
-
- for (var i = decorators.length - 1; i >= 0; i--) {
- var obj = this.fromClassDescriptor(elements);
- var elementsAndFinisher = this.toClassDescriptor((0, decorators[i])(obj) || obj);
-
- if (elementsAndFinisher.finisher !== undefined) {
- finishers.push(elementsAndFinisher.finisher);
- }
-
- if (elementsAndFinisher.elements !== undefined) {
- elements = elementsAndFinisher.elements;
-
- for (var j = 0; j < elements.length - 1; j++) {
- for (var k = j + 1; k < elements.length; k++) {
- if (elements[j].key === elements[k].key && elements[j].placement === elements[k].placement) {
- throw new TypeError("Duplicated element (" + elements[j].key + ")");
- }
- }
- }
- }
- }
-
- return {
- elements: elements,
- finishers: finishers
- };
- },
- fromElementDescriptor: function (element) {
- var obj = {
- kind: element.kind,
- key: element.key,
- placement: element.placement,
- descriptor: element.descriptor
- };
- var desc = {
- value: "Descriptor",
- configurable: true
- };
- Object.defineProperty(obj, Symbol.toStringTag, desc);
- if (element.kind === "field") obj.initializer = element.initializer;
- return obj;
- },
- toElementDescriptors: function (elementObjects) {
- if (elementObjects === undefined) return;
- return _toArray(elementObjects).map(function (elementObject) {
- var element = this.toElementDescriptor(elementObject);
- this.disallowProperty(elementObject, "finisher", "An element descriptor");
- this.disallowProperty(elementObject, "extras", "An element descriptor");
- return element;
- }, this);
- },
- toElementDescriptor: function (elementObject) {
- var kind = String(elementObject.kind);
-
- if (kind !== "method" && kind !== "field") {
- throw new TypeError('An element descriptor\'s .kind property must be either "method" or' + ' "field", but a decorator created an element descriptor with' + ' .kind "' + kind + '"');
- }
-
- var key = _toPropertyKey(elementObject.key);
-
- var placement = String(elementObject.placement);
-
- if (placement !== "static" && placement !== "prototype" && placement !== "own") {
- throw new TypeError('An element descriptor\'s .placement property must be one of "static",' + ' "prototype" or "own", but a decorator created an element descriptor' + ' with .placement "' + placement + '"');
- }
-
- var descriptor = elementObject.descriptor;
- this.disallowProperty(elementObject, "elements", "An element descriptor");
- var element = {
- kind: kind,
- key: key,
- placement: placement,
- descriptor: Object.assign({}, descriptor)
- };
-
- if (kind !== "field") {
- this.disallowProperty(elementObject, "initializer", "A method descriptor");
- } else {
- this.disallowProperty(descriptor, "get", "The property descriptor of a field descriptor");
- this.disallowProperty(descriptor, "set", "The property descriptor of a field descriptor");
- this.disallowProperty(descriptor, "value", "The property descriptor of a field descriptor");
- element.initializer = elementObject.initializer;
- }
-
- return element;
- },
- toElementFinisherExtras: function (elementObject) {
- var element = this.toElementDescriptor(elementObject);
-
- var finisher = _optionalCallableProperty(elementObject, "finisher");
-
- var extras = this.toElementDescriptors(elementObject.extras);
- return {
- element: element,
- finisher: finisher,
- extras: extras
- };
- },
- fromClassDescriptor: function (elements) {
- var obj = {
- kind: "class",
- elements: elements.map(this.fromElementDescriptor, this)
- };
- var desc = {
- value: "Descriptor",
- configurable: true
- };
- Object.defineProperty(obj, Symbol.toStringTag, desc);
- return obj;
- },
- toClassDescriptor: function (obj) {
- var kind = String(obj.kind);
-
- if (kind !== "class") {
- throw new TypeError('A class descriptor\'s .kind property must be "class", but a decorator' + ' created a class descriptor with .kind "' + kind + '"');
- }
-
- this.disallowProperty(obj, "key", "A class descriptor");
- this.disallowProperty(obj, "placement", "A class descriptor");
- this.disallowProperty(obj, "descriptor", "A class descriptor");
- this.disallowProperty(obj, "initializer", "A class descriptor");
- this.disallowProperty(obj, "extras", "A class descriptor");
-
- var finisher = _optionalCallableProperty(obj, "finisher");
-
- var elements = this.toElementDescriptors(obj.elements);
- return {
- elements: elements,
- finisher: finisher
- };
- },
- runClassFinishers: function (constructor, finishers) {
- for (var i = 0; i < finishers.length; i++) {
- var newConstructor = (0, finishers[i])(constructor);
-
- if (newConstructor !== undefined) {
- if (typeof newConstructor !== "function") {
- throw new TypeError("Finishers must return a constructor.");
- }
-
- constructor = newConstructor;
- }
- }
-
- return constructor;
- },
- disallowProperty: function (obj, name, objectType) {
- if (obj[name] !== undefined) {
- throw new TypeError(objectType + " can't have a ." + name + " property.");
- }
- }
- };
- return api;
-}
-
-function _createElementDescriptor(def) {
- var key = _toPropertyKey(def.key);
-
- var descriptor;
-
- if (def.kind === "method") {
- descriptor = {
- value: def.value,
- writable: true,
- configurable: true,
- enumerable: false
- };
- } else if (def.kind === "get") {
- descriptor = {
- get: def.value,
- configurable: true,
- enumerable: false
- };
- } else if (def.kind === "set") {
- descriptor = {
- set: def.value,
- configurable: true,
- enumerable: false
- };
- } else if (def.kind === "field") {
- descriptor = {
- configurable: true,
- writable: true,
- enumerable: true
- };
- }
-
- var element = {
- kind: def.kind === "field" ? "field" : "method",
- key: key,
- placement: def.static ? "static" : def.kind === "field" ? "own" : "prototype",
- descriptor: descriptor
- };
- if (def.decorators) element.decorators = def.decorators;
- if (def.kind === "field") element.initializer = def.value;
- return element;
-}
-
-function _coalesceGetterSetter(element, other) {
- if (element.descriptor.get !== undefined) {
- other.descriptor.get = element.descriptor.get;
- } else {
- other.descriptor.set = element.descriptor.set;
- }
-}
-
-function _coalesceClassElements(elements) {
- var newElements = [];
-
- var isSameElement = function (other) {
- return other.kind === "method" && other.key === element.key && other.placement === element.placement;
- };
-
- for (var i = 0; i < elements.length; i++) {
- var element = elements[i];
- var other;
-
- if (element.kind === "method" && (other = newElements.find(isSameElement))) {
- if (_isDataDescriptor(element.descriptor) || _isDataDescriptor(other.descriptor)) {
- if (_hasDecorators(element) || _hasDecorators(other)) {
- throw new ReferenceError("Duplicated methods (" + element.key + ") can't be decorated.");
- }
-
- other.descriptor = element.descriptor;
- } else {
- if (_hasDecorators(element)) {
- if (_hasDecorators(other)) {
- throw new ReferenceError("Decorators can't be placed on different accessors with for " + "the same property (" + element.key + ").");
- }
-
- other.decorators = element.decorators;
- }
-
- _coalesceGetterSetter(element, other);
- }
- } else {
- newElements.push(element);
- }
- }
-
- return newElements;
-}
-
-function _hasDecorators(element) {
- return element.decorators && element.decorators.length;
-}
-
-function _isDataDescriptor(desc) {
- return desc !== undefined && !(desc.value === undefined && desc.writable === undefined);
-}
-
-function _optionalCallableProperty(obj, name) {
- var value = obj[name];
-
- if (value !== undefined && typeof value !== "function") {
- throw new TypeError("Expected '" + name + "' to be a function");
- }
-
- return value;
-}
-
-const CPromise = require('../../lib/c-promise');
-
-const {
- async,
- listen,
- cancel,
- timeout,
- E_REASON_DISPOSED
-} = CPromise;
-/*
-class Test {
- //@timeout(1000)
- @listen
- @async
- *asyncTask(delay) {
- const result1= yield CPromise.delay(delay, 123);
- const result2= yield new CPromise((resolve, reject, {onCancel})=>{
- const timer= setTimeout(resolve, 1000);
- onCancel((reason)=>{
- console.log(`Cancel inner promise due ${reason}`);
- clearTimeout(timer);
- })
- })
- return result1 + 1;
- }
-
- //@timeout(1000)
- @cancel(E_REASON_DISPOSED)
- async asyncTask2(delay){
- return CPromise.delay(delay, 123);
- }
-}
-
-const test= new Test();
-
-test.asyncTask(1000)
- .then(
- value => console.log(`Done: ${value}`),
- err => console.warn(`Fail: ${err}`)
- );
-
-setTimeout(()=>{
- test.asyncTask2(1000);
-}, 1100);
-*/
-
-/*let chain;
-
-CPromise.resolve().then(()=>{
- chain= CPromise.resolve().then(()=>{
- console.log('executed1');
- }).then(()=>{
- console.log('executed2');
- })
- console.log('willUnmount');
-}).then(()=>{
- console.log('cancel');
- chain.cancel();
-})*/
-
-/*const chain2= new CPromise(resolve=>resolve(123)).label('first').then((value, scope)=> {
- console.warn('executed', value)
- //console.warn('executed', scope.isCanceled, chain2.isCanceled)
-}).label('second').catch(err=> console.warn(`Rethrow ${err}`));*/
-
-/*const chain3= new CPromise(resolve=>{
- resolve(123);
-}).then(value=> {
- console.log(`Done: ${value}`);
- //return 456;
-}, err=> console.warn(`Failed: ${err}`));
-
-chain3.cancel();*/
-//chain3.parent.reject( new Error('test'));
-
-let Test = _decorate(null, function (_initialize) {
- class Test {
- constructor() {
- _initialize(this);
- }
-
- }
-
- return {
- F: Test,
- d: [{
- kind: "method",
- decorators: [async],
- key: "asyncMethod",
- value: function* asyncMethod(x, y) {
- const z = yield CPromise.delay(1000);
- return x + y + z;
- }
- }]
- };
-});
-
-const test = new Test();
-const promise = test.asyncMethod(1, 2);
-console.log(promise instanceof CPromise); // true
-
-promise.then(value => console.log(`Done: ${value}`), err => console.warn(`Fail: ${err}`));
-setTimeout(() => promise.cancel(), 500);
diff --git a/playground/src/decorators.js b/playground/src/decorators.js
index 434e717..ba67b70 100644
--- a/playground/src/decorators.js
+++ b/playground/src/decorators.js
@@ -41,3 +41,18 @@ test.asyncTask(1000)
setTimeout(()=>{
test.asyncTask2(1000);
}, 1100);
+
+
+class Component{
+ @canceled((err)=>{
+
+ })
+ @async()
+ *test(){
+ console.log('this', this);
+ }
+}
+
+const c= new Component();
+
+c.test().then(console.log);
diff --git a/test/src/decorators.js b/test/src/decorators.js
index 02ecdb9..7236414 100644
--- a/test/src/decorators.js
+++ b/test/src/decorators.js
@@ -7,6 +7,7 @@ const {
timeout,
innerWeight,
label,
+ canceled,
CanceledError,
E_REASON_TIMEOUT
} = require('../../lib/c-promise');
@@ -119,5 +120,43 @@ module.exports = {
assert.fail('early cancellation detected');
}
})
+ },
+
+ "should support canceled decorator": async function () {
+ const time = measureTime();
+
+ let invoked = false;
+
+ const klass = class {
+ @canceled(function (err, scope, context) {
+ assert.ok(this instanceof klass);
+ assert.ok(context instanceof klass);
+ assert.ok(err instanceof CanceledError);
+ assert.ok(scope instanceof CPromise);
+ invoked = true;
+ })
+ @async
+ * generator() {
+ yield delay(1000, 123);
+ }
+ }
+
+ const obj = new klass();
+
+ const thenable = obj.generator();
+
+ setTimeout(() => {
+ thenable.cancel();
+ }, 100);
+
+ return thenable.then(() => {
+ assert.ok(invoked, 'was not canceled');
+ }, err => {
+ if(err instanceof CanceledError) {
+ assert.fail(`was not caught: ${err}`);
+ }else{
+ throw err;
+ }
+ })
}
}