diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 5cbd9d2dd44..00000000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "create-react-app"]
- path = create-react-app
- url = https://github.com/swagger-api/swagger-editor-cra.git
diff --git a/README.md b/README.md
index d0e29ac9433..46cb3611c65 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,5 @@
# SwaggerEditor
-SwaggerEditor is using [**forked** Create React App](https://github.com/swagger-api/swagger-editor-cra/) as it's building infrastructure.
-
## Table of Contents
- [Anonymized analytics](#anonymized-analytics)
@@ -309,8 +307,6 @@ Run the following commands to set up the repository for local development:
$ git clone https://github.com/swagger-api/swagger-editor.git
$ cd swagger-editor
$ git checkout next
- $ git submodule init
- $ git submodule update
$ npm i
$ npm start
```
diff --git a/config/env.js b/config/env.js
new file mode 100644
index 00000000000..9fcf7c1b184
--- /dev/null
+++ b/config/env.js
@@ -0,0 +1,105 @@
+import fs from 'fs';
+import path from 'path';
+import dotenv from 'dotenv';
+import dotenvExpand from 'dotenv-expand';
+
+import paths from './paths.js';
+import { require } from './util.js';
+
+// Make sure that including paths.js after env.js will read .env variables.
+delete require.cache[require.resolve('./paths')];
+
+const { NODE_ENV } = process.env;
+if (!NODE_ENV) {
+ throw new Error('The NODE_ENV environment variable is required but was not specified.');
+}
+
+// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
+const dotenvFiles = [
+ `${paths.dotenv}.${NODE_ENV}.local`,
+ // Don't include `.env.local` for `test` environment
+ // since normally you expect tests to produce the same
+ // results for everyone
+ NODE_ENV !== 'test' && `${paths.dotenv}.local`,
+ `${paths.dotenv}.${NODE_ENV}`,
+ paths.dotenv,
+].filter(Boolean);
+
+// Load environment variables from .env* files. Suppress warnings using silent
+// if this file is missing. dotenv will never modify any environment variables
+// that have already been set. Variable expansion is supported in .env files.
+// https://github.com/motdotla/dotenv
+// https://github.com/motdotla/dotenv-expand
+dotenvFiles.forEach((dotenvFile) => {
+ if (fs.existsSync(dotenvFile)) {
+ dotenvExpand(
+ dotenv.config({
+ path: dotenvFile,
+ })
+ );
+ }
+});
+
+// We support resolving modules according to `NODE_PATH`.
+// This lets you use absolute paths in imports inside large monorepos:
+// https://github.com/facebook/create-react-app/issues/253.
+// It works similar to `NODE_PATH` in Node itself:
+// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
+// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
+// Otherwise, we risk importing Node.js core modules into an app instead of webpack shims.
+// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
+// We also resolve them to make sure all tools using them work consistently.
+const appDirectory = fs.realpathSync(process.cwd());
+process.env.NODE_PATH = (process.env.NODE_PATH || '')
+ .split(path.delimiter)
+ .filter((folder) => folder && !path.isAbsolute(folder))
+ .map((folder) => path.resolve(appDirectory, folder))
+ .join(path.delimiter);
+
+// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
+// injected into the application via DefinePlugin in webpack configuration.
+const REACT_APP = /^REACT_APP_/i;
+
+function getClientEnvironment(publicUrl) {
+ const raw = Object.keys(process.env)
+ .filter((key) => REACT_APP.test(key))
+ .reduce(
+ (env, key) => {
+ return {
+ ...env,
+ [key]: process.env[key],
+ };
+ },
+ {
+ // Useful for determining whether we're running in production mode.
+ // Most importantly, it switches React into the correct mode.
+ NODE_ENV: process.env.NODE_ENV || 'development',
+ // Useful for resolving the correct path to static assets in `public`.
+ // For example,
.
+ // This should only be used as an escape hatch. Normally you would put
+ // images into the `src` and `import` them in code to get their paths.
+ PUBLIC_URL: publicUrl,
+ // We support configuring the sockjs pathname during development.
+ // These settings let a developer run multiple simultaneous projects.
+ // They are used as the connection `hostname`, `pathname` and `port`
+ // in webpackHotDevClient. They are used as the `sockHost`, `sockPath`
+ // and `sockPort` options in webpack-dev-server.
+ WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
+ WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
+ WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
+ // Whether or not react-refresh is enabled.
+ // It is defined here so it is available in the webpackHotDevClient.
+ FAST_REFRESH: process.env.FAST_REFRESH !== 'false',
+ }
+ );
+ // Stringify all values so we can feed into webpack DefinePlugin
+ const stringified = {
+ 'process.env': Object.keys(raw).reduce((env, key) => {
+ return { ...env, [key]: JSON.stringify(raw[key]) };
+ }, {}),
+ };
+
+ return { raw, stringified };
+}
+
+export default getClientEnvironment;
diff --git a/config/getHttpsConfig.js b/config/getHttpsConfig.js
new file mode 100644
index 00000000000..db5736b2174
--- /dev/null
+++ b/config/getHttpsConfig.js
@@ -0,0 +1,59 @@
+import fs from 'fs';
+import path from 'path';
+import crypto from 'crypto';
+import chalk from 'chalk';
+
+import paths from './paths.js';
+
+// Ensure the certificate and key provided are valid and if not
+// throw an easy to debug error
+function validateKeyAndCerts({ cert, key, keyFile, crtFile }) {
+ let encrypted;
+ try {
+ // publicEncrypt will throw an error with an invalid cert
+ encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
+ } catch (err) {
+ throw new Error(`The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`);
+ }
+
+ try {
+ // privateDecrypt will throw an error with an invalid key
+ crypto.privateDecrypt(key, encrypted);
+ } catch (err) {
+ throw new Error(`The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${err.message}`);
+ }
+}
+
+// Read file and throw an error if it doesn't exist
+function readEnvFile(file, type) {
+ if (!fs.existsSync(file)) {
+ throw new Error(
+ `You specified ${chalk.cyan(
+ type
+ )} in your env, but the file "${chalk.yellow(file)}" can't be found.`
+ );
+ }
+ return fs.readFileSync(file);
+}
+
+// Get the https config
+// Return cert files if provided in env, otherwise just true or false
+function getHttpsConfig() {
+ const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
+ const isHttps = HTTPS === 'true';
+
+ if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
+ const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
+ const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
+ const config = {
+ cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
+ key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
+ };
+
+ validateKeyAndCerts({ ...config, keyFile, crtFile });
+ return config;
+ }
+ return isHttps;
+}
+
+export default getHttpsConfig;
diff --git a/config/jest/babelTransform.js b/config/jest/babelTransform.js
new file mode 100644
index 00000000000..0a3cb314749
--- /dev/null
+++ b/config/jest/babelTransform.js
@@ -0,0 +1,30 @@
+import babelJest from 'babel-jest';
+
+import { require } from '../util.js';
+
+const hasJsxRuntime = (() => {
+ if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') {
+ return false;
+ }
+
+ try {
+ require.resolve('react/jsx-runtime');
+ return true;
+ } catch (e) {
+ return false;
+ }
+})();
+
+export default babelJest.default.createTransformer({
+ presets: [
+ [
+ require.resolve('babel-preset-react-app'),
+ {
+ runtime: hasJsxRuntime ? 'automatic' : 'classic',
+ },
+ ],
+ ],
+ plugins: ['@babel/plugin-transform-class-static-block'],
+ babelrc: false,
+ configFile: false,
+});
diff --git a/config/jest/cssTransform.js b/config/jest/cssTransform.js
new file mode 100644
index 00000000000..e65b9dcd476
--- /dev/null
+++ b/config/jest/cssTransform.js
@@ -0,0 +1,12 @@
+// This is a custom Jest transformer turning style imports into empty objects.
+// http://facebook.github.io/jest/docs/en/webpack.html
+
+export default {
+ process() {
+ return 'module.exports = {};';
+ },
+ getCacheKey() {
+ // The output is always the same.
+ return 'cssTransform';
+ },
+};
diff --git a/config/jest/fileTransform.js b/config/jest/fileTransform.js
new file mode 100644
index 00000000000..a74b0162768
--- /dev/null
+++ b/config/jest/fileTransform.js
@@ -0,0 +1,38 @@
+import path from 'path';
+import camelcase from 'camelcase';
+
+// This is a custom Jest transformer turning file imports into filenames.
+// http://facebook.github.io/jest/docs/en/webpack.html
+
+export default {
+ process(src, filename) {
+ const assetFilename = JSON.stringify(path.basename(filename));
+
+ if (filename.match(/\.svg$/)) {
+ // Based on how SVGR generates a component name:
+ // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
+ const pascalCaseFilename = camelcase(path.parse(filename).name, {
+ pascalCase: true,
+ });
+ const componentName = `Svg${pascalCaseFilename}`;
+ return `const React = require('react');
+ module.exports = {
+ __esModule: true,
+ default: ${assetFilename},
+ ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
+ return {
+ $$typeof: Symbol.for('react.element'),
+ type: 'svg',
+ ref: ref,
+ key: null,
+ props: Object.assign({}, props, {
+ children: ${assetFilename}
+ })
+ };
+ }),
+ };`;
+ }
+
+ return `module.exports = ${assetFilename};`;
+ },
+};
diff --git a/config/modules.js b/config/modules.js
new file mode 100644
index 00000000000..307159b7c9b
--- /dev/null
+++ b/config/modules.js
@@ -0,0 +1,135 @@
+import fs from 'fs';
+import path from 'path';
+import chalk from 'chalk';
+// eslint-disable-next-line import/no-extraneous-dependencies
+import typescript from 'typescript';
+
+import paths from './paths.js';
+
+/**
+ * Get additional module paths based on the baseUrl of a compilerOptions object.
+ *
+ * @param {Object} options
+ */
+function getAdditionalModulePaths(options = {}) {
+ const { baseUrl } = options;
+
+ if (!baseUrl) {
+ return '';
+ }
+
+ const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
+
+ // We don't need to do anything if `baseUrl` is set to `node_modules`. This is
+ // the default behavior.
+ if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
+ return null;
+ }
+
+ // Allow the user set the `baseUrl` to `appSrc`.
+ if (path.relative(paths.appSrc, baseUrlResolved) === '') {
+ return [paths.appSrc];
+ }
+
+ // If the path is equal to the root directory we ignore it here.
+ // We don't want to allow importing from the root directly as source files are
+ // not transpiled outside of `src`. We do allow importing them with the
+ // absolute path (e.g. `src/Components/Button.js`) but we set that up with
+ // an alias.
+ if (path.relative(paths.appPath, baseUrlResolved) === '') {
+ return null;
+ }
+
+ // Otherwise, throw an error.
+ throw new Error(
+ chalk.red.bold(
+ "Your project's `baseUrl` can only be set to `src` or `node_modules`." +
+ ' Create React App does not support other values at this time.'
+ )
+ );
+}
+
+/**
+ * Get webpack aliases based on the baseUrl of a compilerOptions object.
+ *
+ * @param {*} options
+ */
+function getWebpackAliases(options = {}) {
+ const { baseUrl } = options;
+
+ if (!baseUrl) {
+ return {};
+ }
+
+ const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
+
+ if (path.relative(paths.appPath, baseUrlResolved) === '') {
+ return {
+ src: paths.appSrc,
+ };
+ }
+
+ return {};
+}
+
+/**
+ * Get jest aliases based on the baseUrl of a compilerOptions object.
+ *
+ * @param {*} options
+ */
+function getJestAliases(options = {}) {
+ const { baseUrl } = options;
+
+ if (!baseUrl) {
+ return {};
+ }
+
+ const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
+
+ if (path.relative(paths.appPath, baseUrlResolved) === '') {
+ return {
+ '^src/(.*)$': '/src/$1',
+ };
+ }
+
+ return {};
+}
+
+function getModules() {
+ // Check if TypeScript is setup
+ const hasTsConfig = fs.existsSync(paths.appTsConfig);
+ const hasJsConfig = fs.existsSync(paths.appJsConfig);
+
+ if (hasTsConfig && hasJsConfig) {
+ throw new Error(
+ 'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
+ );
+ }
+
+ let config;
+
+ // If there's a tsconfig.json we assume it's a
+ // TypeScript project and set up the config
+ // based on tsconfig.json
+ if (hasTsConfig) {
+ config = typescript.readConfigFile(paths.appTsConfig, fs.readFileSync).config;
+ // Otherwise we'll check if there is jsconfig.json
+ // for non TS projects.
+ } else if (hasJsConfig) {
+ config = paths.appJsConfig;
+ }
+
+ config = config || {};
+ const options = config.compilerOptions || {};
+
+ const additionalModulePaths = getAdditionalModulePaths(options);
+
+ return {
+ additionalModulePaths,
+ webpackAliases: getWebpackAliases(options),
+ jestAliases: getJestAliases(options),
+ hasTsConfig,
+ };
+}
+
+export default getModules();
diff --git a/config/paths.js b/config/paths.js
new file mode 100644
index 00000000000..87031be28e2
--- /dev/null
+++ b/config/paths.js
@@ -0,0 +1,78 @@
+import path from 'path';
+import fs from 'fs';
+import getPublicUrlOrPath from 'react-dev-utils/getPublicUrlOrPath.js';
+
+// Make sure any symlinks in the project folder are resolved:
+// https://github.com/facebook/create-react-app/issues/637
+const appDirectory = fs.realpathSync(process.cwd());
+const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);
+
+// We use `PUBLIC_URL` environment variable or "homepage" field to infer
+// "public path" at which the app is served.
+// webpack needs to know it to put the right