GithubHelp home page GithubHelp logo

magic-akari / swc_mut_cjs_exports Goto Github PK

View Code? Open in Web Editor NEW
51.0 2.0 13.0 460 KB

[SWC plugin] mutable CJS exports

Home Page: https://www.npmjs.com/package/swc_mut_cjs_exports

License: MIT License

JavaScript 20.94% Rust 73.71% TypeScript 5.35%
jest swc swc-plugin cjs commonjs

swc_mut_cjs_exports's Introduction

[SWC plugin] mutable CJS exports

Crates.io npm

Test SWC Compat Test with @swc/core@latest with @swc/core@nightly

This is a SWC plugin to emit mutable CJS exports.

This SWC plugin has only been tested for compatibility with jest. It should be used with @swc/jest.

This project was previously called jest_workaround

plugin version

https://swc.rs/docs/plugin/selecting-swc-core

usage

install

npm i -D jest @swc/core @swc/jest swc_mut_cjs_exports
// jest.config.js
const fs = require("node:fs");

const swcrc = JSON.parse(fs.readFileSync(".swcrc", "utf8"));

// If you have other plugins, change this line.
((swcrc.jsc ??= {}).experimental ??= {}).plugins = [
  ["swc_mut_cjs_exports", {}],
];

module.exports = {
  transform: {
    "^.+\\.(t|j)sx?$": ["@swc/jest", swcrc],
  },
};

Make sure that module.type is commonjs in your .swcrc since this plugin does not touch non-workaround parts, such as import statements.

FAQ

1. When do I need this?

If you're using the swc compiler to transform your code to comply with the ESM specification, but you're also using Jest to test it in a CJS environment, you may encounter issues due to the immutable issue of exports.

This plugin can help by transforming the export statements into mutable exports.

2. Do I have a better choice?

You may have other options depending on your specific needs:

  • If you're able to run Jest in an ESM environment, you can use swc to transpile TypeScript/JSX syntax or downgrade JavaScript syntax without module conversion. Simply set the value of module.type to es6 to achieve this.

  • It's possible that some issues related to running Jest in an ESM environment will be resolved over time. Keep an eye on facebook/jest#9430 for updates.

  • If you don't need the behavior of ESM specifically, you can stick with the CJS syntax to get the CJS behavior of exports.

These options may be worth considering before using this plugin.

CJS syntax

exports.foo = function foo() {
  return 42;
};

CTS(CJS in TypeScript) syntax

export = {
  foo: function foo() {
    return 42;
  },
};

Notes:

  • ESM style export means immutable exports when transformed into CJS
  • ESM style import means hoisted require when transformed into CJS

3. After upgrading the plugin version, the changes have not taken effect.

This is a known issue. You could remove the Jest cache by running jest --clearCache as a workaround.

swc_mut_cjs_exports's People

Contributors

dependabot[bot] avatar jrolfs avatar magic-akari avatar renovate[bot] avatar wadjoh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

swc_mut_cjs_exports's Issues

Mocha version

This module solves a problem that is recurring in many situations (and which also occurs in other bundlers). The essential changes seem to have nothing to do with Jest specifically, so would it be possible to modify the API to make it possible to using it with other test runners, like Ava or Mocha?

Typically, seeing something like this in .mocharc.json:

{
  "spec": ["src/**/*.{spec,test}.ts"],
  "require": ["@swc/register", "jest-mutable-exports"],
  "recursive": true
}

Jest commonjs gives ReferenceError: Cannot access before initialization when jest.mock and exported class

I've read #79 but I think I'm seeing a related issue.

minimal reproducible code

There are two input source files:

// 1. application/web/foo.test.ts 
const run = jest.fn()                    
                                         
const fakeBar = {                        
    __esModule: true,                    
    default: {                           
        run,                             
    },                                   
}                                        
jest.mock('./bar', () => fakeBar)        
                                         
import bar from './bar'                  
                                         
describe('Test example', () => {         
    it('has a passing test', () => {           
        expect(bar.run).not.toBeCalled() 
    })                                   
})

// 2. application/web/bar.ts
export default class Bar {
	static run() {}
}                                

The swc config used for transforming TS to JS in jest is:

{                                                     
  "$schema": "http://json.schemastore.org/swcrc",     
  "sourceMaps": true,                                 
  "jsc": {                                            
    "parser": {                                       
      "syntax": "typescript",                         
      "tsx": true,                                    
      "dynamicImport": true,                          
      "decorators": true                              
    },                                                
    "preserveAllComments": true,                      
    "transform": null,                                
    "target": "es2017",                               
    "loose": false,                                   
    "externalHelpers": false,                         
    "keepClassNames": false,                          
    "experimental": {                                 
      "plugins": [                                    
        [                                             
          "swc_mut_cjs_exports",                      
          {}                                          
        ]                                             
      ]                                               
    }                                                 
  },                                                  
  "module": {                                         
    "type": "commonjs"                                
  }                                                   
}                                                     

The tsc config is:

{
  "transpileOnly": true,
  "compilerOptions": {
    "target": "es2017",
    "module": "commonjs",
    "jsx": "react-jsx",
    "esModuleInterop": true,
    "sourceMap": false,
    "allowJs": true
  }
}

tsc transpiled

Test output:

+ TS_LOADER=tsc yarn -s test application/web/foo.test.ts
 PASS  application/web/foo.test.ts
  Test example
    ✓ has a passing test (1 ms)
// tsc js output of foo.test.ts
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const run = jest.fn();
const fakeBar = {
  __esModule: true,
  default: {
    run,
  },
};
jest.mock("./bar", () => fakeBar);
const bar_1 = tslib_1.__importDefault(require("./bar"));
describe("Test example", () => {
  it("has a passing test", () => {
    expect(bar_1.default.run).not.toBeCalled();
  });
});

