Skip to content

Commit e16d675

Browse files
phatedsttk
andauthored
feat: Support theming and translations via config files (#260)
chore!: Remove `description` in config to rely on translations --------- Co-authored-by: sttk <[email protected]>
1 parent 9a1d013 commit e16d675

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+1744
-336
lines changed

.eslintrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"extends": "gulp",
33
"rules": {
44
"max-len": [1, 130],
5-
"max-statements": [1, 40],
5+
"max-statements": [1, 65],
66
"no-console": "off"
77
}
88
}

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
*.log
33
node_modules
44
!test/fixtures/errors/bad-gulp-version/node_modules/
5+
!test/fixtures/config/theming/UNSUPPORTED_GULP_VERSION/node_modules/
56
build
67
*.node
78
components

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ Supported configurations properties:
116116
| flags.tasksDepth | Set default depth of task dependency tree. |
117117
| flags.silent | Silence logging by default |
118118
| flags.series | Run tasks given on the CLI in series (the default is parallel) |
119+
| message(data) | A function used to translate messages that pass through gulp-cli. Can receive an object like `{ tag: Symbol(), ...props }` where the `tag` is a symbol from `@gulpjs/messages`. The string returned from this function will be logged. If `false` is explicitly returned, no message will be logged. |
120+
| timestamp(data) | A function used to provide timestamps for gulp-cli. Can receive an object like `{ tag: Symbol(), ...props }` where the `tag` is a symbol from `@gulpjs/messages`. The string returned from this function will be output before any messages. If `false` is explicitly returned, no timestamp will be output. |
119121

120122
## Flags
121123

index.js

+71-63
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,20 @@ var yargs = require('yargs');
88
var Liftoff = require('liftoff');
99
var interpret = require('interpret');
1010
var v8flags = require('v8flags');
11+
var messages = require('@gulpjs/messages');
1112
var findRange = require('semver-greatest-satisfied-range');
12-
var chalk = require('chalk');
1313

1414
var exit = require('./lib/shared/exit');
15-
var tildify = require('./lib/shared/tildify');
15+
1616
var arrayFind = require('./lib/shared/array-find');
1717
var makeTitle = require('./lib/shared/make-title');
18+
var makeHelp = require('./lib/shared/options/make-help');
1819
var cliOptions = require('./lib/shared/options/cli-options');
1920
var completion = require('./lib/shared/completion');
2021
var cliVersion = require('./package.json').version;
2122
var toConsole = require('./lib/shared/log/to-console');
2223
var mergeCliOpts = require('./lib/shared/config/cli-flags');
24+
var buildTranslations = require('./lib/shared/translate');
2325

