GithubHelp home page GithubHelp logo

bem-sdk-archive / bem-decl Goto Github PK

View Code? Open in Web Editor NEW
11.0 9.0 3.0 209 KB

:capital_abcd: Manage declaration of BEM entities. DEPRECATED →

Home Page: https://github.com/bem/bem-sdk/tree/master/packages/decl

License: Other

JavaScript 100.00%
bem bem-decl bem-cell

bem-decl's Introduction

bem-decl

The library contains a number of methods to work with sets of BEM-entities, aka BEMDECL files.

NPM Status Travis Status Coverage Status Dependency Status

Requirements

Installation

This library is distributed on npm. In order to add it as a dependency, run the following command in your project directory:

npm install --save bem-decl

Note Node comes with npm installed so you should have a version of npm.

Usage

const bemDecl = require('bem-decl');

// Since we using sets stored in files we need to load them asynchronously
async function() {
    // Await loading of file and put it to `set1` variable
    // Note: There are few formats of declaration files but bem-decl here to read them all
    const set1 = await bemDecl.load('set1.bemdecl.js');
    // File set1.bemdecl.js:
    // → exports.blocks = [
    // →     {name: 'button', elems: [{name: 'control'}, {name: 'icon'}]}
    // → ];

    // `set1` is an array of BemCell objects,
    // convert them to strings using `.map` and special `id` property:
    set1.map(c => c.id);
    // → [ 'button', 'button__control', 'button__icon' ]

    // Let's load another set:
    const set2 = await bemDecl.load('set2.bemdecl.js');
    // File set2.bemdecl.js:
    // → exports.deps = [
    // →     {block: 'button', elem: 'icon'},
    // →     {block: 'link', mods: {theme: 'normal'}}
    // → ];

    set2.map(c => c.id);
    // → [ 'button__icon', 'link', 'link_theme', 'link_theme_normal' ]

    // To subtract one set from another just use `.subtract` method:
    bemDecl.subtract(set1, set2).map(c => c.id);
    // → [ 'button', 'button__control' ]

    // Result will be different if we swap arguments (as expected):
    bemDecl.subtract(set2, set1).map(c => c.id);
    // → [ 'link', 'link_theme', 'link_theme_normal' ]

    // To merge two sets use `.merge` method:
    bemDecl.merge(set1, set2).map(c => c.id);
    // → [ 'button', 'button__control', 'button__icon',
    // →   'link', 'link_theme', 'link_theme_normal' ]

    // Also there is `.intersect` method to calculate intersection between them:
    bemDecl.intersect(set1, set2).map(c => c.id);
    // → [ 'button__icon' ]
}

BEMDECL formats

There are several formats:

  • 'v1' — the old BEMDECL format, also known as exports.blocks = [ /* ... */ ].
  • 'v2' — the format based on deps.js-files, also known as exports.deps = [ /* ... */ ].
  • 'enb' — the legacy format for widely used enb deps reader.

Note bem-decl controls all of them.

API

load method

Loads BEM-entities from a file in any format.

Syntax

load(file[, options])

Input parameters

Parameter Type Description
file string bemdecl.js-filename or path to the file.
Examples:
example.bemdecl.js;
./desktop.bundles/example/example.bemdecl.js.
options * � encoding String, Null (default = null);
� flag String (default = 'r').
Read more.

Output data

A promise that represents BemCell[]. Read more about BemCell.

Example

bemDecl.load('set1.bemdecl.js')
    .then(decl => {
        // Work with declaration
    });

save method

Formats and saves a file with BEM-entities from a file in any format

Syntax

save(file, decl, opts)

Input data

Parameter Type Description
file string bemdecl.js-filename or path to the file.
Examples:
example.bemdecl.js;
./desktop.bundles/example/example.bemdecl.js.
decl BemCell[] Set of BEM-entities to save in specific format.
options Object Options for stringify and saveFile methods.
� format String; � exportType String (default = 'cjs');
� encoding String (default = 'utf8');
� flag String (default = 'r').
Read more.

Output data

A promise resolved when file was stored.

Example

const decl = [
    new BemCell({ entity: new BemEntityName({ block: 'button' }) })
];
bemDecl.save('set1.bemdecl.js', decl, { format: 'enb' })
    .then(() => {
        console.log('saved');
    });

merge method

Merges many sets of BEM-entities into one.

Syntax

merge(set1, set2, ...)

