{"id":49408225,"url":"https://github.com/bem-archive/bem-tools","last_synced_at":"2026-04-30T04:01:08.401Z","repository":{"id":865262,"uuid":"602326","full_name":"bem-archive/bem-tools","owner":"bem-archive","description":"Toolkit to work with files based on BEM methodology","archived":true,"fork":false,"pushed_at":"2017-03-09T09:18:23.000Z","size":3914,"stargazers_count":394,"open_issues_count":22,"forks_count":69,"subscribers_count":41,"default_branch":"support/0.10.x","last_synced_at":"2026-01-13T22:20:37.490Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://bem.info/tools/bem/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bem-archive.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2010-04-09T11:38:24.000Z","updated_at":"2025-09-12T01:58:22.000Z","dependencies_parsed_at":"2022-07-05T19:00:30.199Z","dependency_job_id":null,"html_url":"https://github.com/bem-archive/bem-tools","commit_stats":null,"previous_names":["bem/bem-tools"],"tags_count":109,"template":false,"template_full_name":null,"purl":"pkg:github/bem-archive/bem-tools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bem-archive%2Fbem-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bem-archive%2Fbem-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bem-archive%2Fbem-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bem-archive%2Fbem-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bem-archive","download_url":"https://codeload.github.com/bem-archive/bem-tools/tar.gz/refs/heads/support/0.10.x","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bem-archive%2Fbem-tools/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32454170,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T22:27:22.272Z","status":"online","status_checked_at":"2026-04-30T02:00:05.929Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-28T23:00:24.014Z","updated_at":"2026-04-30T04:01:08.382Z","avatar_url":"https://github.com/bem-archive.png","language":"JavaScript","readme":"# BEM Tools [![Build Status](https://secure.travis-ci.org/bem/bem-tools.png?branch=nodejs)](http://travis-ci.org/bem/bem-tools)\nToolkit to work with files based on [BEM methodology](http://bem.github.io/bem-method/pages/beginning/beginning.en.html).\n\n## Installation\nYou need [NodeJS 0.10+](http://nodejs.org/) or later and [npm 2.x+](https://www.npmjs.com/).\n\nRun `npm install bem` to install `bem-tools` locally.\n\n## Usage\nGet the list of commands with `bem --help`.\nTo read about commands and subcommands use `bem COMMAND --help` or `bem COMMAND SUBCOMMAND --help`.\n\n### Shell completion\n\n#### bash\n\nTo make completions for bem-tools available in your bash, run following\ncommand (ensure that you have bash-completion installed, first). Run this\n\n    bem completion \u003e /path/to/etc/bash_completion.d/bem\n\nand restart bash.\n\nIf you aren't using `bash-completion`, you can add `bem completion` to your `.bashrc` and reload:\n\n    bem completion \u003e\u003e ~/.bashrc\n    source ~/.bashrc\n\n#### zsh\n\nIf you use `zsh`, you can add `bem completion` to your `.zshrc` and reload:\n\n    bem completion \u003e\u003e ~/.zshrc\n    source ~/.zshrc\n\n### Commands\n#### bem create\n\nYou can create following entities using `bem create`:\n\n * levels of defenition\n * blocks\n * elements\n * modifiers\n\n##### Level of defenition\n\nLevel of defenition is a directory that holds blocks and an utility directiry `.bem`.\n\nA `.bem` directory holds configuration of a current level:\n\n * naming convention\n * links to the technologies\n\nAn example of technologies' links (this is `blocks-desktop` level of\n`bem-bl` block library):\n\n    https://github.com/bem/bem-bl/blob/master/blocks-common/.bem/level.js\n\n###### Create new level of defenition named `blocks` under current directory:\n\n    bem create level blocks\n\n###### Create a level for pages\n\nIn `bem-tools` terms pages are blocks as well and a directory which holds pages is a level of\ndefenition itself. To create such a directory run this:\n\n    bem create level pages\n\n###### Create a level based on an existing one\n\n`bem create level` allows to use an existing level as a prototype for a level it creates.\n\n    bem create level --level bem-bl/blocks-desktop blocks\n\n##### Block\n\nBlock is a bunch of files in different technologies that hold block's implementation.\n\n###### Create a new block\n\n    bem create block b-my-block\n\nBy default, a block has several techs: (`bemhtml`, `css`, `js`).\n\n###### Create a new block using concrete tech\n\nFlags -t (-T) are to create files of technologies you need:\n\n    bem create block -t deps.js b-my-block\n        // Creates a block implementation in deps.js technology, ecxept of default techs.\n\n    bem create block -T css b-my-block\n        // Creates only CSS technology for a block\n\n    bem create block -T bem-bl/blocks-desktop/i-bem/bem/techs/bemhtml.js b-my-block\n        // -T flag is useful when you need to add a new tech to the block existed\n\nThe value of this flag may be either tech's name (e.g `css`) or a path to tech module.\n\nTech names may be listed in `.bem/level.js` file of a level.\nE.g., https://github.com/bem/bem-bl/blob/master/blocks-common/.bem/level.js\n\nYou can find the examples of tech modules in the repo:\n\n    https://github.com/bem/bem-tools/tree/master/lib/techs\n\n###### Create element\n\nCreate element named `elem` for block `b-my-block`\n\n    bem create elem -b b-my-block elem\n\n###### Create modifier of block or element\n\nCreate modifier named `mod` for block `b-my-block`\n\n    bem create mod -b b-my-block mod\n\nCreate modifier named `mod` having value `val` for block `b-my-block`\n\n    bem create mod -b b-my-block mod -v val\n\nCreate modifier named `mod` for element `elem` of block `b-my-block`\n\n    bem create mod -b b-my-block -e elem mod\n\nCreate modifier named  `mod` having value `val` for element `elem` of block `b-my-block`\n\n    bem create mod -b b-my-block -e elem mod -v val\n\n###### Create any BEM entity using `bem create` command only\n\nYou can create any BEM entities or bunches of them using `bem create` command.\n\nCreate blocks named `b-block1` and `b-block2`\n\n    bem create -b b-block1 -b b-block2\n\nCreate elements named `elem1` and `elem2` for block `b-block`\n\n    bem create -b b-block -e elem1 -e elem2\n\nCreate modifier names `mod` of block `b-block`\n\n    bem create -b b-block -m mod\n\nCreate modifier named `mod` of block `b-block` having values `val1` and `val2`\n\n    bem create -b b-block -m mod -v val1 -v val2\n\nCreate modifier named `mod` for element `elem` of block `b-block`\n\n    bem create -b b-block -e elem -m mod\n\nCreate modifier named `mod` having values `val1` and `val2` for element `elem` of block `b-block`\n\n    bem create -b b-block -e elem -m mod -v val1 -v val2\n\n#### bem build\n\n`bem build` command builds page files in different techs, according to a page declaration.\n\n##### Create bemdecl.js file from page's bemjson\n\n    bem build \\\n        -l bem-bl/blocks-common -l bem-bl/blocks-desktop \\\n        -l blocks -l pages/index/blocks \\\n        -d pages/index/index.bemjson.js -t bemdecl.js \\\n        -o pages/index -n index\n\nYou can use either tech's name or a path to its module as a value of -t flag. This\nmodule says how to build a final file from a declaration.\n\nE.g., this is a module for `deps.js`: https://github.com/bem/bem-tools/blob/master/lib/techs/deps.js.js\n\n##### Create deps.js file from bemdecl.js\n\n    bem build \\\n        -l bem-bl/blocks-common -l bem-bl/blocks-desktop \\\n        -l blocks -l pages/index/blocks \\\n        -d pages/index/index.bemdecl.js -t deps.js \\\n        -o pages/index -n index\n\n###### Create js and css files for a page from deps.js\n\n    bem build \\\n        -l bem-bl/blocks-common -l bem-bl/blocks-desktop \\\n        -l blocks -l pages/index/blocks \\\n        -d pages/index/index.deps.js -t css \\\n        -o pages/index -n index\n\n    bem build \\\n        -l bem-bl/blocks-common -l bem-bl/blocks-desktop \\\n        -l blocks -l pages/index/blocks \\\n        -d pages/index/index.deps.js -t js \\\n        -o pages/index -n index\n\n###### Create bemhtml.js template for a page from deps.js\n\n    bem build \\\n        -l bem-bl/blocks-common -l bem-bl/blocks-desktop \\\n        -l blocks -l pages/index/blocks \\\n        -d pages/index/index.bemhtml.js \\\n        -t bem-bl/blocks-desktop/i-bem/bem/techs/bemhtml.js \\\n        -o pages/index -n index\n\nThere is an example how pages are built using `bem build` in our test project that uses\n`bem-bl` block library: https://github.com/toivonen/bem-bl-test/blob/master/GNUmakefile\n\n#### bem decl\n\n`bem decl` is to work with declaration files. Thus,\n\n * to merge two or more decls into one\n * «subtract» decls\n\nAll subcommands of `bem decl` can take either bemdecl.js or deps.js as input declaration formats.\nas input declaration (via `-d` flag).\n\nOuput data (`-o` flag) is always in `deps.js` format.\n\n##### bem decl merge\n\n`bem decl merge` is to merge two or more decls into one. It is useful if you need, for example, to build\none file for several pages.\n\n###### Create a decl for all the pages\n\n    bem decl merge \\\n        -d pages/index/index.deps.js \\\n        -d pages/about/about.deps.js \\\n        -d pages/search/search.deps.js \\\n        -o pages/common/common.deps.js\n\n##### bem decl subtract\n\n`bem decl subtract` is to «subtract» all next decls from the first one.\nYou may use it to create a bundle that you request by application.\n\n###### Create a decl for a \"heavy\" block requested by application\n\n    bem decl subtract \\\n        -d bundles/heavy-block/heavy-block.deps.js \\\n        -d pages/common/common.deps.js \\\n        -o bundles/heavy-block/heavy-block.bundle.js\n\n##### bem make\n`make` command implements the build process of the BEM projects. You don't have to write your own scripts or makefiles (for GNU make or other build system) to build your BEM project.\n\nSince `0.10.0` `bem make` also supports `enb make` under the hood which is recomended way to build your projects.\n\nDuring the build `bem make`\n\n * fetches the block libraries\n * builds the levels content\n * builds the bundles\n * generates the templates (`bemhtml`)\n * generates `html` from `bemjson.js`\n * generates the static content files (`js`, `css`)\n * expands the `@import` derectives in `css` files (`borschik`)\n * expands the `borschik:link:include` directives  in `js` files (`borschik`)\n * optimizes `css` files using `csso`\n * optimizes `js` files using `uglifyjs`\n\n##### bem server\n\n`bem server` command runs a development server. It makes the project files being accessible via the http protocol.\nThis includes the files which are generated during the build process. So the server can be useful when you develop the\nstatic pages using the bem method. You just edit the files, refresh the browser and get updated page. All the files\nwhich are affected by your changes will be rebuilt automatically.\nIn the case your project has no static pages you can configure your backend server and production environment to retrieve\nthe stylesheets and scripts from the bem server. bem server accepts connections via normal TCP socket and via UNIX domain socket.\n\nBy default the current directory is considered as the project root. You can change it using the --project (-r) option.\n\nDefault TCP port is 8080. You can change it using the --port (-p) option.\n\nWhen requested URL is mapped to a directory, the server will check if there is an index.html file or it's possible to build it.\nIn the case one of these is true the content of the file will be returned to browser. The directory content listing will be returned\notherwise.\n\nSince `0.10.0` `bem server` also supports `enb server` under the hood which is recomended way to build your projects.\n\n#### Build configuration\n\nSince `0.10.0` `bem make` and `bem server` also supports `ENB` under the hood which is recomended way to build your projects. So for build configuration please refer [ENB documentation](https://github.com/enb-make/enb).\n\nThe info about configuration bellow is deprecated and will be removed in the next version.\n\nThere is a default build behavior programmed in the build system. The configuration files allow to adjust it a little or change it completely.\nTo make `bem make` work you should have `.bem/level.js` file within your levels. It should contain the `getTechs()` function, \nwhich returns object with the tech definitions used on the level.\nAnd it should have function `getConfig()`:\n\n```js\nvar extend = require('bem/lib/util').extend;\n\nexports.getTechs = function() {\n    return {\n        'bemjson.js': '',\n        'js': 'js-i',\n        'bemhtml.js': '../../bem-bl/blocks-common/i-bem/bem/techs/bemhtml.js',\n        'priv.js': '../../.bem/techs/priv.js',\n        'html': '../../bem-bl/blocks-common/i-bem/bem/techs/html'\n    };\n};\n\nexports.getConfig = function() {\n\n    return extend({}, this.__base() || {}, {\n\n        bundleBuildLevels: this.resolvePaths([\n            '../../bem-bl/blocks-common',\n            '../../bem-bl/blocks-desktop',\n            '../../blocks'\n        ])\n\n    });\n\n};\n```\n\n`getTechs()` returns an object with used techs. Object properties (for example `'bemjson.js'`, `'js'`, `'bemhtml.js'`) define the\ntech names, object values specify the paths to the appropriate tech files (`''`, `'js-i'`, `'../../bem-bl/blocks-common/i-bem/bem/techs/bemhtml.js'`).\nA path can be relative or absolute, it can be empty, or it can specify just a file name. When the latter case is used the\ntech will be considered being standard (bundled with bem-tools) and the file will be looked up in the `[bem]/lib/techs` folder.\n\n`getConfig()` function returns an object with the `bundleBuildLevels` property, containing the array of the used block levels.\n\nAnother (optional) configuration file is `.bem/make.js` located in the project root. Core of the build system is a graph\nof nodes, each of which executes own part of the whole build process. `make.js` allows you to adjust nodes behavior and change build graph.\nThere are several standard node types:\n * `Node` - base node, implements basic functionality. All other nodes are inherited from this one\n * `LibraryNode` - retrieves external libraries\n * `LevelNode` - inspects the contents of a level and constructs graph branch accordingly to build the level\n * `BundlesLevelNode` - inherits from `LevelNode` and builds the bundles levels\n * `BundleNode` - constructs graph branch for a bundle\n * `MergedBundleNode` - builds merged bundle (aka common bundle)\n * `BorschikNode` - processes files with the `borschik` utility, `csso` and `uglifyjs`\n * `Arch` - builds initial graph, which by default consists of `LibraryNode`, `BundlesLevelNode` and `LevelNode` nodes\n\nTo alter build system behavior for your project you need to alter behavior of the nodes. This can be achieved by adding `MAKE.decl()` calls in the `.bem/make` file. `MAKE.decl()` is a helper\nfunction which accepts two arguments. First one is the node name which we want to change, second - an object with overriding methods.\n\n```js\nMAKE.decl('BundleNode', {\n\n});\n```\n\nNode classes have some fundamental methods, which take care about the build process:\n * `isValid()` - validates the node - indicates is there a need to rebuild it or not. If node artifacts were built during\n  previous build and dependency nodes were not rebuilt after that, the node is considered being valid. In other words\n  if you changed a file after first build then only the nodes which depend on this file will be rebuilt during the\n  consequent build.\n * `make()` - implements the build logic for the node.\n * `run()` - node entry point. In the default implementation it executes isValid method and in case it returns false the make method will be executed next.\n * `clean()` - removes the build artifacts for the node.\n\n##### Sample configuration files for some typical tasks\n\n###### Build of static html, css, js, bemhtml templates on the level `pages`. Bemjson file is used as a source file. Also using blocks level `blocks`, and also `blocks-common` and `blocks-desktop` from bem-bl.\n\n`pages/.bem/level.js`\n```js\nvar extend = require('bem/lib/util').extend;\n\nexports.getTechs = function() {\n\n    return {\n        'bemjson.js': '',\n        'bemdecl.js': 'bemdecl.js',\n        'deps.js': 'deps.js',\n        'js': 'js-i',\n        'css': 'css',\n        'bemhtml.js': '../../bem-bl/blocks-common/i-bem/bem/techs/bemhtml.js',\n        'html': '../../bem-bl/blocks-common/i-bem/bem/techs/html.js'\n    };\n\n};\n\nexports.getConfig = function() {\n\n    return extend({}, this.__base() || {}, {\n\n        bundleBuildLevels: this.resolvePaths([\n            '../../bem-bl/blocks-common',\n            '../../bem-bl/blocks-desktop',\n            '../../blocks'\n        ])\n\n    });\n\n};\n```\n\n`.bem/make.js`\n```js\nMAKE.decl('Arch', {\n\n    getLibraries: function() {\n\n        return {\n            'bem-bl': {\n                type: 'git',\n                url: 'git://github.com/bem/bem-bl.git'\n            }\n        };\n\n    }\n\n});\n\nMAKE.decl('BundleNode', {\n\n    getTechs: function() {\n\n        return [\n            'bemjson.js',\n            'bemdecl.js',\n            'deps.js',\n            'bemhtml.js',\n            'css',\n            'js',\n            'html'\n        ];\n    }\n\n});\n```\n\n\n###### Build of css, js, bemhtml tamples on the level `pages`. `bemdecl` declaration file is used as a source file. Also using blocks level `blocks`, and also `blocks-common` and `blocks-desktop` from bem-bl.\n\n`pages/.bem/level.js`\n```js\nvar extend = require('bem/lib/util').extend;\n\nexports.getTechs = function() {\n\n    return {\n        'bemdecl.js': 'bemdecl.js',\n        'deps.js': 'deps.js',\n        'js': 'js-i',\n        'css': 'css',\n        'bemhtml.js': '../../bem-bl/blocks-common/i-bem/bem/techs/bemhtml.js'\n    };\n\n};\n\nexports.getConfig = function() {\n\n    return extend({}, this.__base() || {}, {\n\n        bundleBuildLevels: this.resolvePaths([\n            '../../bem-bl/blocks-common',\n            '../../bem-bl/blocks-desktop',\n            '../../blocks'\n        ])\n\n    });\n\n};\n```\n\n`.bem/make.js`\n```js\nMAKE.decl('Arch', {\n\n    getLibraries: function() {\n\n        return {\n            'bem-bl': {\n                type: 'git',\n                url: 'git://github.com/bem/bem-bl.git'\n            }\n        };\n\n    }\n\n});\n\nMAKE.decl('BundleNode', {\n\n    getTechs: function() {\n\n        return [\n            'bemdecl.js',\n            'deps.js',\n            'bemhtml.js',\n            'css',\n            'js'\n        ];\n    }\n\n});\n```\n\n###### The block libraries\n\nThe block libraries are not used by default. To use a library add the following code to `.bem/make.js`:\n\n```js\nMAKE.decl('Arch', {\n    getLibraries: function() {\n\n        return {\n            'bem-bl': {\n                type: 'git',\n                url: 'git://github.com/bem/bem-bl.git'\n            }\n        };\n    }\n});\n```\n\n\nWhere:\n * `'Arch'` - node class name which we want to override. Arch builds initial build graph.\n * `getLibraries` - a method of the Arch class, which returns the associative array of the used block libraries.\n * `'bem-bl'` — the name of the library and the folder where it will be copied to.\n * `type` - the type of the library source. We use git in the example, so the library will be checked out of a git repository.\n Possible values are: `'git'`, `'svn'`, `'symlink'`. `svn` works the same as `git`, but with svn repositories. `symlink` -\n creates a symbolic link in the project folder to the library folder. The library path is specified by the `relative` property.\n * `url` - URL to the svn/git repository\n\nAlso you can use shorter code:\n\n```js\nMAKE.decl('Arch', {\n    libraries: {\n        'bem-bl': {\n            type: 'git',\n            url: 'git://github.com/bem/bem-bl.git'\n        }\n    }\n});\n```\n\n###### Block levels\n\nThe folders in the project root matching the `blocks*` mask are considered being the blocks level. You can change this using the following code:\n\n```js\nMAKE.decl('Arch', {\n    blocksLevelsRegexp:  /regular expression/,\n});\n```\n\nThe regular expression will be used to match the folders in the project root. A folder which does match will be used as the blocks level.\n\nIf you need some logic for the levels selection you can achieve that by overriding the `createBlocksLevelsNodes()` method:\n\n```js\nMAKE.decl('Arch', {\n    createBlocksLevelsNodes: function(parent, children) {\n        // Create the LevelNode instance\n        var node1 = new LevelNode(...);\n        // Add it into the graph\n        this.arch.setNode(node1, parent, children);\n\n        var node2 = new LevelNode(...);\n        this.arch.setNode(node2, parent, children);\n\n        // return an array with the Ids of the created nodes\n        return [node1.getId(), node2.getId()];\n    }\n});\n```\n\n###### The bundles and the pages\n\nThe folders in the project root matching the `pages*` abd `bundles*` masks are considered being bundle level. You can change this using the following code:\n\n```js\nMAKE.decl('Arch', {\n    bundlesLevelsRegexp: /regular expression/,\n});\n```\n\nAnd for more precise control:\n\n```js\nMAKE.decl('Arch', {\n\n    getBundlesLevels: function() {\n        return [\n            'pages-desktop',\n            'pages-touch',\n            'bundles/common'\n        ];\n    }\n\n});\n```\n\n\nFor every bundle the following target files are built by default:\n\n * `.bemhtml.js`\n * `.html`\n * `.css`\n * `.ie.css`\n * `.js`\n * `_*.css`\n * `_*.ie.css`\n * `_*.js`\n\nand the intermediate:\n\n * `.bemdecl.js`\n * `.deps.js`\n * `.deps.js.deps.js`\n * `.bemhtml.js.meta.js`\n * `.js.meta.js`\n * `.css.meta.js`\n * `.ie.css.meta.js`\n\n`.bemjson.js` file is considered as a source file. If it does not exist, `.bemdecl.js` is used then. If `.bemdecl.js`\n does not exist too, `.deps.js` will be used. For the cases when `.bemjson.js` does not exist static html will not be built.\n\nTo change the list of the file techs to use, add the following code into `.bem/make.js`:\n\n```js\nMAKE.decl('BundleNode', {\n\n    getTechs: function() {\n        return [\n            'bemdecl.js',\n            'deps.js',\n            'bemhtml.js',\n            'css',\n            'js',\n            'priv.js'\n        ];\n    }\n});\n```\n\n**IMPORTANT:** Techs in the list should be in the order of dependency on each other.  Tech B, which depends on A, should go **bellow** A. The source file tech should also be in the list, for example `bemjson.js`.\n\n###### The merged bundles\nThe merged bundle — a bundle which includes the declarations of all bundles on the level. So for example css in a merged bundle will contain the styles from all of the bundles.\n\nThe following code will enable the build of the merged bundles for all levels:\n\n```js\nMAKE.decl('BundlesLevelNode', {\n    buildMergedBundle: function() {\n        return true;\n    }\n});\n```\n\nIf you need a merged bundle for the selected levels only (for `pages-desktop` level in the example):\n\n```js\nvar PATH = require('path');\n\nMAKE.decl('BundlesLevelNode', {\n    buildMergedBundle: function() {\n        if (this.getLevelPath() === 'pages-desktop') return true;\n\n        return false;\n    }\n});\n```\n\nThe `getLevelPath()` method returns the relative path for the level. We can use it to decide should we enable some special logic for current level or not.\n\nTo change the merged bundle name use the code:\n```js\nMAKE.decl('BundlesLevelNode', {\n\n    mergedBundleName: function() {\n        return 'mymergedbundle';\n    }\n\n});\n```\n\n##### Production and Development builds\nBy changing the `YENV` environment variable value, you can switch between the production and development builds.\nIn production mode static files are processed with the `borschik` utility. It expands the include directives and puts the\nresult content in the file with the `_` prefix. For example, `index.css` has the directives to include `blocks/block1.css`\nand `blocks/block2.css`. `_index.css` will be created with the content of both `block1.css` and `block2.css`. Also the\n`css` files are optimized with the `csso` utility, the `js` files are optimized with `uglifyjs`. In development mode\n`borschik` is used only, no optimizations take the place.\n\nThe default mode is development. To use the production mode set `YENV` to `production`.\n\nEnvironment variables can be set in `.bem/make.js`, for example\n\n```js\nprocess.env.YENV = 'production';\n```\n\n### Configuration files\n#### Level (.bem/level.js)\n\nA level should have `.bem/level.js` configuration file which contains the meta information about the level:\n\n- the mapping rules between the BEM entities and the file system\n- the thech modules defined on the level\n- the meta information for the build system\n\nWhen the `bem create level` command is used to create a level the empty `.bem/level.js` file will be also created.\nWhich means that this level is «standard» one. The logic for standard level is defined in the `Level` class within \n(lib/level.js)[https://github.com/bem/bem-tools/blob/master/lib/level.js].\n\nAs the `.bem/level.js` file is a CommonJS module it's easy to override the level's behavior. `bem-tools` creates a new\nclass inherited from the standard `Level` class using export of this module as a class extention (under the hood the \n[inherit](https://github.com/dfilatov/inherit) module is used).\n\nIn the example bellow the `getTechs()` method is overriden.\n\n```js\nexports.getTechs = function() {\n\n    return {\n        'bemjson.js': ''\n        'css': 'path/to/my/css-tech-module.js'\n    }\n\n};\n```\n\n##### The levels inheritance\n\nTo avoid the copy and paste of the same code among several levels you can put the common parts into the independant\nmodules and inherit them. This way you can build up the levels hierarchy.\n\nTo specify the base level you should export it in the `baseLevelPath` property. For example\n\n```js\nexports.baseLevelPath = require.resolve('path/to/base/level.js');\n```\n\nIt's also possible to create the inherited levels using the command\n\n    bem create level \u003cyour-level-name\u003e --level path/to/base/level.js\n\n##### The mapping rules between BEM entities and the file system\n\nBy default the following mapping scheme is used (this example is about the `css` tech):\n\n```\nlevel/\n    block/\n        __elem/\n            _mod/\n                block__elem_mod_val.css\n            block__elem.css\n        _mod/\n            block_mod_val.css\n        block.css\n```\n\nIf you want to use a custom scheme override the appropriate `match*()` and `get*()` methods in the `.bem/level.js` file.\n\n##### Tech modules defined on the level\n\nTo define a list of the tech modules used on the level export the `getTechs()` function. It should return an object\nthe keys of which contain the tech names and the values contain on of the following:\n\n- the absolute tech path;\n- a short tech name — a tech module with such name bundled with `bem-tools` will be used;\n- an empty string — the default tech implementation will be used.\n\nBy deault there is no any techs defined explicitly on a level. In the case some techs are used within such a level \nby a short name (for example `css`, `js`, etc) then the appropriate tech modules bundled with `bem-tools` are loaded.\nIf such do exist of course. The full list of such techs can be found there [lib/techs](https://github.com/bem/bem-tools/tree/master/lib/techs).\n\nIf you try to use a tech which was not defined explicitly and which is not bundled with `bem-tools` - the default tech\nwill be used (see [lib/tech/v1.js](https://github.com/bem/bem-tools/blob/master/lib/tech/v1.js)).\n\nThe techs defined on the level are used:\n\n- by the `bem create` command\n- by the `bem build` command\n- by the file system introspection (see the `getLevelByIntrospection()` of the `Level` class)\n- during the project build with the `bem make` and `bem build` commands\n\nIt's recommended to define explicitly the used techs.\n\n##### The build system meta information\n\nTo let the build system know which levels should be used to build one bundle or another set the `bundleBuildLevels`\nproperty within an object returned by the `getConfig()` function to an array of these levels.\n\n```js\nexports.getConfig = function() {\n\n    return extend({}, this.__base() || {}, {\n\n        bundleBuildLevels: this.resolvePaths([\n            // your levels here\n        ])\n\n    });\n\n};\n```\n\n### Tech modules\n\n#### API\n\nLook for the documentation in the source code [lib/tech/v1.js](https://github.com/bem/bem-tools/blob/master/lib/tech/v1.js).\n\n#### Creating tech module\n\nThere are many ways to write a tech module.\n\nWhatever manner you choose you can refer to the tech object from methods using `this`.\nAny base method is available using `this.__base(...)` call. Tech class can be referenced\nusing `this.__class`. Thanks to [inherit](https://github.com/dfilatov/node-inherit) module\nthat helps us to organize inheritance here.\n\n##### Trivial way\n\nYou only need to declare regular CommonJS module and export some of its\nfunctions to redefine them. By default your tech will derive from base `Tech` class\ndefined in module [lib/tech/v1.js](https://github.com/bem/bem-tools/blob/master/lib/tech/v1.js).\n\n```js\nexports.getCreateResult = function(...) {\n    // your code goes here\n};\n```\n\nYou can also group all methods in `techMixin` object. This is a recommended way.\n\n```js\nexports.techMixin = {\n\n    getCreateResult: function(...) {\n        // your code goes here\n    }\n\n};\n```\n\n##### Simple way\n\nBesides function, you can also export `baseTechPath` variable to define an\nabsolute path to a tech module you are extending. Or you can\n\n```js\nvar BEM = require('bem');\n\nexports.baseTechPath = BEM.require.resolve('./techs/css');\n```\n\nYou can also derive from tech module by its name using `baseTechName` variable.\nBase class will be chosen in the context of level where tech module will be used.\n\n```js\nexports.baseTechName = 'css';\n```\n\nIn this example new tech will derive from `css` tech declared on level in file\n`.bem/level.js`.\n\n##### Hardcore way\n\nIf you need a total control, you can create a module that exports\nthe whole `Tech` class.\n\n```js\nvar INHERIT = require('inherit'),\n    BaseTech = require('bem/lib/tech').Tech;\n\nexports.Tech = INHERIT(BaseTech, {\n\n    create: function(prefix, vars, force) {\n        // do some creation work\n    },\n\n    build: function(prefixes, outputDir, outputName) {\n        // organize own build process\n    }\n\n});\n```\n\nIf you need to base your tech on an existing one written in a simple way use\n`getTechClass()` function to get its class. We recommend to use `getTechClass()`\nfunction all the time to not depend on tech implementation.\n\n```js\nvar INHERIT = require('inherit'),\n    BEM = require('bem'),\n    BaseTech = BEM.getTechClass(require.resolve('path/to/tech/module'));\n\nexports.Tech = INHERIT(BaseTech, {\n\n    // your overrides go here\n\n});\n```\n\n##### Examples of tech modules\n\n * [bem-tools/lib/techs/](https://github.com/bem/bem-tools/tree/nodejs/lib/techs)\n * [bem-bl/blocks-common/i-bem/bem/techs/](https://github.com/bem/bem-bl/tree/master/blocks-common/i-bem/bem/techs)\n\n### API usage\n\nStarting from 0.2.0 version it is possible to use `bem-tools` from API.\n\n`bem` module exports the object of a command that has an `api` property.\nIt is to use in this way:\n\n```js\nvar Q = require('q'),\n    BEM = require('bem').api,\n\n    techs = ['css', 'js'],\n    blocks = ['b-block1', 'b-block2'];\n\nQ.when(BEM.create.block({ forceTech: techs }, { names: blocks }), function() {\n    console.log('Create blocks: %s', blocks.join(', '));\n});\n```\n\nThe example above shows that you can use all the commands (including subcommands).\n\nA command accepts two args:\n\n * **Object** `opts` command options\n * **Object** `args` command arguments\n\nIt returns an object of `Q.promise` type.\n\n#### BEM.create\n\nCommands to create BEM entities.\n\n##### BEM.create.level()\n\nCreates a level of defenition.\n\n###### Options\n\n * **String** `outputDir` a directory of output (current directory by default)\n * **String** `level` a «prototype» of the level\n * **Boolean** `force` key to force level's creating if it already exists\n\n###### Arguments\n\n * **Array** `names` Namef of levels you are creating\n\n###### Example\n\n```js\nvar PATH = require('path'),\n    Q = require('q'),\n    BEM = require('bem').api,\n\n    outputDir = PATH.join(__dirname, 'levels'),\n    levels = ['blocks-common', 'blocks-desktop'];\n\nQ.when(BEM.create.level({ outputDir: outputDir }, { names: levels }), function() {\n    console.log('Create levels %s at %s', levels.join(', '), outputDir);\n});\n```\n\n##### BEM.create()\n\nCreates BEM entities: blocks, elems, modifiers and their values.\n\n###### Options\n\n * **String** `level` Level directory (current directory by default)\n * **Array** `block` Block name (required)\n * **Array** `elem` Element name\n * **Array** `mod` Modifier name\n * **Array** `val` Modifier value\n * **Array** `addTech` Add the techs listed\n * **Array** `forceTech` Use only the techs listed\n * **Array** `noTech` Exclude the techs listed\n * **Boolean** `force` Force creating BEM entities files (rewrite)\n\n###### Example\n\n```js\nvar Q = require('q'),\n    BEM = require('bem').api,\n\n    forceTechs = ['css'],\n    block = 'b-header',\n    elem = 'logo',\n    mods = ['lang'],\n    vals = ['ru', 'en'];\n\nQ.when(BEM.create({ forceTechs: forceTechs, block: block, mod: mods, val: vals }), function() {\n    console.log('Create mod %s of block %s with vals %s', mods.join(', '), block, vals.join(', '));\n});\n\nQ.when(BEM.create({ forceTechs: forceTechs, block: block, elem: elem, mod: mods, val: vals }), function() {\n    console.log('Create mod %s of elem %s of block %s with vals %s', mods.join(', '), elem, block, vals.join(', '));\n});\n```\n\n##### BEM.create.block()\n\nCreates a block.\n\n###### Options\n\n * **String** `level` A directory of block's level. (Current directory by default)\n * **Array** `addTech` Add the techs listed\n * **Array** `forceTech` Use these techs only\n * **Array** `noTech` Exclude these techs\n * **Boolean** `force` Force files creating\n\n###### Arguments\n\n * **Array** `names` List of block names\n\n###### Example\n\n```js\nvar Q = require('q'),\n    BEM = require('bem').api,\n\n    addTechs = ['bemhtml'],\n    blocks = ['b-header'];\n\nQ.when(BEM.create.block({ addTech: addTechs }, { names: blocks }), function() {\n    console.log('Create blocks: %s', blocks.join(', '));\n});\n```\n\n##### BEM.create.elem()\n\nCreating an element.\n\n###### Options\n\n * **String** `level` A directory of level. (Current directory by default)\n * **String** `blockName` A name of element's block (required)\n * **Array** `addTech` Add the techs listed\n * **Array** `forceTech` Use only the techs listed\n * **Array** `noTech` Exclude the techs listed\n * **Boolean** `force` Force creating element's files (to rewrite them)\n\n###### Arguments\n\n * **Array** `names` List of element names\n\n###### Example\n\n```js\nvar Q = require('q'),\n    BEM = require('bem').api,\n\n    addTechs = ['bemhtml', 'title.txt'],\n    block = 'b-header',\n    elems = ['logo'];\n\nQ.when(BEM.create.elem({ addTech: addTechs, blockName: block }, { names: elems }), function() {\n    console.log('Create elems %s of block %s', elems.join(', '), block);\n});\n```\n\n##### BEM.create.mod()\n\nCreating a modifier for a block or an element.\n\n###### Options\n\n * **String** `level` Level directory (current directory by default)\n * **String** `blockName` Block name of this modifier (required)\n * **String** `elemName` Element name\n * **Array** `modVal` Modifier value\n * **Array** `addTech` Add the techs listed\n * **Array** `forceTech` Use only the techs listed\n * **Array** `noTech` Exclude the techs listed\n * **Boolean** `force` Force creating modifier files (rewrite)\n\n###### Arguments\n\n * **Array** `names` List of modifier\n\n###### Example\n\n```js\nvar Q = require('q'),\n    BEM = require('bem').api,\n\n    forceTechs = ['css'],\n    block = 'b-header',\n    elem = 'logo',\n    mods = ['lang'],\n    vals = ['ru', 'en'];\n\nQ.when(BEM.create.mod({ forceTechs: forceTechs, blockName: block, modVal: vals }, { names: mods }), function() {\n    console.log('Create mod %s of block %s with vals %s', mods.join(', '), block, vals.join(', '));\n});\n\nQ.when(BEM.create.mod({ forceTechs: forceTechs, blockName: block, elemName: elem, modVal: vals }, { names: mods }), function() {\n    console.log('Create mod %s of elem %s of block %s with vals %s', mods.join(', '), elem, block, vals.join(', '));\n});\n```\n\n#### BEM.build()\n\nBuild files from blocks.\n\n###### Options\n\n * **String** `outputDir` An output directory (current directory by default)\n * **String** `outputName` A filename (its prefix) for output\n * **Level** `outputLevel` Output level for BEM entity to create\n * **String** `block` Block name\n * **String** `elem` Element name\n * **String** `mod` Modifier name\n * **String** `val` Modifier name\n * **String** `declaration` A filename of input declaration (required)\n * **Array** `level` List of levels to use\n * **Array** `tech` List of techs to build\n\nYou should use one of the following to specify output prefix:\n\n * `outputName` to specify full path-prefix\n * `outputDir` plus `outputName` to specify directory path and file prefix (they will be joined for you)\n * `outputLevel` plus properties describing BEM entity: `block`, `elem`, `mod` and `val` (path-prefix will\n   be constructed for you using level file mapping scheme)\n\n###### Example\n\n```js\nvar Q = require('q'),\n    B = require('bem'),\n    BEM = B.api,\n\n    decl = 'page.deps.js',\n    outputDir = 'build',\n    outputName = 'page',\n    levels = ['blocks-common', 'blocks-desktop'],\n    techs = ['css', 'js'];\n\n// use outputDir and outputName options\nQ.when(\n    BEM.build({\n        outputDir: outputDir,\n        outputName: outputName,\n        declaration: decl,\n        level: levels,\n        tech: techs\n    }),\n    function() {\n        console.log('Finished build of techs %s for levels %s. Result in %s/%s.* files.',\n            techs.join(', '), levels.join(', '), outputDir, outputName);\n    }\n);\n\n// use outputLevel option\nvar level = B.createLevel('path/to/level'),\n    block = 'page';\nQ.when(\n    BEM.build({\n        outputLevel: level,\n        block: block\n    }),\n    function() {\n        console.log('Finished build of techs %s for levels %s. Result in %s.* files.',\n            techs.join(', '), levels.join(', '), level.getRelByObj({ block: block }));\n    }\n);\n```\n\n#### BEM.decl\n\nCommands to work with declarations.\n\n##### BEM.decl.merge()\n\nMerging two or more declarations into one.\n\n###### Options\n\n * **String** `output` A file for output result. By default output is in STDOUT\n * **Array** `declaration` List of filenames for declarations (required)\n\n##### BEM.decl.subtract()\n\nSubtracting the next declarations from the first one.\n\n###### Options\n\n * **String** `output` A file for output result. By default output is in STDOUT\n * **Array** `declaration` List of filenames for declarations (required)\n\n## Contribute to development \n\n### Executing autotests \n\nTo verify that your changes do not break existing functionality we recommend to run autotests and check that all of them pass. You can do that by executing the following command in the root of the project:\n\n    mocha \n\n### Running autotests with test coverage report\n\nYou can check the level of the code coverage by tests using the command: \n\n    make test-cover\n\nThen open coverage.html file in a browser. Code lines which have not been executed during the tests run will be marked red.\n\n\u003c!-- Yandex.Metrika counter --\u003e\n\u003cimg src=\"//mc.yandex.ru/watch/12831025\" style=\"position:absolute; left:-9999px;\" alt=\"\" /\u003e\n\u003c!-- /Yandex.Metrika counter --\u003e\n","funding_links":[],"categories":["Archived","📦 Legacy \u0026 Inactive Projects"],"sub_categories":["General Dev Tools"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbem-archive%2Fbem-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbem-archive%2Fbem-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbem-archive%2Fbem-tools/lists"}