@pega/custom-dx-components 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/.eslintrc.json +18 -0
  2. package/.prettierignore +2 -0
  3. package/.prettierrc.json +1 -0
  4. package/.vscode/extensions.json +9 -0
  5. package/.vscode/settings.json +48 -0
  6. package/LICENSE +185 -0
  7. package/README.md +204 -0
  8. package/bin/index.js +5 -0
  9. package/cspell.json +26 -0
  10. package/package.json +67 -0
  11. package/src/cli.js +92 -0
  12. package/src/constants.js +92 -0
  13. package/src/tasks/authenticate/helper.js +60 -0
  14. package/src/tasks/authenticate/index.js +75 -0
  15. package/src/tasks/create/index.js +304 -0
  16. package/src/tasks/create/template/config.json.mustache +67 -0
  17. package/src/tasks/create/template/demo.stories.jsx.mustache +44 -0
  18. package/src/tasks/create/template/index.jsx.mustache +55 -0
  19. package/src/tasks/create/template/styles.js.mustache +7 -0
  20. package/src/tasks/delete/helper.js +105 -0
  21. package/src/tasks/delete/index.js +45 -0
  22. package/src/tasks/index.js +9 -0
  23. package/src/tasks/init/helper.js +63 -0
  24. package/src/tasks/init/index.js +165 -0
  25. package/src/tasks/init/template/.eslintrc.json +10 -0
  26. package/src/tasks/init/template/.prettierrc.json +1 -0
  27. package/src/tasks/init/template/.storybook/main.js +6 -0
  28. package/src/tasks/init/template/.storybook/pega-logo.svg +16 -0
  29. package/src/tasks/init/template/.storybook/preview.tsx +44 -0
  30. package/src/tasks/init/template/.storybook/theme.js +44 -0
  31. package/src/tasks/init/template/.stylelintrc.json +4 -0
  32. package/src/tasks/init/template/.vscode/extensions.json +9 -0
  33. package/src/tasks/init/template/.vscode/settings.json +48 -0
  34. package/src/tasks/init/template/README.md +204 -0
  35. package/src/tasks/init/template/build.config.json +1 -0
  36. package/src/tasks/init/template/cspell.json +14 -0
  37. package/src/tasks/init/template/package.json.mustache +69 -0
  38. package/src/tasks/init/template/src/components/MBTAList/MBTAList.stories.tsx +10 -0
  39. package/src/tasks/init/template/src/components/MBTAList/MBTAList.tsx +122 -0
  40. package/src/tasks/init/template/src/components/MBTAList/icons/accessible.icon.tsx +14 -0
  41. package/src/tasks/init/template/src/components/MBTAList/icons/bus.icon.tsx +13 -0
  42. package/src/tasks/init/template/src/components/MBTAList/icons/mbta.icon.tsx +10 -0
  43. package/src/tasks/init/template/src/components/MBTAList/icons/subway.icon.tsx +14 -0
  44. package/src/tasks/init/template/src/components/MBTAList/index.ts +2 -0
  45. package/src/tasks/init/template/src/components/Organization_Library_MediaURL/MediaURL.stories.tsx +19 -0
  46. package/src/tasks/init/template/src/components/Organization_Library_MediaURL/MediaURL.styles.ts +5 -0
  47. package/src/tasks/init/template/src/components/Organization_Library_MediaURL/MediaURL.types.ts +10 -0
  48. package/src/tasks/init/template/src/components/Organization_Library_MediaURL/MediaURLDisplay.tsx +25 -0
  49. package/src/tasks/init/template/src/components/Organization_Library_MediaURL/MediaURLInput.tsx +24 -0
  50. package/src/tasks/init/template/src/components/Organization_Library_MediaURL/config.json +13 -0
  51. package/src/tasks/init/template/src/components/Organization_Library_MediaURL/index.ts +2 -0
  52. package/src/tasks/init/template/src/components/Organization_Library_VideoPlayer/config.json +44 -0
  53. package/src/tasks/init/template/src/components/Organization_Library_VideoPlayer/demo.stories.jsx +40 -0
  54. package/src/tasks/init/template/src/components/Organization_Library_VideoPlayer/index.jsx +42 -0
  55. package/src/tasks/init/template/src/components/Organization_Library_VideoPlayer/styles.js +5 -0
  56. package/src/tasks/init/template/tasks.config.json +21 -0
  57. package/src/tasks/init/template/tsconfig.build.json +16 -0
  58. package/src/tasks/init/template/tsconfig.json +8 -0
  59. package/src/tasks/list/helper.js +118 -0
  60. package/src/tasks/list/index.js +51 -0
  61. package/src/tasks/publish/bundle/builder/index.js +174 -0
  62. package/src/tasks/publish/bundle/builder/modules.js +139 -0
  63. package/src/tasks/publish/bundle/builder/paths.js +50 -0
  64. package/src/tasks/publish/bundle/builder/webpack.config.js +334 -0
  65. package/src/tasks/publish/bundle/index.js +65 -0
  66. package/src/tasks/publish/helper.js +145 -0
  67. package/src/tasks/publish/index.js +55 -0
  68. package/src/tasks/update/index.js +5 -0
  69. package/src/tasks/upgrade/index.js +31 -0
  70. package/src/tasks/validator/index.js +102 -0
  71. package/src/util.js +277 -0
