cypress 5.1.0 → 5.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,126 +1,159 @@
1
1
  "use strict";
2
2
 
3
- function _templateObject7() {
4
- var data = _taggedTemplateLiteral(["\n ", " Warning: Forcing a binary version different than the default.\n\n The CLI expected to install version: ", "\n\n Instead we will install version: ", "\n\n These versions may not work properly together.\n "]);
3
+ const _ = require('lodash');
5
4
 
6
- _templateObject7 = function _templateObject7() {
7
- return data;
8
- };
5
+ const os = require('os');
9
6
 
10
- return data;
11
- }
7
+ const url = require('url');
12
8
 
13
- function _templateObject6() {
14
- var data = _taggedTemplateLiteral(["\n Cypress ", " is installed in ", "\n "]);
9
+ const path = require('path');
15
10
 
16
- _templateObject6 = function _templateObject6() {
17
- return data;
18
- };
11
+ const chalk = require('chalk');
19
12
 
20
- return data;
21
- }
13
+ const debug = require('debug')('cypress:cli');
22
14
 
23
- function _templateObject5() {
24
- var data = _taggedTemplateLiteral(["\n Failed to access ", ":\n\n ", "\n "]);
15
+ const Listr = require('listr');
25
16
 
26
- _templateObject5 = function _templateObject5() {
27
- return data;
28
- };
17
+ const verbose = require('@cypress/listr-verbose-renderer');
29
18
 
30
- return data;
31
- }
19
+ const Promise = require('bluebird');
32
20
 
33
- function _templateObject4() {
34
- var data = _taggedTemplateLiteral(["\n ", " Overriding Cypress cache directory to: ", "\n\n Previous installs of Cypress may not be found.\n "]);
21
+ const logSymbols = require('log-symbols');
35
22
 
36
- _templateObject4 = function _templateObject4() {
37
- return data;
38
- };
23
+ const {
24
+ stripIndent
25
+ } = require('common-tags');
39
26
 
40
- return data;
41
- }
27
+ const fs = require('../fs');
42
28
 
43
- function _templateObject3() {
44
- var data = _taggedTemplateLiteral(["\n ", " Skipping binary installation: Environment variable CYPRESS_INSTALL_BINARY = 0."]);
29
+ const download = require('./download');
45
30
 
46
- _templateObject3 = function _templateObject3() {
47
- return data;
48
- };
31
+ const util = require('../util');
49
32
 
50
- return data;
51
- }
33
+ const state = require('./state');
52
34
 
53
- function _templateObject2() {
54
- var data = _taggedTemplateLiteral(["\n ", " Warning: It looks like you've installed Cypress globally.\n\n This will work, but it's not recommended.\n\n The recommended way to install Cypress is as a devDependency per project.\n\n You should probably run these commands:\n\n - ", "\n - ", "\n "], ["\n ", " Warning: It looks like you\\'ve installed Cypress globally.\n\n This will work, but it'\\s not recommended.\n\n The recommended way to install Cypress is as a devDependency per project.\n\n You should probably run these commands:\n\n - ", "\n - ", "\n "]);
35
+ const unzip = require('./unzip');
55
36
 
56
- _templateObject2 = function _templateObject2() {
57
- return data;
58
- };
37
+ const logger = require('../logger');
59
38
 
60
- return data;
61
- }
39
+ const {
40
+ throwFormErrorText,
41
+ errors
42
+ } = require('../errors');
62
43
 
63
- function _templateObject() {
64
- var data = _taggedTemplateLiteral(["\n Skipping installation:\n\n Pass the ", " option if you'd like to reinstall anyway.\n "]);
44
+ const getNpmArgv = () => {
45
+ const json = process.env.npm_config_argv;
65
46
 
66
- _templateObject = function _templateObject() {
67
- return data;
68
- };
47
+ if (!json) {
48
+ return;
49
+ }
50
+
51
+ debug('found npm argv json %o', json);
69
52
 
70
- return data;
71
- }
53
+ try {
54
+ return JSON.parse(json).original || [];
55
+ } catch (e) {
56
+ return [];
57
+ }
58
+ }; // attempt to discover the version specifier used to install Cypress
59
+ // for example: "^5.0.0", "https://cdn.cypress.io/...", ...
72
60
 
