diff --git a/app/script.js b/app/script.js index 5c242d8..ed68bf5 100644 --- a/app/script.js +++ b/app/script.js @@ -77,4 +77,4 @@ if ( }); } -webpackJsonp([0],{JkW7:function(e,t,n){"use strict";function o(){var e={},t=new Promise(function(t,n){e.resolve=t,e.reject=n});return e.promise=t,V(e,t)}function s(e,t){var n=o();return t===P.HTML?n.resolve({code:e}):t===P.MARKDOWN?n.resolve(window.marked?{code:marked(e)}:{code:e}):t===P.JADE&&n.resolve(window.jade?{code:jade.render(e)}:{code:e}),n.promise}function i(e,t,n){var s,i=o();if(t===D.CSS)i.resolve({code:e});else if(t===D.SCSS||t===D.SASS)window.sass&&e?window.sass.compile(e,{indentedSyntax:t===D.SASS},function(e){e.line&&e.message&&(s={lang:"css",data:[{lineNumber:e.line-1,message:e.message}]}),i.resolve({code:e.text,errors:s})}):i.resolve({code:e});else if(t===D.LESS)less.render(e).then(function(e){i.resolve({code:e.css})},function(e){s={lang:"css",data:[{lineNumber:e.line,message:e.message}]},i.resolve({code:"",errors:s})});else if(t===D.STYLUS)stylus(e).render(function(e,t){if(e){window.err=e;var n=e.message.split("\n");n.pop(),s={lang:"css",data:[{lineNumber:+e.message.match(/stylus:(\d+):/)[1]-298,message:n.pop()}]}}i.resolve({code:t,errors:s})});else if(t===D.ACSS)if(!window.atomizer)i.resolve({code:""});else{const t=atomizer.findClassNames(e);var a;try{a=atomizer.getConfig(t,JSON.parse(n.acssConfig))}catch(n){a=atomizer.getConfig(t,{})}const o=atomizer.getCss(a);i.resolve({code:o})}return i.promise}function a(e,t,n,s){var i,a=o();if(!e)return a.resolve(""),a.promise;if(t===F.JS)try{W.parse(e,{tolerant:!0})}catch(t){i={lang:"js",data:[{lineNumber:t.lineNumber-1,message:t.description}]}}finally{!1!==n&&(e=i?e:h(e,{timeout:s})),a.resolve({code:e,errors:i})}else if(t===F.COFFEESCRIPT){if(!window.CoffeeScript)return a.resolve(""),a.promise;try{e=CoffeeScript.compile(e,{bare:!0})}catch(t){i={lang:"js",data:[{lineNumber:t.location.first_line,message:t.message}]}}finally{!1!==n&&(e=i?e:h(e,{timeout:s})),a.resolve({code:e,errors:i})}}else if(t===F.ES6){if(!window.Babel)return a.resolve(""),a.promise;try{W.parse(e,{tolerant:!0,jsx:!0})}catch(t){i={lang:"js",data:[{lineNumber:t.lineNumber-1,message:t.description}]}}finally{e=Babel.transform(e,{presets:["latest","stage-2","react"]}).code,!1!==n&&(e=i?e:h(e,{timeout:s})),a.resolve({code:e,errors:i})}}else if(t===F.TS)try{if(!window.ts)return a.resolve({code:""}),a.promise;e=ts.transpileModule(e,{reportDiagnostics:!0,compilerOptions:{noEmitOnError:!0,diagnostics:!0,module:ts.ModuleKind.ES2015}}),e.diagnostics.length&&(i={lang:"js",data:[{message:e.diagnostics[0].messageText,lineNumber:ts.getLineOfLocalPosition(e.diagnostics[0].file,e.diagnostics[0].start)-1}]}),e=e.outputText,!1===n||i||(e=h(e,{timeout:s})),a.resolve({code:e,errors:i})}catch(t){}return a.promise}function r(e,t){for(var n=e.split("."),o=t.split("."),s=0;3>s;s++){var i=+n[s],a=+o[s];if(i>a)return 1;if(a>i)return-1;if(!isNaN(i)&&isNaN(a))return 1;if(isNaN(i)&&!isNaN(a))return-1}return 0}function l(e){for(var t="",n=e||10;n--;)t+=U[~~(Math.random()*U.length)];return t}function c(){window.DEBUG&&console.log(Date.now(),...arguments)}function h(e,{timeout:t}){var n=1,o=[],s="_wmloopvar",i=`\nif (Date.now() - %d > ${t}) { window.top.previewException(new Error("Infinite loop")); break;}\n`;return z.parse(e,{tolerant:!0,range:!0,jsx:!0},function(e){switch(e.type){case"DoWhileStatement":case"ForStatement":case"ForInStatement":case"ForOfStatement":case"WhileStatement":var t=1+e.body.range[0],a=e.body.range[1],r=i.replace("%d",s+n),l="";"BlockStatement"!==e.body.type&&(r="{"+r,l="}",--t),o.push({pos:t,str:r}),o.push({pos:a,str:l}),o.push({pos:e.range[0],str:"var %d = Date.now();\n".replace("%d",s+n)}),++n;break;default:}}),o.sort(function(e,t){return t.pos-e.pos}).forEach(function(t){e=e.slice(0,t.pos)+t.str+e.slice(t.pos)}),e}function d(e){var t=new Date(e),n=t.getDate()+" "+["January","February","March","April","May","June","July","August","September","October","November","December"][t.getMonth()]+" "+t.getFullYear();return n}function p(e,t){function n(){var n=document.createElement("a");n.href=window.URL.createObjectURL(t),n.download=e,n.style.display="none",document.body.appendChild(n),n.click(),n.remove()}window.IS_EXTENSION?chrome.downloads.download({url:window.URL.createObjectURL(t),filename:e,saveAs:!0},()=>{chrome.runtime.lastError&&n()}):n()}function u(e,t,n){function o(e){return function(){c(arguments),v("fn","error",e),u.errorCount=(u.errorCount||0)+1,4===u.errorCount&&setTimeout(function(){alert("Oops! Seems like your preview isn't updating. It's recommended to switch to the web app: https://webmakerapp.com/app/.\n\n If you still want to get the extension working, please try the following steps until it fixes:\n - Refresh Web Maker\n - Restart browser\n - Update browser\n - Reinstall Web Maker (don't forget to export all your creations from saved items pane (click the OPEN button) before reinstalling)\n\nIf nothing works, please tweet out to @webmakerApp."),v("ui","writeFileMessageSeen")},1e3)}}var s=!1;window.webkitRequestFileSystem(window.TEMPORARY,5242880,function(i){i.root.getFile(e,{create:!0},function(e){e.createWriter((e)=>{e.onwriteend=function(){return s?n():(s=!0,e.seek(0),e.write(t),!1)},e.truncate(0)},o("createWriterFail"))},o("getFileFail"))},o("webkitRequestFileSystemFail"))}function m(e){var t=o(),n=window.document.getElementsByTagName("script")[0],s=window.document.createElement("script");return s.src=e,s.async=!0,n.parentNode.insertBefore(s,n),s.onload=function(){t.resolve()},t.promise}function g(e,t,n,o,s){if(!o)return"";var i=o.externalLibs.js.split("\n").reduce(function(e,t){return e+(t?"\n":"")},""),a=o.externalLibs.css.split("\n").reduce(function(e,t){return e+(t?"\n":"")},""),r="\n\n
\n\n"+a+"\n\n\n\n"+e+"\n"+i+"\n";if(s||(r+=""),o.jsMode===F.ES6&&(r+=""),"string"==typeof n)r+="\n\n",r}function f(e){var t=s(e.html,e.htmlMode),n=i(e.css,e.cssMode),o=a(e.js,e.jsMode,!1);Promise.all([t,n,o]).then(function(t){var n=t[0].code,o=t[1].code,s=t[2].code,i=g(n,o,s,e,!0),a=new Date,r=["web-maker",a.getFullYear(),a.getMonth()+1,a.getDate(),a.getHours(),a.getMinutes(),a.getSeconds()].join("-");e.title&&(r=e.title),r+=".html";var l=new Blob([i],{type:"text/html;charset=UTF-8"});p(r,l),v("fn","saveFileComplete")})}function b(){var e=o();return window.IS_EXTENSION?(chrome.permissions.contains({permissions:["downloads"]},function(t){t?e.resolve():chrome.permissions.request({permissions:["downloads"]},function(t){t?(v("fn","downloadsPermGiven"),e.resolve()):e.reject()})}),e.promise):(e.resolve(),e.promise)}function v(e,t,n,o){return window.DEBUG?void c("trackevent",e,t,n,o):void(window.ga&&ga("send","event",e,t,n,o))}function C(e,t){var n={};for(var o in e)0<=t.indexOf(o)||Object.prototype.hasOwnProperty.call(e,o)&&(n[o]=e[o]);return n}function y(e){return Object(O.h)(q,K({Tag:"a"},e))}function S(e){return Object(O.h)("div",{class:"main-header"},Object(O.h)("input",{type:"text",id:"titleInput",title:"Click to edit",class:"item-title-input",value:e.title,onBlur:e.titleInputBlurHandler}),Object(O.h)("div",{class:"main-header__btn-wrap flex flex-v-center"},Object(O.h)("a",{id:"runBtn",class:"hide flex flex-v-center hint--rounded hint--bottom-left","aria-label":"Run preview (Ctrl/\u2318 + Shift + 5)",onClick:e.runBtnClickHandler},Y,"Run"),Object(O.h)(y,{onClick:e.addLibraryBtnHandler,"data-event-category":"ui","data-event-action":"addLibraryButtonClick",class:"flex-v-center hint--rounded hint--bottom-left","aria-label":"Add a JS/CSS library"},"Add library"," ",Object(O.h)("span",{id:"js-external-lib-count",style:`display:${e.externalLibCount?"inline":"none"}`,class:"count-label"},e.externalLibCount)),Object(O.h)("a",{class:"flex flex-v-center hint--rounded hint--bottom-left","aria-label":"Start a new creation",onClick:e.newBtnHandler},G,"New"),Object(O.h)("a",{id:"saveBtn",class:`flex flex-v-center hint--rounded hint--bottom-left ${e.isSaving?"is-loading":""} ${e.unsavedEditCount?"is-marked":0}`,"aria-label":"Save current creation (Ctrl/\u2318 + S)",onClick:e.saveBtnHandler},Z,X,"Save"),Object(O.h)("a",{id:"openItemsBtn",class:`flex flex-v-center hint--rounded hint--bottom-left ${e.isFetchingItems?"is-loading":""}`,"aria-label":"Open a saved creation (Ctrl/\u2318 + O)",onClick:e.openBtnHandler},Q,ee,"Open"),Object(O.h)(y,{onClick:e.loginBtnHandler,"data-event-category":"ui","data-event-action":"loginButtonClick",class:"hide-on-login flex flex-v-center hint--rounded hint--bottom-left","aria-label":"Login/Signup"},"Login/Signup"),Object(O.h)(y,{onClick:e.profileBtnHandler,"data-event-category":"ui","data-event-action":"headerAvatarClick","aria-label":"See profile or Logout",class:"hide-on-logout hint--rounded hint--bottom-left"},Object(O.h)("img",{id:"headerAvatarImg",width:"20",src:e.user?e.user.photoURL||J:"",class:"main-header__avatar-img"}))))}function w(e,t){var n=t;return function(){0==--n&&e()}}function k(e,t){var n=ne.a.modes[e].dependencies;if(!n)return t();for(var o=[],s=0;sundefined
when no more characters are available.
- * @returns {Number}
- */
- next() {
- if (this.pos < this.string.length) {
- return this.string.charCodeAt(this.pos++);
- }
- }
-
- /**
- * `match` can be a character code or a function that takes a character code
- * and returns a boolean. If the next character in the stream 'matches'
- * the given argument, it is consumed and returned.
- * Otherwise, `false` is returned.
- * @param {Number|Function} match
- * @returns {Boolean}
- */
- eat(match) {
- const ch = this.peek();
- const ok = typeof match === 'function' ? match(ch) : ch === match;
-
- if (ok) {
- this.next();
- }
-
- return ok;
- }
-
- /**
- * Repeatedly calls eat
with the given argument, until it
- * fails. Returns true
if any characters were eaten.
- * @param {Object} match
- * @returns {Boolean}
- */
- eatWhile(match) {
- const start = this.pos;
- while (!this.eof() && this.eat(match)) {}
- return this.pos !== start;
- }
-
- /**
- * Backs up the stream n characters. Backing it up further than the
- * start of the current token will cause things to break, so be careful.
- * @param {Number} n
- */
- backUp(n) {
- this.pos -= n || 1;
- }
-
- /**
- * Get the string between the start of the current token and the
- * current stream position.
- * @returns {String}
- */
- current() {
- return this.substring(this.start, this.pos);
- }
-
- /**
- * Returns substring for given range
- * @param {Number} start
- * @param {Number} [end]
- * @return {String}
- */
- substring(start, end) {
- return this.string.slice(start, end);
- }
-
- /**
- * Creates error object with current stream state
- * @param {String} message
- * @return {Error}
- */
- error(message) {
- const err = new Error(`${message} at char ${this.pos + 1}`);
- err.originalMessage = message;
- err.pos = this.pos;
- err.string = this.string;
- return err;
- }
-};
-
-
-/* harmony default export */ var stream_reader_es = (StreamReader);
-// CONCATENATED MODULE: ../node_modules/@emmetio/stream-reader-utils/dist/stream-reader-utils.es.js
-var stream_reader_utils_es__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-/**
- * Methods for consuming quoted values
- */
-
-const SINGLE_QUOTE = 39; // '
-const DOUBLE_QUOTE = 34; // "
-
-const defaultOptions = {
- escape: 92, // \ character
- throws: false
-};
-
-/**
- * Consumes 'single' or "double"-quoted string from given string, if possible
- * @param {StreamReader} stream
- * @param {Number} options.escape A character code of quote-escape symbol
- * @param {Boolean} options.throws Throw error if quotes string can’t be properly consumed
- * @return {Boolean} `true` if quoted string was consumed. The contents
- * of quoted string will be availabe as `stream.current()`
- */
-var eatQuoted = function (stream, options) {
- options = options ? stream_reader_utils_es__extends({}, defaultOptions, options) : defaultOptions;
- const start = stream.pos;
- const quote = stream.peek();
-
- if (stream.eat(isQuote)) {
- while (!stream.eof()) {
- switch (stream.next()) {
- case quote:
- stream.start = start;
- return true;
-
- case options.escape:
- stream.next();
- break;
- }
- }
-
- // If we’re here then stream wasn’t properly consumed.
- // Revert stream and decide what to do
- stream.pos = start;
-
- if (options.throws) {
- throw stream.error('Unable to consume quoted string');
- }
- }
-
- return false;
-};
-
-function isQuote(code) {
- return code === SINGLE_QUOTE || code === DOUBLE_QUOTE;
-}
-
-/**
- * Check if given code is a number
- * @param {Number} code
- * @return {Boolean}
- */
-function isNumber(code) {
- return code > 47 && code < 58;
-}
-
-/**
- * Check if given character code is alpha code (letter through A to Z)
- * @param {Number} code
- * @param {Number} [from]
- * @param {Number} [to]
- * @return {Boolean}
- */
-function isAlpha(code, from, to) {
- from = from || 65; // A
- to = to || 90; // Z
- code &= ~32; // quick hack to convert any char code to uppercase char code
-
- return code >= from && code <= to;
-}
-
-/**
- * Check if given character code is alpha-numeric (letter through A to Z or number)
- * @param {Number} code
- * @return {Boolean}
- */
-function isAlphaNumeric(code) {
- return isNumber(code) || isAlpha(code);
-}
-
-function isWhiteSpace(code) {
- return code === 32 /* space */
- || code === 9 /* tab */
- || code === 160; /* non-breaking space */
-}
-
-/**
- * Check if given character code is a space
- * @param {Number} code
- * @return {Boolean}
- */
-function isSpace(code) {
- return isWhiteSpace(code) || code === 10 /* LF */
- || code === 13; /* CR */
-}
-
-const defaultOptions$1 = {
- escape: 92, // \ character
- throws: false
-};
-
-/**
- * Eats paired characters substring, for example `(foo)` or `[bar]`
- * @param {StreamReader} stream
- * @param {Number} open Character code of pair openinig
- * @param {Number} close Character code of pair closing
- * @param {Object} [options]
- * @return {Boolean} Returns `true` if chacarter pair was successfully
- * consumed, it’s content will be available as `stream.current()`
- */
-function eatPair(stream, open, close, options) {
- options = options ? stream_reader_utils_es__extends({}, defaultOptions$1, options) : defaultOptions$1;
- const start = stream.pos;
-
- if (stream.eat(open)) {
- let stack = 1,
- ch;
-
- while (!stream.eof()) {
- if (eatQuoted(stream, options)) {
- continue;
- }
-
- ch = stream.next();
- if (ch === open) {
- stack++;
- } else if (ch === close) {
- stack--;
- if (!stack) {
- stream.start = start;
- return true;
- }
- } else if (ch === options.escape) {
- stream.next();
- }
- }
-
- // If we’re here then paired character can’t be consumed
- stream.pos = start;
-
- if (options.throws) {
- throw stream.error(`Unable to find matching pair for ${String.fromCharCode(open)}`);
- }
- }
-
- return false;
-}
-
-
-// CONCATENATED MODULE: ../node_modules/@emmetio/field-parser/dist/field-parser.es.js
-
-
-
-const DOLLAR = 36; // $
-const COLON = 58; // :
-const ESCAPE = 92; // \
-const OPEN_BRACE = 123; // {
-const CLOSE_BRACE = 125; // }
-
-/**
- * Finds fields in given string and returns object with field-less string
- * and array of fields found
- * @param {String} string
- * @return {Object}
- */
-function parse(string) {
- const stream = new stream_reader_es(string);
- const fields = [];
- let cleanString = '',
- offset = 0,
- pos = 0;
- let code, field;
-
- while (!stream.eof()) {
- code = stream.peek();
- pos = stream.pos;
-
- if (code === ESCAPE) {
- stream.next();
- stream.next();
- } else if (field = consumeField(stream, cleanString.length + pos - offset)) {
- fields.push(field);
- cleanString += stream.string.slice(offset, pos) + field.placeholder;
- offset = stream.pos;
- } else {
- stream.next();
- }
- }
-
- return new FieldString(cleanString + stream.string.slice(offset), fields);
-}
-
-/**
- * Marks given `string` with `fields`: wraps each field range with
- * `${index:placeholder}` (by default) or any other token produced by `token`
- * function, if provided
- * @param {String} string String to mark
- * @param {Array} fields Array of field descriptor. A field descriptor is a
- * `{index, location, length}` array. It is important that fields in array
- * must be ordered by their location in string: some fields my refer the same
- * location so they must appear in order that user expects.
- * @param {Function} [token] Function that generates field token. This function
- * received two arguments: `index` and `placeholder` and should return string
- * @return {String} String with marked fields
- */
-function mark(string, fields, token) {
- token = token || createToken;
-
- // order fields by their location and appearence
- // NB field ranges should not overlap! (not supported yet)
- const ordered = fields.map((field, order) => ({ order, field, end: field.location + field.length })).sort((a, b) => a.end - b.end || a.order - b.order);
-
- // mark ranges in string
- let offset = 0;
- const result = ordered.map(item => {
- const placeholder = string.substr(item.field.location, item.field.length);
- const prefix = string.slice(offset, item.field.location);
- offset = item.end;
- return prefix + token(item.field.index, placeholder);
- });
-
- return result.join('') + string.slice(offset);
-}
-
-/**
- * Creates field token for string
- * @param {Number} index Field index
- * @param {String} placeholder Field placeholder, could be empty string
- * @return {String}
- */
-function createToken(index, placeholder) {
- return placeholder ? `\${${index}:${placeholder}}` : `\${${index}}`;
-}
-
-/**
- * Consumes field from current stream position: it can be an `$index` or
- * or `${index}` or `${index:placeholder}`
- * @param {StreamReader} stream
- * @param {Number} location Field location in *clean* string
- * @return {Field} Object with `index` and `placeholder` properties if
- * field was successfully consumed, `null` otherwise
- */
-function consumeField(stream, location) {
- const start = stream.pos;
-
- if (stream.eat(DOLLAR)) {
- // Possible start of field
- let index = consumeIndex(stream);
- let placeholder = '';
-
- // consumed $index placeholder
- if (index != null) {
- return new Field(index, placeholder, location);
- }
-
- if (stream.eat(OPEN_BRACE)) {
- index = consumeIndex(stream);
- if (index != null) {
- if (stream.eat(COLON)) {
- placeholder = consumePlaceholder(stream);
- }
-
- if (stream.eat(CLOSE_BRACE)) {
- return new Field(index, placeholder, location);
- }
- }
- }
- }
-
- // If we reached here then there’s no valid field here, revert
- // back to starting position
- stream.pos = start;
-}
-
-/**
- * Consumes a placeholder: value right after `:` in field. Could be empty
- * @param {StreamReader} stream
- * @return {String}
- */
-function consumePlaceholder(stream) {
- let code;
- const stack = [];
- stream.start = stream.pos;
-
- while (!stream.eof()) {
- code = stream.peek();
-
- if (code === OPEN_BRACE) {
- stack.push(stream.pos);
- } else if (code === CLOSE_BRACE) {
- if (!stack.length) {
- break;
- }
- stack.pop();
- }
- stream.next();
- }
-
- if (stack.length) {
- throw stream.error('Unable to find matching "}" for curly brace at ' + stack.pop());
- }
-
- return stream.current();
-}
-
-/**
- * Consumes integer from current stream position
- * @param {StreamReader} stream
- * @return {Number}
- */
-function consumeIndex(stream) {
- stream.start = stream.pos;
- if (stream.eatWhile(isNumber)) {
- return Number(stream.current());
- }
-}
-
-let Field = class Field {
- constructor(index, placeholder, location) {
- this.index = index;
- this.placeholder = placeholder;
- this.location = location;
- this.length = this.placeholder.length;
- }
-};
-let FieldString = class FieldString {
- /**
- * @param {String} string
- * @param {Field[]} fields
- */
- constructor(string, fields) {
- this.string = string;
- this.fields = fields;
- }
-
- mark(token) {
- return mark(this.string, this.fields, token);
- }
-
- toString() {
- return this.string;
- }
-};
-
-
-/* harmony default export */ var field_parser_es = (parse);
-
-//# sourceMappingURL=field-parser.es.js.map
-// CONCATENATED MODULE: ../node_modules/@emmetio/extract-abbreviation/dist/extract-abbreviation.es.js
-var extract_abbreviation_es__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-/**
- * Minimalistic backwards stream reader
- */
-let extract_abbreviation_es_StreamReader = class StreamReader {
- constructor(string, start) {
- this.string = string;
- this.start = start || 0;
- this.pos = this.string.length;
- }
-
- sol() {
- return this.pos === this.start;
- }
-
- peek(offset) {
- return this.string.charCodeAt(this.pos - 1 + (offset || 0));
- }
-
- prev() {
- if (!this.sol()) {
- return this.string.charCodeAt(--this.pos);
- }
- }
-
- eat(match) {
- if (this.sol()) {
- return false;
- }
-
- const ok = typeof match === 'function' ? match(this.peek()) : match === this.peek();
-
- if (ok) {
- this.pos--;
- }
-
- return ok;
- }
-
- eatWhile(match) {
- const start = this.pos;
- while (this.eat(match)) {}
- return this.pos < start;
- }
-};
-
-/**
- * Quotes-related utilities
- */
-
-const extract_abbreviation_es_SINGLE_QUOTE = 39; // '
-const extract_abbreviation_es_DOUBLE_QUOTE = 34; // "
-const extract_abbreviation_es_ESCAPE = 92; // \
-
-/**
- * Check if given character code is a quote
- * @param {Number} c
- * @return {Boolean}
- */
-function extract_abbreviation_es_isQuote(c) {
- return c === extract_abbreviation_es_SINGLE_QUOTE || c === extract_abbreviation_es_DOUBLE_QUOTE;
-}
-
-/**
- * Consumes quoted value, if possible
- * @param {StreamReader} stream
- * @return {Boolean} Returns `true` is value was consumed
- */
-function extract_abbreviation_es_eatQuoted(stream) {
- const start = stream.pos;
- const quote = stream.prev();
-
- if (extract_abbreviation_es_isQuote(quote)) {
- while (!stream.sol()) {
- if (stream.prev() === quote && stream.peek() !== extract_abbreviation_es_ESCAPE) {
- return true;
- }
- }
- }
-
- stream.pos = start;
- return false;
-}
-
-const TAB = 9;
-const SPACE = 32;
-const DASH = 45; // -
-const SLASH = 47; // /
-const extract_abbreviation_es_COLON = 58; // :
-const EQUALS = 61; // =
-const ANGLE_LEFT = 60; // <
-const ANGLE_RIGHT = 62; // >
-
-/**
- * Check if given reader’s current position points at the end of HTML tag
- * @param {StreamReader} stream
- * @return {Boolean}
- */
-var isAtHTMLTag = function (stream) {
- const start = stream.pos;
-
- if (!stream.eat(ANGLE_RIGHT)) {
- return false;
- }
-
- let ok = false;
- stream.eat(SLASH); // possibly self-closed element
-
- while (!stream.sol()) {
- stream.eatWhile(extract_abbreviation_es_isWhiteSpace);
-
- if (eatIdent(stream)) {
- // ate identifier: could be a tag name, boolean attribute or unquoted
- // attribute value
- if (stream.eat(SLASH)) {
- // either closing tag or invalid tag
- ok = stream.eat(ANGLE_LEFT);
- break;
- } else if (stream.eat(ANGLE_LEFT)) {
- // opening tag
- ok = true;
- break;
- } else if (stream.eat(extract_abbreviation_es_isWhiteSpace)) {
- // boolean attribute
- continue;
- } else if (stream.eat(EQUALS)) {
- // simple unquoted value or invalid attribute
- if (eatIdent(stream)) {
- continue;
- }
- break;
- } else if (eatAttributeWithUnquotedValue(stream)) {
- // identifier was a part of unquoted value
- ok = true;
- break;
- }
-
- // invalid tag
- break;
- }
-
- if (eatAttribute(stream)) {
- continue;
- }
-
- break;
- }
-
- stream.pos = start;
- return ok;
-};
-
-/**
- * Eats HTML attribute from given string.
- * @param {StreamReader} state
- * @return {Boolean} `true` if attribute was consumed.
- */
-function eatAttribute(stream) {
- return eatAttributeWithQuotedValue(stream) || eatAttributeWithUnquotedValue(stream);
-}
-
-/**
- * @param {StreamReader} stream
- * @return {Boolean}
- */
-function eatAttributeWithQuotedValue(stream) {
- const start = stream.pos;
- if (extract_abbreviation_es_eatQuoted(stream) && stream.eat(EQUALS) && eatIdent(stream)) {
- return true;
- }
-
- stream.pos = start;
- return false;
-}
-
-/**
- * @param {StreamReader} stream
- * @return {Boolean}
- */
-function eatAttributeWithUnquotedValue(stream) {
- const start = stream.pos;
- if (stream.eatWhile(isUnquotedValue) && stream.eat(EQUALS) && eatIdent(stream)) {
- return true;
- }
-
- stream.pos = start;
- return false;
-}
-
-/**
- * Eats HTML identifier from stream
- * @param {StreamReader} stream
- * @return {Boolean}
- */
-function eatIdent(stream) {
- return stream.eatWhile(isIdent);
-}
-
-/**
- * Check if given character code belongs to HTML identifier
- * @param {Number} c
- * @return {Boolean}
- */
-function isIdent(c) {
- return c === extract_abbreviation_es_COLON || c === DASH || extract_abbreviation_es_isAlpha(c) || extract_abbreviation_es_isNumber(c);
-}
-
-/**
- * Check if given character code is alpha code (letter though A to Z)
- * @param {Number} c
- * @return {Boolean}
- */
-function extract_abbreviation_es_isAlpha(c) {
- c &= ~32; // quick hack to convert any char code to uppercase char code
- return c >= 65 && c <= 90; // A-Z
-}
-
-/**
- * Check if given code is a number
- * @param {Number} c
- * @return {Boolean}
- */
-function extract_abbreviation_es_isNumber(c) {
- return c > 47 && c < 58;
-}
-
-/**
- * Check if given code is a whitespace
- * @param {Number} c
- * @return {Boolean}
- */
-function extract_abbreviation_es_isWhiteSpace(c) {
- return c === SPACE || c === TAB;
-}
-
-/**
- * Check if given code may belong to unquoted attribute value
- * @param {Number} c
- * @return {Boolean}
- */
-function isUnquotedValue(c) {
- return c && c !== EQUALS && !extract_abbreviation_es_isWhiteSpace(c) && !extract_abbreviation_es_isQuote(c);
-}
-
-const extract_abbreviation_es_code = ch => ch.charCodeAt(0);
-const SQUARE_BRACE_L = extract_abbreviation_es_code('[');
-const SQUARE_BRACE_R = extract_abbreviation_es_code(']');
-const ROUND_BRACE_L = extract_abbreviation_es_code('(');
-const ROUND_BRACE_R = extract_abbreviation_es_code(')');
-const CURLY_BRACE_L = extract_abbreviation_es_code('{');
-const CURLY_BRACE_R = extract_abbreviation_es_code('}');
-
-const specialChars = new Set('#.*:$-_!@%^+>/'.split('').map(extract_abbreviation_es_code));
-const bracePairs = new Map().set(SQUARE_BRACE_L, SQUARE_BRACE_R).set(ROUND_BRACE_L, ROUND_BRACE_R).set(CURLY_BRACE_L, CURLY_BRACE_R);
-
-const extract_abbreviation_es_defaultOptions = {
- syntax: 'markup',
- lookAhead: null,
- prefix: ''
-};
-
-/**
- * Extracts Emmet abbreviation from given string.
- * The goal of this module is to extract abbreviation from current editor’s line,
- * e.g. like this: `.foo[title=bar|]` -> `.foo[title=bar]`, where
- * `|` is a current caret position.
- * @param {String} line A text line where abbreviation should be expanded
- * @param {Number} [pos] Caret position in line. If not given, uses end-of-line
- * @param {Object} [options]
- * @param {Boolean} [options.lookAhead] Allow parser to look ahead of `pos` index for
- * searching of missing abbreviation parts. Most editors automatically inserts
- * closing braces for `[`, `{` and `(`, which will most likely be right after
- * current caret position. So in order to properly expand abbreviation, user
- * must explicitly move caret right after auto-inserted braces. With this option
- * enabled, parser will search for closing braces right after `pos`. Default is `true`
- * @param {String} [options.syntax] Name of context syntax of expanded abbreviation.
- * Either 'markup' (default) or 'stylesheet'. In 'stylesheet' syntax, braces `[]`
- * and `{}` are not supported thus not extracted.
- * @param {String} [options.prefix] A string that should precede abbreviation in
- * order to make it successfully extracted. If given, the abbreviation will be
- * extracted from the nearest `prefix` occurrence.
- * @return {Object} Object with `abbreviation` and its `location` in given line
- * if abbreviation can be extracted, `null` otherwise
- */
-function extractAbbreviation(line, pos, options) {
- // make sure `pos` is within line range
- pos = Math.min(line.length, Math.max(0, pos == null ? line.length : pos));
-
- if (typeof options === 'boolean') {
- options = extract_abbreviation_es__extends({}, extract_abbreviation_es_defaultOptions, { lookAhead: options });
- } else {
- options = extract_abbreviation_es__extends({}, extract_abbreviation_es_defaultOptions, options);
- }
-
- if (options.lookAhead == null || options.lookAhead === true) {
- pos = offsetPastAutoClosed(line, pos, options);
- }
-
- let c;
- const start = getStartOffset(line, pos, options.prefix);
- if (start === -1) {
- return null;
- }
-
- const stream = new extract_abbreviation_es_StreamReader(line, start);
- stream.pos = pos;
- const stack = [];
-
- while (!stream.sol()) {
- c = stream.peek();
-
- if (isCloseBrace(c, options.syntax)) {
- stack.push(c);
- } else if (isOpenBrace(c, options.syntax)) {
- if (stack.pop() !== bracePairs.get(c)) {
- // unexpected brace
- break;
- }
- } else if (has(stack, SQUARE_BRACE_R) || has(stack, CURLY_BRACE_R)) {
- // respect all characters inside attribute sets or text nodes
- stream.pos--;
- continue;
- } else if (isAtHTMLTag(stream) || !isAbbreviation(c)) {
- break;
- }
-
- stream.pos--;
- }
-
- if (!stack.length && stream.pos !== pos) {
- // found something, remove some invalid symbols from the
- // beginning and return abbreviation
- const abbreviation = line.slice(stream.pos, pos).replace(/^[*+>^]+/, '');
- return {
- abbreviation,
- location: pos - abbreviation.length,
- start: options.prefix ? start - options.prefix.length : pos - abbreviation.length,
- end: pos
- };
- }
-}
-
-/**
- * Returns new `line` index which is right after characters beyound `pos` that
- * editor will likely automatically close, e.g. }, ], and quotes
- * @param {String} line
- * @param {Number} pos
- * @return {Number}
- */
-function offsetPastAutoClosed(line, pos, options) {
- // closing quote is allowed only as a next character
- if (extract_abbreviation_es_isQuote(line.charCodeAt(pos))) {
- pos++;
- }
-
- // offset pointer until non-autoclosed character is found
- while (isCloseBrace(line.charCodeAt(pos), options.syntax)) {
- pos++;
- }
-
- return pos;
-}
-
-/**
- * Returns start offset (left limit) in `line` where we should stop looking for
- * abbreviation: it’s nearest to `pos` location of `prefix` token
- * @param {String} line
- * @param {Number} pos
- * @param {String} prefix
- * @return {Number}
- */
-function getStartOffset(line, pos, prefix) {
- if (!prefix) {
- return 0;
- }
-
- const stream = new extract_abbreviation_es_StreamReader(line);
- const compiledPrefix = String(prefix).split('').map(extract_abbreviation_es_code);
- stream.pos = pos;
- let result;
-
- while (!stream.sol()) {
- if (consumePair(stream, SQUARE_BRACE_R, SQUARE_BRACE_L) || consumePair(stream, CURLY_BRACE_R, CURLY_BRACE_L)) {
- continue;
- }
-
- result = stream.pos;
- if (consumeArray(stream, compiledPrefix)) {
- return result;
- }
-
- stream.pos--;
- }
-
- return -1;
-}
-
-/**
- * Consumes full character pair, if possible
- * @param {StreamReader} stream
- * @param {Number} close
- * @param {Number} open
- * @return {Boolean}
- */
-function consumePair(stream, close, open) {
- const start = stream.pos;
- if (stream.eat(close)) {
- while (!stream.sol()) {
- if (stream.eat(open)) {
- return true;
- }
-
- stream.pos--;
- }
- }
-
- stream.pos = start;
- return false;
-}
-
-/**
- * Consumes all character codes from given array, right-to-left, if possible
- * @param {StreamReader} stream
- * @param {Number[]} arr
- */
-function consumeArray(stream, arr) {
- const start = stream.pos;
- let consumed = false;
-
- for (let i = arr.length - 1; i >= 0 && !stream.sol(); i--) {
- if (!stream.eat(arr[i])) {
- break;
- }
-
- consumed = i === 0;
- }
-
- if (!consumed) {
- stream.pos = start;
- }
-
- return consumed;
-}
-
-function has(arr, value) {
- return arr.indexOf(value) !== -1;
-}
-
-function isAbbreviation(c) {
- return c > 64 && c < 91 || // uppercase letter
- c > 96 && c < 123 // lowercase letter
- || c > 47 && c < 58 // number
- || specialChars.has(c); // special character
-}
-
-function isOpenBrace(c, syntax) {
- return c === ROUND_BRACE_L || syntax === 'markup' && (c === SQUARE_BRACE_L || c === CURLY_BRACE_L);
-}
-
-function isCloseBrace(c, syntax) {
- return c === ROUND_BRACE_R || syntax === 'markup' && (c === SQUARE_BRACE_R || c === CURLY_BRACE_R);
-}
-
-/* harmony default export */ var extract_abbreviation_es = (extractAbbreviation);
-// CONCATENATED MODULE: ../node_modules/@emmetio/node/dist/node.es.js
-var node_es__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-/**
- * Attribute descriptor of parsed abbreviation node
- * @param {String} name Attribute name
- * @param {String} value Attribute value
- * @param {Object} options Additional custom attribute options
- * @param {Boolean} options.boolean Attribute is boolean (e.g. name equals value)
- * @param {Boolean} options.implied Attribute is implied (e.g. must be outputted
- * only if contains non-null value)
- */
-let Attribute = class Attribute {
- constructor(name, value, options) {
- this.name = name;
- this.value = value != null ? value : null;
- this.options = options || {};
- }
-
- /**
- * Create a copy of current attribute
- * @return {Attribute}
- */
- clone() {
- return new Attribute(this.name, this.value, node_es__extends({}, this.options));
- }
-
- /**
- * A string representation of current node
- */
- valueOf() {
- return `${this.name}="${this.value}"`;
- }
-};
-
-/**
- * A parsed abbreviation AST node. Nodes build up an abbreviation AST tree
- */
-
-let Node = class Node {
- /**
- * Creates a new node
- * @param {String} [name] Node name
- * @param {Array} [attributes] Array of attributes to add
- */
- constructor(name, attributes) {
- // own properties
- this.name = name || null;
- this.value = null;
- this.repeat = null;
- this.selfClosing = false;
-
- this.children = [];
-
- /** @type {Node} Pointer to parent node */
- this.parent = null;
-
- /** @type {Node} Pointer to next sibling */
- this.next = null;
-
- /** @type {Node} Pointer to previous sibling */
- this.previous = null;
-
- this._attributes = [];
-
- if (Array.isArray(attributes)) {
- attributes.forEach(attr => this.setAttribute(attr));
- }
- }
-
- /**
- * Array of current node attributes
- * @return {Attribute[]} Array of attributes
- */
- get attributes() {
- return this._attributes;
- }
-
- /**
- * A shorthand to retreive node attributes as map
- * @return {Object}
- */
- get attributesMap() {
- return this.attributes.reduce((out, attr) => {
- out[attr.name] = attr.options.boolean ? attr.name : attr.value;
- return out;
- }, {});
- }
-
- /**
- * Check if current node is a grouping one, e.g. has no actual representation
- * and is used for grouping subsequent nodes only
- * @return {Boolean}
- */
- get isGroup() {
- return !this.name && !this.value && !this._attributes.length;
- }
-
- /**
- * Check if given node is a text-only node, e.g. contains only value
- * @return {Boolean}
- */
- get isTextOnly() {
- return !this.name && !!this.value && !this._attributes.length;
- }
-
- /**
- * Returns first child node
- * @return {Node}
- */
- get firstChild() {
- return this.children[0];
- }
-
- /**
- * Returns last child of current node
- * @return {Node}
- */
- get lastChild() {
- return this.children[this.children.length - 1];
- }
-
- /**
- * Return index of current node in its parent child list
- * @return {Number} Returns -1 if current node is a root one
- */
- get childIndex() {
- return this.parent ? this.parent.children.indexOf(this) : -1;
- }
-
- /**
- * Returns next sibling of current node
- * @return {Node}
- */
- get nextSibling() {
- return this.next;
- }
-
- /**
- * Returns previous sibling of current node
- * @return {Node}
- */
- get previousSibling() {
- return this.previous;
- }
-
- /**
- * Returns array of unique class names in current node
- * @return {String[]}
- */
- get classList() {
- const attr = this.getAttribute('class');
- return attr && attr.value ? attr.value.split(/\s+/g).filter(uniqueClass) : [];
- }
-
- /**
- * Convenient alias to create a new node instance
- * @param {String} [name] Node name
- * @param {Object} [attributes] Attributes hash
- * @return {Node}
- */
- create(name, attributes) {
- return new Node(name, attributes);
- }
-
- /**
- * Sets given attribute for current node
- * @param {String|Object|Attribute} name Attribute name or attribute object
- * @param {String} [value] Attribute value
- */
- setAttribute(name, value) {
- const attr = createAttribute(name, value);
- const curAttr = this.getAttribute(name);
- if (curAttr) {
- this.replaceAttribute(curAttr, attr);
- } else {
- this._attributes.push(attr);
- }
- }
-
- /**
- * Check if attribute with given name exists in node
- * @param {String} name
- * @return {Boolean}
- */
- hasAttribute(name) {
- return !!this.getAttribute(name);
- }
-
- /**
- * Returns attribute object by given name
- * @param {String} name
- * @return {Attribute}
- */
- getAttribute(name) {
- if (typeof name === 'object') {
- name = name.name;
- }
-
- for (var i = 0; i < this._attributes.length; i++) {
- const attr = this._attributes[i];
- if (attr.name === name) {
- return attr;
- }
- }
- }
-
- /**
- * Replaces attribute with new instance
- * @param {String|Attribute} curAttribute Current attribute name or instance
- * to replace
- * @param {String|Object|Attribute} newName New attribute name or attribute object
- * @param {String} [newValue] New attribute value
- */
- replaceAttribute(curAttribute, newName, newValue) {
- if (typeof curAttribute === 'string') {
- curAttribute = this.getAttribute(curAttribute);
- }
-
- const ix = this._attributes.indexOf(curAttribute);
- if (ix !== -1) {
- this._attributes.splice(ix, 1, createAttribute(newName, newValue));
- }
- }
-
- /**
- * Removes attribute with given name
- * @param {String|Attribute} attr Atrtibute name or instance
- */
- removeAttribute(attr) {
- if (typeof attr === 'string') {
- attr = this.getAttribute(attr);
- }
-
- const ix = this._attributes.indexOf(attr);
- if (ix !== -1) {
- this._attributes.splice(ix, 1);
- }
- }
-
- /**
- * Removes all attributes from current node
- */
- clearAttributes() {
- this._attributes.length = 0;
- }
-
- /**
- * Adds given class name to class attribute
- * @param {String} token Class name token
- */
- addClass(token) {
- token = normalize(token);
-
- if (!this.hasAttribute('class')) {
- this.setAttribute('class', token);
- } else if (token && !this.hasClass(token)) {
- this.setAttribute('class', this.classList.concat(token).join(' '));
- }
- }
-
- /**
- * Check if current node contains given class name
- * @param {String} token Class name token
- * @return {Boolean}
- */
- hasClass(token) {
- return this.classList.indexOf(normalize(token)) !== -1;
- }
-
- /**
- * Removes given class name from class attribute
- * @param {String} token Class name token
- */
- removeClass(token) {
- token = normalize(token);
- if (this.hasClass(token)) {
- this.setAttribute('class', this.classList.filter(name => name !== token).join(' '));
- }
- }
-
- /**
- * Appends child to current node
- * @param {Node} node
- */
- appendChild(node) {
- this.insertAt(node, this.children.length);
- }
-
- /**
- * Inserts given `newNode` before `refNode` child node
- * @param {Node} newNode
- * @param {Node} refNode
- */
- insertBefore(newNode, refNode) {
- this.insertAt(newNode, this.children.indexOf(refNode));
- }
-
- /**
- * Insert given `node` at `pos` position of child list
- * @param {Node} node
- * @param {Number} pos
- */
- insertAt(node, pos) {
- if (pos < 0 || pos > this.children.length) {
- throw new Error('Unable to insert node: position is out of child list range');
- }
-
- const prev = this.children[pos - 1];
- const next = this.children[pos];
-
- node.remove();
- node.parent = this;
- this.children.splice(pos, 0, node);
-
- if (prev) {
- node.previous = prev;
- prev.next = node;
- }
-
- if (next) {
- node.next = next;
- next.previous = node;
- }
- }
-
- /**
- * Removes given child from current node
- * @param {Node} node
- */
- removeChild(node) {
- const ix = this.children.indexOf(node);
- if (ix !== -1) {
- this.children.splice(ix, 1);
- if (node.previous) {
- node.previous.next = node.next;
- }
-
- if (node.next) {
- node.next.previous = node.previous;
- }
-
- node.parent = node.next = node.previous = null;
- }
- }
-
- /**
- * Removes current node from its parent
- */
- remove() {
- if (this.parent) {
- this.parent.removeChild(this);
- }
- }
-
- /**
- * Creates a detached copy of current node
- * @param {Boolean} deep Clone node contents as well
- * @return {Node}
- */
- clone(deep) {
- const clone = new Node(this.name);
- clone.value = this.value;
- clone.selfClosing = this.selfClosing;
- if (this.repeat) {
- clone.repeat = node_es__extends({}, this.repeat);
- }
-
- this._attributes.forEach(attr => clone.setAttribute(attr.clone()));
-
- if (deep) {
- this.children.forEach(child => clone.appendChild(child.clone(true)));
- }
-
- return clone;
- }
-
- /**
- * Walks on each descendant node and invokes given `fn` function on it.
- * The function receives two arguments: the node itself and its depth level
- * from current node. If function returns `false`, it stops walking
- * @param {Function} fn
- */
- walk(fn, _level) {
- _level = _level || 0;
- let ctx = this.firstChild;
-
- while (ctx) {
- // in case if context node will be detached during `fn` call
- const next = ctx.next;
-
- if (fn(ctx, _level) === false || ctx.walk(fn, _level + 1) === false) {
- return false;
- }
-
- ctx = next;
- }
- }
-
- /**
- * A helper method for transformation chaining: runs given `fn` function on
- * current node and returns the same node
- */
- use(fn) {
- const args = [this];
- for (var i = 1; i < arguments.length; i++) {
- args.push(arguments[i]);
- }
-
- fn.apply(null, args);
- return this;
- }
-
- toString() {
- const attrs = this.attributes.map(attr => {
- attr = this.getAttribute(attr.name);
- const opt = attr.options;
- let out = `${opt && opt.implied ? '!' : ''}${attr.name || ''}`;
- if (opt && opt.boolean) {
- out += '.';
- } else if (attr.value != null) {
- out += `="${attr.value}"`;
- }
- return out;
- });
-
- let out = `${this.name || ''}`;
- if (attrs.length) {
- out += `[${attrs.join(' ')}]`;
- }
-
- if (this.value != null) {
- out += `{${this.value}}`;
- }
-
- if (this.selfClosing) {
- out += '/';
- }
-
- if (this.repeat) {
- out += `*${this.repeat.count ? this.repeat.count : ''}`;
- if (this.repeat.value != null) {
- out += `@${this.repeat.value}`;
- }
- }
-
- return out;
- }
-};
-
-/**
- * Attribute factory
- * @param {String|Attribute|Object} name Attribute name or attribute descriptor
- * @param {*} value Attribute value
- * @return {Attribute}
- */
-
-function createAttribute(name, value) {
- if (name instanceof Attribute) {
- return name;
- }
-
- if (typeof name === 'string') {
- return new Attribute(name, value);
- }
-
- if (name && typeof name === 'object') {
- return new Attribute(name.name, name.value, name.options);
- }
-}
-
-/**
- * @param {String} str
- * @return {String}
- */
-function normalize(str) {
- return String(str).trim();
-}
-
-function uniqueClass(item, i, arr) {
- return item && arr.indexOf(item) === i;
-}
-
-/* harmony default export */ var node_es = (Node);
-// CONCATENATED MODULE: ../node_modules/@emmetio/abbreviation/dist/abbreviation.es.js
-
-
-
-
-const ASTERISK = 42; // *
-
-/**
- * Consumes node repeat token from current stream position and returns its
- * parsed value
- * @param {StringReader} stream
- * @return {Object}
- */
-function consumeRepeat(stream) {
- if (stream.eat(ASTERISK)) {
- stream.start = stream.pos;
-
- // XXX think about extending repeat syntax with through numbering
- return { count: stream.eatWhile(isNumber) ? +stream.current() : null };
- }
-}
-
-const opt = { throws: true };
-
-/**
- * Consumes quoted literal from current stream position and returns it’s inner,
- * unquoted, value
- * @param {StringReader} stream
- * @return {String} Returns `null` if unable to consume quoted value from current
- * position
- */
-function consumeQuoted(stream) {
- if (eatQuoted(stream, opt)) {
- return stream.current().slice(1, -1);
- }
-}
-
-const TEXT_START = 123; // {
-const TEXT_END = 125; // }
-const abbreviation_es_ESCAPE = 92; // \ character
-
-/**
- * Consumes text node `{...}` from stream
- * @param {StreamReader} stream
- * @return {String} Returns consumed text value (without surrounding braces) or
- * `null` if there’s no text at starting position
- */
-function consumeText(stream) {
- // NB using own implementation instead of `eatPair()` from @emmetio/stream-reader-utils
- // to disable quoted value consuming
- const start = stream.pos;
-
- if (stream.eat(TEXT_START)) {
- let stack = 1,
- ch;
- let result = '';
- let offset = stream.pos;
-
- while (!stream.eof()) {
- ch = stream.next();
- if (ch === TEXT_START) {
- stack++;
- } else if (ch === TEXT_END) {
- stack--;
- if (!stack) {
- stream.start = start;
- return result + stream.substring(offset, stream.pos - 1);
- }
- } else if (ch === abbreviation_es_ESCAPE) {
- ch = stream.next();
- if (ch === TEXT_START || ch === TEXT_END) {
- result += stream.substring(offset, stream.pos - 2) + String.fromCharCode(ch);
- offset = stream.pos;
- }
- }
- }
-
- // If we’re here then paired character can’t be consumed
- stream.pos = start;
- throw stream.error(`Unable to find closing ${String.fromCharCode(TEXT_END)} for text start`);
- }
-
- return null;
-}
-
-const EXCL = 33; // .
-const DOT = 46; // .
-const abbreviation_es_EQUALS = 61; // =
-const ATTR_OPEN = 91; // [
-const ATTR_CLOSE = 93; // ]
-
-const reAttributeName = /^\!?[\w\-:\$@]+\.?$/;
-
-/**
- * Consumes attributes defined in square braces from given stream.
- * Example:
- * [attr col=3 title="Quoted string" selected. support={react}]
- * @param {StringReader} stream
- * @returns {Array} Array of consumed attributes
- */
-function consumeAttributes(stream) {
- if (!stream.eat(ATTR_OPEN)) {
- return null;
- }
-
- const result = [];
- let token, attr;
-
- while (!stream.eof()) {
- stream.eatWhile(isWhiteSpace);
-
- if (stream.eat(ATTR_CLOSE)) {
- return result; // End of attribute set
- } else if ((token = consumeQuoted(stream)) != null) {
- // Consumed quoted value: anonymous attribute
- result.push({
- name: null,
- value: token
- });
- } else if (eatUnquoted(stream)) {
- // Consumed next word: could be either attribute name or unquoted default value
- token = stream.current();
- if (!reAttributeName.test(token)) {
- // anonymous attribute
- result.push({ name: null, value: token });
- } else {
- // Looks like a regular attribute
- attr = parseAttributeName(token);
- result.push(attr);
-
- if (stream.eat(abbreviation_es_EQUALS)) {
- // Explicitly defined value. Could be a word, a quoted string
- // or React-like expression
- if ((token = consumeQuoted(stream)) != null) {
- attr.value = token;
- } else if ((token = consumeText(stream)) != null) {
- attr.value = token;
- attr.options = {
- before: '{',
- after: '}'
- };
- } else if (eatUnquoted(stream)) {
- attr.value = stream.current();
- }
- }
- }
- } else {
- throw stream.error('Expected attribute name');
- }
- }
-
- throw stream.error('Expected closing "]" brace');
-}
-
-function parseAttributeName(name) {
- const options = {};
-
- // If a first character in attribute name is `!` — it’s an implied
- // default attribute
- if (name.charCodeAt(0) === EXCL) {
- name = name.slice(1);
- options.implied = true;
- }
-
- // Check for last character: if it’s a `.`, user wants boolean attribute
- if (name.charCodeAt(name.length - 1) === DOT) {
- name = name.slice(0, name.length - 1);
- options.boolean = true;
- }
-
- const attr = { name };
- if (Object.keys(options).length) {
- attr.options = options;
- }
-
- return attr;
-}
-
-/**
- * Eats token that can be an unquoted value from given stream
- * @param {StreamReader} stream
- * @return {Boolean}
- */
-function eatUnquoted(stream) {
- const start = stream.pos;
- if (stream.eatWhile(isUnquoted)) {
- stream.start = start;
- return true;
- }
-}
-
-function isUnquoted(code) {
- return !isSpace(code) && !isQuote(code) && code !== ATTR_OPEN && code !== ATTR_CLOSE && code !== abbreviation_es_EQUALS;
-}
-
-const HASH = 35; // #
-const DOT$1 = 46; // .
-const abbreviation_es_SLASH = 47; // /
-
-/**
- * Consumes a single element node from current abbreviation stream
- * @param {StringReader} stream
- * @return {Node}
- */
-function consumeElement(stream) {
- // consume element name, if provided
- const start = stream.pos;
- const node = new node_es(eatName(stream));
- let next;
-
- while (!stream.eof()) {
- if (stream.eat(DOT$1)) {
- node.addClass(eatName(stream));
- } else if (stream.eat(HASH)) {
- node.setAttribute('id', eatName(stream));
- } else if (stream.eat(abbreviation_es_SLASH)) {
- // A self-closing indicator must be at the end of non-grouping node
- if (node.isGroup) {
- stream.backUp(1);
- throw stream.error('Unexpected self-closing indicator');
- }
- node.selfClosing = true;
- if (next = consumeRepeat(stream)) {
- node.repeat = next;
- }
- break;
- } else if (next = consumeAttributes(stream)) {
- for (let i = 0, il = next.length; i < il; i++) {
- node.setAttribute(next[i]);
- }
- } else if ((next = consumeText(stream)) !== null) {
- node.value = next;
- } else if (next = consumeRepeat(stream)) {
- node.repeat = next;
- } else {
- break;
- }
- }
-
- if (start === stream.pos) {
- throw stream.error(`Unable to consume abbreviation node, unexpected ${stream.peek()}`);
- }
-
- return node;
-}
-
-function eatName(stream) {
- stream.start = stream.pos;
- stream.eatWhile(isName);
- return stream.current();
-}
-
-function isName(code) {
- return isAlphaNumeric(code) || code === 45 /* - */
- || code === 58 /* : */
- || code === 36 /* $ */
- || code === 64 /* @ */
- || code === 33 /* ! */
- || code === 95 /* _ */
- || code === 37 /* % */;
-}
-
-const GROUP_START = 40; // (
-const GROUP_END = 41; // )
-const OP_SIBLING = 43; // +
-const OP_CHILD = 62; // >
-const OP_CLIMB = 94; // ^
-
-/**
- * Parses given string into a node tree
- * @param {String} str Abbreviation to parse
- * @return {Node}
- */
-function abbreviation_es_parse(str) {
- const stream = new stream_reader_es(str.trim());
- const root = new node_es();
- let ctx = root,
- groupStack = [],
- ch;
-
- while (!stream.eof()) {
- ch = stream.peek();
-
- if (ch === GROUP_START) {
- // start of group
- // The grouping node should be detached to properly handle
- // out-of-bounds `^` operator. Node will be attached right on group end
- const node = new node_es();
- groupStack.push([node, ctx, stream.pos]);
- ctx = node;
- stream.next();
- continue;
- } else if (ch === GROUP_END) {
- // end of group
- const lastGroup = groupStack.pop();
- if (!lastGroup) {
- throw stream.error('Unexpected ")" group end');
- }
-
- const node = lastGroup[0];
- ctx = lastGroup[1];
- stream.next();
-
- // a group can have a repeater
- if (node.repeat = consumeRepeat(stream)) {
- ctx.appendChild(node);
- } else {
- // move all children of group into parent node
- while (node.firstChild) {
- ctx.appendChild(node.firstChild);
- }
- }
- // for convenience, groups can be joined with optional `+` operator
- stream.eat(OP_SIBLING);
-
- continue;
- }
-
- const node = consumeElement(stream);
- ctx.appendChild(node);
-
- if (stream.eof()) {
- break;
- }
-
- switch (stream.peek()) {
- case OP_SIBLING:
- stream.next();
- continue;
-
- case OP_CHILD:
- stream.next();
- ctx = node;
- continue;
-
- case OP_CLIMB:
- // it’s perfectly valid to have multiple `^` operators
- while (stream.eat(OP_CLIMB)) {
- ctx = ctx.parent || ctx;
- }
- continue;
- }
- }
-
- if (groupStack.length) {
- stream.pos = groupStack.pop()[2];
- throw stream.error('Expected group close');
- }
-
- return root;
-}
-
-/**
- * Parses given abbreviation and un-rolls it into a full tree: recursively
- * replaces repeated elements with actual nodes
- * @param {String} abbr
- * @return {Node}
- */
-function index(abbr) {
- const tree = abbreviation_es_parse(abbr);
- tree.walk(unroll);
- return tree;
-}
-
-function unroll(node) {
- if (!node.repeat || !node.repeat.count) {
- return;
- }
-
- const parent = node.parent;
- let ix = parent.children.indexOf(node);
-
- for (let i = 0; i < node.repeat.count; i++) {
- const clone = node.clone(true);
- clone.repeat.value = i + 1;
- clone.walk(unroll);
-
- if (clone.isGroup) {
- while (clone.children.length > 0) {
- clone.firstChild.repeat = clone.repeat;
- parent.insertAt(clone.firstChild, ix++);
- }
- } else {
- parent.insertAt(clone, ix++);
- }
- }
-
- node.parent.removeChild(node);
-}
-
-/* harmony default export */ var abbreviation_es = (index);
-//# sourceMappingURL=abbreviation.es.js.map
-// CONCATENATED MODULE: ../node_modules/@emmetio/html-snippets-resolver/dist/html-snippets-resolver.es.js
-var html_snippets_resolver_es__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-
-
-/**
- * For every node in given `tree`, finds matching snippet from `registry` and
- * resolves it into a parsed abbreviation. Resolved node is then updated or
- * replaced with matched abbreviation tree.
- *
- * A HTML registry basically contains aliases to another Emmet abbreviations,
- * e.g. a predefined set of name, attribues and so on, possibly a complex
- * abbreviation with multiple elements. So we have to get snippet, parse it
- * and recursively resolve it.
- *
- * @param {Node} tree Parsed Emmet abbreviation
- * @param {SnippetsRegistry} registry Registry with all available snippets
- * @return {Node} Updated tree
- */
-
-var html_snippets_resolver_es_index = function (tree, registry) {
- tree.walk(node => resolveNode(node, registry));
- return tree;
-};
-
-function resolveNode(node, registry) {
- const stack = new Set();
- const resolve = node => {
- const snippet = registry.resolve(node.name);
- // A snippet in stack means circular reference.
- // It can be either a user error or a perfectly valid snippet like
- // "img": "img[src alt]/", e.g. an element with predefined shape.
- // In any case, simply stop parsing and keep element as is
- if (!snippet || stack.has(snippet)) {
- return;
- }
-
- // In case if matched snippet is a function, pass control into it
- if (typeof snippet.value === 'function') {
- return snippet.value(node, registry, resolve);
- }
-
- const tree = abbreviation_es(snippet.value);
-
- stack.add(snippet);
- tree.walk(resolve);
- stack.delete(snippet);
-
- // move current node contents into new tree
- const childTarget = findDeepestNode(tree);
- merge(childTarget, node);
-
- while (tree.firstChild) {
- node.parent.insertBefore(tree.firstChild, node);
- }
-
- childTarget.parent.insertBefore(node, childTarget);
- childTarget.remove();
- };
-
- resolve(node);
-}
-
-/**
- * Adds data from first node into second node and returns it
- * @param {Node} from
- * @param {Node} to
- * @return {Node}
- */
-function merge(from, to) {
- to.name = from.name;
-
- if (from.selfClosing) {
- to.selfClosing = true;
- }
-
- if (from.value != null) {
- to.value = from.value;
- }
-
- if (from.repeat) {
- to.repeat = html_snippets_resolver_es__extends({}, from.repeat);
- }
-
- return mergeAttributes(from, to);
-}
-
-/**
- * Transfer attributes from first element to second one and preserve first
- * element’s attributes order
- * @param {Node} from
- * @param {Node} to
- * @return {Node}
- */
-function mergeAttributes(from, to) {
- mergeClassNames(from, to);
-
- // It’s important to preserve attributes order: ones in `from` have higher
- // pripority than in `to`. Collect attributes in map in order they should
- // appear in `to`
- const attrMap = new Map();
-
- let attrs = from.attributes;
- for (let i = 0; i < attrs.length; i++) {
- attrMap.set(attrs[i].name, attrs[i].clone());
- }
-
- attrs = to.attributes.slice();
- for (let i = 0, attr, a; i < attrs.length; i++) {
- attr = attrs[i];
- if (attrMap.has(attr.name)) {
- a = attrMap.get(attr.name);
- a.value = attr.value;
-
- // If user explicitly wrote attribute in abbreviation, it’s no longer
- // implied and should be outputted even if value is empty
- if (a.options.implied) {
- a.options.implied = false;
- }
- } else {
- attrMap.set(attr.name, attr);
- }
-
- to.removeAttribute(attr);
- }
-
- const newAttrs = Array.from(attrMap.values());
- for (let i = 0; i < newAttrs.length; i++) {
- to.setAttribute(newAttrs[i]);
- }
-
- return to;
-}
-
-/**
- * Adds class names from first node to second one
- * @param {Node} from
- * @param {Node} to
- * @return {Node}
- */
-function mergeClassNames(from, to) {
- const classNames = from.classList;
- for (let i = 0; i < classNames.length; i++) {
- to.addClass(classNames[i]);
- }
-
- return to;
-}
-
-/**
- * Finds node which is the deepest for in current node or node iteself.
- * @param {Node} node
- * @return {Node}
- */
-function findDeepestNode(node) {
- while (node.children.length) {
- node = node.children[node.children.length - 1];
- }
-
- return node;
-}
-
-/* harmony default export */ var html_snippets_resolver_es = (html_snippets_resolver_es_index);
-// CONCATENATED MODULE: ../node_modules/@emmetio/implicit-tag/dist/implicit-tag.es.js
-const inlineElements = new Set('a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'.split(','));
-const elementMap = {
- p: 'span',
- ul: 'li',
- ol: 'li',
- table: 'tr',
- tr: 'td',
- tbody: 'tr',
- thead: 'tr',
- tfoot: 'tr',
- colgroup: 'col',
- select: 'option',
- optgroup: 'option',
- audio: 'source',
- video: 'source',
- object: 'param',
- map: 'area'
-};
-
-/**
- * Returns best child node name for given parent node name
- * @param {String} parentName Name of parent node
- * @return {String}
- */
-function resolveImplicitName(parentName) {
- parentName = (parentName || '').toLowerCase();
- return elementMap[parentName] || (inlineElements.has(parentName) ? 'span' : 'div');
-}
-
-/* harmony default export */ var implicit_tag_es = (resolveImplicitName);
-// CONCATENATED MODULE: ../node_modules/@emmetio/html-transform/dist/html-transform.es.js
-var html_transform_es__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-
-
-/**
- * Adds missing tag names for given tree depending on node’s parent name
- */
-var implicitTags = function (tree) {
- tree.walk(node => {
- // resolve only nameless nodes without content
- if (node.name == null && node.attributes.length) {
- node.name = implicit_tag_es(node.parent.name);
- }
- });
- return tree;
-};
-
-/**
- * Locates all occurances of given `token` which are not escaped (e.g. are not
- * preceded with `\`) given in `str`
- * @param {String} str
- * @return {Array} Array of token ranges
- */
-function findUnescapedTokens(str, token) {
- const result = new Set();
- const tlen = token.length;
-
- // 1. Find all occurances of tokens
- let pos = 0;
- while ((pos = str.indexOf(token, pos)) !== -1) {
- result.add(pos);
- pos += tlen;
- }
-
- if (result.size) {
- // 2. Remove ones that escaped
- let pos = 0;
- const len = str.length;
-
- while (pos < len) {
- if (str[pos++] === '\\') {
- result.delete(pos++);
- }
- }
- }
-
- return Array.from(result).map(ix => html_transform_es_range(ix, tlen));
-}
-
-/**
- * Replaces `ranges`, generated by `range()` function, with given `value` in `str`
- * @param {String} str Where to replace ranges
- * @param {Array} ranges Ranes, created by `range()` function
- * @param {String|Function} value Replacement value. If it’s a function, it
- * will take a range value as argument and should return a new string
- * @return {String}
- */
-function replaceRanges(str, ranges, value) {
- // should walk from the end of array to keep ranges valid after replacement
- for (let i = ranges.length - 1; i >= 0; i--) {
- const r = ranges[i];
-
- let offset = 0;
- let offsetLength = 0;
- let descendingOrder = false;
-
- if (str.substr(r[0] + r[1], 1) === '@') {
- if (str.substr(r[0] + r[1] + 1, 1) === '-') {
- descendingOrder = true;
- }
- const matches = str.substr(r[0] + r[1] + 1 + Number(descendingOrder)).match(/^(\d+)/);
- if (matches) {
- offsetLength = matches[1].length + 1 + Number(descendingOrder);
- offset = parseInt(matches[1]) - 1;
- } else {
- offsetLength = 2;
- }
- }
-
- str = str.substring(0, r[0]) + (typeof value === 'function' ? value(str.substr(r[0], r[1]), offset, descendingOrder) : value) + str.substring(r[0] + r[1] + offsetLength);
- }
-
- return str;
-}
-
-function html_transform_es_range(start, length) {
- return [start, length];
-}
-
-const numberingToken = '$';
-
-/**
- * Numbering of expanded abbreviation: finds all nodes with `$` in value
- * or attributes and replaces its occurances with repeater value
- */
-var applyNumbering = function (tree) {
- tree.walk(applyNumbering$1);
- return tree;
-};
-
-/**
- * Applies numbering for given node: replaces occurances of numbering token
- * in node’s name, content and attributes
- * @param {Node} node
- * @return {Node}
- */
-function applyNumbering$1(node) {
- const repeater = findRepeater(node);
-
- if (repeater && repeater.value != null) {
- // NB replace numbering in nodes with explicit repeater only:
- // it solves issues with abbreviations like `xsl:if[test=$foo]` where
- // `$foo` is preferred output
- const value = repeater.value;
- const count = repeater.count;
-
- node.name = replaceNumbering(node.name, value, count);
- node.value = replaceNumbering(node.value, value, count);
- node.attributes.forEach(attr => {
- const copy = node.getAttribute(attr.name).clone();
- copy.name = replaceNumbering(attr.name, value, count);
- copy.value = replaceNumbering(attr.value, value, count);
- node.replaceAttribute(attr.name, copy);
- });
- }
-
- return node;
-}
-
-/**
- * Returns repeater object for given node
- * @param {Node} node
- * @return {Object}
- */
-function findRepeater(node) {
- while (node) {
- if (node.repeat) {
- return node.repeat;
- }
-
- node = node.parent;
- }
-}
-
-/**
- * Replaces numbering in given string
- * @param {String} str
- * @param {Number} value
- * @return {String}
- */
-function replaceNumbering(str, value, count) {
- // replace numbering in strings only: skip explicit wrappers that could
- // contain unescaped numbering tokens
- if (typeof str === 'string') {
- const ranges = getNumberingRanges(str);
- return replaceNumberingRanges(str, ranges, value, count);
- }
-
- return str;
-}
-
-/**
- * Returns numbering ranges, e.g. ranges of `$` occurances, in given string.
- * Multiple adjacent ranges are combined
- * @param {String} str
- * @return {Array}
- */
-function getNumberingRanges(str) {
- return findUnescapedTokens(str || '', numberingToken).reduce((out, range$$1) => {
- // skip ranges that actually belongs to output placeholder or tabstops
- if (!/[#{]/.test(str[range$$1[0] + 1] || '')) {
- const lastRange = out[out.length - 1];
- if (lastRange && lastRange[0] + lastRange[1] === range$$1[0]) {
- lastRange[1] += range$$1[1];
- } else {
- out.push(range$$1);
- }
- }
-
- return out;
- }, []);
-}
-
-/**
- * @param {String} str
- * @param {Array} ranges
- * @param {Number} value
- * @return {String}
- */
-function replaceNumberingRanges(str, ranges, value, count) {
- const replaced = replaceRanges(str, ranges, (token, offset, descendingOrder) => {
- let _value = descendingOrder ? String(offset + count - value + 1) : String(value + offset);
- // pad values for multiple numbering tokens, e.g. 3 for $$$ becomes 003
- while (_value.length < token.length) {
- _value = '0' + _value;
- }
- return _value;
- });
-
- // unescape screened numbering tokens
- return unescapeString(replaced);
-}
-
-/**
- * Unescapes characters, screened with `\`, in given string
- * @param {String} str
- * @return {String}
- */
-function unescapeString(str) {
- let i = 0,
- result = '';
- const len = str.length;
-
- while (i < len) {
- const ch = str[i++];
- result += ch === '\\' ? str[i++] || '' : ch;
- }
-
- return result;
-}
-
-/** Placeholder for inserted content */
-const placeholder = '$#';
-
-/** Placeholder for caret */
-const caret = '|';
-
-const reUrl = /^((?:https?|ftp|file):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/;
-const reEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
-const reProto = /^([a-z]+:)?\/\//i;
-
-/**
- * Inserts content into node with implicit repeat count: this node is then
- * duplicated for each content item and content itself is inserted either into
- * deepest child or instead of a special token.
- *
- * This method uses two distinct steps: `prepare()` and `insert()` since most
- * likely these steps will be used separately to properly insert content
- * with unescaped `$` numbering markers.
- *
- * @param {Node} tree Parsed abbreviation
- * @param {String[]} content Array of content items to insert
- * @return {Node}
- */
-/**
- * Finds nodes with implicit repeat and creates `amount` copies of it in tree
- * @param {Node} tree
- * @param {Number} amount
- * @return {Node}
- */
-function prepare(tree, amount) {
- amount = amount || 1;
- tree.walk(node => {
- if (node.repeat && node.repeat.count === null) {
- for (let i = 0; i < amount; i++) {
- const clone = node.clone(true);
- clone.repeat.implicit = true;
- clone.repeat.count = amount;
- clone.repeat.value = i + 1;
- clone.repeat.index = i;
- node.parent.insertBefore(clone, node);
- }
-
- node.remove();
- }
- });
-
- return tree;
-}
-
-/**
- * Inserts content into implicitly repeated nodes, created by `prepare()` method
- * @param {Node} tree
- * @param {String[]} content
- * @return {Node}
- */
-function insert(tree, content) {
- if (Array.isArray(content) && content.length) {
- let updated = false;
- tree.walk(node => {
- if (node.repeat && node.repeat.implicit) {
- updated = true;
- insertContent(node, content[node.repeat.index]);
- }
- });
-
- if (!updated) {
- // no node with implicit repeat was found, insert content as
- // deepest child
- setNodeContent(html_transform_es_findDeepestNode(tree), content.join('\n'));
- }
- }
-
- return tree;
-}
-
-/**
- * Inserts `content` into given `node`: either replaces output placeholders
- * or inserts it into deepest child node
- * @param {Node} node
- * @param {String} content
- * @return {Node}
- */
-function insertContent(node, content) {
- let inserted = insertContentIntoPlaceholder(node, content);
- node.walk(child => inserted |= insertContentIntoPlaceholder(child, content));
-
- if (!inserted) {
- // no placeholders were found in node, insert content into deepest child
- setNodeContent(html_transform_es_findDeepestNode(node), content);
- }
-
- return node;
-}
-
-/**
- * Inserts given `content` into placeholders for given `node`. Placeholders
- * might be available in attribute values and node content
- * @param {Node} node
- * @param {String} content
- * @return {Boolean} Returns `true` if placeholders were found and replaced in node
- */
-function insertContentIntoPlaceholder(node, content) {
- const state = { replaced: false };
-
- node.value = replacePlaceholder(node.value, content, state);
- node.attributes.forEach(attr => {
- if (attr.value) {
- node.setAttribute(attr.name, replacePlaceholder(attr.value, content, state));
- }
- });
-
- return state.replaced;
-}
-
-/**
- * Replaces all placeholder occurances in given `str` with `value`
- * @param {String} str
- * @param {String} value
- * @param {Object} [_state] If provided, set `replaced` property of given
- * object to `true` if placeholder was found and replaced
- * @return {String}
- */
-function replacePlaceholder(str, value, _state) {
- if (typeof str === 'string') {
- const ranges = findUnescapedTokens(str, placeholder);
- if (ranges.length) {
- if (_state) {
- _state.replaced = true;
- }
-
- str = replaceRanges(str, ranges, value);
- }
- }
-
- return str;
-}
-
-/**
- * Finds node which is the deepest for in current node or node iteself.
- * @param {Node} node
- * @return {Node}
- */
-function html_transform_es_findDeepestNode(node) {
- while (node.children.length) {
- node = node.children[node.children.length - 1];
- }
-
- return node;
-}
-
-/**
- * Updates content of given node
- * @param {Node} node
- * @param {String} content
- */
-function setNodeContent(node, content) {
- // find caret position and replace it with content, if possible
- if (node.value) {
- const ranges = findUnescapedTokens(node.value, caret);
- if (ranges.length) {
- node.value = replaceRanges(node.value, ranges, content);
- return;
- }
- }
-
- if (node.name.toLowerCase() === 'a' || node.hasAttribute('href')) {
- // special case: inserting content into `` tag
- if (reUrl.test(content)) {
- node.setAttribute('href', (reProto.test(content) ? '' : 'http://') + content);
- } else if (reEmail.test(content)) {
- node.setAttribute('href', 'mailto:' + content);
- }
- }
-
- node.value = content;
-}
-
-const html_transform_es_defaultOptions = {
- element: '__',
- modifier: '_'
-};
-
-const reElement = /^(-+)([a-z0-9]+[a-z0-9-]*)/i;
-const reModifier = /^(_+)([a-z0-9]+[a-z0-9-_]*)/i;
-const blockCandidates1 = className => /^[a-z]\-/i.test(className);
-const blockCandidates2 = className => /^[a-z]/i.test(className);
-
-/**
- * BEM transformer: updates class names written as `-element` and
- * `_modifier` into full class names as described in BEM specs. Also adds missing
- * class names: fir example, if node contains `.block_modifier` class, ensures
- * that element contains `.block` class as well
- */
-var bem = function (tree, options) {
- options = html_transform_es__extends({}, html_transform_es_defaultOptions, options);
-
- tree.walk(node => expandClassNames(node, options));
-
- const lookup = createBlockLookup(tree);
- tree.walk(node => expandShortNotation(node, lookup, options));
-
- return tree;
-};
-
-/**
- * Expands existing class names in BEM notation in given `node`.
- * For example, if node contains `b__el_mod` class name, this method ensures
- * that element contains `b__el` class as well
- * @param {Node} node
- * @param {Object} options
- * @return {Set}
- */
-function expandClassNames(node, options) {
- const classNames = node.classList.reduce((out, cl) => {
- // remove all modifiers and element prefixes from class name to get a base element name
- const ix = cl.indexOf('_');
- if (ix > 0 && !cl.startsWith('-')) {
- out.add(cl.slice(0, ix));
- out.add(cl.slice(ix));
- return out;
- }
-
- return out.add(cl);
- }, new Set());
-
- if (classNames.size) {
- node.setAttribute('class', Array.from(classNames).join(' '));
- }
-}
-
-/**
- * Expands short BEM notation, e.g. `-element` and `_modifier`
- * @param {Node} node Parsed Emmet abbreviation node
- * @param {Map} lookup BEM block name lookup
- * @param {Object} options
- */
-function expandShortNotation(node, lookup, options) {
- const classNames = node.classList.reduce((out, cl) => {
- let prefix, m;
- const originalClass = cl;
-
- // parse element definition (could be only one)
- if (m = cl.match(reElement)) {
- prefix = getBlockName(node, lookup, m[1]) + options.element + m[2];
- out.add(prefix);
- cl = cl.slice(m[0].length);
- }
-
- // parse modifiers definitions
- if (m = cl.match(reModifier)) {
- if (!prefix) {
- prefix = getBlockName(node, lookup, m[1]);
- out.add(prefix);
- }
-
- out.add(`${prefix}${options.modifier}${m[2]}`);
- cl = cl.slice(m[0].length);
- }
-
- if (cl === originalClass) {
- // class name wasn’t modified: it’s not a BEM-specific class,
- // add it as-is into output
- out.add(originalClass);
- }
-
- return out;
- }, new Set());
-
- const arrClassNames = Array.from(classNames).filter(Boolean);
- if (arrClassNames.length) {
- node.setAttribute('class', arrClassNames.join(' '));
- }
-}
-
-/**
- * Creates block name lookup for each node in given tree, e.g. finds block
- * name explicitly for each node
- * @param {Node} tree
- * @return {Map}
- */
-function createBlockLookup(tree) {
- const lookup = new Map();
-
- tree.walk(node => {
- const classNames = node.classList;
- if (classNames.length) {
- // guess best block name from class or use parent’s block name
- lookup.set(node, find(classNames, blockCandidates1) || find(classNames, blockCandidates2) || lookup.get(node.parent));
- }
- });
-
- return lookup;
-}
-
-/**
- * Returns block name for given `node` by `prefix`, which tells the depth of
- * of parent node lookup
- * @param {Node} node
- * @param {Map} lookup
- * @param {String} prefix
- * @return {String}
- */
-function getBlockName(node, lookup, prefix) {
- let depth = prefix.length > 1 ? prefix.length : 0;
-
- // NB don’t walk up to root node, stay at first root child in case of
- // too deep prefix
- while (node.parent && node.parent.parent && depth--) {
- node = node.parent;
- }
-
- return lookup.get(node) || '';
-}
-
-function find(arr, filter) {
- for (let i = 0; i < arr.length; i++) {
- if (reElement.test(arr[i]) || reModifier.test(arr[i])) {
- break;
- }
- if (filter(arr[i])) {
- return arr[i];
- }
- }
-}
-
-/**
- * JSX transformer: replaces `class` and `for` attributes with `className` and
- * `htmlFor` attributes respectively
- */
-var jsx = function (tree) {
- tree.walk(node => {
- replace(node, 'class', 'className');
- replace(node, 'for', 'htmlFor');
- });
- return tree;
-};
-
-function replace(node, oldName, newName) {
- let attr = node.getAttribute(oldName);
- if (attr) {
- attr.name = newName;
- }
-}
-
-const reSupporterNames = /^xsl:(variable|with\-param)$/i;
-
-/**
- * XSL transformer: removes `select` attributes from certain nodes that contain
- * children
- */
-var xsl = function (tree) {
- tree.walk(node => {
- if (reSupporterNames.test(node.name || '') && (node.children.length || node.value)) {
- node.removeAttribute('select');
- }
- });
- return tree;
-};
-
-const supportedAddons = { bem, jsx, xsl };
-
-/**
- * Runs additional transforms on given tree.
- * These transforms may introduce side-effects and unexpected result
- * so they are not applied by default, authors must specify which addons
- * in `addons` argument as `{addonName: addonOptions}`
- * @param {Node} tree Parsed Emmet abbreviation
- * @param {Object} addons Add-ons to apply and their options
- */
-var addons = function (tree, addons) {
- Object.keys(addons || {}).forEach(key => {
- if (key in supportedAddons) {
- const addonOpt = typeof addons[key] === 'object' ? addons[key] : null;
- tree = tree.use(supportedAddons[key], addonOpt);
- }
- });
-
- return tree;
-};
-
-/**
- * Applies basic HTML-specific transformations for given parsed abbreviation:
- * – resolve implied tag names
- * – insert repeated content
- * – resolve node numbering
- */
-var html_transform_es_index = function (tree, content, appliedAddons) {
- if (typeof content === 'string') {
- content = [content];
- } else if (content && typeof content === 'object' && !Array.isArray(content)) {
- appliedAddons = content;
- content = null;
- }
-
- return tree.use(implicitTags).use(prepare, Array.isArray(content) ? content.length : null).use(applyNumbering).use(insert, content).use(addons, appliedAddons);
-};
-
-/* harmony default export */ var html_transform_es = (html_transform_es_index);
-// CONCATENATED MODULE: ../node_modules/@emmetio/variable-resolver/dist/variable-resolver.es.js
-/**
- * Replaces all unescaped ${variable} occurances in given parsed abbreviation
- * `tree` with values provided in `variables` hash. Precede `$` with `\` to
- * escape it and skip replacement
- * @param {Node} tree Parsed abbreviation tree
- * @param {Object} variables Variables values
- * @return {Node}
- */
-function replaceVariables(tree, variables) {
- variables = variables || {};
- tree.walk(node => replaceInNode(node, variables));
- return tree;
-}
-
-function replaceInNode(node, variables) {
- // Replace variables in attributes.
- const attrs = node.attributes;
-
- for (let i = 0, il = attrs.length; i < il; i++) {
- const attr = attrs[i];
- if (typeof attr.value === 'string') {
- node.setAttribute(attr.name, replaceInString(attr.value, variables));
- }
- }
-
- if (node.value != null) {
- node.value = replaceInString(node.value, variables);
- }
-
- return node;
-}
-
-/**
- * Replaces all unescaped `${variable}` occurances in given string with values
- * from `variables` object
- * @param {String} string
- * @param {Object} variables
- * @return {String}
- */
-function replaceInString(string, variables) {
- const model = createModel(string);
- let offset = 0;
- let output = '';
-
- for (let i = 0, il = model.variables.length; i < il; i++) {
- const v = model.variables[i];
- let value = v.name in variables ? variables[v.name] : v.name;
- if (typeof value === 'function') {
- value = value(model.string, v, offset + v.location);
- }
-
- output += model.string.slice(offset, v.location) + value;
- offset = v.location + v.length;
- }
-
- return output + model.string.slice(offset);
-}
-
-/**
- * Creates variable model from given string. The model contains a `string` with
- * all escaped variable tokens written without escape symbol and `variables`
- * property with all unescaped variables and their ranges
- * @param {String} string
- * @return {Object}
- */
-function createModel(string) {
- const reVariable = /\$\{([a-z][\w\-]*)\}/ig;
- const escapeCharCode = 92; // `\` symbol
- const variables = [];
-
- // We have to replace unescaped (e.g. not preceded with `\`) tokens.
- // Instead of writing a stream parser, we’ll cut some edges here:
- // 1. Find all tokens
- // 2. Walk string char-by-char and resolve only tokens that are not escaped
- const tokens = new Map();
- let m;
- while (m = reVariable.exec(string)) {
- tokens.set(m.index, m);
- }
-
- if (tokens.size) {
- let start = 0,
- pos = 0,
- len = string.length;
- let output = '';
- while (pos < len) {
- if (string.charCodeAt(pos) === escapeCharCode && tokens.has(pos + 1)) {
- // Found escape symbol that escapes variable: we should
- // omit this symbol in output string and skip variable
- const token = tokens.get(pos + 1);
- output += string.slice(start, pos) + token[0];
- start = pos = token.index + token[0].length;
- tokens.delete(pos + 1);
- continue;
- }
-
- pos++;
- }
-
- string = output + string.slice(start);
-
- // Not using `.map()` here to reduce memory allocations
- const validMatches = Array.from(tokens.values());
- for (let i = 0, il = validMatches.length; i < il; i++) {
- const token = validMatches[i];
- variables.push({
- name: token[1],
- location: token.index,
- length: token[0].length
- });
- }
- }
-
- return { string, variables };
-}
-
-/* harmony default export */ var variable_resolver_es = (replaceVariables);
-// CONCATENATED MODULE: ../node_modules/@emmetio/output-renderer/dist/output-renderer.es.js
-var output_renderer_es__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-
-
-const defaultFieldsRenderer = text => text;
-
-/**
- * Output node is an object containing generated output for given Emmet
- * abbreviation node. Output node can be passed to various processors that
- * may shape-up final node output. The final output is simply a concatenation
- * of `.open`, `.text` and `.close` properties and its `.before*` and `.after*`
- * satellites
- * @param {Node} node Parsed Emmet abbreviation node
- * @param {Function} fieldsRenderer A function for rendering fielded text (text with
- * tabstops) for current node. @see ./render.js for details
- */
-let OutputNode = class OutputNode {
- constructor(node, fieldsRenderer, options) {
- if (typeof fieldsRenderer === 'object') {
- options = fieldsRenderer;
- fieldsRenderer = null;
- }
-
- this.node = node;
- this._fieldsRenderer = fieldsRenderer || defaultFieldsRenderer;
-
- this.open = null;
- this.beforeOpen = '';
- this.afterOpen = '';
-
- this.close = null;
- this.beforeClose = '';
- this.afterClose = '';
-
- this.text = null;
- this.beforeText = '';
- this.afterText = '';
-
- this.indent = '';
- this.newline = '';
-
- if (options) {
- output_renderer_es__extends(this, options);
- }
- }
-
- clone() {
- return new this.constructor(this.node, this);
- }
-
- /**
- * Properly indents given multiline text
- * @param {String} text
- */
- indentText(text) {
- const lines = splitByLines(text);
- if (lines.length === 1) {
- // no newlines, nothing to indent
- return text;
- }
-
- // No newline and no indent means no formatting at all:
- // in this case we should replace newlines with spaces
- const nl = !this.newline && !this.indent ? ' ' : this.newline;
- return lines.map((line, i) => i ? this.indent + line : line).join(nl);
- }
-
- /**
- * Renders given text with fields
- * @param {String} text
- * @return {String}
- */
- renderFields(text) {
- return this._fieldsRenderer(text);
- }
-
- toString(children) {
- const open = this._wrap(this.open, this.beforeOpen, this.afterOpen);
- const close = this._wrap(this.close, this.beforeClose, this.afterClose);
- const text = this._wrap(this.text, this.beforeText, this.afterText);
-
- return open + text + (children != null ? children : '') + close;
- }
-
- _wrap(str, before, after) {
- before = before != null ? before : '';
- after = after != null ? after : '';
-
- // automatically trim whitespace for non-empty wraps
- if (str != null) {
- str = before ? str.replace(/^\s+/, '') : str;
- str = after ? str.replace(/\s+$/, '') : str;
- return before + this.indentText(str) + after;
- }
-
- return '';
- }
-};
-
-/**
- * Splits given text by lines
- * @param {String} text
- * @return {String[]}
- */
-
-function splitByLines(text) {
- return (text || '').split(/\r\n|\r|\n/g);
-}
-
-/**
- * Default output of field (tabstop)
- * @param {Number} index Field index
- * @param {String} placeholder Field placeholder, can be null
- * @return {String}
- */
-const defaultField = (index, placeholder) => placeholder || '';
-
-/**
- * Renders given parsed abbreviation `tree` via `formatter` function.
-
- * @param {Node} tree Parsed Emmet abbreviation
- * @param {Function} [field] Optional function to format field/tabstop (@see `defaultField`)
- * @param {Function} formatter Output formatter function. It takes an output node—
- * a special wrapper for parsed node that holds formatting and output properties—
- * and updates its output properties to shape-up node’s output.
- * Function arguments:
- * – `outNode`: OutputNode
- * – `renderFields`: a helper function that parses fields/tabstops from given
- * text and replaces them with `field` function output.
- * It also takes care about field indicies and ensures that the same indicies
- * from different nodes won’t collide
- */
-function render(tree, field, formatter) {
- if (typeof formatter === 'undefined') {
- formatter = field;
- field = null;
- }
-
- field = field || defaultField;
-
- // Each node may contain fields like `${1:placeholder}`.
- // Since most modern editors will link all fields with the same
- // index, we have to ensure that different nodes has their own indicies.
- // We’ll use this `fieldState` object to globally increment field indices
- // during output
- const fieldState = { index: 1 };
-
- const fieldsRenderer = text => text == null ? field(fieldState.index++) : getFieldsModel(text, fieldState).mark(field);
-
- return run(tree.children, formatter, fieldsRenderer);
-}
-
-function run(nodes, formatter, fieldsRenderer) {
- return nodes.map(node => {
- const outNode = formatter(new OutputNode(node, fieldsRenderer));
- return outNode ? outNode.toString(run(node.children, formatter, fieldsRenderer)) : '';
- }).join('');
-}
-
-/**
- * Returns fields (tab-stops) model with properly updated indices that won’t
- * collide with fields in other nodes of foprmatted tree
- * @param {String|Object} text Text to get fields model from or model itself
- * @param {Object} fieldState Abbreviation tree-wide field state reference
- * @return {Object} Field model
- */
-function getFieldsModel(text, fieldState) {
- const model = typeof text === 'object' ? text : field_parser_es(text);
- let largestIndex = -1;
-
- model.fields.forEach(field => {
- field.index += fieldState.index;
- if (field.index > largestIndex) {
- largestIndex = field.index;
- }
- });
-
- if (largestIndex !== -1) {
- fieldState.index = largestIndex + 1;
- }
-
- return model;
-}
-
-/* harmony default export */ var output_renderer_es = (render);
-// CONCATENATED MODULE: ../node_modules/@emmetio/markup-formatters/dist/markup-formatters.es.js
-var markup_formatters_es__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-
-
-
-const TOKEN = /^(.*?)([A-Z_]+)(.*?)$/;
-const TOKEN_OPEN = 91; // [
-const TOKEN_CLOSE = 93; // ]
-
-/**
- * A basic templating engine.
- * Takes every `[TOKEN]` from given string and replaces it with
- * `TOKEN` value from given `data` attribute. The token itself may contain
- * various characters between `[`, token name and `]`. Contents of `[...]` will
- * be outputted only if `TOKEN` value is not empty. Also, only `TOKEN` name will
- * be replaced with actual value, all other characters will remain as is.
- *
- * Example:
- * ```
- * template('[from
and to
values
- * @param {Number} from
- * @param {Number} to
- * @returns {Number}
- */
-function rand(from, to) {
- return Math.floor(Math.random() * (to - from) + from);
-}
-
-/**
- * @param {Array} arr
- * @param {Number} count
- * @returns {Array}
- */
-function sample(arr, count) {
- const len = arr.length;
- const iterations = Math.min(len, count);
- const result = new Set();
-
- while (result.size < iterations) {
- result.add(arr[rand(0, len)]);
- }
-
- return Array.from(result);
-}
-
-function choice(val) {
- return val[rand(0, val.length - 1)];
-}
-
-function sentence(words, end) {
- if (words.length) {
- words = [capitalize(words[0])].concat(words.slice(1));
- }
-
- return words.join(' ') + (end || choice('?!...')); // more dots than question marks
-}
-
-function capitalize(word) {
- return word[0].toUpperCase() + word.slice(1);
-}
-
-/**
- * Insert commas at randomly selected words. This function modifies values
- * inside words
array
- * @param {Array} words
- */
-function insertCommas(words) {
- if (words.length < 2) {
- return words;
- }
-
- words = words.slice();
- const len = words.length;
- const hasComma = /,$/;
- let totalCommas = 0;
-
- if (len > 3 && len <= 6) {
- totalCommas = rand(0, 1);
- } else if (len > 6 && len <= 12) {
- totalCommas = rand(0, 2);
- } else {
- totalCommas = rand(1, 4);
- }
-
- for (let i = 0, pos, word; i < totalCommas; i++) {
- pos = rand(0, len - 2);
- if (!hasComma.test(words[pos])) {
- words[pos] += ',';
- }
- }
-
- return words;
-}
-
-/**
- * Generate a paragraph of "Lorem ipsum" text
- * @param {Object} dict Words dictionary (see `lang/*.json`)
- * @param {Number} wordCount Words count in paragraph
- * @param {Boolean} startWithCommon Should paragraph start with common
- * "lorem ipsum" sentence.
- * @returns {String}
- */
-function paragraph(dict, wordCount, startWithCommon) {
- const result = [];
- let totalWords = 0;
- let words;
-
- if (startWithCommon && dict.common) {
- words = dict.common.slice(0, wordCount);
- totalWords += words.length;
- result.push(sentence(insertCommas(words), '.'));
- }
-
- while (totalWords < wordCount) {
- words = sample(dict.words, Math.min(rand(2, 30), wordCount - totalWords));
- totalWords += words.length;
- result.push(sentence(insertCommas(words)));
- }
-
- return result.join(' ');
-}
-
-/**
- * Check if given node is in repeating context, e.g. node itself or one of its
- * parent is repeated
- * @param {Node} node
- * @return {Boolean}
- */
-function isRepeating(node) {
- while (node.parent) {
- if (node.repeat && node.repeat.value && node.repeat.value > 1) {
- return true;
- }
-
- node = node.parent;
- }
-
- return false;
-}
-
-/* harmony default export */ var lorem_es = (lorem_es_index);
-// CONCATENATED MODULE: ../node_modules/@emmetio/snippets-registry/dist/snippets-registry.es.js
-let Snippet = class Snippet {
- constructor(key, value) {
- this.key = key;
- this.value = value;
- }
-};
-let SnippetsStorage = class SnippetsStorage {
- constructor(data) {
- this._string = new Map();
- this._regexp = new Map();
- this._disabled = false;
-
- this.load(data);
- }
-
- get disabled() {
- return this._disabled;
- }
-
- /**
- * Disables current store. A disabled store always returns `undefined`
- * on `get()` method
- */
- disable() {
- this._disabled = true;
- }
-
- /**
- * Enables current store.
- */
- enable() {
- this._disabled = false;
- }
-
- /**
- * Registers a new snippet item
- * @param {String|Regexp} key
- * @param {String|Function} value
- */
- set(key, value) {
- if (typeof key === 'string') {
- key.split('|').forEach(k => this._string.set(k, new Snippet(k, value)));
- } else if (key instanceof RegExp) {
- this._regexp.set(key, new Snippet(key, value));
- } else {
- throw new Error('Unknow snippet key: ' + key);
- }
-
- return this;
- }
-
- /**
- * Returns a snippet matching given key. It first tries to find snippet
- * exact match in a string key map, then tries to match one with regexp key
- * @param {String} key
- * @return {Snippet}
- */
- get(key) {
- if (this.disabled) {
- return undefined;
- }
-
- if (this._string.has(key)) {
- return this._string.get(key);
- }
-
- const keys = Array.from(this._regexp.keys());
- for (let i = 0, il = keys.length; i < il; i++) {
- if (keys[i].test(key)) {
- return this._regexp.get(keys[i]);
- }
- }
- }
-
- /**
- * Batch load of snippets data
- * @param {Object|Map} data
- */
- load(data) {
- this.reset();
- if (data instanceof Map) {
- data.forEach((value, key) => this.set(key, value));
- } else if (data && typeof data === 'object') {
- Object.keys(data).forEach(key => this.set(key, data[key]));
- }
- }
-
- /**
- * Clears all stored snippets
- */
- reset() {
- this._string.clear();
- this._regexp.clear();
- }
-
- /**
- * Returns all available snippets from given store
- */
- values() {
- if (this.disabled) {
- return [];
- }
-
- const string = Array.from(this._string.values());
- const regexp = Array.from(this._regexp.values());
- return string.concat(regexp);
- }
-};
-
-/**
- * A snippets registry. Contains snippets, separated by store and sorted by
- * priority: a store with higher priority takes precedence when resolving snippet
- * for given key
- */
-
-let SnippetsRegistry = class SnippetsRegistry {
- /**
- * Creates snippets registry, filled with given `data`
- * @param {Object|Array} data Registry snippets. If array is given, adds items
- * from array in order of precedence, registers global snippets otherwise
- */
- constructor(data) {
- this._registry = [];
-
- if (Array.isArray(data)) {
- data.forEach((snippets, level) => this.add(level, snippets));
- } else if (typeof data === 'object') {
- this.add(data);
- }
- }
-
- /**
- * Return store for given level
- * @param {Number} level
- * @return {SnippetsStorage}
- */
- get(level) {
- for (let i = 0; i < this._registry.length; i++) {
- const item = this._registry[i];
- if (item.level === level) {
- return item.store;
- }
- }
- }
-
- /**
- * Adds new store for given level
- * @param {Number} [level] Store level (priority). Store with higher level
- * takes precedence when resolving snippets
- * @param {Object} [snippets] A snippets data for new store
- * @return {SnipetsStorage}
- */
- add(level, snippets) {
- if (level != null && typeof level === 'object') {
- snippets = level;
- level = 0;
- }
-
- const store = new SnippetsStorage(snippets);
-
- // remove previous store from same level
- this.remove(level);
-
- this._registry.push({ level, store });
- this._registry.sort((a, b) => b.level - a.level);
-
- return store;
- }
-
- /**
- * Remove registry with given level or store
- * @param {Number|SnippetsStorage} data Either level or snippets store
- */
- remove(data) {
- this._registry = this._registry.filter(item => item.level !== data && item.store !== data);
- }
-
- /**
- * Returns snippet from registry that matches given name
- * @param {String} name
- * @return {Snippet}
- */
- resolve(name) {
- for (let i = 0; i < this._registry.length; i++) {
- const snippet = this._registry[i].store.get(name);
- if (snippet) {
- return snippet;
- }
- }
- }
-
- /**
- * Returns all available snippets from current registry. Snippets with the
- * same key are resolved by their storage priority.
- * @param {Object} options
- * @param {Object} options.type Return snippets only of given type: 'string'
- * or 'regexp'. Returns all snippets if not defined
- * @return {Array}
- */
- all(options) {
- options = options || {};
- const result = new Map();
-
- const fillResult = snippet => {
- const type = snippet.key instanceof RegExp ? 'regexp' : 'string';
- if ((!options.type || options.type === type) && !result.has(snippet.key)) {
- result.set(snippet.key, snippet);
- }
- };
-
- this._registry.forEach(item => {
- item.store.values().forEach(fillResult);
- });
-
- return Array.from(result.values());
- }
-
- /**
- * Removes all stores from registry
- */
- clear() {
- this._registry.length = 0;
- }
-};
-
-
-/* harmony default export */ var snippets_registry_es = (SnippetsRegistry);
-// CONCATENATED MODULE: ../node_modules/@emmetio/output-profile/dist/output-profile.es.js
-var output_profile_es__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-/**
- * @type {EmmetOutputProfile}
- */
-var output_profile_es_defaultOptions = {
- indent: '\t',
- tagCase: '',
- attributeCase: '',
- attributeQuotes: 'double',
- format: true,
- formatSkip: ['html'],
- formatForce: ['body'],
- inlineBreak: 3,
- compactBooleanAttributes: false,
- booleanAttributes: ['contenteditable', 'seamless', 'async', 'autofocus', 'autoplay', 'checked', 'controls', 'defer', 'disabled', 'formnovalidate', 'hidden', 'ismap', 'loop', 'multiple', 'muted', 'novalidate', 'readonly', 'required', 'reversed', 'selected', 'typemustmatch'],
- selfClosingStyle: 'html',
- inlineElements: ['a', 'abbr', 'acronym', 'applet', 'b', 'basefont', 'bdo', 'big', 'br', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'object', 'q', 's', 'samp', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'textarea', 'tt', 'u', 'var']
-};
-
-/**
- * Creates output profile for given options
- */
-let Profile = class Profile {
- /**
- * @param {EmmetOutputProfile} options
- */
- constructor(options) {
- /** @type {EmmetOutputProfile} */
- this.options = output_profile_es__extends({}, output_profile_es_defaultOptions, options);
- this.quoteChar = this.options.attributeQuotes === 'single' ? '\'' : '"';
- }
-
- /**
- * Returns value of given option name
- * @param {String} name
- * @return {*}
- */
- get(name) {
- return this.options[name];
- }
-
- /**
- * Quote given string according to profile
- * @param {String} str String to quote
- * @return {String}
- */
- quote(str) {
- return `${this.quoteChar}${str != null ? str : ''}${this.quoteChar}`;
- }
-
- /**
- * Output given tag name according to options
- * @param {String} name
- * @return {String}
- */
- name(name) {
- return strcase(name, this.options.tagCase);
- }
-
- /**
- * Outputs attribute name according to current settings
- * @param {String} attr Attribute name
- * @return {String}
- */
- attribute(attr) {
- return strcase(attr, this.options.attributeCase);
- }
-
- /**
- * Check if given attribute is boolean
- * @param {Object} attr
- * @return {Boolean}
- */
- isBooleanAttribute(attr) {
- return attr.options.boolean || this.get('booleanAttributes').indexOf((attr.name || '').toLowerCase()) !== -1;
- }
-
- /**
- * Returns a token for self-closing tag, depending on current options
- * @return {String}
- */
- selfClose() {
- switch (this.options.selfClosingStyle) {
- case 'xhtml':
- return ' /';
- case 'xml':
- return '/';
- default:
- return '';
- }
- }
-
- /**
- * Returns indent for given level
- * @param {Number} level Indentation level
- * @return {String}
- */
- indent(level) {
- level = level || 0;
- let output = '';
- while (level--) {
- output += this.options.indent;
- }
-
- return output;
- }
-
- /**
- * Check if given tag name belongs to inline-level element
- * @param {Object|String} node Parsed node or tag name
- * @return {Boolean}
- */
- isInline(node) {
- if (typeof node === 'string') {
- return this.get('inlineElements').indexOf(node.toLowerCase()) !== -1;
- }
-
- // inline node is a node either with inline-level name or text-only node
- return node.name != null ? this.isInline(node.name) : node.isTextOnly;
- }
-
- /**
- * Outputs formatted field for given params
- * @param {Number} index Field index
- * @param {String} [placeholder] Field placeholder, can be empty
- * @return {String}
- */
- field(index, placeholder) {
- return this.options.field(index, placeholder);
- }
-};
-
-function strcase(string, type) {
- if (type) {
- return type === 'upper' ? string.toUpperCase() : string.toLowerCase();
- }
-
- return string;
-}
-
-/* harmony default export */ var output_profile_es = (Profile);
-// CONCATENATED MODULE: ../node_modules/@emmetio/expand-abbreviation/dist/expand.es.js
-var expand_es__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-/**
- * Expands given abbreviation into code
- * @param {String|Node} abbr Abbreviation to parse or already parsed abbreviation
- * @param {Object} config
- * @return {String}
- */
-function expand(abbr, config) {
- config = expand_es__extends({}, config);
-
- if (typeof abbr === 'string') {
- abbr = expand_es_parse(abbr, config);
- }
-
- return markup_formatters_es(abbr, config.profile, config.syntax, config);
-}
-
-/**
- * Parses given Emmet abbreviation into a final abbreviation tree with all
- * required transformations applied
- * @param {String} Abbreviation to parse
- * @param {Object} config
- * @return {Node}
- */
-function expand_es_parse(abbr, config) {
- return abbreviation_es(abbr).use(html_snippets_resolver_es, config.snippets).use(variable_resolver_es, config.variables).use(html_transform_es, config.text, config.options);
-}
-
-/**
- * Expands given abbreviation into code
- * @param {String|Node} abbr Abbreviation to parse or already parsed abbreviation
- * @param {Object} config
- * @return {String}
- */
-function expand$1(abbr, config) {
- config = config || {};
-
- if (typeof abbr === 'string') {
- abbr = parse$1(abbr, config);
- }
-
- return stylesheet_formatters_es(abbr, config.profile, config.syntax, config);
-}
-
-/**
- * Parses given Emmet abbreviation into a final abbreviation tree with all
- * required transformations applied
- * @param {String|Node} abbr Abbreviation to parse or already parsed abbreviation
- * @param {Object} config
- * @return {Node}
- */
-function parse$1(abbr, config) {
- if (typeof abbr === 'string') {
- abbr = css_abbreviation_es(abbr);
- }
-
- return abbr.use(css_snippets_resolver_es, config.snippets, config.options);
-}
-
-const reLorem = /^lorem([a-z]*)(\d*)$/i;
-
-/**
- * Constructs a snippets registry, filled with snippets, for given options
- * @param {String} syntax Abbreviation syntax
- * @param {Object|Object[]} snippets Additional snippets
- * @return {SnippetsRegistry}
- */
-function snippetsRegistryFactory(type, syntax, snippets) {
- const registrySnippets = [];
-
- if (type === 'markup') {
- registrySnippets.push(snippets_es.html);
- } else if (type === 'stylesheet') {
- registrySnippets.push(snippets_es.css);
- }
-
- if (syntax in snippets_es && registrySnippets.indexOf(snippets_es[syntax]) === -1) {
- registrySnippets.push(snippets_es[syntax]);
- }
-
- if (Array.isArray(snippets)) {
- snippets.forEach(item => {
- // if array item is a string, treat it as a reference to globally
- // defined snippets
- registrySnippets.push(typeof item === 'string' ? snippets_es[item] : item);
- });
- } else if (typeof snippets === 'object') {
- registrySnippets.push(snippets);
- }
-
- const registry = new snippets_registry_es(registrySnippets.filter(Boolean));
-
- // for non-stylesheet syntaxes add Lorem Ipsum generator
- if (type !== 'stylesheet') {
- registry.get(0).set(reLorem, loremGenerator);
- }
-
- return registry;
-}
-
-function loremGenerator(node) {
- const options = {};
- const m = node.name.match(reLorem);
- if (m[1]) {
- options.lang = m[1];
- }
-
- if (m[2]) {
- options.wordCount = +m[2];
- }
-
- return lorem_es(node, options);
-}
-
-/**
- * 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 expand_es_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}
- */
-function expand$2(abbr, config) {
- config = createOptions(config);
-
- return getType(config.type, config.syntax) === 'stylesheet' ? expand$1(abbr, config) : expand(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}
- */
-function parse$2(abbr, options) {
- options = createOptions(options);
-
- return getType(options.type, options.syntax) === 'stylesheet' ? parse$1(abbr, options) : expand_es_parse(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}
- */
-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 snippets_registry_es ? snippets : snippetsRegistryFactory(type, syntax, snippets);
-}
-
-function createOptions(options) {
- if (typeof options === 'string') {
- options = { syntax: options };
- }
-
- options = expand_es__extends({}, expand_es_defaultOptions, options);
- if (options.type == null && options.syntax) {
- options.type = isStylesheet(options.syntax) ? 'stylesheet' : 'markup';
- }
-
- options.format = expand_es__extends({ field: options.field }, options.format);
- options.profile = createProfile(options);
- options.variables = expand_es__extends({}, 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}
- */
-function isStylesheet(syntax) {
- return stylesheetSyntaxes.indexOf(syntax) !== -1;
-}
-
-/**
- * Creates output profile from given options
- * @param {Object} options
- * @return {Profile}
- */
-function createProfile(options) {
- return options.profile instanceof output_profile_es ? options.profile : new output_profile_es(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';
-}
-
-
-//# sourceMappingURL=expand.es.js.map
-// CONCATENATED MODULE: ../node_modules/@emmetio/css-snippets-resolver/dist/css-snippets-resolver.es.js
-var dist_css_snippets_resolver_es__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-const dist_css_snippets_resolver_es_DASH = 45; // -
-
-/**
- * Calculates fuzzy match score of how close `abbr` matches given `string`.
- * @param {String} abbr Abbreviation to score
- * @param {String} string String to match
- * @param {Number} [fuzziness] Fuzzy factor
- * @return {Number} Match score
- */
-function css_snippets_resolver_es_stringScore(abbr, string) {
- abbr = abbr.toLowerCase();
- string = string.toLowerCase();
-
- if (abbr === string) {
- return 1;
- }
-
- // a string MUST start with the same character as abbreviation
- if (!string || abbr.charCodeAt(0) !== string.charCodeAt(0)) {
- return 0;
- }
-
- const abbrLength = abbr.length;
- const stringLength = string.length;
- let i = 1,
- j = 1,
- score = stringLength;
- let ch1, ch2, found, acronym;
-
- while (i < abbrLength) {
- ch1 = abbr.charCodeAt(i);
- found = false;
- acronym = false;
-
- while (j < stringLength) {
- ch2 = string.charCodeAt(j);
-
- if (ch1 === ch2) {
- found = true;
- score += (stringLength - j) * (acronym ? 2 : 1);
- break;
- }
-
- // add acronym bonus for exactly next match after unmatched `-`
- acronym = ch2 === dist_css_snippets_resolver_es_DASH;
- j++;
- }
-
- if (!found) {
- break;
- }
-
- i++;
- }
-
- return score && score * (i / abbrLength) / css_snippets_resolver_es_sum(stringLength);
-}
-
-/**
- * Calculates sum of first `n` natural numbers, e.g. 1+2+3+...n
- * @param {Number} n
- * @return {Number}
- */
-function css_snippets_resolver_es_sum(n) {
- return n * (n + 1) / 2;
-}
-
-const css_snippets_resolver_es_reProperty = /^([a-z\-]+)(?:\s*:\s*([^\n\r]+))?$/;
-const dist_css_snippets_resolver_es_DASH$1 = 45; // -
-
-/**
- * Creates a special structure for resolving CSS properties from plain CSS
- * snippets.
- * Almost all CSS snippets are aliases for real CSS properties with available
- * value variants, optionally separated by `|`. Most values are keywords that
- * can be fuzzy-resolved as well. Some CSS properties are shorthands for other,
- * more specific properties, like `border` and `border-style`. For such cases
- * keywords from more specific properties should be available in shorthands too.
- * @param {Snippet[]} snippets
- * @return {CSSSnippet[]}
- */
-function css_snippets_resolver_es_cssSnippets(snippets) {
- return css_snippets_resolver_es_nest(snippets.map(snippet => new css_snippets_resolver_es_CSSSnippet(snippet.key, snippet.value)));
-}
-
-let css_snippets_resolver_es_CSSSnippet = class CSSSnippet {
- constructor(key, value) {
- this.key = key;
- this.value = value;
- this.property = null;
-
- // detect if given snippet is a property
- const m = value && value.match(css_snippets_resolver_es_reProperty);
- if (m) {
- this.property = m[1];
- this.value = m[2];
- }
-
- this.dependencies = [];
- }
-
- addDependency(dep) {
- this.dependencies.push(dep);
- }
-
- get defaultValue() {
- return this.value != null ? css_snippets_resolver_es_splitValue(this.value)[0] : null;
- }
-
- /**
- * Returns list of unique keywords for current CSS snippet and its dependencies
- * @return {String[]}
- */
- keywords() {
- const stack = [];
- const keywords = new Set();
- let i = 0,
- item,
- candidates;
-
- if (this.property) {
- // scan valid CSS-properties only
- stack.push(this);
- }
-
- while (i < stack.length) {
- // NB Keep items in stack instead of push/pop to avoid possible
- // circular references
- item = stack[i++];
-
- if (item.value) {
- candidates = css_snippets_resolver_es_splitValue(item.value).filter(dist_css_snippets_resolver_es_isKeyword);
-
- // extract possible keywords from snippet value
- for (let j = 0; j < candidates.length; j++) {
- keywords.add(candidates[j].trim());
- }
-
- // add dependencies into scan stack
- for (let j = 0, deps = item.dependencies; j < deps.length; j++) {
- if (stack.indexOf(deps[j]) === -1) {
- stack.push(deps[j]);
- }
- }
- }
- }
-
- return Array.from(keywords);
- }
-};
-
-/**
- * Nests more specific CSS properties into shorthand ones, e.g.
- * background-position-x -> background-position -> background
- * @param {CSSSnippet[]} snippets
- * @return {CSSSnippet[]}
- */
-
-function css_snippets_resolver_es_nest(snippets) {
- snippets = snippets.sort(css_snippets_resolver_es_snippetsSort);
- const stack = [];
-
- // For sorted list of CSS properties, create dependency graph where each
- // shorthand property contains its more specific one, e.g.
- // backgound -> background-position -> background-position-x
- for (let i = 0, cur, prev; i < snippets.length; i++) {
- cur = snippets[i];
-
- if (!cur.property) {
- // not a CSS property, skip it
- continue;
- }
-
- // Check if current property belongs to one from parent stack.
- // Since `snippets` array is sorted, items are perfectly aligned
- // from shorthands to more specific variants
- while (stack.length) {
- prev = stack[stack.length - 1];
-
- if (cur.property.indexOf(prev.property) === 0 && cur.property.charCodeAt(prev.property.length) === dist_css_snippets_resolver_es_DASH$1) {
- prev.addDependency(cur);
- stack.push(cur);
- break;
- }
-
- stack.pop();
- }
-
- if (!stack.length) {
- stack.push(cur);
- }
- }
-
- return snippets;
-}
-
-/**
- * A sorting function for array of snippets
- * @param {CSSSnippet} a
- * @param {CSSSnippet} b
- * @return {Number}
- */
-function css_snippets_resolver_es_snippetsSort(a, b) {
- if (a.key === b.key) {
- return 0;
- }
-
- return a.key < b.key ? -1 : 1;
-}
-
-/**
- * Check if given string is a keyword candidate
- * @param {String} str
- * @return {Boolean}
- */
-function dist_css_snippets_resolver_es_isKeyword(str) {
- return (/^\s*[\w-]+/.test(str)
- );
-}
-
-function css_snippets_resolver_es_splitValue(value) {
- return String(value).split('|');
-}
-
-const css_snippets_resolver_es_globalKeywords = ['auto', 'inherit', 'unset'];
-const css_snippets_resolver_es_unitlessProperties = ['z-index', 'line-height', 'opacity', 'font-weight', 'zoom', 'flex', 'flex-grow', 'flex-shrink'];
-
-const dist_css_snippets_resolver_es_defaultOptions = {
- intUnit: 'px',
- floatUnit: 'em',
- unitAliases: {
- e: 'em',
- p: '%',
- x: 'ex',
- r: 'rem'
- },
- fuzzySearchMinScore: 0
-};
-
-/**
- * For every node in given `tree`, finds matching snippet from `registry` and
- * updates node with snippet data.
- *
- * This resolver uses fuzzy matching for searching matched snippets and their
- * keyword values.
- */
-
-function dist_css_snippets_resolver_es_index(tree, registry, options) {
- options = dist_css_snippets_resolver_es__extends({}, dist_css_snippets_resolver_es_defaultOptions, options);
- options.unitAliases = dist_css_snippets_resolver_es__extends({}, dist_css_snippets_resolver_es_defaultOptions.unitAliases, options && options.unitAliases);
-
- const snippets = css_snippets_resolver_es_convertToCSSSnippets(registry);
-
- tree.walk(node => dist_css_snippets_resolver_es_resolveNode(node, snippets, options));
- return tree;
-}
-
-function css_snippets_resolver_es_convertToCSSSnippets(registry) {
- return css_snippets_resolver_es_cssSnippets(registry.all({ type: 'string' }));
-}
-
-/**
- * Resolves given node: finds matched CSS snippets using fuzzy match and resolves
- * keyword aliases from node value
- * @param {Node} node
- * @param {CSSSnippet[]} snippets
- * @param {Object} options
- * @return {Node}
- */
-function dist_css_snippets_resolver_es_resolveNode(node, snippets, options) {
- const snippet = css_snippets_resolver_es_findBestMatch(node.name, snippets, 'key', options.fuzzySearchMinScore);
-
- if (!snippet) {
- // Edge case: `!important` snippet
- return node.name === '!' ? css_snippets_resolver_es_setNodeAsText(node, '!important') : node;
- }
-
- return snippet.property ? css_snippets_resolver_es_resolveAsProperty(node, snippet, options) : css_snippets_resolver_es_resolveAsSnippet(node, snippet);
-}
-
-/**
- * Resolves given parsed abbreviation node as CSS property
- * @param {Node} node
- * @param {CSSSnippet} snippet
- * @param {Object} formatOptions
- * @return {Node}
- */
-function css_snippets_resolver_es_resolveAsProperty(node, snippet, formatOptions) {
- const abbr = node.name;
- node.name = snippet.property;
-
- if (node.value && typeof node.value === 'object') {
- // resolve keyword shortcuts
- const keywords = snippet.keywords();
-
- if (!node.value.size) {
- // no value defined, try to resolve unmatched part as a keyword alias
- let kw = css_snippets_resolver_es_findBestMatch(css_snippets_resolver_es_getUnmatchedPart(abbr, snippet.key), keywords);
-
- if (!kw) {
- // no matching value, try to get default one
- kw = snippet.defaultValue;
- if (kw && kw.indexOf('${') === -1) {
- // Quick and dirty test for existing field. If not, wrap
- // default value in a field
- kw = `\${1:${kw}}`;
- }
- }
-
- if (kw) {
- node.value.add(kw);
- }
- } else {
- // replace keyword aliases in current node value
- for (let i = 0, token; i < node.value.value.length; i++) {
- token = node.value.value[i];
-
- if (token === '!') {
- token = `${!i ? '${1} ' : ''}!important`;
- } else if (css_snippets_resolver_es_isKeyword$1(token)) {
- token = css_snippets_resolver_es_findBestMatch(token.value, keywords) || css_snippets_resolver_es_findBestMatch(token.value, css_snippets_resolver_es_globalKeywords) || token;
- } else if (css_snippets_resolver_es_isNumericValue(token)) {
- token = css_snippets_resolver_es_resolveNumericValue(node.name, token, formatOptions);
- }
-
- node.value.value[i] = token;
- }
- }
- }
-
- return node;
-}
-
-/**
- * Resolves given parsed abbreviation node as a snippet: a plain code chunk
- * @param {Node} node
- * @param {CSSSnippet} snippet
- * @return {Node}
- */
-function css_snippets_resolver_es_resolveAsSnippet(node, snippet) {
- return css_snippets_resolver_es_setNodeAsText(node, snippet.value);
-}
-
-/**
- * Sets given parsed abbreviation node as a text snippet
- * @param {Node} node
- * @param {String} text
- * @return {Node}
- */
-function css_snippets_resolver_es_setNodeAsText(node, text) {
- node.name = null;
- node.value = text;
- return node;
-}
-
-/**
- * Finds best matching item from `items` array
- * @param {String} abbr Abbreviation to match
- * @param {Array} items List of items for match
- * @param {String} [key] If `items` is a list of objects, use `key` as object
- * property to test against
- * @param {Number} fuzzySearchMinScore The minimum score the best matched item should have to be a valid match.
- * @return {*}
- */
-function css_snippets_resolver_es_findBestMatch(abbr, items, key, fuzzySearchMinScore) {
- if (!abbr) {
- return null;
- }
-
- let matchedItem = null;
- let maxScore = 0;
- fuzzySearchMinScore = fuzzySearchMinScore || 0;
-
- for (let i = 0, item; i < items.length; i++) {
- item = items[i];
- const score = css_snippets_resolver_es_stringScore(abbr, css_snippets_resolver_es_getScoringPart(item, key));
-
- if (score === 1) {
- // direct hit, no need to look further
- return item;
- }
-
- if (score && score >= maxScore) {
- maxScore = score;
- matchedItem = item;
- }
- }
-
- return maxScore >= fuzzySearchMinScore ? matchedItem : null;
-}
-
-function css_snippets_resolver_es_getScoringPart(item, key) {
- const value = item && typeof item === 'object' ? item[key] : item;
- const m = (value || '').match(/^[\w-@]+/);
- return m ? m[0] : value;
-}
-
-/**
- * Returns a part of `abbr` that wasn’t directly matched agains `string`.
- * For example, if abbreviation `poas` is matched against `position`, the unmatched part will be `as`
- * since `a` wasn’t found in string stream
- * @param {String} abbr
- * @param {String} string
- * @return {String}
- */
-function css_snippets_resolver_es_getUnmatchedPart(abbr, string) {
- for (let i = 0, lastPos = 0; i < abbr.length; i++) {
- lastPos = string.indexOf(abbr[i], lastPos);
- if (lastPos === -1) {
- return abbr.slice(i);
- }
- lastPos++;
- }
-
- return '';
-}
-
-/**
- * Check if given CSS value token is a keyword
- * @param {*} token
- * @return {Boolean}
- */
-function css_snippets_resolver_es_isKeyword$1(token) {
- return css_snippets_resolver_es_tokenTypeOf(token, 'keyword');
-}
-
-/**
- * Check if given CSS value token is a numeric value
- * @param {*} token
- * @return {Boolean}
- */
-function css_snippets_resolver_es_isNumericValue(token) {
- return css_snippets_resolver_es_tokenTypeOf(token, 'numeric');
-}
-
-function css_snippets_resolver_es_tokenTypeOf(token, type) {
- return token && typeof token === 'object' && token.type === type;
-}
-
-/**
- * Resolves numeric value for given CSS property
- * @param {String} property CSS property name
- * @param {NumericValue} token CSS numeric value token
- * @param {Object} formatOptions Formatting options for units
- * @return {NumericValue}
- */
-function css_snippets_resolver_es_resolveNumericValue(property, token, formatOptions) {
- if (token.unit) {
- token.unit = formatOptions.unitAliases[token.unit] || token.unit;
- } else if (token.value !== 0 && css_snippets_resolver_es_unitlessProperties.indexOf(property) === -1) {
- // use `px` for integers, `em` for floats
- // NB: num|0 is a quick alternative to Math.round(0)
- token.unit = token.value === (token.value | 0) ? formatOptions.intUnit : formatOptions.floatUnit;
- }
-
- return token;
-}
-
-/* harmony default export */ var dist_css_snippets_resolver_es = (dist_css_snippets_resolver_es_index);
-
-//# sourceMappingURL=css-snippets-resolver.es.js.map
-// CONCATENATED MODULE: ../node_modules/@emmetio/html-matcher/dist/html-matcher.es.js
-var html_matcher_es__extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
-
-
-
-let html_matcher_es_Node = class Node {
- constructor(stream, type, open, close) {
- this.stream = stream;
- this.type = type;
- this.open = open;
- this.close = close;
-
- this.children = [];
- this.parent = null;
- }
-
- /**
- * Returns node name
- * @return {String}
- */
- get name() {
- if (this.type === 'tag' && this.open) {
- return this.open && this.open.name && this.open.name.value;
- }
-
- return '#' + this.type;
- }
-
- /**
- * Returns attributes of current node
- * @return {Array}
- */
- get attributes() {
- return this.open && this.open.attributes;
- }
-
- /**
- * Returns node’s start position in stream
- * @return {*}
- */
- get start() {
- return this.open && this.open.start;
- }
-
- /**
- * Returns node’s start position in stream
- * @return {*}
- */
- get end() {
- return this.close ? this.close.end : this.open && this.open.end;
- }
-
- get firstChild() {
- return this.children[0];
- }
-
- get nextSibling() {
- const ix = this.getIndex();
- return ix !== -1 ? this.parent.children[ix + 1] : null;
- }
-
- get previousSibling() {
- const ix = this.getIndex();
- return ix !== -1 ? this.parent.children[ix - 1] : null;
- }
-
- /**
- * Returns current element’s index in parent list of child nodes
- * @return {Number}
- */
- getIndex() {
- return this.parent ? this.parent.children.indexOf(this) : -1;
- }
-
- /**
- * Adds given node as a child
- * @param {Node} node
- * @return {Node} Current node
- */
- addChild(node) {
- this.removeChild(node);
- this.children.push(node);
- node.parent = this;
- return this;
- }
-
- /**
- * Removes given node from current node’s child list
- * @param {Node} node
- * @return {Node} Current node
- */
- removeChild(node) {
- const ix = this.children.indexOf(node);
- if (ix !== -1) {
- this.children.splice(ix, 1);
- node.parent = null;
- }
-
- return this;
- }
-};
-
-/**
- * A token factory method
- * @param {StreamReader} stream
- * @param {Point|Function} start Tokens’ start location or stream consumer
- * @param {Point} [end] Tokens’ end location
- * @return {Token}
- */
-
-var html_matcher_es_token = function (stream, start, end) {
- return typeof start === 'function' ? eatToken(stream, start) : new Token(stream, start, end);
-};
-
-/**
- * Consumes characters from given stream that matches `fn` call and returns it
- * as token, if consumed
- * @param {StreamReader} stream
- * @param {Function} test
- * @return {Token}
- */
-function eatToken(stream, test) {
- const start = stream.pos;
- if (stream.eatWhile(test)) {
- return new Token(stream, start, stream.pos);
- }
-
- stream.pos = start;
-}
-
-/**
- * A structure describing text fragment in content stream
- */
-let Token = class Token {
- /**
- * @param {ContentStreamReader} stream
- * @param {Point} start Tokens’ start location in content stream
- * @param {Point} end Tokens’ end location in content stream
- */
- constructor(stream, start, end) {
- this.stream = stream;
- this.start = start != null ? start : stream.start;
- this.end = end != null ? end : stream.pos;
- this._value = null;
- }
-
- /**
- * Returns token textual value
- * NB implemented as getter to reduce unnecessary memory allocations for
- * strings that not required
- * @return {String}
- */
- get value() {
- if (this._value === null) {
- const start = this.stream.start;
- const end = this.stream.pos;
-
- this.stream.start = this.start;
- this.stream.pos = this.end;
- this._value = this.stream.current();
-
- this.stream.start = start;
- this.stream.pos = end;
- }
-
- return this._value;
- }
-
- toString() {
- return this.value;
- }
-
- valueOf() {
- return `${this.value} [${this.start}; ${this.end}]`;
- }
-};
-
-
-const LANGLE = 60;
-const RANGLE = 62; // < and >
-const LSQUARE = 91;
-const RSQUARE = 93; // [ and ]
-const LROUND = 40;
-const RROUND = 41; // ( and )
-const LCURLY = 123;
-const RCURLY = 125; // { and }
-
-const html_matcher_es_opt = { throws: true };
-
-/**
- * Consumes paired tokens (like `[` and `]`) with respect of nesting and embedded
- * quoted values
- * @param {StreamReader} stream
- * @return {Token} A token with consumed paired character
- */
-var eatPaired = function (stream) {
- const start = stream.pos;
- const consumed = eatPair(stream, LANGLE, RANGLE, html_matcher_es_opt) || eatPair(stream, LSQUARE, RSQUARE, html_matcher_es_opt) || eatPair(stream, LROUND, RROUND, html_matcher_es_opt) || eatPair(stream, LCURLY, RCURLY, html_matcher_es_opt);
-
- if (consumed) {
- return html_matcher_es_token(stream, start);
- }
-};
-
-const SLASH$1 = 47; // /
-const html_matcher_es_EQUALS = 61; // =
-const RIGHT_ANGLE$1 = 62; // >
-
-/**
- * Consumes attributes from given stream
- * @param {StreamReader} stream
- * @return {Array} Array of consumed attributes
- */
-var eatAttributes = function (stream) {
- const result = [];
- let name, value, attr;
-
- while (!stream.eof()) {
- stream.eatWhile(isSpace);
- attr = { start: stream.pos };
-
- // A name could be a regular name or expression:
- // React-style –