diff --git a/README.md b/README.md index 2f3e177..44cd7d1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ #Bemy [![Build Status][travis-image]][travis-url] -Bemy is a CLI helper for auto-generation BEM structure. Especialy usefull with webstorm (external tools). It allows to generate folder and file structure using deps.js file with one command (or hotkey). For all file types taking templates with including BEM names into placeholders. You can tune it and you can add your own file types. +Bemy is a CLI helper for auto-generation and renaming BEM structure. Especialy usefull with webstorm (external tools). It allows to generate folder and file structure using deps.js file with one command (or hotkey). For all file types taking templates with including BEM names into placeholders. You can tune it and you can add your own file types. +Bemy can run three usable tasks: 'create', 'rename' and 'auto'; ##Install ```bash @@ -8,67 +9,86 @@ npm i -g bemy ``` ##Usage ```bash -bemy [options] +bemy -t [task] -f [path] [options] ``` -###CLI options + +When you call bemy on files it is like you call bemy on the folder contains this file. So this two variants are equal: `-f ~/testBlock/__elem` and `-f ~/testBlock/__elem/testBlock__elem.bh.js`. + +###Shared CLI options `-t [task name]` — name of the called task. default: 'auto'; `-f [path]` — path to BEM node (folder or file); -`-p [file list]` — file types list for task of `creation`. Available following file types: `-p "css js deps priv bh"`. Also you can use short notation `p c j b d`. You can add you own file types and shortcuts at config.json. -`-g` — adding into git for created files (calls `git add` for each file); -`-c [config path]` — path of your own config json file. By default using config.json from bemy directory; -`-o` — to open the file after creation. This command configured in config.json in section `editor-open-command`. Default value is `wstorm {{file-path}}:{{line-number}}`. See more details at below in section `Configuring`. +`-g` — adding into git for created or renamed files (calls `git add` for each file); +`-c [config path]` — path of your own config json file. By default used config.json from bemy directory; ###The task of creation Takes arguments with file types and creates files using templates. -####CLI of task of creation: -`bemy -t create -f [file path] -p "[file types]"`, where `file path` — is a path to BEM node (folder or file), `file types` — list of needed files separated by space. +####CLI for task of creation: +`bemy -t create -f [path] -p "[file types]"`, where `file path` — is a path to BEM node (folder or file), `file types` — list of needed files separated by space. Example: Command: `bemy -t create -f ~/testBlock/__elem -p "css js"` Result: In the folder `~/testBlock/__elem` was added two files: `testBlock__elem.js` and `testBlock__elem.css`. -When you use bemy on files supposed to use bemy on the folder containg this file. So this two variants are equal: `-f ~/testBlock/__elem` and `-f ~/testBlock/__elem/testBlock__elem.bh.js`. +####Options +`-o` — to open the file after creation. This command configured in config.json in section `editor-open-command`. Default value is `wstorm {{file-path}}:{{line-number}}`. See more details at below in section `Configuring`.; +`-p [file list]` — file types list. Available following file types: `-p "css js deps priv bh"`. Also you can use short notation `p c j b d`. You can add you own file types and shortcuts at config.json. -####Placeholders in templates -There are following placeholders: `{{blockName}}`, `{{elemName}}`, `{{modName}}`, `{{modVal}}` and `{{cursor}}`. When files creating this entries will be replaced with relevant part of BEM node name. And `{{cursor}}` will be deleted and used for setting cursor line number (see more at Configuring section). -For example, default css template contain: -``` -.{{blockName}}{{elemName}}{{modName}}{{modVal}} -{ - {{cursor}} -} -``` -, so resulted file will contain: -```css -.testBlock__elem { -/* curor will be here, if you use right configured -o key */ -} -``` - -An example of using bemy with `external tools` of webstorm: +An example of using bemy with `external tools` of webstorm for the task of creation: ![](https://cloud.githubusercontent.com/assets/769992/6725632/0232f4ee-ce2e-11e4-942e-7845381663ed.png) Don't forget to configure hotkey for task running (e.g. `ctrl + c`) at `keymap` section. +###Task of renaming +Recursively renames current node and its children. `-d` turn on deep mode and the contents of the files will also be renamed. Deep rename used `rename` param from config file so you should to configure it for you own file types. `rename` renames only described files and valid directories (e.g. mod folder in mod folder isn't valid). + +####CLI for task of renaming: +`bemy -t rename -f [path] -p [new name] -d` + +####Options +`-d` — turn on deep mode with renaming of files content; +`-p` — new BEM node name; + +An example of using bemy with `external tools` of webstorm for the task of renaming: +![](https://cloud.githubusercontent.com/assets/769992/6766361/e3006d96-d025-11e4-948e-1f11a663f2ea.png) + ###Autotask Call default action depend on BEM node. Currently work following variants: 1. If target is deps-file, creates described elems\mods\elemMods folder structure. And depend on options of config.json also creates elems\mods\elemMods files. By default it's css files. Se `Configuring` section for more details. -2. Otherwise call create task with default options (equal `-t create -f [file path] -p "css"``). Default file types for autotask configurable at config.json. +2. Otherwise call create task with default options (equal `-t create -f [path] -p "css"`). Default file types for autotask configurable at config.json. -####CLI of autotask: -`bemy -f [file path]`, where `file path` — it's a path to BEM node. +####CLI for autotask +`bemy -f [path]` -An example of using bemy with `external tools` of webstorm: +An example of using bemy with `external tools` of webstorm for the autotask: ![](https://cloud.githubusercontent.com/assets/769992/6725778/23a5188a-ce30-11e4-828d-0d590fb26e08.png) Don't forget to configure hotkey for task running (e.g. `ctrl + a`) at `keymap` section. ###Confgiring `config.json` is in bemy root folder. + ####Sections -`suffixes` — a list of shotrcuts and relevant file extensions. Shotrcuts using in `-p` key. -`file-templates` — a list of shortcuts with relevant pathes to templates. -`deps_task` – options for autotask when it called on deps file. `files` – list of files to be created in addition to folders. +#####`file-types` +Description of the used file types. +`suffix` used by 'create' when forming file and by 'rename' for files validation (`rename` renames only described files); +`shortcuts` — list of short that you can use after `-p` key in Task of creation; +`rename` – mask for deep renaming. {{bemNode}} will be replaced to new node name. You can also use an array of masks; +`template` — path to template of file type. Teamplate used when any files are created. +There are following placeholders: `{{blockName}}`, `{{elemName}}`, `{{modName}}`, `{{modVal}}` and `{{cursor}}`. When files are created this entries will be replaced with relevant part of BEM node name. And `{{cursor}}` will be deleted and used for setting cursor line number (see more at Configuring section). +For example, default css template contain: +``` +.{{blockName}}{{elemName}}{{modName}}{{modVal}} +{ + {{cursor}} +} +``` +, so resulted file will contain: +```css +.testBlock__elem { +/* curor will be here, if you use right configured -o key */ +} +``` +`deps_task` – options for autotask when it called on deps file. `files` – list of file types to be created in addition to folders. `editor-open-command` — command to be called after creating the file. There are two placeholders: 1) {{file-path}} to be replaced with relevant file path. 2) {{line-number}} will be taken from {{cursor}} position of relevant template. Default command is `wstorm {{file-path}}:{{line-number}}`, so if you use webstorm you need to create CLI launcher at webstorm with same name (Tools / Create Command-line Lanucher). If u use old wersion of webstorm you can try to use `/Applications/WebStorm.app/Contents/MacOS/webide` for `editor-open-command`. -`bem` — your BEM options. If you using own `separators` you must set right `allowed-name-symbols-regexp`. +`bem` — your BEM options. If you use own `separators` you must set right `allowed-name-symbols-regexp`. [travis-url]: http://travis-ci.org/f0rmat1k/bemy [travis-image]: http://img.shields.io/travis/f0rmat1k/bemy.svg?branch=master&style=flat \ No newline at end of file diff --git a/bem-info.js b/bem-info.js index 0b8167d..1ea5aa8 100644 --- a/bem-info.js +++ b/bem-info.js @@ -1,37 +1,37 @@ var fs = require('fs'); var path = require('path'); +//todo сепараторы кастомной длины +module.exports = function(config){ + return function(trgPath, isFile){ + var info = {}, + separators = config.bem.separators, + allowedSymbols = config.bem['allowed-name-symbols-regexp']; -module.exports = function(options){ - var info = {}, - trgPath = options.trgPath, - isFile = options.isFile, - separators = (options.bem && options.bem.separators) || { elem: '__', mod: '_', modVal: '_'}, - allowedSymbols = options.bem && options.bem['allowed-name-symbols-regexp'] || '[-a-z0-9]'; + if (!trgPath) throw new Error('Required path'); - if (!trgPath) throw new Error('Required path'); + try { info.stat = fs.statSync(trgPath); } catch (e) { } - try { info.stat = fs.statSync(trgPath); } catch (e) { } + info.isFile = info.stat && info.stat.isFile() || isFile || false; + info.isDir = info.stat && info.stat.isDirectory() || !info.isFile; + info.type = getTargetType(info.isFile, trgPath, config); + info.dirPath = getDirPath(trgPath, info.isFile); + info.dirName = getDirNameByPath(info.dirPath); + info.fileName = getFileNameByPath(trgPath, info.isFile); - info.isFile = info.stat && info.stat.isFile() || isFile || false; - info.isDir = info.stat && info.stat.isDirectory() || !info.isFile; - info.type = getTargetType(info.isFile, trgPath, options.bem); - info.dirPath = getDirPath(trgPath, info.isFile); - info.dirName = getDirNameByPath(info.dirPath); - info.fileName = getFileNameByPath(trgPath, info.isFile); + info.isBlock = isBlock(info.dirName, separators, config.bem); + info.isElem = isElem(info.dirName, separators, allowedSymbols); + info.isMod = isMod(info.dirName, separators, allowedSymbols); - info.isBlock = isBlock(info.dirName, separators, options.bem); - info.isElem = isElem(info.dirName, separators, allowedSymbols); - info.isMod = isMod(info.dirName, separators, allowedSymbols); + info.nodeType = info.isBlock ? 'block' : info.isElem ? 'elem' : info.isMod ? 'mod' : undefined; - info.nodeType = info.isBlock ? 'block' : info.isElem ? 'elem' : info.isMod ? 'mod' : undefined; + info.blockName = getBlockName(trgPath, info.isBlock, info.isFile, config.bem, allowedSymbols); + info.elemName = getElemName(info.isElem, info.isMod, info.dirName, info.dirPath, separators); + info.modName = getModName(info.isMod, info.dirName); + info.bemName = getBemName(info.blockName, info.elemName, info.modName, config.bem); + info.ownInfo = getOwnInfo(info, separators, allowedSymbols); - info.blockName = getBlockName(trgPath, info.isBlock, info.isFile, options.bem, allowedSymbols); - info.elemName = getElemName(info.isElem, info.isMod, info.dirName, trgPath, options.bem); - info.modName = getModName(info.isMod, info.dirName); - info.bemName = getBemName(info.blockName, info.elemName, info.modName, options.bem); - info.ownInfo = getOwnInfo(info, separators, allowedSymbols); - - return info; + return info; + }; }; function getOwnInfo(info, separators, allowedSymbols){ @@ -60,8 +60,8 @@ function getFileNameByPath(trgPath, isFile){ return isFile ? path.basename(trgPath) : ''; } -function getTargetType(isFile, trgPath, bem){ - return isFile ? detectFileType(trgPath) : detectDirType(trgPath, bem); +function getTargetType(isFile, trgPath, config){ + return isFile ? detectFileType(trgPath, config) : detectDirType(trgPath, config.bem.separators); } function getDirPath(trgPath, isFile){ @@ -109,12 +109,12 @@ function getBlockName(trgPath, isBlock, isFile, bem, allowedSymbols){ return baseName; } -function getElemName(isElem, isMod, dirName, trgPath, bem){ +function getElemName(isElem, isMod, dirName, trgPath, separators){ if (isElem) return dirName; if (isMod) { var parentDir = path.basename(path.resolve(trgPath, '../')), - elemSeparator = bem && bem.separators.elem || '__', + elemSeparator = separators.elem, elemRegExp = new RegExp('^(' + elemSeparator + ')', 'ig'), parentIsElem = elemRegExp.test(parentDir); @@ -128,22 +128,21 @@ function getModName(isMod, dirName){ return isMod ? dirName : ''; } -//todo -function detectFileType(targetFile) { +function detectFileType(targetFile, config) { var filename = path.basename(targetFile); + var fileTypes = Object.keys(config['file-types']); - if (/\.deps\./.test(filename)) return 'deps'; - if (/\.css$/.test(filename)) return 'css'; - if (/\.priv\.js$/.test(filename)) return 'priv'; - if (/\.bh\.js$/.test(filename)) return 'bh'; - if (/\.js$/.test(filename)) return 'js'; + for (var i = 0; i < fileTypes.length; i++) { + var regExp = new RegExp(escapeRegExp(config['file-types'][fileTypes[i]].suffix) + '$'); + if (regExp.test(filename)) return fileTypes[i]; + } } -function detectDirType(targetDir, bem){ +function detectDirType(targetDir, separators){ var dirName = path.basename(targetDir), dirType, - elemRegExp = new RegExp(bem && bem.separators.elem || '__'), - modRegExp = new RegExp(bem && bem.separators.mod || '_'); + elemRegExp = new RegExp(separators.elem), + modRegExp = new RegExp(separators.mod); if (elemRegExp.test(dirName)) { dirType = 'elemDir'; @@ -153,3 +152,7 @@ function detectDirType(targetDir, bem){ return dirType; } + +function escapeRegExp(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); +} \ No newline at end of file diff --git a/bemy.js b/bemy.js index 4e3a5ec..5b179b8 100644 --- a/bemy.js +++ b/bemy.js @@ -12,53 +12,46 @@ var options = minimist(process.argv.slice(2)), trgPath = options.f, configPath = options.c ? path.resolve(options.c) : path.join(__dirname, 'config.json'), prompt = options.p ? options.p.toString().split(/\s/) : '', - bemInfo = require('./bem-info.js'), config = JSON.parse(fs.readFileSync(configPath, 'utf-8')), - ownConfig = options.c; + isOwnConfig = options.c, + bemInfo = require('./bem-info.js')(config); var bem = config.bem, - BEM_INFO = bemInfo({ - trgPath: trgPath, - bem: bem - }), - SUFFIXES = config.suffixes, - FILE_TEMPLATES = config['file-templates'], + SHORTCUTS = function(){ + var fileTypes = config['file-types'], + shortcuts = {}; + + Object.keys(fileTypes).forEach(function(fileType){ + try { + var cuts = fileTypes[fileType].shortcuts; + if (!Array.isArray(cuts)) cuts = [ cuts ]; + + cuts.forEach(function(cut){ + shortcuts[cut] = fileTypes[fileType]; + }); + } catch (e) {} + }); + + return shortcuts; + }(), DEFAULT_ACTIONS = { blockDir: startCreating.bind(this, ['css']), deps: createStructureByDeps, elemDir: startCreating.bind(this, ['css']), modDir: startCreating.bind(this, ['css']) }, + BEM_INFO = bemInfo(trgPath), tasks = { auto: DEFAULT_ACTIONS[BEM_INFO.type], create: startCreating.bind(this, prompt), rename: rename.bind(this, trgPath) - }, - FILE_TYPES = [], - EXTENSIONS = function(){ - var result = {}; - - Object.keys(SUFFIXES).forEach(function(shortcut){ - FILE_TYPES.push(SUFFIXES[shortcut]); - - var shortcuts = shortcut.split(/\s/ig); - if (shortcuts.length > 1) { - shortcuts.forEach(function(current_shortcut){ - result[current_shortcut] = SUFFIXES[shortcut]; - }); - } else { - result[shortcut] = SUFFIXES[shortcut]; - } - }); - - return result; - }(); + }; var task = options.t || 'auto'; tasks[task](); function rename(nodePath, originNode){ - var nodeInfo = bemInfo({ trgPath: nodePath }); + var nodeInfo = bemInfo(nodePath); if (nodeInfo.isFile && !originNode) { rename(path.dirname(nodePath)); @@ -66,7 +59,7 @@ function rename(nodePath, originNode){ } originNode = originNode || { - originalInfo: bemInfo({ trgPath: nodePath }), + originalInfo: bemInfo(nodePath), path: nodePath, type: nodeInfo.nodeType, newName: prompt[0], @@ -83,27 +76,46 @@ function rename(nodePath, originNode){ fs.renameSync(nodePath, newDirPath); - if (options.g) gitAddTrg(nodeParent, newDirPath); - var nodes = getValidDirNodes(nodePath, newDirPath, originNode.originalInfo); nodes.forEach(function(node){ var oldChildPath = path.resolve(nodePath, node), currentChildPath = path.resolve(newDirPath, node), - childInfo = bemInfo({ - trgPath: oldChildPath, - isFile: bemInfo({ trgPath: currentChildPath }).isFile - }), + childInfo = bemInfo(oldChildPath, bemInfo(currentChildPath).isFile), newChildPath = path.resolve(newDirPath, node.replace(originNode.name, originNode.newName)); if (childInfo.isFile) { fs.renameSync(currentChildPath, newChildPath); + if (options.d) { + var file = fs.readFileSync(newChildPath, 'utf-8'), + newFileInfo = bemInfo(newChildPath), + newName = newFileInfo.bemName, + oldName = newName.replace(prompt[0], originNode.name), + renameRule = config['file-types'][newFileInfo.type].rename, + oldString = oldName, + newString = newName; + + if (renameRule) { + if (!Array.isArray(renameRule)) { + renameRule = [renameRule]; + } + + renameRule.forEach(function(rule){ + oldString = escapeRegExp(rule.replace(/{{bemNode}}/g, oldName)); + newString = rule.replace(/{{bemNode}}/g, newName); + + file = file.replace(new RegExp(oldString, 'g'), newString); + }); + } - if (options.g) gitAddTrg(nodeParent, newChildPath); + fs.writeFileSync(newChildPath, file); + } } else { rename(newChildPath, originNode); } }); + + if (options.g) gitAddTrg(nodeParent, newDirPath); } function getValidDirNodes(oldNodePath, newNodePath, originalInfo){ @@ -113,22 +125,22 @@ function getValidDirNodes(oldNodePath, newNodePath, originalInfo){ } function isValidNode(child, oldParentPath, newParentPath, originalInfo){ - var parentInfo = bemInfo({ trgPath: oldParentPath }), + var parentInfo = bemInfo(oldParentPath), childPath = path.resolve(oldParentPath, child), newChildPath = path.resolve(newParentPath, child), isValid; - var childInfo = bemInfo({ - trgPath: childPath, - isFile: bemInfo({ trgPath: newChildPath }).isFile - }); + var childInfo = bemInfo(childPath, bemInfo(newChildPath).isFile); if (childInfo.isFile) { if (!childInfo.type) { isValid = false; } else { - FILE_TYPES.forEach(function(fileType){ - if (child.indexOf(fileType) !== -1) { + var fileTypes = config['file-types']; + Object.keys(fileTypes).forEach(function(fileType){ + var suffix = fileTypes[fileType].suffix; + + if (child.indexOf(suffix) !== -1) { if (childInfo.ownInfo.blockName !== originalInfo.blockName) { isValid = false; } else if (parentInfo.isElem && childInfo.ownInfo.elemName !== parentInfo.elemName) { @@ -162,14 +174,13 @@ function startCreating(fileTypes){ function createFileFromTemplate(fileType, trg, modVal){ trg = trg || trgPath; - var tmpPath = FILE_TEMPLATES[fileType]; - - if (!tmpPath) { - console.error('Unknown file type'); - return; + var tmpPath; + try { tmpPath = SHORTCUTS[fileType].template; } catch (e) { + tmpPath = 'tmp/empty.tmp' } - if (!ownConfig) { + //todo resolve + if (!isOwnConfig) { tmpPath = path.join(__dirname, tmpPath); } @@ -183,10 +194,7 @@ function createFileFromTemplate(fileType, trg, modVal){ } function insertName(file, trg, modVal){ - var info = bemInfo({ - trgPath: trg, - bem: bem - }); + var info = bemInfo(trg); return file .replace(/{{blockName}}/g, info.blockName) @@ -209,14 +217,14 @@ function createNode(nodeObj){ var blockDir = path.dirname(trgPath), nodePath, fileTypes = config.deps_task ? config.deps_task.files : [], - modSeparator = bem.separators.mod || '_', - modValSeparator = bem.separators.modVal || '_', + modSeparator = bem.separators.mod, + modValSeparator = bem.separators.modVal, modVal = nodeObj.modVal ? modValSeparator + nodeObj.modVal : ''; if (nodeObj.elem) { if (BEM_INFO.isElem) return; - var elemSeparator = bem.separators.elem || '__'; + var elemSeparator = bem.separators.elem; nodePath = path.join(blockDir, elemSeparator + nodeObj.elem); @@ -267,14 +275,11 @@ function createFile(file, type, trg, modVal, cursorPos){ modVal = modVal || ''; - var info = bemInfo({ - trgPath: trg, - bem: bem - }); + var info = bemInfo(trg); if (info.isFile) trg = path.dirname(trg); - var p = path.join(trg, info.bemName + modVal + EXTENSIONS[type]); + var p = path.join(trg, info.bemName + modVal + SHORTCUTS[type].suffix); if (!fs.existsSync(p)) { fs.writeFileSync(p, file); @@ -318,9 +323,9 @@ function parseString(dep) { var obj = {}, allowedSymbols = bem['allowed-name-symbols-regexp'], blockRegExp = new RegExp(allowedSymbols + '+', 'i'), - elemSeparator = bem && bem.separators.elem || '__', - modSeparator = bem && bem.separators.mod || '_', - modValSeparator = bem && bem.separators.modVal || '_'; + elemSeparator = bem.separators.elem, + modSeparator = bem.separators.mod, + modValSeparator = bem.separators.modVal; var block = (dep.match(blockRegExp) || [])[0], elem = (dep.match(new RegExp('^' + allowedSymbols + '+' + elemSeparator + '(' + allowedSymbols + '+)', 'i')) || [])[1], @@ -334,3 +339,7 @@ function parseString(dep) { return obj; } + +function escapeRegExp(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); +} diff --git a/config.json b/config.json index 832659b..b41a2a0 100644 --- a/config.json +++ b/config.json @@ -1,25 +1,34 @@ { - "suffixes": { - "css c": ".css", - "js j": ".js", - "deps d": ".deps.js", - "bh b": ".bh.js", - "priv p": ".priv.js" - }, - "file-templates": { - "js": "tmp/js-template.js", - "j": "tmp/js-template.js", - "css": "tmp/css-template.css", - "c": "tmp/css-template.css", - "bh": "tmp/bh-template.js", - "b": "tmp/bh-template.js", - "deps": "tmp/deps-template.js", - "d": "tmp/deps-template.js", - "priv": "tmp/priv-template.js", - "p": "tmp/priv-template.js" - }, - "deps_task": { - "files": [ "css" ] + "file-types": { + "css": { + "suffix": ".css", + "shortcuts": [ "c", "css" ], + "rename": ".{{bemNode}}", + "template": "tmp/css-template.css" + }, + "deps": { + "suffix": ".deps.js", + "shortcuts": [ "d", "deps" ], + "template": "tmp/deps-template.js" + }, + "bh": { + "suffix": ".bh.js", + "shortcuts": [ "b", "bh" ], + "rename": "match('{{bemNode}}", + "template": "tmp/bh-template.js" + }, + "priv": { + "suffix": ".priv.js", + "shortcuts": [ "p", "priv" ], + "rename": [ "declare('{{bemNode}}", "block: '{{bemNode}}'", "block:'{{bemNode}}'" ], + "template": "tmp/priv-template.js" + }, + "js": { + "suffix": ".js", + "shortcuts": [ "j", "js" ], + "rename": "decl('{{bemNode}}", + "template": "tmp/js-template.js" + } }, "editor-open-command": "wstorm {{file-path}}:{{line-number}}", "bem": { @@ -29,5 +38,8 @@ "modVal": "_" }, "allowed-name-symbols-regexp": "[-a-z0-9]" + }, + "deps_task": { + "files": [ "css" ] } } diff --git a/package.json b/package.json index 2fb0dd3..d9ce7a4 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "type": "git", "url": "https://github.com/f0rmat1k/bemy.git" }, - "version": "1.5.2", + "version": "2.0.0", "keywords": [ "bem", "BEM Tools" diff --git a/test/bem-info.js b/test/bem-info.js index 2f64a19..412250a 100644 --- a/test/bem-info.js +++ b/test/bem-info.js @@ -4,14 +4,13 @@ require('should'); -var bemInfo = require('../bem-info.js'); +var fs = require('fs'), + config = JSON.parse(fs.readFileSync('test/config.json', 'utf-8')), + bemInfo = require('../bem-info.js')(config); describe('bemInfo', function () { it('should be correct processing with "/" in the end of block path', function () { - bemInfo({ - trgPath: 'somePath/someBlock/', - isFile: false - }).should.be.eql({ + bemInfo('somePath/someBlock/', false).should.be.eql({ isFile: false, isDir: true, type: 'blockDir', @@ -31,10 +30,7 @@ describe('bemInfo', function () { }); it('should be correct processing without "/" in the end of block path', function () { - bemInfo({ - trgPath: 'somePath/someBlock/', - isFile: false - }).should.be.eql({ + bemInfo('somePath/someBlock/', false).should.be.eql({ isFile: false, isDir: true, type: 'blockDir', @@ -54,10 +50,7 @@ describe('bemInfo', function () { }); it('should be correct processing with "/" in the end of elem path', function () { - bemInfo({ - trgPath: 'somePath/someBlock/__someElem/', - isFile: false - }).should.be.eql({ + bemInfo('somePath/someBlock/__someElem/', false).should.be.eql({ isFile: false, isDir: true, type: 'elemDir', @@ -77,10 +70,7 @@ describe('bemInfo', function () { }); it('should be correct processing without "/" in the end of elem path', function () { - bemInfo({ - trgPath: 'somePath/someBlock/__someElem', - isFile: false - }).should.be.eql({ + bemInfo('somePath/someBlock/__someElem', false).should.be.eql({ isFile: false, isDir: true, type: 'elemDir', @@ -100,10 +90,7 @@ describe('bemInfo', function () { }); it('should be correct processing with "/" in the end of mod path', function () { - bemInfo({ - trgPath: 'somePath/someBlock/__someElem/_someMod/', - isFile: false - }).should.be.eql({ + bemInfo('somePath/someBlock/__someElem/_someMod/', false).should.be.eql({ isFile: false, isDir: true, type: 'modDir', @@ -126,11 +113,32 @@ describe('bemInfo', function () { ); }); + it('should be correct working when called on elem mod file', function () { + bemInfo('somePath/someBlock/__someElem/_someMod/someBlock__someElem_someMod.css', true).should.be.eql({ + isFile: true, + isDir: false, + type: 'css', + dirPath: 'somePath/someBlock/__someElem/_someMod', + dirName: '_someMod', + isBlock: false, + isElem: false, + isMod: true, + fileName: 'someBlock__someElem_someMod.css', + nodeType: 'mod', + ownInfo: { + blockName: 'someBlock', + elemName: '__someElem', + modName: '_someMod' + }, + blockName: 'someBlock', + elemName: '__someElem', + modName: '_someMod', + bemName: 'someBlock__someElem_someMod' } + ); + }); + it('should be correct processing without "/" in the end of mod path', function () { - bemInfo({ - trgPath: 'somePath/someBlock/__someElem/_someMod', - isFile: false - }).should.be.eql({ + bemInfo('somePath/someBlock/__someElem/_someMod', false).should.be.eql({ isFile: false, isDir: true, type: 'modDir', @@ -154,10 +162,7 @@ describe('bemInfo', function () { }); it('correct detection for block deps file', function () { - bemInfo({ - trgPath: 'somePath/someBlock/someBlock.deps.js', - isFile: true - }).should.be.eql({ + bemInfo('somePath/someBlock/someBlock.deps.js', true).should.be.eql({ isFile: true, isDir: false, type: 'deps', @@ -177,10 +182,7 @@ describe('bemInfo', function () { }); it('correct detection for elem deps file', function () { - bemInfo({ - trgPath: 'somePath/someBlock/__someElem/someBlock__someElem.deps.js', - isFile: true - }).should.be.eql({ + bemInfo('somePath/someBlock/__someElem/someBlock__someElem.deps.js', true).should.be.eql({ isFile: true, isDir: false, type: 'deps', diff --git a/test/config.json b/test/config.json index 387e621..96c20e2 100644 --- a/test/config.json +++ b/test/config.json @@ -1,27 +1,34 @@ { - "suffixes": { - "css": ".css", - "c": ".css", - "js": ".js", - "j": ".js", - "deps": ".deps.js", - "d": ".deps.js", - "bh": ".bh.js", - "b": ".bh.js", - "priv": ".priv.js", - "p": ".priv.js" - }, - "file-templates": { - "js": "tmp/js-template.js", - "j": "tmp/js-template.js", - "css": "tmp/css-template.css", - "c": "tmp/css-template.css", - "bh": "tmp/bh-template.js", - "b": "tmp/bh-template.js", - "deps": "test/deps-template.js", - "d": "test/deps-template.js", - "priv": "tmp/priv-template.js", - "p": "tmp/priv-template.js" + "file-types": { + "css": { + "suffix": ".css", + "shortcuts": [ "c", "css" ], + "rename": ".{{bemNode}}", + "template": "tmp/css-template.css" + }, + "deps": { + "suffix": ".deps.js", + "shortcuts": [ "d", "deps" ], + "template": "test/deps-template.js" + }, + "bh": { + "suffix": ".bh.js", + "shortcuts": [ "b", "bh" ], + "rename": "match('{{bemNode}}", + "template": "tmp/bh-template.js" + }, + "priv": { + "suffix": ".priv.js", + "shortcuts": [ "p", "priv" ], + "rename": [ "declare('{{bemNode}}", "block: '{{bemNode}}'", "block:'{{bemNode}}'" ], + "template": "tmp/priv-template.js" + }, + "js": { + "suffix": ".js", + "shortcuts": [ "j", "js" ], + "rename": "decl('{{bemNode}}", + "template": "tmp/js-template.js" + } }, "deps_task": { "files": [ "css" ] diff --git a/test/config_custon-separators.json b/test/config_custon-separators.json index 5061a07..3a5b3a2 100644 --- a/test/config_custon-separators.json +++ b/test/config_custon-separators.json @@ -1,27 +1,34 @@ { - "suffixes": { - "css": ".css", - "c": ".css", - "js": ".js", - "j": ".js", - "deps": ".deps.js", - "d": ".deps.js", - "bh": ".bh.js", - "b": ".bh.js", - "priv": ".priv.js", - "p": ".priv.js" - }, - "file-templates": { - "js": "tmp/js-template.js", - "j": "tmp/js-template.js", - "css": "tmp/css-template.css", - "c": "tmp/css-template.css", - "bh": "tmp/bh-template.js", - "b": "tmp/bh-template.js", - "deps": "test/deps-template.js", - "d": "test/deps-template.js", - "priv": "tmp/priv-template.js", - "p": "tmp/priv-template.js" + "file-types": { + "css": { + "suffix": ".css", + "shortcuts": [ "c", "css" ], + "rename": ".{{bemNode}}", + "template": "tmp/css-template.css" + }, + "deps": { + "suffix": ".deps.js", + "shortcuts": [ "d", "deps" ], + "template": "test/deps-template.js" + }, + "bh": { + "suffix": ".bh.js", + "shortcuts": [ "b", "bh" ], + "rename": "match('{{bemNode}}", + "template": "tmp/bh-template.js" + }, + "priv": { + "suffix": ".priv.js", + "shortcuts": [ "p", "priv" ], + "rename": [ "declare('{{bemNode}}", "block: '{{bemNode}}'", "block:'{{bemNode}}'" ], + "template": "tmp/priv-template.js" + }, + "js": { + "suffix": ".js", + "shortcuts": [ "j", "js" ], + "rename": "decl('{{bemNode}}", + "template": "tmp/js-template.js" + } }, "deps_task": { "files": [ "css" ] @@ -29,9 +36,9 @@ "editor-open-command": "wstorm {{file-path}}:{{line-number}}", "bem": { "separators": { - "elem": "--", - "mod": "-", - "modVal": "-" + "elem": "---", + "mod": "--", + "modVal": "--" }, "allowed-name-symbols-regexp": "[a-z0-9]" } diff --git a/test/rename.js b/test/rename.js index 5b48707..00b7eec 100644 --- a/test/rename.js +++ b/test/rename.js @@ -6,122 +6,168 @@ var sh = require('execSync'); var exec = sh.run; var fs = require('fs-extra'); -createTestBlock(); - describe('Renaming', function(){ - it('Renaming mod of block', function(){ - exec('node bemy.js -t rename -f test/rename/_mod -p "foo"'); + describe('#Simple renaming', function(){ + before(createTestBlock); - fs.existsSync('test/rename/_foo/').should.be.eql(true); - fs.existsSync('test/rename/_foo/rename_foo.css').should.be.eql(true); - fs.existsSync('test/rename/_foo/rename_foo_val.js').should.be.eql(true); - }); + after(function(){ + fs.removeSync('test/slider/'); + }); - it('Renaming mods of block when called by mod file', function(){ - exec('node bemy.js -t rename -f test/rename/_foo/rename_foo_val.js -p "bar"'); + it('Renaming mod of block', function(){ + exec('node bemy.js -t rename -f test/rename/_mod -p "foo"'); - fs.existsSync('test/rename/_bar/').should.be.eql(true); - fs.existsSync('test/rename/_bar/rename_bar.css').should.be.eql(true); - fs.existsSync('test/rename/_bar/rename_bar_val.js').should.be.eql(true); - }); + fs.existsSync('test/rename/_foo/').should.be.eql(true); + fs.existsSync('test/rename/_foo/rename_foo.css').should.be.eql(true); + fs.existsSync('test/rename/_foo/rename_foo_val.js').should.be.eql(true); + }); - it('Renaming elem', function(){ - exec('node bemy.js -t rename -f test/rename/__elem -p "text"'); + it('Renaming mods of block when called by mod file', function(){ + exec('node bemy.js -t rename -f test/rename/_foo/rename_foo_val.js -p "bar"'); - fs.existsSync('test/rename/__text/').should.be.eql(true); - fs.existsSync('test/rename/__text/rename__text.css').should.be.eql(true); - fs.existsSync('test/rename/__text/rename__text.deps.js').should.be.eql(true); + fs.existsSync('test/rename/_bar/').should.be.eql(true); + fs.existsSync('test/rename/_bar/rename_bar.css').should.be.eql(true); + fs.existsSync('test/rename/_bar/rename_bar_val.js').should.be.eql(true); + }); - fs.existsSync('test/rename/__text/_mod/rename__text_mod.css').should.be.eql(true); - fs.existsSync('test/rename/__text/_mod/rename__text_mod_val.js').should.be.eql(true); - }); + it('Renaming elem', function(){ + exec('node bemy.js -t rename -f test/rename/__elem -p "text"'); - it('Renaming elem when called by elem file', function(){ - exec('node bemy.js -t rename -f test/rename/__text/rename__text.deps.js -p "kontur"'); + fs.existsSync('test/rename/__text/').should.be.eql(true); + fs.existsSync('test/rename/__text/rename__text.css').should.be.eql(true); + fs.existsSync('test/rename/__text/rename__text.deps.js').should.be.eql(true); - fs.existsSync('test/rename/__kontur/').should.be.eql(true); - fs.existsSync('test/rename/__kontur/rename__kontur.css').should.be.eql(true); - fs.existsSync('test/rename/__kontur/rename__kontur.deps.js').should.be.eql(true); + fs.existsSync('test/rename/__text/_mod/rename__text_mod.css').should.be.eql(true); + fs.existsSync('test/rename/__text/_mod/rename__text_mod_val.js').should.be.eql(true); + }); - fs.existsSync('test/rename/__kontur/_mod/rename__kontur_mod.css').should.be.eql(true); - fs.existsSync('test/rename/__kontur/_mod/rename__kontur_mod_val.js').should.be.eql(true); - }); + it('Renaming elem when called by elem file', function(){ + exec('node bemy.js -t rename -f test/rename/__text/rename__text.deps.js -p "kontur"'); - it('Renaming mod of elem', function(){ - exec('node bemy.js -t rename -f test/rename/__kontur/_mod/ -p "foo"'); + fs.existsSync('test/rename/__kontur/').should.be.eql(true); + fs.existsSync('test/rename/__kontur/rename__kontur.css').should.be.eql(true); + fs.existsSync('test/rename/__kontur/rename__kontur.deps.js').should.be.eql(true); - fs.existsSync('test/rename/__kontur/_foo').should.be.eql(true); - fs.existsSync('test/rename/__kontur/_foo/rename__kontur_foo.css').should.be.eql(true); - fs.existsSync('test/rename/__kontur/_foo/rename__kontur_foo_val.js').should.be.eql(true); - }); + fs.existsSync('test/rename/__kontur/_mod/rename__kontur_mod.css').should.be.eql(true); + fs.existsSync('test/rename/__kontur/_mod/rename__kontur_mod_val.js').should.be.eql(true); + }); - it('Renaming mod of elem when called by mod file', function(){ - exec('node bemy.js -t rename -f test/rename/__kontur/_foo/rename__kontur_foo_val.js -p "bar"'); + it('Renaming mod of elem', function(){ + exec('node bemy.js -t rename -f test/rename/__kontur/_mod/ -p "foo"'); - fs.existsSync('test/rename/__kontur/_bar').should.be.eql(true); - fs.existsSync('test/rename/__kontur/_bar/rename__kontur_bar.css').should.be.eql(true); - fs.existsSync('test/rename/__kontur/_bar/rename__kontur_bar_val.js').should.be.eql(true); - }); + fs.existsSync('test/rename/__kontur/_foo').should.be.eql(true); + fs.existsSync('test/rename/__kontur/_foo/rename__kontur_foo.css').should.be.eql(true); + fs.existsSync('test/rename/__kontur/_foo/rename__kontur_foo_val.js').should.be.eql(true); + }); - it('Block renaming', function(){ - exec('node bemy.js -t rename -f test/rename -p "megablock"'); + it('Renaming mod of elem when called by mod file', function(){ + exec('node bemy.js -t rename -f test/rename/__kontur/_foo/rename__kontur_foo_val.js -p "bar"'); - fs.existsSync('test/megablock').should.be.eql(true); - fs.existsSync('test/megablock/megablock.css').should.be.eql(true); - fs.existsSync('test/megablock/megablock.priv.js').should.be.eql(true); + fs.existsSync('test/rename/__kontur/_bar').should.be.eql(true); + fs.existsSync('test/rename/__kontur/_bar/rename__kontur_bar.css').should.be.eql(true); + fs.existsSync('test/rename/__kontur/_bar/rename__kontur_bar_val.js').should.be.eql(true); + }); - fs.existsSync('test/megablock/_bar/megablock_bar.css').should.be.eql(true); - fs.existsSync('test/megablock/_bar/megablock_bar_val.js').should.be.eql(true); + it('Block renaming', function(){ + exec('node bemy.js -t rename -f test/rename -p "megablock"'); - fs.existsSync('test/megablock/__kontur/megablock__kontur.css').should.be.eql(true); - fs.existsSync('test/megablock/__kontur/megablock__kontur.deps.js').should.be.eql(true); + fs.existsSync('test/megablock').should.be.eql(true); + fs.existsSync('test/megablock/megablock.css').should.be.eql(true); + fs.existsSync('test/megablock/megablock.priv.js').should.be.eql(true); - fs.existsSync('test/megablock/__kontur/_bar/megablock__kontur_bar.css').should.be.eql(true); - fs.existsSync('test/megablock/__kontur/_bar/megablock__kontur_bar_val.js').should.be.eql(true); - }); + fs.existsSync('test/megablock/_bar/megablock_bar.css').should.be.eql(true); + fs.existsSync('test/megablock/_bar/megablock_bar_val.js').should.be.eql(true); + + fs.existsSync('test/megablock/__kontur/megablock__kontur.css').should.be.eql(true); + fs.existsSync('test/megablock/__kontur/megablock__kontur.deps.js').should.be.eql(true); + + fs.existsSync('test/megablock/__kontur/_bar/megablock__kontur_bar.css').should.be.eql(true); + fs.existsSync('test/megablock/__kontur/_bar/megablock__kontur_bar_val.js').should.be.eql(true); + }); - it('Block renaming when called by mod', function(){ - exec('node bemy.js -t rename -f test/megablock/megablock.priv.js -p "slider"'); + it('Block renaming when called by mod', function(){ + exec('node bemy.js -t rename -f test/megablock/megablock.priv.js -p "slider"'); - fs.existsSync('test/slider').should.be.eql(true); - fs.existsSync('test/slider/slider.css').should.be.eql(true); - fs.existsSync('test/slider/slider.priv.js').should.be.eql(true); + fs.existsSync('test/slider').should.be.eql(true); + fs.existsSync('test/slider/slider.css').should.be.eql(true); + fs.existsSync('test/slider/slider.priv.js').should.be.eql(true); - fs.existsSync('test/slider/_bar/slider_bar.css').should.be.eql(true); - fs.existsSync('test/slider/_bar/slider_bar_val.js').should.be.eql(true); + fs.existsSync('test/slider/_bar/slider_bar.css').should.be.eql(true); + fs.existsSync('test/slider/_bar/slider_bar_val.js').should.be.eql(true); - fs.existsSync('test/slider/__kontur/slider__kontur.css').should.be.eql(true); - fs.existsSync('test/slider/__kontur/slider__kontur.deps.js').should.be.eql(true); + fs.existsSync('test/slider/__kontur/slider__kontur.css').should.be.eql(true); + fs.existsSync('test/slider/__kontur/slider__kontur.deps.js').should.be.eql(true); - fs.existsSync('test/slider/__kontur/_bar/slider__kontur_bar.css').should.be.eql(true); - fs.existsSync('test/slider/__kontur/_bar/slider__kontur_bar_val.js').should.be.eql(true); + fs.existsSync('test/slider/__kontur/_bar/slider__kontur_bar.css').should.be.eql(true); + fs.existsSync('test/slider/__kontur/_bar/slider__kontur_bar_val.js').should.be.eql(true); + }); + + it('Garbage must be ignored', function(){ + fs.existsSync('test/slider/slider.less').should.be.eql(false); + fs.existsSync('test/slider/__kontur/__wrong').should.be.eql(true); + fs.existsSync('test/slider/_bar/_wrong').should.be.eql(true); + }); }); - it('Garbage must be ignored', function(){ - fs.existsSync('test/slider/slider.less').should.be.eql(false); - fs.existsSync('test/slider/__kontur/__wrong').should.be.eql(true); - fs.existsSync('test/slider/_bar/_wrong').should.be.eql(true); + describe('#Deep renaming', function(){ + before(createTestBlock); + + after(function(){ + fs.removeSync('test/megablock/'); + }); + + it('Correct renaming of mod of block', function(){ + exec('node bemy.js -t rename -f test/rename/_mod -p "foo" -d'); + fs.readFileSync('test/rename/_foo/rename_foo.css', 'utf-8').indexOf('.rename_foo').should.not.eql(-1); + fs.readFileSync('test/rename/_foo/rename_foo_val.js', 'utf-8').indexOf('rename_foo_val').should.not.eql(-1); + }); + + it('Correct renaming of elem', function(){ + exec('node bemy.js -t rename -f test/rename/__elem -p "some" -d'); + fs.readFileSync('test/rename/__some/rename__some.css', 'utf-8').indexOf('.rename__some').should.not.eql(-1); + fs.readFileSync('test/rename/__some/rename__some.deps.js', 'utf-8').indexOf('rename__some').should.be.eql(-1); + }); + + it('Correct renaming of mod of elem', function(){ + exec('node bemy.js -t rename -f test/rename/__some/_mod -p "foo" -d'); + fs.readFileSync('test/rename/__some/_foo/rename__some_foo.css', 'utf-8').indexOf('.rename__some_foo').should.not.eql(-1); + fs.readFileSync('test/rename/__some/_foo/rename__some_foo_val.js', 'utf-8').indexOf('rename__some_foo_val').should.not.eql(-1); + }); + + it('Correct renaming of block', function(){ + exec('node bemy.js -t rename -f test/rename -p "megablock" -d'); + + fs.readFileSync('test/megablock/megablock.css', 'utf-8').indexOf('.megablock').should.not.eql(-1); + fs.readFileSync('test/megablock/megablock.priv.js', 'utf-8').indexOf('megablock').should.not.eql(-1); + + fs.readFileSync('test/megablock/_foo/megablock_foo.css', 'utf-8').indexOf('.megablock_foo').should.not.eql(-1); + fs.readFileSync('test/megablock/_foo/megablock_foo_val.js', 'utf-8').indexOf('megablock_foo_val').should.not.eql(-1); + + fs.readFileSync('test/megablock/__some/megablock__some.css', 'utf-8').indexOf('.megablock__some').should.not.eql(-1); + fs.readFileSync('test/megablock/__some/megablock__some.deps.js', 'utf-8').indexOf('rename__some').should.be.eql(-1); - fs.removeSync('test/slider/'); + fs.readFileSync('test/megablock/__some/_foo/megablock__some_foo.css', 'utf-8').indexOf('.megablock__some_foo').should.not.eql(-1); + fs.readFileSync('test/megablock/__some/_foo/megablock__some_foo_val.js', 'utf-8').indexOf('megablock__some_val').should.be.eql(-1); + }); }); }); function createTestBlock(){ fs.mkdirpSync('test/rename'); - fs.writeFileSync('test/rename/rename.css'); - fs.writeFileSync('test/rename/rename.priv.js'); + fs.writeFileSync('test/rename/rename.css', '.rename { }'); + fs.writeFileSync('test/rename/rename.priv.js', "blocks.declare('rename', function (data) {"); fs.mkdirpSync('test/rename/_mod'); - fs.writeFileSync('test/rename/_mod/rename_mod.css'); - fs.writeFileSync('test/rename/_mod/rename_mod_val.js'); + fs.writeFileSync('test/rename/_mod/rename_mod.css', '.rename_mod { }'); + fs.writeFileSync('test/rename/_mod/rename_mod_val.js', "BEM.DOM.decl('rename_mod_val', {"); fs.mkdirpSync('test/rename/__elem'); - fs.writeFileSync('test/rename/__elem/rename__elem.css'); - fs.writeFileSync('test/rename/__elem/rename__elem.deps.js'); + fs.writeFileSync('test/rename/__elem/rename__elem.css', '.rename__elem { }'); + fs.writeFileSync('test/rename/__elem/rename__elem.deps.js', 'shouldDeps: [rename__elem'); fs.mkdirpSync('test/rename/__elem/_mod'); - fs.writeFileSync('test/rename/__elem/_mod/rename__elem_mod.css'); - fs.writeFileSync('test/rename/__elem/_mod/rename__elem_mod_val.js'); + fs.writeFileSync('test/rename/__elem/_mod/rename__elem_mod.css', '.rename__elem_mod { }'); + fs.writeFileSync('test/rename/__elem/_mod/rename__elem_mod_val.js', "BEM.DOM.decl('rename__elem_mod_val', {"); //garbage fs.writeFileSync('test/rename/rename.less'); diff --git a/tmp/empty.tmp b/tmp/empty.tmp new file mode 100644 index 0000000..e69de29 diff --git a/tmp/priv-template.js b/tmp/priv-template.js index 69c41ee..825e761 100644 --- a/tmp/priv-template.js +++ b/tmp/priv-template.js @@ -2,7 +2,7 @@ module.exports = function (blocks) { blocks.declare('{{blockName}}{{elemName}}{{modName}}{{modVal}}', function (data) { return { block: '{{blockName}}', - content: {{cursor}} + content: ''{{cursor}} }; }); };