73
- function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }
74
61
 
75
- var _ = require('lodash');
62
+ const getVersionSpecifier = (startDir = path.resolve(__dirname, '../..')) => {
63
+ const argv = getNpmArgv();
76
64
 
77
- var os = require('os');
65
+ if (argv) {
66
+ const tgz = _.find(argv, t => t.endsWith('cypress.tgz'));
78
67
 
79
- var path = require('path');
68
+ if (tgz) {
69
+ return tgz;
70
+ }
71
+ }
80
72
 
81
- var chalk = require('chalk');
73
+ const getVersionSpecifierFromPkg = dir => {
74
+ debug('looking for versionSpecifier %o', {
75
+ dir
76
+ });
82
77
 
83
- var debug = require('debug')('cypress:cli');
78
+ const tryParent = () => {
79
+ const parentPath = path.resolve(dir, '..');
84
80
 
85
- var Listr = require('listr');
81
+ if (parentPath === dir) {
82
+ debug('reached FS root with no versionSpecifier found');
83
+ return;
84
+ }
86
85
 
87
- var verbose = require('@cypress/listr-verbose-renderer');
86
+ return getVersionSpecifierFromPkg(parentPath);
87
+ };
88
88
 
89
- var Promise = require('bluebird');
89
+ return fs.readJSON(path.join(dir, 'package.json')).catch(() => ({})).then(pkg => {
90
+ const specifier = _.chain(['dependencies', 'devDependencies', 'optionalDependencies']).map(prop => _.get(pkg, `${prop}.cypress`)).compact().first().value();
90
91
 
91
- var logSymbols = require('log-symbols');
92
+ return specifier || tryParent();
93
+ });
94
+ }; // recurse through parent directories until package.json with `cypress` is found
92
95
 
93
- var _require = require('common-tags'),
94
- stripIndent = _require.stripIndent;
95
96
 
96
- var fs = require('../fs');
97
+ return getVersionSpecifierFromPkg(startDir).then(versionSpecifier => {
98
+ debug('finished looking for versionSpecifier', {
99
+ versionSpecifier
100
+ });
101
+ return versionSpecifier;
102
+ });
103
+ };
97
104
 
98
- var download = require('./download');
105
+ const betaNpmUrlRe = /^\/beta\/npm\/(?<version>[0-9.]+)\/(?<artifactSlug>[^/]+)\/cypress\.tgz$/; // convert a prerelease NPM package .tgz URL to the corresponding binary .zip URL
99
106
 
100
- var util = require('../util');
107
+ const getBinaryUrlFromPrereleaseNpmUrl = npmUrl => {
108
+ let parsed;
101
109
 
102
- var state = require('./state');
110
+ try {
111
+ parsed = url.parse(npmUrl);
112
+ } catch (e) {
113
+ return;
114
+ }
103
115
 
104
- var unzip = require('./unzip');
116
+ const matches = betaNpmUrlRe.exec(parsed.pathname);
105
117
 
106
- var logger = require('../logger');
118
+ if (parsed.hostname !== 'cdn.cypress.io' || !matches) {
119
+ return;
120
+ }
107
121
 
108
- var _require2 = require('../errors'),
109
- throwFormErrorText = _require2.throwFormErrorText,
110
- errors = _require2.errors;
122
+ const {
123
+ version,
124
+ artifactSlug
125
+ } = matches.groups;
126
+ parsed.pathname = `/beta/binary/${version}/${os.platform()}-${os.arch()}/${artifactSlug}/cypress.zip`;
127
+ return parsed.format();
128
+ };
111
129
 