// tsc js output of bar.ts
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class Bar {
  static run() {}
}
exports.default = Bar;

swc transpiled

Test output:

+ TS_LOADER=swc yarn -s test application/web/foo.test.ts
 FAIL  application/web/foo.test.ts
  ● Test suite failed to run

    ReferenceError: Cannot access 'fakeBar' before initialization

       7 | 	},
       8 | }
    >  9 | jest.mock('./bar', () => fakeBar)
         |                          ^
      10 |
      11 | import bar from './bar'
      12 |

      at fakeBar (application/web/foo.test.ts:9:26)
      at Object.<anonymous> (application/web/foo.test.ts:6:39)
// swc js output of foo.test.ts
"use strict";
Object.defineProperty(exports, "__esModule", {
  value: true,
});
const _bar = _interop_require_default(require("./bar"));
function _interop_require_default(obj) {
  return obj && obj.__esModule
    ? obj
    : {
        default: obj,
      };
}
const run = jest.fn();
const fakeBar = {
  __esModule: true,
  default: {
    run,
  },
};
jest.mock("./bar", () => fakeBar);
describe("Test example", () => {
  it("has a passing test", () => {
    expect(_bar.default.run).not.toBeCalled();
  });
})

// swc js output of bar.ts
"use strict";
Object.defineProperty(exports, "__esModule", {
  value: true,
});
Object.defineProperty(exports, "default", {
  enumerable: true,
  get() {
    return Bar;
  },
  set(v) {
    Bar = v;
  },
  configurable: true,
});
var Bar;
Bar = class Bar {
  static run() {}
};

Notes

SWC version info:

Tsc generates this import order:

jest.mock("./bar", () => fakeBar);
const bar_1 = tslib_1.__importDefault(require("./bar"));

while swc generates:

const _bar = _interop_require_default(require("./bar"));
function _interop_require_default(obj) { ... }
const run = jest.fn();
const fakeBar = { ... }
jest.mock("./bar", () => fakeBar);

Could that ordering be an issue that causes the runtime error?

I'm using the jest preset ts-jest with a custom transformer (to allow switching at runtime using TS_LOADER between tsc and swc).

Could a jest plugin like this hoisting of mock calls be related?

I hope this issue contains all the information. Let me know if a reproducible git repo would be helpful to narrow down the problem. Thank you!

set configurable when re-exporting

Hi:
It seems like when transpiling ts code with export {someProperties} as someObject from 'somefile' the transpiled code don't let spyOn that objects. The function used for exports doesn't set configurable=true

function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: all[name]
    });
}

Members of unnamed re-exports cannot be redefined

When given an export like:

export * from './someModule'

And using jest.spyOn on a member from someModule an TypeError: Cannot redefine property error is still produced.

Re-exporting with names doesn't seem to have this problem, though:

export * as blah from './someModule'
export { foo, bar, baz } from './someModule'

I've created a small repo that reproduces the issue: https://github.com/wadjoh/swc-jest-workaround-bug
The re-export statement can be found in the src/someModule/index.ts file in that repo.

Compatibility with TS Enum

Input

export enum Foo {
  Bar = "Bar",
  Baz = "Baz",
}

After TypeScript strip

export var Foo;
(function(Foo) {
    Foo["Bar"] = "Bar";
    Foo["Baz"] = "Baz";
})(Foo || (Foo = {}));

Final output(with this plugin)

"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "Foo", {
    enumerable: true,
    get: function() {
        return Foo;
    },
    configurable: true
});
var Foo;
(function(Foo) {
    exports.Foo["Bar"] = "Bar";
    exports.Foo["Baz"] = "Baz";
})(exports.Foo || (exports.Foo = {}));

Note:
exports.Foo = {} did not change the value of exports.Foo.

Expect Behaviour:
Do not rewrite Foo in assign expr.

Plugin issues on Apple M1 chipset

Great plugin! Some developers on our team with M1 chips are experiencing issues. Is this something that could be addressed?

Issue

cwd: /Users/path/to/project/
cmd: SD_DB_TESTS=1 NODE_ENV=test /Users/path/to/project/node_modules/.bin/jest --runInBand --colors --forceExit --verbose --watch --colors test/models/article.db.test.js

thread '<unnamed>' panicked at 'failed to invoke plugin: failed to invoke plugin on 'Some("/Users/path/to/project/dev/jest-setup-framework.js")'

Caused by:
    0: Failed to create plugin instance
    1: missing requires CPU features: "EnumSet(SSE2)"', /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/swc-0.245.20/src/plugin.rs:228:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 FAIL  test/models/article.db.test.js
  ● Test suite failed to run

    failed to handle: failed to invoke plugin: failed to invoke plugin on 'Some("/Users/path/to/project/dev/jest-setup-framework.js")'

    Caused by:
        0: Failed to create plugin instance
        1: missing requires CPU features: "EnumSet(SSE2)"

      at Compiler.transformSync (node_modules/@swc/core/index.js:241:29)
      at transformSync (node_modules/@swc/core/index.js:348:21)
      at Object.process (node_modules/@swc/jest/index.js:73:45)
      at ScriptTransformer.transformSource (node_modules/@jest/transform/build/ScriptTransformer.js:542:31)
      at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:671:40)
      at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:723:19)

thread '<unnamed>' panicked at 'failed to invoke plugin: failed to invoke plugin on 'Some("/Users/path/to/project/dev/jest-setup-framework.js")'

Caused by:
    0: Failed to create plugin instance
    1: missing requires CPU features: "EnumSet(SSE2)"', /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/swc-0.245.20/src/plugin.rs:228:14

Details

    "@swc/core": "1.3.34",
    "@swc/helpers": "0.4.14",
    "jest_workaround": "0.1.14",

Doesn't appear to work with typescript?

I've installed the jest_workaround, and setup my jest.config to pass the plugin in,

