From 90f03153bb7c4a8d5b448eab228c46203e9cdaed Mon Sep 17 00:00:00 2001 From: Adam Skoufis Date: Thu, 28 Mar 2024 15:13:40 +1100 Subject: [PATCH] Fix `walkObject` to work with module namespace objects (#1368) --- .changeset/chilly-hairs-serve.md | 19 ++++++++++ .changeset/rare-days-suffer.md | 10 +++++ .changeset/warm-bulldogs-sin.md | 5 +++ packages/private/src/walkObject.ts | 2 +- pnpm-lock.yaml | 3 ++ tests/package.json | 1 + tests/walkObject/tokens.ts | 1 + tests/walkObject/walkObject.vitest.test.ts | 44 ++++++++++++++++++++++ 8 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 .changeset/chilly-hairs-serve.md create mode 100644 .changeset/rare-days-suffer.md create mode 100644 .changeset/warm-bulldogs-sin.md create mode 100644 tests/walkObject/tokens.ts create mode 100644 tests/walkObject/walkObject.vitest.test.ts diff --git a/.changeset/chilly-hairs-serve.md b/.changeset/chilly-hairs-serve.md new file mode 100644 index 000000000..3e42306ae --- /dev/null +++ b/.changeset/chilly-hairs-serve.md @@ -0,0 +1,19 @@ +--- +'@vanilla-extract/private': patch +--- + +**walkObject**: Use an empty object to initialize a clone instead of calling the input object's `constructor` + +This allows `walkObject` to be used on module namespace objects: + +```ts +import * as ns from './foo'; + +// Runtime error in `vite-node` +walkObject(ns, myMappingFunction); +``` + +The previous implementation did not work with these objects because [they do not have a `constructor` function][es6 spec]. +`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. + +[es6 spec]: https://262.ecma-international.org/6.0/#sec-module-namespace-objects diff --git a/.changeset/rare-days-suffer.md b/.changeset/rare-days-suffer.md new file mode 100644 index 000000000..136556263 --- /dev/null +++ b/.changeset/rare-days-suffer.md @@ -0,0 +1,10 @@ +--- +'@vanilla-extract/vite-plugin': patch +--- + +Update `@vanilla-extract/css` dependency + +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`. +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]. + +[es6 spec]: https://262.ecma-international.org/6.0/#sec-module-namespace-objects diff --git a/.changeset/warm-bulldogs-sin.md b/.changeset/warm-bulldogs-sin.md new file mode 100644 index 000000000..654a4e557 --- /dev/null +++ b/.changeset/warm-bulldogs-sin.md @@ -0,0 +1,5 @@ +--- +'@vanilla-extract/css': patch +--- + +Update `@vanilla-extract/private` dependency diff --git a/packages/private/src/walkObject.ts b/packages/private/src/walkObject.ts index 09983953d..d07d69e9f 100644 --- a/packages/private/src/walkObject.ts +++ b/packages/private/src/walkObject.ts @@ -11,7 +11,7 @@ export function walkObject( fn: (value: Primitive, path: Array) => MapTo, path: Array = [], ): MapLeafNodes { - const clone = obj.constructor(); + const clone = {} as any; for (let key in obj) { const value = obj[key]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9aebc6e69..cf4c6775b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -933,6 +933,9 @@ importers: '@vanilla-extract/integration': specifier: '*' version: link:../packages/integration + '@vanilla-extract/private': + specifier: '*' + version: link:../packages/private '@vanilla-extract/recipes': specifier: '*' version: link:../packages/recipes diff --git a/tests/package.json b/tests/package.json index 82906365e..1d1c09d10 100644 --- a/tests/package.json +++ b/tests/package.json @@ -12,6 +12,7 @@ "@vanilla-extract/css": "*", "@vanilla-extract/dynamic": "*", "@vanilla-extract/integration": "*", + "@vanilla-extract/private": "*", "@vanilla-extract/recipes": "*", "@vanilla-extract/sprinkles": "*", "vite-tsconfig-paths": "^4.3.1" diff --git a/tests/walkObject/tokens.ts b/tests/walkObject/tokens.ts new file mode 100644 index 000000000..e63808e9d --- /dev/null +++ b/tests/walkObject/tokens.ts @@ -0,0 +1 @@ +export const space = { small: '8px', large: '16px' }; diff --git a/tests/walkObject/walkObject.vitest.test.ts b/tests/walkObject/walkObject.vitest.test.ts new file mode 100644 index 000000000..4fb3911b4 --- /dev/null +++ b/tests/walkObject/walkObject.vitest.test.ts @@ -0,0 +1,44 @@ +import { describe, test, expect } from 'vitest'; +import { walkObject } from '@vanilla-extract/private'; +import * as tokens from './tokens'; + +describe('walkObject', () => { + test('walkObject', () => { + const obj = { + a: { + b: { + c: 1, + }, + d: 2, + }, + e: 3, + }; + + const result = walkObject(obj, (value) => String(value)); + + expect(result).toMatchInlineSnapshot(` + { + "a": { + "b": { + "c": "1", + }, + "d": "2", + }, + "e": "3", + } + `); + }); + + test('walkObject module namespace object', () => { + const result = walkObject(tokens, (value) => `foo${value}`); + + expect(result).toMatchInlineSnapshot(` + { + "space": { + "large": "foo16px", + "small": "foo8px", + }, + } + `); + }); +});