Input parameters

Parameter Type Description
set1, set2, ... BemCell[] Sets of BEM-entities. Read more.

Output data

A new set of BEM-entities (BemCell[]).

Example

const decl1 = [
    new BemCell({ entity: new BemEntityName({ block: 'button' }) })
];

const decl2 = [
    new BemCell({ entity: new BemEntityName({ block: 'link' }) })
];

const decl3 = [
    new BemCell({ entity: new BemEntityName({ block: 'button' }) }),
    new BemCell({ entity: new BemEntityName({ block: 'link' }) })
];

bemDecl.merge(decl1, decl2, decl3).map(c => c.id);

// → ['button', 'link']

intersect method

Calculates the set of BEM-entities that exists in each passed set.

Syntax

intersect(set1, set2, ...)

Input parameters

Parameter Type Description
set1, set2, ... BemCell[] Sets of BEM-entities. Read more.

Output data

A new set of BEM-entities (BemCell[]).

Example

const decl1 = [
    new BemCell({ entity: new BemEntityName({ block: 'button' }) }),
    new BemCell({ entity: new BemEntityName({ block: 'select' }) })
];

const decl2 = [
    new BemCell({ entity: new BemEntityName({ block: 'button' }) }),
    new BemCell({ entity: new BemEntityName({ block: 'link' }) })
];

const decl3 = [
    new BemCell({ entity: new BemEntityName({ block: 'button' }) }),
    new BemCell({ entity: new BemEntityName({ block: 'attach' }) })
];

bemDecl.intersect(decl1, decl2, decl3).map(c => c.id);

// → ['button']

subtract method

Calculates the set of BEM-entities that occur only in the first passed set and does not exist in the rest.

Syntax

subtract(set1, set2, ...)

Input parameters

Parameter Type Description
set1, set2, ... BemCell[] Sets of BEM-entities. set1 is the main set. Read more.

Output data

A new set of BEM-entities (BemCell[]).

Example

const decl1 = [
    new BemCell({ entity: new BemEntityName({ block: 'button' }) }),
    new BemCell({ entity: new BemEntityName({ block: 'select' }) }),
    new BemCell({ entity: new BemEntityName({ block: 'link' }) })
];

const decl2 = [
    new BemCell({ entity: new BemEntityName({ block: 'link' }) })
];

const decl3 = [
    new BemCell({ entity: new BemEntityName({ block: 'select' }) })
];

bemDecl.subtract(decl1, decl2, decl3).map(c => c.id);

// → ['button']

parse method

Parses raw string or evaluated JS object to a set of BEM-entities.

Syntax

parse(bemdecl)

Input parameters

Parameter Type Description
bemdecl string | Object Declaration of BEM-entities.

Output data

Set of BEM-entities (BemCell[]).

Example

bemDecl.parse('exports.deps = [{ block: "button" }]').map(c => c.id);

// → ['button']

See also Declarations in BEM.

stringify method

Stringifies set of BEM-entities to a specific format.

Note Temporary there is just enb format. It will be fixed later.

Syntax

stringify(set, options)

Input parameters

Parameter Type Description
set BemCell[] Representation of BEM-entity.
options Object Example: {format: 'enb'}
options.format String Format of the output. Example: 'enb'
options.exportType String Type of output wrapper. Example: 'json5'
options.space `String Number`

Output data

String.

Example

const decl = [
    new BemCell({ entity: new BemEntityName({ block: 'button' }) })
];

bemDecl.stringify(decl, { format: 'enb', exportType: 'commonjs' });
 
// → module.exports = {
// →     "format": "enb",
// →     "decl": [
// →         {
// →             "block": "block"
// →         }
// →     ]
// → };

Contributing

Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.

Versioning

We use SemVer for versioning. For the versions available, see the tags on this repository.

Authors

  • Andrew Abramov (Initial workblond).

See also the full list of contributors who participated in this project.

You may also get it with git log --pretty=format:"%an <%ae>" | sort -u.

License

Code and documentation copyright © 2014-2017 YANDEX LLC. Code released under the Mozilla Public License 2.0.

bem-decl's People

Contributors

blond avatar godfreyd avatar greenkeeper[bot] avatar greenkeeperio-bot avatar qfox avatar skad0 avatar tadatuta avatar yeti-or avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bem-decl's Issues

Serialize

The reverse process of normalization. The method serialize should process declaration specific to each format.

BEMDECL 1.0

