Skip to content
This repository has been archived by the owner on Feb 18, 2024. It is now read-only.

Commit

Permalink
Feature: allow specifying to use before or after other use
Browse files Browse the repository at this point in the history
  • Loading branch information
eliperelman committed Oct 5, 2017
1 parent 5aec63a commit bcab25a
Show file tree
Hide file tree
Showing 14 changed files with 466 additions and 196 deletions.
175 changes: 162 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,34 +183,47 @@ has(key)

```js
// Returns an array of all the values stored in the Map.
// This will order values if before() or after() are used.
// returns: Array
values()
```

```js
// Returns an object of all the entries in the backing Map
// where the key is the object property, and the value
// corresponding to the key. Will return `undefined` if the backing
// Map is empty.
// corresponding to the key.
// Will return `undefined` if the backing Map is empty.
// This will order keys if before() or after() are used.
// returns: Object, undefined if empty
entries()
````

```js
// Provide an object which maps its properties and values
// into the backing Map as keys and values.
// into the backing Map as keys and values. Can specify
// an array of keys to omit from the merge.
// obj: Object
merge(obj)
// omit: Optional Array
merge(obj, omit)
```

```js
// Conditionally execute a function to continue configuration
// condition: Boolean
// truthyHandler: Function -> ChainedMap
// whenTruthy: Function -> ChainedMap
// invoked when condition is truthy, given a single argument of the ChainedMap instance
// falsyHandler: Function -> ChainedMap
// whenFalsy: Optional Function -> ChainedMap
// invoked when condition is falsy, given a single argument of the ChainedMap instance
when(condition, truthyHandler, falsyHandler)
when(condition, whenTruthy, whenFalsy)
```

```js
// Returns an object containing the entries of the ChainedMap,
// as well as an array containing an ordering of the keys based
// on usage of before() and after(). Used internally by webpack-chain
// to generate the output for values() and entries().
// Schema: { entries: Object, order: [String] }
order()
```

## ChainedSet
Expand Down Expand Up @@ -267,11 +280,11 @@ merge(arr)
```js
// Conditionally execute a function to continue configuration
// condition: Boolean
// truthyHandler: Function -> ChainedSet
// whenTruthy: Function -> ChainedSet
// invoked when condition is truthy, given a single argument of the ChainedSet instance
// falsyHandler: Function -> ChainedSet
// whenFalsy: Optional Function -> ChainedSet
// invoked when condition is falsy, given a single argument of the ChainedSet instance
when(condition, truthyHandler, falsyHandler)
when(condition, whenTruthy, whenFalsy)
```

## Shorthand methods
Expand Down Expand Up @@ -600,6 +613,48 @@ config
.init((Plugin, args) => new Plugin(...args));
```

#### Config plugins: ordering before

Specify that the current `plugin` context should operate before another named `plugin`.
You cannot use `before()` and `after()` on the same plugin.

```js
config
.plugin(name)
.before(otherName)
// Example
config
.plugin('html-template')
.use(HtmlWebpackTemplate)
.end()
.plugin('script-ext')
.use(ScriptExtWebpackPlugin)
.before('html-template');
```

#### Config plugins: ordering after

Specify that the current `plugin` context should operate after another named `plugin`.
You cannot use `before()` and `after()` on the same plugin.

```js
config
.plugin(name)
.after(otherName)
// Example
config
.plugin('html-template')
.after('script-ext')
.use(HtmlWebpackTemplate)
.end()
.plugin('script-ext')
.use(ScriptExtWebpackPlugin);
```

#### Config resolve plugins

```js
Expand Down Expand Up @@ -633,6 +688,48 @@ config.resolve
.init((Plugin, args) => new Plugin(...args))
```

#### Config resolve plugins: ordering before

Specify that the current `plugin` context should operate before another named `plugin`.
You cannot use `before()` and `after()` on the same plugin.

```js
config.resolve
.plugin(name)
.before(otherName)
// Example
config.resolve
.plugin('beta')
.use(BetaWebpackPlugin)
.end()
.plugin('alpha')
.use(AlphaWebpackPlugin)
.before('beta');
```

#### Config resolve plugins: ordering after

Specify that the current `plugin` context should operate after another named `plugin`.
You cannot use `before()` and `after()` on the same plugin.

```js
config.resolve
.plugin(name)
.after(otherName)
// Example
config.resolve
.plugin('beta')
.after('alpha')
.use(BetaWebpackTemplate)
.end()
.plugin('alpha')
.use(AlphaWebpackPlugin);
```

#### Config node

```js
Expand Down Expand Up @@ -750,6 +847,52 @@ config.module
.options({ presets: ['babel-preset-es2015'] });
```

