├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmignore ├── .npmrc ├── .nvmrc ├── .travis.yml ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── babel.config.js ├── hero.png ├── jest.config.js ├── package-lock.json ├── package.json ├── src ├── componentToReact.js ├── constants.js └── index.js └── test ├── index.test.js └── pkgOverride.test.json /.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 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "global-require": 0, 5 | "import/no-dynamic-require": 0, 6 | "indent": 0 7 | }, 8 | "env": { 9 | "jest": true 10 | }, 11 | "plugins": ["jest"] 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage 2 | dist 3 | node_modules 4 | .coveralls.yml 5 | test_output/ 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Ignore Everything 2 | * 3 | 4 | # Except... 5 | !src/*.js 6 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v10.15.3 -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | - "10" 5 | - "stable" 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "jest.autoEnable": false 3 | } 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.0.1-8](https://github.com/petermikitsh/stencil-react/compare/v0.0.1-7...v0.0.1-8) (2019-10-31) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * **componentToReact:** reassign properties only on change ([2f82108](https://github.com/petermikitsh/stencil-react/commit/2f82108)) 7 | 8 | 9 | 10 | ## [0.0.1-7](https://github.com/petermikitsh/stencil-react/compare/v0.0.1-6...v0.0.1-7) (2019-10-28) 11 | 12 | 13 | ### Bug Fixes 14 | 15 | * always set properties (closes [#4](https://github.com/petermikitsh/stencil-react/issues/4)) ([#6](https://github.com/petermikitsh/stencil-react/issues/6)) ([7e432f2](https://github.com/petermikitsh/stencil-react/commit/7e432f2)) 16 | 17 | 18 | ### Features 19 | 20 | * --packageJson and --packageJsonPath options ([8a1b0cc](https://github.com/petermikitsh/stencil-react/commit/8a1b0cc)) 21 | 22 | 23 | 24 | ## [0.0.1-6](https://github.com/petermikitsh/stencil-react/compare/v0.0.1-5...v0.0.1-6) (2019-09-04) 25 | 26 | 27 | ### Bug Fixes 28 | 29 | * get class name directly from file; add d3-stencil test ([e49ecbe](https://github.com/petermikitsh/stencil-react/commit/e49ecbe)) 30 | 31 | 32 | 33 | ## [0.0.1-5](https://github.com/petermikitsh/stencil-react/compare/v0.0.1-4...v0.0.1-5) (2019-09-04) 34 | 35 | 36 | ### Bug Fixes 37 | 38 | * find entry files relative to collection manifest directory ([fa7cfb1](https://github.com/petermikitsh/stencil-react/commit/fa7cfb1)) 39 | 40 | 41 | 42 | ## [0.0.1-4](https://github.com/petermikitsh/stencil-react/compare/v0.0.1-3...v0.0.1-4) (2019-09-04) 43 | 44 | 45 | ### Bug Fixes 46 | 47 | * use camelCase property names instead of kebab-case ([022f50a](https://github.com/petermikitsh/stencil-react/commit/022f50a)) 48 | 49 | 50 | 51 | ## [0.0.1-3](https://github.com/petermikitsh/stencil-react/compare/v0.0.1-2...v0.0.1-3) (2019-09-04) 52 | 53 | 54 | ### Bug Fixes 55 | 56 | * keep tsx files (for source map support) ([3c65bd0](https://github.com/petermikitsh/stencil-react/commit/3c65bd0)) 57 | 58 | 59 | 60 | ## [0.0.1-2](https://github.com/petermikitsh/stencil-react/compare/v0.0.1-1...v0.0.1-2) (2019-09-04) 61 | 62 | 63 | 64 | ## [0.0.1-1](https://github.com/petermikitsh/stencil-react/compare/v0.0.1-0...v0.0.1-1) (2019-09-03) 65 | 66 | 67 | 68 | ## [0.0.1-0](https://github.com/petermikitsh/stencil-react/compare/fa98a4d...v0.0.1-0) (2019-09-02) 69 | 70 | 71 | ### Bug Fixes 72 | 73 | * add bracket ([6314dce](https://github.com/petermikitsh/stencil-react/commit/6314dce)) 74 | * add tslib dependency to generated package.json ([65fdb87](https://github.com/petermikitsh/stencil-react/commit/65fdb87)) 75 | * use React.createElement (output proper ES5) ([9cff4b4](https://github.com/petermikitsh/stencil-react/commit/9cff4b4)) 76 | 77 | 78 | ### Features 79 | 80 | * add peerDependencies to generated package.json ([61e3610](https://github.com/petermikitsh/stencil-react/commit/61e3610)) 81 | * generate bindings ([fa98a4d](https://github.com/petermikitsh/stencil-react/commit/fa98a4d)) 82 | * generate ESM, CJS builds ([b66596f](https://github.com/petermikitsh/stencil-react/commit/b66596f)) 83 | * support aria-* props ([ec853b1](https://github.com/petermikitsh/stencil-react/commit/ec853b1)) 84 | * support outDir option ([e13e598](https://github.com/petermikitsh/stencil-react/commit/e13e598)) 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Peter Mikitsh 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Update 2 | 3 | **Check out https://github.com/ionic-team/stencil-ds-plugins**. You may want that instead of this. 4 | 5 |