var serialize = require('bem-decl').serialize,
    decl = [
        { name: 'block', elems: [{ name: 'elem-1' }] }],
        { name: 'block', elems: [{ name: 'elem-2' }] }]
    ];

serialize(decl, { version: '1.0' });
// [{ name: 'block', elems: [{ name: 'elem-1' }, { name: 'elem-2' }] }]

BEMDECL 2.0

var serialize = require('bem-decl').serialize,
    decl = [
        { block: 'block' }],
        { block: 'block', elem: 'elem-1' }],
        { block: 'block', elem: 'elem-2' }]
    ];

serialize(decl, { version: '2.0' });
// [{ block: 'block', elems: ['elem-1', 'elem-2'] }]

BEMDECL next

var serialize = require('bem-decl').serialize,
    decl = [
        { block: 'block' }],
        { scope: 'block', elem: 'elem-1' }],
        { scope: 'block', elem: 'elem-2' }]
    ];

serialize(decl, { version: 'next' });
// [{ block: 'block', elems: ['elem-1', 'elem-2'] }]

Translate

Methods:

  • translate(decl, opts)

The method is to translate a declaration from one format to another.

var translate = require('bem-decl').translate,
    decl = [
        { block: 'block' }
    ];

translate(decl, {
    from: '2.0',
    to: '1.0'
});
// [{ name: 'block' }]

BEMDECL next

For the experimental version to use next value.

Now:

var normalize = require('bem-decl').normalize,
    decl = [{ block: 'block-1' }];

normalize(decl, { harmony: true });

Need:

var normalize = require('bem-decl').normalize,
    decl = [{ block: 'block-1' }];

normalize(decl, { version: 'next' });

Describe BEMDECL 1.x

It should be a very detailed description of the BEMDECL 1.x format of declaration. The description should include:

  • All cases
  • Problems
  • Shortcats

Part of the description can be found at NDA.

Update stringify method

API:

/**
 * @param {BemCell[]} decl 
 * @param {Object} opts
 * @param {String} opts.exportType - can be one of 'cjs', 'json5', 'json', 'es6'
 * @param {String} opts.format - v1, v2, enb
 * @returns {String}
*/

Description:

opts.format defines how to format normalized declaration:

  • v1 - export formatted decl for v1 format with blocks field
  • v2 - export formatted decl for v2 format with decl field
  • enb - export formatted decl for enb format with deps field

opts.exportType defines how to wrap stringified declaration:

  • cjs - in commonJS module
  • json5
  • json
  • es6 - export default (not right now)

