Best JavaScript code snippet using cypress
blueprint.js
Source:blueprint.js
1'use strict';2/**3@module ember-cli4*/5const FileInfo = require('./file-info');6const chalk = require('chalk');7const MarkdownColor = require('../utilities/markdown-color');8const sequence = require('../utilities/sequence');9const printCommand = require('../utilities/print-command');10const insertIntoFile = require('../utilities/insert-into-file');11const cleanRemove = require('../utilities/clean-remove');12const fs = require('fs-extra');13const inflector = require('inflection');14const minimatch = require('minimatch');15const path = require('path');16const stringUtils = require('ember-cli-string-utils');17const _ = require('ember-cli-lodash-subset');18const walkSync = require('walk-sync');19const SilentError = require('silent-error');20const CoreObject = require('core-object');21const EOL = require('os').EOL;22const bowEpParser = require('bower-endpoint-parser');23const logger = require('heimdalljs-logger')('ember-cli:blueprint');24const normalizeEntityName = require('ember-cli-normalize-entity-name');25const { removeTypes } = require('remove-types');26const isAddon = require('../utilities/is-addon');27const { deprecate } = require('../debug');28const initialIgnoredFiles = ['.DS_Store'];29/**30 A blueprint is a bundle of template files with optional install31 logic.32 Blueprints follow a simple structure. Let's take the built-in33 `controller` blueprint as an example:34 ```35 blueprints/controller36 âââ files37 â âââ app38 â â âââ __path__39 â â âââ __name__.js40 âââ index.js41 blueprints/controller-test42 âââ files43 â âââ tests44 â âââ unit45 â âââ controllers46 â âââ __test__.js47 âââ index.js48 ```49 ## Files50 `files` contains templates for the all the files to be51 installed into the target directory.52 The `__name__` token is subtituted with the dasherized53 entity name at install time. For example, when the user54 invokes `ember generate controller foo` then `__name__` becomes55 `foo`. When the `--pod` flag is used, for example `ember56 generate controller foo --pod` then `__name__` becomes57 `controller`.58 The `__path__` token is substituted with the blueprint59 name at install time. For example, when the user invokes60 `ember generate controller foo` then `__path__` becomes61 `controller`. When the `--pod` flag is used, for example62 `ember generate controller foo --pod` then `__path__`63 becomes `foo` (or `<podModulePrefix>/foo` if the64 podModulePrefix is defined). This token is primarily for65 pod support, and is only necessary if the blueprint can be66 used in pod structure. If the blueprint does not require pod67 support, simply use the blueprint name instead of the68 `__path__` token.69 The `__test__` token is substituted with the dasherized70 entity name and appended with `-test` at install time.71 This token is primarily for pod support and only necessary72 if the blueprint requires support for a pod structure. If73 the blueprint does not require pod support, simply use the74 `__name__` token instead.75 ## Template Variables (AKA Locals)76 Variables can be inserted into templates with77 `<%= someVariableName %>`.78 For example, the built-in `util` blueprint79 `files/app/utils/__name__.js` looks like this:80 ```js81 export default function <%= camelizedModuleName %>() {82 return true;83 }84 ```85 `<%= camelizedModuleName %>` is replaced with the real86 value at install time.87 The following template variables are provided by default:88 - `dasherizedPackageName`89 - `classifiedPackageName`90 - `dasherizedModuleName`91 - `classifiedModuleName`92 - `camelizedModuleName`93 `packageName` is the project name as found in the project's94 `package.json`.95 `moduleName` is the name of the entity being generated.96 The mechanism for providing custom template variables is97 described below.98 ## Index.js99 Custom installation and uninstallation behavior can be added100 by overriding the hooks documented below. `index.js` should101 export a plain object, which will extend the prototype of the102 `Blueprint` class. If needed, the original `Blueprint` prototype103 can be accessed through the `_super` property.104 ```js105 module.exports = {106 locals(options) {107 // Return custom template variables here.108 return {};109 },110 normalizeEntityName(entityName) {111 // Normalize and validate entity name here.112 return entityName;113 },114 fileMapTokens(options) {115 // Return custom tokens to be replaced in your files116 return {117 __token__(options){118 // logic to determine value goes here119 return 'value';120 }121 }122 },123 filesPath(options) {124 return path.join(this.path, 'files');125 },126 beforeInstall(options) {},127 afterInstall(options) {},128 beforeUninstall(options) {},129 afterUninstall(options) {}130 };131 ```132 ## Blueprint Hooks133 ### beforeInstall & beforeUninstall134 Called before any of the template files are processed and receives135 the `options` and `locals` hashes as parameters. Typically used for136 validating any additional command line options or for any asynchronous137 setup that is needed. As an example, the `controller` blueprint validates138 its `--type` option in this hook. If you need to run any asynchronous code,139 wrap it in a promise and return that promise from these hooks. This will140 ensure that your code is executed correctly.141 ### afterInstall & afterUninstall142 The `afterInstall` and `afterUninstall` hooks receives the same143 arguments as `locals`. Use it to perform any custom work after the144 files are processed. For example, the built-in `route` blueprint145 uses these hooks to add and remove relevant route declarations in146 `app/router.js`.147 ### Overriding Install148 If you don't want your blueprint to install the contents of149 `files` you can override the `install` method. It receives the150 same `options` object described above and must return a promise.151 See the built-in `resource` blueprint for an example of this.152 @class Blueprint153 @constructor154 @extends CoreObject155 @param {String} [blueprintPath]156*/157let Blueprint = CoreObject.extend({158 availableOptions: [],159 anonymousOptions: ['name'],160 _printableProperties: ['name', 'description', 'availableOptions', 'anonymousOptions', 'overridden'],161 /**162 Indicates whether or not a blueprint is a candidate for automatic transpilation from TS to JS.163 This property could be false in the case that the blueprint is written in JS and is not intended164 to work with TS at all, OR in the case that the blueprint is written in TS and the author does165 not intend to support transpilation to JS.166 @public167 @property shouldTransformTypeScript168 @type Boolean169 */170 shouldTransformTypeScript: false,171 init(blueprintPath) {172 this._super();173 this.path = blueprintPath;174 this.name = path.basename(blueprintPath);175 },176 /**177 Hook to specify the path to the blueprint's files. By default this is178 `path.join(this.path, 'files)`.179 This can be used to customize which set of files to install based on options180 or environmental variables. It defaults to the `files` directory within the181 blueprint's folder.182 @public183 @method filesPath184 @param {Object} options185 @return {String} Path to the blueprints files directory.186 */187 filesPath(/* options */) {188 return path.join(this.path, 'files');189 },190 /**191 Used to retrieve files for blueprint.192 @public193 @method files194 @return {Array} Contents of the blueprint's files directory195 */196 files() {197 if (this._files) {198 return this._files;199 }200 let filesPath = this.filesPath(this.options);201 if (Blueprint._existsSync(filesPath)) {202 this._files = walkSync(filesPath);203 } else {204 this._files = [];205 }206 return this._files;207 },208 /**209 @method srcPath210 @param {String} file211 @return {String} Resolved path to the file212 */213 srcPath(file) {214 return path.resolve(this.filesPath(this.options), file);215 },216 /**217 Hook for normalizing entity name218 Use the `normalizeEntityName` hook to add custom normalization and219 validation of the provided entity name. The default hook does not220 make any changes to the entity name, but makes sure an entity name221 is present and that it doesn't have a trailing slash.222 This hook receives the entity name as its first argument. The string223 returned by this hook will be used as the new entity name.224 @public225 @method normalizeEntityName226 @param {String} entityName227 @return {null}228 */229 normalizeEntityName(entityName) {230 return normalizeEntityName(entityName);231 },232 /**233 Write a status and message to the UI234 @private235 @method _writeStatusToUI236 @param {Function} chalkColor237 @param {String} keyword238 @param {String} message239 */240 _writeStatusToUI(chalkColor, keyword, message) {241 if (this.ui) {242 this.ui.writeLine(` ${chalkColor(keyword)} ${message}`);243 }244 },245 /**246 @private247 @method _writeFile248 @param {Object} info249 @return {Promise}250 */251 async _writeFile(info) {252 if (!this.dryRun) {253 return fs.outputFile(info.outputPath, await info.render());254 }255 },256 /**257 Actions lookup258 @private259 @property _actions260 @type Object261 */262 _actions: {263 write(info) {264 this._writeStatusToUI(chalk.green, 'create', info.displayPath);265 return this._writeFile(info);266 },267 skip(info) {268 let label = 'skip';269 if (info.resolution === 'identical') {270 label = 'identical';271 }272 this._writeStatusToUI(chalk.yellow, label, info.displayPath);273 },274 overwrite(info) {275 this._writeStatusToUI(chalk.yellow, 'overwrite', info.displayPath);276 return this._writeFile(info);277 },278 edit(info) {279 this._writeStatusToUI(chalk.green, 'edited', info.displayPath);280 },281 remove(info) {282 this._writeStatusToUI(chalk.red, 'remove', info.displayPath);283 if (!this.dryRun) {284 return cleanRemove(info);285 }286 },287 },288 /**289 Calls an action.290 @private291 @method _commit292 @param {Object} result293 @return {Promise}294 @throws {Error} Action doesn't exist.295 */296 _commit(result) {297 let action = this._actions[result.action];298 if (action) {299 return action.call(this, result);300 } else {301 throw new Error(`Tried to call action "${result.action}" but it does not exist`);302 }303 },304 /**305 Prints warning for pod unsupported.306 @private307 @method _checkForPod308 */309 _checkForPod(verbose) {310 if (!this.hasPathToken && this.pod && verbose) {311 this.ui.writeLine(312 chalk.yellow(313 'You specified the pod flag, but this' +314 ' blueprint does not support pod structure. It will be generated with' +315 ' the default structure.'316 )317 );318 }319 },320 /**321 @private322 @method _normalizeEntityName323 @param {Object} entity324 */325 _normalizeEntityName(entity) {326 if (entity) {327 entity.name = this.normalizeEntityName(entity.name);328 }329 },330 /**331 @private332 @method _checkInRepoAddonExists333 @param {Object} options334 */335 _checkInRepoAddonExists(options) {336 let addon;337 if (options.inRepoAddon) {338 addon = findAddonByName(this.project, options.inRepoAddon);339 if (!addon) {340 throw new SilentError(341 `You specified the 'in-repo-addon' flag, but the ` +342 `in-repo-addon '${options.inRepoAddon}' does not exist. Please check the name and try again.`343 );344 }345 }346 if (options.in) {347 if (!ensureTargetDirIsAddon(options.in)) {348 throw new SilentError(349 `You specified the 'in' flag, but the ` +350 `in repo addon '${options.in}' does not exist. Please check the name and try again.`351 );352 }353 }354 },355 /**356 @private357 @method _process358 @param {Object} options359 @param {Function} beforeHook360 @param {Function} process361 @param {Function} afterHook362 */363 async _process(options, beforeHook, process, afterHook) {364 let intoDir = options.target;365 let locals = await this._locals(options);366 // run beforeInstall/beforeUninstall userland hooks367 await beforeHook.call(this, options, locals);368 // gather fileInfos to be processed369 let fileInfos = await process.call(this, intoDir, locals);370 // commit changes for each FileInfo (with prompting as needed)371 await Promise.all(fileInfos.map((info) => this._commit(info)));372 // run afterInstall/afterUninstall userland hooks373 await afterHook.call(this, options);374 },375 /**376 @private377 @method shouldConvertToJS378 @param {Object} options379 @param {FileInfo} fileInfo380 @return {Boolean}381 */382 shouldConvertToJS(options, fileInfo) {383 // If this isn't turned on, it doesn't matter what else was passed, we're not touching it.384 if (!this.shouldTransformTypeScript) {385 return false;386 }387 // If the blueprint isn't a TS file to begin with, there's nothing to convert.388 if (!isTypeScriptFile(fileInfo.outputPath)) {389 // If the user wants TypeScript output but there is no TypeScript blueprint available, we want390 // to warn them that they're not going to get what they're expecting while still at least giving391 // them the JS output. We check for this *after* checking `shouldTranformTypeScript` because392 // it's possible for people to set `{typescript: true}` in their `.ember-cli` file, which would393 // then erroneously trigger this message every time they generate a JS blueprint even though394 // they didn't pass the flag.395 if (options.typescript === true) {396 this.ui.writeLine(397 chalk.yellow(398 "You passed the '--typescript' flag but there is no TypeScript blueprint available. " +399 'A JavaScript blueprint will be generated instead.'400 )401 );402 }403 return false;404 }405 // Indicates when the user explicitly passed either `--typescript` or `--no-typescript` as opposed406 // to not passing a flag at all and allowing for default behavior407 const userExplicitlySelectedTypeScriptStatus = options.typescript !== undefined;408 // Indicates when the user has asked for TypeScript either globally (by setting409 // `isTypeScriptProject` to true) or locally (by passing the `--typescript` flag when they410 // invoked the generator). Although ember-cli merges `.ember-cli` and all of the flag values into411 // one object, we thought the DX would be improved by differentiating between what is intended412 // to be global vs. local config.413 const shouldUseTypeScript = userExplicitlySelectedTypeScriptStatus414 ? options.typescript415 : options.isTypeScriptProject;416 // if the user wants TS output and we have a TS file available, we do *not* want to downlevel to JS417 if (shouldUseTypeScript) {418 return false;419 }420 return true;421 },422 /**423 @private424 @method convertToJS425 @param {FileInfo} fileInfo426 @return {Promise}427 */428 async convertToJS(fileInfo) {429 let rendered = await fileInfo.render();430 const transformed = await removeTypes(rendered);431 fileInfo.rendered = transformed;432 fileInfo.displayPath = replaceExtension(fileInfo.displayPath, '.js');433 fileInfo.outputPath = replaceExtension(fileInfo.outputPath, '.js');434 return fileInfo;435 },436 /**437 @method install438 @param {Object} options439 @return {Promise}440 */441 install(options) {442 let ui = (this.ui = options.ui);443 let dryRun = (this.dryRun = options.dryRun);444 this.project = options.project;445 this.pod = options.pod;446 this.options = options;447 this.hasPathToken = hasPathToken(this.files(this.options));448 ui.writeLine(`installing ${this.name}`);449 if (dryRun) {450 ui.writeLine(chalk.yellow('You specified the dry-run flag, so no' + ' changes will be written.'));451 }452 this._normalizeEntityName(options.entity);453 this._checkForPod(options.verbose);454 this._checkInRepoAddonExists(options);455 logger.info('START: processing blueprint: `%s`', this.name);456 let start = new Date();457 return this._process(options, this.beforeInstall, this.processFiles, this.afterInstall).finally(() =>458 logger.info('END: processing blueprint: `%s` in (%dms)', this.name, new Date() - start)459 );460 },461 /**462 @method uninstall463 @param {Object} options464 @return {Promise}465 */466 uninstall(options) {467 let ui = (this.ui = options.ui);468 let dryRun = (this.dryRun = options.dryRun);469 this.project = options.project;470 this.pod = options.pod;471 this.options = options;472 this.hasPathToken = hasPathToken(this.files(this.options));473 ui.writeLine(`uninstalling ${this.name}`);474 if (dryRun) {475 ui.writeLine(chalk.yellow('You specified the dry-run flag, so no' + ' files will be deleted.'));476 }477 this._normalizeEntityName(options.entity);478 this._checkForPod(options.verbose);479 return this._process(options, this.beforeUninstall, this.processFilesForUninstall, this.afterUninstall);480 },481 /**482 Hook for running operations before install.483 @method beforeInstall484 @return {Promise|null}485 */486 beforeInstall() {},487 /**488 Hook for running operations after install.489 @method afterInstall490 @return {Promise|null}491 */492 afterInstall() {},493 /**494 Hook for running operations before uninstall.495 @method beforeUninstall496 @return {Promise|null}497 */498 beforeUninstall() {},499 /**500 Hook for running operations after uninstall.501 @method afterUninstall502 @return {Promise|null}503 */504 afterUninstall() {},505 filesToRemove: [],506 /**507 Hook for adding custom template variables.508 When the following is called on the command line:509 ```sh510 ember generate controller foo --type=array --dry-run isAdmin:true511 ```512 The object passed to `locals` looks like this:513 ```js514 {515 entity: {516 name: 'foo',517 options: {518 isAdmin: true519 }520 },521 dryRun: true522 type: "array"523 // more keys524 }525 ```526 This hook must return an object or a Promise which resolves to an object.527 The resolved object will be merged with the aforementioned default locals.528 @public529 @method locals530 @param {Object} options General and entity-specific options531 @return {Object|Promise|null}532 */533 locals(/* options */) {},534 /**535 Hook to add additional or override existing fileMap tokens.536 Use `fileMapTokens` to add custom fileMap tokens for use537 in the `mapFile` method. The hook must return an object in the538 following pattern:539 ```js540 {541 __token__(options){542 // logic to determine value goes here543 return 'value';544 }545 }546 ```547 It will be merged with the default `fileMapTokens`, and can be used548 to override any of the default tokens.549 Tokens are used in the files folder (see `files`), and get replaced with550 values when the `mapFile` method is called.551 @public552 @method fileMapTokens553 @return {Object|null}554 */555 fileMapTokens() {},556 /**557 @private558 @method _fileMapTokens559 @param {Object} options560 @return {Object}561 */562 _fileMapTokens(options) {563 let { project } = this;564 let standardTokens = {565 __name__(options) {566 if (options.pod && options.hasPathToken) {567 return options.blueprintName;568 }569 return options.dasherizedModuleName;570 },571 __path__(options) {572 let blueprintName = options.blueprintName;573 if (/-test/.test(blueprintName)) {574 blueprintName = options.blueprintName.slice(0, options.blueprintName.indexOf('-test'));575 }576 if (options.pod && options.hasPathToken) {577 return path.join(options.podPath, options.dasherizedModuleName);578 }579 return inflector.pluralize(blueprintName);580 },581 __root__(options) {582 if (options.inRepoAddon) {583 let addon = findAddonByName(project, options.inRepoAddon);584 let relativeAddonPath = path.relative(project.root, addon.root);585 return path.join(relativeAddonPath, 'addon');586 }587 if (options.in) {588 let relativeAddonPath = path.relative(project.root, options.in);589 return path.join(relativeAddonPath, 'addon');590 }591 if (options.inDummy) {592 return path.join('tests', 'dummy', 'app');593 }594 if (options.inAddon) {595 return 'addon';596 }597 return 'app';598 },599 __test__(options) {600 if (options.pod && options.hasPathToken) {601 return options.blueprintName;602 }603 return `${options.dasherizedModuleName}-test`;604 },605 };606 let customTokens = this.fileMapTokens(options) || options.fileMapTokens || {};607 return _.merge(standardTokens, customTokens);608 },609 /**610 Used to generate fileMap tokens for mapFile.611 @method generateFileMap612 @param {Object} fileMapVariables613 @return {Object}614 */615 generateFileMap(fileMapVariables) {616 let tokens = this._fileMapTokens(fileMapVariables);617 let fileMapValues = _.values(tokens);618 let tokenValues = fileMapValues.map((token) => token(fileMapVariables));619 let tokenKeys = Object.keys(tokens);620 return _.zipObject(tokenKeys, tokenValues);621 },622 /**623 @method buildFileInfo624 @param {Function} destPath625 @param {Object} templateVariables626 @param {String} file627 @return {FileInfo}628 */629 buildFileInfo(intoDir, templateVariables, file) {630 let mappedPath = this.mapFile(file, templateVariables);631 return new FileInfo({632 action: 'write',633 outputBasePath: path.normalize(intoDir),634 outputPath: path.join(intoDir, mappedPath),635 displayPath: path.normalize(mappedPath),636 inputPath: this.srcPath(file),637 templateVariables,638 ui: this.ui,639 });640 },641 /**642 @method isUpdate643 @return {Boolean}644 */645 isUpdate() {646 if (this.project && this.project.isEmberCLIProject) {647 return this.project.isEmberCLIProject();648 }649 },650 /**651 @private652 @method _getFileInfos653 @param {Array} files654 @param {String} intoDir655 @param {Object} templateVariables656 @return {Array} file infos657 */658 _getFileInfos(files, intoDir, templateVariables) {659 return files.map(this.buildFileInfo.bind(this, intoDir, templateVariables));660 },661 /**662 Add update files to ignored files or reset them663 @private664 @method _ignoreUpdateFiles665 */666 _ignoreUpdateFiles() {667 if (this.isUpdate()) {668 Blueprint.ignoredFiles = Blueprint.ignoredFiles.concat(Blueprint.ignoredUpdateFiles);669 } else {670 Blueprint.ignoredFiles = initialIgnoredFiles;671 }672 },673 /**674 @private675 @method _getFilesForInstall676 @param {Array} targetFiles677 @return {Array} files678 */679 _getFilesForInstall(targetFiles) {680 let files = this.files(this.options);681 // if we've defined targetFiles, get file info on ones that match682 return (targetFiles && targetFiles.length > 0 && _.intersection(files, targetFiles)) || files;683 },684 /**685 @private686 @method _checkForNoMatch687 @param {Array} fileInfos688 @param {String} rawArgs689 */690 _checkForNoMatch(fileInfos, rawArgs) {691 if (fileInfos.filter(isFilePath).length < 1 && rawArgs) {692 this.ui.writeLine(693 chalk.yellow(`The globPattern "${rawArgs}" ` + `did not match any files, so no file updates will be made.`)694 );695 }696 },697 /**698 @method processFiles699 @param {String} intoDir700 @param {Object} templateVariables701 @return {Promise<FileInfo[]>}702 */703 processFiles(intoDir, templateVariables) {704 let files = this._getFilesForInstall(templateVariables.targetFiles);705 let fileInfos = this._getFileInfos(files, intoDir, templateVariables);706 this._checkForNoMatch(fileInfos, templateVariables.rawArgs);707 this._ignoreUpdateFiles();708 let fileInfosToRemove = this._getFileInfos(this.filesToRemove, intoDir, templateVariables);709 fileInfosToRemove = finishProcessingForUninstall(fileInfosToRemove);710 return Promise.all(fileInfos.filter(isValidFile).map(prepareConfirm))711 .then(finishProcessingForInstall)712 .then((fileInfos) => {713 return Promise.all(714 fileInfos.map((info) => {715 if (this.shouldConvertToJS(this.options, info)) {716 return this.convertToJS(info);717 }718 return info;719 })720 );721 })722 .then((fileInfos) => fileInfos.concat(fileInfosToRemove));723 },724 /**725 @method processFilesForUninstall726 @param {String} intoDir727 @param {Object} templateVariables728 */729 processFilesForUninstall(intoDir, templateVariables) {730 let fileInfos = this._getFileInfos(this.files(this.options), intoDir, templateVariables);731 this._ignoreUpdateFiles();732 fileInfos = fileInfos.filter(isValidFile).reduce((acc, info) => {733 // if it's possible that this blueprint could have produced either typescript OR javascript, we have to do some734 // work to figure out which files to delete.735 if (this.shouldTransformTypeScript) {736 if (this.options.typescript === true) {737 // if the user explicitly passed `--typescript`, we only want to delete TS files, so we stick with the existing738 // info object since it will contain a .ts outputPath (since we know this blueprint is authored in TS because739 // of our check above)740 acc.push(info);741 return acc;742 }743 const jsInfo = new FileInfo({744 ...info,745 outputPath: replaceExtension(info.outputPath, '.js'),746 displayPath: replaceExtension(info.displayPath, '.js'),747 });748 if (this.options.typescript === false) {749 // if the user explicitly passed `--no-typescript`, we only want to delete JS file, so we return our newly750 // created jsInfo object since it contains the javascript version of the output path.751 acc.push(jsInfo);752 return acc;753 }754 if (this.options.typescript === undefined) {755 // if the user didn't specify one way or the other, then both the JS and TS paths are possibilities, so we add756 // both of them to the list. `finishProcessingForUninstall` will actually look to see which of them exists and757 // delete whatever it finds.758 acc.push(info, jsInfo);759 return acc;760 }761 }762 acc.push(info);763 return acc;764 }, []);765 return finishProcessingForUninstall(fileInfos);766 },767 /**768 @method mapFile769 @param {String} file770 @param locals771 @return {String}772 */773 mapFile(file, locals) {774 let pattern, i;775 let fileMap = locals.fileMap || { __name__: locals.dasherizedModuleName };776 file = Blueprint.renamedFiles[file] || file;777 for (i in fileMap) {778 pattern = new RegExp(i, 'g');779 file = file.replace(pattern, fileMap[i]);780 }781 return file;782 },783 /**784 Looks for a __root__ token in the files folder. Must be present for785 the blueprint to support addon tokens. The `server`, `blueprints`, and `test`786 @private787 @method supportsAddon788 @return {Boolean}789 */790 supportsAddon() {791 return /__root__/.test(this.files().join());792 },793 /**794 @private795 @method _generateFileMapVariables796 @param {String} moduleName797 @param locals798 @param {Object} options799 @return {Object}800 */801 _generateFileMapVariables(moduleName, locals, options) {802 let originBlueprintName = options.originBlueprintName || this.name;803 let podModulePrefix = this.project.config().podModulePrefix || '';804 let podPath = podModulePrefix.substr(podModulePrefix.lastIndexOf('/') + 1);805 let inAddon = this.project.isEmberCLIAddon() || !!options.inRepoAddon;806 let inDummy = this.project.isEmberCLIAddon() ? options.dummy : false;807 return {808 pod: this.pod,809 podPath,810 hasPathToken: this.hasPathToken,811 inAddon,812 inRepoAddon: options.inRepoAddon,813 in: options.in,814 inDummy,815 blueprintName: this.name,816 originBlueprintName,817 dasherizedModuleName: stringUtils.dasherize(moduleName),818 locals,819 };820 },821 /**822 @private823 @method _locals824 @param {Object} options825 @return {Object}826 */827 _locals(options) {828 let packageName = options.project.name();829 let moduleName = (options.entity && options.entity.name) || packageName;830 let sanitizedModuleName = moduleName.replace(/\//g, '-');831 return new Promise((resolve) => {832 resolve(this.locals(options));833 }).then((customLocals) => {834 let fileMapVariables = this._generateFileMapVariables(moduleName, customLocals, options);835 let fileMap = this.generateFileMap(fileMapVariables);836 let standardLocals = {837 dasherizedPackageName: stringUtils.dasherize(packageName),838 classifiedPackageName: stringUtils.classify(packageName),839 dasherizedModuleName: stringUtils.dasherize(moduleName),840 classifiedModuleName: stringUtils.classify(sanitizedModuleName),841 camelizedModuleName: stringUtils.camelize(sanitizedModuleName),842 decamelizedModuleName: stringUtils.decamelize(sanitizedModuleName),843 fileMap,844 hasPathToken: this.hasPathToken,845 targetFiles: options.targetFiles,846 rawArgs: options.rawArgs,847 };848 return _.merge({}, standardLocals, customLocals);849 });850 },851 /**852 Used to add a package to the project's `package.json`.853 Generally, this would be done from the `afterInstall` hook, to854 ensure that a package that is required by a given blueprint is855 available.856 @method addPackageToProject857 @param {String} packageName858 @param {String} target859 @return {Promise}860 */861 addPackageToProject(packageName, target) {862 let packageObject = { name: packageName };863 if (target) {864 packageObject.target = target;865 }866 return this.addPackagesToProject([packageObject]);867 },868 /**869 Used to add multiple packages to the project's `package.json`.870 Generally, this would be done from the `afterInstall` hook, to871 ensure that a package that is required by a given blueprint is872 available.873 Expects each array item to be an object with a `name`. Each object874 may optionally have a `target` to specify a specific version.875 @method addPackagesToProject876 @param {Array} packages877 @return {Promise}878 @example879 ```js880 this.addPackagesToProject([881 { name: 'lodash' },882 { name: 'moment', target: '^2.17.0' },883 ]);884 ```885 */886 addPackagesToProject(packages) {887 let task = this.taskFor('npm-install');888 let installText = packages.length > 1 ? 'install packages' : 'install package';889 let packageNames = [];890 let packageArray = [];891 for (let i = 0; i < packages.length; i++) {892 packageNames.push(packages[i].name);893 let packageNameAndVersion = packages[i].name;894 if (packages[i].target) {895 packageNameAndVersion += `@${packages[i].target}`;896 }897 packageArray.push(packageNameAndVersion);898 }899 this._writeStatusToUI(chalk.green, installText, packageNames.join(', '));900 return task.run({901 'save-dev': true,902 verbose: false,903 packages: packageArray,904 });905 },906 /**907 Used to remove a package from the project's `package.json`.908 Generally, this would be done from the `afterInstall` hook, to909 ensure that any package conflicts can be resolved before the910 addon is used.911 @method removePackageFromProject912 @param {String} packageName913 @return {Promise}914 */915 removePackageFromProject(packageName) {916 let packageObject = { name: packageName };917 return this.removePackagesFromProject([packageObject]);918 },919 /**920 Used to remove multiple packages from the project's `package.json`.921 Generally, this would be done from the `afterInstall` hook, to922 ensure that any package conflicts can be resolved before the923 addon is used.924 Expects each array item to be an object with a `name` property.925 @method removePackagesFromProject926 @param {Array} packages927 @return {Promise}928 */929 removePackagesFromProject(packages) {930 let task = this.taskFor('npm-uninstall');931 let installText = packages.length > 1 ? 'uninstall packages' : 'uninstall package';932 let packageNames = [];933 let projectDependencies = this.project.dependencies();934 for (let i = 0; i < packages.length; i++) {935 let packageName = packages[i].name;936 if (packageName in projectDependencies) {937 packageNames.push(packageName);938 }939 }940 if (packageNames.length === 0) {941 this._writeStatusToUI(chalk.yellow, 'remove', 'Skipping uninstall because no matching package is installed.');942 return Promise.resolve();943 }944 this._writeStatusToUI(chalk.green, installText, packageNames.join(', '));945 return task.run({946 'save-dev': true,947 verbose: false,948 packages: packageNames,949 });950 },951 /**952 Used to add a Bower package to the projects `bower.json`.953 954 Bower is a package manager that is no longer recommended 955 for new projects, but you may find this hook used in older956 addons.957 Generally, this would be done from the `afterInstall` hook, to958 ensure that a package that is required by a given blueprint is959 available.960 `localPackageName` and `target` may be thought of as equivalent961 to the key-value pairs in the `dependency` or `devDepencency`962 objects contained within a bower.json file.963 @method addBowerPackageToProject964 @param {String} localPackageName965 @param {String} target966 @param {Object} installOptions967 @return {Promise}968 @example969 ```js970 addBowerPackageToProject('jquery', '~1.11.1');971 addBowerPackageToProject('old_jquery', 'jquery#~1.9.1');972 addBowerPackageToProject('bootstrap-3', 'https://twitter.github.io/bootstrap/assets/bootstrap');973 ```974 */975 addBowerPackageToProject(localPackageName, target, installOptions) {976 deprecate(977 [978 `(Blueprint: \`${this.name}\`) \`addBowerPackageToProject\` has been deprecated.`,979 'If the package is also available on the npm registry, please use `addPackageToProject` instead.',980 'If not, please install the Bower package manually by running:',981 `\`bower install ${localPackageName} --save\``,982 ].join('\n'),983 false,984 {985 for: 'ember-cli',986 id: 'ember-cli.blueprint.add-bower-package-to-project',987 since: {988 available: '4.2.0',989 enabled: '4.2.0',990 },991 until: '5.0.0',992 }993 );994 let lpn = localPackageName;995 let tar = target;996 let packageObject = bowEpParser.json2decomposed(lpn, tar);997 return this.addBowerPackagesToProject([packageObject], installOptions, true);998 },999 /**1000 Used to add an array of packages to the projects `bower.json`.1001 1002 Bower is a package manager that is no longer recommended 1003 for new projects, but you may find this hook used in older1004 addons.1005 Generally, this would be done from the `afterInstall` hook, to1006 ensure that a package that is required by a given blueprint is1007 available.1008 Expects each array item to be an object with a `name`. Each object1009 may optionally have a `target` to specify a specific version, or a1010 `source` to specify a non-local name to be resolved.1011 @method addBowerPackagesToProject1012 @param {Array} packages1013 @param {Object} installOptions1014 @return {Promise}1015 */1016 addBowerPackagesToProject(packages, installOptions, _deprecationCondition = false) {1017 let task = this.taskFor('bower-install');1018 let installText = packages.length > 1 ? 'install bower packages' : 'install bower package';1019 let packageNames = [];1020 let packageNamesAndVersions = packages1021 .map((pkg) => {1022 pkg.source = pkg.source || pkg.name;1023 packageNames.push(pkg.name);1024 return pkg;1025 })1026 .map(bowEpParser.compose);1027 deprecate(1028 [1029 `(Blueprint: \`${this.name}\`) \`addBowerPackagesToProject\` has been deprecated.`,1030 'If the packages are also available on the npm registry, please use `addPackagesToProject` instead.',1031 'If not, please install the Bower packages manually by running:',1032 `\`bower install ${packageNames.join(' ')} --save\``,1033 ].join('\n'),1034 _deprecationCondition,1035 {1036 for: 'ember-cli',1037 id: 'ember-cli.blueprint.add-bower-packages-to-project',1038 since: {1039 available: '4.2.0',1040 enabled: '4.2.0',1041 },1042 until: '5.0.0',1043 }1044 );1045 this._writeStatusToUI(chalk.green, installText, packageNames.join(', '));1046 return task.run({1047 verbose: true,1048 packages: packageNamesAndVersions,1049 installOptions: installOptions || { save: true },1050 });1051 },1052 /**1053 Used to add an addon to the project's `package.json` and run it's1054 `defaultBlueprint` if it provides one.1055 Generally, this would be done from the `afterInstall` hook, to1056 ensure that a package that is required by a given blueprint is1057 available.1058 @method addAddonToProject1059 @param {Object} options1060 @return {Promise}1061 */1062 addAddonToProject(options) {1063 return this.addAddonsToProject({1064 packages: [options],1065 extraArgs: options.extraArgs || {},1066 blueprintOptions: options.blueprintOptions || {},1067 });1068 },1069 /**1070 Used to add multiple addons to the project's `package.json` and run their1071 `defaultBlueprint` if they provide one.1072 Generally, this would be done from the `afterInstall` hook, to1073 ensure that a package that is required by a given blueprint is1074 available.1075 @method addAddonsToProject1076 @param {Object} options1077 @return {Promise}1078 */1079 addAddonsToProject(options) {1080 let taskOptions = {1081 packages: [],1082 extraArgs: options.extraArgs || [],1083 blueprintOptions: options.blueprintOptions || {},1084 };1085 let packages = options.packages;1086 if (packages && packages.length) {1087 taskOptions.packages = packages.map((pkg) => {1088 if (typeof pkg === 'string') {1089 return pkg;1090 }1091 if (!pkg.name) {1092 throw new SilentError('You must provide a package `name` to addAddonsToProject');1093 }1094 if (pkg.target) {1095 pkg.name += `@${pkg.target}`;1096 }1097 return pkg.name;1098 });1099 } else {1100 throw new SilentError('You must provide package to addAddonsToProject');1101 }1102 let installText = packages.length > 1 ? 'install addons' : 'install addon';1103 this._writeStatusToUI(chalk.green, installText, taskOptions['packages'].join(', '));1104 return this.taskFor('addon-install').run(taskOptions);1105 },1106 /**1107 Used to retrieve a task with the given name. Passes the new task1108 the standard information available (like `ui`, `analytics`, `project`, etc).1109 @method taskFor1110 @param dasherizedName1111 @public1112 */1113 taskFor(dasherizedName) {1114 const Task = require(`../tasks/${dasherizedName}`);1115 return new Task({1116 ui: this.ui,1117 project: this.project,1118 analytics: this.analytics,1119 });1120 },1121 /**1122 Inserts the given content into a file. If the `contentsToInsert` string is already1123 present in the current contents, the file will not be changed unless `force` option1124 is passed.1125 If `options.before` is specified, `contentsToInsert` will be inserted before1126 the first instance of that string. If `options.after` is specified, the1127 contents will be inserted after the first instance of that string.1128 If the string specified by options.before or options.after is not in the file,1129 no change will be made.1130 If neither `options.before` nor `options.after` are present, `contentsToInsert`1131 will be inserted at the end of the file.1132 Example:1133 ```1134 // app/router.js1135 Router.map(function () {1136 });1137 ```1138 ```1139 insertIntoFile('app/router.js', ' this.route("admin");', {1140 after: 'Router.map(function () {' + EOL1141 }).then(function() {1142 // file has been inserted into!1143 });1144 ```1145 ```1146 // app/router.js1147 Router.map(function () {1148 this.route("admin");1149 });1150 ```1151 @method insertIntoFile1152 @param {String} pathRelativeToProjectRoot1153 @param {String} contentsToInsert1154 @param {Object} providedOptions1155 @return {Promise}1156 */1157 insertIntoFile(pathRelativeToProjectRoot, contentsToInsert, providedOptions) {1158 let fullPath = path.join(this.project.root, pathRelativeToProjectRoot);1159 return insertIntoFile(fullPath, contentsToInsert, providedOptions);1160 },1161 _printCommand: printCommand,1162 printBasicHelp(verbose) {1163 let initialMargin = ' ';1164 let output = initialMargin;1165 if (this.overridden) {1166 output += chalk.grey(`(overridden) ${this.name}`);1167 } else {1168 output += this.name;1169 output += this._printCommand(initialMargin, true);1170 if (verbose) {1171 output += EOL + this.printDetailedHelp(this.availableOptions);1172 }1173 }1174 return output;1175 },1176 printDetailedHelp() {1177 let markdownColor = new MarkdownColor();1178 let filePath = getDetailedHelpPath(this.path);1179 if (Blueprint._existsSync(filePath)) {1180 return markdownColor.renderFile(filePath, { indent: ' ' });1181 }1182 return '';1183 },1184 getJson(verbose) {1185 let json = {};1186 this._printableProperties.forEach((key) => {1187 let value = this[key];1188 if (key === 'availableOptions') {1189 value = _.cloneDeep(value);1190 value.forEach((option) => {1191 if (typeof option.type === 'function') {1192 option.type = option.type.name;1193 }1194 });1195 }1196 json[key] = value;1197 });1198 if (verbose) {1199 let detailedHelp = this.printDetailedHelp(this.availableOptions);1200 if (detailedHelp) {1201 json.detailedHelp = detailedHelp;1202 }1203 }1204 return json;1205 },1206 /**1207 Used to retrieve a blueprint with the given name.1208 @method lookupBlueprint1209 @param {String} dasherizedName1210 @return {Blueprint}1211 @public1212 */1213 lookupBlueprint(dasherizedName) {1214 let projectPaths = this.project ? this.project.blueprintLookupPaths() : [];1215 return Blueprint.lookup(dasherizedName, {1216 paths: projectPaths,1217 });1218 },1219});1220/**1221 @static1222 @method lookup1223 @namespace Blueprint1224 @param {String} name1225 @param {Object} [options]1226 @param {Array} [options.paths] Extra paths to search for blueprints1227 @param {Boolean} [options.ignoreMissing] Throw a `SilentError` if a1228 matching Blueprint could not be found1229 @return {Blueprint}1230*/1231Blueprint.lookup = function (name, options) {1232 options = options || {};1233 if (name.includes(path.sep)) {1234 let blueprintPath = path.resolve(name);1235 let isNameAPath = Boolean(blueprintPath);1236 if (isNameAPath) {1237 if (Blueprint._existsSync(blueprintPath)) {1238 return Blueprint.load(blueprintPath);1239 }1240 if (!options.ignoreMissing) {1241 throw new SilentError(`Unknown blueprint: ${name}`);1242 }1243 return;1244 }1245 }1246 let lookupPaths = generateLookupPaths(options.paths);1247 let lookupPath;1248 for (let i = 0; (lookupPath = lookupPaths[i]); i++) {1249 let blueprintPath = path.resolve(lookupPath, name);1250 if (Blueprint._existsSync(blueprintPath)) {1251 return Blueprint.load(blueprintPath);1252 }1253 }1254 if (!options.ignoreMissing) {1255 throw new SilentError(`Unknown blueprint: ${name}`);1256 }1257};1258/**1259 Loads a blueprint from given path.1260 @static1261 @method load1262 @namespace Blueprint1263 @param {String} blueprintPath1264 @return {Blueprint} blueprint instance1265*/1266Blueprint.load = function (blueprintPath) {1267 if (fs.lstatSync(blueprintPath).isDirectory()) {1268 let Constructor = Blueprint;1269 let constructorPath = path.resolve(blueprintPath, 'index.js');1270 if (Blueprint._existsSync(constructorPath)) {1271 const blueprintModule = require(constructorPath);1272 if (typeof blueprintModule === 'function') {1273 Constructor = blueprintModule;1274 } else {1275 Constructor = Blueprint.extend(blueprintModule);1276 }1277 }1278 return new Constructor(blueprintPath);1279 }1280};1281/**1282 @static1283 @method list1284 @namespace Blueprint1285 @param {Object} [options]1286 @param {Array} [options.paths] Extra paths to search for blueprints1287 @return {Array}1288*/1289Blueprint.list = function (options) {1290 options = options || {};1291 let lookupPaths = generateLookupPaths(options.paths);1292 let seen = [];1293 return lookupPaths.map((lookupPath) => {1294 let source;1295 let packagePath = path.join(lookupPath, '../package.json');1296 if (Blueprint._existsSync(packagePath)) {1297 source = require(packagePath).name;1298 } else {1299 source = path.basename(path.join(lookupPath, '..'));1300 }1301 let blueprints = dir(lookupPath).map((blueprintPath) => {1302 let blueprint = Blueprint.load(blueprintPath);1303 if (blueprint) {1304 let name = blueprint.name;1305 blueprint.overridden = _.includes(seen, name);1306 seen.push(name);1307 return blueprint;1308 }1309 });1310 return {1311 source,1312 blueprints: _.compact(blueprints),1313 };1314 });1315};1316Blueprint._existsSync = function (path, parent) {1317 return fs.existsSync(path, parent);1318};1319Blueprint._readdirSync = function (path) {1320 return fs.readdirSync(path);1321};1322/**1323 Files that are renamed when installed into the target directory.1324 This allows including files in the blueprint that would have an effect1325 on another process, such as a file named `.gitignore`.1326 The keys are the filenames used in the files folder.1327 The values are the filenames used in the target directory.1328 @static1329 @property renamedFiles1330*/1331Blueprint.renamedFiles = {1332 gitignore: '.gitignore',1333};1334/**1335 @static1336 @property ignoredFiles1337*/1338Blueprint.ignoredFiles = initialIgnoredFiles;1339/**1340 @static1341 @property ignoredUpdateFiles1342*/1343Blueprint.ignoredUpdateFiles = ['.gitkeep', 'app.css', 'LICENSE.md'];1344/**1345 @static1346 @property defaultLookupPaths1347*/1348Blueprint.defaultLookupPaths = function () {1349 return [path.resolve(__dirname, '..', '..', 'blueprints')];1350};1351/**1352 @private1353 @method prepareConfirm1354 @param {FileInfo} info1355 @return {Promise}1356*/1357function prepareConfirm(info) {1358 return info.checkForConflict().then((resolution) => {1359 info.resolution = resolution;1360 return info;1361 });1362}1363/**1364 @private1365 @method markIdenticalToBeSkipped1366 @param {FileInfo} info1367*/1368function markIdenticalToBeSkipped(info) {1369 if (info.resolution === 'identical') {1370 info.action = 'skip';1371 }1372}1373/**1374 @private1375 @method markToBeRemoved1376 @param {FileInfo} info1377*/1378function markToBeRemoved(info) {1379 info.action = 'remove';1380}1381/**1382 @private1383 @method gatherConfirmationMessages1384 @param {Array} collection1385 @param {FileInfo} info1386 @return {Array}1387*/1388function gatherConfirmationMessages(collection, info) {1389 if (info.resolution === 'confirm') {1390 collection.push(info.confirmOverwriteTask());1391 }1392 return collection;1393}1394/**1395 @private1396 @method isIgnored1397 @param {FileInfo} info1398 @return {Boolean}1399*/1400function isIgnored(info) {1401 let fn = info.inputPath;1402 return Blueprint.ignoredFiles.some((ignoredFile) => minimatch(fn, ignoredFile, { matchBase: true }));1403}1404/**1405 Combines provided lookup paths with defaults and removes1406 duplicates.1407 @private1408 @method generateLookupPaths1409 @param {Array} lookupPaths1410 @return {Array}1411*/1412function generateLookupPaths(lookupPaths) {1413 lookupPaths = lookupPaths || [];1414 lookupPaths = lookupPaths.concat(Blueprint.defaultLookupPaths());1415 return _.uniq(lookupPaths);1416}1417/**1418 Looks for a __path__ token in the files folder. Must be present for1419 the blueprint to support pod tokens.1420 @private1421 @method hasPathToken1422 @param {files} files1423 @return {Boolean}1424*/1425function hasPathToken(files) {1426 return /__path__/.test(files.join());1427}1428function findAddonByName(addonOrProject, name) {1429 let addon = addonOrProject.addons.find((addon) => addon.name === name);1430 if (addon) {1431 return addon;1432 }1433 return addonOrProject.addons.find((addon) => findAddonByName(addon, name));1434}1435function ensureTargetDirIsAddon(addonPath) {1436 let projectInfo;1437 try {1438 projectInfo = require(path.join(addonPath, 'package.json'));1439 } catch (err) {1440 if (err.code === 'MODULE_NOT_FOUND') {1441 throw new Error(`The directory ${addonPath} does not appear to be a valid addon directory.`);1442 } else {1443 throw err;1444 }1445 }1446 return isAddon(projectInfo.keywords);1447}1448/**1449 @private1450 @method isValidFile1451 @param {Object} fileInfo1452 @return {Promise}1453*/1454function isValidFile(fileInfo) {1455 if (isIgnored(fileInfo)) {1456 return false;1457 } else {1458 return isFilePath(fileInfo);1459 }1460}1461/**1462 @private1463 @method isFilePath1464 @param {Object} fileInfo1465 @return {Promise}1466*/1467function isFilePath(fileInfo) {1468 return fs.statSync(fileInfo.inputPath).isFile();1469}1470/**1471 @private1472 @method dir1473 @return {Array} list of files in the given directory or and empty array if no directory exists1474*/1475function dir(fullPath) {1476 if (Blueprint._existsSync(fullPath)) {1477 return Blueprint._readdirSync(fullPath).map((fileName) => path.join(fullPath, fileName));1478 } else {1479 return [];1480 }1481}1482/**1483 @private1484 @method getDetailedHelpPath1485 @param {String} thisPath1486 @return {String} help path1487*/1488function getDetailedHelpPath(thisPath) {1489 return path.join(thisPath, './HELP.md');1490}1491function finishProcessingForInstall(infos) {1492 infos.forEach(markIdenticalToBeSkipped);1493 let infosNeedingConfirmation = infos.reduce(gatherConfirmationMessages, []);1494 return sequence(infosNeedingConfirmation).then(() => infos);1495}1496function finishProcessingForUninstall(infos) {1497 let validInfos = infos.filter((info) => fs.existsSync(info.outputPath));1498 validInfos.forEach(markToBeRemoved);1499 return validInfos;1500}1501function replaceExtension(filePath, newExt) {1502 const { dir, name } = path.parse(filePath);1503 return path.format({1504 dir,1505 name,1506 ext: newExt,1507 });1508}1509function isTypeScriptFile(filePath) {1510 return path.extname(filePath) === '.ts';1511}...
typescript-blueprint-polyfill.js
Source:typescript-blueprint-polyfill.js
1const { removeTypes } = require('remove-types');2const chalk = require('chalk');3const { replaceExtension, isTypeScriptFile } = require('./utils');4module.exports = function (context) {5 const blueprintClass = context._super.constructor.prototype;6 const originalProcessFiles = context.processFiles;7 const originalInstall = context.install;8 const originalUninstall = context.uninstall;9 if (Object.keys(blueprintClass).includes('shouldConvertToJS')) {10 return;11 }12 context.install = function () {13 this.blueprintFunction = 'install';14 return originalInstall.apply(this, arguments);15 };16 context.uninstall = function () {17 this.blueprintFunction = 'uninstall';18 return originalUninstall.apply(this, arguments);19 };20 context.shouldConvertToJS = function (options, fileInfo) {21 // If this isn't turned on, it doesn't matter what else was passed, we're not touching it.22 if (!this.shouldTransformTypeScript) {23 return false;24 }25 // If the blueprint isn't a TS file to begin with, there's nothing to convert.26 if (!isTypeScriptFile(fileInfo.outputPath)) {27 // If the user wants TypeScript output but there is no TypeScript blueprint available, we want28 // to warn them that they're not going to get what they're expecting while still at least giving29 // them the JS output. We check for this *after* checking `shouldTranformTypeScript` because30 // it's possible for people to set `{typescript: true}` in their `.ember-cli` file, which would31 // then erroneously trigger this message every time they generate a JS blueprint even though32 // they didn't pass the flag.33 if (options.typescript === true) {34 this.ui.writeLine(35 chalk.yellow(36 "You passed the '--typescript' flag but there is no TypeScript blueprint available. " +37 'A JavaScript blueprint will be generated instead.'38 )39 );40 }41 return false;42 }43 // Indicates when the user explicitly passed either `--typescript` or `--no-typescript` as opposed44 // to not passing a flag at all and allowing for default behavior45 const userExplicitlySelectedTypeScriptStatus =46 options.typescript !== undefined;47 // Indicates when the user has asked for TypeScript either globally (by setting48 // `isTypeScriptProject` to true) or locally (by passing the `--typescript` flag when they49 // invoked the generator). Although ember-cli merges `.ember-cli` and all of the flag values into50 // one object, we thought the DX would be improved by differentiating between what is intended51 // to be global vs. local config.52 const shouldUseTypeScript = userExplicitlySelectedTypeScriptStatus53 ? options.typescript54 : options.isTypeScriptProject;55 // if the user wants TS output and we have a TS file available, we do *not* want to downlevel to JS56 if (shouldUseTypeScript) {57 return false;58 }59 return true;60 };61 context.convertToJS = async function (fileInfo) {62 let rendered = await fileInfo.render();63 const transformed = await removeTypes(rendered);64 fileInfo.rendered = transformed;65 fileInfo.displayPath = replaceExtension(fileInfo.displayPath, '.js');66 fileInfo.outputPath = replaceExtension(fileInfo.outputPath, '.js');67 return fileInfo;68 };69 context.processFiles = function () {70 const upstreamResult = originalProcessFiles.apply(this, arguments);71 return upstreamResult.then((fileInfos) => {72 return Promise.all(73 fileInfos.map((info) => {74 if (this.shouldConvertToJS(this.options, info)) {75 return this.convertToJS(info);76 }77 return info;78 })79 );80 });81 };82 context._getFileInfos = function (files, intoDir, templateVariables) {83 const fileInfos = files.map(84 this.buildFileInfo.bind(this, intoDir, templateVariables)85 );86 if (this.blueprintFunction === 'install') {87 return fileInfos;88 }89 return fileInfos.reduce((acc, info) => {90 // if it's possible that this blueprint could have produced either typescript OR javascript, we have to do some91 // work to figure out which files to delete.92 if (this.shouldTransformTypeScript) {93 if (this.options.typescript === true) {94 // if the user explicitly passed `--typescript`, we only want to delete TS files, so we stick with the existing95 // info object since it will contain a .ts outputPath (since we know this blueprint is authored in TS because96 // of our check above)97 acc.push(info);98 return acc;99 }100 const jsInfo = Object.create(info);101 Object.assign(jsInfo, {102 outputPath: replaceExtension(info.outputPath, '.js'),103 displayPath: replaceExtension(info.displayPath, '.js'),104 });105 if (this.options.typescript === false) {106 // if the user explicitly passed `--no-typescript`, we only want to delete JS file, so we return our newly107 // created jsInfo object since it contains the javascript version of the output path.108 acc.push(jsInfo);109 return acc;110 }111 if (this.options.typescript === undefined) {112 // if the user didn't specify one way or the other, then both the JS and TS paths are possibilities, so we add113 // both of them to the list. `finishProcessingForUninstall` will actually look to see which of them exists and114 // delete whatever it finds.115 acc.push(info, jsInfo);116 return acc;117 }118 }119 acc.push(info);120 return acc;121 }, []);122 };...
cli.ts
Source:cli.ts
...28 .description(pkg.description)29program.command('dev').action(async () => {30 printLogo()31 const config = await getUserSNextConfig()32 const useTypescript = shouldUseTypescript()33 process.env.NODE_ENV = 'development'34 if (config.runtime === 'cloudflare-worker') {35 ensureSNextCloudflareWorkerInstalled()36 const { startWorkerDevServer } = await import('@snext/cloudflare-worker')37 startWorkerDevServer({38 ...config,39 useTypescript,40 })41 } else {42 const { default: startDevServer } = await import('./startDevServer.js')43 startDevServer({44 ...config,45 useTypescript,46 compileNodeCommonJS: config.runtime === 'commonjs',47 })48 }49})50program.command('build').action(async () => {51 printLogo()52 const config = await getUserSNextConfig()53 const useTypescript = shouldUseTypescript()54 process.env.NODE_ENV = 'production'55 if (config.runtime === 'cloudflare-worker') {56 ensureSNextCloudflareWorkerInstalled()57 const { buildForWorker } = await import('@snext/cloudflare-worker')58 console.log()59 console.log('Creating an optimized build...')60 console.log()61 buildForWorker({62 ...config,63 useTypescript,64 })65 } else {66 const { default: build } = await import('./build.js')67 console.log()...
Using AI Code Generation
1describe('My First Test', function() {2 it('Does not do much!', function() {3 expect(true).to.equal(true)4 })5})6{7 "compilerOptions": {8 }9}10{11 "env": {},12 "reporterOptions": {13 },14}15{16 "compilerOptions": {17 }18}19module.exports = (on, config) => {20 require('@cypress/code-coverage/task')(on, config)21}22module.exports = (on, config) => {23 require('@cypress/code-coverage/task')(on, config)24}25import '@cypress/code-coverage/support'26{
Using AI Code Generation
1const cypress = require('cypress');2cypress.shouldUseTypescript();3import * as cypress from 'cypress';4cypress.shouldUseTypescript();5import { shouldUseTypescript } from 'cypress';6shouldUseTypescript();7import shouldUseTypescript from 'cypress';8shouldUseTypescript();9const shouldUseTypescript = require('cypress').shouldUseTypescript;10shouldUseTypescript();11const { shouldUseTypescript } = require('cypress');12shouldUseTypescript();13const shouldUseTypescript = require('cypress/shouldUseTypescript');14shouldUseTypescript();15const shouldUseTypescript = require('cypress/shouldUseTypescript').default;16shouldUseTypescript();17const shouldUseTypescript = require('cypress/shouldUseTypescript').shouldUseTypescript;18shouldUseTypescript();19const { shouldUseTypescript } = require('cypress/shouldUseTypescript');20shouldUseTypescript();21import shouldUseTypescript from 'cypress/shouldUseTypescript';22shouldUseTypescript();23import { shouldUseTypescript } from 'cypress/shouldUseTypescript';24shouldUseTypescript();25import shouldUseTypescript from 'cypress/shouldUseTypescript.js';26shouldUseTypescript();27import { shouldUseTypescript } from 'cypress/shouldUseTypescript.js';28shouldUseTypescript();29import shouldUseTypescript from 'cypress/shouldUseTypescript.ts';30shouldUseTypescript();
Using AI Code Generation
1{2 "dependencies": {3 },4 "devDependencies": {5 },6 "scripts": {7 },8 "cypress-cucumber-preprocessor": {9 }10}11{12 "reporterOptions": {
Using AI Code Generation
1Cypress.shouldUseTypescript = () => {2 return true;3};4Cypress.shouldUseTypescript = () => {5 return false;6};7{8 "compilerOptions": {9 }10}11{12 "compilerOptions": {13 }14}15Cypress.shouldUseTypescript = () => {16 return true;17};18Cypress.shouldUseTypescript = () => {19 return false;20};21Cypress.shouldUseTypescript = () => {22 return true;23};24Cypress.shouldUseTypescript = () => {25 return false;26};27Cypress.shouldUseTypescript = () => {28 return true;29};30Cypress.shouldUseTypescript = () => {31 return false;32};33Cypress.shouldUseTypescript = () => {34 return true;35};36Cypress.shouldUseTypescript = () => {37 return false;38};39Cypress.shouldUseTypescript = () => {40 return true;41};42Cypress.shouldUseTypescript = () => {43 return false;44};45Cypress.shouldUseTypescript = () => {46 return true;47};48Cypress.shouldUseTypescript = () => {49 return false;50};
Using AI Code Generation
1cy.shouldUseTypescript();2Cypress.Commands.add('shouldUseTypescript', function() {3 cy.exec('npm ls typescript').then((result) => {4 if (result.stdout.includes('typescript')) {5 cy.log('Typescript is installed');6 } else {7 cy.log('Typescript is not installed');8 }9 });10});11describe('My First Test', function() {12 it('Does not do much!', function() {13 cy.shouldUseTypescript();14 });15});
Using AI Code Generation
1const { shouldUseTypescript } = require('@nrwl/cypress/plugins/should-use-typescript');2const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin');3module.exports = (on, config) => {4 if (shouldUseTypescript(config)) {5 const { initPlugin } = require('@nrwl/cypress/plugins/init');6 initPlugin(on, config);7 }8 addMatchImageSnapshotPlugin(on, config);9 return config;10};11{12 "compilerOptions": {13 },14}15{16}17describe('app', () => {18 beforeEach(() => cy.visit('/'));19 it('should display welcome message', () => {20 cy.get('h1').should('contain', 'Welcome to app!');21 });22});23export class AppPage {24 navigateTo() {25 return cy.visit('/');26 }27 getParagraphText() {28 return cy.get('h1').should('contain', 'Welcome to app!');29 }30}31import './commands';32import { initPlugin } from '@nrwl/cypress/plugin';33import { addMatchImageSnapshotPlugin } from '
Cypress is a renowned Javascript-based open-source, easy-to-use end-to-end testing framework primarily used for testing web applications. Cypress is a relatively new player in the automation testing space and has been gaining much traction lately, as evidenced by the number of Forks (2.7K) and Stars (42.1K) for the project. LambdaTest’s Cypress Tutorial covers step-by-step guides that will help you learn from the basics till you run automation tests on LambdaTest.
You can elevate your expertise with end-to-end testing using the Cypress automation framework and stay one step ahead in your career by earning a Cypress certification. Check out our Cypress 101 Certification.
Watch this 3 hours of complete tutorial to learn the basics of Cypress and various Cypress commands with the Cypress testing at LambdaTest.
Get 100 minutes of automation test minutes FREE!!