2426
// Get supported ranges
2527
var ranges = fs.readdirSync(path.join(__dirname, '/lib/versioned/'));
@@ -31,7 +33,6 @@ process.env.INIT_CWD = process.cwd();
3133
var cli = new Liftoff({
3234
name: 'gulp',
3335
processTitle: makeTitle('gulp', process.argv.slice(2)),
34-
completions: completion,
3536
extensions: interpret.jsVariants,
3637
v8flags: v8flags,
3738
configFiles: [
@@ -49,38 +50,34 @@ var cli = new Liftoff({
4950
],
5051
});
5152

52-
var usage =
53-
'\n' + chalk.bold('Usage:') +
54-
' gulp ' + chalk.blue('[options]') + ' tasks';
55-
5653
var parser = yargs
5754
.help(false)
5855
.version(false)
5956
.detectLocale(false)
60-
.usage(usage)
57+
.showHelpOnFail(false)
58+
.exitProcess(false)
59+
.fail(onFail)
6160
.options(cliOptions);
6261

6362
var opts = parser.parse();
6463

6564
// Set up event listeners for logging temporarily.
66-
toConsole(log, opts);
65+
// TODO: Rework console logging before we can set up proper config
66+
// Possibly by batching messages in gulplog until listeners are attached
67+
var cleanupListeners = toConsole(log, opts, buildTranslations());
6768

6869
cli.on('preload:before', function(name) {
69-
log.info('Preloading external module:', chalk.magenta(name));
70+
log.info({ tag: messages.PRELOAD_BEFORE, name: name });
7071
});
7172

7273
cli.on('preload:success', function(name) {
73-
log.info('Preloaded external module:', chalk.magenta(name));
74+
log.info({ tag: messages.PRELOAD_SUCCESS, name: name });
7475
});
7576

7677
cli.on('preload:failure', function(name, error) {
77-
log.warn(
78-
chalk.yellow('Failed to preload external module:'),
79-
chalk.magenta(name)
80-
);
81-
/* istanbul ignore else */
78+
log.warn({ tag: messages.PRELOAD_FAILURE, name: name });
8279
if (error) {
83-
log.warn(chalk.yellow(error.toString()));
80+
log.warn({ tag: messages.PRELOAD_ERROR, error: error });
8481
}
8582
});
8683

@@ -90,34 +87,27 @@ cli.on('loader:success', function(name) {
9087
// However, we don't want to show the mjs-stub loader in the logs
9188
/* istanbul ignore else */
9289
if (path.basename(name, '.js') !== 'mjs-stub') {
93-
log.info('Loaded external module:', chalk.magenta(name));
90+
log.info({ tag: messages.LOADER_SUCCESS, name: name });
9491
}
9592
});
9693

9794
cli.on('loader:failure', function(name, error) {
98-
log.warn(
99-
chalk.yellow('Failed to load external module:'),
100-
chalk.magenta(name)
101-
);
102-
/* istanbul ignore else */
95+
log.warn({ tag: messages.LOADER_FAILURE, name: name });
10396
if (error) {
104-
log.warn(chalk.yellow(error.toString()));
97+
log.warn({ tag: messages.LOADER_ERROR, error: error });
10598
}
10699
});
107100

108101
cli.on('respawn', function(flags, child) {
109-
var nodeFlags = chalk.magenta(flags.join(', '));
110-
var pid = chalk.magenta(child.pid);
111-
log.info('Node flags detected:', nodeFlags);
112-
log.info('Respawned to PID:', pid);
102+
log.info({ tag: messages.NODE_FLAGS, flags: flags });
103+
log.info({ tag: messages.RESPAWNED, pid: child.pid });
113104
});
114105

115106
function run() {
116107
cli.prepare({
117108
cwd: opts.cwd,
118109
configPath: opts.gulpfile,
119110
preload: opts.preload,
120-
completion: opts.completion,
121111
}, onPrepare);
122112
}
123113

@@ -127,22 +117,50 @@ function isDefined(cfg) {
127117
return cfg != null;
128118
}
129119

120+
function onFail(message, error) {
121+
// Run Liftoff#prepare to get the env. Primarily to load themes.
122+
cli.prepare({}, function (env) {
123+
// We only use the first config found, which is a departure from
124+
// the previous implementation that merged with the home
125+
var cfg = arrayFind(env.config, isDefined);
126+
var translate = buildTranslations(cfg);
127+
128+
var errorMsg = translate.message({ tag: messages.ARGV_ERROR, message: message, error: error });
129+
if (errorMsg) {
130+
console.error(errorMsg);
131+
}
132+
133+
makeHelp(parser, translate).showHelp(console.error);
134+
exit(1);
135+
});
136+
}
137+
130138
function onPrepare(env) {
131139
// We only use the first config found, which is a departure from
132140
// the previous implementation that merged with the home
133141
var cfg = arrayFind(env.config, isDefined);
134142
var flags = mergeCliOpts(opts, cfg);
135143

136-
// Set up event listeners for logging after configuring.
137-
toConsole(log, flags);
144+
// Remove the previous listeners since we have appropriate config now
145+
cleanupListeners();
146+
147+
var translate = buildTranslations(cfg);
148+
149+
// Set up event listeners for logging again after configuring.
150+
toConsole(log, flags, translate);
138151

139152
cli.execute(env, cfg.nodeFlags, function (env) {
140-
onExecute(env, cfg, flags);
153+
onExecute(env, flags, translate);
141154
});
142155
}
143156

144157
// The actual logic
145-
function onExecute(env, cfg, flags) {
158+
function onExecute(env, flags, translate) {
159+
// Moved the completion logic outside of Liftoff since we need to include translations
160+
if (flags.completion) {
161+
return completion(flags.completion, translate);
162+
}
163+
146164
// This translates the --continue flag in gulp
147165
// To the settle env variable for undertaker
148166
// We use the process.env so the user's gulpfile
@@ -152,7 +170,7 @@ function onExecute(env, cfg, flags) {
152170
}
153171

154172
if (flags.help) {
155-
parser.showHelp(console.log);
173+
makeHelp(parser, translate).showHelp(console.log);
156174
exit(0);
157175
}
158176

@@ -164,60 +182,50 @@ function onExecute(env, cfg, flags) {
164182
}
165183

166184
if (!env.modulePath) {
167-
/* istanbul ignore next */
168185
var missingNodeModules =
169186
fs.existsSync(path.join(env.cwd, 'package.json'))
170187
&& !fs.existsSync(path.join(env.cwd, 'node_modules'));
171188

172-
/* istanbul ignore next */
173-
var missingGulpMessage =
174-
missingNodeModules
175-
? 'Local modules not found in'
176-
: 'Local gulp not found in';
177-
log.error(
178-
chalk.red(missingGulpMessage),
179-
chalk.magenta(tildify(env.cwd))
180-
);
181189
var hasYarn = fs.existsSync(path.join(env.cwd, 'yarn.lock'));
182-
/* istanbul ignore next */
183-
var installCommand =
184-
missingNodeModules
185-
? hasYarn
186-
? 'yarn install'
187-
: 'npm install'
188-
: hasYarn
189-
? 'yarn add gulp'
190-
: 'npm install gulp';
191-
log.error(chalk.red('Try running: ' + installCommand));
190+
if (missingNodeModules) {
191+
log.error({ tag: messages.MISSING_NODE_MODULES, cwd: env.cwd });
192+
if (hasYarn) {
193+
log.error({ tag: messages.YARN_INSTALL })
194+
} else {
195+
log.error({ tag: messages.NPM_INSTALL })
196+
}
197+
} else {
198+
log.error({ tag: messages.MISSING_GULP, cwd: env.cwd });
199+
if (hasYarn) {
200+
log.error({ tag: messages.YARN_INSTALL_GULP });
201+
} else {
202+
log.error({ tag: messages.NPM_INSTALL_GULP });
203+
}
204+
}
192205
exit(1);
193206
}
194207

195208
if (!env.configPath) {
196-
log.error(chalk.red('No gulpfile found'));
209+
log.error({ tag: messages.MISSING_GULPFILE });
197210
exit(1);
198211
}
199212

200213
// Chdir before requiring gulpfile to make sure
201214
// we let them chdir as needed
202215
if (process.cwd() !== env.cwd) {
203216
process.chdir(env.cwd);
204-
log.info(
205-
'Working directory changed to',
206-
chalk.magenta(tildify(env.cwd))
207-
);
217+
log.info({ tag: messages.CWD_CHANGED, cwd: env.cwd });
208218
}
209219

210220
// Find the correct CLI version to run
211221
var range = findRange(env.modulePackage.version, ranges);
212222

213223
if (!range) {
214-
log.error(
215-
chalk.red('Unsupported gulp version', env.modulePackage.version)
216-
);
224+
log.error({ tag: messages.UNSUPPORTED_GULP_VERSION, version: env.modulePackage.version });
217225
exit(1);
218226
}
219227

220228
// Load and execute the CLI version
221229
var versionedDir = path.join(__dirname, '/lib/versioned/', range, '/');
222-
require(versionedDir)(env, cfg, flags);
230+
require(versionedDir)(env, flags, translate);
223231
}

lib/shared/completion.js

+5-7
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,18 @@
33
var fs = require('fs');
44
var path = require('path');
55

6-
module.exports = function(name) {
6+
var messages = require('@gulpjs/messages');
7+
8+
module.exports = function(name, translate) {
79
if (typeof name !== 'string') {
8-
throw new Error('Missing completion type');
10+
throw new Error(translate.message({ tag: messages.COMPLETION_TYPE_MISSING }));
911
}
1012
var file = path.join(__dirname, '../../completion', name);
1113
try {
1214
console.log(fs.readFileSync(file, 'utf8'));
1315
process.exit(0);
1416
} catch (err) {
15-
console.log(
16-
'echo "gulp autocompletion rules for',
17-
'\'' + name + '\'',
18-
'not found"'
19-
);
17+
console.log(translate.message({ tag: messages.COMPLETION_TYPE_UNKNOWN, name: name }));
2018
process.exit(5);
2119
}
2220
};

0 commit comments

Comments
 (0)