My .swcrc file:

{
    "jsc": {
        "parser": {
            "syntax": "typescript",
            "tsx": true
        }
    },
    "module": {
        "type": "commonjs"
    }
}

when I run I still get:

 ● Test suite failed to run

    TypeError: Cannot redefine property: trackCtaClicked
        at Function.defineProperty (<anonymous>)

Not sure what I'm doing wrong.

Package versions:

"@swc/cli": "^0.1.57",
"@swc/core": "^1.3.14",
"@swc/jest": "^0.2.23",
"jest_workaround": "^0.1.13"

plugin crashes after update @swc/core to 1.4.0

Hi, I get this error after updating @swc/core to version 1.4.0:

Error: failed to handle: failed to invoke plugin: failed to invoke plugin on 'Some("/webapp/node_modules/jest-runner/build/index.js")'

Caused by:
    0: failed to invoke `swc_mut_cjs_exports` as js transform plugin at swc_mut_cjs_exports
    1: RuntimeError: unreachable
           at __rust_start_panic (<module>[1726]:0x7b89c)
           at rust_panic (<module>[1721]:0x7b84c)
           at std::panicking::rust_panic_with_hook::h7601402c0a383194 (<module>[1720]:0x7b83e)
           at std::panicking::begin_panic_handler::{{closure}}::he405aaeb801d5772 (<module>[1709]:0x7aec3)
           at std::sys_common::backtrace::__rust_end_short_backtrace::h04fac26f88d230df (<module>[1708]:0x7adf0)
           at rust_begin_unwind (<module>[1715]:0x7b4a5)
           at core::panicking::panic_fmt::h6dad0405f48e39e2 (<module>[1784]:0x7c488)
           at core::result::unwrap_failed::h7ed8731a69ab17a3 (<module>[1814]:0x8282c)
           at rkyv::impls::core::<impl rkyv::DeserializeUnsized<[U],D> for [T]>::deserialize_unsized::h576ee81e50546263 (<module>[383]:0x4267e)
           at rkyv::impls::core::<impl rkyv::DeserializeUnsized<T,D> for <T as rkyv::Archive>::Archived>::deserialize_unsized::hd20e8bee2c63cb9b (<module>[98]:0x13729)
           at swc_ecma_ast::stmt::_::<impl rkyv::Deserialize<swc_ecma_ast::stmt::Stmt,__D> for <swc_ecma_ast::stmt::Stmt as rkyv::Archive>::Archived>::deserialize::h5c5c5b1e0b3cbea7 (<module>[132]:0x2313e)
           at rkyv::impls::core::<impl rkyv::DeserializeUnsized<[U],D> for [T]>::deserialize_unsized::h6d522b21df4cfcaa (<module>[19]:0x2a8f)
           at swc_common::plugin::serialized::_::<impl rkyv::Deserialize<swc_common::plugin::serialized::VersionedSerializable<T>,__D> for <swc_common::plugin::serialized::VersionedSerializable<T> as rkyv::Archive>::Archived>::deserialize::hdcb48105b95c48a3 (<module>[18]:0x1b81)
           at swc_common::plugin::serialized::PluginSerializedBytes::deserialize::h0e19d44d2707fe14 (<module>[21]:0x3124)
           at __transform_plugin_process_impl (<module>[441]:0x4ccbe)
    at Compiler.transformSync (/webapp/node_modules/@swc/core/index.js:244:29)
    at transformSync (/webapp/node_modules/@swc/core/index.js:351:21)
    at Object.process (/webapp/node_modules/@swc/jest/index.js:73:45)
    at ScriptTransformer.transformSource (/webapp/node_modules/@jest/transform/build/ScriptTransformer.js:545:31)
    at revertHook.exts (/webapp/node_modules/@jest/transform/build/ScriptTransformer.js:776:18)
    at Module._compile (/webapp/node_modules/pirates/lib/index.js:113:29)
    at Module._extensions..js (node:internal/modules/cjs/loader:1295:10)
    at Object.newLoader (/webapp/node_modules/pirates/lib/index.js:121:7)
    at Module.load (node:internal/modules/cjs/loader:1091:32)
    at Module._load (node:internal/modules/cjs/loader:938:12)

my package.json:

{
  "devDependencies": {
    "@swc/core": "^1.3.96",
    "@swc/jest": "^0.2.36",
    "@testing-library/jest-dom": "^6.4.1",
    "@types/jest": "^29.5.12",
    "jest": "^29.7.0",
    "swc_mut_cjs_exports": "^0.86.17",
    "ts-jest": "^29.1.1",
    "typescript": "^5.2.2",
  }
}

Crashes with thread '<unnamed>' panicked at 'failed to invoke plugin

@swc/jest causes jest to crash in CI when using the jest_workaround plugin.

GH action run: https://github.com/getsentry/sentry-javascript/actions/runs/4437301786/jobs/7787193218

PR w/ crash: getsentry/sentry-javascript#7484

SWC versions:

    "@swc/core": "1.3.40",
    "@swc/jest": "0.2.24",

jest_workaround versions:

  "jest_workaround": "0.1.16",
> @sentry/core:test

$ jest
thread '<unnamed>' panicked at 'failed to invoke plugin: failed to invoke plugin on 'Some("/home/runner/work/sentry-javascript/sentry-javascript/packages/core/test/lib/base.test.ts")'

Caused by:
    0: RuntimeError: out of bounds memory access
    1: heap_get_oob', /usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/swc-0.255.3/src/plugin.rs:228:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Segmentation fault (core dumped)
error Command failed with exit code 139.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

SWC bug report: swc-project/swc#7092

swc-project/swc#7092 (comment)

Imports from file with same name but different location dropped

I have installed "@swc/core": "1.3.4" and "jest_workaround": "0.1.11"

In a file I have imports like

