Skip to content
This repository has been archived by the owner on Nov 3, 2023. It is now read-only.

Commit

Permalink
Merge pull request #19 from apache-superset/kristw--new-core
Browse files Browse the repository at this point in the history
Add new core modules from incubator-superset
  • Loading branch information
kristw authored and zhaoyongjie committed Nov 26, 2021
1 parent b9391d3 commit 7097a0e
Show file tree
Hide file tree
Showing 18 changed files with 720 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## @superset-ui/core

[![Version](https://img.shields.io/npm/v/@superset-ui/core.svg?style=flat)](https://img.shields.io/npm/v/@superset-ui/core.svg?style=flat)
[![David (path)](https://img.shields.io/david/apache-superset/superset-ui.svg?path=packages%2Fsuperset-ui-core&style=flat-square)](https://david-dm.org/apache-superset/superset-ui?path=packages/superset-ui-core)

Description

#### Example usage

```js
import { xxx } from '@superset-ui/core';
```

#### API

`fn(args)`

- TBD

### Development

`@data-ui/build-config` is used to manage the build configuration for this package including babel
builds, jest testing, eslint, and prettier.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "@superset-ui/core",
"version": "0.2.0",
"description": "Superset UI core",
"sideEffects": false,
"main": "lib/index.js",
"module": "esm/index.js",
"files": [
"esm",
"lib"
],
"repository": {
"type": "git",
"url": "git+https://github.com/apache-superset/superset-ui.git"
},
"keywords": [
"superset"
],
"author": "Superset",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/apache-superset/superset-ui/issues"
},
"homepage": "https://github.com/apache-superset/superset-ui#readme",
"publishConfig": {
"access": "public"
},
"dependencies": {
"lodash": "^4.17.11"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export { default as Plugin } from './models/Plugin';
export { default as Preset } from './models/Preset';
export { default as Registry } from './models/Registry';

export { default as convertKeysToCamelCase } from './utils/convertKeysToCamelCase';
export { default as isDefined } from './utils/isDefined';
export { default as isRequired } from './utils/isRequired';
export { default as makeSingleton } from './utils/makeSingleton';
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export default class Plugin {
constructor() {
this.resetConfig();
}

resetConfig() {
// The child class can set default config
// by overriding this function.
this.config = {};

return this;
}

configure(config, replace = false) {
if (replace) {
this.config = config;
} else {
this.config = { ...this.config, ...config };
}

return this;
}

register() {
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export default class Preset {
constructor({ name = '', description = '', presets = [], plugins = [] } = {}) {
this.name = name;
this.description = description;
this.presets = presets;
this.plugins = plugins;
}

register() {
this.presets.forEach(preset => {
preset.register();
});
this.plugins.forEach(plugin => {
plugin.register();
});

return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
export default class Registry {
constructor(name = '') {
this.name = name;
this.items = {};
this.promises = {};
}

clear() {
this.items = {};
this.promises = {};

return this;
}

has(key) {
const item = this.items[key];

return item !== null && item !== undefined;
}

registerValue(key, value) {
const item = this.items[key];
if (!item || item.value !== value) {
this.items[key] = { value };
delete this.promises[key];
}

return this;
}

registerLoader(key, loader) {
const item = this.items[key];
if (!item || item.loader !== loader) {
this.items[key] = { loader };
delete this.promises[key];
}

return this;
}

get(key) {
const item = this.items[key];
if (item) {
return item.loader ? item.loader() : item.value;
}

return null;
}

getAsPromise(key) {
const promise = this.promises[key];
if (promise) {
return promise;
}
const item = this.get(key);
if (item) {
const newPromise = Promise.resolve(item);
this.promises[key] = newPromise;

return newPromise;
}

return Promise.reject(new Error(`Item with key "${key}" is not registered.`));
}

getMap() {
return this.keys().reduce((prev, key) => {
const map = prev;
map[key] = this.get(key);

return map;
}, {});
}

getMapAsPromise() {
const keys = this.keys();

return Promise.all(keys.map(key => this.getAsPromise(key))).then(values =>
values.reduce((prev, value, i) => {
const map = prev;
map[keys[i]] = value;

return map;
}, {}),
);
}

keys() {
return Object.keys(this.items);
}

values() {
return this.keys().map(key => this.get(key));
}

valuesAsPromise() {
return Promise.all(this.keys().map(key => this.getAsPromise(key)));
}

entries() {
return this.keys().map(key => ({
key,
value: this.get(key),
}));
}

entriesAsPromise() {
const keys = this.keys();

return Promise.all(keys.map(key => this.getAsPromise(key))).then(values =>
values.map((value, i) => ({
key: keys[i],
value,
})),
);
}

remove(key) {
delete this.items[key];
delete this.promises[key];

return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import camelCase from 'lodash/fp/camelCase';
import isPlainObject from 'lodash/fp/isPlainObject';
import mapKeys from 'lodash/fp/mapKeys';

export default function convertKeysToCamelCase(object) {
if (object === null || object === undefined) {
return object;
}
if (isPlainObject(object)) {
return mapKeys(k => camelCase(k), object);
}
throw new Error(`Cannot convert input that is not a plain object: ${object}`);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function isDefined(x) {
return x !== null && x !== undefined;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function isRequired(field) {
throw new Error(`${field} is required.`);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default function makeSingleton(BaseClass, ...args) {
let singleton;

return function getInstance() {
if (!singleton) {
singleton = new BaseClass(...args);
}

return singleton;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
describe('My Test', () => {
it('tests something', () => {
expect(1).toEqual(1);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import Plugin from '../../src/models/Plugin';

describe('Plugin', () => {
it('exists', () => {
expect(Plugin).toBeDefined();
});

describe('new Plugin()', () => {
it('creates a new plugin', () => {
const plugin = new Plugin();
expect(plugin).toBeInstanceOf(Plugin);
});
});

describe('.configure(config, replace)', () => {
it('extends the default config with given config when replace is not set or false', () => {
const plugin = new Plugin();
plugin.configure({ key: 'abc', foo: 'bar' });
plugin.configure({ key: 'def' });
expect(plugin.config).toEqual({ key: 'def', foo: 'bar' });
});
it('replaces the default config with given config when replace is true', () => {
const plugin = new Plugin();
plugin.configure({ key: 'abc', foo: 'bar' });
plugin.configure({ key: 'def' }, true);
expect(plugin.config).toEqual({ key: 'def' });
});
it('returns the plugin itself', () => {
const plugin = new Plugin();
expect(plugin.configure({ key: 'abc' })).toBe(plugin);
});
});

describe('.resetConfig()', () => {
it('resets config back to default', () => {
const plugin = new Plugin();
plugin.configure({ key: 'abc', foo: 'bar' });
plugin.resetConfig();
expect(plugin.config).toEqual({});
});
it('returns the plugin itself', () => {
const plugin = new Plugin();
expect(plugin.resetConfig()).toBe(plugin);
});
});

describe('.register()', () => {
it('returns the plugin itself', () => {
const plugin = new Plugin();
expect(plugin.register()).toBe(plugin);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Preset from '../../src/models/Preset';
import Plugin from '../../src/models/Plugin';

describe('Preset', () => {
it('exists', () => {
expect(Preset).toBeDefined();
});

describe('new Preset()', () => {
it('creates new preset', () => {
const preset = new Preset();
expect(preset).toBeInstanceOf(Preset);
});
});

describe('.register()', () => {
it('register all listed presets then plugins', () => {
const values = [];
class Plugin1 extends Plugin {
register() {
values.push(1);
}
}
class Plugin2 extends Plugin {
register() {
values.push(2);
}
}
class Plugin3 extends Plugin {
register() {
values.push(3);
}
}
class Plugin4 extends Plugin {
register() {
const { key } = this.config;
values.push(key);
}
}

const preset1 = new Preset({
plugins: [new Plugin1()],
});
const preset2 = new Preset({
plugins: [new Plugin2()],
});
const preset3 = new Preset({
presets: [preset1, preset2],
plugins: [new Plugin3(), new Plugin4().configure({ key: 'abc' })],
});
preset3.register();
expect(values).toEqual([1, 2, 3, 'abc']);
});

it('returns itself', () => {
const preset = new Preset();
expect(preset.register()).toBe(preset);
});
});
});
Loading

0 comments on commit 7097a0e

Please sign in to comment.