@carbon/cli 10.29.0

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 (37) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +57 -0
  3. package/bin/carbon-cli.js +46 -0
  4. package/docker-compose.yml +13 -0
  5. package/package.json +56 -0
  6. package/src/changelog.js +217 -0
  7. package/src/cli.js +39 -0
  8. package/src/commands/bundle/bundlers.js +14 -0
  9. package/src/commands/bundle/javascript.js +142 -0
  10. package/src/commands/bundle.js +67 -0
  11. package/src/commands/changelog.js +70 -0
  12. package/src/commands/check.js +71 -0
  13. package/src/commands/ci-check.js +51 -0
  14. package/src/commands/component.js +130 -0
  15. package/src/commands/contribute/setup.js +232 -0
  16. package/src/commands/contribute/tools/getGitHubClient.js +73 -0
  17. package/src/commands/contribute.js +16 -0
  18. package/src/commands/inline.js +170 -0
  19. package/src/commands/publish.js +274 -0
  20. package/src/commands/release.js +302 -0
  21. package/src/commands/sassdoc/tools.js +405 -0
  22. package/src/commands/sassdoc.js +90 -0
  23. package/src/commands/sync/npm.js +43 -0
  24. package/src/commands/sync/package.js +122 -0
  25. package/src/commands/sync/readme.js +68 -0
  26. package/src/commands/sync/remark/remark-monorepo.js +425 -0
  27. package/src/commands/sync.js +39 -0
  28. package/src/compile.js +26 -0
  29. package/src/component/index.js +47 -0
  30. package/src/component/templates/component.template.js +19 -0
  31. package/src/component/templates/index.template.js +9 -0
  32. package/src/component/templates/mdx.template.mdx +37 -0
  33. package/src/component/templates/story.template.js +22 -0
  34. package/src/component/templates/test.template.js +35 -0
  35. package/src/git.js +38 -0
  36. package/src/logger.js +95 -0
  37. package/src/workspace.js +60 -0
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Copyright IBM Corp. 2019, 2019
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ /* eslint-disable no-console */
9
+
10
+ 'use strict';
11
+
12
+ const chalk = require('chalk');
13
+ const { exec } = require('child-process-promise');
14
+ const { prompt } = require('inquirer');
15
+ const path = require('path');
16
+ const createLogger = require('progress-estimator');
17
+ const getGitHubClient = require('./tools/getGitHubClient');
18
+
19
+ const logger = createLogger();
20
+
21
+ chalk.link = chalk.dim.underline.italic;
22
+ chalk.dimmed = chalk.dim.italic;
23
+
24
+ async function setup() {
25
+ console.log(chalk`
26
+ {bold Hi there!} 👋
27
+ This tools is built for people looking to contribute to carbon.`);
28
+
29
+ if (!process.env.GH_TOKEN) {
30
+ console.log(chalk`
31
+ To get started, you will need a GitHub account {link (https://github.com/)}
32
+
33
+ Once you have an account you will need to setup a GitHub access token
34
+ {link (https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line)}
35
+ `);
36
+ }
37
+
38
+ const client = await getGitHubClient();
39
+ const { data: whoami } = await client.users.getAuthenticated();
40
+
41
+ console.log(`Thanks for that, ${chalk.underline(
42
+ whoami.name
43
+ )}! Now, let's get started...
44
+
45
+ Our first step is going to be to create a fork for each project you want to work on.
46
+ `);
47
+
48
+ const { projects } = await prompt([
49
+ {
50
+ type: 'checkbox',
51
+ name: 'projects',
52
+ message: 'Select the projects you would like to contribute to',
53
+ choices: availableProjects,
54
+ },
55
+ ]);
56
+
57
+ console.log();
58
+ console.log(`Awesome! Let's get started`);
59
+ console.log();
60
+
61
+ const cwd = process.cwd();
62
+
63
+ for (const project of projects) {
64
+ await fork(client, cwd, project);
65
+ }
66
+
67
+ console.log('Done! 🥳 Thanks so much for contributing to Carbon! 🙏');
68
+ }
69
+
70
+ async function fork(client, cwd, project) {
71
+ const { commands, gitCloneEstimate, owner, repo } = project;
72
+
73
+ const createForkPromise = client.repos.createFork({
74
+ owner: project.owner,
75
+ repo: project.repo,
76
+ });
77
+ const { data } = await logger(
78
+ createForkPromise,
79
+ `Creating your fork for ${owner}/${repo}...`,
80
+ {
81
+ estimate: 1000,
82
+ }
83
+ );
84
+
85
+ console.log(
86
+ `Your fork is done! Now let's setup the project on your computer.`
87
+ );
88
+ console.log();
89
+
90
+ const { folder } = await prompt([
91
+ {
92
+ type: 'input',
93
+ name: 'folder',
94
+ message: 'Where would you like this project to be on your computer?',
95
+ default: path.join(cwd, project.repo),
96
+ },
97
+ ]);
98
+ const folderPath = path.isAbsolute(folder)
99
+ ? folder
100
+ : path.resolve(cwd, folder);
101
+
102
+ const gitCloneCommand = `git clone ${data.git_url} ${path.relative(
103
+ cwd,
104
+ folderPath
105
+ )}`;
106
+ const gitClonePromise = exec(gitCloneCommand);
107
+ await logger(gitClonePromise, `Running: ${chalk.dim(gitCloneCommand)}\n`, {
108
+ estimate: gitCloneEstimate,
109
+ });
110
+
111
+ const gitRemoteCommand = `git remote add upstream git@github.com:${owner}/${repo}.git`;
112
+ const gitRemotePromise = exec(gitRemoteCommand, {
113
+ cwd: folderPath,
114
+ });
115
+ await logger(gitRemotePromise, `Running: ${chalk.dim(gitRemoteCommand)}\n`, {
116
+ estimate: 500,
117
+ });
118
+
119
+ for (const { command, estimate, reason } of commands) {
120
+ await logger(
121
+ exec(command, {
122
+ cwd: folderPath,
123
+ }),
124
+ `Running: ${chalk.dim(`\`${command}\``)} ${reason}\n`,
125
+ {
126
+ estimate,
127
+ }
128
+ );
129
+ }
130
+
131
+ console.log(
132
+ `All done! You can find your project at ${chalk.underline(
133
+ path.relative(cwd, folderPath)
134
+ )}`
135
+ );
136
+ }
137
+
138
+ function wrap(fn) {
139
+ return async (...args) => {
140
+ try {
141
+ await fn(...args);
142
+ } catch (error) {
143
+ console.log(chalk.yellow.bold('Yikes!'));
144
+ console.log(
145
+ chalk`Looks like something went wrong 🙈 {dimmed (we're sorry about that)}
146
+
147
+ Here is the error message:
148
+ {dim ${indent(error.message, 4)}}
149
+
150
+ If this is not helpful, please reach out! We're happy to help 🙂 You can make
151
+ an issue over at:
152
+ {link https://github.com/carbon-design-system/carbon/issues/new/choose}`
153
+ );
154
+ }
155
+ };
156
+ }
157
+
158
+ function indent(string, spaces = 2) {
159
+ return string
160
+ .split('\n')
161
+ .map((s) => s.padStart(spaces + s.length, ' '))
162
+ .join('\n');
163
+ }
164
+
165
+ const availableProjects = [
166
+ {
167
+ name: 'carbon',
168
+ value: {
169
+ owner: 'carbon-design-system',
170
+ repo: 'carbon',
171
+ gitCloneEstimate: 180 * 1000,
172
+ commands: [
173
+ {
174
+ command: 'yarn install --offline',
175
+ estimate: 150 * 1000,
176
+ reason: `to install the project's dependencies`,
177
+ },
178
+ {
179
+ command: 'yarn build',
180
+ estimate: 60 * 1000 * 5,
181
+ reason: `to build all the project's packages`,
182
+ },
183
+ ],
184
+ },
185
+ },
186
+ {
187
+ name: 'carbon-website',
188
+ value: {
189
+ owner: 'carbon-design-system',
190
+ repo: 'carbon-website',
191
+ gitCloneEstimate: 180 * 1000,
192
+ commands: [
193
+ {
194
+ command: 'yarn install --offline',
195
+ estimate: 45 * 1000,
196
+ reason: "to install the project's dependencies",
197
+ },
198
+ {
199
+ command: 'cd packages/addons-website && yarn build',
200
+ estimate: 30 * 1000,
201
+ reason: "to build all the project's packages",
202
+ },
203
+ ],
204
+ },
205
+ },
206
+ {
207
+ name: 'gatsby-theme-carbon',
208
+ value: {
209
+ owner: 'carbon-design-system',
210
+ repo: 'gatsby-theme-carbon',
211
+ gitCloneEstimate: 10 * 1000,
212
+ commands: [
213
+ {
214
+ command: 'yarn install',
215
+ estimate: 60 * 1000,
216
+ reason: "to install the project's dependencies",
217
+ },
218
+ {
219
+ command: 'yarn build',
220
+ estimate: 150 * 1000,
221
+ reason: "to build all the project's packages",
222
+ },
223
+ ],
224
+ },
225
+ },
226
+ ];
227
+
228
+ module.exports = {
229
+ command: 'setup',
230
+ desc: 'setup your environment',
231
+ handler: wrap(setup),
232
+ };
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Copyright IBM Corp. 2019, 2019
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ /* eslint-disable no-console */
9
+
10
+ 'use strict';
11
+
12
+ const Octokit = require('@octokit/rest');
13
+ const { prompt } = require('inquirer');
14
+
15
+ const CustomOctokit = Octokit.plugin([
16
+ require('@octokit/plugin-throttling'),
17
+ require('@octokit/plugin-retry'),
18
+ ]);
19
+
20
+ async function getGitHubClient() {
21
+ let { GH_TOKEN } = process.env;
22
+
23
+ if (!GH_TOKEN) {
24
+ const question = [
25
+ {
26
+ type: 'password',
27
+ name: 'token',
28
+ message: 'Provide a GitHub access token',
29
+ hint:
30
+ 'Help: https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line',
31
+ },
32
+ ];
33
+ const answers = await prompt(question);
34
+ GH_TOKEN = answers.token;
35
+ }
36
+
37
+ const octokit = new CustomOctokit({
38
+ auth: `token ${GH_TOKEN}`,
39
+ throttle: {
40
+ onRateLimit: (retryAfter, options) => {
41
+ console.log(
42
+ `Request quota exhausted for request ${options.method} ${options.url}`
43
+ );
44
+
45
+ if (options.request.retryCount === 0) {
46
+ // only retries once
47
+ console.log(`Retrying after ${retryAfter} seconds!`);
48
+ return true;
49
+ }
50
+ },
51
+ onAbuseLimit: (retryAfter, options) => {
52
+ // does not retry, only logs a warning
53
+ console.log(
54
+ `Abuse detected for request ${options.method} ${options.url}`
55
+ );
56
+ if (options.request.retryCount === 0) {
57
+ // only retries once
58
+ console.log(`Retrying after ${retryAfter} seconds!`);
59
+ return true;
60
+ }
61
+ },
62
+ },
63
+ });
64
+
65
+ try {
66
+ await octokit.users.getAuthenticated();
67
+ return octokit;
68
+ } catch (error) {
69
+ throw new Error('Invalid GitHub token');
70
+ }
71
+ }
72
+
73
+ module.exports = getGitHubClient;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Copyright IBM Corp. 2019, 2019
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ module.exports = {
11
+ command: 'contribute <command>',
12
+ desc: 'get started contributing with Carbon',
13
+ builder(yargs) {
14
+ yargs.commandDir('contribute');
15
+ },
16
+ };
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Copyright IBM Corp. 2019, 2019
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ const fs = require('fs-extra');
11
+ const klaw = require('klaw-sync');
12
+ const os = require('os');
13
+ const path = require('path');
14
+ const replace = require('replace-in-file');
15
+ const { createLogger } = require('../logger');
16
+
17
+ const logger = createLogger('inline');
18
+ const isWin = process.platform === 'win32';
19
+ const tmpDir = os.tmpdir();
20
+
21
+ async function inline({ output }) {
22
+ logger.start('inline');
23
+
24
+ const cwd = process.cwd();
25
+ const packageJsonPath = path.join(cwd, 'package.json');
26
+ const sourceFolder = path.join(cwd, output);
27
+ const inlineFolder = path.join(cwd, output, '_inlined');
28
+ const vendorFolder = path.join(cwd, output, 'vendor');
29
+
30
+ await Promise.all([fs.remove(inlineFolder), fs.remove(vendorFolder)]);
31
+
32
+ logger.info('Inlining sass dependencies');
33
+
34
+ await inlineSassDependencies(
35
+ packageJsonPath,
36
+ sourceFolder,
37
+ vendorFolder,
38
+ cwd
39
+ );
40
+
41
+ logger.stop();
42
+ }
43
+
44
+ async function inlineSassDependencies(
45
+ packageJsonPath,
46
+ sourceFolder,
47
+ vendorFolder,
48
+ cwd
49
+ ) {
50
+ if (!fs.existsSync(packageJsonPath)) {
51
+ throw new Error(`Expected a package.json file at ${packageJsonPath}`);
52
+ }
53
+
54
+ const packageJson = await fs.readJson(packageJsonPath);
55
+ const { dependencies = {}, devDependencies = {} } = packageJson;
56
+ const allPossibleDependencies = [
57
+ ...Object.keys(dependencies),
58
+ ...Object.keys(devDependencies),
59
+ ];
60
+ const inlinedDependencies = (
61
+ await Promise.all(
62
+ allPossibleDependencies.map(async (dependency) => {
63
+ const modules = findSassModule(dependency, cwd);
64
+ if (modules) {
65
+ const [scssFolder] = modules;
66
+ const dependencyOutputFolder = path.join(vendorFolder, dependency);
67
+
68
+ await fs.copy(scssFolder, dependencyOutputFolder);
69
+
70
+ return [dependency, dependencyOutputFolder];
71
+ }
72
+ })
73
+ )
74
+ ).filter(Boolean);
75
+
76
+ if (inlinedDependencies.length === 0) {
77
+ return;
78
+ }
79
+
80
+ const tmpFolder = await fs.mkdtemp(
81
+ path.join(tmpDir, 'carbon-bundler-inline-')
82
+ );
83
+ const inlineFolder = path.join(sourceFolder, '_inlined');
84
+ const inlineFilename = path.join(
85
+ sourceFolder,
86
+ `${path.basename(path.dirname(sourceFolder))}.scss`
87
+ );
88
+
89
+ await fs.copy(sourceFolder, tmpFolder, {
90
+ filter(src) {
91
+ if (src === vendorFolder) {
92
+ return false;
93
+ }
94
+
95
+ if (src === inlineFilename) {
96
+ return false;
97
+ }
98
+
99
+ if (path.relative(sourceFolder, src).includes('modules')) {
100
+ return false;
101
+ }
102
+
103
+ return path.basename(src) !== 'index.scss';
104
+ },
105
+ });
106
+ await fs.copy(tmpFolder, inlineFolder);
107
+ await fs.remove(tmpFolder);
108
+
109
+ const paths = klaw(inlineFolder, {
110
+ nodir: true,
111
+ });
112
+
113
+ const REPLACE_REGEX = new RegExp(
114
+ `^@import '(${inlinedDependencies.map(([name]) => name).join('|')})/scss`,
115
+ 'gm'
116
+ );
117
+ await Promise.all(
118
+ paths.map(async (file) => {
119
+ const relativeImportPath = path.relative(
120
+ path.dirname(file.path),
121
+ vendorFolder
122
+ );
123
+
124
+ await replace({
125
+ files: file.path,
126
+ from: REPLACE_REGEX,
127
+ to(_, match) {
128
+ return `@import '${
129
+ isWin ? relativeImportPath.replace('\\', '/') : relativeImportPath
130
+ }/${match}`;
131
+ },
132
+ });
133
+ })
134
+ );
135
+ }
136
+
137
+ function findSassModule(packageName, cwd) {
138
+ let currentDirectory = cwd;
139
+
140
+ while (currentDirectory !== path.dirname(currentDirectory)) {
141
+ const nodeModulesFolder = path.join(currentDirectory, 'node_modules');
142
+ const packageFolder = path.join(nodeModulesFolder, packageName);
143
+ const scssFolder = path.join(packageFolder, 'scss');
144
+ const packageJsonPath = path.join(packageFolder, 'package.json');
145
+
146
+ if (fs.existsSync(scssFolder)) {
147
+ return [scssFolder, packageFolder, packageJsonPath];
148
+ }
149
+
150
+ currentDirectory = path.dirname(currentDirectory);
151
+ }
152
+
153
+ return false;
154
+ }
155
+
156
+ module.exports = {
157
+ command: 'inline',
158
+ desc: 'inline sass dependencies from package.json in a target folder',
159
+ builder(yargs) {
160
+ yargs.options({
161
+ o: {
162
+ alias: 'output',
163
+ describe: 'the directory to output inlined sass dependencies',
164
+ type: 'string',
165
+ default: 'scss',
166
+ },
167
+ });
168
+ },
169
+ handler: inline,
170
+ };