Skip to content

Commit 90f0315

Browse files
authored
Fix walkObject to work with module namespace objects (#1368)
1 parent d4d8474 commit 90f0315

File tree

8 files changed

+84
-1
lines changed

8 files changed

+84
-1
lines changed

.changeset/chilly-hairs-serve.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@vanilla-extract/private': patch
3+
---
4+
5+
**walkObject**: Use an empty object to initialize a clone instead of calling the input object's `constructor`
6+
7+
This allows `walkObject` to be used on module namespace objects:
8+
9+
```ts
10+
import * as ns from './foo';
11+
12+
// Runtime error in `vite-node`
13+
walkObject(ns, myMappingFunction);
14+
```
15+
16+
The previous implementation did not work with these objects because [they do not have a `constructor` function][es6 spec].
17+
`esbuild` seems to have papered over this issue by providing a `constructor` function on these objects, but this seems to not be the case with `vite-node`, hence the need for this fix.
18+
19+
[es6 spec]: https://262.ecma-international.org/6.0/#sec-module-namespace-objects

.changeset/rare-days-suffer.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@vanilla-extract/vite-plugin': patch
3+
---
4+
5+
Update `@vanilla-extract/css` dependency
6+
7+
This fixes a bug where APIs that used the `walkObject` utility (e.g. `createTheme`) would fail when used with module namespace objects inside `vite-node`.
8+
This was due to the previous implementation using the input object's `constructor` to initialize a clone, which does not work with module namespace objects because [they do not have a `constructor` function][es6 spec].
9+
10+
[es6 spec]: https://262.ecma-international.org/6.0/#sec-module-namespace-objects

.changeset/warm-bulldogs-sin.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@vanilla-extract/css': patch
3+
---
4+
5+
Update `@vanilla-extract/private` dependency

packages/private/src/walkObject.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export function walkObject<T extends Walkable, MapTo>(
1111
fn: (value: Primitive, path: Array<string>) => MapTo,
1212
path: Array<string> = [],
1313
): MapLeafNodes<T, MapTo> {
14-
const clone = obj.constructor();
14+
const clone = {} as any;
1515

1616
for (let key in obj) {
1717
const value = obj[key];

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"@vanilla-extract/css": "*",
1313
"@vanilla-extract/dynamic": "*",
1414
"@vanilla-extract/integration": "*",
15+
"@vanilla-extract/private": "*",
1516
"@vanilla-extract/recipes": "*",
1617
"@vanilla-extract/sprinkles": "*",
1718
"vite-tsconfig-paths": "^4.3.1"

tests/walkObject/tokens.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const space = { small: '8px', large: '16px' };
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { describe, test, expect } from 'vitest';
2+
import { walkObject } from '@vanilla-extract/private';
3+
import * as tokens from './tokens';
4+
5+
describe('walkObject', () => {
6+
test('walkObject', () => {
7+
const obj = {
8+
a: {
9+
b: {
10+
c: 1,
11+
},
12+
d: 2,
13+
},
14+
e: 3,
15+
};
16+
17+
const result = walkObject(obj, (value) => String(value));
18+
19+
expect(result).toMatchInlineSnapshot(`
20+
{
21+
"a": {
22+
"b": {
23+
"c": "1",
24+
},
25+
"d": "2",
26+
},
27+
"e": "3",
28+
}
29+
`);
30+
});
31+
32+
test('walkObject module namespace object', () => {
33+
const result = walkObject(tokens, (value) => `foo${value}`);
34+
35+
expect(result).toMatchInlineSnapshot(`
36+
{
37+
"space": {
38+
"large": "foo16px",
39+
"small": "foo8px",
40+
},
41+
}
42+
`);
43+
});
44+
});

0 commit comments

Comments
 (0)