JSPM

  • Created
  • Published
  • Downloads 62
  • Score
    100M100P100Q114687F
  • License MPL-2.0

Walk easily thru BEM file structure

Package Exports

  • @bem/sdk.walk

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@bem/sdk.walk) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

walk

Tool for traversing a BEM project's file system.

NPM Status

It returns the following information about found files:

Quick start

Note To use @bem/sdk.walk, you must install Node.js 4.0+.

1. Install package

$ npm install --save @bem/sdk.walk

2. Import default module

Create a JavaScript file with any name and add the following string:

const walk = require('@bem/sdk.walk');

Note You will use this JavaScript file for all the following steps.

3. Define file system levels

Define the project's file system levels in the config object.

const config = {
    // project levels
    levels: {
        'lib/bem-core/common.blocks': {
            // `naming` — file naming scheme
            naming: 'two-dashes'
        },
        'common.blocks': {
            // `scheme` — file system scheme
            scheme: 'nested'
        }
    }
};

Specify either the file naming scheme or the file system type for each level. This lets you get information about BEM entities using their names or using the names of files and directories.

The table shows the possible values that can be set for each of the schemes.

Key Scheme Default value Possible values
naming File naming origin origin, two-dashes
scheme File system nested nested, flat

More information:

Note Instead of defining the project's levels manually, use the config module.

const config = require('@bem/sdk.config')();
const levelMap = config.levelMapSync();
const stream = walk(levels, { levels: levelMap });

4. Define the paths to traverse

Specify the paths to walk in the levels object.

Path options:

  • Relative to the root directory.

    const levels = [
        'libs/bem-core/common.blocks',
        'common.blocks'
    ];
  • Absolute.

    const levels = [
        '/path/to/project/lib/bem-core/common.blocks',
        '/path/to/project/common.blocks'
    ];

5. Get information about found files

Pass the walk() method the levels and config objects.

Streaming is used for getting data about found files. When a portion of data is received, the data event is generated and information about the found file is added to the files array. If an error occurs, walk stops processing the request and returns a response containing the error ID and description. The end event occurs when all the data has been received from the stream.

const files = [];

const stream = walk(levels, config);
// adds information about a found file to the end of the "files" array
stream.on('data', file => files.push(file));

stream.on('error', console.error);

stream.on('end', () => console.log(files));

Complete code sample

When all these steps have been completed, the full code of the JavaScript file should look like this:

const walk = require('@bem/sdk.walk');
const config = require('@bem/sdk.config')();
const levels = [
    'libs/bem-components/common.blocks',
    'common.blocks'
];
const files = [];

const stream = walk(levels, {
        levels: config.levelMapSync()
    })
    .on('data', file => files.push(file))
    .on('error', console.error)
    .on('end', () => console.log(files));

Note This sample uses the bem/sdk.config package.

API

walk method

walk(levels, config);

Description

Traverses the directories described in the levels parameter and returns stream.Readable.

Input parameters

Requirements for the search are defined in the levels and config parameters.

Parameter Type Description
levels string[] Paths to traverse
config object Project levels

Output data

Readable stream (stream.Readable) that has the following events:

Event Description
'data' Returns a JavaScript object with information about a found file.

The example below shows a JSON interface with elements that are in the response for the walk method. Objects and keys have sample values.

Example

{
  "cell": {
    "entity": { "block": "page" },
    "layer": "libs/bem-core/desktop.blocks",
    "tech": "bemhtml"
  },
  "path": "libs/bem-core/desktop.blocks/page/page.bemhtml.js"
}

cell — BEM cell instance.
entity — BEM entity name instance.
layer — Directory path.
tech — Implementation technology.
path — Relative path to the file.
'error' Generated if an error occurred while traversing the levels. Returns an object with the error description.
'end' Generated when walk finishes traversing the levels defined in the levels object.

Usage examples

Typical tasks that use the resulting JavaScript objects:

Grouping

Grouping found files by block name.

const walk = require('@bem/sdk.walk');
const config = require('@bem/sdk.config')();
const util = require('util');
const levels = [
    'libs/bem-components/common.blocks',
    'common.blocks'
];
const groups = {};

const stream = walk(levels, {
        levels: config.levelMapSync()
    })
    .on('data', file => {
        // Getting the block name for a found file.
        const block = file.entity.block;

        // Adding information about the found file.
        (groups[block] = []).push(file);
    })
    .on('error', console.error)
    .on('end', () => console.log(util.inspect(groups, {
        depth: null
    })));

/*
{ button:
   [ BemFile {
      cell: BemCell {
         entity: BemEntityName { block: 'button', mod: { name: 'togglable', val: 'radio' } },
         tech: 'spec.js',
         layer: 'libs/bem-components/common.blocks'
      },
      path: 'libs/bem-components/common.blocks/button/_togglable/
        button_togglable_radio.spec.js' } ] },
 ...
}
*/

Filtering

Finding files for the popup block.

const walk = require('@bem/sdk.walk');
const config = require('@bem/sdk.config')();
const levels = [
    'libs/bem-components/common.blocks',
    'common.blocks'
];
const files = [];

const stream = walk(levels, {
        levels: config.levelMapSync()
    })
    .on('data', file => {
        // Getting the block name for a found file.
        const block = file.entity.block;

        // Adding information about the found file.
        if (block == 'popup') {
            files.push(file);
        }
    })
    .on('error', console.error)
    .on('end', () => console.log(files));

/*
[BemFile {
   cell: BemCell {
     entity: BemEntityName { block: 'popup', mod: { name: 'target', val: true } },
     tech: 'js',
     layer: 'libs/bem-components/common.blocks'
   },
   path: 'libs/bem-components/common.blocks/popup/_target/popup_target.js'
},
...
]
*/

Transformation

Finding BEM files, reading the contents, and creating the new source property.

const fs = require('fs');
const walk = require('@bem/sdk.walk');
const config = require('@bem/sdk.config')();
const stringify = require('JSONStream').stringify;
const through2 = require('through2');
const levels = [
    'libs/bem-components/common.blocks',
    'common.blocks'
];

const stream = walk(levels, {
        levels: config.levelMapSync()
    })
    .pipe(through2.obj(function(file, enc, callback) {
        try {
            // Certain technologies (for example, `i18n`) might be directories instead of files.
            if (fs.statSync(file.path).isFile()) {
                // Writing the file content to the `source` field.
                file.source = fs.readFileSync(file.path, 'utf-8');
                this.push(file);
            }

        } catch (err) {
            callback(err);
        }
    }))
    .pipe(stringify())
    .pipe(process.stdout);

/*
[{"cell":{
    "entity":{"block":"search","elem":"header"},
    "tech":"css",
    "layer":"common.blocks"
  },
  "path":"common.blocks/search/__header/search__header.css",
  "source":".search__header {\n\tdisplay: block;\n\tfont-size: 20px;\n\tcolor:
  rgba(0,0,0,0.84);\n\tmargin: 0;\n\tpadding: 0 0 16px;\n\n}\n\n"},
...
]
*/