chore: remove LionSingleton
This commit is contained in:
parent
d5517f2dee
commit
9ecab4d5b2
16 changed files with 70 additions and 243 deletions
9
.changeset/silver-rice-applaud.md
Normal file
9
.changeset/silver-rice-applaud.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
'@lion/ajax': minor
|
||||||
|
'@lion/core': minor
|
||||||
|
'@lion/icon': minor
|
||||||
|
'@lion/localize': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Removing LionSingleton as es modules are already guaranteed to be singletons.
|
||||||
|
This reduces complexity and means less code to ship to our users.
|
||||||
|
|
@ -91,7 +91,7 @@ This prefix should be stripped before parsing the string as JSON.
|
||||||
Pass the prefix with the `jsonPrefix` option.
|
Pass the prefix with the `jsonPrefix` option.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const myAjax = AjaxClass.getNewInstance({ jsonPrefix: ")]}'," });
|
const myAjax = new AjaxClass({ jsonPrefix: ")]}'," });
|
||||||
myAjax
|
myAjax
|
||||||
.get('./packages/ajax/docs/assets/data.json')
|
.get('./packages/ajax/docs/assets/data.json')
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
|
@ -110,7 +110,7 @@ Add additional headers to the requests with the `headers` option.
|
||||||
export const additionalHeaders = () => html`
|
export const additionalHeaders = () => html`
|
||||||
<button
|
<button
|
||||||
@click=${() => {
|
@click=${() => {
|
||||||
const myAjax = AjaxClass.getNewInstance({ headers: { 'MY-HEADER': 'SOME-HEADER-VALUE' } });
|
const myAjax = new AjaxClass({ headers: { 'MY-HEADER': 'SOME-HEADER-VALUE' } });
|
||||||
myAjax
|
myAjax
|
||||||
.get('./packages/ajax/docs/assets/data.json')
|
.get('./packages/ajax/docs/assets/data.json')
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
|
@ -136,7 +136,7 @@ It is possible to make an Ajax request cancelable, and then call `cancel()` to m
|
||||||
export const cancelableRequests = () => html`
|
export const cancelableRequests = () => html`
|
||||||
<button
|
<button
|
||||||
@click=${() => {
|
@click=${() => {
|
||||||
const myAjax = AjaxClass.getNewInstance({ cancelable: true });
|
const myAjax = new AjaxClass({ cancelable: true });
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
myAjax.cancel('too slow');
|
myAjax.cancel('too slow');
|
||||||
});
|
});
|
||||||
|
|
@ -163,7 +163,7 @@ You can cancel concurrent requests with the `cancelPreviousOnNewRequest` option.
|
||||||
export const cancelConcurrentRequests = () => html`
|
export const cancelConcurrentRequests = () => html`
|
||||||
<button
|
<button
|
||||||
@click=${() => {
|
@click=${() => {
|
||||||
const myAjax = AjaxClass.getNewInstance({ cancelPreviousOnNewRequest: true });
|
const myAjax = new AjaxClass({ cancelPreviousOnNewRequest: true });
|
||||||
myAjax
|
myAjax
|
||||||
.get('./packages/ajax/docs/assets/data.json')
|
.get('./packages/ajax/docs/assets/data.json')
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { axios } from '@bundled-es-modules/axios';
|
import { axios } from '@bundled-es-modules/axios';
|
||||||
import { LionSingleton } from '@lion/core';
|
|
||||||
import {
|
import {
|
||||||
cancelInterceptorFactory,
|
cancelInterceptorFactory,
|
||||||
cancelPreviousOnNewRequestInterceptorFactory,
|
cancelPreviousOnNewRequestInterceptorFactory,
|
||||||
|
|
@ -11,7 +10,7 @@ import { jsonPrefixTransformerFactory } from './transformers.js';
|
||||||
* `AjaxClass` creates the singleton instance {@link:ajax}. It is a promise based system for
|
* `AjaxClass` creates the singleton instance {@link:ajax}. It is a promise based system for
|
||||||
* fetching data, based on [axios](https://github.com/axios/axios).
|
* fetching data, based on [axios](https://github.com/axios/axios).
|
||||||
*/
|
*/
|
||||||
export class AjaxClass extends LionSingleton {
|
export class AjaxClass {
|
||||||
/**
|
/**
|
||||||
* @property {Object} proxy the axios instance that is bound to the AjaxClass instance
|
* @property {Object} proxy the axios instance that is bound to the AjaxClass instance
|
||||||
*/
|
*/
|
||||||
|
|
@ -28,8 +27,6 @@ export class AjaxClass extends LionSingleton {
|
||||||
* @param {string} config.cancelPreviousOnNewRequest prevents concurrent requests
|
* @param {string} config.cancelPreviousOnNewRequest prevents concurrent requests
|
||||||
*/
|
*/
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
super();
|
|
||||||
|
|
||||||
this.__config = {
|
this.__config = {
|
||||||
lang: document.documentElement.getAttribute('lang'),
|
lang: document.documentElement.getAttribute('lang'),
|
||||||
languageHeader: true,
|
languageHeader: true,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { AjaxClass } from './AjaxClass.js';
|
||||||
/**
|
/**
|
||||||
* @typedef {ajax} ajax the global instance for handling all ajax requests
|
* @typedef {ajax} ajax the global instance for handling all ajax requests
|
||||||
*/
|
*/
|
||||||
export let ajax = singletonManager.get('@lion/ajax::ajax::0.3.x') || AjaxClass.getInstance(); // eslint-disable-line import/no-mutable-exports
|
export let ajax = singletonManager.get('@lion/ajax::ajax::0.3.x') || new AjaxClass(); // eslint-disable-line import/no-mutable-exports
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* setAjax allows the Application Developer to override the globally used instance of {@link:ajax}.
|
* setAjax allows the Application Developer to override the globally used instance of {@link:ajax}.
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,10 @@ import { AjaxClass } from '../src/AjaxClass.js';
|
||||||
describe('AjaxClass interceptors', () => {
|
describe('AjaxClass interceptors', () => {
|
||||||
let server;
|
let server;
|
||||||
|
|
||||||
|
function getInstance(cfg) {
|
||||||
|
return new AjaxClass(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
server = sinon.fakeServer.create({ autoRespond: true });
|
server = sinon.fakeServer.create({ autoRespond: true });
|
||||||
});
|
});
|
||||||
|
|
@ -24,8 +28,8 @@ describe('AjaxClass interceptors', () => {
|
||||||
this[type] = [...this[type], myInterceptor];
|
this[type] = [...this[type], myInterceptor];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const ajaxWithout = AjaxClass.getNewInstance();
|
const ajaxWithout = getInstance();
|
||||||
const ajaxWith = MyApi.getNewInstance();
|
const ajaxWith = new MyApi();
|
||||||
expect(ajaxWithout[type]).to.not.include(myInterceptor);
|
expect(ajaxWithout[type]).to.not.include(myInterceptor);
|
||||||
expect(ajaxWith[type]).to.include(myInterceptor);
|
expect(ajaxWith[type]).to.include(myInterceptor);
|
||||||
});
|
});
|
||||||
|
|
@ -34,8 +38,8 @@ describe('AjaxClass interceptors', () => {
|
||||||
it('can be added per instance without changing the class', () => {
|
it('can be added per instance without changing the class', () => {
|
||||||
['requestInterceptors', 'responseInterceptors'].forEach(type => {
|
['requestInterceptors', 'responseInterceptors'].forEach(type => {
|
||||||
const myInterceptor = () => {};
|
const myInterceptor = () => {};
|
||||||
const ajaxWithout = AjaxClass.getNewInstance();
|
const ajaxWithout = getInstance();
|
||||||
const ajaxWith = AjaxClass.getNewInstance();
|
const ajaxWith = getInstance();
|
||||||
ajaxWith[type].push(myInterceptor);
|
ajaxWith[type].push(myInterceptor);
|
||||||
expect(ajaxWithout[type]).to.not.include(myInterceptor);
|
expect(ajaxWithout[type]).to.not.include(myInterceptor);
|
||||||
expect(ajaxWith[type]).to.include(myInterceptor);
|
expect(ajaxWith[type]).to.include(myInterceptor);
|
||||||
|
|
@ -53,7 +57,7 @@ describe('AjaxClass interceptors', () => {
|
||||||
|
|
||||||
const myInterceptor = sinon.spy(foo => foo);
|
const myInterceptor = sinon.spy(foo => foo);
|
||||||
|
|
||||||
const ajax = AjaxClass.getNewInstance();
|
const ajax = getInstance();
|
||||||
|
|
||||||
ajax[type].push(myInterceptor);
|
ajax[type].push(myInterceptor);
|
||||||
await ajax.get('data.json');
|
await ajax.get('data.json');
|
||||||
|
|
@ -68,7 +72,7 @@ describe('AjaxClass interceptors', () => {
|
||||||
|
|
||||||
it('has access to provided instance config(options) on requestInterceptors', async () => {
|
it('has access to provided instance config(options) on requestInterceptors', async () => {
|
||||||
server.respondWith('GET', 'data.json', [200, { 'Content-Type': 'application/json' }, '{}']);
|
server.respondWith('GET', 'data.json', [200, { 'Content-Type': 'application/json' }, '{}']);
|
||||||
const ajax = AjaxClass.getNewInstance();
|
const ajax = getInstance();
|
||||||
ajax.options.myCustomValue = 'foo';
|
ajax.options.myCustomValue = 'foo';
|
||||||
let customValueAccess = false;
|
let customValueAccess = false;
|
||||||
const myInterceptor = config => {
|
const myInterceptor = config => {
|
||||||
|
|
@ -94,7 +98,7 @@ describe('AjaxClass interceptors', () => {
|
||||||
'{ "method": "put" }',
|
'{ "method": "put" }',
|
||||||
]);
|
]);
|
||||||
const enforcePutInterceptor = config => ({ ...config, method: 'PUT' });
|
const enforcePutInterceptor = config => ({ ...config, method: 'PUT' });
|
||||||
const myAjax = AjaxClass.getNewInstance();
|
const myAjax = getInstance();
|
||||||
myAjax.requestInterceptors.push(enforcePutInterceptor);
|
myAjax.requestInterceptors.push(enforcePutInterceptor);
|
||||||
const response = await myAjax.post('data.json');
|
const response = await myAjax.post('data.json');
|
||||||
expect(response.data).to.deep.equal({ method: 'put' });
|
expect(response.data).to.deep.equal({ method: 'put' });
|
||||||
|
|
@ -112,7 +116,7 @@ describe('AjaxClass interceptors', () => {
|
||||||
...response,
|
...response,
|
||||||
data: { ...response.data, foo: 'bar' },
|
data: { ...response.data, foo: 'bar' },
|
||||||
});
|
});
|
||||||
const myAjax = AjaxClass.getNewInstance();
|
const myAjax = getInstance();
|
||||||
myAjax.responseInterceptors.push(addDataInterceptor);
|
myAjax.responseInterceptors.push(addDataInterceptor);
|
||||||
const response = await myAjax.get('data.json');
|
const response = await myAjax.get('data.json');
|
||||||
expect(response.data).to.deep.equal({ method: 'get', foo: 'bar' });
|
expect(response.data).to.deep.equal({ method: 'get', foo: 'bar' });
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,10 @@ import { ajax } from '../src/ajax.js';
|
||||||
describe('AjaxClass', () => {
|
describe('AjaxClass', () => {
|
||||||
let server;
|
let server;
|
||||||
|
|
||||||
|
function getInstance(cfg) {
|
||||||
|
return new AjaxClass(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
server = sinon.fakeServer.create({ autoRespond: true });
|
server = sinon.fakeServer.create({ autoRespond: true });
|
||||||
});
|
});
|
||||||
|
|
@ -16,16 +20,16 @@ describe('AjaxClass', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets content type json if passed an object', async () => {
|
it('sets content type json if passed an object', async () => {
|
||||||
const myAjax = AjaxClass.getNewInstance();
|
const myAjax = getInstance();
|
||||||
server.respondWith('POST', /\/api\/foo/, [200, { 'Content-Type': 'application/json' }, '']);
|
server.respondWith('POST', /\/api\/foo/, [200, { 'Content-Type': 'application/json' }, '']);
|
||||||
await myAjax.post('/api/foo', { a: 1, b: 2 });
|
await myAjax.post('/api/foo', { a: 1, b: 2 });
|
||||||
expect(server.requests[0].requestHeaders['Content-Type']).to.include('application/json');
|
expect(server.requests[0].requestHeaders['Content-Type']).to.include('application/json');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('AjaxClass.getNewInstance({ jsonPrefix: "%prefix%" })', () => {
|
describe('AjaxClass({ jsonPrefix: "%prefix%" })', () => {
|
||||||
it('adds new transformer to responseDataTransformers', () => {
|
it('adds new transformer to responseDataTransformers', () => {
|
||||||
const myAjaxWithout = AjaxClass.getNewInstance({ jsonPrefix: '' });
|
const myAjaxWithout = getInstance({ jsonPrefix: '' });
|
||||||
const myAjaxWith = AjaxClass.getNewInstance({ jsonPrefix: 'prefix' });
|
const myAjaxWith = getInstance({ jsonPrefix: 'prefix' });
|
||||||
const lengthWithout = myAjaxWithout.responseDataTransformers.length;
|
const lengthWithout = myAjaxWithout.responseDataTransformers.length;
|
||||||
const lengthWith = myAjaxWith.responseDataTransformers.length;
|
const lengthWith = myAjaxWith.responseDataTransformers.length;
|
||||||
expect(lengthWith - lengthWithout).to.eql(1);
|
expect(lengthWith - lengthWithout).to.eql(1);
|
||||||
|
|
@ -38,7 +42,7 @@ describe('AjaxClass', () => {
|
||||||
'for(;;);{"success":true}',
|
'for(;;);{"success":true}',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const myAjax = AjaxClass.getNewInstance({ jsonPrefix: 'for(;;);' });
|
const myAjax = getInstance({ jsonPrefix: 'for(;;);' });
|
||||||
const response = await myAjax.get('data.json');
|
const response = await myAjax.get('data.json');
|
||||||
expect(response.status).to.equal(200);
|
expect(response.status).to.equal(200);
|
||||||
expect(response.data.success).to.equal(true);
|
expect(response.data.success).to.equal(true);
|
||||||
|
|
@ -47,24 +51,24 @@ describe('AjaxClass', () => {
|
||||||
it('works with non-JSON responses', async () => {
|
it('works with non-JSON responses', async () => {
|
||||||
server.respondWith('GET', 'data.txt', [200, { 'Content-Type': 'text/plain' }, 'some text']);
|
server.respondWith('GET', 'data.txt', [200, { 'Content-Type': 'text/plain' }, 'some text']);
|
||||||
|
|
||||||
const myAjax = AjaxClass.getNewInstance({ jsonPrefix: 'for(;;);' });
|
const myAjax = getInstance({ jsonPrefix: 'for(;;);' });
|
||||||
const response = await myAjax.get('data.txt');
|
const response = await myAjax.get('data.txt');
|
||||||
expect(response.status).to.equal(200);
|
expect(response.status).to.equal(200);
|
||||||
expect(response.data).to.equal('some text');
|
expect(response.data).to.equal('some text');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('AjaxClass.getNewInstance({ cancelable: true })', () => {
|
describe('AjaxClass({ cancelable: true })', () => {
|
||||||
it('adds new interceptor to requestInterceptors', () => {
|
it('adds new interceptor to requestInterceptors', () => {
|
||||||
const myAjaxWithout = AjaxClass.getNewInstance();
|
const myAjaxWithout = getInstance();
|
||||||
const myAjaxWith = AjaxClass.getNewInstance({ cancelable: true });
|
const myAjaxWith = getInstance({ cancelable: true });
|
||||||
const lengthWithout = myAjaxWithout.requestInterceptors.length;
|
const lengthWithout = myAjaxWithout.requestInterceptors.length;
|
||||||
const lengthWith = myAjaxWith.requestInterceptors.length;
|
const lengthWith = myAjaxWith.requestInterceptors.length;
|
||||||
expect(lengthWith - lengthWithout).to.eql(1);
|
expect(lengthWith - lengthWithout).to.eql(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows to cancel single running requests', async () => {
|
it('allows to cancel single running requests', async () => {
|
||||||
const myAjax = AjaxClass.getNewInstance({ cancelable: true });
|
const myAjax = getInstance({ cancelable: true });
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
myAjax.cancel('is cancelled');
|
myAjax.cancel('is cancelled');
|
||||||
|
|
@ -79,7 +83,7 @@ describe('AjaxClass', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('allows to cancel multiple running requests', async () => {
|
it('allows to cancel multiple running requests', async () => {
|
||||||
const myAjax = AjaxClass.getNewInstance({ cancelable: true });
|
const myAjax = getInstance({ cancelable: true });
|
||||||
let cancelCount = 0;
|
let cancelCount = 0;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
@ -102,7 +106,7 @@ describe('AjaxClass', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not cancel resolved requests', async () => {
|
it('does not cancel resolved requests', async () => {
|
||||||
const myAjax = AjaxClass.getNewInstance({ cancelable: true });
|
const myAjax = getInstance({ cancelable: true });
|
||||||
server.respondWith('GET', 'data.json', [
|
server.respondWith('GET', 'data.json', [
|
||||||
200,
|
200,
|
||||||
{ 'Content-Type': 'application/json' },
|
{ 'Content-Type': 'application/json' },
|
||||||
|
|
@ -119,17 +123,17 @@ describe('AjaxClass', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('AjaxClass.getNewInstance({ cancelPreviousOnNewRequest: true })', () => {
|
describe('AjaxClass({ cancelPreviousOnNewRequest: true })', () => {
|
||||||
it('adds new interceptor to requestInterceptors', () => {
|
it('adds new interceptor to requestInterceptors', () => {
|
||||||
const myAjaxWithout = AjaxClass.getNewInstance();
|
const myAjaxWithout = getInstance();
|
||||||
const myAjaxWith = AjaxClass.getNewInstance({ cancelPreviousOnNewRequest: true });
|
const myAjaxWith = getInstance({ cancelPreviousOnNewRequest: true });
|
||||||
const lengthWithout = myAjaxWithout.requestInterceptors.length;
|
const lengthWithout = myAjaxWithout.requestInterceptors.length;
|
||||||
const lengthWith = myAjaxWith.requestInterceptors.length;
|
const lengthWith = myAjaxWith.requestInterceptors.length;
|
||||||
expect(lengthWith - lengthWithout).to.eql(1);
|
expect(lengthWith - lengthWithout).to.eql(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('automatically cancels previous running request', async () => {
|
it('automatically cancels previous running request', async () => {
|
||||||
const myAjax = AjaxClass.getNewInstance({ cancelPreviousOnNewRequest: true });
|
const myAjax = getInstance({ cancelPreviousOnNewRequest: true });
|
||||||
server.respondWith('GET', 'data.json', [
|
server.respondWith('GET', 'data.json', [
|
||||||
200,
|
200,
|
||||||
{ 'Content-Type': 'application/json' },
|
{ 'Content-Type': 'application/json' },
|
||||||
|
|
@ -157,7 +161,7 @@ describe('AjaxClass', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('automatically cancels multiple previous requests to the same endpoint', async () => {
|
it('automatically cancels multiple previous requests to the same endpoint', async () => {
|
||||||
const myAjax = AjaxClass.getNewInstance({ cancelPreviousOnNewRequest: true });
|
const myAjax = getInstance({ cancelPreviousOnNewRequest: true });
|
||||||
server.respondWith('GET', 'data.json', [
|
server.respondWith('GET', 'data.json', [
|
||||||
200,
|
200,
|
||||||
{ 'Content-Type': 'application/json' },
|
{ 'Content-Type': 'application/json' },
|
||||||
|
|
@ -189,7 +193,7 @@ describe('AjaxClass', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('automatically cancels multiple previous requests to different endpoints', async () => {
|
it('automatically cancels multiple previous requests to different endpoints', async () => {
|
||||||
const myAjax = AjaxClass.getNewInstance({ cancelPreviousOnNewRequest: true });
|
const myAjax = getInstance({ cancelPreviousOnNewRequest: true });
|
||||||
server.respondWith('GET', 'data.json', [
|
server.respondWith('GET', 'data.json', [
|
||||||
200,
|
200,
|
||||||
{ 'Content-Type': 'application/json' },
|
{ 'Content-Type': 'application/json' },
|
||||||
|
|
@ -221,7 +225,7 @@ describe('AjaxClass', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not automatically cancel requests made via generic ajax', async () => {
|
it('does not automatically cancel requests made via generic ajax', async () => {
|
||||||
const myAjax = AjaxClass.getNewInstance({ cancelPreviousOnNewRequest: true });
|
const myAjax = getInstance({ cancelPreviousOnNewRequest: true });
|
||||||
server.respondWith('GET', 'data.json', [
|
server.respondWith('GET', 'data.json', [
|
||||||
200,
|
200,
|
||||||
{ 'Content-Type': 'application/json' },
|
{ 'Content-Type': 'application/json' },
|
||||||
|
|
@ -257,8 +261,8 @@ describe('AjaxClass', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not automatically cancel requests made via other instances', async () => {
|
it('does not automatically cancel requests made via other instances', async () => {
|
||||||
const myAjax1 = AjaxClass.getNewInstance({ cancelPreviousOnNewRequest: true });
|
const myAjax1 = getInstance({ cancelPreviousOnNewRequest: true });
|
||||||
const myAjax2 = AjaxClass.getNewInstance({ cancelPreviousOnNewRequest: true });
|
const myAjax2 = getInstance({ cancelPreviousOnNewRequest: true });
|
||||||
server.respondWith('GET', 'data.json', [
|
server.respondWith('GET', 'data.json', [
|
||||||
200,
|
200,
|
||||||
{ 'Content-Type': 'application/json' },
|
{ 'Content-Type': 'application/json' },
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,10 @@ import { AjaxClass } from '../src/AjaxClass.js';
|
||||||
describe('AjaxClass transformers', () => {
|
describe('AjaxClass transformers', () => {
|
||||||
let server;
|
let server;
|
||||||
|
|
||||||
|
function getInstance(cfg) {
|
||||||
|
return new AjaxClass(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
server = sinon.fakeServer.create({ autoRespond: true });
|
server = sinon.fakeServer.create({ autoRespond: true });
|
||||||
});
|
});
|
||||||
|
|
@ -24,18 +28,18 @@ describe('AjaxClass transformers', () => {
|
||||||
this[type] = [...this[type], myInterceptor];
|
this[type] = [...this[type], myInterceptor];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const ajaxWithout = AjaxClass.getNewInstance();
|
const ajaxWithout = getInstance();
|
||||||
const ajaxWith = MyApi.getNewInstance();
|
const ajaxWith = new MyApi();
|
||||||
expect(ajaxWithout[type]).to.not.include(myInterceptor);
|
expect(ajaxWithout[type]).to.not.include(myInterceptor);
|
||||||
expect(ajaxWith[type]).to.include(myInterceptor);
|
expect(ajaxWith[type]).to.include(myInterceptor);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can be added per instance withour changing the class', () => {
|
it('can be added per instance without changing the class', () => {
|
||||||
['requestDataTransformers', 'responseDataTransformers'].forEach(type => {
|
['requestDataTransformers', 'responseDataTransformers'].forEach(type => {
|
||||||
const myInterceptor = () => {};
|
const myInterceptor = () => {};
|
||||||
const ajaxWithout = AjaxClass.getNewInstance();
|
const ajaxWithout = getInstance();
|
||||||
const ajaxWith = AjaxClass.getNewInstance();
|
const ajaxWith = getInstance();
|
||||||
ajaxWith[type].push(myInterceptor);
|
ajaxWith[type].push(myInterceptor);
|
||||||
expect(ajaxWithout[type]).to.not.include(myInterceptor);
|
expect(ajaxWithout[type]).to.not.include(myInterceptor);
|
||||||
expect(ajaxWith[type]).to.include(myInterceptor);
|
expect(ajaxWith[type]).to.include(myInterceptor);
|
||||||
|
|
@ -53,7 +57,7 @@ describe('AjaxClass transformers', () => {
|
||||||
|
|
||||||
const myTransformer = sinon.spy(foo => foo);
|
const myTransformer = sinon.spy(foo => foo);
|
||||||
|
|
||||||
const ajax = AjaxClass.getNewInstance();
|
const ajax = getInstance();
|
||||||
|
|
||||||
ajax[type].push(myTransformer);
|
ajax[type].push(myTransformer);
|
||||||
await ajax.get('data.json');
|
await ajax.get('data.json');
|
||||||
|
|
@ -75,7 +79,7 @@ describe('AjaxClass transformers', () => {
|
||||||
'{ "method": "post" }',
|
'{ "method": "post" }',
|
||||||
]);
|
]);
|
||||||
const addBarTransformer = data => ({ ...data, bar: 'bar' });
|
const addBarTransformer = data => ({ ...data, bar: 'bar' });
|
||||||
const myAjax = AjaxClass.getNewInstance();
|
const myAjax = getInstance();
|
||||||
myAjax.requestDataTransformers.push(addBarTransformer);
|
myAjax.requestDataTransformers.push(addBarTransformer);
|
||||||
const response = await myAjax.post('data.json', { foo: 'foo' });
|
const response = await myAjax.post('data.json', { foo: 'foo' });
|
||||||
expect(JSON.parse(response.config.data)).to.deep.equal({
|
expect(JSON.parse(response.config.data)).to.deep.equal({
|
||||||
|
|
@ -93,7 +97,7 @@ describe('AjaxClass transformers', () => {
|
||||||
'{ "method": "get" }',
|
'{ "method": "get" }',
|
||||||
]);
|
]);
|
||||||
const addBarTransformer = data => ({ ...data, bar: 'bar' });
|
const addBarTransformer = data => ({ ...data, bar: 'bar' });
|
||||||
const myAjax = AjaxClass.getNewInstance();
|
const myAjax = getInstance();
|
||||||
myAjax.responseDataTransformers.push(addBarTransformer);
|
myAjax.responseDataTransformers.push(addBarTransformer);
|
||||||
const response = await myAjax.get('data.json');
|
const response = await myAjax.get('data.json');
|
||||||
expect(response.data).to.deep.equal({ method: 'get', bar: 'bar' });
|
expect(response.data).to.deep.equal({ method: 'get', bar: 'bar' });
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,6 @@ export { dedupeMixin } from '@open-wc/dedupe-mixin';
|
||||||
export { DelegateMixin } from './src/DelegateMixin.js';
|
export { DelegateMixin } from './src/DelegateMixin.js';
|
||||||
export { DisabledMixin } from './src/DisabledMixin.js';
|
export { DisabledMixin } from './src/DisabledMixin.js';
|
||||||
export { DisabledWithTabIndexMixin } from './src/DisabledWithTabIndexMixin.js';
|
export { DisabledWithTabIndexMixin } from './src/DisabledWithTabIndexMixin.js';
|
||||||
export { LionSingleton } from './src/LionSingleton.js';
|
|
||||||
export { SlotMixin } from './src/SlotMixin.js';
|
export { SlotMixin } from './src/SlotMixin.js';
|
||||||
export { UpdateStylesMixin } from './src/UpdateStylesMixin.js';
|
export { UpdateStylesMixin } from './src/UpdateStylesMixin.js';
|
||||||
export { browserDetection } from './src/browserDetection.js';
|
export { browserDetection } from './src/browserDetection.js';
|
||||||
|
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
/**
|
|
||||||
* 'LionSingleton' provides an instance of the given class via .getInstance(foo, bar) and will
|
|
||||||
* return the same instance if already created. It can reset its instance so a new one will be
|
|
||||||
* created via .resetInstance() and can at any time add mixins via .addInstanceMixin().
|
|
||||||
* It can provide new instances (with applied Mixins) via .getNewInstance().
|
|
||||||
*/
|
|
||||||
export class LionSingleton {
|
|
||||||
/**
|
|
||||||
* @param {function} mixin
|
|
||||||
*/
|
|
||||||
static addInstanceMixin(mixin) {
|
|
||||||
if (!this.__instanceMixins) {
|
|
||||||
/** @type {function[]} */
|
|
||||||
this.__instanceMixins = [];
|
|
||||||
}
|
|
||||||
this.__instanceMixins.push(mixin);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {...*} args
|
|
||||||
* @returns {LionSingleton}
|
|
||||||
*/
|
|
||||||
static getNewInstance(...args) {
|
|
||||||
let Klass = this;
|
|
||||||
if (Array.isArray(this.__instanceMixins)) {
|
|
||||||
this.__instanceMixins.forEach(mixin => {
|
|
||||||
Klass = mixin(Klass);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Ignoring, because it's up to the extension layer to accept arguments in its constructor
|
|
||||||
// @ts-ignore-next-line
|
|
||||||
return new Klass(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {...*} args
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
static getInstance(...args) {
|
|
||||||
if (this.__instance) {
|
|
||||||
return this.__instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.__instance = this.getNewInstance(...args);
|
|
||||||
return this.__instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
static resetInstance() {
|
|
||||||
this.__instance = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,126 +0,0 @@
|
||||||
import { expect } from '@open-wc/testing';
|
|
||||||
|
|
||||||
import { LionSingleton } from '../src/LionSingleton.js';
|
|
||||||
|
|
||||||
describe('LionSingleton', () => {
|
|
||||||
it('provides an instance of the given class via .getInstance()', async () => {
|
|
||||||
class MySingleton extends LionSingleton {}
|
|
||||||
const mySingleton = MySingleton.getInstance();
|
|
||||||
expect(mySingleton).to.be.an.instanceOf(MySingleton);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('supports parameters for .getInstance(foo, bar)', async () => {
|
|
||||||
class MySingleton extends LionSingleton {
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {string} foo
|
|
||||||
* @param {string} bar
|
|
||||||
*/
|
|
||||||
constructor(foo, bar) {
|
|
||||||
super();
|
|
||||||
this.foo = foo;
|
|
||||||
this.bar = bar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const mySingleton = MySingleton.getInstance('isFoo', 'isBar');
|
|
||||||
expect(mySingleton).to.deep.equal({
|
|
||||||
foo: 'isFoo',
|
|
||||||
bar: 'isBar',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('will return the same instance if already created', async () => {
|
|
||||||
let counter = 0;
|
|
||||||
class MySingleton extends LionSingleton {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
counter += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const mySingleton = MySingleton.getInstance();
|
|
||||||
mySingleton.foo = 'bar';
|
|
||||||
expect(mySingleton).to.deep.equal(MySingleton.getInstance());
|
|
||||||
expect(counter).to.equal(1);
|
|
||||||
expect(new MySingleton()).to.not.deep.equal(MySingleton.getInstance());
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can reset its instance so a new one will be created via .resetInstance()', async () => {
|
|
||||||
let counter = 0;
|
|
||||||
class MySingleton extends LionSingleton {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
counter += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const mySingleton = MySingleton.getInstance();
|
|
||||||
mySingleton.foo = 'bar';
|
|
||||||
expect(mySingleton.foo).to.equal('bar');
|
|
||||||
expect(counter).to.equal(1);
|
|
||||||
|
|
||||||
MySingleton.resetInstance();
|
|
||||||
const updatedSingleton = MySingleton.getInstance();
|
|
||||||
expect(updatedSingleton.foo).to.be.undefined;
|
|
||||||
expect(counter).to.equal(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can at any time add mixins via .addInstanceMixin()', () => {
|
|
||||||
// @ts-ignore because we're getting rid of LionSingleton altogether
|
|
||||||
const MyMixin = superclass =>
|
|
||||||
class extends superclass {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.myMixin = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
class MySingleton extends LionSingleton {}
|
|
||||||
|
|
||||||
MySingleton.addInstanceMixin(MyMixin);
|
|
||||||
const mySingleton = MySingleton.getInstance();
|
|
||||||
expect(mySingleton.myMixin).to.be.true;
|
|
||||||
|
|
||||||
// @ts-ignore because we're getting rid of LionSingleton altogether
|
|
||||||
const OtherMixin = superclass =>
|
|
||||||
class extends superclass {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.otherMixin = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
MySingleton.addInstanceMixin(OtherMixin);
|
|
||||||
expect(mySingleton.otherMixin).to.be.undefined;
|
|
||||||
|
|
||||||
MySingleton.resetInstance();
|
|
||||||
const updatedSingleton = MySingleton.getInstance();
|
|
||||||
expect(updatedSingleton.myMixin).to.be.true;
|
|
||||||
expect(updatedSingleton.otherMixin).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can provide new instances (with applied Mixins) via .getNewInstance()', async () => {
|
|
||||||
// @ts-ignore because we're getting rid of LionSingleton altogether
|
|
||||||
const MyMixin = superclass =>
|
|
||||||
class extends superclass {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.myMixin = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
class MySingleton extends LionSingleton {}
|
|
||||||
|
|
||||||
MySingleton.addInstanceMixin(MyMixin);
|
|
||||||
const singletonOne = MySingleton.getNewInstance();
|
|
||||||
// @ts-ignore because we're getting rid of LionSingleton altogether
|
|
||||||
singletonOne.one = true;
|
|
||||||
// @ts-ignore because we're getting rid of LionSingleton altogether
|
|
||||||
expect(singletonOne.myMixin).to.be.true;
|
|
||||||
// @ts-ignore because we're getting rid of LionSingleton altogether
|
|
||||||
expect(singletonOne.one).to.be.true;
|
|
||||||
|
|
||||||
const singletonTwo = MySingleton.getNewInstance();
|
|
||||||
// @ts-ignore because we're getting rid of LionSingleton altogether
|
|
||||||
expect(singletonTwo.myMixin).to.be.true;
|
|
||||||
// @ts-ignore because we're getting rid of LionSingleton altogether
|
|
||||||
expect(singletonTwo.one).to.be.undefined;
|
|
||||||
// @ts-ignore because we're getting rid of LionSingleton altogether
|
|
||||||
expect(singletonOne.one).to.be.true; // to be sure
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,9 +1,5 @@
|
||||||
import { LionSingleton } from '@lion/core';
|
export class IconManager {
|
||||||
|
constructor() {
|
||||||
export class IconManager extends LionSingleton {
|
|
||||||
constructor(params = {}) {
|
|
||||||
super(params);
|
|
||||||
|
|
||||||
this.__iconResolvers = new Map();
|
this.__iconResolvers = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { singletonManager } from 'singleton-manager';
|
||||||
import { IconManager } from './IconManager.js';
|
import { IconManager } from './IconManager.js';
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-mutable-exports
|
// eslint-disable-next-line import/no-mutable-exports
|
||||||
export let icons = singletonManager.get('@lion/icon::icons::0.5.x') || IconManager.getInstance();
|
export let icons = singletonManager.get('@lion/icon::icons::0.5.x') || new IconManager();
|
||||||
|
|
||||||
export function setIcons(newIcons) {
|
export function setIcons(newIcons) {
|
||||||
icons = newIcons;
|
icons = newIcons;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import MessageFormat from '@bundled-es-modules/message-format/MessageFormat.js';
|
import MessageFormat from '@bundled-es-modules/message-format/MessageFormat.js';
|
||||||
import { LionSingleton } from '@lion/core';
|
|
||||||
import isLocalizeESModule from './isLocalizeESModule.js';
|
import isLocalizeESModule from './isLocalizeESModule.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -9,10 +8,9 @@ import isLocalizeESModule from './isLocalizeESModule.js';
|
||||||
/**
|
/**
|
||||||
* `LocalizeManager` manages your translations (includes loading)
|
* `LocalizeManager` manages your translations (includes loading)
|
||||||
*/
|
*/
|
||||||
export class LocalizeManager extends LionSingleton {
|
export class LocalizeManager {
|
||||||
// eslint-disable-line no-unused-vars
|
// eslint-disable-line no-unused-vars
|
||||||
constructor({ autoLoadOnLocaleChange = false, fallbackLocale = '' } = {}) {
|
constructor({ autoLoadOnLocaleChange = false, fallbackLocale = '' } = {}) {
|
||||||
super();
|
|
||||||
this.__delegationTarget = document.createDocumentFragment();
|
this.__delegationTarget = document.createDocumentFragment();
|
||||||
this._autoLoadOnLocaleChange = !!autoLoadOnLocaleChange;
|
this._autoLoadOnLocaleChange = !!autoLoadOnLocaleChange;
|
||||||
this._fallbackLocale = fallbackLocale;
|
this._fallbackLocale = fallbackLocale;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { LocalizeManager } from './LocalizeManager.js';
|
||||||
// eslint-disable-next-line import/no-mutable-exports
|
// eslint-disable-next-line import/no-mutable-exports
|
||||||
export let localize =
|
export let localize =
|
||||||
singletonManager.get('@lion/localize::localize::0.10.x') ||
|
singletonManager.get('@lion/localize::localize::0.10.x') ||
|
||||||
LocalizeManager.getInstance({
|
new LocalizeManager({
|
||||||
autoLoadOnLocaleChange: true,
|
autoLoadOnLocaleChange: true,
|
||||||
fallbackLocale: 'en-GB',
|
fallbackLocale: 'en-GB',
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -643,8 +643,7 @@ describe('When supporting external translation tools like Google Translate', ()
|
||||||
* @returns {LocalizeManager}
|
* @returns {LocalizeManager}
|
||||||
*/
|
*/
|
||||||
function getInstance(cfg) {
|
function getInstance(cfg) {
|
||||||
LocalizeManager.resetInstance();
|
return new LocalizeManager(cfg || {});
|
||||||
return LocalizeManager.getInstance(cfg || {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import { expect } from '@open-wc/testing';
|
import { expect } from '@open-wc/testing';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
|
|
||||||
import { LionSingleton } from '@lion/core';
|
|
||||||
import { LocalizeManager } from '../src/LocalizeManager.js';
|
import { LocalizeManager } from '../src/LocalizeManager.js';
|
||||||
|
|
||||||
import { localize, setLocalize } from '../src/localize.js';
|
import { localize, setLocalize } from '../src/localize.js';
|
||||||
|
|
@ -13,10 +11,6 @@ describe('localize', () => {
|
||||||
// we test newly created instances of this class separately
|
// we test newly created instances of this class separately
|
||||||
// this allows to avoid any side effects caused by changing singleton state between tests
|
// this allows to avoid any side effects caused by changing singleton state between tests
|
||||||
|
|
||||||
it('is a singleton', () => {
|
|
||||||
expect(localize).to.be.an.instanceOf(LionSingleton);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('is an instance of LocalizeManager', () => {
|
it('is an instance of LocalizeManager', () => {
|
||||||
expect(localize).to.be.an.instanceOf(LocalizeManager);
|
expect(localize).to.be.an.instanceOf(LocalizeManager);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue