├── .gitignore
├── dist
└── my-app
│ ├── .storybook
│ ├── preview.js
│ └── main.js
│ ├── src
│ ├── setupTests.js
│ ├── reportWebVitals.js
│ └── index.js
│ ├── config
│ ├── webpack
│ │ └── persistentCache
│ │ │ └── createEnvironmentHash.js
│ ├── jest
│ │ ├── cssTransform.js
│ │ ├── babelTransform.js
│ │ └── fileTransform.js
│ ├── getHttpsConfig.js
│ ├── paths.js
│ ├── modules.js
│ ├── env.js
│ ├── webpackDevServer.config.js
│ └── webpack.config.js
│ ├── .gitignore
│ ├── scripts
│ ├── test.js
│ ├── start.js
│ └── build.js
│ ├── README.md
│ └── package.json
├── .eslintrc.js
├── index.js
├── lib
├── template
│ ├── Component.stories.js
│ ├── App.js
│ ├── ClassPage.js
│ ├── ClassComponent.js
│ ├── ExtendJS.js
│ └── DS.js
├── Template.js
├── ExtendJS.js
├── Html.js
├── File.js
├── Plugin.js
└── parse
│ ├── ParseCommon.js
│ ├── ParseCode.js
│ ├── ParseRegex.js
│ ├── ParseRender.js
│ └── ParseOverride.js
├── package.json
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
--------------------------------------------------------------------------------
/dist/my-app/.storybook/preview.js:
--------------------------------------------------------------------------------
1 | export const parameters = {
2 | actions: { argTypesRegex: "^on[A-Z].*" },
3 | controls: {
4 | matchers: {
5 | color: /(background|color)$/i,
6 | date: /Date$/,
7 | },
8 | },
9 | }
--------------------------------------------------------------------------------
/dist/my-app/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/dist/my-app/config/webpack/persistentCache/createEnvironmentHash.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const { createHash } = require('crypto');
3 |
4 | module.exports = env => {
5 | const hash = createHash('md5');
6 | hash.update(JSON.stringify(env));
7 |
8 | return hash.digest('hex');
9 | };
10 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "env": {
3 | "browser": true,
4 | "es2021": true,
5 | "node": true
6 | },
7 | "extends": [
8 | "standard"
9 | ],
10 | "parserOptions": {
11 | "ecmaVersion": 12,
12 | "sourceType": "module"
13 | },
14 | "rules": {
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const Plugin = require('./lib/Plugin.js')
2 |
3 | // executed by electron's node.js
4 | module.exports = {
5 | async saveToFile (data, lib) {
6 | await Plugin.syncAppFiles(data.folder)
7 | await Plugin.syncStaticFolders(data)
8 | Plugin.syncIndexHtml(data.folder)
9 | Plugin.syncJsCode(data, lib)
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/dist/my-app/.storybook/main.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "stories": [
3 | "../src/**/*.stories.mdx",
4 | "../src/**/*.stories.@(js|jsx|ts|tsx)"
5 | ],
6 | "addons": [
7 | "@storybook/addon-links",
8 | "@storybook/addon-essentials"
9 | ],
10 | "staticDirs": [
11 | "../public"
12 | ],
13 | "framework": "@storybook/react"
14 | }
--------------------------------------------------------------------------------
/lib/template/Component.stories.js:
--------------------------------------------------------------------------------
1 | import CLASSNAME from '../FILEPATH'
2 | import * as css from '../../public/css/compiled/style.css' // eslint-disable-line
3 |
4 | export default {
5 | title: 'Desech/CLASSNAME',
6 | component: CLASSNAME
7 | }
8 |
9 | export const CLASSNAMEStory = (args) =>
10 | CLASSNAMEStory.storyName = 'CLASSNAME'
11 |
--------------------------------------------------------------------------------
/lib/Template.js:
--------------------------------------------------------------------------------
1 | const File = require('./File.js')
2 |
3 | module.exports = {
4 | getProjectFile (folder, file) {
5 | const destFile = File.resolve(folder, file)
6 | return File.readFile(destFile)
7 | },
8 |
9 | getTemplate (template) {
10 | const file = File.resolve(__dirname, 'template', template)
11 | return File.readFile(file)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/dist/my-app/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // This is a custom Jest transformer turning style imports into empty objects.
4 | // http://facebook.github.io/jest/docs/en/webpack.html
5 |
6 | module.exports = {
7 | process() {
8 | return 'module.exports = {};';
9 | },
10 | getCacheKey() {
11 | // The output is always the same.
12 | return 'cssTransform';
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/dist/my-app/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/lib/template/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { BrowserRouter, Routes, Route } from 'react-router-dom'
3 | // desech - start import block
4 | // desech - end import block
5 |
6 | export default function App () {
7 | return (
8 |
9 |
10 | {/* desech - start router block */}
11 | {/* desech - end router block */}
12 |
13 |
14 | )
15 | }
16 |
--------------------------------------------------------------------------------
/dist/my-app/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/dist/my-app/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import reportWebVitals from './reportWebVitals';
5 |
6 | ReactDOM.render(
7 |
8 |
9 | ,
10 | document.getElementById('root')
11 | );
12 |
13 | // If you want to start measuring performance in your app, pass a function
14 | // to log results (for example: reportWebVitals(console.log))
15 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
16 | reportWebVitals();
17 |
--------------------------------------------------------------------------------
/lib/template/ClassPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | // desech - start import block
3 | // desech - end import block
4 |
5 | /**
6 | * A desech page
7 | **/
8 | export default class CLASSNAME extends React.Component {
9 | render () {
10 | const d = DS.getDesechData(this.props, this.getComponentData()) // eslint-disable-line
11 | // desech - start render block
12 | // desech - end render block
13 | return render
14 | }
15 |
16 | getComponentData () {
17 | // desech - start data block
18 | // desech - end data block
19 | return data
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/dist/my-app/config/jest/babelTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const babelJest = require('babel-jest').default;
4 |
5 | const hasJsxRuntime = (() => {
6 | if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') {
7 | return false;
8 | }
9 |
10 | try {
11 | require.resolve('react/jsx-runtime');
12 | return true;
13 | } catch (e) {
14 | return false;
15 | }
16 | })();
17 |
18 | module.exports = babelJest.createTransformer({
19 | presets: [
20 | [
21 | require.resolve('babel-preset-react-app'),
22 | {
23 | runtime: hasJsxRuntime ? 'automatic' : 'classic',
24 | },
25 | ],
26 | ],
27 | babelrc: false,
28 | configFile: false,
29 | });
30 |
--------------------------------------------------------------------------------
/lib/template/ClassComponent.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 | // desech - start import block
4 | // desech - end import block
5 |
6 | /**
7 | * A desech component
8 | **/
9 | export default class CLASSNAME extends React.Component {
10 | render () {
11 | const d = DS.getDesechData(this.props, this.getComponentData()) // eslint-disable-line
12 | // desech - start render block
13 | // desech - end render block
14 | return render
15 | }
16 |
17 | getComponentData () {
18 | // desech - start data block
19 | // desech - end data block
20 | return data
21 | }
22 | }
23 |
24 | CLASSNAME.propTypes = {
25 | // desech - start props block
26 | // desech - end props block
27 | }
28 |
--------------------------------------------------------------------------------
/lib/ExtendJS.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | toPascalCase (string) {
3 | return string.replace(/(?:^\w|[A-Z]|\b\w|\s+)/g, match => {
4 | if (+match === 0) return ''
5 | return match.toUpperCase()
6 | }).replace(/\W/g, '')
7 | },
8 |
9 | isEmpty (obj) {
10 | return !obj || (Object.keys(obj).length === 0 && obj.constructor === Object)
11 | },
12 |
13 | unique (array) {
14 | return [...new Set(array)]
15 | },
16 |
17 | removeFromArray (array, value) {
18 | const index = array.indexOf(value)
19 | if (index !== -1) array.splice(index, 1)
20 | },
21 |
22 | splitByCharacter (string, delimiter, wrap1 = '(', wrap2 = ')') {
23 | // regex is /(?![^(]*\))/gi
24 | const regex = new RegExp(`${delimiter}(?![^${wrap1}]*\\${wrap2})`, 'gi')
25 | return string.split(regex)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "studio-react",
3 | "version": "2.0.1",
4 | "description": "React Desech Studio Plugin",
5 | "main": "index.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "git@github.com:desech/studio-react.git"
9 | },
10 | "homepage": "https://www.desech.com",
11 | "author": {
12 | "name": "Desech Studio SRL",
13 | "email": "contact@desech.com"
14 | },
15 | "license": "ISC",
16 | "devDependencies": {
17 | "eslint": "^8.5.0",
18 | "eslint-config-standard": "^16.0.3",
19 | "eslint-plugin-import": "^2.25.3",
20 | "eslint-plugin-node": "^11.1.0",
21 | "eslint-plugin-promise": "^6.0.0",
22 | "eslint-plugin-standard": "^4.1.0"
23 | },
24 | "desech": {
25 | "title": "React",
26 | "author": "Desech",
27 | "category": "exportCode",
28 | "url": "https://github.com/desech/studio-react",
29 | "requires": "2.0.1",
30 | "autoUpdate": true
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Desech
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 |
--------------------------------------------------------------------------------
/lib/template/ExtendJS.js:
--------------------------------------------------------------------------------
1 | export default class ExtendJS {
2 | static toPascalCase (string) {
3 | return string.replace(/(?:^\w|[A-Z]|\b\w|\s+)/g, match => {
4 | if (+match === 0) return ''
5 | return match.toUpperCase()
6 | }).replace(/\W/g, '')
7 | }
8 |
9 | static isEmpty (obj) {
10 | return !obj || (Object.keys(obj).length === 0 && obj.constructor === Object)
11 | }
12 |
13 | static objectFlip (obj) {
14 | const ret = {}
15 | Object.keys(obj).forEach(key => {
16 | ret[obj[key]] = key
17 | })
18 | return ret
19 | }
20 |
21 | static mergeDeep (target, ...sources) {
22 | if (!sources.length) return target
23 | const source = sources.shift()
24 | if (typeof target === 'object' && typeof source === 'object') {
25 | for (const key in source) {
26 | if (typeof source[key] === 'object') {
27 | if (!target[key]) Object.assign(target, { [key]: {} })
28 | this.mergeDeep(target[key], source[key])
29 | } else {
30 | Object.assign(target, { [key]: source[key] })
31 | }
32 | }
33 | }
34 | return this.mergeDeep(target, ...sources)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/dist/my-app/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const camelcase = require('camelcase');
5 |
6 | // This is a custom Jest transformer turning file imports into filenames.
7 | // http://facebook.github.io/jest/docs/en/webpack.html
8 |
9 | module.exports = {
10 | process(src, filename) {
11 | const assetFilename = JSON.stringify(path.basename(filename));
12 |
13 | if (filename.match(/\.svg$/)) {
14 | // Based on how SVGR generates a component name:
15 | // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
16 | const pascalCaseFilename = camelcase(path.parse(filename).name, {
17 | pascalCase: true,
18 | });
19 | const componentName = `Svg${pascalCaseFilename}`;
20 | return `const React = require('react');
21 | module.exports = {
22 | __esModule: true,
23 | default: ${assetFilename},
24 | ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
25 | return {
26 | $$typeof: Symbol.for('react.element'),
27 | type: 'svg',
28 | ref: ref,
29 | key: null,
30 | props: Object.assign({}, props, {
31 | children: ${assetFilename}
32 | })
33 | };
34 | }),
35 | };`;
36 | }
37 |
38 | return `module.exports = ${assetFilename};`;
39 | },
40 | };
41 |
--------------------------------------------------------------------------------
/dist/my-app/scripts/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // Do this as the first thing so that any code reading it knows the right env.
4 | process.env.BABEL_ENV = 'test';
5 | process.env.NODE_ENV = 'test';
6 | process.env.PUBLIC_URL = '';
7 |
8 | // Makes the script crash on unhandled rejections instead of silently
9 | // ignoring them. In the future, promise rejections that are not handled will
10 | // terminate the Node.js process with a non-zero exit code.
11 | process.on('unhandledRejection', err => {
12 | throw err;
13 | });
14 |
15 | // Ensure environment variables are read.
16 | require('../config/env');
17 |
18 | const jest = require('jest');
19 | const execSync = require('child_process').execSync;
20 | let argv = process.argv.slice(2);
21 |
22 | function isInGitRepository() {
23 | try {
24 | execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
25 | return true;
26 | } catch (e) {
27 | return false;
28 | }
29 | }
30 |
31 | function isInMercurialRepository() {
32 | try {
33 | execSync('hg --cwd . root', { stdio: 'ignore' });
34 | return true;
35 | } catch (e) {
36 | return false;
37 | }
38 | }
39 |
40 | // Watch unless on CI or explicitly running all tests
41 | if (
42 | !process.env.CI &&
43 | argv.indexOf('--watchAll') === -1 &&
44 | argv.indexOf('--watchAll=false') === -1
45 | ) {
46 | // https://github.com/facebook/create-react-app/issues/5210
47 | const hasSourceControl = isInGitRepository() || isInMercurialRepository();
48 | argv.push(hasSourceControl ? '--watch' : '--watchAll');
49 | }
50 |
51 |
52 | jest.run(argv);
53 |
--------------------------------------------------------------------------------
/dist/my-app/config/getHttpsConfig.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const crypto = require('crypto');
6 | const chalk = require('react-dev-utils/chalk');
7 | const paths = require('./paths');
8 |
9 | // Ensure the certificate and key provided are valid and if not
10 | // throw an easy to debug error
11 | function validateKeyAndCerts({ cert, key, keyFile, crtFile }) {
12 | let encrypted;
13 | try {
14 | // publicEncrypt will throw an error with an invalid cert
15 | encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
16 | } catch (err) {
17 | throw new Error(
18 | `The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`
19 | );
20 | }
21 |
22 | try {
23 | // privateDecrypt will throw an error with an invalid key
24 | crypto.privateDecrypt(key, encrypted);
25 | } catch (err) {
26 | throw new Error(
27 | `The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${
28 | err.message
29 | }`
30 | );
31 | }
32 | }
33 |
34 | // Read file and throw an error if it doesn't exist
35 | function readEnvFile(file, type) {
36 | if (!fs.existsSync(file)) {
37 | throw new Error(
38 | `You specified ${chalk.cyan(
39 | type
40 | )} in your env, but the file "${chalk.yellow(file)}" can't be found.`
41 | );
42 | }
43 | return fs.readFileSync(file);
44 | }
45 |
46 | // Get the https config
47 | // Return cert files if provided in env, otherwise just true or false
48 | function getHttpsConfig() {
49 | const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
50 | const isHttps = HTTPS === 'true';
51 |
52 | if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
53 | const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
54 | const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
55 | const config = {
56 | cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
57 | key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
58 | };
59 |
60 | validateKeyAndCerts({ ...config, keyFile, crtFile });
61 | return config;
62 | }
63 | return isHttps;
64 | }
65 |
66 | module.exports = getHttpsConfig;
67 |
--------------------------------------------------------------------------------
/dist/my-app/config/paths.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');
6 |
7 | // Make sure any symlinks in the project folder are resolved:
8 | // https://github.com/facebook/create-react-app/issues/637
9 | const appDirectory = fs.realpathSync(process.cwd());
10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
11 |
12 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer
13 | // "public path" at which the app is served.
14 | // webpack needs to know it to put the right