#### Config module rules uses (loaders): ordering before

Specify that the current `use` context should operate before another named `use`.
You cannot use `before()` and `after()` on the same `use`.

```js
config.module
.rule(name)
.use(name)
.before(otherName)
// Example
config.module
.rule('compile')
.use('babel')
.loader('babel-loader')
.end()
.use('cache')
.loader('cache-loader')
.before('babel');
```

#### Config module rules uses (loaders): ordering after

Specify that the current `use` context should operate after another named `use`.
You cannot use `before()` and `after()` on the same `use`.

```js
config.module
.rule(name)
.use(name)
.after(otherName)
// Example
config.module
.rule('compile')
.use('babel')
.loader('babel-loader')
.after('cache')
.end()
.use('cache')
.loader('cache-loader');
```

#### Config module rules uses (loaders): modifying options

```js
Expand Down Expand Up @@ -833,7 +976,9 @@ config.merge({
plugin: {
[name]: {
plugin: WebpackPlugin,
args: [...args]
args: [...args],
before,
after
}
},
Expand Down Expand Up @@ -891,7 +1036,9 @@ config.merge({
plugin: {
[name]: {
plugin: WebpackPlugin,
args: [...args]
args: [...args],
before,
after
}
}
},
Expand Down Expand Up @@ -929,7 +1076,9 @@ config.merge({
use: {
[name]: {
loader: LoaderString,
options: LoaderOptions
options: LoaderOptions,
before,
after
}
}
}
Expand Down
96 changes: 81 additions & 15 deletions src/ChainedMap.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const Chainable = require('./Chainable');
const merge = require('deepmerge');

module.exports = class extends Chainable {
class ChainedMap extends Chainable {
constructor(parent) {
super(parent);
this.store = new Map();
Expand All @@ -23,21 +24,41 @@ module.exports = class extends Chainable {
return this;
}

entries() {
const entries = [...this.store];

if (!entries.length) {
return;
}

return entries.reduce((acc, [key, value]) => {
order() {
const entries = [...this.store].reduce((acc, [key, value]) => {
acc[key] = value;
return acc;
}, {});
const names = Object.keys(entries);
const order = [...names];

names.forEach(name => {
const { __before, __after } = entries[name];

if (__before && order.includes(__before)) {
order.splice(order.indexOf(name), 1);
order.splice(order.indexOf(__before), 0, name);
} else if (__after && order.includes(__after)) {
order.splice(order.indexOf(name), 1);
order.splice(order.indexOf(__after) + 1, 0, name);
}
});

return { entries, order };
}

values() {
return [...this.store.values()];
const { entries, order } = this.order();

return order.map(name => entries[name]);
}

entries() {
const { entries, order } = this.order();

if (order.length) {
return entries;
}
}

get(key) {
Expand All @@ -53,8 +74,23 @@ module.exports = class extends Chainable {
return this;
}

merge(obj) {
Object.keys(obj).forEach(key => this.set(key, obj[key]));
merge(obj, omit = []) {
Object
.keys(obj)
.forEach(key => {
if (omit.includes(key)) {
return;
}

const value = obj[key];

if ((!Array.isArray(value) && typeof value !== 'object') || value === null || !this.has(key)) {
this.set(key, value);
} else {
this.set(key, merge(this.get(key), value));
}
});

return this;
}

Expand Down Expand Up @@ -82,13 +118,43 @@ module.exports = class extends Chainable {
}, {});
}

when(condition, trueBrancher = Function.prototype, falseBrancher = Function.prototype) {
when(condition, whenTruthy = Function.prototype, whenFalsy = Function.prototype) {
if (condition) {
trueBrancher(this);
whenTruthy(this);
} else {
falseBrancher(this);
whenFalsy(this);
}

return this;
}
}

ChainedMap.orderable = (Class) => class extends Class {
before(name) {
if (this.__after) {
throw new Error(`Unable to set before(${JSON.stringify(name)}) with existing value for after`);
}

this.__before = name;
return this;
}

after(name) {
if (this.__after) {
throw new Error(`Unable to set after(${JSON.stringify(name)}) with existing value for before`);
}

this.__after = name;
return this;
}

merge(obj, omit = []) {
if (obj.before && obj.after) {
throw new Error(`Unable to merge before: ${JSON.stringify(obj.before)} and after: ${JSON.stringify(obj.after)} on the same object`);
}

return super.merge(obj, [...omit, 'before', 'after']);
}
};

module.exports = ChainedMap;
Loading

0 comments on commit bcab25a

Please sign in to comment.