├── jest.setup.js ├── test ├── fixtures │ ├── export_async │ │ ├── src │ │ │ ├── rust │ │ │ │ ├── empty_code │ │ │ │ │ ├── lib.rs │ │ │ │ │ └── Cargo.toml │ │ │ │ └── single_function │ │ │ │ │ ├── lib.rs │ │ │ │ │ └── Cargo.toml │ │ │ └── index.js │ │ ├── jest.config.js │ │ └── test │ │ │ └── index.spec.js │ ├── export_buffer │ │ ├── src │ │ │ ├── rust │ │ │ │ ├── empty_code │ │ │ │ │ ├── lib.rs │ │ │ │ │ └── Cargo.toml │ │ │ │ └── single_function │ │ │ │ │ ├── lib.rs │ │ │ │ │ └── Cargo.toml │ │ │ └── index.js │ │ ├── jest.config.js │ │ └── test │ │ │ └── index.spec.js │ ├── export_instance │ │ ├── src │ │ │ ├── rust │ │ │ │ ├── empty_code │ │ │ │ │ ├── lib.rs │ │ │ │ │ └── Cargo.toml │ │ │ │ └── single_function │ │ │ │ │ ├── lib.rs │ │ │ │ │ └── Cargo.toml │ │ │ └── index.js │ │ ├── jest.config.js │ │ └── test │ │ │ └── index.spec.js │ ├── export_module │ │ ├── src │ │ │ ├── rust │ │ │ │ ├── empty_code │ │ │ │ │ ├── lib.rs │ │ │ │ │ └── Cargo.toml │ │ │ │ └── single_function │ │ │ │ │ ├── lib.rs │ │ │ │ │ └── Cargo.toml │ │ │ └── index.js │ │ ├── jest.config.js │ │ └── test │ │ │ └── index.spec.js │ ├── export_async-instance │ │ ├── src │ │ │ ├── rust │ │ │ │ ├── empty_code │ │ │ │ │ ├── lib.rs │ │ │ │ │ └── Cargo.toml │ │ │ │ └── single_function │ │ │ │ │ ├── lib.rs │ │ │ │ │ └── Cargo.toml │ │ │ └── index.js │ │ ├── jest.config.js │ │ └── test │ │ │ └── index.spec.js │ ├── export_async-module │ │ ├── src │ │ │ ├── rust │ │ │ │ ├── empty_code │ │ │ │ │ ├── lib.rs │ │ │ │ │ └── Cargo.toml │ │ │ │ └── single_function │ │ │ │ │ ├── lib.rs │ │ │ │ │ └── Cargo.toml │ │ │ └── index.js │ │ ├── jest.config.js │ │ └── test │ │ │ └── index.spec.js │ └── utils.js ├── export.test.ts ├── utils.ts └── shim.d.ts ├── examples └── stencil │ ├── src │ ├── components │ │ └── my-component │ │ │ ├── my-component.css │ │ │ ├── lib.rs │ │ │ ├── Cargo.toml │ │ │ ├── my-component.tsx │ │ │ └── my-component.spec.ts │ ├── wasm.d.ts │ ├── index.html │ └── components.d.ts │ ├── .editorconfig │ ├── stencil.config.ts │ ├── tsconfig.json │ ├── LICENSE │ ├── package.json │ └── readme.md ├── src ├── utils │ ├── constants.ts │ ├── index.ts │ ├── permissive-exec.ts │ ├── get-cache-key.ts │ └── logger.ts ├── index.ts ├── options.ts ├── shim.d.ts ├── preprocess.ts └── cargo.ts ├── index.d.ts ├── .huskyrc.json ├── .babelrc ├── .editorconfig ├── tsconfig.json ├── tslint.json ├── jest.config.js ├── .prettierrc.json ├── CHANGELOG.md ├── .commitlintrc.json ├── .gitignore ├── LICENSE.md ├── rollup.config.js ├── .github ├── WORKFLOW.md ├── HACKING.md └── CONTRIBUTING.md ├── package.json ├── .circleci └── config.yml └── README.md /jest.setup.js: -------------------------------------------------------------------------------- 1 | jest.setTimeout(10000); 2 | -------------------------------------------------------------------------------- /test/fixtures/export_async/src/rust/empty_code/lib.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/export_buffer/src/rust/empty_code/lib.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/export_instance/src/rust/empty_code/lib.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/export_module/src/rust/empty_code/lib.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/stencil/src/components/my-component/my-component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/export_async-instance/src/rust/empty_code/lib.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/export_async-module/src/rust/empty_code/lib.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/stencil/src/components/my-component/lib.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | pub fn add(a: i32, b: i32) -> i32 { 3 | a + b 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/export_async/src/rust/single_function/lib.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | pub fn add(a: u8, b: u8) -> u8 { 3 | a + b 4 | } -------------------------------------------------------------------------------- /test/fixtures/export_buffer/src/rust/single_function/lib.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | pub fn add(a: u8, b: u8) -> u8 { 3 | a + b 4 | } -------------------------------------------------------------------------------- /test/fixtures/export_module/src/rust/single_function/lib.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | pub fn add(a: u8, b: u8) -> u8 { 3 | a + b 4 | } -------------------------------------------------------------------------------- /test/fixtures/export_instance/src/rust/single_function/lib.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | pub fn add(a: u8, b: u8) -> u8 { 3 | a + b 4 | } -------------------------------------------------------------------------------- /test/fixtures/export_async-instance/src/rust/single_function/lib.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | pub fn add(a: u8, b: u8) -> u8 { 3 | a + b 4 | } -------------------------------------------------------------------------------- /test/fixtures/export_async-module/src/rust/single_function/lib.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | pub fn add(a: u8, b: u8) -> u8 { 3 | a + b 4 | } -------------------------------------------------------------------------------- /src/utils/constants.ts: -------------------------------------------------------------------------------- 1 | export enum Constant { 2 | GLOBALS_KEY = 'rs-jest', 3 | CONFIGFILE = 'cargo.toml', 4 | LOGFILE = 'rs-jest.log' 5 | } 6 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare interface RsJest extends jest.Transformer { 2 | createTransformer(options?: any): jest.Transformer; 3 | } 4 | 5 | export = RsJest; 6 | -------------------------------------------------------------------------------- /test/fixtures/export_async/src/index.js: -------------------------------------------------------------------------------- 1 | exports.from_empty_code = require('./rust/empty_code/lib.rs'); 2 | exports.from_single_function = require('./rust/single_function/lib.rs'); 3 | -------------------------------------------------------------------------------- /test/fixtures/export_buffer/src/index.js: -------------------------------------------------------------------------------- 1 | exports.from_empty_code = require('./rust/empty_code/lib.rs'); 2 | exports.from_single_function = require('./rust/single_function/lib.rs'); 3 | -------------------------------------------------------------------------------- /test/fixtures/export_instance/src/index.js: -------------------------------------------------------------------------------- 1 | exports.from_empty_code = require('./rust/empty_code/lib.rs'); 2 | exports.from_single_function = require('./rust/single_function/lib.rs'); 3 | -------------------------------------------------------------------------------- /test/fixtures/export_module/src/index.js: -------------------------------------------------------------------------------- 1 | exports.from_empty_code = require('./rust/empty_code/lib.rs'); 2 | exports.from_single_function = require('./rust/single_function/lib.rs'); 3 | -------------------------------------------------------------------------------- /test/fixtures/export_async-instance/src/index.js: -------------------------------------------------------------------------------- 1 | exports.from_empty_code = require('./rust/empty_code/lib.rs'); 2 | exports.from_single_function = require('./rust/single_function/lib.rs'); 3 | -------------------------------------------------------------------------------- /test/fixtures/export_async-module/src/index.js: -------------------------------------------------------------------------------- 1 | exports.from_empty_code = require('./rust/empty_code/lib.rs'); 2 | exports.from_single_function = require('./rust/single_function/lib.rs'); 3 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './logger'; 2 | export { default as execPermissive } from './permissive-exec'; 3 | export { default as getCacheKey } from './get-cache-key'; 4 | export * from './constants'; 5 | -------------------------------------------------------------------------------- /.huskyrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "pre-commit": "pretty-quick --staged && tsc --pretty -p . --noemit && lint-staged", 4 | "commit-msg": "commitlint -e $HUSKY_GIT_PARAMS", 5 | "post-commit": "git update-index --again" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/stencil/src/wasm.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.rs' { 2 | global { 3 | namespace WebAssembly { 4 | interface Instance { 5 | exports: any; 6 | } 7 | } 8 | } 9 | 10 | const wasm: WebAssembly.Instance; 11 | export default wasm; 12 | } 13 | -------------------------------------------------------------------------------- /examples/stencil/src/components/my-component/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "adder" 3 | version = "0.1.0" 4 | authors = ["Fahmi Akbar Wildana "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | path = "lib.rs" 9 | 10 | [profile.release] 11 | lto = true 12 | -------------------------------------------------------------------------------- /test/fixtures/export_async/src/rust/empty_code/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "empty_code" 3 | version = "0.0.0" 4 | authors = ["Fahmi Akbar Wildana "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | path = 'lib.rs' 9 | 10 | [profile.release] 11 | lto = true -------------------------------------------------------------------------------- /test/fixtures/export_buffer/src/rust/empty_code/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "empty_code" 3 | version = "0.0.0" 4 | authors = ["Fahmi Akbar Wildana "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | path = 'lib.rs' 9 | 10 | [profile.release] 11 | lto = true -------------------------------------------------------------------------------- /test/fixtures/export_instance/src/rust/empty_code/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "empty_code" 3 | version = "0.0.0" 4 | authors = ["Fahmi Akbar Wildana "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | path = 'lib.rs' 9 | 10 | [profile.release] 11 | lto = true -------------------------------------------------------------------------------- /test/fixtures/export_module/src/rust/empty_code/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "empty_code" 3 | version = "0.0.0" 4 | authors = ["Fahmi Akbar Wildana "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | path = 'lib.rs' 9 | 10 | [profile.release] 11 | lto = true -------------------------------------------------------------------------------- /test/fixtures/export_async-instance/src/rust/empty_code/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "empty_code" 3 | version = "0.0.0" 4 | authors = ["Fahmi Akbar Wildana "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | path = 'lib.rs' 9 | 10 | [profile.release] 11 | lto = true -------------------------------------------------------------------------------- /test/fixtures/export_async-module/src/rust/empty_code/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "empty_code" 3 | version = "0.0.0" 4 | authors = ["Fahmi Akbar Wildana "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | path = 'lib.rs' 9 | 10 | [profile.release] 11 | lto = true -------------------------------------------------------------------------------- /test/fixtures/export_async/src/rust/single_function/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "single_function" 3 | version = "0.0.0" 4 | authors = ["Fahmi Akbar Wildana "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | path = 'lib.rs' 9 | 10 | [profile.release] 11 | lto = true -------------------------------------------------------------------------------- /test/fixtures/export_buffer/src/rust/single_function/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "single_function" 3 | version = "0.0.0" 4 | authors = ["Fahmi Akbar Wildana "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | path = 'lib.rs' 9 | 10 | [profile.release] 11 | lto = true -------------------------------------------------------------------------------- /test/fixtures/export_instance/src/rust/single_function/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "single_function" 3 | version = "0.0.0" 4 | authors = ["Fahmi Akbar Wildana "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | path = 'lib.rs' 9 | 10 | [profile.release] 11 | lto = true -------------------------------------------------------------------------------- /test/fixtures/export_module/src/rust/single_function/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "single_function" 3 | version = "0.0.0" 4 | authors = ["Fahmi Akbar Wildana "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | path = 'lib.rs' 9 | 10 | [profile.release] 11 | lto = true -------------------------------------------------------------------------------- /test/fixtures/export_async-instance/src/rust/single_function/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "single_function" 3 | version = "0.0.0" 4 | authors = ["Fahmi Akbar Wildana "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | path = 'lib.rs' 9 | 10 | [profile.release] 11 | lto = true -------------------------------------------------------------------------------- /test/fixtures/export_async-module/src/rust/single_function/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "single_function" 3 | version = "0.0.0" 4 | authors = ["Fahmi Akbar Wildana "] 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | path = 'lib.rs' 9 | 10 | [profile.release] 11 | lto = true -------------------------------------------------------------------------------- /test/fixtures/export_async/jest.config.js: -------------------------------------------------------------------------------- 1 | const {rsJestScriptPath} = require("../utils") 2 | 3 | module.exports = { 4 | testEnvironment: "node", 5 | globals: { 6 | "rs-jest": { 7 | export: "async" 8 | } 9 | }, 10 | transform: { 11 | "^.+\\.rs$": rsJestScriptPath 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/export_buffer/jest.config.js: -------------------------------------------------------------------------------- 1 | const {rsJestScriptPath} = require("../utils") 2 | 3 | module.exports = { 4 | testEnvironment: "node", 5 | globals: { 6 | "rs-jest": { 7 | export: "buffer" 8 | } 9 | }, 10 | transform: { 11 | "^.+\\.rs$": rsJestScriptPath 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/export_module/jest.config.js: -------------------------------------------------------------------------------- 1 | const {rsJestScriptPath} = require("../utils") 2 | 3 | module.exports = { 4 | testEnvironment: "node", 5 | globals: { 6 | "rs-jest": { 7 | export: "module" 8 | } 9 | }, 10 | transform: { 11 | "^.+\\.rs$": rsJestScriptPath 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/export_instance/jest.config.js: -------------------------------------------------------------------------------- 1 | const {rsJestScriptPath} = require("../utils") 2 | 3 | module.exports = { 4 | testEnvironment: "node", 5 | globals: { 6 | "rs-jest": { 7 | export: "instance" 8 | } 9 | }, 10 | transform: { 11 | "^.+\\.rs$": rsJestScriptPath 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["@babel/env", { 4 | "targets": {"node": 8}, 5 | "modules": false 6 | }], "@babel/typescript" 7 | ], 8 | "plugins": [ 9 | "@babel/proposal-export-namespace-from", 10 | "@babel/proposal-class-properties", 11 | "@babel/proposal-object-rest-spread" 12 | ] 13 | } -------------------------------------------------------------------------------- /test/fixtures/export_async-instance/jest.config.js: -------------------------------------------------------------------------------- 1 | const {rsJestScriptPath} = require("../utils") 2 | 3 | module.exports = { 4 | testEnvironment: "node", 5 | globals: { 6 | "rs-jest": { 7 | export: "async-instance" 8 | } 9 | }, 10 | transform: { 11 | "^.+\\.rs$": rsJestScriptPath 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/export_async-module/jest.config.js: -------------------------------------------------------------------------------- 1 | const {rsJestScriptPath} = require("../utils") 2 | 3 | module.exports = { 4 | testEnvironment: "node", 5 | globals: { 6 | "rs-jest": { 7 | export: "async-module" 8 | } 9 | }, 10 | transform: { 11 | "^.+\\.rs$": rsJestScriptPath 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/stencil/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | insert_final_newline = false 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /examples/stencil/stencil.config.ts: -------------------------------------------------------------------------------- 1 | import {Config} from "@stencil/core" 2 | import rust from "rollup-plugin-rust" 3 | 4 | export const config: Config = { 5 | namespace: "mycomponent", 6 | outputTargets: [ 7 | { 8 | type: "dist" 9 | }, 10 | { 11 | type: "www", 12 | serviceWorker: null 13 | } 14 | ], 15 | plugins: [rust({export: "instance"})] 16 | } 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.config.js] 4 | indent_style = tab 5 | indent_size = 4 6 | insert_final_newline = false 7 | 8 | [{src, test}/**.{ts, js}] 9 | indent_style = space 10 | indent_size = 2 11 | insert_final_newline = true 12 | 13 | [*{rc, json, config}] 14 | indent_style = tab 15 | indent_size = 4 16 | insert_final_newline = false 17 | 18 | [*.md] 19 | indent_size = 2 -------------------------------------------------------------------------------- /examples/stencil/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Stencil Component Starter 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/stencil/src/components/my-component/my-component.tsx: -------------------------------------------------------------------------------- 1 | import { Component, Prop } from "@stencil/core"; 2 | import wasm from "./lib.rs"; 3 | 4 | @Component({ 5 | tag: "my-component", 6 | styleUrl: "my-component.css", 7 | shadow: true 8 | }) 9 | export class MyComponent { 10 | @Prop() 11 | a: number; 12 | @Prop() 13 | b: number; 14 | 15 | render() { 16 | return
Hello, World! I'm {wasm.exports.add(this.a, this.b)}
; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { getCacheKey } from './utils'; 2 | import process from './preprocess'; 3 | 4 | const createTransformer = (options?: any): jest.Transformer => { 5 | // options are always empty, must be the older jest API giving options here 6 | return { 7 | canInstrument: true, 8 | getCacheKey, 9 | process, 10 | createTransformer: undefined as any 11 | }; 12 | }; 13 | 14 | module.exports = createTransformer(); 15 | module.exports.createTransformer = createTransformer; 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "target": "esnext", 5 | "module": "commonjs", 6 | "lib": ["esnext", "dom"], 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "allowSyntheticDefaultImports": true, 10 | "experimentalDecorators": true, 11 | "emitDecoratorMetadata": true, 12 | "outDir": "dist", 13 | "typeRoots": ["node_modules/@types"] 14 | }, 15 | "include": ["src", "test", "index.d.ts"], 16 | "exclude": ["node_modules", "examples"] 17 | } 18 | -------------------------------------------------------------------------------- /examples/stencil/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "allowUnreachableCode": false, 5 | "declaration": false, 6 | "experimentalDecorators": true, 7 | "lib": ["dom", "es2017"], 8 | "moduleResolution": "node", 9 | "module": "es2015", 10 | "target": "es2017", 11 | "noUnusedLocals": true, 12 | "noUnusedParameters": true, 13 | "jsx": "react", 14 | "jsxFactory": "h" 15 | }, 16 | "include": ["src", "types/jsx.d.ts", "stencil.config.ts"], 17 | "exclude": ["node_modules"] 18 | } 19 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": ["tslint:recommended", "tslint-config-prettier"], 4 | "linterOptions": { 5 | "exclude": ["node_modules/**", "examples/**"] 6 | }, 7 | "rules": { 8 | "quotemark": [true, "single", "avoid-escape"], 9 | "indent": [true, "spaces", 2], 10 | "interface-name": false, 11 | "ordered-imports": false, 12 | "object-literal-sort-keys": false, 13 | "no-consecutive-blank-lines": true, 14 | "no-console": false, 15 | "curly": [true, "ignore-same-line"], 16 | "semicolon": [true, "always"] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: "node", 3 | globals: { 4 | "ts-jest": { 5 | useBabelrc: true 6 | } 7 | }, 8 | transform: { 9 | "^.+\\.tsx?$": "ts-jest" 10 | }, 11 | testPathIgnorePatterns: [ 12 | "/test/fixtures", 13 | "/examples", 14 | "/node_modules/" 15 | ], 16 | coveragePathIgnorePatterns: [".*\\.d\\.ts", "/node_modules/"], 17 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 18 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 19 | setupTestFrameworkScriptFile: "./jest.setup.js" 20 | } 21 | -------------------------------------------------------------------------------- /src/utils/permissive-exec.ts: -------------------------------------------------------------------------------- 1 | import { execSync } from 'child_process'; 2 | 3 | /** Execute command in permissive environment 4 | * @param cmd command to execute 5 | * @param cwd current working directory where the command is executed 6 | * @example const result = execPermissive('cargo build', '/root/projects/mine') 7 | */ 8 | export default function execPermissive(cmd: string, cwd: string) { 9 | try { 10 | return execSync(cmd, { 11 | cwd, 12 | encoding: 'utf-8', 13 | maxBuffer: 2 * 1024 * 1024 * 1024 14 | }); 15 | } catch (error) { 16 | return error; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/fixtures/export_instance/test/index.spec.js: -------------------------------------------------------------------------------- 1 | const { getExportedFunctions } = require('../../utils'); 2 | 3 | describe('test mode {export: "instance"} should export Rust code as WebAssembly.Instance', () => { 4 | test('empty_code', () => { 5 | const wasm_instance = require('../src').from_empty_code; 6 | 7 | expect(wasm_instance).toBeInstanceOf(WebAssembly.Instance); 8 | }); 9 | 10 | test('single_function', () => { 11 | const wasm_instance = require('../src').from_single_function; 12 | 13 | expect(wasm_instance).toBeInstanceOf(WebAssembly.Instance); 14 | expect(wasm_instance.exports.add(1, 2)).toBe(3); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /test/fixtures/utils.js: -------------------------------------------------------------------------------- 1 | exports.rsJestScriptPath = '../../../dist/index.js'; 2 | 3 | /** Get list of exported functions from instance of `WebAssembly.Module` 4 | * @param {WebAssembly.Module} wasm_module instance of `WebAssembly.Module` 5 | * @return {Array} list of exported functions 6 | * @example const func_list = getExportedFunctions(new WebAssembly.Module([0x00,0x61,0x73,0x6d,0x01,0,0,0])); 7 | */ 8 | exports.getExportedFunctions = wasm_module => 9 | WebAssembly.Module.exports(wasm_module) 10 | .filter( 11 | obj => obj.kind === 'function' && obj.name !== 'rust_eh_personality' 12 | ) 13 | .map(obj => obj.name); 14 | -------------------------------------------------------------------------------- /test/export.test.ts: -------------------------------------------------------------------------------- 1 | /// https://stackoverflow.com/a/50856790/5221998 2 | import { resolve } from './utils'; 3 | import { basename } from 'path'; 4 | import jest_please = require('jest'); 5 | 6 | describe('test export mode', () => { 7 | const options = { 8 | reporters: [['jest-silent-reporter', { useDots: true }]] 9 | } as jestCLI.Options; 10 | 11 | const fixture = resolve('fixtures/export_*'); 12 | const projects = fixture.map((s, i) => [basename(s).replace('_', ' as '), i]); 13 | 14 | test.each(projects)(`%s`, async (s, i) => { 15 | const { results } = await jest_please.runCLI(options, [fixture[i]]); 16 | expect(results.success).toBe(true); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "excludeFiles": "*.config.js", 5 | "files": "*.js", 6 | "options": { 7 | "parser": "babylon", 8 | "singleQuote": true, 9 | "bracketSpacing": true 10 | } 11 | }, 12 | { 13 | "excludeFiles": "*.config.ts", 14 | "files": "*.ts", 15 | "options": { 16 | "parser": "typescript", 17 | "singleQuote": true, 18 | "bracketSpacing": true 19 | } 20 | }, 21 | { 22 | "files": ["*.json", ".*rc", ".*.json"], 23 | "options": { 24 | "parser": "json", 25 | "useTabs": true 26 | } 27 | }, 28 | { 29 | "files": ["*.config.js", "*.config.ts"], 30 | "options": { 31 | "useTabs": true, 32 | "bracketSpacing": false, 33 | "semi": false 34 | } 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | 6 | 7 | # [1.1.0](https://github.com/DrSensor/rs-jest/compare/v1.0.0...v1.1.0) (2018-10-17) 8 | 9 | ### Features 10 | 11 | - use webassembly-loader internally ([#8](https://github.com/DrSensor/rs-jest/issues/8)) ([995ced6](https://github.com/DrSensor/rs-jest/commit/995ced6)) 12 | 13 | 14 | 15 | # 1.0.0 (2018-09-06) 16 | 17 | ### Features 18 | 19 | - **wasm:** add feature to convert Rust into Wasm ([c3597a6](https://github.com/DrSensor/rs-jest/commit/c3597a6)) 20 | 21 | 22 | 23 | # 0.0.0 (2018-08-29) 24 | -------------------------------------------------------------------------------- /src/options.ts: -------------------------------------------------------------------------------- 1 | import { Constant } from './utils'; 2 | 3 | /** Default options for rs-jest */ 4 | export const defaultConfig: RsJestConfig = { 5 | target: 'wasm32-unknown-unknown', 6 | release: true, 7 | export: 'async' 8 | }; 9 | 10 | /** Get this transformer configuration from globals['rs-jest'] 11 | * @see https://jestjs.io/docs/en/configuration.html#globals-object 12 | * 13 | * @param {jest.ProjectConfig|jest.InitialOptions} jestConfig jest Config Options 14 | * @returns {RsJestConfig} globals['rs-jest'] parameters/keys 15 | * @example const {export} = getConfigFrom(jestConfig); 16 | */ 17 | export function getConfigFrom( 18 | jestConfig: jest.ProjectConfig | jest.InitialOptions 19 | ): Partial { 20 | return (jestConfig.globals && jestConfig.globals[Constant.GLOBALS_KEY]) || {}; 21 | } 22 | -------------------------------------------------------------------------------- /test/fixtures/export_async-instance/test/index.spec.js: -------------------------------------------------------------------------------- 1 | const { getExportedFunctions } = require('../../utils'); 2 | 3 | describe('test mode {export: "async-instance"} should export Rust code as (() => WebAssembly.instantiate(wasmModule))', () => { 4 | test('empty_code', async () => { 5 | const wasm_instantiate = require('../src').from_empty_code; 6 | 7 | const wasm_instance = await wasm_instantiate(); 8 | 9 | expect(wasm_instance).toBeInstanceOf(WebAssembly.Instance); 10 | }); 11 | 12 | test('single_function', async () => { 13 | const wasm_instantiate = require('../src').from_single_function; 14 | 15 | const wasm_instance = await wasm_instantiate(); 16 | 17 | expect(wasm_instance).toBeInstanceOf(WebAssembly.Instance); 18 | expect(wasm_instance.exports.add(1, 2)).toBe(3); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/shim.d.ts: -------------------------------------------------------------------------------- 1 | // tslint:disable:no-namespace 2 | 3 | //#region polyfill 4 | namespace Webpack { 5 | namespace Loader { 6 | interface Context { 7 | emitWarning(warning: Error); 8 | emitError(error: Error); 9 | addDependency(file: string); 10 | } 11 | } 12 | } 13 | //#endregion 14 | 15 | interface JestCacheKeyOptions { 16 | rootDir: string; 17 | instrument: boolean; 18 | } 19 | 20 | interface RsJestConfig { 21 | target: string; // use by rust-native-wasm-loader 22 | release: boolean; // use by rust-native-wasm-loader 23 | export: 24 | | 'buffer' 25 | | 'instance' 26 | | 'module' 27 | | 'async' 28 | | 'async-instance' 29 | | 'async-module'; 30 | } 31 | 32 | declare namespace jest { 33 | interface ConfigGlobals { 34 | 'rs-jest': Partial; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.commitlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@commitlint/config-conventional"], 3 | 4 | "rules": { 5 | "body-leading-blank": [1, "always"], 6 | "footer-leading-blank": [1, "always"], 7 | "header-max-length": [2, "always", 72], 8 | "scope-case": [2, "always", "lower-case"], 9 | "subject-case": [ 10 | 2, 11 | "never", 12 | ["sentence-case", "start-case", "pascal-case", "upper-case"] 13 | ], 14 | "subject-empty": [2, "never"], 15 | "subject-full-stop": [2, "never", "."], 16 | "type-case": [2, "always", "lower-case"], 17 | "type-empty": [2, "never"], 18 | "type-enum": [ 19 | 2, 20 | "always", 21 | [ 22 | "build", 23 | "chore", 24 | "ci", 25 | "docs", 26 | "feat", 27 | "fix", 28 | "perf", 29 | "refactor", 30 | "revert", 31 | "style", 32 | "test" 33 | ] 34 | ] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/utils.ts: -------------------------------------------------------------------------------- 1 | import { resolve as r } from 'path'; 2 | import { hasMagic as globbable, sync as glob } from 'glob'; 3 | 4 | /** Just like path.resolve(__dirname, path) but can be use for array of path with glob pattern 5 | * @param relativePaths array of paths that are relative with the current file 6 | * @returns array of fullpath 7 | * @example const paths: string[] = resolve(['fixtures/exports/*', 'fixtures/simple']) 8 | */ 9 | export function resolve(relativePaths: string[] | string): string[] { 10 | if (Array.isArray(relativePaths)) { 11 | relativePaths.forEach((path, index) => { 12 | if (globbable(path)) { 13 | (relativePaths as string[]).splice(index, 1, ...glob(path)); 14 | } 15 | }); 16 | } else { 17 | relativePaths = globbable(relativePaths) 18 | ? glob(r(__dirname, relativePaths)) 19 | : [relativePaths]; 20 | } 21 | 22 | return relativePaths.map(path => r(__dirname, path)); 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .utopian/ 2 | .NOTE.md 3 | 4 | # Smoke Test 5 | examples/**/*-lock.* 6 | examples/**/*.lock 7 | examples/**/node_modules 8 | examples/**/.stencil 9 | examples/**/www 10 | examples/**/target 11 | 12 | # Rust 13 | *.lock 14 | **/target/ 15 | 16 | # build result 17 | dist/ 18 | 19 | # cached process of `eslint --cache` 20 | *cache 21 | 22 | # Logs 23 | logs 24 | *.log 25 | npm-debug.log* 26 | 27 | # Runtime data 28 | pids 29 | *.pid 30 | *.seed 31 | 32 | # Directory for instrumented libs generated by jscoverage/JSCover 33 | lib-cov 34 | 35 | # Coverage directory used by tools like istanbul 36 | coverage 37 | 38 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 39 | .grunt 40 | 41 | # node-waf configuration 42 | .lock-wscript 43 | 44 | # Compiled binary addons (http://nodejs.org/api/addons.html) 45 | build/Release 46 | 47 | # Dependency directory 48 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git 49 | node_modules -------------------------------------------------------------------------------- /examples/stencil/src/components/my-component/my-component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestWindow } from '@stencil/core/testing'; 2 | import { MyComponent } from './my-component'; 3 | 4 | describe('my-component', () => { 5 | it('should build', () => { 6 | expect(new MyComponent()).toBeTruthy(); 7 | }); 8 | 9 | describe('rendering', () => { 10 | let element: HTMLMyComponentElement; 11 | let testWindow: TestWindow; 12 | beforeEach(async () => { 13 | testWindow = new TestWindow(); 14 | element = await testWindow.load({ 15 | components: [MyComponent], 16 | html: '' 17 | }); 18 | }); 19 | 20 | it('should work without parameters', () => { 21 | expect(element.textContent.trim()).toEqual("Hello, World! I'm 0"); 22 | }); 23 | 24 | it('should work with both `a` and `b`', async () => { 25 | element.a = 1; 26 | element.b = 2; 27 | await testWindow.flush(); 28 | expect(element.textContent.trim()).toEqual("Hello, World! I'm 3"); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /examples/stencil/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ionic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/fixtures/export_async/test/index.spec.js: -------------------------------------------------------------------------------- 1 | const { getExportedFunctions } = require('../../utils'); 2 | 3 | describe('test mode {export: "async"} should export Rust code as (() => WebAssembly.instantiate(wasmCode))', () => { 4 | test('empty_code', async () => { 5 | const wasm_instantiate = require('../src').from_empty_code; 6 | 7 | const { instance, module } = await wasm_instantiate(); 8 | const exported_functions = getExportedFunctions(module); 9 | 10 | expect(instance).toBeInstanceOf(WebAssembly.Instance); 11 | expect(module).toBeInstanceOf(WebAssembly.Module); 12 | expect(exported_functions).toEqual([]); 13 | }); 14 | 15 | test('single_function', async () => { 16 | const wasm_instantiate = require('../src').from_single_function; 17 | 18 | const { instance, module } = await wasm_instantiate(); 19 | const exported_functions = getExportedFunctions(module); 20 | 21 | expect(instance).toBeInstanceOf(WebAssembly.Instance); 22 | expect(module).toBeInstanceOf(WebAssembly.Module); 23 | expect(exported_functions).toEqual(['add']); 24 | expect(instance.exports.add(1, 2)).toBe(3); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/fixtures/export_module/test/index.spec.js: -------------------------------------------------------------------------------- 1 | const { getExportedFunctions } = require('../../utils'); 2 | 3 | describe('test mode {export: "module"} should export Rust code as WebAssembly.Module', () => { 4 | test('empty_code', () => { 5 | const wasm_module = require('../src').from_empty_code; 6 | 7 | const wasm_instance = new WebAssembly.Instance(wasm_module); 8 | const exported_functions = getExportedFunctions(wasm_module); 9 | 10 | expect(wasm_module).toBeInstanceOf(WebAssembly.Module); 11 | expect(wasm_instance).toBeInstanceOf(WebAssembly.Instance); 12 | expect(exported_functions).toEqual([]); 13 | }); 14 | 15 | test('single_function', () => { 16 | const wasm_module = require('../src').from_single_function; 17 | 18 | const wasm_instance = new WebAssembly.Instance(wasm_module); 19 | const exported_functions = getExportedFunctions(wasm_module); 20 | 21 | expect(wasm_module).toBeInstanceOf(WebAssembly.Module); 22 | expect(wasm_instance).toBeInstanceOf(WebAssembly.Instance); 23 | expect(exported_functions).toEqual(['add']); 24 | expect(wasm_instance.exports.add(1, 2)).toBe(3); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import {dirname} from "path" 2 | import {mv} from "shelljs" 3 | import pkg from "./package.json" 4 | import prc from "./.prettierrc.json" 5 | 6 | import commonjs from "rollup-plugin-commonjs" 7 | import resolve from "rollup-plugin-node-resolve" 8 | import autoExternal from "rollup-plugin-auto-external" 9 | import babel from "rollup-plugin-babel" 10 | import prettier from "rollup-plugin-prettier" 11 | import typescript from "rollup-plugin-typescript2" 12 | 13 | // #region helper 14 | let {overrides, ...options} = prc 15 | const prettierrc = { 16 | options: options, 17 | files: files => overrides.find(p => p.files === files).options 18 | } 19 | // #endregion 20 | 21 | // Rollup Configuration 22 | export default [ 23 | { 24 | input: { 25 | index: "src/index.ts", 26 | cargo: "src/cargo.ts" 27 | }, 28 | output: { 29 | dir: dirname(pkg.main), 30 | format: "cjs", 31 | exports: "named" 32 | }, 33 | experimentalCodeSplitting: true, 34 | plugins: [ 35 | typescript({ 36 | exclude: ["test/**"], 37 | tsconfigOverride: {compilerOptions: {module: "esnext"}} 38 | }), 39 | babel(), 40 | commonjs(), 41 | resolve(), 42 | autoExternal(), 43 | prettier(prettierrc.files("*.js")) 44 | ] 45 | } 46 | ] 47 | -------------------------------------------------------------------------------- /test/fixtures/export_async-module/test/index.spec.js: -------------------------------------------------------------------------------- 1 | const { getExportedFunctions } = require('../../utils'); 2 | 3 | describe('test mode {export: "async-module"} should be exported as (() => WebAssembly.compile(wasmCode))', () => { 4 | test('empty_code', async () => { 5 | const wasm_compile = require('../src').from_empty_code; 6 | 7 | const wasm_module = await wasm_compile(); 8 | const wasm_instance = new WebAssembly.Instance(wasm_module); 9 | const exported_functions = getExportedFunctions(wasm_module); 10 | 11 | expect(wasm_module).toBeInstanceOf(WebAssembly.Module); 12 | expect(wasm_instance).toBeInstanceOf(WebAssembly.Instance); 13 | expect(exported_functions).toEqual([]); 14 | }); 15 | 16 | test('single_function', async () => { 17 | const wasm_compile = require('../src').from_single_function; 18 | 19 | const wasm_module = await wasm_compile(); 20 | const wasm_instance = new WebAssembly.Instance(wasm_module); 21 | const exported_functions = getExportedFunctions(wasm_module); 22 | 23 | expect(wasm_module).toBeInstanceOf(WebAssembly.Module); 24 | expect(wasm_instance).toBeInstanceOf(WebAssembly.Instance); 25 | expect(exported_functions).toEqual(['add']); 26 | expect(wasm_instance.exports.add(1, 2)).toBe(3); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/utils/get-cache-key.ts: -------------------------------------------------------------------------------- 1 | import { relative } from 'path'; 2 | import { readFileSync } from 'fs'; 3 | 4 | /** This function are copied and modified from 5 | * {@link https://github.com/kulshekhar/ts-jest/blob/master/src/utils/get-cache-key.ts}. 6 | * And yes, it's difficult to deduce what parameter is stand for because 7 | * Jest not documenting on how to write Jest transformer/preprocessor. 8 | * Also, I don't even know what Jest context function I can use 😞 9 | * Wondering if this function can be used for something usefull 🤔 10 | */ 11 | export default function getCacheKey( 12 | fileData: string, 13 | filePath: string, 14 | jestConfigString: string, 15 | { instrument, rootDir }: JestCacheKeyOptions 16 | ): string { 17 | const jestConfig: jest.ProjectConfig = JSON.parse(jestConfigString) || {}; 18 | delete jestConfig.cacheDirectory; 19 | delete jestConfig.name; 20 | // jest creates hash under the hoods 21 | return JSON.stringify([ 22 | readFileSync(__filename), 23 | fileData, 24 | relative(rootDir, filePath), 25 | jestConfig, 26 | /// TODO: use and modify https://github.com/facebook/jest/blob/8e72341c6df9af92a5e95e4a5784923baf5245de/packages/babel-jest/src/index.js#L35-L79 27 | /// or just return JSON.stringify(toml2json(Cargo.toml))❓ 🤔 28 | /* getBabelRC(filePath) */ '', 29 | instrument 30 | ]); 31 | } 32 | -------------------------------------------------------------------------------- /test/fixtures/export_buffer/test/index.spec.js: -------------------------------------------------------------------------------- 1 | const { getExportedFunctions } = require('../../utils'); 2 | 3 | describe('test mode {export: "buffer"} should export Rust code as Buffer', () => { 4 | test('empty_code', () => { 5 | const wasm_buffer = require('../src').from_empty_code; 6 | 7 | const wasm_module = new WebAssembly.Module(wasm_buffer); 8 | const wasm_instance = new WebAssembly.Instance(wasm_module); 9 | const exported_functions = getExportedFunctions(wasm_module); 10 | 11 | expect(wasm_buffer).toBeInstanceOf(Buffer); 12 | expect(wasm_module).toBeInstanceOf(WebAssembly.Module); 13 | expect(wasm_instance).toBeInstanceOf(WebAssembly.Instance); 14 | expect(exported_functions).toEqual([]); 15 | }); 16 | 17 | test('single_function', () => { 18 | const wasm_buffer = require('../src').from_single_function; 19 | 20 | const wasm_module = new WebAssembly.Module(wasm_buffer); 21 | const wasm_instance = new WebAssembly.Instance(wasm_module); 22 | const exported_functions = getExportedFunctions(wasm_module); 23 | 24 | expect(wasm_buffer).toBeInstanceOf(Buffer); 25 | expect(wasm_module).toBeInstanceOf(WebAssembly.Module); 26 | expect(wasm_instance).toBeInstanceOf(WebAssembly.Instance); 27 | expect(exported_functions).toEqual(['add']); 28 | expect(wasm_instance.exports.add(1, 2)).toBe(3); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /examples/stencil/src/components.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This is an autogenerated file created by the Stencil compiler. 3 | * It contains typing information for all components that exist in this project. 4 | */ 5 | /* tslint:disable */ 6 | 7 | import '@stencil/core'; 8 | 9 | export namespace Components { 10 | interface MyComponent { 11 | a: number; 12 | b: number; 13 | } 14 | interface MyComponentAttributes extends StencilHTMLAttributes { 15 | a?: number; 16 | b?: number; 17 | } 18 | } 19 | 20 | declare global { 21 | interface StencilElementInterfaces { 22 | MyComponent: Components.MyComponent; 23 | } 24 | 25 | interface StencilIntrinsicElements { 26 | 'my-component': Components.MyComponentAttributes; 27 | } 28 | 29 | interface HTMLMyComponentElement 30 | extends Components.MyComponent, 31 | HTMLStencilElement {} 32 | var HTMLMyComponentElement: { 33 | prototype: HTMLMyComponentElement; 34 | new (): HTMLMyComponentElement; 35 | }; 36 | 37 | interface HTMLElementTagNameMap { 38 | 'my-component': HTMLMyComponentElement; 39 | } 40 | 41 | interface ElementTagNameMap { 42 | 'my-component': HTMLMyComponentElement; 43 | } 44 | 45 | export namespace JSX { 46 | export interface Element {} 47 | export interface IntrinsicElements extends StencilIntrinsicElements { 48 | [tagName: string]: any; 49 | } 50 | } 51 | export interface HTMLAttributes extends StencilHTMLAttributes {} 52 | } 53 | -------------------------------------------------------------------------------- /examples/stencil/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-component", 3 | "version": "0.0.1", 4 | "description": "Stencil Component Starter", 5 | "module": "dist/esm/index.js", 6 | "main": "dist/index.js", 7 | "types": "dist/types/components.d.ts", 8 | "collection": "dist/collection/collection-manifest.json", 9 | "files": ["dist/"], 10 | "scripts": { 11 | "build": "stencil build", 12 | "start": "stencil build --dev --watch --serve", 13 | "test": "jest", 14 | "test.watch": "jest --watch" 15 | }, 16 | "dependencies": {}, 17 | "devDependencies": { 18 | "@stencil/core": "^0.12.4", 19 | "@types/jest": "^23.3.1", 20 | "jest": "^23.5.0", 21 | "rollup": "^0.65.0", 22 | "rollup-plugin-rust": "^1.1.2", 23 | "rs-jest": "file:../.." 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/ionic-team/stencil-component-starter.git" 28 | }, 29 | "author": "Ionic Team", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/ionic-team/stencil" 33 | }, 34 | "homepage": "https://github.com/ionic-team/stencil", 35 | "jest": { 36 | "globals": { 37 | "rs-jest": { 38 | "export": "instance" 39 | } 40 | }, 41 | "transform": { 42 | "^.+\\.(ts|tsx)$": "/node_modules/@stencil/core/testing/jest.preprocessor.js", 43 | "^.+\\.rs$": "rs-jest" 44 | }, 45 | "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", 46 | "moduleFileExtensions": ["ts", "tsx", "js", "json", "jsx"] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/utils/logger.ts: -------------------------------------------------------------------------------- 1 | /** This file are partially copied from ts-jest project 💩 2 | * @see https://github.com/kulshekhar/ts-jest/blob/master/src/utils/logger.ts 3 | * @todo If jest have lib utils for their own logger (just like webpack), switch to it immedeatly❗️ ️ 4 | */ 5 | import fs from 'fs'; 6 | import path from 'path'; 7 | import { Constant } from './constants'; 8 | 9 | /** 10 | * Logger file that enables logging things just once. Does this by traversing the array of previously recorded 11 | * logs to see if the exact same message has already been logged 12 | * @type {any[]} 13 | */ 14 | 15 | const logs: any[] = []; 16 | let logsFlushed: boolean = false; 17 | // Set this to true to also log to the console. It's very nice for local debugging. 18 | const outputToConsole: boolean = false; 19 | 20 | function shouldLog(): boolean { 21 | // If the env variable is set and the logs have not already been flushed, log the line 22 | return ( 23 | (Boolean(process.env.RS_JEST_DEBUG) || outputToConsole) && !logsFlushed 24 | ); 25 | } 26 | 27 | // Log function. Only logs prior to calls to flushLogs. 28 | export function logOnce(...thingsToLog: any[]): void { 29 | if (!shouldLog()) { 30 | return; 31 | } 32 | logs.push(thingsToLog); 33 | } 34 | 35 | // This function JSONifies logs and flushes them to disk. 36 | export function flushLogs(): void { 37 | if (!shouldLog()) { 38 | return; // only output stuff for the first invocation and if logging is enabled. 39 | } 40 | logsFlushed = true; 41 | const rootPath = path.resolve(__dirname, '..', '..'); 42 | const JSONifiedLogs = logs.map(convertToJSONIfPossible); 43 | const logString = JSONifiedLogs.join('\n'); 44 | const filePath = path.resolve(rootPath, Constant.LOGFILE); 45 | if (outputToConsole) { 46 | // tslint:disable-next-line 47 | console.log(logString); 48 | } else { 49 | fs.writeFileSync(filePath, logString); 50 | } 51 | } 52 | 53 | function convertToJSONIfPossible(object: any): string { 54 | //#region ERROR: cause error when bundling 💢 55 | // try { 56 | // return JSON.stringify(object, null, 2); 57 | // } catch { 58 | // return object.toString(); 59 | // } 60 | //#endregion 61 | return JSON.stringify(object, null, 2); 62 | } 63 | -------------------------------------------------------------------------------- /.github/WORKFLOW.md: -------------------------------------------------------------------------------- 1 | # Workflow of rs-jest 2 | 3 | This is a documentation of workflow that rs-jest use: 4 | 5 | - [Release Procedure](#release) 6 | 7 | ### Release Procedure 8 | 9 | This project use tool called [`standard-version`][] to manage the release process. Run this command to generate [CHANGELOG.md][] and increment version: 10 | 11 | ```console 12 | $ npm run release 13 | 14 | > rs-jest@0.0.0 release /home/wildan/Projects/OSS/rs-jest 15 | > standard-version --skip.commit --skip.tag 16 | 17 | ✔ bumping version in package.json from 0.0.0 to 0.0.1 18 | ✔ bumping version in package-lock.json from 0.0.0 to 0.0.1 19 | ✔ Running lifecycle script "postbump" 20 | ℹ - execute command: "echo auto correct code-style for package.json and lock file" 21 | ✔ created CHANGELOG.md 22 | ✔ outputting changes to CHANGELOG.md 23 | ``` 24 | 25 | Review [CHANGELOG.md](./CHANGELOG.md) file and if it's ok then run this command to automatically commit the file and tag it: 26 | 27 | ```console 28 | $ npm run release:ok 29 | 30 | > rs-jest@0.0.1 release:ok /home/wildan/Projects/OSS/rs-jest 31 | > standard-version --sign --commit-all --skip.bump --skip.changelog 32 | 33 | ✔ Running lifecycle script "precommit" 34 | ℹ - execute command: "git add CHANGELOG.md package*.json" 35 | ✔ committing CHANGELOG.md 36 | husky > pre-commit (node v8.11.3) 37 | Running tasks for *.js [started] 38 | Running tasks for *.js [skipped] 39 | → No staged files match *.js 40 | husky > commit-msg (node v8.11.3) 41 | ⧗ input: chore(release): 0.0.1 42 | ✔ found 0 problems, 0 warnings 43 | 44 | husky > post-commit (node v8.11.3) 45 | 46 | ✔ tagging release v0.0.1 47 | ℹ Run `git push --follow-tags origin master && npm publish` to publish 48 | ``` 49 | 50 | To specify the release type manually (like npm version <`major`|`minor`|`patch`>, default is `patch`), run this command: 51 | 52 | ```console 53 | $ npm run release:as -- minor 54 | 55 | > rs-jest@0.0.0 release:as /home/wildan/Projects/OSS/rs-jest 56 | > standard-version --skip.commit --skip.tag --release-as "minor" 57 | 58 | ✔ bumping version in package.json from 0.0.0 to 0.1.0 59 | ✔ bumping version in package-lock.json from 0.0.0 to 0.1.0 60 | ✔ Running lifecycle script "postbump" 61 | ℹ - execute command: "auto correct code-style for package.json and it's lock file" 62 | ✔ created CHANGELOG.md 63 | ✔ outputting changes to CHANGELOG.md 64 | ``` 65 | 66 | --- 67 | 68 | [changelog.md]: ./CHANGELOG.md 69 | [`standard-version`]: https://github.com/conventional-changelog/standard-version 70 | -------------------------------------------------------------------------------- /src/preprocess.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync } from 'fs'; 2 | import { cargoCommand, findSrcDir, handleCargo } from './cargo'; 3 | 4 | import { flushLogs, logOnce, execPermissive } from './utils'; 5 | import { defaultConfig, getConfigFrom } from './options'; 6 | import wasm2js from 'webassembly-loader'; 7 | 8 | //#region helper 9 | const is = (path: string) => ({ rustFile: /\.rs$/.test(path) }); 10 | const polyfill = { 11 | // TODO: convert to Jest context if JestAPI began to provide it 12 | webpackLoader: { 13 | emitWarning: (warning: string | Error) => console.warn(warning.toString()), 14 | emitError: (error: string | Error) => console.error(error.toString()), 15 | addDependency: (file: string) => (file ? undefined : undefined) 16 | } 17 | }; 18 | //#endregion 19 | 20 | /** Main function that do the transformation from Rust code to WebAssembly 21 | * @param {unused} src the source code, I guess 🤔 22 | * @param filePath fullpaht of the file that going to be transformed 23 | * @param jestConfig jest configuration 24 | * @param {unused} transformOptions.instrument a proxy for collectCoverage {@link https://github.com/kulshekhar/ts-jest/issues/201#issuecomment-300572902} 25 | * @returns transformed code with sourcemap or just the code 26 | * 27 | * However, it's unfortunate that jest will not support Promises for asynchronous transformation 😭 28 | * @see https://github.com/facebook/jest/issues/5556#issuecomment-365526603 29 | */ 30 | export default function preprocess( 31 | src: string, 32 | filePath: jest.Path, 33 | jestConfig: jest.ProjectConfig, 34 | transformOptions?: jest.TransformOptions 35 | ): jest.TransformedSource | string { 36 | const rsJestConfig = getConfigFrom(jestConfig); 37 | logOnce("defined globals['rs-jest']: ", rsJestConfig); 38 | 39 | const options = Object.assign(defaultConfig, rsJestConfig) as RsJestConfig; // diff and merge with predefined config 40 | logOnce("final globals['rs-jest']: ", options); 41 | 42 | const cmd = cargoCommand(options.target, options.release); 43 | logOnce('cargoCommand: ', cmd); 44 | 45 | /** In `ts-jest` codebase, it says: 46 | * --- 47 | * We can potentially do this faster by using the language service. 48 | * @see https://github.com/TypeStrong/ts-node/blob/ad6183a1b99df4f535903e7b51ce99571221c95b/src/index.ts#L307 49 | * --- 50 | * @todo I wonder if it can be applied here 🤔 51 | */ 52 | 53 | if (!is(filePath).rustFile) throw new Error(`${filePath} is not Rust file`); 54 | if (!options.target.includes('wasm')) { 55 | throw new Error(`For now, this transformer only support wasm related target compile! 56 | For more info see https://kripken.github.io/blog/binaryen/2018/04/18/rust-emscripten.html 57 | `); 58 | } 59 | 60 | const cwd = findSrcDir(filePath); 61 | if (!cwd) { 62 | throw new Error('No Cargo.toml file found in any parent directory.'); 63 | } 64 | 65 | const result = execPermissive(cmd, cwd); 66 | 67 | const { wasmFile } = handleCargo(polyfill.webpackLoader, result); 68 | if (!wasmFile) throw new Error('No wasm file produced as build output'); 69 | 70 | const wasmCode = readFileSync(wasmFile); 71 | flushLogs(); 72 | 73 | return wasm2js(wasmCode, { 74 | export: options.export, 75 | module: 'cjs' 76 | }); 77 | } 78 | -------------------------------------------------------------------------------- /src/cargo.ts: -------------------------------------------------------------------------------- 1 | /** This file are the synchronous version of cargo.js in rust-native-wasm-loader 2 | * @see https://github.com/dflemstr/rust-native-wasm-loader/blob/master/src/cargo.js 3 | */ 4 | import fs from 'fs'; 5 | import path from 'path'; 6 | 7 | //#region helpers 8 | const reverseString = (str: string) => 9 | str 10 | .split('') 11 | .reverse() 12 | .join(''); 13 | //#endregion 14 | 15 | export const parseDependencies = (data: string, baseFile: string) => 16 | data 17 | .split('\n') 18 | .filter(str => str.startsWith(baseFile.replace(/ /g, '\\ '))) 19 | .map(str => str.slice(str.indexOf(': ') + 2)) 20 | .map(reverseString) 21 | .map(str => str.split(/(?: (?!\\))/)) 22 | .reduce((allDeps, lineDeps) => [...allDeps, ...lineDeps], []) 23 | .map(reverseString) 24 | .map(str => str.replace(/\\ /g, ' ')); 25 | 26 | export function findSrcDir(childPath: string) { 27 | let candidate = childPath; 28 | 29 | while (candidate !== path.parse(candidate).root) { 30 | const maybeCargoFile = path.join(candidate, 'Cargo.toml'); 31 | if (fs.existsSync(maybeCargoFile)) { 32 | return candidate; 33 | } 34 | 35 | const newCandidate = path.dirname(candidate); 36 | if (newCandidate === candidate) { 37 | break; 38 | } 39 | candidate = newCandidate; 40 | } 41 | 42 | return null; 43 | } 44 | 45 | export function cargoCommand( 46 | target: string, 47 | release: boolean, 48 | subcmd = [] 49 | ): string { 50 | const cmd = [ 51 | 'cargo', 52 | ...subcmd, 53 | 'build', 54 | '--message-format=json', 55 | '--target=' + target 56 | ]; 57 | 58 | if (release) { 59 | cmd.push('--release'); 60 | } 61 | 62 | return cmd.join(' '); 63 | } 64 | 65 | export function handleCargo( 66 | self: Webpack.Loader.Context, 67 | result: string 68 | ): { 69 | wasmFile: string; 70 | jsFile: string; 71 | } { 72 | let wasmFile; 73 | let jsFile; 74 | let hasError = false; 75 | outer: for (const line of result.split('\n')) { 76 | if (/^\s*$/.test(line)) { 77 | continue; 78 | } 79 | const data = JSON.parse(line); 80 | switch (data.reason) { 81 | case 'compiler-message': 82 | switch (data.message.level) { 83 | case 'warning': 84 | self.emitWarning(new Error(data.message.rendered)); 85 | break; 86 | case 'error': 87 | self.emitError(new Error(data.message.rendered)); 88 | hasError = true; 89 | break; 90 | } 91 | break; 92 | case 'compiler-artifact': 93 | if (!wasmFile) { 94 | wasmFile = data.filenames.find((p: string) => p.endsWith('.wasm')); 95 | } 96 | if (!jsFile) { 97 | jsFile = data.filenames.find((p: string) => p.endsWith('.js')); 98 | } 99 | if (wasmFile) { 100 | break outer; 101 | } 102 | break; 103 | } 104 | } 105 | 106 | if (hasError) { 107 | throw new Error('Cargo build failed'); 108 | } 109 | 110 | const depFile = wasmFile.slice(0, -'.wasm'.length) + '.d'; 111 | const depContents = fs.readFileSync(depFile, 'utf-8'); 112 | const deps = parseDependencies(depContents, wasmFile); 113 | 114 | for (const dep of deps) { 115 | self.addDependency(dep); 116 | } 117 | 118 | return { wasmFile, jsFile }; 119 | } 120 | -------------------------------------------------------------------------------- /.github/HACKING.md: -------------------------------------------------------------------------------- 1 | # Want to Hack? 2 | 3 | Thanks for your interest to tinker this project. Let's make it great!! 🙂 4 | 5 | ## Basic Overview 6 | 7 | This project use rollup to bundle the final result while maintain the code format and it's comments block. Overall, the technology stack that this project uses are (you don't need to install this tools beforehand because it's already in dependecy list): 8 | 9 | - static-type checker: [typescript][] 10 | - code-style checker (linter): [tslint][] + [prettier][] 11 | - bundler: [rollup][] + [babel][] 12 | - git hooks: [husky][] + [commitlint][] + [lint-staged][] + [standard-version][] 13 | - test framework: [jest][] 14 | 15 | ## Start Hacking 16 | 17 | ### Setup 18 | 19 | First, install all dependencies by running 20 | 21 | ```console 22 | npm install 23 | ``` 24 | 25 | and if you got message about security vulnurability, you can use this command to fix it 26 | 27 | ```console 28 | npm audit fix 29 | ``` 30 | 31 | ### Test 32 | 33 | This project has 2 kind of tests, unit-tests and smoke-tests. The unit-tests will use [jest][] which basically will run in `node.js` environment. Run this command to start the unit-tests (choose which one): 34 | 35 | ```console 36 | npm run test 37 | npm run test:watch 38 | npm run test:coverage 39 | ``` 40 | 41 | The smoke-tests is basically just an example how to use plugin in real simple project. To run the smoke-tests, you need to [build/bundle](#Build) it first, change directory to the example you want to run, then try to build that example. Summary if you want to build `stencil` example, this is what you need to do: 42 | 43 | ```console 44 | npm run build 45 | cd examples/stencil 46 | npm test 47 | ``` 48 | 49 | ### Build 50 | 51 | To compile/bundle this project, you can choose between this 2 command 52 | 53 | ```console 54 | npm run build 55 | npm start 56 | ``` 57 | 58 | ## Project Structure 59 | 60 | In general, the folder structure of this project follow: 61 | 62 | ```sh 63 | . 64 | ├── examples 65 | │ ├──────────────────── 66 | │ │ Bunch of smoke-tests 67 | │ └──────────────────── 68 | │ 69 | ├── src # scripts that will be build/bundled 70 | │ ├── ...bunch_of_helper_scripts 71 | │ ├── index.ts # exported module used by Jest 72 | │ └── preprocessor.ts # main scripts 73 | │ 74 | ├── test 75 | │ ├── fixtures 76 | │ │ ├────────────────────────────── 77 | │ │ │ Bunch of sample to be tested 78 | │ │ ├────────────────────────────── 79 | │ │ └── utils.js # helper script used in various fixtures 80 | │ │ 81 | │ │ 82 | │ ├──────────────────────────────────────────────── 83 | │ │ Few test-cases with file-extension *.test.ts 84 | │ ├──────────────────────────────────────────────── 85 | │ └── utils.ts # helper script used in various test-cases 86 | │ 87 | ├───────────────────── 88 | │ Bunch of config files 89 | └───────────────────── 90 | ``` 91 | 92 | --- 93 | 94 | [lint-staged]: https://github.com/okonet/lint-staged 95 | [rollup-plugin]: https://github.com/rollup/rollup/wiki/Plugins#creating-plugins 96 | [rollup]: https://rollupjs.org/guide/en 97 | [typescript]: https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html 98 | [tslint]: https://palantir.github.io/tslint/ 99 | [prettier]: https://prettier.io/docs/en/install.html 100 | [babel]: https://babeljs.io/docs/en 101 | [husky]: https://github.com/typicode/husky 102 | [commitlint]: https://github.com/marionebl/commitlint 103 | [standard-version]: https://github.com/conventional-changelog/standard-version 104 | [conventionalcommits]: https://conventionalcommits.org/ 105 | [jest]: https://jestjs.io/docs/en/getting-started.html 106 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rs-jest", 3 | "version": "1.1.0", 4 | "description": "Jest preprocessor/transformer for Rust", 5 | "main": "dist/index.js", 6 | "typings": "index.d.ts", 7 | "files": ["dist/", "index.d.ts"], 8 | "scripts": { 9 | "prebuild": "shx rm -r dist || true", 10 | "build": "rollup -c", 11 | "prestart": "npm run prebuild", 12 | "start": "rollup -c -w || true", 13 | "lint": "(tsc --pretty -p . --noemit || true) && tslint -p . --force", 14 | "lint:fix": "tslint -p . --fix --force", 15 | "lint:commits": "commitlint --to=$(git rev-parse HEAD)", 16 | "release": "standard-version --skip.commit --skip.tag", 17 | "release:as": "standard-version --skip.commit --skip.tag --release-as", 18 | "release:ok": "standard-version --sign --commit-all --skip.bump --skip.changelog", 19 | "release:validate": "commitlint --from=$(git describe --tags --abbrev=0) --to=$(git rev-parse HEAD)", 20 | "ci:lint": "tsc --pretty -p . --noemit && tslint -p .", 21 | "ci:test": "jest --runInBand --silent --ci", 22 | "ci:coverage": "jest --collectCoverageFrom='src/**/*.ts' --coverage --runInBand --silent --ci", 23 | "ci:release": "conventional-github-releaser -p angular", 24 | "ci:lint:commits": "commitlint --from=${CIRCLE_BRANCH} --to=${CIRCLE_SHA1}", 25 | "pretest": "npm run build", 26 | "test": "jest --notify", 27 | "posttest": "shx rm -r test/fixtures/**/target test/fixtures/**/Cargo.lock || true", 28 | "test:watch": "npm test -- --watch || true", 29 | "test:coverage": "jest --collectCoverageFrom='src/**/*.ts' --coverage", 30 | "prepublishOnly": "npm run build" 31 | }, 32 | "lint-staged": { 33 | "linters": { 34 | "*.ts": ["tslint -c tslint.json -p tsconfig.json"] 35 | }, 36 | "ignore": ["examples/**"] 37 | }, 38 | "standard-version": { 39 | "scripts": { 40 | "postbump": "prettier package*.json --write", 41 | "precommit": "git add CHANGELOG.md package*.json" 42 | } 43 | }, 44 | "engines": { 45 | "node": ">= 8.9.0" 46 | }, 47 | "repository": { 48 | "type": "git", 49 | "url": "git+https://github.com/DrSensor/rs-jest.git" 50 | }, 51 | "keywords": ["jest", "rust", "webassembly"], 52 | "author": "Fahmi Akbar Wildana", 53 | "license": "MIT", 54 | "bugs": { 55 | "url": "https://github.com/DrSensor/rs-jest/issues" 56 | }, 57 | "homepage": "https://github.com/DrSensor/rs-jest#readme", 58 | "devDependencies": { 59 | "@babel/core": "^7.0.0-rc.3", 60 | "@babel/plugin-proposal-class-properties": "^7.0.0", 61 | "@babel/plugin-proposal-export-namespace-from": "^7.0.0", 62 | "@babel/plugin-proposal-object-rest-spread": "^7.0.0", 63 | "@babel/preset-env": "^7.0.0-rc.3", 64 | "@babel/preset-typescript": "^7.0.0", 65 | "@commitlint/cli": "^7.0.0", 66 | "@commitlint/config-conventional": "^7.0.1", 67 | "@types/glob": "^5.0.35", 68 | "@types/jest": "^23.3.1", 69 | "@types/node": "^10.9.3", 70 | "babel-core": "^7.0.0-bridge.0", 71 | "babel-jest": "^23.4.2", 72 | "conventional-github-releaser": "^3.1.2", 73 | "glob": "^7.1.3", 74 | "husky": "^1.0.0-rc.13", 75 | "jest": "^23.5.0", 76 | "jest-silent-reporter": "^0.1.0", 77 | "lint-staged": "^7.2.2", 78 | "prettier": "^1.14.2", 79 | "pretty-quick": "^1.6.0", 80 | "rollup": "^0.66.6", 81 | "rollup-plugin-auto-external": "^2.0.0", 82 | "rollup-plugin-babel": "^4.0.2", 83 | "rollup-plugin-commonjs": "^9.1.6", 84 | "rollup-plugin-node-resolve": "^3.3.0", 85 | "rollup-plugin-prettier": "^0.4.0", 86 | "rollup-plugin-typescript2": "^0.17.0", 87 | "shx": "^0.3.2", 88 | "standard-version": "^4.4.0", 89 | "ts-jest": "^23.1.4", 90 | "ts-node": "^7.0.1", 91 | "tslint": "^5.11.0", 92 | "tslint-config-prettier": "^1.15.0", 93 | "typescript": "^3.0.1", 94 | "webassembly-loader": "^1.1.0" 95 | }, 96 | "dependencies": {} 97 | } 98 | -------------------------------------------------------------------------------- /examples/stencil/readme.md: -------------------------------------------------------------------------------- 1 | ![Built With Stencil](https://img.shields.io/badge/-Built%20With%20Stencil-16161d.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjIuMSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI%2BCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI%2BCgkuc3Qwe2ZpbGw6I0ZGRkZGRjt9Cjwvc3R5bGU%2BCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik00MjQuNywzNzMuOWMwLDM3LjYtNTUuMSw2OC42LTkyLjcsNjguNkgxODAuNGMtMzcuOSwwLTkyLjctMzAuNy05Mi43LTY4LjZ2LTMuNmgzMzYuOVYzNzMuOXoiLz4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTQyNC43LDI5Mi4xSDE4MC40Yy0zNy42LDAtOTIuNy0zMS05Mi43LTY4LjZ2LTMuNkgzMzJjMzcuNiwwLDkyLjcsMzEsOTIuNyw2OC42VjI5Mi4xeiIvPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNNDI0LjcsMTQxLjdIODcuN3YtMy42YzAtMzcuNiw1NC44LTY4LjYsOTIuNy02OC42SDMzMmMzNy45LDAsOTIuNywzMC43LDkyLjcsNjguNlYxNDEuN3oiLz4KPC9zdmc%2BCg%3D%3D&colorA=16161d&style=flat-square) 2 | 3 | # Stencil-Rust Component Starter 4 | 5 | This is a starter project for building a standalone Web Component using Stencil and Rust. 6 | 7 | Stencil is also great for building entire apps. For that, use the [stencil-app-starter](https://github.com/ionic-team/stencil-app-starter) instead. 8 | 9 | # Stencil 10 | 11 | Stencil is a compiler for building fast web apps using Web Components. 12 | 13 | Stencil combines the best concepts of the most popular frontend frameworks into a compile-time rather than run-time tool. Stencil takes TypeScript, JSX, a tiny virtual DOM layer, efficient one-way data binding, an asynchronous rendering pipeline (similar to React Fiber), and lazy-loading out of the box, and generates 100% standards-based Web Components that run in any browser supporting the Custom Elements v1 spec. 14 | 15 | Stencil components are just Web Components, so they work in any major framework or with no framework at all. 16 | 17 | ## Getting Started 18 | 19 | To start building a new web component using Stencil, clone this repo to a new directory: 20 | 21 | ```bash 22 | git clone https://github.com/ionic-team/stencil-component-starter.git my-component 23 | cd my-component 24 | git remote rm origin 25 | ``` 26 | 27 | and run: 28 | 29 | ```bash 30 | npm install 31 | npm start 32 | ``` 33 | 34 | To build the component for production, run: 35 | 36 | ```bash 37 | npm run build 38 | ``` 39 | 40 | To run the unit tests for the components, run: 41 | 42 | ```bash 43 | npm test 44 | ``` 45 | 46 | Need help? Check out our docs [here](https://stenciljs.com/docs/my-first-component). 47 | 48 | ## Naming Components 49 | 50 | When creating new component tags, we recommend _not_ using `stencil` in the component name (ex: ``). This is because the generated component has little to nothing to do with Stencil; it's just a web component! 51 | 52 | Instead, use a prefix that fits your company or any name for a group of related components. For example, all of the Ionic generated web components use the prefix `ion`. 53 | 54 | ## Using this component 55 | 56 | ### Script tag 57 | 58 | - [Publish to NPM](https://docs.npmjs.com/getting-started/publishing-npm-packages) 59 | - Put a script tag similar to this `` in the head of your index.html 60 | - Then you can use the element anywhere in your template, JSX, html etc 61 | 62 | ### Node Modules 63 | 64 | - Run `npm install my-component --save` 65 | - Put a script tag similar to this `` in the head of your index.html 66 | - Then you can use the element anywhere in your template, JSX, html etc 67 | 68 | ### In a stencil-starter app 69 | 70 | - Run `npm install my-component --save` 71 | - Add an import to the npm packages `import my-component;` 72 | - Then you can use the element anywhere in your template, JSX, html etc 73 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing in rs-jest 2 | 3 | We'd always love contributions to further improve the jest ecosystem! 4 | Here are the guidelines we'd like you to follow: 5 | 6 | - [Questions and Problems](#question) 7 | - [Issues and Bugs](#issue) 8 | - [Feature Requests](#feature) 9 | - [Pull Request Submission Guidelines](#submit-pr) 10 | - [Commit Message Conventions](#commit) 11 | 12 | ### Got a Question or Problem? 13 | 14 | Please submit support requests and questions to StackOverflow using the tag [[jest]](http://stackoverflow.com/tags/jest). 15 | StackOverflow is better suited for this kind of support. 16 | The issue tracker is for bug reports and feature discussions. 17 | 18 | ### Found an Issue or Bug? 19 | 20 | Before you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available. 21 | 22 | We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs, we ask that you to provide a minimal reproduction scenario (github repo or failing test case). Having a live, reproducible scenario gives us a wealth of important information without going back & forth to you with additional questions like: 23 | 24 | - version of jest used 25 | - version of the rs-jest you are using 26 | - the use-case that fails (if possible and not become a burden for you 😉) 27 | 28 | A minimal reproduce scenario allows us to quickly confirm a bug (or point out config problems) as well as confirm that we are fixing the right problem. 29 | 30 | We will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it. 31 | 32 | Unfortunately, we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that doesn't have enough info to be reproduced. 33 | 34 | ### Feature Requests? 35 | 36 | You can _request_ a new feature by creating an issue on Github. 37 | 38 | If you would like to _implement_ a new feature, please submit an issue with a proposal for your work `first`, to be sure that particular makes sense for the project. 39 | 40 | ### Pull Request Submission Guidelines 41 | 42 | Before you submit your Pull Request (PR) consider the following guidelines: 43 | 44 | - Search Github for an open or closed PR that relates to your submission. You don't want to duplicate effort. 45 | - Commit your changes using a descriptive commit message that follows our [commit message conventions](#commit). Adherence to these conventions is necessary because release notes are automatically generated from these messages. 46 | - Fill out our `Pull Request Template`. Your pull request will not be considered if it is ignored. 47 | - Please sign the `Contributor License Agreement (CLA)` when a pull request is opened. We cannot accept your pull request without this. Make sure you sign with the primary email address associated with your local / github account. 48 | 49 | ### jest Contrib Commit Conventions 50 | 51 | Each commit message consists of a **header**, a **body** and a **footer**. The header has a special 52 | format that includes a **type**, a **scope** and a **subject**: 53 | 54 | ```xml 55 | (): 56 | 57 | 58 | 59 |