112
- var alreadyInstalledMsg = function alreadyInstalledMsg() {
130
+ const alreadyInstalledMsg = () => {
113
131
  if (!util.isPostInstall()) {
114
- logger.log(stripIndent(_templateObject(), chalk.yellow('--force')));
132
+ logger.log(stripIndent`
133
+ Skipping installation:
134
+
135
+ Pass the ${chalk.yellow('--force')} option if you'd like to reinstall anyway.
136
+ `);
115
137
  }
116
138
  };
117
139
 
118
- var displayCompletionMsg = function displayCompletionMsg() {
140
+ const displayCompletionMsg = () => {
119
141
  // check here to see if we are globally installed
120
142
  if (util.isInstalledGlobally()) {
121
143
  // if we are display a warning
122
144
  logger.log();
123
- logger.warn(stripIndent(_templateObject2(), logSymbols.warning, chalk.cyan('npm uninstall -g cypress'), chalk.cyan('npm install --save-dev cypress')));
145
+ logger.warn(stripIndent`
146
+ ${logSymbols.warning} Warning: It looks like you\'ve installed Cypress globally.
147
+
148
+ This will work, but it'\s not recommended.
149
+
150
+ The recommended way to install Cypress is as a devDependency per project.
151
+
152
+ You should probably run these commands:
153
+
154
+ - ${chalk.cyan('npm uninstall -g cypress')}
155
+ - ${chalk.cyan('npm install --save-dev cypress')}
156
+ `);
124
157
  return;
125
158
  }
126
159
 
@@ -131,52 +164,53 @@ var displayCompletionMsg = function displayCompletionMsg() {
131
164
  logger.log();
132
165
  };
133
166
 
134
- var downloadAndUnzip = function downloadAndUnzip(_ref) {
135
- var version = _ref.version,
136
- installDir = _ref.installDir,
137
- downloadDir = _ref.downloadDir;
138
- var progress = {
167
+ const downloadAndUnzip = ({
168
+ version,
169
+ installDir,
170
+ downloadDir
171
+ }) => {
172
+ const progress = {
139
173
  throttle: 100,
140
174
  onProgress: null
141
175
  };
142
- var downloadDestination = path.join(downloadDir, 'cypress.zip');
143
- var rendererOptions = getRendererOptions(); // let the user know what version of cypress we're downloading!
176
+ const downloadDestination = path.join(downloadDir, 'cypress.zip');
177
+ const rendererOptions = getRendererOptions(); // let the user know what version of cypress we're downloading!
144
178
 
145
- logger.log("Installing Cypress ".concat(chalk.gray("(version: ".concat(version, ")"))));
179
+ logger.log(`Installing Cypress ${chalk.gray(`(version: ${version})`)}`);
146
180
  logger.log();
147
- var tasks = new Listr([{
181
+ const tasks = new Listr([{
148
182
  title: util.titleize('Downloading Cypress'),
149
- task: function task(ctx, _task) {
183
+ task: (ctx, task) => {
150
184
  // as our download progresses indicate the status
151
- progress.onProgress = progessify(_task, 'Downloading Cypress');
185
+ progress.onProgress = progessify(task, 'Downloading Cypress');
152
186
  return download.start({
153
- version: version,
154
- downloadDestination: downloadDestination,
155
- progress: progress
156
- }).then(function (redirectVersion) {
187
+ version,
188
+ downloadDestination,
189
+ progress
190
+ }).then(redirectVersion => {
157
191
  if (redirectVersion) version = redirectVersion;
158
- debug("finished downloading file: ".concat(downloadDestination));
159
- }).then(function () {
192
+ debug(`finished downloading file: ${downloadDestination}`);
193
+ }).then(() => {
160
194
  // save the download destination for unzipping
161
- util.setTaskTitle(_task, util.titleize(chalk.green('Downloaded Cypress')), rendererOptions.renderer);
195
+ util.setTaskTitle(task, util.titleize(chalk.green('Downloaded Cypress')), rendererOptions.renderer);
162
196
  });
163
197
  }
164
198
  }, unzipTask({
165
- progress: progress,
199
+ progress,
166
200
  zipFilePath: downloadDestination,
167
- installDir: installDir,
168
- rendererOptions: rendererOptions
201
+ installDir,
202
+ rendererOptions
169
203
  }), {
170
204
  title: util.titleize('Finishing Installation'),
171
- task: function task(ctx, _task2) {
172
- var cleanup = function cleanup() {
205
+ task: (ctx, task) => {
206
+ const cleanup = () => {
173
207
  debug('removing zip file %s', downloadDestination);
174
208
  return fs.removeAsync(downloadDestination);
175
209
  };
176
210
 
177
- return cleanup().then(function () {
211
+ return cleanup().then(() => {
178
212
  debug('finished installation in', installDir);
179
- util.setTaskTitle(_task2, util.titleize(chalk.green('Finished Installation'), chalk.gray(installDir)), rendererOptions.renderer);
213
+ util.setTaskTitle(task, util.titleize(chalk.green('Finished Installation'), chalk.gray(installDir)), rendererOptions.renderer);
180
214
  });
181
215
  }
182
216
  }], rendererOptions); // start the tasks!
@@ -184,9 +218,7 @@ var downloadAndUnzip = function downloadAndUnzip(_ref) {
184
218
  return Promise.resolve(tasks.run());
185
219
  };
186
220
 
187
- var start = function start() {
188
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
189
-
221
+ const start = (options = {}) => {
190
222
  // handle deprecated / removed
191
223
  if (util.getEnv('CYPRESS_BINARY_VERSION')) {
192
224
  return throwFormErrorText(errors.removed.CYPRESS_BINARY_VERSION)();
@@ -202,56 +234,77 @@ var start = function start() {
202
234
  force: false
203
235
  });
204
236
 
205
- var pkgVersion = util.pkgVersion();
206
- var needVersion = pkgVersion;
237
+ const pkgVersion = util.pkgVersion();
238
+ let needVersion = pkgVersion;
239
+ let binaryUrlOverride;
207
240
  debug('version in package.json is', needVersion); // let this environment variable reset the binary version we need
208
241
 
209
242
  if (util.getEnv('CYPRESS_INSTALL_BINARY')) {
210
243
  // because passed file paths are often double quoted
211
244
  // and might have extra whitespace around, be robust and trim the string
212
- var trimAndRemoveDoubleQuotes = true;
213
- var envVarVersion = util.getEnv('CYPRESS_INSTALL_BINARY', trimAndRemoveDoubleQuotes);
245
+ const trimAndRemoveDoubleQuotes = true;
246
+ const envVarVersion = util.getEnv('CYPRESS_INSTALL_BINARY', trimAndRemoveDoubleQuotes);
214
247
  debug('using environment variable CYPRESS_INSTALL_BINARY "%s"', envVarVersion);
215
248
 
216
249
  if (envVarVersion === '0') {
217
250
  debug('environment variable CYPRESS_INSTALL_BINARY = 0, skipping install');
218
- logger.log(stripIndent(_templateObject3(), chalk.yellow('Note:')));
251
+ logger.log(stripIndent`
252
+ ${chalk.yellow('Note:')} Skipping binary installation: Environment variable CYPRESS_INSTALL_BINARY = 0.`);
219
253
  logger.log();
220
254
  return Promise.resolve();
221
- } // if this doesn't match the expected version
222
- // then print warning to the user
223
-
224
-
225
- if (envVarVersion !== needVersion) {
226
- // reset the version to the env var version
227
- needVersion = envVarVersion;
228
255
  }
256
+
257
+ binaryUrlOverride = envVarVersion;
229
258
  }
230
259
 
231
260
  if (util.getEnv('CYPRESS_CACHE_FOLDER')) {
232
- var envCache = util.getEnv('CYPRESS_CACHE_FOLDER');
233
- logger.log(stripIndent(_templateObject4(), chalk.yellow('Note:'), chalk.cyan(envCache)));
261
+ const envCache = util.getEnv('CYPRESS_CACHE_FOLDER');
262
+ logger.log(stripIndent`
263
+ ${chalk.yellow('Note:')} Overriding Cypress cache directory to: ${chalk.cyan(envCache)}
264
+
265
+ Previous installs of Cypress may not be found.
266
+ `);
234
267
  logger.log();
235
268
  }
236
269
 
237
- var installDir = state.getVersionDir(pkgVersion);
238
- var cacheDir = state.getCacheDir();
239
- var binaryDir = state.getBinaryDir(pkgVersion);
240
- return fs.ensureDirAsync(cacheDir)["catch"]({
270
+ const installDir = state.getVersionDir(pkgVersion);
271
+ const cacheDir = state.getCacheDir();
272
+ const binaryDir = state.getBinaryDir(pkgVersion);
273
+ return fs.ensureDirAsync(cacheDir).catch({
241
274
  code: 'EACCES'
242
- }, function (err) {
243
- return throwFormErrorText(errors.invalidCacheDirectory)(stripIndent(_templateObject5(), chalk.cyan(cacheDir), err.message));
244
- }).then(function () {
245
- return state.getBinaryPkgVersionAsync(binaryDir);
246
- }).then(function (binaryVersion) {
275
+ }, err => {
276
+ return throwFormErrorText(errors.invalidCacheDirectory)(stripIndent`
277
+ Failed to access ${chalk.cyan(cacheDir)}:
278
+
279
+ ${err.message}
280
+ `);
281
+ }).then(() => {
282
+ return Promise.all([state.getBinaryPkgVersionAsync(binaryDir), getVersionSpecifier()]);
283
+ }).then(([binaryVersion, versionSpecifier]) => {
284
+ if (!binaryUrlOverride && versionSpecifier) {
285
+ const computedBinaryUrl = getBinaryUrlFromPrereleaseNpmUrl(versionSpecifier);
286
+
287
+ if (computedBinaryUrl) {
288
+ debug('computed binary url from version specifier %o', {
289
+ computedBinaryUrl,
290
+ needVersion
291
+ });
292
+ binaryUrlOverride = computedBinaryUrl;
293
+ }
294
+ }
295
+
296
+ needVersion = binaryUrlOverride || needVersion;
297
+ debug('installed version is', binaryVersion, 'version needed is', needVersion);
298
+
247
299
  if (!binaryVersion) {
248
300
  debug('no binary installed under cli version');
249
301
  return true;
250
302
  }
251
303
 
252
- debug('installed version is', binaryVersion, 'version needed is', needVersion);
253
304
  logger.log();
254
- logger.log(stripIndent(_templateObject6(), chalk.green(binaryVersion), chalk.cyan(installDir)));
305
+ logger.log(stripIndent`
306
+ Cypress ${chalk.green(binaryVersion)} is installed in ${chalk.cyan(installDir)}
307
+ `);
255
308
  logger.log();
256
309
 
257
310
  if (options.force) {
@@ -266,7 +319,7 @@ var start = function start() {
266
319
  }
267
320
 
268
321
  return true;
269
- }).then(function (shouldInstall) {
322
+ }).then(shouldInstall => {
270
323
  // noop if we've been told not to download
271
324
  if (!shouldInstall) {
272
325
  debug('Not downloading or installing binary');
@@ -274,19 +327,27 @@ var start = function start() {
274
327
  }
275
328
 
276
329
  if (needVersion !== pkgVersion) {
277
- logger.log(chalk.yellow(stripIndent(_templateObject7(), logSymbols.warning, chalk.green(pkgVersion), chalk.green(needVersion))));
330
+ logger.log(chalk.yellow(stripIndent`
331
+ ${logSymbols.warning} Warning: Forcing a binary version different than the default.
332
+
333
+ The CLI expected to install version: ${chalk.green(pkgVersion)}
334
+
335
+ Instead we will install version: ${chalk.green(needVersion)}
336
+
337
+ These versions may not work properly together.
338
+ `));
278
339
  logger.log();
279
340
  } // see if version supplied is a path to a binary
280
341
 
281
342
 
282
- return fs.pathExistsAsync(needVersion).then(function (exists) {
343
+ return fs.pathExistsAsync(needVersion).then(exists => {
283
344
  if (exists) {
284
345
  return path.extname(needVersion) === '.zip' ? needVersion : false;
285
346
  }
286
347
 
287
- var possibleFile = util.formAbsolutePath(needVersion);
348
+ const possibleFile = util.formAbsolutePath(needVersion);
288
349
  debug('checking local file', possibleFile, 'cwd', process.cwd());
289
- return fs.pathExistsAsync(possibleFile).then(function (exists) {
350
+ return fs.pathExistsAsync(possibleFile).then(exists => {
290
351
  // if this exists return the path to it
291
352
  // else false
292
353
  if (exists && path.extname(possibleFile) === '.zip') {
@@ -295,20 +356,20 @@ var start = function start() {
295
356
 
296
357
  return false;
297
358
  });
298
- }).then(function (pathToLocalFile) {
359
+ }).then(pathToLocalFile => {
299
360
  if (pathToLocalFile) {
300
- var absolutePath = path.resolve(needVersion);
361
+ const absolutePath = path.resolve(needVersion);
301
362
  debug('found local file at', absolutePath);
302
363
  debug('skipping download');
303
- var rendererOptions = getRendererOptions();
364
+ const rendererOptions = getRendererOptions();
304
365
  return new Listr([unzipTask({
305
366
  progress: {
306
367
  throttle: 100,
307
368
  onProgress: null
308
369
  },
309
370
  zipFilePath: absolutePath,
310
- installDir: installDir,
311
- rendererOptions: rendererOptions
371
+ installDir,
372
+ rendererOptions
312
373
  })], rendererOptions).run();
313
374
  }
314
375
 
@@ -318,50 +379,53 @@ var start = function start() {
318
379
  }
319
380
 
320
381
  debug('preparing to download and unzip version ', needVersion, 'to path', installDir);
321
- var downloadDir = os.tmpdir();
382
+ const downloadDir = os.tmpdir();
322
383
  return downloadAndUnzip({
323
384
  version: needVersion,
324
- installDir: installDir,
325
- downloadDir: downloadDir
385
+ installDir,
386
+ downloadDir
326
387
  });
327
388
  }) // delay 1 sec for UX, unless we are testing
328
- .then(function () {
389
+ .then(() => {
329
390
  return Promise.delay(1000);
330
391
  }).then(displayCompletionMsg);
331
392
  });
332
393
  };
333
394
 
334
395
  module.exports = {
335
- start: start
396
+ start,
397
+ _getVersionSpecifier: getVersionSpecifier,
398
+ _getBinaryUrlFromPrereleaseNpmUrl: getBinaryUrlFromPrereleaseNpmUrl
336
399
  };
337
400
 
338
- var unzipTask = function unzipTask(_ref2) {
339
- var zipFilePath = _ref2.zipFilePath,
340
- installDir = _ref2.installDir,
341
- progress = _ref2.progress,
342
- rendererOptions = _ref2.rendererOptions;
401
+ const unzipTask = ({
402
+ zipFilePath,
403
+ installDir,
404
+ progress,
405
+ rendererOptions
406
+ }) => {
343
407
  return {
344
408
  title: util.titleize('Unzipping Cypress'),
345
- task: function task(ctx, _task3) {
409
+ task: (ctx, task) => {
346
410
  // as our unzip progresses indicate the status
347
- progress.onProgress = progessify(_task3, 'Unzipping Cypress');
411
+ progress.onProgress = progessify(task, 'Unzipping Cypress');
348
412
  return unzip.start({
349
- zipFilePath: zipFilePath,
350
- installDir: installDir,
351
- progress: progress
352
- }).then(function () {
353
- util.setTaskTitle(_task3, util.titleize(chalk.green('Unzipped Cypress')), rendererOptions.renderer);
413
+ zipFilePath,
414
+ installDir,
415
+ progress
416
+ }).then(() => {
417
+ util.setTaskTitle(task, util.titleize(chalk.green('Unzipped Cypress')), rendererOptions.renderer);
354
418
  });
355
419
  }
356
420
  };
357
421
  };
358
422
 
359
- var progessify = function progessify(task, title) {
423
+ const progessify = (task, title) => {
360
424
  // return higher order function
361
- return function (percentComplete, remaining) {
362
- percentComplete = chalk.white(" ".concat(percentComplete, "%")); // pluralize seconds remaining
425
+ return (percentComplete, remaining) => {
426
+ percentComplete = chalk.white(` ${percentComplete}%`); // pluralize seconds remaining
363
427
 
364
- remaining = chalk.gray("".concat(remaining, "s"));
428
+ remaining = chalk.gray(`${remaining}s`);
365
429
  util.setTaskTitle(task, util.titleize(title, percentComplete, remaining), getRendererOptions().renderer);
366
430
  };
367
431
  }; // if we are running in CI then use
@@ -369,14 +433,14 @@ var progessify = function progessify(task, title) {
369
433
  // the default
370
434
 
371
435
 
372
- var getRendererOptions = function getRendererOptions() {
373
- var renderer = util.isCi() ? verbose : 'default';
436
+ const getRendererOptions = () => {
437
+ let renderer = util.isCi() ? verbose : 'default';
374
438
 
375
439
  if (logger.logLevel() === 'silent') {
376
440
  renderer = 'silent';
377
441
  }
378
442
 
379
443
  return {
380
- renderer: renderer
444
+ renderer
381
445
  };
382
446
  };