6 | 7 |

8 | 9 | # stencil-react 10 | 11 | [![npm package][npm-image]][npm-url] 12 | [![Build Status][travis-image]][travis-url] 13 | [![Coverage Status][coveralls-image]][coveralls-url] 14 | [![Dependencies Status][david-image]][david-url] 15 | 16 | Generate React Components ("bindings") from Stencil 1.x projects. 17 | 18 | ## Usage 19 | 20 | Make sure your Stencil v1 component library (e.g, `@anjuna/core`) is installed as an npm dependency. 21 | 22 | ``` 23 | npm i stencil-react 24 | stencil-react @anjuna/core --outDir dist 25 | ``` 26 | 27 | ### Options 28 | 29 | | Option | Description | Default Value | 30 | |---------------------|-----------------------------------------------|---------------| 31 | | `--outDir` | Output directory | `dist` | 32 | | `--packageJson` | Override output package.json fields | N/A | 33 | | `--packageJsonPath` | Override output package.json fields from file | N/A | 34 | 35 | You cannot override fields `['main', 'module', 'types', 'peerDependencies', 'dependencies']`. 36 | 37 | ### Output 38 | 39 | Your output directory will contain: 40 | 41 | - A `package.json` file with `main`, `module`, and `types` fields 42 | - An ES Module build of your React-wrapped Stencil components 43 | - A CommonJS build of your React-wrapped Stencil components 44 | - TypeScript types 45 | - Source Maps 46 | 47 | ## Usage (In React) 48 | 49 | The generated NPM package is the original, suffixed with `-react`. 50 | 51 | All your Stencil Components will be exported from the main/module entry file. E.g., if you had a `Button` component: 52 | 53 | ```jsx 54 | import { Button } from '@anjuna/core-react'; 55 | ``` 56 | 57 | Custom properties, custom events, synthentic React events, and aria-attributes are all supported: 58 | 59 | ```jsx 60 | import React from 'react'; 61 | import ReactDOM from 'react-dom'; 62 | 63 | const App = ( 64 | 72 | ); 73 | 74 | ReactDOM.render(, document.body); 75 | ``` 76 | 77 | [npm-image]:https://img.shields.io/npm/v/stencil-react.svg 78 | [npm-url]:https://www.npmjs.com/package/stencil-react 79 | [travis-image]:https://travis-ci.org/petermikitsh/stencil-react.svg?branch=master 80 | [travis-url]:https://travis-ci.org/petermikitsh/stencil-react 81 | [david-image]:https://david-dm.org/petermikitsh/stencil-react/status.svg 82 | [david-url]:https://david-dm.org/petermikitsh/stencil-react 83 | [coveralls-image]:https://coveralls.io/repos/github/petermikitsh/stencil-react/badge.svg?branch=master 84 | [coveralls-url]:https://coveralls.io/github/petermikitsh/stencil-react?branch=master 85 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = (api) => { 2 | api.cache(false); 3 | return { 4 | plugins: [ 5 | '@babel/plugin-transform-modules-commonjs', 6 | ], 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/petermikitsh/stencil-react/0322663b1c4fb61631f03fa741a94b6c01f6dec6/hero.png -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | collectCoverage: true, 3 | collectCoverageFrom: [ 4 | 'src/**.js', 5 | ], 6 | coverageReporters: [ 7 | 'lcov', 8 | 'text-summary', 9 | 'html', 10 | ], 11 | testEnvironment: 'jsdom', 12 | transformIgnorePatterns: [ 13 | '/node_modules/(?!(@anjuna/core|d3-stencil)).+\\.js$', 14 | ], 15 | verbose: true, 16 | }; 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stencil-react", 3 | "version": "0.0.1-8", 4 | "description": "CLI tool to generate React bindings for Stencil v1 Components", 5 | "keywords": [ 6 | "stencil", 7 | "react", 8 | "bindings" 9 | ], 10 | "main": "src/index.js", 11 | "scripts": { 12 | "coverage:open": "open coverage/index.html", 13 | "coverage:report": "cat ./coverage/lcov.info | coveralls", 14 | "lint": "eslint src/**/*.js", 15 | "version": "conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md", 16 | "test": "jest" 17 | }, 18 | "bin": { 19 | "stencil-react": "src/index.js" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "git+https://github.com/petermikitsh/stencil-react.git" 24 | }, 25 | "author": "Peter Mikitsh ", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/petermikitsh/stencil-react/issues" 29 | }, 30 | "homepage": "http://blog.mikit.sh/post/React-Bindings-For-Stencil-Components/", 31 | "devDependencies": { 32 | "@anjuna/core": "1.0.0-rc.0", 33 | "@stencil/state-tunnel": "1.0.1", 34 | "@types/jest": "^24.0.18", 35 | "@types/prettier": "^1.18.2", 36 | "@types/react": "16.9.2", 37 | "conventional-changelog-cli": "2.0.23", 38 | "coveralls": "^3.0.6", 39 | "d3-stencil": "2.2.0", 40 | "eslint": "^6.1.0", 41 | "eslint-config-airbnb": "^18.0.1", 42 | "eslint-plugin-import": "^2.18.2", 43 | "eslint-plugin-jest": "^22.16.0", 44 | "eslint-plugin-jsx-a11y": "^6.2.3", 45 | "eslint-plugin-react": "^7.14.3", 46 | "eslint-plugin-react-hooks": "^1.7.0", 47 | "jest": "^24.9.0", 48 | "popper.js": "1.15.0", 49 | "react": "16.9.0", 50 | "rimraf": "^3.0.0", 51 | "tslib": "1.10.0" 52 | }, 53 | "dependencies": { 54 | "@babel/core": "7.5.5", 55 | "@babel/plugin-transform-modules-commonjs": "7.5.0", 56 | "@babel/register": "7.5.5", 57 | "@stencil/core": "1.3.2", 58 | "@types/lodash": "^4.14.138", 59 | "fs-extra": "8.1.0", 60 | "lodash": "^4.17.15", 61 | "mri": "1.1.4", 62 | "outdent": "0.7.0", 63 | "prettier": "^1.18.2", 64 | "typescript": "3.6.2" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/componentToReact.js: -------------------------------------------------------------------------------- 1 | const outdent = require('outdent'); 2 | 3 | module.exports = (componentClass) => { 4 | const { 5 | is: customElementTag, 6 | properties, 7 | events, 8 | name: exportName, 9 | } = componentClass; 10 | 11 | const quote = (str) => { 12 | const hasHyphen = str.indexOf('-') > -1; 13 | if (hasHyphen) { 14 | return `'${str}'`; 15 | } 16 | return str; 17 | }; 18 | 19 | const iterate = (obj, mapFn, join) => { 20 | if (!obj) { 21 | return ''; 22 | } 23 | return Object.entries(obj).map(mapFn).join(join || `\n${' '.repeat(2)}`); 24 | }; 25 | 26 | return outdent` 27 | import React, { Component } from 'react'; 28 | 29 | interface ${exportName}Props { 30 | ${iterate(properties, ([key, prop]) => ( 31 | `${quote(key)}?: ${prop.complexType.resolved.replace(/"/g, "'")};` 32 | ))} 33 | ${iterate(events, ([, prop]) => ( 34 | `${quote(prop.method)}?: Function;` 35 | ))} 36 | [key: string]: any; 37 | } 38 | 39 | export class ${exportName} extends Component<${exportName}Props> { 40 | ref: React.RefObject; 41 | properties: string[]; 42 | events: string[]; 43 | 44 | constructor(props: ${exportName}Props) { 45 | super(props); 46 | this.ref = React.createRef(); 47 | this.properties = [${iterate( 48 | properties, 49 | ([key]) => (`'${key}'`), 50 | ', ', 51 | )}]; 52 | this.events = [${iterate( 53 | events, 54 | ([, { method }]) => (`'${method}'`), 55 | ', ', 56 | )}]; 57 | } 58 | 59 | componentDidMount() { 60 | this.properties.forEach((property) => { 61 | const propertyValue = this.props[property]; 62 | this.ref.current[property] = propertyValue; 63 | }); 64 | 65 | this.events.forEach((event) => { 66 | const eventFn = this.props[event]; 67 | if (eventFn) { 68 | this.ref.current.addEventListener(event, eventFn); 69 | } 70 | }); 71 | } 72 | 73 | componentDidUpdate(prevProps: ${exportName}Props) { 74 | this.properties.forEach((property) => { 75 | const prevProp = prevProps[property]; 76 | const currProp = this.props[property]; 77 | if (prevProp !== currProp) { 78 | this.ref.current[property] = currProp; 79 | } 80 | }); 81 | 82 | this.events.forEach((event) => { 83 | const prevEvent = prevProps[event]; 84 | const currEvent = this.props[event]; 85 | if (prevEvent !== event) { 86 | this.ref.current.removeEventListener(event, prevEvent); 87 | this.ref.current.addEventListener(event, currEvent); 88 | } 89 | }); 90 | } 91 | 92 | render() { 93 | /* Pass all other props, e.g., React Synthetic Events like 'onClick' 94 | * or aria attrs like 'aria-label' to custom element 95 | */ 96 | const others = Object.keys(this.props).reduce((accumulator: { [s: string]: any; }, key) => { 97 | const isAria = key.indexOf('aria-') === 0; 98 | const notCustomProperty = this.properties.indexOf(key) === -1; 99 | const notCustomEvent = this.events.indexOf(key) === -1; 100 | if (isAria || notCustomProperty && notCustomEvent) { 101 | accumulator[key] = this.props[key]; 102 | } 103 | return accumulator; 104 | }, {}); 105 | return <${customElementTag} ref={this.ref} {...others} />; 106 | } 107 | } 108 | 109 | `; 110 | }; 111 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | /** 3 | * These package.json fields are ignored and cannot be override 4 | */ 5 | ignoredPkgJsonOverrideFields: [ 6 | 'main', 7 | 'module', 8 | 'types', 9 | 'peerDependencies', 10 | 'dependencies', 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const fs = require('fs-extra'); 4 | const mri = require('mri'); 5 | const path = require('path'); 6 | const ts = require('typescript'); 7 | const prettier = require('prettier'); 8 | const { 9 | omit, 10 | } = require('lodash'); 11 | 12 | const componentToReact = require('./componentToReact'); 13 | const { 14 | ignoredPkgJsonOverrideFields, 15 | } = require('./constants'); 16 | 17 | const { _: [moduleName], ...opts } = mri(process.argv.slice(2)); 18 | if (!moduleName) { 19 | throw Error('No module supplied. See https://github.com/petermikitsh/stencil-react#usage'); 20 | } 21 | const outDir = opts.outDir || 'dist'; 22 | const pkgBasePath = path.resolve('node_modules', moduleName); 23 | const pkgJsonPath = path.resolve(pkgBasePath, 'package.json'); 24 | const pkgJson = require(pkgJsonPath); 25 | // Compile stencil files so they can be read in NodeJS 26 | require('@babel/register')({ 27 | only: [pkgBasePath], 28 | plugins: ['@babel/plugin-transform-modules-commonjs'], 29 | cache: false, 30 | }); 31 | 32 | async function main() { 33 | const collectionPath = path.resolve(pkgBasePath, pkgJson.collection); 34 | const collectionDir = path.dirname(collectionPath); 35 | const { entries } = require(collectionPath); 36 | let indexFile = ''; 37 | const relativeFiles = []; 38 | 39 | const transforms = entries.map(async (entry) => { 40 | const entryPath = path.resolve(collectionDir, entry); 41 | const componentFile = require(entryPath); 42 | const exportName = Object.keys(componentFile)[0]; 43 | const componentClass = componentFile[exportName]; 44 | const reactComponent = componentToReact(componentClass); 45 | const writePath = path.resolve(outDir, 'tsx', entry).replace('.js', '.tsx'); 46 | const writeDir = path.dirname(writePath); 47 | const relativePath = path.relative(outDir, path.resolve(outDir, entry)); 48 | const absPath = path.resolve(outDir, relativePath); 49 | relativeFiles.push(absPath); 50 | indexFile += `export { ${exportName} } from './${relativePath.replace('.js', '')}';\n`; 51 | await fs.ensureDir(writeDir); 52 | await fs.writeFile(writePath, reactComponent); 53 | }); 54 | 55 | await Promise.all(transforms); 56 | const indexPath = path.resolve(outDir, 'tsx/index.ts'); 57 | await fs.writeFile(indexPath, indexFile); 58 | 59 | // Typescript file generation complete. 60 | // Now to make ES Modules. 61 | const files = [indexPath, ...relativeFiles]; 62 | const baseConfig = { 63 | target: ts.ScriptTarget.ES5, 64 | importHelpers: true, 65 | sourceMap: true, 66 | jsx: ts.JsxEmit.React, 67 | }; 68 | const esmProgram = ts.createProgram(files, { 69 | ...baseConfig, 70 | module: ts.ModuleKind.ESNext, 71 | outDir: path.resolve(outDir, 'esm'), 72 | declaration: true, 73 | declarationDir: path.resolve(outDir, 'types'), 74 | }); 75 | esmProgram.emit(); 76 | 77 | // Also, make CommonJS Modules. 78 | const cjsProgram = ts.createProgram(files, { 79 | ...baseConfig, 80 | module: ts.ModuleKind.CommonJS, 81 | outDir: path.resolve(outDir, 'cjs'), 82 | }); 83 | cjsProgram.emit(); 84 | 85 | // Make a package.json file 86 | let jsonOverride = (() => { 87 | try { 88 | return JSON.parse(opts.packageJson || '{ }'); 89 | } catch (e) { 90 | console.log('⚠️ Unable to parse --packageJson option. Ignoring input.'); 91 | return {}; 92 | } 93 | })(); 94 | 95 | const cliPkgJsonOverridePath = opts.packageJsonPath; 96 | if (cliPkgJsonOverridePath !== undefined) { 97 | let override = { }; 98 | try { 99 | override = require(path.resolve(cliPkgJsonOverridePath)); 100 | } catch (e) { 101 | console.warn(e); 102 | } 103 | jsonOverride = { 104 | ...override, 105 | ...jsonOverride, 106 | }; 107 | } 108 | const genPkgJsonPath = path.resolve(outDir, 'package.json'); 109 | const finalPkgJsonObj = { 110 | name: `${moduleName}-react`, 111 | description: `${moduleName} Stencil Components for React`, 112 | version: `${pkgJson.version}`, 113 | main: './cjs/index.js', 114 | module: './esm/index.js', 115 | types: './types/index.d.ts', 116 | peerDependencies: { 117 | [moduleName]: `^${pkgJson.version}`, 118 | }, 119 | dependencies: { 120 | tslib: `^${require('../package.json').devDependencies.tslib}`, 121 | }, 122 | ...omit( 123 | jsonOverride, 124 | ...ignoredPkgJsonOverrideFields, 125 | ), 126 | }; 127 | await fs.writeFile( 128 | genPkgJsonPath, 129 | prettier.format( 130 | JSON.stringify(finalPkgJsonObj), 131 | { 132 | parser: 'json', 133 | }, 134 | ), 135 | ); 136 | } 137 | 138 | module.exports = main(); 139 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | const rimraf = require('rimraf'); 2 | const path = require('path'); 3 | 4 | const componentToReact = require('../src/componentToReact'); 5 | const testPkgOverride = require('./pkgOverride.test.json'); 6 | const { 7 | ignoredPkgJsonOverrideFields, 8 | } = require('../src/constants'); 9 | 10 | beforeEach(() => { 11 | jest.resetModules(); 12 | }); 13 | 14 | test('Generate React Component from Web Component', () => { 15 | const componentClass = { 16 | is: 'anj-button', 17 | properties: { 18 | context: { 19 | type: 'string', 20 | complexType: { 21 | original: "'primary' | 'secondary' | 'text' | 'icon' | 'free'", 22 | // eslint-disable-next-line 23 | resolved: "\"free\" | \"icon\" | \"primary\" | \"secondary\" | \"text\"", 24 | }, 25 | attribute: 'context', 26 | }, 27 | }, 28 | events: [ 29 | { 30 | method: 'anjBlur', 31 | name: 'anjBlur', 32 | complexType: { 33 | original: 'void', 34 | resolved: 'void', 35 | }, 36 | }, 37 | ], 38 | name: 'Button', 39 | }; 40 | const result = componentToReact(componentClass); 41 | expect(typeof result).toBe('string'); 42 | }); 43 | 44 | describe('CLI npm package generation', () => { 45 | /** 46 | * Clean up directories 47 | * 48 | * @param {string} dirs 49 | */ 50 | function cleanup(...dirs) { 51 | dirs.forEach((dir) => rimraf.sync(path.resolve(__dirname, dir))); 52 | } 53 | 54 | cleanup( 55 | '../dist', 56 | '../test_output', 57 | ); 58 | 59 | it('should fail when no name supplied', async () => { 60 | try { 61 | await require('../src/index.js'); 62 | } catch (e) { 63 | expect(e.message).toMatch('No module supplied.'); 64 | } 65 | }); 66 | 67 | it('should generate package inside /dist if no --outDir provided', async () => { 68 | jest.setTimeout(30000); 69 | 70 | process.argv.push('@anjuna/core'); 71 | await require('../src/index.js'); 72 | process.argv.pop(); 73 | 74 | const json = require(path.resolve(__dirname, '../dist/package.json')); 75 | expect(json.name).toBe('@anjuna/core-react'); 76 | }); 77 | 78 | it('should generate in correct directory if --outDir provided', async () => { 79 | jest.setTimeout(30000); 80 | 81 | process.argv.push('d3-stencil', '--outDir', 'test_output/outdir'); 82 | await require('../src/index.js'); 83 | process.argv.splice(-3, 3); 84 | 85 | const json = require(path.resolve(__dirname, '../test_output/outdir/package.json')); 86 | expect(json.name).toBe('d3-stencil-react'); 87 | }); 88 | 89 | /** 90 | * Validate package.json by checking all the override fileds except ignored ones are same. 91 | * 92 | * @param {object} overrideSource The json used for override. 93 | * @param {object} outputJson The package.json output. 94 | */ 95 | function compareJsonWithOverrideSource( 96 | overrideSource, 97 | outputJson, 98 | ) { 99 | Object.keys(overrideSource).forEach((key) => { 100 | if (ignoredPkgJsonOverrideFields.indexOf(key) !== -1) { 101 | expect(outputJson[key]).not.toEqual(testPkgOverride[key]); 102 | } else { 103 | expect(outputJson[key]).toEqual(testPkgOverride[key]); 104 | } 105 | }); 106 | } 107 | 108 | it('should generate package with correct package.json if --packageJson provided', async () => { 109 | jest.setTimeout(30000); 110 | 111 | process.argv.push( 112 | 'd3-stencil', 113 | '--outDir', 114 | 'test_output/packageJson', 115 | '--packageJson', 116 | JSON.stringify(testPkgOverride), 117 | ); 118 | await require('../src/index.js'); 119 | process.argv.splice(-5, 5); 120 | 121 | const json = require(path.resolve(__dirname, '../test_output/packageJson/package.json')); 122 | compareJsonWithOverrideSource( 123 | testPkgOverride, 124 | json, 125 | ); 126 | }); 127 | 128 | it('should generate package with correct package.json if --packageJsonPath provided', async () => { 129 | jest.setTimeout(30000); 130 | 131 | process.argv.push( 132 | '@anjuna/core', 133 | '--outDir', 134 | 'test_output/packageJsonPath', 135 | '--packageJsonPath', 136 | './test/pkgOverride.test.json', 137 | ); 138 | await require('../src/index.js'); 139 | process.argv.splice(-5, 5); 140 | 141 | const json = require(path.resolve(__dirname, '../test_output/packageJsonPath/package.json')); 142 | compareJsonWithOverrideSource( 143 | testPkgOverride, 144 | json, 145 | ); 146 | }); 147 | 148 | it('should not apply any override to package.json if provide a non-existent --packageJsonPath', async () => { 149 | jest.setTimeout(30000); 150 | 151 | process.argv.push( 152 | '@anjuna/core', 153 | '--outDir', 154 | 'test_output/wrongPackageJsonPath', 155 | '--packageJsonPath', 156 | './test/pkgOverride.test.wrong.json', 157 | ); 158 | await require('../src/index.js'); 159 | process.argv.splice(-5, 5); 160 | 161 | const json = require(path.resolve(__dirname, '../test_output/wrongPackageJsonPath/package.json')); 162 | Object.keys(testPkgOverride).forEach((key) => { 163 | expect(json[key]).not.toEqual(testPkgOverride[key]); 164 | }); 165 | }); 166 | }); 167 | -------------------------------------------------------------------------------- /test/pkgOverride.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "override-package-name", 3 | "main": "./src/empty.js", 4 | "module": "./dir/index.js", 5 | "types": "./types/type.d.ts", 6 | "peerDependencies": { }, 7 | "dependencies": { } 8 | } 9 | --------------------------------------------------------------------------------