Returned string is representation of object with fields format and formatted decaration (name is defined by opts.format.

Usage:

Use at save with opts.exportType = 'cjs' by default.

Wildcards

Support wildcards for next format.

Methods:

  • glob(decl, callback)
  • globSync(decl)

The method should to fill declaration entities by file system.

.
├── common.blocks/
│   └── block/
│       ├── _mod/
│       │   ├── block_mod_val-1.css
│       │   └── block_mod_val-2.css
│       ├── __elem-1/
│       └── __elem-2/
└── bemconf.json
var glob = require('bem-decl').globSync,
    blocks = [{ block: '*' }],
    mods = [{ scope: 'block', mods: { mod: '*' } }],
    elems = [{ scope: 'block', elems: '*' }];

glob(blocks); // { block: 'block' }
glob(mods);   // { scope: 'block', mods: { mod: ['val-1', 'val-2'] } }
glob(elems);  // { scope: 'block', elems: ['elem-1', 'elem-2'] }

Implement `parse` method to parse data in files

Ref: #6

Methods:

  • parse(data: {version: ?string, blocks: ?object[], decl: ?object[]): BEMEntityParts[]

The method should determine the format of the file content.

BEMDECL 1.0

exports.blocks = [
    { name: 'block' }
];

or

exports.version = '1.0';
exports.decl = [
    { name: 'block' }
];

BEMDECL 2.0

exports.version = '2.0';
exports.decl = [
    { block: 'block' }
];

BEMDECL next

exports.version = 'next';
exports.decl = [
    { block: 'block' }
];

The method should translate any format to normalized BEMDECL 2.0.

var parse = require('bem-decl').parse;

// bemdecl-1.0.js
// exports.blocks = [
//     { name: 'block' }
// ];

parse(fs.readFileSync('bemdecl-1.0.js')); // [{ block: 'block' }]

Public Normalize

The method normalize should process declaration specific to each format.

BEMDECL 1.0

var normalize = require('bem-decl').normalize,
    decl = [{ name: 'block', elems: [{ name: 'elem-1' }, { name: 'elem-2' }] }];

normalize(decl, { version: '1.0' });
// [
//     { name: 'block', elems: [{ name: 'elem-1' }] }],
//     { name: 'block', elems: [{ name: 'elem-2' }] }]
// ]

BEMDECL 2.0

var normalize = require('bem-decl').normalize,
    decl = [{ block: 'block', elems: ['elem-1', 'elem-2'] }];

normalize(decl, { version: '2.0' });
// [
//     { block: 'block' }],
//     { block: 'block', elem: 'elem-1' }],
//     { block: 'block', elem: 'elem-2' }]
// ]

BEMDECL next

var normalize = require('bem-decl').normalize,
    decl = [{ block: 'block', elems: ['elem-1', 'elem-2'] }];

normalize(decl, { version: 'next' });
// [
//     { block: 'block' }],
//     { scope: 'block', elem: 'elem-1' }],
//     { scope: 'block', elem: 'elem-2' }]
// ]

Format to BEMDECL v2

const decl = require('@bem/decl');
const BemCell = require('@bem/cell');

const cells = [new BemCell({ entity: { block: 'button' }, tech: 'css'  })];

decl.format(cells, { format: 'v2' });

// [{ block: 'button' }]

Format to BEMDECL v1

const decl = require('@bem/decl');
const BemCell = require('@bem/cell');

const cells = [new BemCell({ entity: { block: 'button' }, tech: 'css'  })];

decl.format(cells, { format: 'v1' });

// [{ name: 'button' }]

make possible to work with browserify

current obstacle is:

lib/index.js:

load: require('./load'),

lib/load.js:

const fs = require('graceful-fs');

ll be cool, if lib/index.js ll not agregate all lib modules into itself

Describe BEMDECL 2.x

It should be a very detailed description of the BEMDECL 2.x format of declaration. The description should include:

  • All cases
  • Problems
  • Shortcats

Part of the description can be found at bem.info and NDA.

File List by Declaration

Methods:

  • toFiles
  • toFilesSync

The method should get files by declaration.

.
├── common.blocks/
│   └── block/
│       ├── block.css/
│       └── block.js/
└── bemconf.json
var toFiles = require('bem-decl').toFilesSync,
    decl = [
        { block: 'block' }
    ];

toFiles(decl); 
// [
//     'common.blocks/block/block.css',
//     'common.blocks/block/block.js'
// ]

Private Normalize

Remove normalize method of the public API and rename to _normalize.

User should not work with private format of declaration. This private format is something like a AST for bem-decl package.

String Only Format

BEMDECL next should support string only format of declaration.

var normalize = require('bem-decl').normalize,
    decl = [
        'block',
        'block_mod',
        'block_mod-name_mod-val',
        'block__elem'
    ];

normalize(decl, { version: 'next' });
// [
//     { block: 'block' }],
//     { scope: 'block', modName: 'mod', modVal: true }],
//     { scope: 'block', modName: 'mod-name', modVal: 'mod-val' }],
//     { scope: 'block', elem: 'elem' }]
// ]

This format should support custom naming conventions.

var normalize = require('bem-decl').normalize,
    csswizardry = { elem: '__', mod: '--' },
    decl = [
        'block',
        'block--mod',
        'block__elem'
    ];

normalize(decl, { version: 'next', naming: csswizardry });
// [
//     { block: 'block' }],
//     { scope: 'block', modName: 'mod', modVal: true }],
//     { scope: 'block', elem: 'elem' }]
// ]

Save File

Methods:

  • save(filename, decl): Promise
  • save(filename, decl, opts): Promise

By default, the file must be recorded in the BEMDECL 2.0 format.

var save = require('bem-decl').save,
    decl = [
        new BemCell({ entity: new BemEntityName({ block: 'block' }) })
    ];

save('bemdecl.js', decl);
// exports.format = 'v2';
// exports.decl = [
//     { block: 'block' }
// ];

If you want to record the declaration in a different format, you will need to use the option format.

var save = require('bem-decl').save,
    decl = [
        new BemCell({ entity: new BemEntityName({ block: 'block' }) })
    ];

save('bemdecl.js', decl, { format: 'v1' });
// exports.format = 'v1';
// exports.decl = [
//     { name: 'block' }
// ];

normalize2 should process unscoped entities

normalize({
    elems: ['close'],
    mods: {theme: 'protect'}
})

should return

[
    {entity: {block: null}}
    {entity: {block: null, elem: 'close'}}
    {entity: {block: null, modName: 'theme', modVal: 'protect'}}
]

but returns just:

[
    {entity: {block: undefined, modName: 'theme', modVal: 'protect'}}
]

cc @Yeti-or

BEMDECL 1.0

Rename current format by default to BEMDECL 1.0.

Think about invalid cases in v2

He said:

Хорошо бы подумать про обработку невалидных кейсов, которые, не указаны в SchemeJSON.

We have to do it here.

Option `version`

var normalize = require('bem-decl').normalize,
    decl1 = [{ name: 'block-1' }],
    decl2 = [{ block: 'block-1' }];

normalize(decl1, { version: '1.0' });
normalize(decl2, { version: '2.0' });

Need support semver to use 1.x, 2.x and other values.

Quick Start

In addition to a brief description should describe how to get to the library for Node.js.

Describe API

See: bem/bem-sdk#23

Note: Don't forget to specify which methods are available only for use with Node.js and will not be available in the browser.

Use BemCell

https://github.com/bem-sdk/bem-cell

In publick API:

  • format(decl: BemCell[], opts: {format: 'v1'|'v2'|'enb'}): *
  • stringify(BemCell[], {format: String}): String
  • merge(BemCell[], BemCell[], ...): BemCell[])
  • intersect(BemCell[], BemCell[], ...): BemCell[]
  • subtract(BemCell[], BemCell[]): BemCell[])

