This repository has been archived by the owner on Aug 23, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
index.js
213 lines (187 loc) · 6.2 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
'use strict';
import Profile from '@emmetio/output-profile';
import SnippetsRegistry from '@emmetio/snippets-registry';
import { expand as htmlExpand, parse as htmlParse } from './lib/html';
import { expand as cssExpand, parse as cssParse } from './lib/css';
import snippetsRegistryFactory from './lib/snippets-registry';
/**
* Default variables used in snippets to insert common values into predefined snippets
* @type {Object}
*/
const defaultVariables = {
lang: 'en',
locale: 'en-US',
charset: 'UTF-8'
};
/**
* A list of syntaxes that should use Emmet CSS abbreviations:
* a variations of default abbreviation that holds values right in abbreviation name
* @type {Array}
*/
const stylesheetSyntaxes = ['css', 'sass', 'scss', 'less', 'stylus', 'sss'];
const defaultOptions = {
/**
* Type of abbreviation to parse: 'markup' or 'stylesheet'.
* Can be auto-detected from `syntax` property. Default is 'markup'
*/
type: null,
/**
* Abbreviation output syntax
* @type {String}
*/
syntax: 'html',
/**
* Field/tabstop generator for editor. Most editors support TextMate-style
* fields: ${0} or ${1:item}. So for TextMate-style fields this function
* will look like this:
* @example
* (index, placeholder) => `\${${index}${placeholder ? ':' + placeholder : ''}}`
*
* @param {Number} index Placeholder index. Fields with the same indices
* should be linked
* @param {String} [placeholder] Field placeholder
* @return {String}
*/
field: (index, placeholder) => placeholder || '',
/**
* 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
* @type {String|String[]}
*/
text: null,
/**
* Either predefined output profile or options for output profile. Used for
* abbreviation output
* @type {Profile|Object}
*/
profile: null,
/**
* Custom variables for variable resolver
* @see @emmetio/variable-resolver
* @type {Object}
*/
variables: {},
/**
* 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 (String; the key in default snippets hash)
* @see @emmetio/snippets
* @type {Object|SnippetsRegistry}
*/
snippets: {},
/**
* Hash of additional transformations 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 a key and transform options as value:
* @example
* {
* bem: {element: '--'},
* jsx: true // no options, just enable transform
* }
* @see @emmetio/html-transform/lib/addons
* @type {Object}
*/
options: null,
/**
* Additional options for syntax formatter
* @see @emmetio/markup-formatters
* @type {Object}
*/
format: null
};
/**
* Expands given abbreviation into string, formatted according to provided
* syntax and options
* @param {String|Node} abbr Abbreviation string or parsed abbreviation tree
* @param {String|Object} [config] Parsing and formatting options (object) or
* abbreviation syntax (string)
* @return {String}
*/
export function expand(abbr, config) {
config = createOptions(config);
return getType(config.type, config.syntax) === 'stylesheet'
? cssExpand(abbr, config)
: htmlExpand(abbr, config);
}
/**
* Parses given abbreviation into AST tree. This tree can be later formatted to
* string with `expand` function
* @param {String} abbr Abbreviation to parse
* @param {String|Object} [options] Parsing and formatting options (object) or
* abbreviation syntax (string)
* @return {Node}
*/
export function parse(abbr, options) {
options = createOptions(options);
return getType(options.type, options.syntax) === 'stylesheet'
? cssParse(abbr, options)
: htmlParse(abbr, options);
}
/**
* Creates snippets registry for given syntax and additional `snippets`
* @param {String} type Abbreviation type, 'markup' or 'stylesheet'
* @param {String} syntax Snippets syntax, used for retrieving predefined snippets
* @param {SnippetsRegistry|Object|Object[]} [snippets] Additional snippets
* @return {SnippetsRegistry}
*/
export function createSnippetsRegistry(type, syntax, snippets) {
// Backward-compatibility with <0.6
if (type && type !== 'markup' && type !== 'stylesheet') {
snippets = syntax;
syntax = type;
type = 'markup';
}
return snippets instanceof SnippetsRegistry
? snippets
: snippetsRegistryFactory(type, syntax, snippets);
}
export function createOptions(options) {
if (typeof options === 'string') {
options = { syntax: options };
}
options = Object.assign({}, defaultOptions, options);
if (options.type == null && options.syntax) {
options.type = isStylesheet(options.syntax) ? 'stylesheet' : 'markup';
}
options.format = Object.assign({field: options.field}, options.format);
options.profile = createProfile(options);
options.variables = Object.assign({}, defaultVariables, options.variables);
options.snippets = createSnippetsRegistry(options.type, options.syntax, options.snippets);
return options;
}
/**
* Check if given syntax belongs to stylesheet markup.
* Emmet uses different abbreviation flavours: one is a default markup syntax,
* used for HTML, Slim, Pug etc, the other one is used for stylesheets and
* allows embedded values in abbreviation name
* @param {String} syntax
* @return {Boolean}
*/
export function isStylesheet(syntax) {
return stylesheetSyntaxes.indexOf(syntax) !== -1;
}
/**
* Creates output profile from given options
* @param {Object} options
* @return {Profile}
*/
export function createProfile(options) {
return options.profile instanceof Profile
? options.profile
: new Profile(options.profile);
}
/**
* Returns type of abbreviation expander: either 'markup' or 'stylesheet'
* @param {String} type
* @param {String} [syntax]
*/
function getType(type, syntax) {
if (type) {
return type === 'stylesheet' ? 'stylesheet' : 'markup';
}
return isStylesheet(syntax) ? 'stylesheet' : 'markup';
}