import {
    getBooleanConfigValue,
    getNumericConfigValue
} from "@init-code/config/config";
import { shouldModuleBeInitialized } from "@async-core/config";

function a() {
 const config = getBooleanConfigValue();
}

test file calls something from the file above

and it fails with this
test-file-fail

I added a debug break point and see this
swc-bug
the _config is the module @async-core/config and @init-code/config/config is completely missing

if I do this change

const shouldModuleBeInitialized = () => true;

and delete the import @async-core/config then @init-code/config/config shows up
and then it contains all the exported stuff from it

Seems like @async-core/config and @init-code/config/config cannot coexist and the one that is imported later overrides the one before.
It seems like it has issues if both of them are files named config?

Default exports are not set as configurable

Hello, first of all thx for the plugin, it is being very useful at jest transform.
I would like to advice you that transpiled code defines default export is not being defined through your _export function son it keeps not configurable.

Object.defineProperty(exports, 'default', {
  enumerable: true,
  get: () => _default
});

It would be great if also default property is set as configurable.

RuntimeError: unreachable on latest @swc/core

I just updated to @swc/core 1.3.3, and now I can no longer run this plugin.

The error stack is:

failed to handle: failed to invoke plugin: failed to invoke plugin on 'Some("path/to/file.ts")'

    Caused by:
        0: failed to invoke `node_modules/.pnpm/[email protected]_@[email protected]+@[email protected]/node_modules/jest_workaround/target/wasm32-unknown-unknown/release/jest_workaround.wasm` as js transform plugin at node_modules/.pnpm/[email protected]_@[email protected]+@[email protected]/node_modules/jest_workaround/target/wasm32-unknown-unknown/release/jest_workaround.wasm
        1: RuntimeError: unreachable
               at __rust_start_panic (<module>[1695]:0x12861a)
               at rust_panic (<module>[1692]:0x1285f3)
               at std::panicking::rust_panic_with_hook::h84feca33bd4bd229 (<module>[1691]:0x1285c3)
               at std::panicking::begin_panic_handler::{{closure}}::hd2eacd3bb9ff1eab (<module>[1678]:0x127c96)
               at std::sys_common::backtrace::__rust_end_short_backtrace::h976699518d897fb1 (<module>[1677]:0x127bd5)
               at rust_begin_unwind (<module>[1686]:0x12825a)
               at core::panicking::panic_fmt::hc171d095bc4a492d (<module>[1760]:0x129807)
               at core::result::unwrap_failed::h68ab818eb89182b6 (<module>[1801]:0x1300f3)
               at rkyv::impls::core::<impl rkyv::DeserializeUnsized<[U],D> for [T]>::deserialize_unsized::hd7ead72f4806bf83 (<module>[789]:0xdc359)
               at rkyv::impls::core::<impl rkyv::DeserializeUnsized<[U],D> for [T]>::deserialize_unsized::ha2c88e8a71aeda28 (<module>[310]:0x43e69)
               at swc_common::plugin::serialized::PluginSerializedBytes::deserialize::h897224c27b98e658 (<module>[910]:0xf0e67)
               at swc_common::plugin::serialized::deserialize_from_ptr::hc9c103e6cc480c1b (<module>[909]:0xf0bf1)
               at __transform_plugin_process_impl (<module>[829]:0xe1dda)
        2: unreachable

      at std::panicking::rust_panic_with_hook::h84feca33bd4bd229 (<module>[1691]:0x1285c3)
      at std::panicking::begin_panic_handler::{{closure}}::hd2eacd3bb9ff1eab (<module>[1678]:0x127c96)
      at std::sys_common::backtrace::__rust_end_short_backtrace::h976699518d897fb1 (<module>[1677]:0x127bd5)
                 at rust_begin_unwind (<module>[1686]:0x12825a)
      at core::panicking::panic_fmt::hc171d095bc4a492d (<module>[1760]:0x129807)
      at core::result::unwrap_failed::h68ab818eb89182b6 (<module>[1801]:0x1300f3)
      at rkyv::impls::core::<impl rkyv::DeserializeUnsized<[U],D> for [T]>::deserialize_unsized::hd7ead72f4806bf83 (<module>[789]:0xdc359)
      at rkyv::impls::core::<impl rkyv::DeserializeUnsized<[U],D> for [T]>::deserialize_unsized::ha2c88e8a71aeda28 (<module>[310]:0x43e69)
      at swc_common::plugin::serialized::PluginSerializedBytes::deserialize::h897224c27b98e658 (<module>[910]:0xf0e67)
      at swc_common::plugin::serialized::deserialize_from_ptr::hc9c103e6cc480c1b (<module>[909]:0xf0bf1)
                 at __transform_plugin_process_impl (<module>[829]:0xe1dda)
          2: unreachable
      at Compiler.transformSync (../../node_modules/.pnpm/@[email protected]/node_modules/@swc/core/index.js:241:29)
      at transformSync (../../node_modules/.pnpm/@[email protected]/node_modules/@swc/core/index.js:348:21)
      at Object.process (../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@swc/jest/index.js:72:45)
      at ScriptTransformer.transformSource (../../node_modules/.pnpm/@[email protected]/node_modules/@jest/transform/build/ScriptTransformer.js:615:31)
      at ScriptTransformer._transformAndBuildScript (../../node_modules/.pnpm/@[email protected]/node_modules/@jest/transform/build/ScriptTransformer.js:757:40)
      at ScriptTransformer.transform (../../node_modules/.pnpm/@[email protected]/node_modules/@jest/transform/build/ScriptTransformer.js:814:19)

Invalid left-hand side in assignmet when using swc_mut_cjs_exports

I use io-ts in my code, and io-ts has as export named null. This is reexported in code as

export { null } from 'io-ts'; 

This generates the following export when used with the plugin:

