├── .editorconfig
├── .eslintrc.js
├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE
├── README.md
├── index.js
├── lib
├── css.js
├── html.js
└── snippets-registry.js
├── package-lock.json
├── package.json
├── rollup.config.js
└── test
├── config.js
├── css.js
├── html.js
└── sample-config.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = tab
5 | indent_size = 4
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.{json,yml}]
12 | indent_style = space
13 | indent_size = 2
14 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "env": {
3 | "es6": true,
4 | "node": true,
5 | "mocha": true,
6 | "browser": true
7 | },
8 | "extends": "eslint:recommended",
9 | "parserOptions": {
10 | "sourceType": "module"
11 | },
12 | "rules": {
13 | "indent": [
14 | "error",
15 | "tab"
16 | ],
17 | "linebreak-style": [
18 | "error",
19 | "unix"
20 | ],
21 | "quotes": [
22 | "error",
23 | "single"
24 | ],
25 | "semi": [
26 | "error",
27 | "always"
28 | ],
29 | "no-cond-assign": "off",
30 | "no-empty": [
31 | "error",
32 | { "allowEmptyCatch": true }
33 | ],
34 | "no-console": "warn"
35 | }
36 | };
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # nyc test coverage
18 | .nyc_output
19 |
20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21 | .grunt
22 |
23 | # node-waf configuration
24 | .lock-wscript
25 |
26 | # Compiled binary addons (http://nodejs.org/api/addons.html)
27 | build/Release
28 |
29 | # Dependency directories
30 | node_modules
31 | jspm_packages
32 |
33 | # Optional npm cache directory
34 | .npm
35 |
36 | # Optional REPL history
37 | .node_repl_history
38 | /dist
39 | .DS_Store
40 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | npm-debug.log*
2 | node_modules
3 | jspm_packages
4 | .npm
5 | /.*
6 | /*.*
7 | /test
8 | /lib
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | node_js:
4 | - "4"
5 | - "5"
6 | - "6"
7 | - "7"
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Emmet.io
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Deprecated
2 |
3 | Module implementation is moved to monorepo: https://github.com/emmetio/emmet
4 |
5 | ---
6 |
7 | # [Emmet](http://emmet.io) abbreviation expander
8 |
9 | Reference implementation of Emmet’s “Expand Abbreviation” action.
10 |
11 | ```js
12 | import { expand } from '@emmetio/expand-abbreviation';
13 |
14 | console.log(expand('ul.nav>.nav-item{Item $}*2'));
15 | // outputs:
16 | //
17 | // - Item 1
18 | // - Item 2
19 | //
20 |
21 | // use XHTML-style output
22 | console.log(expand('img[src=image.png]', {
23 | profile: {
24 | selfClosingStyle: 'xhtml'
25 | }
26 | }));
27 | // outputs:
28 |
29 | // Output in Slim syntax
30 | console.log(expand('ul.nav>.nav-item{Item $}*2', {syntax: 'slim'}));
31 | // outputs:
32 | // ul.nav
33 | // li.nav-item Item 1
34 | // li.nav-item Item 2
35 | ```
36 |
37 | ## API
38 |
39 | This module exports two functions: `parse(abbr, options)` and `expand(abbr, options)`.
40 |
41 | The `parse(abbr, options)` function [parses abbreviation into tree](https://github.com/emmetio/abbreviation), applies various transformations required for proper output and returns parsed tree. The `expand(abbr, options)` does the same but returns formatted string. In most cases you should use `expand(abbr, options)` only but if you want to analyze or update parsed abbreviation somehow, you can `parse()` abbreviation first, update parsed tree and then `expand()` it:
42 |
43 | ```js
44 | import { parse, expand } from '@emmetio/expand-abbreviation';
45 |
46 | // 1. Parse string abbreviation into tree
47 | const tree = parse('ul>.item*3');
48 |
49 | // 2. Walk on each tree node, read or update them somehow
50 | tree.walk(node => { ... });
51 |
52 | // 3. Output result
53 | console.log(expand(tree));
54 | ```
55 |
56 | ### Options
57 |
58 | Both `parse()` and `expand()` methods accept the following options:
59 |
60 | * `syntax` (string): abbreviation output syntax. Currently supported syntaxes are: `html`, `slim`, `pug`, `haml`.
61 | * `field(index, placeholder)` (function): field/tabstop generator for host editor. Most editors support TextMate-style fields: `${0}` or `${1:placeholder}`. For TextMate-style fields this function will look like this:
62 |
63 | ```js
64 | const field = (index, placeholder) => `\${${index}${placeholder ? ':' + placeholder : ''}}`;
65 | ```
66 |
67 | > Emmet natively supports TextMate fields and provides [module for parsing them](https://github.com/emmetio/field-parser).
68 |
69 | * `text` (string or array of strings): insert given text string(s) into expanded abbreviation. If array of strings is given, the implicitly repeated element (e.g. `li*`) will be repeated by the amount of items in array.
70 | * `profile` (object or [`Profile`](https://github.com/emmetio/output-profile)): either predefined [output profile](https://github.com/emmetio/output-profile) or options for output profile. Used for by [markup formatters](https://github.com/emmetio/markup-formatters) to shape-up final output.
71 | * `variables` (object): custom variables for [variable resolver](https://github.com/emmetio/variable-resolver).
72 | * `snippets` (object, array of objects or [`SnippetsRegistry`](https://github.com/emmetio/snippets-registry)): custom predefined snippets for abbreviation. The expanded abbreviation will try to match given snippets that may contain custom elements, predefined attributes etc. May also contain array of items: either snippets (object) or references to [default syntax snippets](https://github.com/emmetio/snippets) (string; the key in default snippets hash).
73 | * `addons` (object): hash of [additional transformations](https://github.com/emmetio/html-transform/tree/master/lib/addons) that should be applied to expanded abbreviation, like BEM or JSX. Since these transformations introduce side-effect, they are disabled by default and should be enabled by providing a transform name as key and transform options as value:
74 |
75 | ```js
76 | {
77 | bem: {element: '--'}, // enable transform & override options
78 | jsx: true // no options, just enable transform
79 | }
80 | ```
81 |
82 | * `format` (object): additional options for output formatter:
83 | * `markup` (object): options for markup syntaxes like XML, HTML, Pug, Slim etc.:
84 | ```js
85 | // Auto-comment expanded HTML elements with specific attributes, e.g. `p.foo` → ``
86 | comment: {
87 | // Enable/disable commenting
88 | enabled: false,
89 |
90 | // Attributes that should trigger node commenting on specific node, if commenting is enabled
91 | trigger: ['id', 'class'],
92 |
93 | // Template strings for placing before opening and/or after closing tags. Content between `[` and `]` will be outputted only if specified attribute name (uppercased; dashes replaced with underscores) is available in element
94 | before: '',
95 | after: '\n'
96 | }
97 | ```
98 | * `stylesheet` (object): options for stylesheet formatters like CSS, SCSS, LESS etc.:
99 | ```js
100 | {
101 | // Use short hex notation where possible, e.g. `#000` instead of `#000000`
102 | shortHex: true,
103 |
104 | // A string between property name and value
105 | between: ': ',
106 |
107 | // A string after property value
108 | after: ';'
109 | }
110 | ```
111 |
112 |
113 | See [`test`](/test) folder for usage examples.
114 |
115 | ## Design goals
116 |
117 | This module is just an umbrella projects that combines various stand-alone submodules into a unified process for parsing and outputting Emmet abbreviations. Thus, you can create your own “Expand Abbreviation” implementation that can re-use these submodules with additional tweaks and transforms that matches your requirements.
118 |
119 | The standard abbreviation expanding workflow:
120 |
121 | 1. [Parse Emmet abbreviation](https://github.com/emmetio/abbreviation) into DOM-like tree.
122 | 1. [Prepare parsed tree for markup output](https://github.com/emmetio/html-transform). This step includes implicit name resolving (`.item` → `div.item`), item numbering (`.item$*2` → `.item1+.item2`) and so on.
123 | 1. Match tree nodes with [predefined snippets](https://github.com/emmetio/snippets). Snippets are basically another Emmet abbreviations that define element shape (name, attributes, self-closing etc.).
124 | 1. [Resolve variables](https://github.com/emmetio/variable-resolver) in parsed tree.
125 | 1. Convert parsed abbreviation to formatted string using [markup formatters](https://github.com/emmetio/markup-formatters).
126 |
127 | ## Build targets
128 |
129 | `@emmetio/expand-abbreviation` NPM module is available in two flavors: CommonJS and ES6 modules. There’s also a complete, zero-dependency UMD module suitable for browsers (see `dist/expand-full.js`).
130 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import Profile from '@emmetio/output-profile';
4 | import SnippetsRegistry from '@emmetio/snippets-registry';
5 | import { expand as htmlExpand, parse as htmlParse } from './lib/html';
6 | import { expand as cssExpand, parse as cssParse } from './lib/css';
7 | import snippetsRegistryFactory from './lib/snippets-registry';
8 |
9 | /**
10 | * Default variables used in snippets to insert common values into predefined snippets
11 | * @type {Object}
12 | */
13 | const defaultVariables = {
14 | lang: 'en',
15 | locale: 'en-US',
16 | charset: 'UTF-8'
17 | };
18 |
19 | /**
20 | * A list of syntaxes that should use Emmet CSS abbreviations:
21 | * a variations of default abbreviation that holds values right in abbreviation name
22 | * @type {Array}
23 | */
24 | const stylesheetSyntaxes = ['css', 'sass', 'scss', 'less', 'stylus', 'sss'];
25 |
26 | const defaultOptions = {
27 | /**
28 | * Type of abbreviation to parse: 'markup' or 'stylesheet'.
29 | * Can be auto-detected from `syntax` property. Default is 'markup'
30 | */
31 | type: null,
32 |
33 | /**
34 | * Abbreviation output syntax
35 | * @type {String}
36 | */
37 | syntax: 'html',
38 |
39 | /**
40 | * Field/tabstop generator for editor. Most editors support TextMate-style
41 | * fields: ${0} or ${1:item}. So for TextMate-style fields this function
42 | * will look like this:
43 | * @example
44 | * (index, placeholder) => `\${${index}${placeholder ? ':' + placeholder : ''}}`
45 | *
46 | * @param {Number} index Placeholder index. Fields with the same indices
47 | * should be linked
48 | * @param {String} [placeholder] Field placeholder
49 | * @return {String}
50 | */
51 | field: (index, placeholder) => placeholder || '',
52 |
53 | /**
54 | * Insert given text string(s) into expanded abbreviation
55 | * If array of strings is given, the implicitly repeated element (e.g. `li*`)
56 | * will be repeated by the amount of items in array
57 | * @type {String|String[]}
58 | */
59 | text: null,
60 |
61 | /**
62 | * Either predefined output profile or options for output profile. Used for
63 | * abbreviation output
64 | * @type {Profile|Object}
65 | */
66 | profile: null,
67 |
68 | /**
69 | * Custom variables for variable resolver
70 | * @see @emmetio/variable-resolver
71 | * @type {Object}
72 | */
73 | variables: {},
74 |
75 | /**
76 | * Custom predefined snippets for abbreviation. The expanded abbreviation
77 | * will try to match given snippets that may contain custom elements,
78 | * predefined attributes etc.
79 | * May also contain array of items: either snippets (Object) or references
80 | * to default syntax snippets (String; the key in default snippets hash)
81 | * @see @emmetio/snippets
82 | * @type {Object|SnippetsRegistry}
83 | */
84 | snippets: {},
85 |
86 | /**
87 | * Hash of additional transformations that should be applied to expanded
88 | * abbreviation, like BEM or JSX. Since these transformations introduce
89 | * side-effect, they are disabled by default and should be enabled by
90 | * providing a transform name as a key and transform options as value:
91 | * @example
92 | * {
93 | * bem: {element: '--'},
94 | * jsx: true // no options, just enable transform
95 | * }
96 | * @see @emmetio/html-transform/lib/addons
97 | * @type {Object}
98 | */
99 | options: null,
100 |
101 | /**
102 | * Additional options for syntax formatter
103 | * @see @emmetio/markup-formatters
104 | * @type {Object}
105 | */
106 | format: null
107 | };
108 |
109 | /**
110 | * Expands given abbreviation into string, formatted according to provided
111 | * syntax and options
112 | * @param {String|Node} abbr Abbreviation string or parsed abbreviation tree
113 | * @param {String|Object} [config] Parsing and formatting options (object) or
114 | * abbreviation syntax (string)
115 | * @return {String}
116 | */
117 | export function expand(abbr, config) {
118 | config = createOptions(config);
119 |
120 | return getType(config.type, config.syntax) === 'stylesheet'
121 | ? cssExpand(abbr, config)
122 | : htmlExpand(abbr, config);
123 | }
124 |
125 | /**
126 | * Parses given abbreviation into AST tree. This tree can be later formatted to
127 | * string with `expand` function
128 | * @param {String} abbr Abbreviation to parse
129 | * @param {String|Object} [options] Parsing and formatting options (object) or
130 | * abbreviation syntax (string)
131 | * @return {Node}
132 | */
133 | export function parse(abbr, options) {
134 | options = createOptions(options);
135 |
136 | return getType(options.type, options.syntax) === 'stylesheet'
137 | ? cssParse(abbr, options)
138 | : htmlParse(abbr, options);
139 | }
140 |
141 | /**
142 | * Creates snippets registry for given syntax and additional `snippets`
143 | * @param {String} type Abbreviation type, 'markup' or 'stylesheet'
144 | * @param {String} syntax Snippets syntax, used for retrieving predefined snippets
145 | * @param {SnippetsRegistry|Object|Object[]} [snippets] Additional snippets
146 | * @return {SnippetsRegistry}
147 | */
148 | export function createSnippetsRegistry(type, syntax, snippets) {
149 | // Backward-compatibility with <0.6
150 | if (type && type !== 'markup' && type !== 'stylesheet') {
151 | snippets = syntax;
152 | syntax = type;
153 | type = 'markup';
154 | }
155 |
156 | return snippets instanceof SnippetsRegistry
157 | ? snippets
158 | : snippetsRegistryFactory(type, syntax, snippets);
159 | }
160 |
161 | export function createOptions(options) {
162 | if (typeof options === 'string') {
163 | options = { syntax: options };
164 | }
165 |
166 | options = Object.assign({}, defaultOptions, options);
167 | if (options.type == null && options.syntax) {
168 | options.type = isStylesheet(options.syntax) ? 'stylesheet' : 'markup';
169 | }
170 |
171 | options.format = Object.assign({field: options.field}, options.format);
172 | options.profile = createProfile(options);
173 | options.variables = Object.assign({}, defaultVariables, options.variables);
174 | options.snippets = createSnippetsRegistry(options.type, options.syntax, options.snippets);
175 |
176 | return options;
177 | }
178 |
179 | /**
180 | * Check if given syntax belongs to stylesheet markup.
181 | * Emmet uses different abbreviation flavours: one is a default markup syntax,
182 | * used for HTML, Slim, Pug etc, the other one is used for stylesheets and
183 | * allows embedded values in abbreviation name
184 | * @param {String} syntax
185 | * @return {Boolean}
186 | */
187 | export function isStylesheet(syntax) {
188 | return stylesheetSyntaxes.indexOf(syntax) !== -1;
189 | }
190 |
191 | /**
192 | * Creates output profile from given options
193 | * @param {Object} options
194 | * @return {Profile}
195 | */
196 | export function createProfile(options) {
197 | return options.profile instanceof Profile
198 | ? options.profile
199 | : new Profile(options.profile);
200 | }
201 |
202 | /**
203 | * Returns type of abbreviation expander: either 'markup' or 'stylesheet'
204 | * @param {String} type
205 | * @param {String} [syntax]
206 | */
207 | function getType(type, syntax) {
208 | if (type) {
209 | return type === 'stylesheet' ? 'stylesheet' : 'markup';
210 | }
211 |
212 | return isStylesheet(syntax) ? 'stylesheet' : 'markup';
213 | }
214 |
--------------------------------------------------------------------------------
/lib/css.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import parseAbbreviation from '@emmetio/css-abbreviation';
4 | import resolveSnippets from '@emmetio/css-snippets-resolver';
5 | import format from '@emmetio/stylesheet-formatters';
6 |
7 | /**
8 | * Expands given abbreviation into code
9 | * @param {String|Node} abbr Abbreviation to parse or already parsed abbreviation
10 | * @param {Object} config
11 | * @return {String}
12 | */
13 | export function expand(abbr, config) {
14 | config = config || {};
15 |
16 | if (typeof abbr === 'string') {
17 | abbr = parse(abbr, config);
18 | }
19 |
20 | return format(abbr, config.profile, config.syntax, config);
21 | }
22 |
23 | /**
24 | * Parses given Emmet abbreviation into a final abbreviation tree with all
25 | * required transformations applied
26 | * @param {String|Node} abbr Abbreviation to parse or already parsed abbreviation
27 | * @param {Object} config
28 | * @return {Node}
29 | */
30 | export function parse(abbr, config) {
31 | if (typeof abbr === 'string') {
32 | abbr = parseAbbreviation(abbr);
33 | }
34 |
35 | return abbr.use(resolveSnippets, config.snippets, config.options);
36 | }
37 |
--------------------------------------------------------------------------------
/lib/html.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import parseAbbreviation from '@emmetio/abbreviation';
4 | import resolveSnippets from '@emmetio/html-snippets-resolver';
5 | import transform from '@emmetio/html-transform';
6 | import resolveVariables from '@emmetio/variable-resolver';
7 | import format from '@emmetio/markup-formatters';
8 |
9 | /**
10 | * Expands given abbreviation into code
11 | * @param {String|Node} abbr Abbreviation to parse or already parsed abbreviation
12 | * @param {Object} config
13 | * @return {String}
14 | */
15 | export function expand(abbr, config) {
16 | config = Object.assign({}, config);
17 |
18 | if (typeof abbr === 'string') {
19 | abbr = parse(abbr, config);
20 | }
21 |
22 | return format(abbr, config.profile, config.syntax, config);
23 | }
24 |
25 | /**
26 | * Parses given Emmet abbreviation into a final abbreviation tree with all
27 | * required transformations applied
28 | * @param {String} Abbreviation to parse
29 | * @param {Object} config
30 | * @return {Node}
31 | */
32 | export function parse(abbr, config) {
33 | return parseAbbreviation(abbr)
34 | .use(resolveSnippets, config.snippets)
35 | .use(resolveVariables, config.variables)
36 | .use(transform, config.text, config.options);
37 | }
38 |
--------------------------------------------------------------------------------
/lib/snippets-registry.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import defaultSnippets from '@emmetio/snippets';
4 | import lorem from '@emmetio/lorem';
5 | import SnippetsRegistry from '@emmetio/snippets-registry';
6 |
7 | const reLorem = /^lorem([a-z]*)(\d*)$/i;
8 |
9 | /**
10 | * Constructs a snippets registry, filled with snippets, for given options
11 | * @param {String} syntax Abbreviation syntax
12 | * @param {Object|Object[]} snippets Additional snippets
13 | * @return {SnippetsRegistry}
14 | */
15 | export default function(type, syntax, snippets) {
16 | const registrySnippets = [];
17 |
18 | if (type === 'markup') {
19 | registrySnippets.push(defaultSnippets.html);
20 | } else if (type === 'stylesheet') {
21 | registrySnippets.push(defaultSnippets.css);
22 | }
23 |
24 | if (syntax in defaultSnippets && registrySnippets.indexOf(defaultSnippets[syntax]) === -1) {
25 | registrySnippets.push(defaultSnippets[syntax]);
26 | }
27 |
28 | if (Array.isArray(snippets)) {
29 | snippets.forEach(item => {
30 | // if array item is a string, treat it as a reference to globally
31 | // defined snippets
32 | registrySnippets.push(typeof item === 'string' ? defaultSnippets[item] : item);
33 | });
34 | } else if (typeof snippets === 'object') {
35 | registrySnippets.push(snippets);
36 | }
37 |
38 | const registry = new SnippetsRegistry(registrySnippets.filter(Boolean));
39 |
40 | // for non-stylesheet syntaxes add Lorem Ipsum generator
41 | if (type !== 'stylesheet') {
42 | registry.get(0).set(reLorem, loremGenerator);
43 | }
44 |
45 | return registry;
46 | }
47 |
48 | function loremGenerator(node) {
49 | const options = {};
50 | const m = node.name.match(reLorem);
51 | if (m[1]) {
52 | options.lang = m[1];
53 | }
54 |
55 | if (m[2]) {
56 | options.wordCount = +m[2];
57 | }
58 |
59 | return lorem(node, options);
60 | }
61 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@emmetio/expand-abbreviation",
3 | "version": "0.7.3",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@emmetio/abbreviation": {
8 | "version": "0.7.0",
9 | "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-0.7.0.tgz",
10 | "integrity": "sha512-CjLWtUCyh2nRgG/TkBruPTNI03i+b2Bau9UP7g0zgWdeV6bBjNC8CxX106ZdMekK3I/RmTrWuzVV9b+7nwqKXA==",
11 | "requires": {
12 | "@emmetio/node": "^0.1.2",
13 | "@emmetio/stream-reader": "^2.2.0",
14 | "@emmetio/stream-reader-utils": "^0.1.0"
15 | }
16 | },
17 | "@emmetio/config": {
18 | "version": "0.3.0",
19 | "resolved": "https://registry.npmjs.org/@emmetio/config/-/config-0.3.0.tgz",
20 | "integrity": "sha512-IvWUxjNTy8sl+9ysTQYLRjWzyTrnMFAl+LmKsnu+yRMdnPGrhYABwZwtTk4yrVUPhb0YsX+jQegmt/h14CBV5A==",
21 | "dev": true
22 | },
23 | "@emmetio/css-abbreviation": {
24 | "version": "0.4.0",
25 | "resolved": "https://registry.npmjs.org/@emmetio/css-abbreviation/-/css-abbreviation-0.4.0.tgz",
26 | "integrity": "sha512-8b4+ZoBElpNMedO+gGCiEX/xGv8Do0NYUvsdVNv6O0fuP9octnxyzjb7HFGqDJ7hFzVORAfzOhpjyL8y2dw9AQ==",
27 | "requires": {
28 | "@emmetio/node": "^0.1.2",
29 | "@emmetio/stream-reader": "^2.2.0",
30 | "@emmetio/stream-reader-utils": "^0.1.0"
31 | }
32 | },
33 | "@emmetio/css-snippets-resolver": {
34 | "version": "0.4.0",
35 | "resolved": "https://registry.npmjs.org/@emmetio/css-snippets-resolver/-/css-snippets-resolver-0.4.0.tgz",
36 | "integrity": "sha512-H0eOed2KljA/nQ64j3BKwAkAFliku5LAD58o4pvS3A9tZ2g3ctEpJ+61po78SZE1+Q+gRA3CGtC6rxtk7QlGPA=="
37 | },
38 | "@emmetio/field-parser": {
39 | "version": "0.3.1",
40 | "resolved": "https://registry.npmjs.org/@emmetio/field-parser/-/field-parser-0.3.1.tgz",
41 | "integrity": "sha512-A26JuVvZRUBb/rNpaDdmBB2jaN3spx2JRLJQfkskz9CRbiSW9ZE/M7etKKMunV5UWUfSlygFaFUclT3y+UNDxw==",
42 | "requires": {
43 | "@emmetio/stream-reader": "^2.2.0",
44 | "@emmetio/stream-reader-utils": "^0.1.0"
45 | }
46 | },
47 | "@emmetio/html-snippets-resolver": {
48 | "version": "0.1.4",
49 | "resolved": "https://registry.npmjs.org/@emmetio/html-snippets-resolver/-/html-snippets-resolver-0.1.4.tgz",
50 | "integrity": "sha1-szrT+nj9eNZLlL+Iqftos62Ojn4=",
51 | "requires": {
52 | "@emmetio/abbreviation": "^0.6.0"
53 | },
54 | "dependencies": {
55 | "@emmetio/abbreviation": {
56 | "version": "0.6.6",
57 | "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-0.6.6.tgz",
58 | "integrity": "sha512-jsh1Hyc7iY+5tADcn6GlIF/kxEbglPW+JE/FcCb4NNYqDr2swXvEGWd+DN3porBA67VDfDZVAwThhvYTsHKrRw==",
59 | "requires": {
60 | "@emmetio/node": "^0.1.2",
61 | "@emmetio/stream-reader": "^2.2.0",
62 | "@emmetio/stream-reader-utils": "^0.1.0"
63 | }
64 | }
65 | }
66 | },
67 | "@emmetio/html-transform": {
68 | "version": "0.3.9",
69 | "resolved": "https://registry.npmjs.org/@emmetio/html-transform/-/html-transform-0.3.9.tgz",
70 | "integrity": "sha512-Eoj+eebHCMFnqsH2ZNYcDTJIwUg1rmLIitTH89ZqU7kMyS0Z8NuB6QHjxOozF2xQAGryl8CZCbeBcGGn4OwpvQ==",
71 | "requires": {
72 | "@emmetio/implicit-tag": "^1.0.0"
73 | }
74 | },
75 | "@emmetio/implicit-tag": {
76 | "version": "1.0.0",
77 | "resolved": "https://registry.npmjs.org/@emmetio/implicit-tag/-/implicit-tag-1.0.0.tgz",
78 | "integrity": "sha1-+CbU4fxR2jlDTCMmtvbQ4rLntBk="
79 | },
80 | "@emmetio/lorem": {
81 | "version": "1.0.2",
82 | "resolved": "https://registry.npmjs.org/@emmetio/lorem/-/lorem-1.0.2.tgz",
83 | "integrity": "sha1-jealcY85Fy6n0iUypbDTu9EAg9w=",
84 | "requires": {
85 | "@emmetio/implicit-tag": "^1.0.0"
86 | }
87 | },
88 | "@emmetio/markup-formatters": {
89 | "version": "0.4.1",
90 | "resolved": "https://registry.npmjs.org/@emmetio/markup-formatters/-/markup-formatters-0.4.1.tgz",
91 | "integrity": "sha512-RR+QPozAAL7pnFL5Nl3g5qXxUF2qw54oGl0njmBTZYYwf96LDJ2p6DfRhy8uCenRjMMgUijjQ31wtmDR4cobDA==",
92 | "requires": {
93 | "@emmetio/field-parser": "^0.3.0",
94 | "@emmetio/output-renderer": "^0.1.2"
95 | }
96 | },
97 | "@emmetio/node": {
98 | "version": "0.1.2",
99 | "resolved": "https://registry.npmjs.org/@emmetio/node/-/node-0.1.2.tgz",
100 | "integrity": "sha1-QjHVOMRUgaUYNfwquj9dn8EpY0w="
101 | },
102 | "@emmetio/output-profile": {
103 | "version": "0.1.6",
104 | "resolved": "https://registry.npmjs.org/@emmetio/output-profile/-/output-profile-0.1.6.tgz",
105 | "integrity": "sha512-7bIwR3YHmTEnyy76X4l9e5+wXE+lah2E1AIoeDyKFIfVujztXNqcv+BmPcV4LRl1+V6Qir8hIex+F2nz7PTPCg=="
106 | },
107 | "@emmetio/output-renderer": {
108 | "version": "0.1.2",
109 | "resolved": "https://registry.npmjs.org/@emmetio/output-renderer/-/output-renderer-0.1.2.tgz",
110 | "integrity": "sha1-Ds4RrM6SmFB4aK7SGrUlPh6wgvg=",
111 | "requires": {
112 | "@emmetio/field-parser": "^0.3.0"
113 | }
114 | },
115 | "@emmetio/snippets": {
116 | "version": "0.2.9",
117 | "resolved": "https://registry.npmjs.org/@emmetio/snippets/-/snippets-0.2.9.tgz",
118 | "integrity": "sha512-n/oaJMcKB5No8Q1wnxfHmrZV2LA40cmYMwVbH0ebfpiZSxX1EMY26QaYu+PJiGcqR+GElS79aMagIO+dOTCntw=="
119 | },
120 | "@emmetio/snippets-registry": {
121 | "version": "0.3.1",
122 | "resolved": "https://registry.npmjs.org/@emmetio/snippets-registry/-/snippets-registry-0.3.1.tgz",
123 | "integrity": "sha1-7A6KEi/paDZZzmmiI5b0E2uUDSA="
124 | },
125 | "@emmetio/stream-reader": {
126 | "version": "2.2.0",
127 | "resolved": "https://registry.npmjs.org/@emmetio/stream-reader/-/stream-reader-2.2.0.tgz",
128 | "integrity": "sha1-Rs/+oRmgoAMxKiHC2bVijLX81EI="
129 | },
130 | "@emmetio/stream-reader-utils": {
131 | "version": "0.1.0",
132 | "resolved": "https://registry.npmjs.org/@emmetio/stream-reader-utils/-/stream-reader-utils-0.1.0.tgz",
133 | "integrity": "sha1-JEywLHfsLnT3ipvTGCGKvJxQCmE="
134 | },
135 | "@emmetio/stylesheet-formatters": {
136 | "version": "0.2.1",
137 | "resolved": "https://registry.npmjs.org/@emmetio/stylesheet-formatters/-/stylesheet-formatters-0.2.1.tgz",
138 | "integrity": "sha512-1XHNVx6S3ra7dnv12CNT6Gq15VyT2Fkrhgp2yCj4g2jJJflVHU6t++VfjoK6w36hGYu0AqZL9TCa/8hLj2YjQw==",
139 | "requires": {
140 | "@emmetio/field-parser": "^0.3.0",
141 | "@emmetio/output-renderer": "^0.1.1"
142 | }
143 | },
144 | "@emmetio/variable-resolver": {
145 | "version": "0.2.1",
146 | "resolved": "https://registry.npmjs.org/@emmetio/variable-resolver/-/variable-resolver-0.2.1.tgz",
147 | "integrity": "sha1-zhG1FYRmmjQJhmkM8OwmnkTGP7o="
148 | },
149 | "balanced-match": {
150 | "version": "1.0.0",
151 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
152 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
153 | "dev": true
154 | },
155 | "brace-expansion": {
156 | "version": "1.1.8",
157 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
158 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
159 | "dev": true,
160 | "requires": {
161 | "balanced-match": "^1.0.0",
162 | "concat-map": "0.0.1"
163 | }
164 | },
165 | "browser-stdout": {
166 | "version": "1.3.0",
167 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz",
168 | "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=",
169 | "dev": true
170 | },
171 | "builtin-modules": {
172 | "version": "2.0.0",
173 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-2.0.0.tgz",
174 | "integrity": "sha512-3U5kUA5VPsRUA3nofm/BXX7GVHKfxz0hOBAPxXrIvHzlDRkQVqEn6yi8QJegxl4LzOHLdvb7XF5dVawa/VVYBg==",
175 | "dev": true
176 | },
177 | "commander": {
178 | "version": "2.11.0",
179 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
180 | "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
181 | "dev": true
182 | },
183 | "concat-map": {
184 | "version": "0.0.1",
185 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
186 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
187 | "dev": true
188 | },
189 | "diff": {
190 | "version": "3.3.1",
191 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz",
192 | "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==",
193 | "dev": true
194 | },
195 | "escape-string-regexp": {
196 | "version": "1.0.5",
197 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
198 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
199 | "dev": true
200 | },
201 | "fs.realpath": {
202 | "version": "1.0.0",
203 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
204 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
205 | "dev": true
206 | },
207 | "glob": {
208 | "version": "7.1.2",
209 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
210 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
211 | "dev": true,
212 | "requires": {
213 | "fs.realpath": "^1.0.0",
214 | "inflight": "^1.0.4",
215 | "inherits": "2",
216 | "minimatch": "^3.0.4",
217 | "once": "^1.3.0",
218 | "path-is-absolute": "^1.0.0"
219 | }
220 | },
221 | "growl": {
222 | "version": "1.10.3",
223 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz",
224 | "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==",
225 | "dev": true
226 | },
227 | "has-flag": {
228 | "version": "2.0.0",
229 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
230 | "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
231 | "dev": true
232 | },
233 | "he": {
234 | "version": "1.1.1",
235 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
236 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
237 | "dev": true
238 | },
239 | "inflight": {
240 | "version": "1.0.6",
241 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
242 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
243 | "dev": true,
244 | "requires": {
245 | "once": "^1.3.0",
246 | "wrappy": "1"
247 | }
248 | },
249 | "inherits": {
250 | "version": "2.0.3",
251 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
252 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
253 | "dev": true
254 | },
255 | "is-module": {
256 | "version": "1.0.0",
257 | "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
258 | "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
259 | "dev": true
260 | },
261 | "minimatch": {
262 | "version": "3.0.4",
263 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
264 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
265 | "dev": true,
266 | "requires": {
267 | "brace-expansion": "^1.1.7"
268 | }
269 | },
270 | "minimist": {
271 | "version": "0.0.8",
272 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
273 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
274 | "dev": true
275 | },
276 | "mkdirp": {
277 | "version": "0.5.1",
278 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
279 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
280 | "dev": true,
281 | "requires": {
282 | "minimist": "0.0.8"
283 | }
284 | },
285 | "mocha": {
286 | "version": "5.0.1",
287 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.0.1.tgz",
288 | "integrity": "sha512-SpwyojlnE/WRBNGtvJSNfllfm5PqEDFxcWluSIgLeSBJtXG4DmoX2NNAeEA7rP5kK+79VgtVq8nG6HskaL1ykg==",
289 | "dev": true,
290 | "requires": {
291 | "browser-stdout": "1.3.0",
292 | "commander": "2.11.0",
293 | "debug": "3.1.0",
294 | "diff": "3.3.1",
295 | "escape-string-regexp": "1.0.5",
296 | "glob": "7.1.2",
297 | "growl": "1.10.3",
298 | "he": "1.1.1",
299 | "mkdirp": "0.5.1",
300 | "supports-color": "4.4.0"
301 | },
302 | "dependencies": {
303 | "debug": {
304 | "version": "3.1.0",
305 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
306 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
307 | "dev": true,
308 | "requires": {
309 | "ms": "2.0.0"
310 | }
311 | },
312 | "supports-color": {
313 | "version": "4.4.0",
314 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
315 | "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
316 | "dev": true,
317 | "requires": {
318 | "has-flag": "^2.0.0"
319 | }
320 | }
321 | }
322 | },
323 | "ms": {
324 | "version": "2.0.0",
325 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
326 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
327 | "dev": true
328 | },
329 | "once": {
330 | "version": "1.4.0",
331 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
332 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
333 | "dev": true,
334 | "requires": {
335 | "wrappy": "1"
336 | }
337 | },
338 | "path-is-absolute": {
339 | "version": "1.0.1",
340 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
341 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
342 | "dev": true
343 | },
344 | "path-parse": {
345 | "version": "1.0.5",
346 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
347 | "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
348 | "dev": true
349 | },
350 | "resolve": {
351 | "version": "1.6.0",
352 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.6.0.tgz",
353 | "integrity": "sha512-mw7JQNu5ExIkcw4LPih0owX/TZXjD/ZUF/ZQ/pDnkw3ZKhDcZZw5klmBlj6gVMwjQ3Pz5Jgu7F3d0jcDVuEWdw==",
354 | "dev": true,
355 | "requires": {
356 | "path-parse": "^1.0.5"
357 | }
358 | },
359 | "rollup": {
360 | "version": "0.56.3",
361 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.56.3.tgz",
362 | "integrity": "sha512-/iH4RfioboHgBjo7TbQcdMad/ifVGY/ToOB1AsW7oZHUhfhm+low6QlrImUSaJO1JqklOpWEKlD+b3MZYLuptA==",
363 | "dev": true
364 | },
365 | "rollup-plugin-node-resolve": {
366 | "version": "3.3.0",
367 | "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-3.3.0.tgz",
368 | "integrity": "sha512-9zHGr3oUJq6G+X0oRMYlzid9fXicBdiydhwGChdyeNRGPcN/majtegApRKHLR5drboUvEWU+QeUmGTyEZQs3WA==",
369 | "dev": true,
370 | "requires": {
371 | "builtin-modules": "^2.0.0",
372 | "is-module": "^1.0.0",
373 | "resolve": "^1.1.6"
374 | }
375 | },
376 | "wrappy": {
377 | "version": "1.0.2",
378 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
379 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
380 | "dev": true
381 | }
382 | }
383 | }
384 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@emmetio/expand-abbreviation",
3 | "version": "0.7.3",
4 | "description": "Reference implementation of Emmet abbreviation expander",
5 | "main": "dist/expand.cjs.js",
6 | "module": "dist/expand.es.js",
7 | "dependencies": {
8 | "@emmetio/abbreviation": "^0.7.0",
9 | "@emmetio/css-abbreviation": "^0.4.0",
10 | "@emmetio/css-snippets-resolver": "^0.4.0",
11 | "@emmetio/html-snippets-resolver": "^0.1.4",
12 | "@emmetio/html-transform": "^0.3.9",
13 | "@emmetio/lorem": "^1.0.1",
14 | "@emmetio/markup-formatters": "^0.4.1",
15 | "@emmetio/output-profile": "^0.1.6",
16 | "@emmetio/snippets": "^0.2.9",
17 | "@emmetio/snippets-registry": "^0.3.1",
18 | "@emmetio/stylesheet-formatters": "^0.2.1",
19 | "@emmetio/variable-resolver": "^0.2.1"
20 | },
21 | "devDependencies": {
22 | "@emmetio/config": "^0.3.0",
23 | "mocha": "^5.0.1",
24 | "rollup": "^0.56.3",
25 | "rollup-plugin-node-resolve": "^3.2.0"
26 | },
27 | "scripts": {
28 | "test": "mocha",
29 | "build": "rollup -c",
30 | "pretest": "NODE_ENV=test npm run build",
31 | "prepare": "npm run test && npm run build"
32 | },
33 | "repository": {
34 | "type": "git",
35 | "url": "git+https://github.com/emmetio/expand-abbreviation.git"
36 | },
37 | "keywords": [
38 | "emmet",
39 | "abbreviation",
40 | "expand"
41 | ],
42 | "author": "Sergey Chikuyonok ",
43 | "license": "MIT",
44 | "bugs": {
45 | "url": "https://github.com/emmetio/expand-abbreviation/issues"
46 | },
47 | "homepage": "https://github.com/emmetio/expand-abbreviation#readme"
48 | }
49 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import nodeResolve from 'rollup-plugin-node-resolve';
4 |
5 | const config = [{
6 | input: './index.js',
7 | external: [
8 | '@emmetio/abbreviation',
9 | '@emmetio/css-abbreviation',
10 | '@emmetio/css-snippets-resolver',
11 | '@emmetio/stylesheet-formatters',
12 | '@emmetio/lorem',
13 | '@emmetio/snippets',
14 | '@emmetio/snippets-registry',
15 | '@emmetio/html-snippets-resolver',
16 | '@emmetio/output-profile',
17 | '@emmetio/html-transform',
18 | '@emmetio/variable-resolver',
19 | '@emmetio/markup-formatters'
20 | ],
21 | output: [{
22 | format: 'cjs',
23 | sourcemap: true,
24 | file: 'dist/expand.cjs.js'
25 | }, {
26 | format: 'es',
27 | sourcemap: true,
28 | file: 'dist/expand.es.js'
29 | }]
30 | }];
31 |
32 | if (process.env.NODE_ENV !== 'test') {
33 | config.push({
34 | input: './index.js',
35 | plugins: [nodeResolve()],
36 | output: {
37 | format: 'umd',
38 | name: 'emmet',
39 | sourcemap: true,
40 | file: 'dist/expand-full.js',
41 | }
42 | });
43 | }
44 |
45 | export default config;
46 |
--------------------------------------------------------------------------------
/test/config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const config = require('@emmetio/config');
5 | const expand = require('../').expand;
6 | const sampleConfig = require('./sample-config.json');
7 |
8 | describe('Config support', () => {
9 | describe('Markup', () => {
10 | it('globals', () => {
11 | const conf = config(sampleConfig, { syntax: 'html' });
12 |
13 | assert.equal(
14 | expand('.test', conf),
15 | '\n',
16 | 'Use markup format and profile options'
17 | );
18 |
19 | assert.equal(
20 | expand('.foo>.-bar', conf),
21 | '\n',
22 | 'Use markup BEM options'
23 | );
24 |
25 | assert.equal(
26 | expand('[lang="${lang}" foo=${bar}]', conf),
27 | '',
28 | 'Use markup variables'
29 | );
30 |
31 | assert.equal(
32 | expand('sw>a>img', conf),
33 | '
',
34 | 'Use markup & default snippets'
35 | );
36 | });
37 |
38 | it('syntax', () => {
39 | const conf = config(sampleConfig, { syntax: 'angular' });
40 |
41 | assert.equal(
42 | expand('.test', conf),
43 | '',
44 | 'Use markup format and profile options, override with syntax format & options'
45 | );
46 |
47 | assert.equal(
48 | expand('sw>a>img', conf),
49 | '',
50 | 'Use markup snippets, override with syntax snippets'
51 | );
52 | });
53 |
54 | it('project', () => {
55 | const conf = config(sampleConfig, {
56 | syntax: 'angular',
57 | project: 'proj1'
58 | });
59 |
60 | // NB even if `tagCase` is set to "upper", syntax-specific config
61 | // takes precedence over type-specific, defined in project
62 | assert.equal(
63 | expand('.foo>.-bar', conf),
64 | '',
65 | 'Use markup format & syntax config, disable formatting in project'
66 | );
67 |
68 | assert.equal(
69 | expand('p1s>sw>a>img', conf),
70 | '',
71 | 'Use markup & syntax snippets, add from project globals'
72 | );
73 | });
74 | });
75 |
76 | describe('Stylesheet', () => {
77 | it('globals', () => {
78 | const conf = config(sampleConfig, { type: 'stylesheet' });
79 |
80 | assert.equal(
81 | expand('c', conf),
82 | 'COLOR:#000;',
83 | 'Use stylesheet format and profile options'
84 | );
85 |
86 | assert.equal(
87 | expand('c+bg#fc0', conf),
88 | 'COLOR:#000;BACKGROUND:#fc0;',
89 | 'Use stylesheet format and profile options'
90 | );
91 |
92 | assert.equal(
93 | expand('p10+gd', conf),
94 | 'PADDING:10px;GRID:;',
95 | 'Use stylesheet & default snippets'
96 | );
97 | });
98 |
99 | it('syntax', () => {
100 | const conf = config(sampleConfig, { syntax: 'sugarss' });
101 |
102 | assert.equal(
103 | expand('c', conf),
104 | 'COLOR #000',
105 | 'Use stylesheet format and profile options, override with syntax'
106 | );
107 |
108 | assert.equal(
109 | expand('c+bg#fc0', conf),
110 | 'COLOR #000BACKGROUND #fc0',
111 | 'Use stylesheet format and profile options, override with syntax'
112 | );
113 |
114 | assert.equal(
115 | expand('p10+gd+foo', conf),
116 | 'PADDING 10pxGRID BAR ',
117 | 'Use stylesheet & default snippets, override with syntax'
118 | );
119 | });
120 |
121 | it('project', () => {
122 | const conf = config(sampleConfig, {
123 | syntax: 'sugarss',
124 | project: 'proj1'
125 | });
126 |
127 | assert.equal(
128 | expand('c', conf),
129 | 'COLOR #000;;',
130 | 'Use global & syntax format and profile options, override with project'
131 | );
132 |
133 | assert.equal(
134 | expand('c+bg#fc0', conf),
135 | 'COLOR #000;;BACKGROUND #fc0;;',
136 | 'Use global & syntax format and profile options, override with project'
137 | );
138 |
139 | assert.equal(
140 | expand('gd+foo', conf),
141 | 'BAZ ;;BAR ;;',
142 | 'Use global & syntax snippets, override with project'
143 | );
144 |
145 | assert.equal(
146 | expand('p10+m5a', conf),
147 | 'PADDING 10cm;;MARGIN 5bbbb;;',
148 | 'Override options with project'
149 | );
150 | });
151 | });
152 | });
153 |
--------------------------------------------------------------------------------
/test/css.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const _expand = require('../').expand;
5 |
6 | const expand = (abbr, options) => _expand(abbr, Object.assign({syntax: 'css'}, options));
7 |
8 | describe('CSS expand', () => {
9 | it('basic', () => {
10 | assert.equal(expand('p10'), 'padding: 10px;');
11 | assert.equal(expand('c'), 'color: #000;');
12 | assert.equal(expand('fl-l'), 'float: left;');
13 | assert.equal(expand('fl-r'), 'float: right;');
14 | assert.equal(expand('@k'), '@keyframes identifier {\n\t\n}');
15 | assert.equal(expand('fll'), 'float: left;');
16 | assert.equal(expand('ovh'), 'overflow: hidden;');
17 |
18 | // insert TextMate-style fields/tabstops in output
19 | const field = (index, placeholder) => `\${${index}${placeholder ? ':' + placeholder : ''}}`;
20 | assert.equal(expand('bg-u', {field}), 'background: url(${1});');
21 | assert.equal(expand('c', {field}), 'color: #${2:000};');
22 | });
23 |
24 | it('linear-gradient', () => {
25 | assert.equal(expand('lg(to right, black, #f00.4)'), 'background-image: linear-gradient(to right, black, rgba(255, 0, 0, 0.4));');
26 | });
27 |
28 | it('chains', () => {
29 | assert.equal(expand('p.5+m-a'), 'padding: 0.5em;\nmargin: auto;');
30 | });
31 |
32 | it('formatter options', () => {
33 | let options = {
34 | format: {
35 | between: '::',
36 | after: ';;'
37 | },
38 | options: {
39 | intUnit: 'pt',
40 | floatUnit: 'vh',
41 | unitAliases: {
42 | e: 'em',
43 | p: '%',
44 | x: 'ex',
45 | r: ' / @rem'
46 | }
47 | }
48 | };
49 | assert.equal(expand('p10', options), 'padding::10pt;;');
50 | assert.equal(expand('p10.2', options), 'padding::10.2vh;;');
51 | assert.equal(expand('p10r', options), 'padding::10 / @rem;;');
52 | });
53 | });
54 |
--------------------------------------------------------------------------------
/test/html.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const expand = require('../').expand;
5 |
6 | describe('HTML expand', () => {
7 | it('basic', () => {
8 | assert.equal(expand('ul>.item$*2'), '');
9 |
10 | // insert text into abbreviation
11 | assert.equal(expand('ul>.item$*', {text: ['foo', 'bar']}), '');
12 |
13 | // insert TextMate-style fields/tabstops in output
14 | const field = (index, placeholder) => `\${${index}${placeholder ? ':' + placeholder : ''}}`;
15 | assert.equal(expand('ul>.item$*2', {field}), '');
16 | });
17 |
18 | it('syntax', () => {
19 | assert.equal(expand('ul>.item$*2', {syntax: 'html'}), '');
20 | assert.equal(expand('ul>.item$*2', {syntax: 'slim'}), 'ul\n\tli.item1\n\tli.item2');
21 | assert.equal(expand('xsl:variable[name=a select=b]>div', { options: { xsl: true } }), '\n\t\n');
22 | });
23 |
24 | it('custom profile', () => {
25 | const profile = {selfClosingStyle: 'xhtml'};
26 |
27 | assert.equal(expand('img'), '
');
28 | assert.equal(expand('img', {profile}), '
');
29 | });
30 |
31 | it('custom variables', () => {
32 | const variables = {charset: 'ru-RU'};
33 |
34 | assert.equal(expand('[charset=${charset}]{${charset}}'), 'UTF-8
');
35 | assert.equal(expand('[charset=${charset}]{${charset}}', {variables}), 'ru-RU
');
36 | });
37 |
38 | it('custom snippets', () => {
39 | const snippets = {
40 | link: 'link[foo=bar href]/',
41 | 'foo': '.foo[bar=baz]'
42 | };
43 |
44 | assert.equal(expand('foo', { snippets }), '');
45 |
46 | // `link:css` depends on `link` snippet so changing it will result in
47 | // altered `link:css` result
48 | assert.equal(expand('link:css'), '');
49 | assert.equal(expand('link:css', { snippets }), '');
50 | });
51 |
52 | it('formatter options', () => {
53 | const format = {comment: {enabled: true}};
54 |
55 | assert.equal(expand('ul>.item$*2'), '');
56 | assert.equal(expand('ul>.item$*2', {format}), '');
57 | });
58 |
59 | it('lorem ipsum', () => {
60 | const reLorem = /^Lorem.+ipsum.+dolor/;
61 | assert(reLorem.test(expand('lorem')));
62 | assert(reLorem.test(expand('LoRem')));
63 | assert(reLorem.test(expand('LORem20')));
64 | });
65 | });
66 |
--------------------------------------------------------------------------------
/test/sample-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "globals": {
4 | "markup": {
5 | "format": {
6 | "comment": {
7 | "enabled": true
8 | }
9 | },
10 | "profile": {
11 | "tagCase": "upper",
12 | "attributeCase": "upper"
13 | },
14 | "options": {
15 | "bem": {
16 | "element": "_el",
17 | "modifier": "-mod"
18 | }
19 | },
20 | "variables": {
21 | "lang": "ru",
22 | "foo": "bar"
23 | },
24 | "snippets": {
25 | "a": "a[href title]",
26 | "list": "ul>li.item"
27 | }
28 | },
29 | "stylesheet": {
30 | "format": {
31 | "shortHex": true,
32 | "between": ":"
33 | },
34 | "profile": {
35 | "tagCase": "upper",
36 | "format": false
37 | },
38 | "snippets": {
39 | "gd": "grid"
40 | }
41 | }
42 | },
43 | "syntax": {
44 | "angular": {
45 | "type": "markup",
46 | "format": {
47 | "comment": {
48 | "enabled": false
49 | }
50 | },
51 | "options": {
52 | "jsx": true
53 | },
54 | "profile": {
55 | "tagCase": "lower",
56 | "attributeCase": "upper"
57 | },
58 | "snippets": {
59 | "sw": "div[ngSwitch]"
60 | }
61 | },
62 | "sugarss": {
63 | "type": "stylesheet",
64 | "format": {
65 | "between": " ",
66 | "after": ""
67 | },
68 | "snippets": {
69 | "foo": "bar"
70 | }
71 | }
72 | },
73 | "project": {
74 | "proj1": {
75 | "globals": {
76 | "markup": {
77 | "profile": {
78 | "tagCase": "upper",
79 | "format": false
80 | },
81 | "snippets": {
82 | "p1s": "div.proj1-snippet"
83 | }
84 | },
85 | "stylesheet": {
86 | "snippets": {
87 | "gd": "baz"
88 | }
89 | }
90 | },
91 | "syntax": {
92 | "sugarss": {
93 | "format": {
94 | "after": ";;"
95 | },
96 | "options": {
97 | "intUnit": "cm",
98 | "unitAliases": {
99 | "a": "bbbb"
100 | }
101 | }
102 | }
103 | }
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------