diff --git a/jquery-ajax-chain/jquery-ajax-chain-tests.ts b/jquery-ajax-chain/jquery-ajax-chain-tests.ts
new file mode 100644
index 0000000000..8a484fa633
--- /dev/null
+++ b/jquery-ajax-chain/jquery-ajax-chain-tests.ts
@@ -0,0 +1,287 @@
+///
+///
+///
+
+function test_public_methods(): void {
+
+ let ajaxChain: ajaxChain.JQueryAjaxChain,
+ configurationObj1: ajaxChain.AjaxChainConfiguration,
+ configurationObj2: ajaxChain.AjaxChainConfiguration;
+
+ configurationObj1 = {
+
+ ajaxSettings: {
+
+ type: 'GET',
+ dataType: 'xml',
+ url: '/endpoint1'
+
+ }
+
+ };
+
+ configurationObj2 = {
+
+ ajaxSettings: {
+
+ type: 'GET',
+ dataType: 'xml',
+ url: '/endpoint2'
+
+ }
+
+ };
+
+ ajaxChain.enqueue(configurationObj1);
+ ajaxChain.clearQueue();
+ ajaxChain.enqueue([configurationObj1, configurationObj2]);
+ ajaxChain.dequeue().then(doneResult => { console.log(doneResult); },
+ failResult => { console.log(failResult); },
+ progressResult => { console.log(progressResult); });
+
+}
+
+function test_optional_parameters(): void {
+
+ let itemsCollectionCache: XMLDocument = null,
+ itemDetailCacheMap: WeakMap = new WeakMap(),
+ ajaxChain: ajaxChain.JQueryAjaxChain,
+ configurationObj1: ajaxChain.AjaxChainConfiguration,
+ configurationObj2: ajaxChain.AjaxChainConfiguration,
+ configurationObj3: ajaxChain.AjaxChainConfiguration,
+ configurationObj4: ajaxChain.AjaxChainConfiguration;
+
+ ajaxChain = new $.AjaxChain();
+
+ configurationObj1 = {
+
+ ajaxSettings: {
+
+ type: 'GET',
+ dataType: 'xml',
+ url: '/items',
+ success: function (xmlResponse): void {
+
+ itemsCollectionCache = xmlResponse;
+
+ },
+
+ },
+
+ hasHaltingCapabilities: function (xmlResponse): Boolean {
+
+ let $tempXmlResponse: JQuery;
+
+ $tempXmlResponse = $(xmlResponse);
+
+ if (!$tempXmlResponse.find('item').length) {
+
+ return true;
+
+ }
+
+ return false;
+
+ },
+
+ hasCache: function (xmlResponse): XMLDocument {
+
+ if (itemsCollectionCache) {
+
+ return itemsCollectionCache;
+
+ };
+
+ return null;
+ },
+
+ transform: function (xmlResponse): Object {
+
+ let $tempXmlResponse: JQuery,
+ $tempItems: JQuery,
+ nextCallDataObj: Object;
+
+ $tempXmlResponse = $(xmlResponse);
+ $tempItems = $tempXmlResponse.find('item');
+
+ if ($tempItems.length) {
+
+ nextCallDataObj = {
+
+ id: $tempItems.first()
+ .attr('id')
+
+ };
+
+ return nextCallDataObj;
+
+ }
+
+ return null;
+
+ }
+
+ };
+
+ configurationObj2 = {
+
+ ajaxSettings: {
+
+ type: 'GET',
+ dataType: 'xml',
+ url: '/item',
+ success: function (xmlResponse): void {
+
+ let $tempXmlResponse: JQuery,
+ itemId: String;
+
+ $tempXmlResponse = $(xmlResponse);
+
+ itemId = $tempXmlResponse.find('id')
+ .text();
+
+ if (itemId && !itemDetailCacheMap.has(itemId)) {
+
+ itemDetailCacheMap.set(itemId, xmlResponse);
+
+ }
+
+ }
+
+ },
+
+ transform: function (xmlResponse): String {
+
+ let $tempXmlResponse: JQuery,
+ tempTrackingCode: String,
+ nextCallDataStr: String = "";
+
+ $tempXmlResponse = $(xmlResponse);
+
+ tempTrackingCode = $tempXmlResponse.find('code')
+ .text();
+
+ if (tempTrackingCode) {
+
+ nextCallDataStr = "tracking=" + tempTrackingCode;
+
+ }
+
+ return nextCallDataStr;
+
+ },
+
+ hasCache: function (xmlResponse): XMLDocument {
+
+ let $tempXmlResponse: JQuery,
+ itemId: String;
+
+ $tempXmlResponse = $(xmlResponse);
+
+ itemId = $tempXmlResponse.find('id')
+ .text();
+
+ if (itemDetailCacheMap.has(itemId)) {
+
+ return itemDetailCacheMap.get(itemId);
+
+ }
+
+ return null;
+
+ },
+
+ hasErrors: function (xmlResponse): String {
+
+ var $tempXmlResponse: JQuery,
+ categoryFilter: string = '1';
+
+ $tempXmlResponse = $(xmlResponse);
+
+ if ($tempXmlResponse.find('categoryId')
+ .text() === categoryFilter) {
+
+ return '[Exception] forbidden category id: ' + categoryFilter;
+
+ }
+
+ return '';
+
+ },
+
+ appendToUrl: function (xmlResponse): String {
+
+ let $tempXmlResponse: JQuery,
+ categoryId: string = '';
+
+ $tempXmlResponse = $(xmlResponse);
+ categoryId = $tempXmlResponse.find('categoryId')
+ .text();
+
+ return (categoryId) ? ('/' + categoryId) : '';
+
+ }
+
+ };
+
+ configurationObj3 = {
+
+ ajaxSettings: {
+
+ type: 'GET',
+ dataType: 'xml',
+ url: '/categories'
+
+ },
+
+ isSkippable: function (xmlResponse): Boolean {
+
+ return true;
+
+ },
+
+ transform: function (xmlResponse): Object[] {
+
+ let $tempXmlResponse: JQuery,
+ nextCallDataArr: Object[] = [];
+
+ $tempXmlResponse = $(xmlResponse);
+
+ $tempXmlResponse.find('subCategory').each(function (index, node) {
+
+ let $tempIdNode = $(node).find('id');
+
+ nextCallDataArr.push({
+
+ name: $tempIdNode.attr('name'),
+ value: $tempIdNode.text()
+
+ });
+
+ });
+
+ return nextCallDataArr;
+
+ }
+
+ };
+
+ configurationObj4 = {
+
+ ajaxSettings: {
+
+ type: 'GET',
+ dataType: 'xml',
+ url: '/subcategories'
+
+ }
+
+ };
+
+ ajaxChain.enqueue([configurationObj1, configurationObj2, configurationObj3, configurationObj4])
+ .dequeue()
+ .then(doneResult => { console.log(doneResult); },
+ failResult => { console.log(failResult); },
+ progressResult => { console.log(progressResult); });
+
+}
diff --git a/jquery-ajax-chain/jquery-ajax-chain.d.ts b/jquery-ajax-chain/jquery-ajax-chain.d.ts
new file mode 100644
index 0000000000..3d67e3742b
--- /dev/null
+++ b/jquery-ajax-chain/jquery-ajax-chain.d.ts
@@ -0,0 +1,97 @@
+// Type definitions for jquery-ajax-chain v 1.0.4
+// Project: https://github.com/humana-fragilitas/jQuery-Ajax-Chain/
+// Definitions by: Andrea Blasio
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+///
+
+declare module ajaxChain {
+
+ /**
+ * Static members of JQueryAjaxChain
+ */
+ interface JQueryAjaxChainStatic {
+
+ new (): JQueryAjaxChain
+
+ }
+
+ /**
+ * Instance members of JQueryAjaxChain
+ */
+ interface JQueryAjaxChain extends JQueryPromise {
+
+ /**
+ * Enqueues one or more configuration objects for later processing.
+ */
+ enqueue(confObj: AjaxChainConfiguration | AjaxChainConfiguration[]): JQueryAjaxChain;
+ /**
+ * Sequentially and synchronously dequeues the configuration objects enqueued via enqueue() method
+ * in the order they were added, triggering the related Ajax calls.
+ */
+ dequeue(): JQueryAjaxChain;
+ /**
+ * Clears the currently queued configuration objects.
+ */
+ clearQueue(): JQueryAjaxChain;
+
+ }
+
+ /**
+ * A set of key/value pairs that configure the AjaxChain request; 'ajaxSettings' is mandatory.
+ */
+ interface AjaxChainConfiguration {
+
+ /**
+ * jQuery $.ajax method settings (required).
+ */
+ ajaxSettings: JQueryAjaxSettings;
+ /**
+ * Configuration object label (optional).
+ */
+ label?: String;
+ /**
+ * Returning a truthy value (Object) allows to arbitrarily overwrite the next queued Ajax call
+ * 'data' property value specified in the original jQuery $.ajax method configuration
+ * object ('ajaxSettings') (optional).
+ */
+ transform?: (response: any) => String | Object | Object[];
+ /**
+ * Returning a truthy value (String) allows to append a string to the next queued
+ * Ajax call 'url' property value specified in original jQuery $.ajax method configuration
+ * object ('ajaxSettings') (optional).
+ */
+ appendToUrl?: (response: any) => String;
+ /**
+ * Returning a truthy value determines any registered fail callback(s) to be called immediately,
+ * passing the former as an argument to the latter; the queue is then rejected (optional).
+ */
+ hasErrors?: (response: any) => any;
+ /**
+ * Returning a truthy value allows to prevent the related Ajax call from being executed,
+ * passing the former as a parameter to any registered handler(s); useful to create
+ * caching mechanisms (optional).
+ */
+ hasCache?: (response: any) => any;
+ /**
+ * Returning a truthy value prevents the queue from further progressing to the succeeding
+ * Ajax calls; the queue is then resolved (optional).
+ */
+ hasHaltingCapabilities?: (response: any) => Boolean;
+ /**
+ * Returning a truthy value prevents the queue from being halted in case of Ajax error (optional).
+ */
+ isSkippable?: (response: any) => Boolean;
+
+ }
+
+}
+
+interface JQueryStatic {
+
+ /**
+ * JQueryAjaxChain constructor
+ */
+ AjaxChain: ajaxChain.JQueryAjaxChainStatic;
+
+}
\ No newline at end of file