draft
Content:
## How to write any bem-tools plugin
Plugin name rule: %editor%-bem-%name%.
Every single plugin from %editor%-bem-tools family MUST NOT have separate menu group and it MUST place own actions items in common bem-tools menus groups.
Every context menu SHOULD has config display option (user can disable every unnecessary context menu).
Context menu item MUST be named as plugin action, e.g. Create BEM block (not bem-create). One plugin can has a few actions.
### Menus > `Editor app menu` is an top OS app menu.TODO: Move into bem-create repo and crosslink ref.
> `Editor Buffer` is an editor file content canvas.
-
Put into
Packagesor similar top app menu group an item named asBEM Toolswith subitems:Create BEM Block— Recognize active editor app pane (tree view or editor canvas), then callcreate_by_text_selectionorcreate_under_text_cursororcreate_under_tree_cursormethod.- TBD
-
Put into Editor Buffer context menu items in top and bottom separators:
Create BEM Block— Callcreate_by_text_selectionorcreate_under_text_cursormethod.- TBD
-
Put into Editor Tree View context menu items in top and bottom separators:
Create BEM Block— Callcreate_under_tree_cursormethod.- TBD
Place BEM Tools items group at the middle of a context menu.
### Editor Buffer magic **Note** `Editor Buffer` is an editor file content canvas.This spec's section describes parsing bem entities process and its stages order.
See reference library implementation draft and tests cases also.
- Bemjson detection under cursor Stage
The corner cases list:
Note Here # is an Editor Buffer any symbols set.
#{ block: 'block' }## <-- File content part
^^ ^ ^^
12 3 45 <-- Cursor positions1, 5 — skip the Stage,
2, 3, 4 — grab the block.
Note Plain Objects MUST be skiped in favor of parent bemjson if present
#{ block: 'block', mods: {mod:'val'} }##
. ^^^ ^^
. 123 451, 2, 3, 4, 5 — grab block_mod_val,
Also, 2, 3, 4 — skip an Object.
#{ block: 'block' }###{foo: 'bar'}#
. ^^ ^^^ ^^^
. 12 345 6781 — grab the block,
2, 3, 4, 5, 6, 7, 8 — skip the Stage,
Also, 4, 5, 6, 7 — skip an Object.
#{foo: 'bar'}#
^^^
1231, 2, 3 — skip the Stage,
Also, 2, 3 — skip an Object.
Note a mix property MUST be omitted. {block: 'block', mix: {block:'mix'}} --> block
Note a bemjson in mix property MUST be parsed as a target bemjson without seek a parent bemjson.
Note a partial bemjson MUST be parsed as a target bemjson (bem-create MUST use curent block path context). See partial-bemjson in naming section.
{ block: 'block', mix: [{elem:'mix'}] }
. ^ ^^^^ ^^^
. 1 2345 6781, 2, 3, 8 — grab the block,
Also, 8 — skip lefthand outer bemjson,
4, 5, 6, 7 — grab __mix.
Note bemjson in any quoted strings and comments MUST be parsed too.
Note multiline bemjson MUST be parsed as well.
Note bemjson in any valid JavaScript Expressions MUST be parsed. bemjson in invalid Expressions SHOULD be parsed.
A few examples:
MUST be parsed:
`var o = {
block: 'block'
}, qux = 42;`SHOULD be parsed:
"int o=={ block: 'block' }qux?=42!##;"- Bemslug detection under cursor Stage
Note Here # is an Editor Buffer [^a-zA-Z0-9_-] symbols set.
#block__elem_mod_val##
^^ ^ ^^
12 3 451, 5 — bementity is not found,
2, 3, 4 — grab the block__elem_mod_val.
- Bemjson detection in selection Stage
Parse and verify selection as a bemjson
- Bemslug detection in selection Stage
Parse and verify selection as a bemslug
#### Under cursor bemjson detector AlgorithmLocal/ad-hoc/backward AST-builder/Lexer. Current Lexer doesn't parse all the Editor Buffer's text (it may be broken or it may be not js).
Lexer traverses source code right-to-left looking up target node's left boundary.
Then Lexer tries to build AST from left boundary up to first unexpected symbol.
Step by step algo:
- Locate first odd lefthand opening curly bracket (
FIRST_O_CURL).
In other words, if first lefthand curly bracket is closing then skip it with next opening brace and so on).
### { ## { # { ############# } } # } ## some trash ##
. ^-- FIRST_O_CURL ^-- CURSOR-
Call fullfeatured AST-builder (e.g. Acorn) at
FIRST_O_CURLoffset. -
Trim righthand trailing content (if AST-builder raised an error) from error's pos to end.
P.S. Error meta contains error.pos property (is an first mistaken symbol offset).
### { ## { # { ########### } } # } ## some trash ##
---| |------------------
^-- offset ^-- Code Snippet Area ^-- trailing content- Rerun AST-builder then run AST-traverse Depth-first search.
- Stop at every
ObjectExpressionthen check is it a bemjson.
Stop traverse if true. Check parent else (if not checked earlier) then if parent isn't exist then enlarge Code Snippet Area (set lefthand offset to previous FIRST_O_CURL position) then goto 2 once.
- Convert AST node into bemjson JavaScript Object and return it if found or return
nullelse. - If
bemjson-declorbemjson-defliterals present then convert them intobementityliteral. Read more aboutbemjson-*,bementity. - Call bem-create with found
bementityliteral.
See BEM techs declarators section.
TBD
### Config *TBD*TBD
TBD
## Run library from not a javascript world There are common libraries for plugins, e.g. `bem-tools/bem-tools/editor-buffer-bem-parser`.If you write plugin for not js-based editor:
- Java: Try out something like this: http://stackoverflow.com/q/14320308/2953419
- Other: Try your variant of
exec('node bem-tools-plugin/match-bem-entity file.js --row 1 --column 5')
Read more practical naming article also.
Read more practical bem methodology articles also.
Default (yandex style) separators scheme:
__(underscore, underscore) — elem_(underscore) — mod-(minus) — block name pseudo namespace
Much more formal bem-naming spec (BNF variant):
FULL_BEMSLUG ::= BLOCK_NAME | BLOCK_NAME ELEM_DECL | BLOCK_NAME MOD_DECL
ELEM_DECL ::= "__" ELEM_NAME | "__" ELEM MOD_DECL
MOD_DECL ::= "_" MOD_NAME | "_" MOD_NAME "_" MOD_VAL
BLOCK_NAME ::= BLOCK_NAME | BLOCK_NAME "-" BLOCK_SUB_NAME
ELEM_NAME ::= EXTENDED_IDENTIFIER
MOD_NAME ::= EXTENDED_IDENTIFIER
MOD_VAL ::= EXTENDED_IDENTIFIER
BLOCK_NAME ::= IDENTIFIER
BLOCK_SUB_NAME ::= IDENTIFIER
IDENTIFIER ::= [a-z0-9_] | IDENTIFIER
EXTENDED_IDENTIFIER ::= [a-z0-9_-] | EXTENDED_IDENTIFIERExamples:
suggest2-item__icon_size_m—( BLOCK_NAME "-" BLOCK_SUB_NAME ) ( "__" ELEM_NAME ( "_" MOD_NAME "_" MOD_VAL ) )
Popular alternative schemes:
Mixed dashes style (named Harry Roberts):
--(minus, minus) — elem_(underscore) — mod-(minus) — block name pseudo namespace
Read more about alternative schemes [en] [ru].
### Complete formed BEM blocks literalsNames list for programming and speaking:
- bemslug {String}
'block__elem_mod_val' - bemjson-name {Object}
{block: 'block', elem: 'elem', modName: 'mod', modVal: 'val'}— single block applicator/matcher declaration - bemjson-decl {Object}
{block: 'block', elem: 'elem', elemMods: {mod:'val', mod2: 'val2'}}— plural blocks applicator/matcher declaration - bemjson-def {Object}
{block: 'block', elem: 'elem', elemMods: {mod:'val'}, content: [...],,,}— general bemjson block definition- bemjson-tree {Object}
{block: 'block', elem: 'elem', elemMods: {mod:'val'}, content: [...], mix: [{...},,,]}— bemtree block definition - bemjson-html {Object}
{block: 'block', elem: 'elem', elemMods: {mod:'val'}, attrs: {...}, content: [...],,,}— bemhtml block definition
- bemjson-tree {Object}
bemjson- constrains*:
Correct bemjson-decl and bemjson-def forms:
{block:_,,,}
{block:_, mods:_,,,}
{block:_, elem:_,,,}
{block:_, elem:_, elemMods:_,,,}
Correct bemjson-def forms:
{block:_, elem:_, mods:_,,,} — where block,elem is a matcher part (what we use), mods is a body part (what we change)
Other therms:
applicator— call by name referencematcher— pattern mathing rulebody— declarative bem definition (what new will be added/changed)slug— short notation, //wiki/slug
Other therms:
bemjson-tree context— parents' bemjson-def properties Object.
TODO
bementity
bemfile
{ entity: bementityname, tech: 'js/css/ilolo', path: String, level: String }deps