@@ -0,0 +1,40 @@
1
+ import React, { useState } from 'react';
2
+ import { withKnobs, text, boolean } from '@storybook/addon-knobs';
3
+
4
+ import VideoPlayer from './index';
5
+
6
+ export default {
7
+ title: 'VideoPlayer',
8
+ decorators: [withKnobs],
9
+ component: VideoPlayer
10
+ };
11
+
12
+ export const baseVideoPlayer = () => {
13
+ const [value, setValue] = useState('test value');
14
+
15
+ const props = {
16
+ getPConnect: () => {
17
+ return {
18
+ getActionsApi: () => {
19
+ return {
20
+ updateFieldValue: (propName, value) => {
21
+ setValue(value);
22
+ }
23
+ };
24
+ },
25
+ getStateProps: () => {
26
+ return { value: '.name' };
27
+ }
28
+ };
29
+ },
30
+ value: text('src', 'https://www.youtube.com/watch?v=EtG5IuNGYSk'),
31
+ placeholder: text('Placeholder', 'Test placeholder'),
32
+ disabled: boolean('Disabled', false),
33
+ readOnly: boolean('Disabled', false),
34
+ required: boolean('Disabled', false),
35
+ label: text('Label', 'Video player label'),
36
+ testId: text('Test id', 'video-12344566')
37
+ };
38
+
39
+ return <VideoPlayer {...props} />;
40
+ };
@@ -0,0 +1,42 @@
1
+ import PropTypes from 'prop-types';
2
+ import React from 'react';
3
+ import { Label } from '@pega/cosmos-react-core';
4
+ import ReactPlayer from 'react-player';
5
+
6
+ import StyledVideoPlayerWrapper from './styles';
7
+
8
+ const VideoPlayer = props => {
9
+ const { getPConnect, value, placeholder, disabled, readOnly, required, label } = props;
10
+
11
+ const pConn = getPConnect();
12
+ const actions = pConn.getActionsApi();
13
+ const propName = pConn?.getStateProps()?.value;
14
+
15
+ return (
16
+ <StyledVideoPlayerWrapper>
17
+ <Label>{label}</Label>
18
+ <ReactPlayer url={value} />
19
+ </StyledVideoPlayerWrapper>
20
+ );
21
+ };
22
+
23
+ VideoPlayer.defaultProps = {
24
+ value: '',
25
+ placeholder: '',
26
+ disabled: false,
27
+ readOnly: false,
28
+ required: false,
29
+ testId: null
30
+ };
31
+ VideoPlayer.propTypes = {
32
+ label: PropTypes.string,
33
+ value: PropTypes.string.isRequired,
34
+ placeholder: PropTypes.string,
35
+ getPConnect: PropTypes.func.isRequired,
36
+ disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
37
+ readOnly: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
38
+ required: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
39
+ testId: PropTypes.string
40
+ };
41
+
42
+ export default VideoPlayer;
@@ -0,0 +1,5 @@
1
+ import styled, { css } from 'styled-components';
2
+
3
+ export default styled.div(() => {
4
+ return css``;
5
+ });
@@ -0,0 +1,21 @@
1
+ {
2
+ "components-directory-path": "src/components",
3
+ "server-config": {
4
+ "server": "https://localhost:38764/prweb",
5
+ "user": "user",
6
+ "password": "password",
7
+ "rulesetName": "rulesetName",
8
+ "rulesetVersion": "rulesetVersion",
9
+ "sourceOfComponents": "Server",
10
+ "devBuild": false,
11
+ "clientId": "",
12
+ "clientSecret": ""
13
+ },
14
+ "component": {
15
+ "library": "",
16
+ "type": "",
17
+ "subtype": "",
18
+ "description": "",
19
+ "icon": ""
20
+ }
21
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "include": ["./src/**/*.ts", "./src/**/*.tsx", "./src/**/*.js", "./src/**/*.jsx"],
4
+ "exclude": [
5
+ "./src/**/*.stories.ts",
6
+ "./src/**/*.stories.tsx",
7
+ "./src/**/*.stories.js",
8
+ "./src/**/*.stories.jsx"
9
+ ],
10
+ "compilerOptions": {
11
+ "noEmit": false,
12
+ "composite": true,
13
+ "rootDir": "./src",
14
+ "outDir": "./lib"
15
+ }
16
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "@pega/tsconfig/index.json",
3
+ "include": ["./**/*", ".storybook/**/*"],
4
+ "compilerOptions": {
5
+ "noEmit": true,
6
+ "allowJs": true
7
+ }
8
+ }
@@ -0,0 +1,118 @@
1
+ import fs from 'fs';
2
+ import https from 'https';
3
+
4
+ import chalk from 'chalk';
5
+ import fetch from 'node-fetch';
6
+
7
+ import { LIST_COMPONENT_SERVICE_REST_ENDPOINT, TOKEN_PATH } from '../../constants.js';
8
+ import { constructCompleteUrl, getComponents, getPegaServerConfig } from '../../util.js';
9
+
10
+ export const SOURCE_OF_COMPONENT_TYPES = {
11
+ SERVER: 'Server',
12
+ LOCAL: 'Local'
13
+ };
14
+
15
+ export const getListComponentsQuestions = async (options, sourceOfComponentsOption) => {
16
+ const defaultPegaServerConfig = await getPegaServerConfig();
17
+
18
+ return [
19
+ {
20
+ name: 'sourceOfComponents',
21
+ type: 'rawlist',
22
+ message: 'List components from Server or Local ?',
23
+ choices: Object.values(SOURCE_OF_COMPONENT_TYPES),
24
+ default: defaultPegaServerConfig.sourceOfComponents,
25
+ when() {
26
+ return !options.params[3];
27
+ }
28
+ }
29
+ ];
30
+ };
31
+
32
+ export const listLocalComponents = async sourceOfComponents => {
33
+ let localComponents = await getComponents();
34
+ localComponents = localComponents.map(name => ({ 'Rule name': name }));
35
+ if (localComponents.length > 0) {
36
+ console.log(chalk.bold.blueBright(`List of custom components in ${sourceOfComponents}`));
37
+ console.table(localComponents, ['Rule name']);
38
+ } else {
39
+ console.log(chalk.bold.redBright(`No custom components in ${sourceOfComponents}`));
40
+ }
41
+ };
42
+
43
+ export const getComponentsFromServer = async data => {
44
+ const defaultPegaServerConfig = await getPegaServerConfig();
45
+ const url = constructCompleteUrl(
46
+ defaultPegaServerConfig.server,
47
+ LIST_COMPONENT_SERVICE_REST_ENDPOINT
48
+ );
49
+ return new Promise((resolve, reject) => {
50
+ try {
51
+ fs.readFile(TOKEN_PATH, 'utf8', (err, data) => {
52
+ if (err) {
53
+ reject(
54
+ `\n${chalk.bold.red(
55
+ 'Error occured in authentication. Please regenerate using authenticate'
56
+ )}`
57
+ );
58
+ }
59
+ if (data) {
60
+ const {
61
+ access_token: accessToken,
62
+ token_type: tokenType,
63
+ refresh_token: refreshToken
64
+ } = JSON.parse(data);
65
+ let status = 500;
66
+ fetch(url, {
67
+ method: 'GET',
68
+ agent: new https.Agent({ rejectUnauthorized: false }),
69
+ headers: {
70
+ Authorization: `${tokenType} ${accessToken}`
71
+ }
72
+ })
73
+ .then(response => {
74
+ status = response.status;
75
+ return response.text();
76
+ })
77
+ .then(resp => {
78
+ const respData = JSON.parse(resp);
79
+ if (status === 401) {
80
+ throw new Error(
81
+ 'Error occured in authentication. Please regenerate using authenticate'
82
+ );
83
+ // console.log(accessTokenUri, refreshToken);
84
+ /* TODO - Handle refresh_token */
85
+ } else if (status == 200) {
86
+ resolve(resp);
87
+ } else {
88
+ throw new Error(`${respData.message}`);
89
+ }
90
+ })
91
+ .catch(e => reject(`${chalk.bold.red(e)}`));
92
+ }
93
+ });
94
+ } catch (error) {
95
+ console.log(`\n${chalk.bold.red(error)}`);
96
+ reject(`${chalk.bold.red(error)}`);
97
+ }
98
+ });
99
+ };
100
+
101
+ export const displayServerComponents = async data => {
102
+ const defaultPegaServerConfig = await getPegaServerConfig();
103
+ const parsedData = JSON.parse(data);
104
+ const componentList = parsedData.pxResults?.map(({ label, pyRuleSet, pyRuleSetVersion }) => ({
105
+ 'Rule name': label,
106
+ 'Ruleset name': pyRuleSet,
107
+ 'Ruleset version': pyRuleSetVersion
108
+ }));
109
+
110
+ if (componentList && componentList.length > 0) {
111
+ console.log(
112
+ chalk.bold.blueBright(`List of custom components in ${defaultPegaServerConfig.server}`)
113
+ );
114
+ console.table(componentList, ['Rule name', 'Ruleset name', 'Ruleset version']);
115
+ } else {
116
+ console.log(chalk.bold.redBright(`No custom components in ${defaultPegaServerConfig.server}`));
117
+ }
118
+ };
@@ -0,0 +1,51 @@
1
+ import inquirer from 'inquirer';
2
+ import ora from 'ora';
3
+ import chalk from 'chalk';
4
+
5
+ import {
6
+ listLocalComponents,
7
+ SOURCE_OF_COMPONENT_TYPES,
8
+ getComponentsFromServer,
9
+ displayServerComponents,
10
+ getListComponentsQuestions
11
+ } from './helper.js';
12
+
13
+ const getList = async (sourceOfComponents, answers) => {
14
+ switch (sourceOfComponents) {
15
+ case SOURCE_OF_COMPONENT_TYPES.LOCAL: {
16
+ await listLocalComponents(sourceOfComponents);
17
+ break;
18
+ }
19
+ case SOURCE_OF_COMPONENT_TYPES.SERVER: {
20
+ const spinner = ora('Fetching components from server\n').start();
21
+ const data = await getComponentsFromServer(answers);
22
+ spinner.stop();
23
+ await displayServerComponents(data, answers);
24
+
25
+ break;
26
+ }
27
+ default: {
28
+ console.log('Source of components needs to be either Local or Server');
29
+ break;
30
+ }
31
+ }
32
+ };
33
+
34
+ export default async options => {
35
+ let sourceOfComponentsOption = SOURCE_OF_COMPONENT_TYPES.LOCAL;
36
+
37
+ if (options.params[3] === SOURCE_OF_COMPONENT_TYPES.LOCAL) {
38
+ sourceOfComponentsOption = options.params[3];
39
+ await getList(sourceOfComponentsOption);
40
+ } else if (options.params[3] === SOURCE_OF_COMPONENT_TYPES.SERVER) {
41
+ sourceOfComponentsOption = options.params[3];
42
+ const questions = await getListComponentsQuestions(options, sourceOfComponentsOption);
43
+ const answers = await inquirer.prompt(questions);
44
+ await getList(sourceOfComponentsOption, answers);
45
+ } else {
46
+ const questions = await getListComponentsQuestions(options);
47
+ const answers = await inquirer.prompt(questions);
48
+ const { sourceOfComponents } = answers;
49
+ await getList(sourceOfComponents, answers);
50
+ }
51
+ };
@@ -0,0 +1,174 @@
1
+ import chalk from 'chalk';
2
+ import fs from 'fs-extra';
3
+ import webpack from 'webpack';
4
+ import FileSizeReporter from 'react-dev-utils/FileSizeReporter.js';
5
+ import printBuildError from 'react-dev-utils/printBuildError.js';
6
+
7
+ import configFactory from './webpack.config.js';
8
+ import paths from './paths.js';
9
+
10
+ // Do this as the first thing so that any code reading it knows the right env.
11
+ let Env = 'production';
12
+ if (process.argv.includes('development')) {
13
+ Env = 'development';
14
+ }
15
+
16
+ if (process.argv.includes('source-map')) {
17
+ process.env.SOURCE_MAP = true;
18
+ }
19
+
20
+ // Do this as the first thing so that any code reading it knows the right env.
21
+ process.env.BABEL_ENV = Env;
22
+ process.env.NODE_ENV = Env;
23
+
24
+ // Makes the script crash on unhandled rejections instead of silently
25
+ // ignoring them. In the future, promise rejections that are not handled will
26
+ // terminate the Node.js process with a non-zero exit code.
27
+ process.on('unhandledRejection', err => {
28
+ console.log(err);
29
+ process.exit(1);
30
+ });
31
+
32
+ const measureFileSizesBeforeBuild = FileSizeReporter.measureFileSizesBeforeBuild;
33
+ const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
34
+
35
+ // These sizes are pretty large. We'll warn for bundles exceeding them.
36
+ const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
37
+ const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
38
+
39
+ // Create the build and print the deployment instructions.
40
+ function build(config, previousFileSizes) {
41
+ console.log(`Creating a ${Env} build...`);
42
+
43
+ const compiler = webpack(config);
44
+ return new Promise((resolve, reject) => {
45
+ compiler.run((err, stats) => {
46
+ let messages;
47
+ if (err) {
48
+ if (!err.message) {
49
+ return reject(err);
50
+ }
51
+
52
+ let errMessage = err.message;
53
+
54
+ // Add additional information for postcss errors
55
+ if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) {
56
+ errMessage += `\nCompileError: Begins at CSS selector ${err.postcssNode.selector}`;
57
+ }
58
+
59
+ messages = {
60
+ errors: [errMessage],
61
+ warnings: []
62
+ };
63
+ } else {
64
+ messages = stats.toJson({ all: false, warnings: true, errors: true });
65
+ }
66
+ if (messages.errors.length) {
67
+ // Only keep the first error. Others are often indicative
68
+ // of the same problem, but confuse the reader with noise.
69
+ if (messages.errors.length > 1) {
70
+ messages.errors.length = 1;
71
+ }
72
+ return reject(new Error(messages.errors));
73
+ }
74
+ if (
75
+ process.env.CI &&
76
+ (typeof process.env.CI !== 'string' || process.env.CI.toLowerCase() !== 'false') &&
77
+ messages.warnings.length
78
+ ) {
79
+ console.log(
80
+ chalk.yellow(
81
+ '\nTreating warnings as errors because process.env.CI = true.\n' +
82
+ 'Most CI servers set it automatically.\n'
83
+ )
84
+ );
85
+ return reject(new Error(messages.warnings.join('\n\n')));
86
+ }
87
+
88
+ const resolveArgs = {
89
+ stats,
90
+ previousFileSizes,
91
+ warnings: messages.warnings
92
+ };
93
+ return resolve(resolveArgs);
94
+ });
95
+ });
96
+ }
97
+
98
+ export default ({
99
+ inputFile,
100
+ outputFile,
101
+ componentKey,
102
+ externals,
103
+ globals,
104
+ sourceMap,
105
+ devBuild
106
+ }) => {
107
+ // Generate configuration
108
+ const config = configFactory(Env, {
109
+ inputFile,
110
+ outputFile,
111
+ componentKey,
112
+ externals,
113
+ globals,
114
+ sourceMap,
115
+ devBuild
116
+ });
117
+
118
+ if (devBuild) {
119
+ Env = 'development';
120
+ }
121
+
122
+ return new Promise((resolve, reject) => {
123
+ measureFileSizesBeforeBuild(paths.appBuild)
124
+ .then(previousFileSizes => {
125
+ // Remove all content but keep the directory so that
126
+ // if you're in it, you don't end up in Trash
127
+ fs.emptyDirSync(paths.appBuild);
128
+ // Start the webpack build
129
+ return build(config, previousFileSizes);
130
+ })
131
+ .then(
132
+ ({ stats, previousFileSizes, warnings }) => {
133
+ if (warnings.length) {
134
+ console.log(chalk.yellow('Compiled with warnings.\n'), warnings[0].message);
135
+ } else {
136
+ console.log(chalk.green('Compiled successfully.\n'));
137
+ }
138
+
139
+ console.log('File sizes after gzip:\n');
140
+ printFileSizesAfterBuild(
141
+ stats,
142
+ previousFileSizes,
143
+ paths.appBuild,
144
+ WARN_AFTER_BUNDLE_GZIP_SIZE,
145
+ WARN_AFTER_CHUNK_GZIP_SIZE
146
+ );
147
+ resolve('done emitting');
148
+ },
149
+ err => {
150
+ reject();
151
+ const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
152
+ if (tscCompileOnError) {
153
+ console.log(
154
+ chalk.yellow(
155
+ 'Compiled with the following type errors (you may want to check these before deploying your app):\n'
156
+ )
157
+ );
158
+ printBuildError(err);
159
+ } else {
160
+ console.log(chalk.red('Failed to compile.\n'));
161
+ printBuildError(err);
162
+ process.exit(1);
163
+ }
164
+ }
165
+ )
166
+ .catch(err => {
167
+ reject();
168
+ if (err && err.message) {
169
+ console.log(err.message);
170
+ }
171
+ process.exit(1);
172
+ });
173
+ });
174
+ };
@@ -0,0 +1,139 @@
1
+ /* eslint-disable import/no-dynamic-require */
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { createRequire } from 'module';
6
+
7
+ import chalk from 'chalk';
8
+ import resolve from 'resolve';
9
+
10
+ import paths from './paths.js';
11
+
12
+ const require = createRequire(import.meta.url);
13
+
14
+ /**
15
+ * Get additional module paths based on the baseUrl of a compilerOptions object.
16
+ *
17
+ * @param {Object} options
18
+ */
19
+ function getAdditionalModulePaths(options = {}) {
20
+ const baseUrl = options.baseUrl;
21
+
22
+ if (!baseUrl) {
23
+ return '';
24
+ }
25
+
26
+ const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
27
+
28
+ // We don't need to do anything if `baseUrl` is set to `node_modules`. This is
29
+ // the default behavior.
30
+ if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
31
+ return null;
32
+ }
33
+
34
+ // Allow the user set the `baseUrl` to `appSrc`.
35
+ if (path.relative(paths.appSrc, baseUrlResolved) === '') {
36
+ return [paths.appSrc];
37
+ }
38
+
39
+ // If the path is equal to the root directory we ignore it here.
40
+ // We don't want to allow importing from the root directly as source files are
41
+ // not transpiled outside of `src`. We do allow importing them with the
42
+ // absolute path (e.g. `src/Components/Button.js`) but we set that up with
43
+ // an alias.
44
+ if (path.relative(paths.appPath, baseUrlResolved) === '') {
45
+ return null;
46
+ }
47
+
48
+ // Otherwise, throw an error.
49
+ throw new Error(
50
+ chalk.red.bold(
51
+ "Your project's `baseUrl` can only be set to `src` or `node_modules`." +
52
+ ' Create React App does not support other values at this time.'
53
+ )
54
+ );
55
+ }
56
+
57
+ /**
58
+ * Get webpack aliases based on the baseUrl of a compilerOptions object.
59
+ *
60
+ * @param {*} options
61
+ */
62
+ function getWebpackAliases(options = {}) {
63
+ const baseUrl = options.baseUrl;
64
+
65
+ if (!baseUrl) {
66
+ return {};
67
+ }
68
+
69
+ const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
70
+
71
+ if (path.relative(paths.appPath, baseUrlResolved) === '') {
72
+ return {
73
+ src: paths.appSrc
74
+ };
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Get jest aliases based on the baseUrl of a compilerOptions object.
80
+ *
81
+ * @param {*} options
82
+ */
83
+ function getJestAliases(options = {}) {
84
+ const baseUrl = options.baseUrl;
85
+
86
+ if (!baseUrl) {
87
+ return {};
88
+ }
89
+
90
+ const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
91
+
92
+ if (path.relative(paths.appPath, baseUrlResolved) === '') {
93
+ return {
94
+ '^src/(.*)$': '<rootDir>/src/$1'
95
+ };
96
+ }
97
+ }
98
+
99
+ function getModules() {
100
+ // Check if TypeScript is setup
101
+ const hasTsConfig = fs.existsSync(paths.appTsConfig);
102
+ const hasJsConfig = fs.existsSync(paths.appJsConfig);
103
+
104
+ if (hasTsConfig && hasJsConfig) {
105
+ throw new Error(
106
+ 'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
107
+ );
108
+ }
109
+
110
+ let config;
111
+
112
+ // If there's a tsconfig.json we assume it's a
113
+ // TypeScript project and set up the config
114
+ // based on tsconfig.json
115
+ if (hasTsConfig) {
116
+ const ts = require(resolve.sync('typescript', {
117
+ basedir: paths.appNodeModules
118
+ }));
119
+ config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
120
+ // Otherwise we'll check if there is jsconfig.json
121
+ // for non TS projects.
122
+ } else if (hasJsConfig) {
123
+ config = require(paths.appJsConfig);
124
+ }
125
+
126
+ config = config || {};
127
+ const options = config.compilerOptions || {};
128
+
129
+ const additionalModulePaths = getAdditionalModulePaths(options);
130
+
131
+ return {
132
+ additionalModulePaths,
133
+ webpackAliases: getWebpackAliases(options),
134
+ jestAliases: getJestAliases(options),
135
+ hasTsConfig
136
+ };
137
+ }
138
+
139
+ module.exports = getModules();
@@ -0,0 +1,50 @@
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+
4
+ // Make sure any symlinks in the project folder are resolved:
5
+ // https://github.com/facebook/create-react-app/issues/637
6
+ const appDirectory = fs.realpathSync(process.cwd());
7
+ const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
8
+
9
+ const buildPath = 'dist/components';
10
+
11
+ export const moduleFileExtensions = [
12
+ 'web.mjs',
13
+ 'mjs',
14
+ 'web.js',
15
+ 'js',
16
+ 'web.ts',
17
+ 'ts',
18
+ 'web.tsx',
19
+ 'tsx',
20
+ 'json',
21
+ 'web.jsx',
22
+ 'jsx'
23
+ ];
24
+
25
+ // Resolve file paths in the same order as webpack
26
+ const resolveModule = (resolveFn, filePath) => {
27
+ const extension = moduleFileExtensions.find(ext =>
28
+ fs.existsSync(resolveFn(`${filePath}.${ext}`))
29
+ );
30
+
31
+ if (extension) {
32
+ return resolveFn(`${filePath}.${extension}`);
33
+ }
34
+
35
+ return resolveFn(`${filePath}.js`);
36
+ };
37
+
38
+ // config after eject: we're in ./config/
39
+ export default {
40
+ dotenv: resolveApp('.env'),
41
+ appPath: resolveApp('.'),
42
+ appBuild: resolveApp(buildPath),
43
+ appPublic: resolveApp('public'),
44
+ appIndexJs: resolveModule(resolveApp, 'src/index'),
45
+ appPackageJson: resolveApp('package.json'),
46
+ appSrc: resolveApp('src'),
47
+ appTsConfig: resolveApp('tsconfig.json'),
48
+ appJsConfig: resolveApp('jsconfig.json'),
49
+ appNodeModules: resolveApp('node_modules')
50
+ };