Skip to content

Commit 0b69d12

Browse files
authored
feat: add unsafe option (#13)
* feat: add `unsafe` option * fix(types): strict `Options` interplay * chore: add `options.unsafe` docs
1 parent c6814c4 commit 0b69d12

File tree

4 files changed

+144
-4
lines changed

4 files changed

+144
-4
lines changed

index.d.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
export interface Options {
1+
export type Options = {
22
browser?: boolean;
33
conditions?: string[];
44
require?: boolean;
5+
unsafe?: false;
6+
} | {
7+
conditions?: string[];
8+
unsafe?: true;
59
}
610

711
export function resolve<T=any>(pkg: T, entry: string, options?: Options): string | void;

readme.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,42 @@ resolve(contents, '.', {
206206
}); //=> "./index.worker.js"
207207
```
208208

209+
#### options.unsafe
210+
Type: `boolean` <br>
211+
Default: `false`
212+
213+
> **Important:** You probably do not want this option! <br>It will break out of Node's default resolution conditions.
214+
215+
When enabled, this option will ignore **all other options** except [`options.conditions`](#optionsconditions). This is because, when enabled, `options.unsafe` **does not** assume or provide any default conditions except the `"default"` condition.
216+
217+
```js
218+
resolve(contents);
219+
//=> Conditions: ["default", "import", "node"]
220+
221+
resolve(contents, { unsafe: true });
222+
//=> Conditions: ["default"]
223+
224+
resolve(contents, { unsafe: true, require: true, browser: true });
225+
//=> Conditions: ["default"]
226+
```
227+
228+
In other words, this means that trying to use `options.require` or `options.browser` alongside `options.unsafe` will have no effect. In order to enable these conditions, you must provide them manually into the `options.conditions` list:
229+
230+
```js
231+
resolve(contents, {
232+
unsafe: true,
233+
conditions: ["require"]
234+
});
235+
//=> Conditions: ["default", "require"]
236+
237+
resolve(contents, {
238+
unsafe: true,
239+
conditions: ["browser", "require", "custom123"]
240+
});
241+
//=> Conditions: ["default", "browser", "require", "custom123"]
242+
```
243+
244+
209245
### legacy(pkg, options?)
210246
Returns: `string` or `undefined`
211247

src/index.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,13 @@ function toName(name, entry) {
5353
* @param {boolean} [options.browser]
5454
* @param {boolean} [options.require]
5555
* @param {string[]} [options.conditions]
56+
* @param {boolean} [options.unsafe]
5657
*/
5758
export function resolve(pkg, entry='.', options={}) {
5859
let { name, exports } = pkg;
5960

6061
if (exports) {
61-
let { browser, require, conditions=[] } = options;
62+
let { browser, require, unsafe, conditions=[] } = options;
6263

6364
let target = toName(name, entry);
6465
if (target[0] !== '.') target = './' + target;
@@ -68,8 +69,8 @@ export function resolve(pkg, entry='.', options={}) {
6869
}
6970

7071
let allows = new Set(['default', ...conditions]);
71-
allows.add(require ? 'require' : 'import');
72-
allows.add(browser ? 'browser' : 'node');
72+
unsafe || allows.add(require ? 'require' : 'import');
73+
unsafe || allows.add(browser ? 'browser' : 'node');
7374

7475
let key, tmp, isSingle=false;
7576

test/resolve.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,3 +610,102 @@ conditions('should throw an error if no known conditions', ctx => {
610610
});
611611

612612
conditions.run();
613+
614+
// ---
615+
616+
const unsafe = suite('options.unsafe', {
617+
"exports": {
618+
".": {
619+
"production": "$prod",
620+
"development": "$dev",
621+
"default": "$default",
622+
},
623+
"./spec/type": {
624+
"import": "$import",
625+
"require": "$require",
626+
"default": "$default"
627+
},
628+
"./spec/env": {
629+
"worker": {
630+
"default": "$worker"
631+
},
632+
"browser": "$browser",
633+
"node": "$node",
634+
"default": "$default"
635+
}
636+
}
637+
});
638+
639+
unsafe('should ignore unknown conditions by default', pkg => {
640+
pass(pkg, '$default', '.', {
641+
unsafe: true,
642+
});
643+
});
644+
645+
unsafe('should ignore "import" and "require" conditions by default', pkg => {
646+
pass(pkg, '$default', './spec/type', {
647+
unsafe: true,
648+
});
649+
650+
pass(pkg, '$default', './spec/type', {
651+
unsafe: true,
652+
require: true,
653+
});
654+
});
655+
656+
unsafe('should ignore "node" and "browser" conditions by default', pkg => {
657+
pass(pkg, '$default', './spec/type', {
658+
unsafe: true,
659+
});
660+
661+
pass(pkg, '$default', './spec/type', {
662+
unsafe: true,
663+
browser: true,
664+
});
665+
});
666+
667+
unsafe('should respect/accept any custom condition(s) when specified', pkg => {
668+
// root, dev only
669+
pass(pkg, '$dev', '.', {
670+
unsafe: true,
671+
conditions: ['development']
672+
});
673+
674+
// root, defined order
675+
pass(pkg, '$prod', '.', {
676+
unsafe: true,
677+
conditions: ['development', 'production']
678+
});
679+
680+
// import vs require, defined order
681+
pass(pkg, '$require', './spec/type', {
682+
unsafe: true,
683+
conditions: ['require']
684+
});
685+
686+
// import vs require, defined order
687+
pass(pkg, '$import', './spec/type', {
688+
unsafe: true,
689+
conditions: ['import', 'require']
690+
});
691+
692+
// import vs require, defined order
693+
pass(pkg, '$node', './spec/env', {
694+
unsafe: true,
695+
conditions: ['node']
696+
});
697+
698+
// import vs require, defined order
699+
pass(pkg, '$browser', './spec/env', {
700+
unsafe: true,
701+
conditions: ['browser', 'node']
702+
});
703+
704+
// import vs require, defined order
705+
pass(pkg, '$worker', './spec/env', {
706+
unsafe: true,
707+
conditions: ['browser', 'node', 'worker']
708+
});
709+
});
710+
711+
unsafe.run();

0 commit comments

Comments
 (0)