Object.defineProperty(exports, "null", {
    enumerable: true,
    get () {
        return _iots.null;
    },
    set (v) {
        null = v;
    },
    configurable: true
});

This errors out because null = v is invalid.

The minimal repro of this issue can be found here: https://github.com/HiranmayaGundu/null-error-repro

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

cargo
Cargo.toml
  • swc_core 0.90.24
  • swc_core 0.90.24
  • testing 0.35.21
github-actions
.github/workflows/cron-latest.yml
  • actions/checkout v4
  • actions/setup-node v4
  • pnpm/action-setup v2
  • actions/cache v4
.github/workflows/cron-nightly.yml
  • actions/checkout v4
  • actions/setup-node v4
  • pnpm/action-setup v2
  • actions/cache v4
.github/workflows/publish.yml
  • actions/checkout v4
  • softprops/action-gh-release 9d7c94cfd0a1f3ed45544c887983e9fa900f0564
  • actions/checkout v4
  • actions/setup-node v4
  • pnpm/action-setup v2
  • softprops/action-gh-release 9d7c94cfd0a1f3ed45544c887983e9fa900f0564
.github/workflows/swc-compat-test.yml
  • actions/checkout v4
  • pnpm/action-setup v2
  • actions/upload-artifact v4
  • actions/checkout v4
  • actions/setup-node v4
  • pnpm/action-setup v2
  • actions/download-artifact v4
.github/workflows/test.yml
  • actions/checkout v4
  • actions/checkout v4
  • actions/checkout v4
  • actions/checkout v4
  • actions/setup-node v4
  • pnpm/action-setup v2
nodenv
.node-version
  • node 20.11.1
npm
package.json
  • @swc/core ^1.4.0
  • @swc/jest ^0.2.36
  • @types/jest ^29.5.11
  • jest ^29.7.0
  • @swc/core ^1.4.0
  • @swc/jest ^0.2.36
  • pnpm 8.15.5

  • Check this box to trigger a request for Renovate to run again on this repository

AST schema version is not compatible w/ 0.90.3 & [email protected]

Using the latest version of this plugin and the latest version of SWC, I get this error:

    0: failed to invoke `swc_mut_cjs_exports` as js transform plugin at swc_mut_cjs_exports
    1: Plugin's AST schema version is not compatible with host's. Host: 1, Plugin: 2
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

@swc/core: 1.4.1
swc_mut_cjs_exports: 0.90.3

If I'm reading the versioning guidelines correctly, I believe these versions should be compatible?

Overriding a re-export with a local variable of same name results in runtime ReferenceError

Version: 0.79.55

Issue

Given an input file of:

export * from './someModule'
export const foo = () => {}

swc_mut_cjs_exports will output:

export { };
Object.defineProperty(exports, "foo", {
    enumerable: true,
    get () {
        return foo;
    },
    set (v) {
        foo = v;
    },
    configurable: true
});
Object.keys(mod).forEach(function(key) {
    if (key === "default" || key === "__esModule") return;
    if (key in exports && exports[key] === mod[key]) return;
    exports[key] = mod[key];
});
import * as mod from './someModule';
const foo = ()=>{};

If someModule exports a member named foo a ReferenceError will be thrown at runtime:

ReferenceError: Cannot access 'foo' before initialization

This is because the forEach in the output file tries to access exports.foo which has a getter to return the local foo variable which hasn't been defined yet.

Expectation

I think, ideally, we'd want the transformed exports to follow the same order as the pre-transformed exports rather than hoisting local exports to the top.

Like:

export { };
Object.keys(mod).forEach(function(key) {
    if (key === "default" || key === "__esModule") return;
    if (key in exports && exports[key] === mod[key]) return;
    exports[key] = mod[key];
});
Object.defineProperty(exports, "foo", {
    enumerable: true,
    get () {
        return foo;
    },
    set (v) {
        foo = v;
    },
    configurable: true
});
import * as mod from './someModule';
const foo = ()=>{};

Is SSE2 required? Can it not be?

Running jest with jest_workaround on an Apple Macbook Pro with an M1 Pro, I get:

thread '<unnamed>' panicked at 'failed to invoke plugin: failed to invoke plugin on 'Some("/Users/...path redacted.../dev/jest-setup-framework.js")'

Caused by:
    0: Failed to create plugin instance
    1: missing requires CPU features: "EnumSet(SSE2)"', /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/swc-0.245.20/src/plugin.rs:228:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 FAIL  test/models/article.db.test.js
  ● Test suite failed to run

    failed to handle: failed to invoke plugin: failed to invoke plugin on 'Some("/Users/...path redacted.../dev/jest-setup-framework.js")'

    Caused by:
        0: Failed to create plugin instance
        1: missing requires CPU features: "EnumSet(SSE2)"

      at Compiler.transformSync (node_modules/@swc/core/index.js:241:29)
      at transformSync (node_modules/@swc/core/index.js:348:21)
      at Object.process (node_modules/@swc/jest/index.js:73:45)
      at ScriptTransformer.transformSource (node_modules/@jest/transform/build/ScriptTransformer.js:542:31)
      at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:671:40)
      at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:723:19)

I don't know much about Rust, but it looks like maybe something is requiring SSE2? Could the build config be altered to not require it, or use ARM64 equivalents when building on that architecture?

Feature Request: Support Object.assign on imported objects

We have the following code in one of our test files:

import * as ProposalStore from 'views/InteractiveProposal/store/proposalStore';
Object.assign(ProposalStore, { useProposalDispatch: () => mockDispatch });

Which gives the following error:

● Test suite failed to run

TypeError: Cannot set property useProposalDispatch of [object Object] which has only a getter
    at Function.assign (<anonymous>)

   8 | jest.mock('views/InteractiveProposal/store/actions/updateDownPaymentAndSelectedFinanceOption');
   9 | const mockDispatch = jest.fn();