In private API:

  • assign(cell: BemCell, scope: BemEntityName): BemCell
  • normalize(*, {format: String}): BemCell[]

UPD:

  • assign(cell: {entity: BemCell-like, scope: BemCell): BemCell

Support true bemcell algebra

Cross tech decl algebra:

// U — merge
[{ entity: A }] U [{ entity: A, tech: '1' }] 
     [{ entity: A }, { entity: A, tech: '1' }] // Because any tech can be not '1' in result
[{ entity: A, tech: '1' }] U [{ entity: A, tech: '2' }] 
     [{ entity: A, tech: '1' }, { entity: A, tech: '2' }]

// / — subtract
[{ entity: A, tech: 'specified' }] / [{ entity: A }]  []
[{ entity: A, layer: 'specified' }] / [{ entity: A }]  []
[{ entity: A }] / [{ entity: A, tech: 'specified' }]  ERROR
[{ entity: A }] / [{ entity: A, layer: 'specified' }]  ERROR
[{ entity: A, tech: 'specified' }] / [{ entity: A, layer: 'specified' }]  ERROR
[{ entity: A, layer: 'specified' }] / [{ entity: A, tech: 'specified' }]  ERROR

// П — intersect
[{ entity: A }] П [{ entity: A, tech: 'specified' }]  [{ entity: A, tech: 'specified' }]
[{ entity: A, tech: '1' }] П [{ entity: A, tech: '2' }]  []
[{ entity: A, tech: '1' }] П [{ entity: A, layer: 'l' }]  [{ entity: A, tech: '1', layer: 'l' }]

Read File

Methods:

  • read(filename, callback)
  • readSync(filename)

The method should determine the format of the file content.

BEMDECL 1.0

exports.blocks = [
    { name: 'block' }
];

or

exports.version = '1.0';
exports.decl = [
    { name: 'block' }
];

BEMDECL 2.0

exports.version = '2.0';
exports.decl = [
    { block: 'block' }
];

BEMDECL next

exports.version = 'next';
exports.decl = [
    { block: 'block' }
];

The method should translate any format to normalized BEMDECL 2.0.

var read = require('bem-decl').readSync;

// bemdecl-1.0.js
// exports.blocks = [
//     { name: 'block' }
// ];

read('bemdecl-1.0.js'); // [{ block: 'block' }]

Add consistent mod/val for elems

We have possibility to write
{ block, mod, val }

But in case of elems it doesn't supported.

{
    block: 'block',
    elems: [
        { elem: 'elem', mod: 'modname', val: 'modval' }
    ]
}

Support browsers

bem-decl should work in browsers and contain all not fs-specific methods:

  • normalize
  • serialize
  • merge
  • subtract
  • intersect

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.