Skip to content

Commit 09da5bb

Browse files
committed
export the keys of plain objects as named exports
this is in addition to exporting the object itself as "default", "default_1" etc. e.g.: const props = { foo, bar } module.exports = props is processed as: const props = { foo, bar } module.exports.foo = foo module.exports.bar = bar module.exports.default = props
1 parent 391f0af commit 09da5bb

File tree

8 files changed

+134
-87
lines changed

8 files changed

+134
-87
lines changed

Diff for: .editorconfig

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# http://EditorConfig.org
1+
# https://EditorConfig.org
22

33
# is this the topmost EditorConfig file?
44
root = true

Diff for: CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
**0.1.0** - TBD
2+
3+
- export the keys of plain objects as named exports, in addition to exporting
4+
the object itself as "default", "default_1" etc.
5+
16
**0.0.2** - 2020-04-26
27

38
- add missing documentation

Diff for: README.md

+19-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# UnCommonJS
22

3-
[![Build Status](https://secure.travis-ci.org/chocolateboy/uncommonjs.svg)](https://travis-ci.org/chocolateboy/uncommonjs)
3+
[![Build Status](https://travis-ci.org/chocolateboy/uncommonjs.svg)](https://travis-ci.org/chocolateboy/uncommonjs)
44
[![NPM Version](https://img.shields.io/npm/v/@chocolateboy/uncommonjs.svg)](https://www.npmjs.org/package/@chocolateboy/uncommonjs)
55

66
<!-- toc -->
@@ -36,7 +36,7 @@ UnCommonJS - a minimum viable shim for `module.exports`
3636
- `module.exports`
3737
- `exports`
3838
- `require` (just for diagnostics - raises an exception if called)
39-
- tiny (&lt; 500 B minified)
39+
- tiny (~600 B minified)
4040
- no dependencies
4141
- suitable for userscripts
4242

@@ -167,6 +167,23 @@ assigned the name `default`. As with named exports, duplicate default exports
167167
are assigned distinct names by appending a numeric suffix, e.g. `default`,
168168
`default_1`, `default_2` etc.
169169

170+
If a plain object is assigned to `module.exports`, its properties are assigned
171+
by name (the object's own, enumerable string keys) in addition to the default
172+
export, e.g.:
173+
174+
```javascript
175+
const props = { foo, bar }
176+
module.exports = props
177+
```
178+
179+
is equivalent to:
180+
181+
```javascript
182+
module.exports.foo = foo
183+
module.exports.bar = bar
184+
module.exports.default = props
185+
```
186+
170187
## exports
171188

172189
This is an alias for `module.exports`.

Diff for: index.js

+32-19
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
(function () {
2-
const uniqueName = function () {
3-
const names = {}
4-
5-
return function (name) {
6-
let nextIndex = names[name]
7-
8-
if (nextIndex) {
9-
names[name] += 1
10-
return `${name}_${nextIndex}`
11-
} else {
12-
names[name] = 1
13-
return name
14-
}
2+
const names = {}
3+
const toString = {}.toString
4+
5+
const uniqueName = function (name) {
6+
let nextIndex = names[name]
7+
8+
if (nextIndex) {
9+
names[name] += 1
10+
return `${name}_${nextIndex}`
11+
} else {
12+
names[name] = 1
13+
return name
1514
}
16-
}()
15+
}
1716

1817
const $exports = new Proxy({}, {
1918
set (target, name, value) {
@@ -28,12 +27,26 @@
2827
},
2928

3029
set exports (value) {
31-
let key
30+
// if the value is a plain object, export each of its keys as a
31+
// named export (in addition to exporting the object itself as
32+
// "default", "default_1" etc.)
33+
if (toString.call(value) === '[object Object]') {
34+
// since this is a convenience and the full object is still
35+
// available as a fallback, we can afford to be strict in what
36+
// we support/export here, namely: a) only string keys (i.e. not
37+
// symbols) and b) only (own) enumerable properties
38+
const keys = Object.keys(value)
39+
40+
for (let i = 0; i < keys.length; ++i) {
41+
const key = keys[i]
42+
$exports[key] = value[key]
43+
}
44+
}
45+
46+
let key = 'default'
3247

33-
if (typeof value === 'function' && value.name) {
34-
key = value.name
35-
} else {
36-
key = 'default'
48+
if (typeof value === 'function') {
49+
key = value.name || key
3750
}
3851

3952
$exports[key] = value

Diff for: index.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
"index.min.js"
2020
],
2121
"devDependencies": {
22-
"ava": "^3.7.1",
22+
"ava": "^3.8.1",
2323
"npm-run-all": "^4.1.5",
24-
"terser": "^4.6.12"
24+
"terser": "^4.6.13"
2525
},
2626
"keywords": [
2727
"adapter",

Diff for: test.js

+15-25
Original file line numberDiff line numberDiff line change
@@ -28,28 +28,29 @@ test('single export', t => {
2828
t.deepEqual(module.exports, { foo })
2929
})
3030

31-
test('multiple named exports, different names', t => {
31+
test('multiple named exports (different names)', t => {
3232
module.exports.foo = foo
3333
module.exports.bar = bar
3434
t.deepEqual(module.exports, { foo, bar })
3535
})
3636

37-
test('multiple named exports, same name', t => {
37+
test('multiple named exports (same name)', t => {
3838
module.exports.foo = foo
3939
module.exports.foo = bar
4040
t.deepEqual(module.exports, { foo: foo, foo_1: bar })
4141
})
4242

4343
test('multiple default exports (anonymous functions)', t => {
44-
// it's quite hard to get a reference to an anonymous function in ES6
44+
// it's quite hard to refer to an anonymous function in ES6 without
45+
// accidentally naming it
4546
const anon = [() => {}]
4647
module.exports = anon[0]
4748
module.exports = anon[0]
4849
t.deepEqual(module.exports, { default: anon[0], default_1: anon[0] })
4950
})
5051

51-
test('multiple default exports (non-functions)', t => {
52-
const anon = { foo: 42 }
52+
test('multiple default exports (anonymous non-functions)', t => {
53+
const anon = ['foo', 42]
5354
module.exports = anon
5455
module.exports = anon
5556
t.deepEqual(module.exports, { default: anon, default_1: anon })
@@ -61,30 +62,19 @@ test('multiple default exports (named functions)', t => {
6162
t.deepEqual(module.exports, { foo, bar })
6263
})
6364

64-
test('mixed exports', t => {
65-
const anon = [() => {}]
66-
67-
module.exports.foo = foo
68-
module.exports.foo = bar
69-
70-
module.exports.bar = foo
71-
module.exports.bar = bar
65+
test('multiple default exports (named properties)', t => {
66+
const props = { foo, bar }
7267

73-
module.exports = foo
74-
module.exports = bar
75-
76-
module.exports = anon[0]
77-
module.exports = anon[0]
68+
module.exports = props
69+
module.exports = props
7870

7971
t.deepEqual(module.exports, {
80-
foo: foo,
81-
foo_1: bar,
82-
bar: foo,
72+
foo,
73+
bar,
74+
default: props,
75+
foo_1: foo,
8376
bar_1: bar,
84-
foo_2: foo,
85-
bar_2: bar,
86-
default: anon[0],
87-
default_1: anon[0],
77+
default_1: props,
8878
})
8979
})
9080

0 commit comments

Comments
 (0)