> 10 | Object.assign(ProposalStore, { useProposalDispatch: () => mockDispatch });

We were able to work around it by changing the code to:

jest.mock('views/InteractiveProposal/store/proposalStore', () => {
 const actual = jest.requireActual('views/InteractiveProposal/store/proposalStore');
 return {
   ...actual,
   useProposalDispatch: () => mockDispatch,
 };
});

But it'd be nice to support the other, existing way also.

Thanks!

Can't get tests to run to provide repro of bug

I'm trying to create a test case in this repo for a bug we're hitting. It has something to do with a circular dependency doing a re-export. The bug is something along the lines of the source from emit_export_stmts being moved from the very top of the file to below its imports which will eventually lead to an import returning undefined.

However, when I try to clone this repo, install deps, and run tests, I get this for every test:

 FAIL  __test__/case_10/index.spec.ts
  ● Test suite failed to run

    index not found

      at Compiler.transformSync (node_modules/.pnpm/@[email protected]/node_modules/@swc/core/index.js:241:29)
      at transformSync (node_modules/.pnpm/@[email protected]/node_modules/@swc/core/index.js:348:21)
      at Object.process (node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@swc/jest/index.js:73:45)
      at ScriptTransformer.transformSource (node_modules/.pnpm/@[email protected]/node_modules/@jest/transform/build/ScriptTransformer.js:542:31)
      at ScriptTransformer._transformAndBuildScript (node_modules/.pnpm/@[email protected]/node_modules/@jest/transform/build/ScriptTransformer.js:671:40)
      at ScriptTransformer.transform (node_modules/.pnpm/@[email protected]/node_modules/@jest/transform/build/ScriptTransformer.js:723:19)

Is this something you've seen?

set configurable when re-exporting *

Hi:
It seems like when transpiling ts code with export * as someObject from 'somefile' the transpiled code don't let spyOn that objects. The function used for exports doesn't set configurable=true

function _exportStar(from, to) {
    Object.keys(from).forEach(function(k) {
        if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) Object.defineProperty(to, k, {
            enumerable: true,
            get: function() {
                return from[k];
            }
        });
    });
    return from;
}

NextJS compatibility

This looks like just what I need. But when I run Jest I get all the same issues about spying. It doesn't seem to have made any difference.

I have updated the .swcrc file as per the Readme and it is highlighted in VSCode saying:

Property experimental is not allowed

Screenshot 2022-07-29 at 16 05 09

This is the full .swcrc file:

{
  "$schema": "http://json.schemastore.org/swcrc",
  "jsc": {
    "experimental": {
      "plugins": [["jest_workaround", {}]]
    },
    "parser": {
      "syntax": "typescript",
      "tsx": true,
      "decorators": false,
      "dynamicImport": true
    },
    "target": "es5",
    "baseUrl": ".",
    "paths": { [...]  }
  },
  "module": {
    "type": "commonjs"
  }
}

Installed package versions:

  • "jest_workaround": "^0.1.5",
  • "@swc/core": "^1.2.220",
  • "@swc/jest": "^0.2.22",
  • "swc-node": "^1.0.0",

I'm also using NextJS. Is there something I am missing to enable plugins for SWC ?

Thanks!

Failed to create plugin instance

Trying to use this plugin in nextjs and getting this error:

Caused by:
    0: Failed to create plugin instance
    1: Error while importing "env"."__set_transform_plugin_core_pkg_diagnostics": unknown import. Expected Function(FunctionType { params: [I32, I32], results: [] })
    at Object.transformSync (/Users/psenders/Documents/GitHub/web/node_modules/next/dist/build/swc/index.js:289:33)
    at Object.transformSync (/Users/psenders/Documents/GitHub/web/node_modules/next/dist/build/swc/index.js:325:21)
    at Object.process (/Users/psenders/Documents/GitHub/web/node_modules/next/dist/build/swc/jest-transformer.js:27:36)
    at ScriptTransformer.transformSource (/Users/psenders/Documents/GitHub/web/node_modules/@jest/transform/build/ScriptTransformer.js:615:31)
    at revertHook.exts (/Users/psenders/Documents/GitHub/web/node_modules/@jest/transform/build/ScriptTransformer.js:863:18)
    at Module._compile (/Users/psenders/Documents/GitHub/web/node_modules/@jest/transform/node_modules/pirates/lib/index.js:130:29)
    at Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
    at Object.newLoader (/Users/psenders/Documents/GitHub/web/node_modules/@jest/transform/node_modules/pirates/lib/index.js:141:7)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    ```

Unreadable logs printed to .swc

When the plugin has any errors with transforming it logs an unreadable file (AFAIK, I tried reading it with all sort of stuff)...
attached an example log I had thrown when trying to use the plugin for moving a fe project from ts-jest -> swc
and when trying to update swc-core 1.2.224 -> 1.2.232 (maybe something got broken there but can't be sure because I can't read the logs there...)
example_log.zip

Purposed Solution:

  • Have an option to mute those logs
  • Find out how to make them readable

Not compatible with @swc/core v1.0.6

swc_mut_cjs_exports plugin broken after swc/core v1.0.6, I've fixed by downgrade version as v1.0.5 which is working fine.

Determining test suites to run...thread '<unnamed>' panicked at /Users/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc-0.272.1/src/plugin.rs:162:14:
failed to invoke plugin: failed to invoke plugin on 'Some("/Users/bb/repos/test/jest.init.js")'

Caused by:
    0: failed to invoke `swc_mut_cjs_exports` as js transform plugin at swc_mut_cjs_exports
    1: RuntimeError: unreachable
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

RuntimeError: unreachable with 0.76.0 and @swc/core 1.3.57

thread '<unnamed>' panicked at 'failed to invoke plugin: failed to invoke plugin on 'Some("/home/circleci/project/node_modules/vfile/lib/index.js")'

Caused by:
    0: failed to invoke `jest_workaround` as js transform plugin at node_modules/jest_workaround/jest_workaround.wasm
    1: RuntimeError: unreachable
           at __rust_start_panic (<module>[1859]:0x7fcc7)
           at rust_panic (<module>[1855]:0x7fc7a)
           at std::panicking::rust_panic_with_hook::h53f3fdca929f741f (<module>[1854]:0x7fc4a)
           at std::panicking::begin_panic_handler::{{closure}}::hda540cd53c390dc8 (<module>[1843]:0x7f2f8)
           at std::sys_common::backtrace::__rust_end_short_backtrace::h70e30ae5ec54511f (<module>[1842]:0x7f222)
           at rust_begin_unwind (<module>[1849]:0x7f89f)
           at core::panicking::panic_fmt::he11703d1a35eb9c9 (<module>[1963]:0x8851e)
           at core::result::unwrap_failed::hdac82fff0478684f (<module>[1995]:0x8e702)
           at rkyv::impls::core::<impl rkyv::DeserializeUnsized<[U],D> for [T]>::deserialize_unsized::hc85c81db4df45160 (<module>[129]:0x1c9b6)
           at swc_ecma_ast::stmt::_::<impl rkyv::Deserialize<swc_ecma_ast::stmt::ForHead,__D> for <swc_ecma_ast::stmt::ForHead as rkyv::Archive>::Archived>::deserialize::hff45d62c04e9ac5b (<module>[163]:0x252d6)
           at swc_ecma_ast::stmt::_::<impl rkyv::Deserialize<swc_ecma_ast::stmt::Stmt,__D> for <swc_ecma_ast::stmt::Stmt as rkyv::Archive>::Archived>::deserialize::h220ba4715bb81d81 (<module>[151]:0x245be)
           at rkyv::impls::core::<impl rkyv::DeserializeUnsized<[U],D> for [T]>::deserialize_unsized::h12346709c41120da (<module>[152]:0x24b8b)
           at rkyv::impls::core::<impl rkyv::DeserializeUnsized<[U],D> for [T]>::deserialize_unsized::h8a04dcf2b030dc0e (<module>[383]:0x40d74)
           at rkyv::impls::core::<impl rkyv::DeserializeUnsized<T,D> for <T as rkyv::Archive>::Archived>::deserialize_unsized::h13661b86cad955b4 (<module>[126]:0x1bcb4)
           at swc_ecma_ast::decl::_::<impl rkyv::Deserialize<swc_ecma_ast::decl::Decl,__D> for <swc_ecma_ast::decl::Decl as rkyv::Archive>::Archived>::deserialize::hfc90dfb606fae481 (<module>[125]:0x1b0b4)
           at rkyv::impls::core::<impl rkyv::DeserializeUnsized<[U],D> for [T]>::deserialize_unsized::hc48f02ca6560408e (<module>[77]:0xbc38)
           at swc_ecma_ast::module::_::<impl rkyv::Deserialize<swc_ecma_ast::module::Program,__D> for <swc_ecma_ast::module::Program as rkyv::Archive>::Archived>::deserialize::h63f5759e9b58d816 (<module>[30]:0x2d8a)
           at swc_common::plugin::serialized::PluginSerializedBytes::deserialize::hc4e77da1b58a7da3 (<module>[28]:0x2cb4)
           at swc_common::plugin::serialized::deserialize_from_ptr::hd31b6b0e3a2e1472 (<module>[27]:0x2aa0)
           at __transform_plugin_process_impl (<module>[448]:0x4d807)', /usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/swc-0.260.46/src/plugin.rs:219:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Hope this trace helps, let me know if you need any additional information!

Cannot use it with yarn 3/pnp

Hi, @magic-akari
Seem that jest_workaround cannot work under yarn 3 pnp.
Here is a example to reproduce.

I have try pnpm, it works well. But when use package manager yarn 3, it cannot to run test successfully.
I have also try to run test using node 16/20, neither of them works.

Here is the error

 FAIL  src/calculate.spec.ts
  ● Test suite failed to run

    failed to get the node_modules path

      at Compiler.transformSync (.yarn/unplugged/@swc-core-virtual-4ff309335d/node_modules/@swc/core/index.js:241:29)
      at transformSync (.yarn/unplugged/@swc-core-virtual-4ff309335d/node_modules/@swc/core/index.js:348:21)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        0.241 s
Ran all test suites.

If I comment out the line, the test runs successfully.

Do I miss Any fatal config?

Failed to invoke plugin

Possibly need to be updated to the latest swc crates?

Started getting this after updating swc:

thread '<unnamed>' panicked at /Users/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/swc-0.270.26/src/plugin.rs:162:14:
failed to invoke plugin: failed to invoke plugin on 'Some("/Users/alexmiller/dev/app/node_modules/jest-runner/build/index.js")'

Caused by:
    0: failed to invoke `swc_mut_cjs_exports` as js transform plugin at swc_mut_cjs_exports
    1: RuntimeError: unreachable

Stack backtrace:
   0: _napi_register_module_v1
   1: _wasmer_vm_imported_memory32_atomic_notify
   2: _napi_register_module_v1
   3: _napi_register_module_v1
   4: _napi_register_module_v1
   5: _napi_register_module_v1
   6: _napi_register_module_v1

I had to update my own plugin too 😅

Optional chaining not transpiled properly

Hi there,

I'm completely stuck by enabling jest with swc because of an issue with optional chaining not being transpiled properly.

To reproduce the error, you can place in a test:

const foo = [1, 2, 3];
console.log(foo[2], foo?.[2]);

The result of that console log is 3, and undefined.

I think the problem is within this plugin as I already use swc to build my app and I checked the compiled javascript, which result in a correct working output.
There was recently an issue with swc that was not transpiling the optional chain.
So I also tried to upgrade the swc, cleared all the cache for swc and jest, and tried again with the same result.

TypeError when accessing exported member with "circular" dependency on barrel file

Issue

Note that module.type in the swc config is set to commonjs for this issue.

When a member (in this case, a TS enum) is re-exported in a barrel file and a sub-dependency of the barrel file imports that enum through the barrel file and tries to access it, a TypeError is thrown:

TypeError: Cannot read properties of undefined (reading 'A')

This is due to how swc_mut_cjs_exports groups all the require calls at the top of the transpiled file and then adds the keys to the exports object after all of those require.

// task.js
var _enumDep = /*#__PURE__*/ _interop_require_wildcard(require("./enumDep"));
var _anotherDep = /*#__PURE__*/ _interop_require_wildcard(require("./anotherDep"));

/* ...helper functions... */

Object.keys(_enumDep).forEach(function(key) {
    if (key === "default" || key === "__esModule") return;
    if (Object.prototype.hasOwnProperty.call(exports, key)) return;
    Object.defineProperty(exports, key, {
        enumerable: true,
        get: function get() {
            return _enumDep[key];
        },
        configurable: true
    });
});
Object.keys(_anotherDep).forEach(function(key) {
    if (key === "default" || key === "__esModule") return;
    if (Object.prototype.hasOwnProperty.call(exports, key)) return;
    Object.defineProperty(exports, key, {
        enumerable: true,
        get: function get() {
            return _anotherDep[key];
        },
        configurable: true
    });
});

./enumDep exports SomeEnum, and ./anotherDep eventually imports SomeEnum from the task.js barrel file. But since the keys for ./enumDep haven't been added to exports by the time ./anotherDep is required, the SomeEnum ends up being undefined.

Reproduction

I've set up a small repo with the reproduction of this and the README has info on the structure:
https://github.com/wadjoh/swc_mut_cjs_exports_debug_ts_enum

This is the structure of the TS code that causes an error when the transpiled code is executed:
bug_explanation

Potential Fix

When swc_mut_cjs_exports transpiles star exports, this issue can be avoided by adding the keys to the exports object immediately after the associated require call:

// task.js

// moved helper function definitions to the top
/* ...helper functions... */

// `exports` is populated with module keys immediately after the module's `require` call
var _enumDep = /*#__PURE__*/ _interop_require_wildcard(require("./enumDep"));
Object.keys(_enumDep).forEach(function(key) {
    if (key === "default" || key === "__esModule") return;
    if (Object.prototype.hasOwnProperty.call(exports, key)) return;
    Object.defineProperty(exports, key, {
        enumerable: true,
        get: function get() {
            return _enumDep[key];
        },
        configurable: true
    });
});

var _anotherDep = /*#__PURE__*/ _interop_require_wildcard(require("./anotherDep"));
Object.keys(_anotherDep).forEach(function(key) {
    if (key === "default" || key === "__esModule") return;
    if (Object.prototype.hasOwnProperty.call(exports, key)) return;
    Object.defineProperty(exports, key, {
        enumerable: true,
        get: function get() {
            return _anotherDep[key];
        },
        configurable: true
    });
});

I have manually modified output code in the linked reproduction repo that works fine when executed: https://github.com/wadjoh/swc_mut_cjs_exports_debug_ts_enum/blob/main/results/fixed_output_with_plugin/task.js

Change the plugin name to something unrelated to Jest?

I came across this plugin when searching for ways of changing the output of SWC so that exports would be mutable. This seemed to do just that, but the naming seemed to imply it was Jest specific. As you told me in #65, it is not Jest specific at all and should work out of the box! I then demonstrated it actually works fine with Mocha (and any other general tool that would register this module before running).

So ... that left me wondering: why on Earth should this still be called jest_workaround? That name is neither telling in what it does nor true to the implication of it being Jest specific. It's a general plugin to alter SWC's common js output. So I suggest renaming it to something like swc-plugin-mutable-cjs-exports. It would make it much more apparent that it is generally applicable and one could still market it for Jest as before, but also any other tool.

RuntimeError: unreachable with 0.75.4 and swc/core of 1.3.57

Caused by:
0: failed to invoke jest_workaround as js transform plugin at node_modules/jest_workaround/jest_workaround.wasm
1: RuntimeError: unreachable
at Compiler.transformSync (/Users/scamden/watershed/ghg/node_modules/.pnpm/@swc+core@1.3.57_@swc[email protected]/node_modules/@swc/core/index.js:241:29)
at transformSync (/Users/scamden/watershed/ghg/node_modules/.pnpm/@swc+core@1.3.57_@swc[email protected]/node_modules/@swc/core/index.js:348:21)
at Object.process (/Users/scamden/watershed/ghg/node_modules/.pnpm/@swc+jest@0.2.26_@swc[email protected]/node_modules/@swc/jest/index.js:73:45)
at ScriptTransformer.transformSource (/Users/scamden/watershed/ghg/node_modules/.pnpm/@jest[email protected]/node_modules/@jest/transform/build/ScriptTransformer.js:542:31)
at revertHook.exts (/Users/scamden/watershed/ghg/node_modules/.pnpm/@jest[email protected]/node_modules/@jest/transform/build/ScriptTransformer.js:773:18)
at Module._compile (/Users/scamden/watershed/ghg/node_modules/.pnpm/[email protected]/node_modules/pirates/lib/index.js:130:29)
at Module._extensions..js (node:internal/modules/cjs/loader:1213:10)
at Object.newLoader (/Users/scamden/watershed/ghg/node_modules/.pnpm/[email protected]/node_modules/pirates/lib/index.js:141:7)
at Module.load (node:internal/modules/cjs/loader:1037:32)
at Module._load (node:internal/modules/cjs/loader:878:12)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.