/******/ (function(modules) { // webpackBootstrap /******/ // install a JSONP callback for chunk loading /******/ var parentJsonpFunction = window["webpackJsonp"]; /******/ window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) { /******/ // add "moreModules" to the modules object, /******/ // then flag all "chunkIds" as loaded and fire callback /******/ var moduleId, chunkId, i = 0, resolves = [], result; /******/ for(;i < chunkIds.length; i++) { /******/ chunkId = chunkIds[i]; /******/ if(installedChunks[chunkId]) { /******/ resolves.push(installedChunks[chunkId][0]); /******/ } /******/ installedChunks[chunkId] = 0; /******/ } /******/ for(moduleId in moreModules) { /******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { /******/ modules[moduleId] = moreModules[moduleId]; /******/ } /******/ } /******/ if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules); /******/ while(resolves.length) { /******/ resolves.shift()(); /******/ } /******/ if(executeModules) { /******/ for(i=0; i < executeModules.length; i++) { /******/ result = __webpack_require__(__webpack_require__.s = executeModules[i]); /******/ } /******/ } /******/ return result; /******/ }; /******/ /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // objects to store loaded and loading chunks /******/ var installedChunks = { /******/ 3: 0 /******/ }; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ // This file contains only the entry chunk. /******/ // The chunk loading function for additional chunks /******/ __webpack_require__.e = function requireEnsure(chunkId) { /******/ var installedChunkData = installedChunks[chunkId]; /******/ if(installedChunkData === 0) { /******/ return new Promise(function(resolve) { resolve(); }); /******/ } /******/ /******/ // a Promise means "currently loading". /******/ if(installedChunkData) { /******/ return installedChunkData[2]; /******/ } /******/ /******/ // setup Promise in chunk cache /******/ var promise = new Promise(function(resolve, reject) { /******/ installedChunkData = installedChunks[chunkId] = [resolve, reject]; /******/ }); /******/ installedChunkData[2] = promise; /******/ /******/ // start chunk loading /******/ var head = document.getElementsByTagName('head')[0]; /******/ var script = document.createElement('script'); /******/ script.type = "text/javascript"; /******/ script.charset = 'utf-8'; /******/ script.async = true; /******/ script.timeout = 120000; /******/ /******/ if (__webpack_require__.nc) { /******/ script.setAttribute("nonce", __webpack_require__.nc); /******/ } /******/ script.src = __webpack_require__.p + "" + ({"0":"monaco"}[chunkId]||chunkId) + ".chunk.js"; /******/ var timeout = setTimeout(onScriptComplete, 120000); /******/ script.onerror = script.onload = onScriptComplete; /******/ function onScriptComplete() { /******/ // avoid mem leaks in IE. /******/ script.onerror = script.onload = null; /******/ clearTimeout(timeout); /******/ var chunk = installedChunks[chunkId]; /******/ if(chunk !== 0) { /******/ if(chunk) { /******/ chunk[1](new Error('Loading chunk ' + chunkId + ' failed.')); /******/ } /******/ installedChunks[chunkId] = undefined; /******/ } /******/ }; /******/ head.appendChild(script); /******/ /******/ return promise; /******/ }; /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = "./"; /******/ /******/ // on error function for async loading /******/ __webpack_require__.oe = function(err) { console.error(err); throw err; }; /******/ }) /************************************************************************/ /******/ ({ /***/ "+BLB": /***/ (function(module, exports, __webpack_require__) { "use strict"; // (C) 1995-2013 Jean-loup Gailly and Mark Adler // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. var utils = __webpack_require__("tbG5"); var trees = __webpack_require__("+sRJ"); var adler32 = __webpack_require__("uxo6"); var crc32 = __webpack_require__("X4kj"); var msg = __webpack_require__("gMAY"); /* Public constants ==========================================================*/ /* ===========================================================================*/ /* Allowed flush values; see deflate() and inflate() below for details */ var Z_NO_FLUSH = 0; var Z_PARTIAL_FLUSH = 1; //var Z_SYNC_FLUSH = 2; var Z_FULL_FLUSH = 3; var Z_FINISH = 4; var Z_BLOCK = 5; //var Z_TREES = 6; /* Return codes for the compression/decompression functions. Negative values * are errors, positive values are used for special but normal events. */ var Z_OK = 0; var Z_STREAM_END = 1; //var Z_NEED_DICT = 2; //var Z_ERRNO = -1; var Z_STREAM_ERROR = -2; var Z_DATA_ERROR = -3; //var Z_MEM_ERROR = -4; var Z_BUF_ERROR = -5; //var Z_VERSION_ERROR = -6; /* compression levels */ //var Z_NO_COMPRESSION = 0; //var Z_BEST_SPEED = 1; //var Z_BEST_COMPRESSION = 9; var Z_DEFAULT_COMPRESSION = -1; var Z_FILTERED = 1; var Z_HUFFMAN_ONLY = 2; var Z_RLE = 3; var Z_FIXED = 4; var Z_DEFAULT_STRATEGY = 0; /* Possible values of the data_type field (though see inflate()) */ //var Z_BINARY = 0; //var Z_TEXT = 1; //var Z_ASCII = 1; // = Z_TEXT var Z_UNKNOWN = 2; /* The deflate compression method */ var Z_DEFLATED = 8; /*============================================================================*/ var MAX_MEM_LEVEL = 9; /* Maximum value for memLevel in deflateInit2 */ var MAX_WBITS = 15; /* 32K LZ77 window */ var DEF_MEM_LEVEL = 8; var LENGTH_CODES = 29; /* number of length codes, not counting the special END_BLOCK code */ var LITERALS = 256; /* number of literal bytes 0..255 */ var L_CODES = LITERALS + 1 + LENGTH_CODES; /* number of Literal or Length codes, including the END_BLOCK code */ var D_CODES = 30; /* number of distance codes */ var BL_CODES = 19; /* number of codes used to transfer the bit lengths */ var HEAP_SIZE = 2 * L_CODES + 1; /* maximum heap size */ var MAX_BITS = 15; /* All codes must not exceed MAX_BITS bits */ var MIN_MATCH = 3; var MAX_MATCH = 258; var MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1; var PRESET_DICT = 0x20; var INIT_STATE = 42; var EXTRA_STATE = 69; var NAME_STATE = 73; var COMMENT_STATE = 91; var HCRC_STATE = 103; var BUSY_STATE = 113; var FINISH_STATE = 666; var BS_NEED_MORE = 1; /* block not completed, need more input or more output */ var BS_BLOCK_DONE = 2; /* block flush performed */ var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */ var BS_FINISH_DONE = 4; /* finish done, accept no more input or output */ var OS_CODE = 0x03; // Unix :) . Don't detect, use this default. function err(strm, errorCode) { strm.msg = msg[errorCode]; return errorCode; } function rank(f) { return (f << 1) - (f > 4 ? 9 : 0); } function zero(buf) { var len = buf.length;while (--len >= 0) { buf[len] = 0; } } /* ========================================================================= * Flush as much pending output as possible. All deflate() output goes * through this function so some applications may wish to modify it * to avoid allocating a large strm->output buffer and copying into it. * (See also read_buf()). */ function flush_pending(strm) { var s = strm.state; //_tr_flush_bits(s); var len = s.pending; if (len > strm.avail_out) { len = strm.avail_out; } if (len === 0) { return; } utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out); strm.next_out += len; s.pending_out += len; strm.total_out += len; strm.avail_out -= len; s.pending -= len; if (s.pending === 0) { s.pending_out = 0; } } function flush_block_only(s, last) { trees._tr_flush_block(s, s.block_start >= 0 ? s.block_start : -1, s.strstart - s.block_start, last); s.block_start = s.strstart; flush_pending(s.strm); } function put_byte(s, b) { s.pending_buf[s.pending++] = b; } /* ========================================================================= * Put a short in the pending buffer. The 16-bit value is put in MSB order. * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ function putShortMSB(s, b) { // put_byte(s, (Byte)(b >> 8)); // put_byte(s, (Byte)(b & 0xff)); s.pending_buf[s.pending++] = b >>> 8 & 0xff; s.pending_buf[s.pending++] = b & 0xff; } /* =========================================================================== * Read a new buffer from the current input stream, update the adler32 * and total number of bytes read. All deflate() input goes through * this function so some applications may wish to modify it to avoid * allocating a large strm->input buffer and copying from it. * (See also flush_pending()). */ function read_buf(strm, buf, start, size) { var len = strm.avail_in; if (len > size) { len = size; } if (len === 0) { return 0; } strm.avail_in -= len; // zmemcpy(buf, strm->next_in, len); utils.arraySet(buf, strm.input, strm.next_in, len, start); if (strm.state.wrap === 1) { strm.adler = adler32(strm.adler, buf, len, start); } else if (strm.state.wrap === 2) { strm.adler = crc32(strm.adler, buf, len, start); } strm.next_in += len; strm.total_in += len; return len; } /* =========================================================================== * Set match_start to the longest match starting at the given string and * return its length. Matches shorter or equal to prev_length are discarded, * in which case the result is equal to prev_length and match_start is * garbage. * IN assertions: cur_match is the head of the hash chain for the current * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ function longest_match(s, cur_match) { var chain_length = s.max_chain_length; /* max hash chain length */ var scan = s.strstart; /* current string */ var match; /* matched string */ var len; /* length of current match */ var best_len = s.prev_length; /* best match length so far */ var nice_match = s.nice_match; /* stop if match long enough */ var limit = s.strstart > s.w_size - MIN_LOOKAHEAD ? s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0 /*NIL*/; var _win = s.window; // shortcut var wmask = s.w_mask; var prev = s.prev; /* Stop when cur_match becomes <= limit. To simplify the code, * we prevent matches with the string of window index 0. */ var strend = s.strstart + MAX_MATCH; var scan_end1 = _win[scan + best_len - 1]; var scan_end = _win[scan + best_len]; /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); /* Do not waste too much time if we already have a good match: */ if (s.prev_length >= s.good_match) { chain_length >>= 2; } /* Do not look for matches beyond the end of the input. This is necessary * to make deflate deterministic. */ if (nice_match > s.lookahead) { nice_match = s.lookahead; } // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); do { // Assert(cur_match < s->strstart, "no future"); match = cur_match; /* Skip to next match if the match length cannot increase * or if the match length is less than 2. Note that the checks below * for insufficient lookahead only occur occasionally for performance * reasons. Therefore uninitialized memory will be accessed, and * conditional jumps will be made that depend on those values. * However the length of the match is limited to the lookahead, so * the output of deflate is not affected by the uninitialized values. */ if (_win[match + best_len] !== scan_end || _win[match + best_len - 1] !== scan_end1 || _win[match] !== _win[scan] || _win[++match] !== _win[scan + 1]) { continue; } /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2; match++; // Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { /*jshint noempty:false*/ } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && scan < strend); // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (strend - scan); scan = strend - MAX_MATCH; if (len > best_len) { s.match_start = cur_match; best_len = len; if (len >= nice_match) { break; } scan_end1 = _win[scan + best_len - 1]; scan_end = _win[scan + best_len]; } } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0); if (best_len <= s.lookahead) { return best_len; } return s.lookahead; } /* =========================================================================== * Fill the window when the lookahead becomes insufficient. * Updates strstart and lookahead. * * IN assertion: lookahead < MIN_LOOKAHEAD * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD * At least one byte has been read, or avail_in == 0; reads are * performed for at least two bytes (required for the zip translate_eol * option -- not supported here). */ function fill_window(s) { var _w_size = s.w_size; var p, n, m, more, str; //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); do { more = s.window_size - s.lookahead - s.strstart; // JS ints have 32 bit, block below not needed /* Deal with !@#$% 64K limit: */ //if (sizeof(int) <= 2) { // if (more == 0 && s->strstart == 0 && s->lookahead == 0) { // more = wsize; // // } else if (more == (unsigned)(-1)) { // /* Very unlikely, but possible on 16 bit machine if // * strstart == 0 && lookahead == 1 (input done a byte at time) // */ // more--; // } //} /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) { utils.arraySet(s.window, s.window, _w_size, _w_size, 0); s.match_start -= _w_size; s.strstart -= _w_size; /* we now have strstart >= MAX_DIST */ s.block_start -= _w_size; /* Slide the hash table (could be avoided with 32 bit values at the expense of memory usage). We slide even when level == 0 to keep the hash table consistent if we switch back to level > 0 later. (Using level 0 permanently is not an optimal usage of zlib, so we don't care about this pathological case.) */ n = s.hash_size; p = n; do { m = s.head[--p]; s.head[p] = m >= _w_size ? m - _w_size : 0; } while (--n); n = _w_size; p = n; do { m = s.prev[--p]; s.prev[p] = m >= _w_size ? m - _w_size : 0; /* If n is not on any hash chain, prev[n] is garbage but * its value will never be used. */ } while (--n); more += _w_size; } if (s.strm.avail_in === 0) { break; } /* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && * more == window_size - lookahead - strstart * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) * => more >= window_size - 2*WSIZE + 2 * In the BIG_MEM or MMAP case (not yet supported), * window_size == input_size + MIN_LOOKAHEAD && * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. * Otherwise, window_size == 2*WSIZE so more >= 2. * If there was sliding, more >= WSIZE. So in all cases, more >= 2. */ //Assert(more >= 2, "more < 2"); n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); s.lookahead += n; /* Initialize the hash value now that we have some input: */ if (s.lookahead + s.insert >= MIN_MATCH) { str = s.strstart - s.insert; s.ins_h = s.window[str]; /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */ s.ins_h = (s.ins_h << s.hash_shift ^ s.window[str + 1]) & s.hash_mask; //#if MIN_MATCH != 3 // Call update_hash() MIN_MATCH-3 more times //#endif while (s.insert) { /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ s.ins_h = (s.ins_h << s.hash_shift ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask; s.prev[str & s.w_mask] = s.head[s.ins_h]; s.head[s.ins_h] = str; str++; s.insert--; if (s.lookahead + s.insert < MIN_MATCH) { break; } } } /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, * but this is not important since only literal bytes will be emitted. */ } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); /* If the WIN_INIT bytes after the end of the current data have never been * written, then zero those bytes in order to avoid memory check reports of * the use of uninitialized (or uninitialised as Julian writes) bytes by * the longest match routines. Update the high water mark for the next * time through here. WIN_INIT is set to MAX_MATCH since the longest match * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. */ // if (s.high_water < s.window_size) { // var curr = s.strstart + s.lookahead; // var init = 0; // // if (s.high_water < curr) { // /* Previous high water mark below current data -- zero WIN_INIT // * bytes or up to end of window, whichever is less. // */ // init = s.window_size - curr; // if (init > WIN_INIT) // init = WIN_INIT; // zmemzero(s->window + curr, (unsigned)init); // s->high_water = curr + init; // } // else if (s->high_water < (ulg)curr + WIN_INIT) { // /* High water mark at or above current data, but below current data // * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up // * to end of window, whichever is less. // */ // init = (ulg)curr + WIN_INIT - s->high_water; // if (init > s->window_size - s->high_water) // init = s->window_size - s->high_water; // zmemzero(s->window + s->high_water, (unsigned)init); // s->high_water += init; // } // } // // Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, // "not enough room for search"); } /* =========================================================================== * Copy without compression as much as possible from the input stream, return * the current block state. * This function does not insert new strings in the dictionary since * uncompressible data is probably not useful. This function is used * only for the level=0 compression option. * NOTE: this function should be optimized to avoid extra copying from * window to pending_buf. */ function deflate_stored(s, flush) { /* Stored blocks are limited to 0xffff bytes, pending_buf is limited * to pending_buf_size, and each stored block has a 5 byte header: */ var max_block_size = 0xffff; if (max_block_size > s.pending_buf_size - 5) { max_block_size = s.pending_buf_size - 5; } /* Copy as much as possible from input to output: */ for (;;) { /* Fill the window as much as possible: */ if (s.lookahead <= 1) { //Assert(s->strstart < s->w_size+MAX_DIST(s) || // s->block_start >= (long)s->w_size, "slide too late"); // if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) || // s.block_start >= s.w_size)) { // throw new Error("slide too late"); // } fill_window(s); if (s.lookahead === 0 && flush === Z_NO_FLUSH) { return BS_NEED_MORE; } if (s.lookahead === 0) { break; } /* flush the current block */ } //Assert(s->block_start >= 0L, "block gone"); // if (s.block_start < 0) throw new Error("block gone"); s.strstart += s.lookahead; s.lookahead = 0; /* Emit a stored block if pending_buf will be full: */ var max_start = s.block_start + max_block_size; if (s.strstart === 0 || s.strstart >= max_start) { /* strstart == 0 is possible when wraparound on 16-bit machine */ s.lookahead = s.strstart - max_start; s.strstart = max_start; /*** FLUSH_BLOCK(s, 0); ***/ flush_block_only(s, false); if (s.strm.avail_out === 0) { return BS_NEED_MORE; } /***/ } /* Flush if we may have to slide, otherwise block_start may become * negative and the data will be gone: */ if (s.strstart - s.block_start >= s.w_size - MIN_LOOKAHEAD) { /*** FLUSH_BLOCK(s, 0); ***/ flush_block_only(s, false); if (s.strm.avail_out === 0) { return BS_NEED_MORE; } /***/ } } s.insert = 0; if (flush === Z_FINISH) { /*** FLUSH_BLOCK(s, 1); ***/ flush_block_only(s, true); if (s.strm.avail_out === 0) { return BS_FINISH_STARTED; } /***/ return BS_FINISH_DONE; } if (s.strstart > s.block_start) { /*** FLUSH_BLOCK(s, 0); ***/ flush_block_only(s, false); if (s.strm.avail_out === 0) { return BS_NEED_MORE; } /***/ } return BS_NEED_MORE; } /* =========================================================================== * Compress as much as possible from the input stream, return the current * block state. * This function does not perform lazy evaluation of matches and inserts * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ function deflate_fast(s, flush) { var hash_head; /* head of the hash chain */ var bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s.lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { return BS_NEED_MORE; } if (s.lookahead === 0) { break; /* flush the current block */ } } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = 0 /*NIL*/; if (s.lookahead >= MIN_MATCH) { /*** INSERT_STRING(s, s.strstart, hash_head); ***/ s.ins_h = (s.ins_h << s.hash_shift ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; s.head[s.ins_h] = s.strstart; /***/ } /* Find the longest match, discarding those <= prev_length. * At this point we have always match_length < MIN_MATCH */ if (hash_head !== 0 /*NIL*/ && s.strstart - hash_head <= s.w_size - MIN_LOOKAHEAD) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s.match_length = longest_match(s, hash_head); /* longest_match() sets match_start */ } if (s.match_length >= MIN_MATCH) { // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only /*** _tr_tally_dist(s, s.strstart - s.match_start, s.match_length - MIN_MATCH, bflush); ***/ bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); s.lookahead -= s.match_length; /* Insert new strings in the hash table only if the match length * is not too large. This saves time but degrades compression. */ if (s.match_length <= s.max_lazy_match /*max_insert_length*/ && s.lookahead >= MIN_MATCH) { s.match_length--; /* string at strstart already in table */ do { s.strstart++; /*** INSERT_STRING(s, s.strstart, hash_head); ***/ s.ins_h = (s.ins_h << s.hash_shift ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; s.head[s.ins_h] = s.strstart; /***/ /* strstart never exceeds WSIZE-MAX_MATCH, so there are * always MIN_MATCH bytes ahead. */ } while (--s.match_length !== 0); s.strstart++; } else { s.strstart += s.match_length; s.match_length = 0; s.ins_h = s.window[s.strstart]; /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */ s.ins_h = (s.ins_h << s.hash_shift ^ s.window[s.strstart + 1]) & s.hash_mask; //#if MIN_MATCH != 3 // Call UPDATE_HASH() MIN_MATCH-3 more times //#endif /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not * matter since it will be recomputed at next deflate call. */ } } else { /* No match, output a literal byte */ //Tracevv((stderr,"%c", s.window[s.strstart])); /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ bflush = trees._tr_tally(s, 0, s.window[s.strstart]); s.lookahead--; s.strstart++; } if (bflush) { /*** FLUSH_BLOCK(s, 0); ***/ flush_block_only(s, false); if (s.strm.avail_out === 0) { return BS_NEED_MORE; } /***/ } } s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1; if (flush === Z_FINISH) { /*** FLUSH_BLOCK(s, 1); ***/ flush_block_only(s, true); if (s.strm.avail_out === 0) { return BS_FINISH_STARTED; } /***/ return BS_FINISH_DONE; } if (s.last_lit) { /*** FLUSH_BLOCK(s, 0); ***/ flush_block_only(s, false); if (s.strm.avail_out === 0) { return BS_NEED_MORE; } /***/ } return BS_BLOCK_DONE; } /* =========================================================================== * Same as above, but achieves better compression. We use a lazy * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ function deflate_slow(s, flush) { var hash_head; /* head of hash chain */ var bflush; /* set if current block must be flushed */ var max_insert; /* Process the input block. */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s.lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { return BS_NEED_MORE; } if (s.lookahead === 0) { break; } /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = 0 /*NIL*/; if (s.lookahead >= MIN_MATCH) { /*** INSERT_STRING(s, s.strstart, hash_head); ***/ s.ins_h = (s.ins_h << s.hash_shift ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; s.head[s.ins_h] = s.strstart; /***/ } /* Find the longest match, discarding those <= prev_length. */ s.prev_length = s.match_length; s.prev_match = s.match_start; s.match_length = MIN_MATCH - 1; if (hash_head !== 0 /*NIL*/ && s.prev_length < s.max_lazy_match && s.strstart - hash_head <= s.w_size - MIN_LOOKAHEAD /*MAX_DIST(s)*/) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s.match_length = longest_match(s, hash_head); /* longest_match() sets match_start */ if (s.match_length <= 5 && (s.strategy === Z_FILTERED || s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096 /*TOO_FAR*/)) { /* If prev_match is also MIN_MATCH, match_start is garbage * but we will ignore the current match anyway. */ s.match_length = MIN_MATCH - 1; } } /* If there was a match at the previous step and the current * match is not better, output the previous match: */ if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) { max_insert = s.strstart + s.lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ //check_match(s, s.strstart-1, s.prev_match, s.prev_length); /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH, bflush);***/ bflush = trees._tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH); /* Insert in hash table all strings up to the end of the match. * strstart-1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ s.lookahead -= s.prev_length - 1; s.prev_length -= 2; do { if (++s.strstart <= max_insert) { /*** INSERT_STRING(s, s.strstart, hash_head); ***/ s.ins_h = (s.ins_h << s.hash_shift ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; s.head[s.ins_h] = s.strstart; /***/ } } while (--s.prev_length !== 0); s.match_available = 0; s.match_length = MIN_MATCH - 1; s.strstart++; if (bflush) { /*** FLUSH_BLOCK(s, 0); ***/ flush_block_only(s, false); if (s.strm.avail_out === 0) { return BS_NEED_MORE; } /***/ } } else if (s.match_available) { /* If there was no match at the previous position, output a * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ //Tracevv((stderr,"%c", s->window[s->strstart-1])); /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]); if (bflush) { /*** FLUSH_BLOCK_ONLY(s, 0) ***/ flush_block_only(s, false); /***/ } s.strstart++; s.lookahead--; if (s.strm.avail_out === 0) { return BS_NEED_MORE; } } else { /* There is no previous match to compare with, wait for * the next step to decide. */ s.match_available = 1; s.strstart++; s.lookahead--; } } //Assert (flush != Z_NO_FLUSH, "no flush?"); if (s.match_available) { //Tracevv((stderr,"%c", s->window[s->strstart-1])); /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]); s.match_available = 0; } s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1; if (flush === Z_FINISH) { /*** FLUSH_BLOCK(s, 1); ***/ flush_block_only(s, true); if (s.strm.avail_out === 0) { return BS_FINISH_STARTED; } /***/ return BS_FINISH_DONE; } if (s.last_lit) { /*** FLUSH_BLOCK(s, 0); ***/ flush_block_only(s, false); if (s.strm.avail_out === 0) { return BS_NEED_MORE; } /***/ } return BS_BLOCK_DONE; } /* =========================================================================== * For Z_RLE, simply look for runs of bytes, generate matches only of distance * one. Do not maintain a hash table. (It will be regenerated if this run of * deflate switches away from Z_RLE.) */ function deflate_rle(s, flush) { var bflush; /* set if current block must be flushed */ var prev; /* byte at distance one to match */ var scan, strend; /* scan goes up to strend for length of run */ var _win = s.window; for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the longest run, plus one for the unrolled loop. */ if (s.lookahead <= MAX_MATCH) { fill_window(s); if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) { return BS_NEED_MORE; } if (s.lookahead === 0) { break; } /* flush the current block */ } /* See how many times the previous byte repeats */ s.match_length = 0; if (s.lookahead >= MIN_MATCH && s.strstart > 0) { scan = s.strstart - 1; prev = _win[scan]; if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) { strend = s.strstart + MAX_MATCH; do { /*jshint noempty:false*/ } while (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan] && scan < strend); s.match_length = MAX_MATCH - (strend - scan); if (s.match_length > s.lookahead) { s.match_length = s.lookahead; } } //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ if (s.match_length >= MIN_MATCH) { //check_match(s, s.strstart, s.strstart - 1, s.match_length); /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/ bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH); s.lookahead -= s.match_length; s.strstart += s.match_length; s.match_length = 0; } else { /* No match, output a literal byte */ //Tracevv((stderr,"%c", s->window[s->strstart])); /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ bflush = trees._tr_tally(s, 0, s.window[s.strstart]); s.lookahead--; s.strstart++; } if (bflush) { /*** FLUSH_BLOCK(s, 0); ***/ flush_block_only(s, false); if (s.strm.avail_out === 0) { return BS_NEED_MORE; } /***/ } } s.insert = 0; if (flush === Z_FINISH) { /*** FLUSH_BLOCK(s, 1); ***/ flush_block_only(s, true); if (s.strm.avail_out === 0) { return BS_FINISH_STARTED; } /***/ return BS_FINISH_DONE; } if (s.last_lit) { /*** FLUSH_BLOCK(s, 0); ***/ flush_block_only(s, false); if (s.strm.avail_out === 0) { return BS_NEED_MORE; } /***/ } return BS_BLOCK_DONE; } /* =========================================================================== * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. * (It will be regenerated if this run of deflate switches away from Huffman.) */ function deflate_huff(s, flush) { var bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we have a literal to write. */ if (s.lookahead === 0) { fill_window(s); if (s.lookahead === 0) { if (flush === Z_NO_FLUSH) { return BS_NEED_MORE; } break; /* flush the current block */ } } /* Output a literal byte */ s.match_length = 0; //Tracevv((stderr,"%c", s->window[s->strstart])); /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ bflush = trees._tr_tally(s, 0, s.window[s.strstart]); s.lookahead--; s.strstart++; if (bflush) { /*** FLUSH_BLOCK(s, 0); ***/ flush_block_only(s, false); if (s.strm.avail_out === 0) { return BS_NEED_MORE; } /***/ } } s.insert = 0; if (flush === Z_FINISH) { /*** FLUSH_BLOCK(s, 1); ***/ flush_block_only(s, true); if (s.strm.avail_out === 0) { return BS_FINISH_STARTED; } /***/ return BS_FINISH_DONE; } if (s.last_lit) { /*** FLUSH_BLOCK(s, 0); ***/ flush_block_only(s, false); if (s.strm.avail_out === 0) { return BS_NEED_MORE; } /***/ } return BS_BLOCK_DONE; } /* Values for max_lazy_match, good_match and max_chain_length, depending on * the desired pack level (0..9). The values given below have been tuned to * exclude worst case performance for pathological files. Better values may be * found for specific files. */ function Config(good_length, max_lazy, nice_length, max_chain, func) { this.good_length = good_length; this.max_lazy = max_lazy; this.nice_length = nice_length; this.max_chain = max_chain; this.func = func; } var configuration_table; configuration_table = [ /* good lazy nice chain */ new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */ new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */ new Config(4, 5, 16, 8, deflate_fast), /* 2 */ new Config(4, 6, 32, 32, deflate_fast), /* 3 */ new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */ new Config(8, 16, 32, 32, deflate_slow), /* 5 */ new Config(8, 16, 128, 128, deflate_slow), /* 6 */ new Config(8, 32, 128, 256, deflate_slow), /* 7 */ new Config(32, 128, 258, 1024, deflate_slow), /* 8 */ new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */ ]; /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ function lm_init(s) { s.window_size = 2 * s.w_size; /*** CLEAR_HASH(s); ***/ zero(s.head); // Fill with NIL (= 0); /* Set the default configuration parameters: */ s.max_lazy_match = configuration_table[s.level].max_lazy; s.good_match = configuration_table[s.level].good_length; s.nice_match = configuration_table[s.level].nice_length; s.max_chain_length = configuration_table[s.level].max_chain; s.strstart = 0; s.block_start = 0; s.lookahead = 0; s.insert = 0; s.match_length = s.prev_length = MIN_MATCH - 1; s.match_available = 0; s.ins_h = 0; } function DeflateState() { this.strm = null; /* pointer back to this zlib stream */ this.status = 0; /* as the name implies */ this.pending_buf = null; /* output still pending */ this.pending_buf_size = 0; /* size of pending_buf */ this.pending_out = 0; /* next pending byte to output to the stream */ this.pending = 0; /* nb of bytes in the pending buffer */ this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ this.gzhead = null; /* gzip header information to write */ this.gzindex = 0; /* where in extra, name, or comment */ this.method = Z_DEFLATED; /* can only be DEFLATED */ this.last_flush = -1; /* value of flush param for previous deflate call */ this.w_size = 0; /* LZ77 window size (32K by default) */ this.w_bits = 0; /* log2(w_size) (8..16) */ this.w_mask = 0; /* w_size - 1 */ this.window = null; /* Sliding window. Input bytes are read into the second half of the window, * and move to the first half later to keep a dictionary of at least wSize * bytes. With this organization, matches are limited to a distance of * wSize-MAX_MATCH bytes, but this ensures that IO is always * performed with a length multiple of the block size. */ this.window_size = 0; /* Actual size of window: 2*wSize, except when the user input buffer * is directly used as sliding window. */ this.prev = null; /* Link to older string with same hash index. To limit the size of this * array to 64K, this link is maintained only for the last 32K strings. * An index in this array is thus a window index modulo 32K. */ this.head = null; /* Heads of the hash chains or NIL. */ this.ins_h = 0; /* hash index of string to be inserted */ this.hash_size = 0; /* number of elements in hash table */ this.hash_bits = 0; /* log2(hash_size) */ this.hash_mask = 0; /* hash_size-1 */ this.hash_shift = 0; /* Number of bits by which ins_h must be shifted at each input * step. It must be such that after MIN_MATCH steps, the oldest * byte no longer takes part in the hash key, that is: * hash_shift * MIN_MATCH >= hash_bits */ this.block_start = 0; /* Window position at the beginning of the current output block. Gets * negative when the window is moved backwards. */ this.match_length = 0; /* length of best match */ this.prev_match = 0; /* previous match */ this.match_available = 0; /* set if previous match exists */ this.strstart = 0; /* start of string to insert */ this.match_start = 0; /* start of matching string */ this.lookahead = 0; /* number of valid bytes ahead in window */ this.prev_length = 0; /* Length of the best match at previous step. Matches not greater than this * are discarded. This is used in the lazy match evaluation. */ this.max_chain_length = 0; /* To speed up deflation, hash chains are never searched beyond this * length. A higher limit improves compression ratio but degrades the * speed. */ this.max_lazy_match = 0; /* Attempt to find a better match only when the current match is strictly * smaller than this value. This mechanism is used only for compression * levels >= 4. */ // That's alias to max_lazy_match, don't use directly //this.max_insert_length = 0; /* Insert new strings in the hash table only if the match length is not * greater than this length. This saves time but degrades compression. * max_insert_length is used only for compression levels <= 3. */ this.level = 0; /* compression level (1..9) */ this.strategy = 0; /* favor or force Huffman coding*/ this.good_match = 0; /* Use a faster search when the previous match is longer than this */ this.nice_match = 0; /* Stop searching when current match exceeds this */ /* used by trees.c: */ /* Didn't use ct_data typedef below to suppress compiler warning */ // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ // Use flat array of DOUBLE size, with interleaved fata, // because JS does not support effective this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2); this.dyn_dtree = new utils.Buf16((2 * D_CODES + 1) * 2); this.bl_tree = new utils.Buf16((2 * BL_CODES + 1) * 2); zero(this.dyn_ltree); zero(this.dyn_dtree); zero(this.bl_tree); this.l_desc = null; /* desc. for literal tree */ this.d_desc = null; /* desc. for distance tree */ this.bl_desc = null; /* desc. for bit length tree */ //ush bl_count[MAX_BITS+1]; this.bl_count = new utils.Buf16(MAX_BITS + 1); /* number of codes at each bit length for an optimal tree */ //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ this.heap = new utils.Buf16(2 * L_CODES + 1); /* heap used to build the Huffman trees */ zero(this.heap); this.heap_len = 0; /* number of elements in the heap */ this.heap_max = 0; /* element of largest frequency */ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. * The same heap array is used to build all trees. */ this.depth = new utils.Buf16(2 * L_CODES + 1); //uch depth[2*L_CODES+1]; zero(this.depth); /* Depth of each subtree used as tie breaker for trees of equal frequency */ this.l_buf = 0; /* buffer index for literals or lengths */ this.lit_bufsize = 0; /* Size of match buffer for literals/lengths. There are 4 reasons for * limiting lit_bufsize to 64K: * - frequencies can be kept in 16 bit counters * - if compression is not successful for the first block, all input * data is still in the window so we can still emit a stored block even * when input comes from standard input. (This can also be done for * all blocks if lit_bufsize is not greater than 32K.) * - if compression is not successful for a file smaller than 64K, we can * even emit a stored file instead of a stored block (saving 5 bytes). * This is applicable only for zip (not gzip or zlib). * - creating new Huffman trees less frequently may not provide fast * adaptation to changes in the input data statistics. (Take for * example a binary file with poorly compressible code followed by * a highly compressible string table.) Smaller buffer sizes give * fast adaptation but have of course the overhead of transmitting * trees more frequently. * - I can't count above 4 */ this.last_lit = 0; /* running index in l_buf */ this.d_buf = 0; /* Buffer index for distances. To simplify the code, d_buf and l_buf have * the same number of elements. To use different lengths, an extra flag * array would be necessary. */ this.opt_len = 0; /* bit length of current block with optimal trees */ this.static_len = 0; /* bit length of current block with static trees */ this.matches = 0; /* number of string matches in current block */ this.insert = 0; /* bytes at end of window left to insert */ this.bi_buf = 0; /* Output buffer. bits are inserted starting at the bottom (least * significant bits). */ this.bi_valid = 0; /* Number of valid bits in bi_buf. All bits above the last valid bit * are always zero. */ // Used for window memory init. We safely ignore it for JS. That makes // sense only for pointers and memory check tools. //this.high_water = 0; /* High water mark offset in window for initialized bytes -- bytes above * this are set to zero in order to avoid memory check warnings when * longest match routines access bytes past the input. This is then * updated to the new high water mark. */ } function deflateResetKeep(strm) { var s; if (!strm || !strm.state) { return err(strm, Z_STREAM_ERROR); } strm.total_in = strm.total_out = 0; strm.data_type = Z_UNKNOWN; s = strm.state; s.pending = 0; s.pending_out = 0; if (s.wrap < 0) { s.wrap = -s.wrap; /* was made negative by deflate(..., Z_FINISH); */ } s.status = s.wrap ? INIT_STATE : BUSY_STATE; strm.adler = s.wrap === 2 ? 0 // crc32(0, Z_NULL, 0) : 1; // adler32(0, Z_NULL, 0) s.last_flush = Z_NO_FLUSH; trees._tr_init(s); return Z_OK; } function deflateReset(strm) { var ret = deflateResetKeep(strm); if (ret === Z_OK) { lm_init(strm.state); } return ret; } function deflateSetHeader(strm, head) { if (!strm || !strm.state) { return Z_STREAM_ERROR; } if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; } strm.state.gzhead = head; return Z_OK; } function deflateInit2(strm, level, method, windowBits, memLevel, strategy) { if (!strm) { // === Z_NULL return Z_STREAM_ERROR; } var wrap = 1; if (level === Z_DEFAULT_COMPRESSION) { level = 6; } if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; windowBits = -windowBits; } else if (windowBits > 15) { wrap = 2; /* write gzip wrapper instead */ windowBits -= 16; } if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return err(strm, Z_STREAM_ERROR); } if (windowBits === 8) { windowBits = 9; } /* until 256-byte window bug fixed */ var s = new DeflateState(); strm.state = s; s.strm = strm; s.wrap = wrap; s.gzhead = null; s.w_bits = windowBits; s.w_size = 1 << s.w_bits; s.w_mask = s.w_size - 1; s.hash_bits = memLevel + 7; s.hash_size = 1 << s.hash_bits; s.hash_mask = s.hash_size - 1; s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); s.window = new utils.Buf8(s.w_size * 2); s.head = new utils.Buf16(s.hash_size); s.prev = new utils.Buf16(s.w_size); // Don't need mem init magic for JS. //s.high_water = 0; /* nothing written to s->window yet */ s.lit_bufsize = 1 << memLevel + 6; /* 16K elements by default */ s.pending_buf_size = s.lit_bufsize * 4; //overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); //s->pending_buf = (uchf *) overlay; s.pending_buf = new utils.Buf8(s.pending_buf_size); // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`) //s->d_buf = overlay + s->lit_bufsize/sizeof(ush); s.d_buf = 1 * s.lit_bufsize; //s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; s.l_buf = (1 + 2) * s.lit_bufsize; s.level = level; s.strategy = strategy; s.method = method; return deflateReset(strm); } function deflateInit(strm, level) { return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); } function deflate(strm, flush) { var old_flush, s; var beg, val; // for gzip header write only if (!strm || !strm.state || flush > Z_BLOCK || flush < 0) { return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR; } s = strm.state; if (!strm.output || !strm.input && strm.avail_in !== 0 || s.status === FINISH_STATE && flush !== Z_FINISH) { return err(strm, strm.avail_out === 0 ? Z_BUF_ERROR : Z_STREAM_ERROR); } s.strm = strm; /* just in case */ old_flush = s.last_flush; s.last_flush = flush; /* Write the header */ if (s.status === INIT_STATE) { if (s.wrap === 2) { // GZIP header strm.adler = 0; //crc32(0L, Z_NULL, 0); put_byte(s, 31); put_byte(s, 139); put_byte(s, 8); if (!s.gzhead) { // s->gzhead == Z_NULL put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, s.level === 9 ? 2 : s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? 4 : 0); put_byte(s, OS_CODE); s.status = BUSY_STATE; } else { put_byte(s, (s.gzhead.text ? 1 : 0) + (s.gzhead.hcrc ? 2 : 0) + (!s.gzhead.extra ? 0 : 4) + (!s.gzhead.name ? 0 : 8) + (!s.gzhead.comment ? 0 : 16)); put_byte(s, s.gzhead.time & 0xff); put_byte(s, s.gzhead.time >> 8 & 0xff); put_byte(s, s.gzhead.time >> 16 & 0xff); put_byte(s, s.gzhead.time >> 24 & 0xff); put_byte(s, s.level === 9 ? 2 : s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? 4 : 0); put_byte(s, s.gzhead.os & 0xff); if (s.gzhead.extra && s.gzhead.extra.length) { put_byte(s, s.gzhead.extra.length & 0xff); put_byte(s, s.gzhead.extra.length >> 8 & 0xff); } if (s.gzhead.hcrc) { strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0); } s.gzindex = 0; s.status = EXTRA_STATE; } } else // DEFLATE header { var header = Z_DEFLATED + (s.w_bits - 8 << 4) << 8; var level_flags = -1; if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) { level_flags = 0; } else if (s.level < 6) { level_flags = 1; } else if (s.level === 6) { level_flags = 2; } else { level_flags = 3; } header |= level_flags << 6; if (s.strstart !== 0) { header |= PRESET_DICT; } header += 31 - header % 31; s.status = BUSY_STATE; putShortMSB(s, header); /* Save the adler32 of the preset dictionary: */ if (s.strstart !== 0) { putShortMSB(s, strm.adler >>> 16); putShortMSB(s, strm.adler & 0xffff); } strm.adler = 1; // adler32(0L, Z_NULL, 0); } } //#ifdef GZIP if (s.status === EXTRA_STATE) { if (s.gzhead.extra /* != Z_NULL*/) { beg = s.pending; /* start of bytes to update crc */ while (s.gzindex < (s.gzhead.extra.length & 0xffff)) { if (s.pending === s.pending_buf_size) { if (s.gzhead.hcrc && s.pending > beg) { strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); } flush_pending(strm); beg = s.pending; if (s.pending === s.pending_buf_size) { break; } } put_byte(s, s.gzhead.extra[s.gzindex] & 0xff); s.gzindex++; } if (s.gzhead.hcrc && s.pending > beg) { strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); } if (s.gzindex === s.gzhead.extra.length) { s.gzindex = 0; s.status = NAME_STATE; } } else { s.status = NAME_STATE; } } if (s.status === NAME_STATE) { if (s.gzhead.name /* != Z_NULL*/) { beg = s.pending; /* start of bytes to update crc */ //int val; do { if (s.pending === s.pending_buf_size) { if (s.gzhead.hcrc && s.pending > beg) { strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); } flush_pending(strm); beg = s.pending; if (s.pending === s.pending_buf_size) { val = 1; break; } } // JS specific: little magic to add zero terminator to end of string if (s.gzindex < s.gzhead.name.length) { val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff; } else { val = 0; } put_byte(s, val); } while (val !== 0); if (s.gzhead.hcrc && s.pending > beg) { strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); } if (val === 0) { s.gzindex = 0; s.status = COMMENT_STATE; } } else { s.status = COMMENT_STATE; } } if (s.status === COMMENT_STATE) { if (s.gzhead.comment /* != Z_NULL*/) { beg = s.pending; /* start of bytes to update crc */ //int val; do { if (s.pending === s.pending_buf_size) { if (s.gzhead.hcrc && s.pending > beg) { strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); } flush_pending(strm); beg = s.pending; if (s.pending === s.pending_buf_size) { val = 1; break; } } // JS specific: little magic to add zero terminator to end of string if (s.gzindex < s.gzhead.comment.length) { val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff; } else { val = 0; } put_byte(s, val); } while (val !== 0); if (s.gzhead.hcrc && s.pending > beg) { strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); } if (val === 0) { s.status = HCRC_STATE; } } else { s.status = HCRC_STATE; } } if (s.status === HCRC_STATE) { if (s.gzhead.hcrc) { if (s.pending + 2 > s.pending_buf_size) { flush_pending(strm); } if (s.pending + 2 <= s.pending_buf_size) { put_byte(s, strm.adler & 0xff); put_byte(s, strm.adler >> 8 & 0xff); strm.adler = 0; //crc32(0L, Z_NULL, 0); s.status = BUSY_STATE; } } else { s.status = BUSY_STATE; } } //#endif /* Flush as much pending output as possible */ if (s.pending !== 0) { flush_pending(strm); if (strm.avail_out === 0) { /* Since avail_out is 0, deflate will be called again with * more output space, but possibly with both pending and * avail_in equal to zero. There won't be anything to do, * but this is not an error situation so make sure we * return OK instead of BUF_ERROR at next call of deflate: */ s.last_flush = -1; return Z_OK; } /* Make sure there is something to do and avoid duplicate consecutive * flushes. For repeated and useless calls with Z_FINISH, we keep * returning Z_STREAM_END instead of Z_BUF_ERROR. */ } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && flush !== Z_FINISH) { return err(strm, Z_BUF_ERROR); } /* User must not provide more input after the first FINISH: */ if (s.status === FINISH_STATE && strm.avail_in !== 0) { return err(strm, Z_BUF_ERROR); } /* Start a new block or continue the current one. */ if (strm.avail_in !== 0 || s.lookahead !== 0 || flush !== Z_NO_FLUSH && s.status !== FINISH_STATE) { var bstate = s.strategy === Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : s.strategy === Z_RLE ? deflate_rle(s, flush) : configuration_table[s.level].func(s, flush); if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) { s.status = FINISH_STATE; } if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { if (strm.avail_out === 0) { s.last_flush = -1; /* avoid BUF_ERROR next call, see above */ } return Z_OK; /* If flush != Z_NO_FLUSH && avail_out == 0, the next call * of deflate should use the same flush parameter to make sure * that the flush is complete. So we don't have to output an * empty block here, this will be done at next call. This also * ensures that for a very small output buffer, we emit at most * one empty block. */ } if (bstate === BS_BLOCK_DONE) { if (flush === Z_PARTIAL_FLUSH) { trees._tr_align(s); } else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ trees._tr_stored_block(s, 0, 0, false); /* For a full flush, this empty block will be recognized * as a special marker by inflate_sync(). */ if (flush === Z_FULL_FLUSH) { /*** CLEAR_HASH(s); ***/ /* forget history */ zero(s.head); // Fill with NIL (= 0); if (s.lookahead === 0) { s.strstart = 0; s.block_start = 0; s.insert = 0; } } } flush_pending(strm); if (strm.avail_out === 0) { s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */ return Z_OK; } } } //Assert(strm->avail_out > 0, "bug2"); //if (strm.avail_out <= 0) { throw new Error("bug2");} if (flush !== Z_FINISH) { return Z_OK; } if (s.wrap <= 0) { return Z_STREAM_END; } /* Write the trailer */ if (s.wrap === 2) { put_byte(s, strm.adler & 0xff); put_byte(s, strm.adler >> 8 & 0xff); put_byte(s, strm.adler >> 16 & 0xff); put_byte(s, strm.adler >> 24 & 0xff); put_byte(s, strm.total_in & 0xff); put_byte(s, strm.total_in >> 8 & 0xff); put_byte(s, strm.total_in >> 16 & 0xff); put_byte(s, strm.total_in >> 24 & 0xff); } else { putShortMSB(s, strm.adler >>> 16); putShortMSB(s, strm.adler & 0xffff); } flush_pending(strm); /* If avail_out is zero, the application will call deflate again * to flush the rest. */ if (s.wrap > 0) { s.wrap = -s.wrap; } /* write the trailer only once! */ return s.pending !== 0 ? Z_OK : Z_STREAM_END; } function deflateEnd(strm) { var status; if (!strm /*== Z_NULL*/ || !strm.state /*== Z_NULL*/) { return Z_STREAM_ERROR; } status = strm.state.status; if (status !== INIT_STATE && status !== EXTRA_STATE && status !== NAME_STATE && status !== COMMENT_STATE && status !== HCRC_STATE && status !== BUSY_STATE && status !== FINISH_STATE) { return err(strm, Z_STREAM_ERROR); } strm.state = null; return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK; } /* ========================================================================= * Initializes the compression dictionary from the given byte * sequence without producing any compressed output. */ function deflateSetDictionary(strm, dictionary) { var dictLength = dictionary.length; var s; var str, n; var wrap; var avail; var next; var input; var tmpDict; if (!strm /*== Z_NULL*/ || !strm.state /*== Z_NULL*/) { return Z_STREAM_ERROR; } s = strm.state; wrap = s.wrap; if (wrap === 2 || wrap === 1 && s.status !== INIT_STATE || s.lookahead) { return Z_STREAM_ERROR; } /* when using zlib wrappers, compute Adler-32 for provided dictionary */ if (wrap === 1) { /* adler32(strm->adler, dictionary, dictLength); */ strm.adler = adler32(strm.adler, dictionary, dictLength, 0); } s.wrap = 0; /* avoid computing Adler-32 in read_buf */ /* if dictionary would fill window, just replace the history */ if (dictLength >= s.w_size) { if (wrap === 0) { /* already empty otherwise */ /*** CLEAR_HASH(s); ***/ zero(s.head); // Fill with NIL (= 0); s.strstart = 0; s.block_start = 0; s.insert = 0; } /* use the tail */ // dictionary = dictionary.slice(dictLength - s.w_size); tmpDict = new utils.Buf8(s.w_size); utils.arraySet(tmpDict, dictionary, dictLength - s.w_size, s.w_size, 0); dictionary = tmpDict; dictLength = s.w_size; } /* insert dictionary into window and hash */ avail = strm.avail_in; next = strm.next_in; input = strm.input; strm.avail_in = dictLength; strm.next_in = 0; strm.input = dictionary; fill_window(s); while (s.lookahead >= MIN_MATCH) { str = s.strstart; n = s.lookahead - (MIN_MATCH - 1); do { /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ s.ins_h = (s.ins_h << s.hash_shift ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask; s.prev[str & s.w_mask] = s.head[s.ins_h]; s.head[s.ins_h] = str; str++; } while (--n); s.strstart = str; s.lookahead = MIN_MATCH - 1; fill_window(s); } s.strstart += s.lookahead; s.block_start = s.strstart; s.insert = s.lookahead; s.lookahead = 0; s.match_length = s.prev_length = MIN_MATCH - 1; s.match_available = 0; strm.next_in = next; strm.input = input; strm.avail_in = avail; s.wrap = wrap; return Z_OK; } exports.deflateInit = deflateInit; exports.deflateInit2 = deflateInit2; exports.deflateReset = deflateReset; exports.deflateResetKeep = deflateResetKeep; exports.deflateSetHeader = deflateSetHeader; exports.deflate = deflate; exports.deflateEnd = deflateEnd; exports.deflateSetDictionary = deflateSetDictionary; exports.deflateInfo = 'pako deflate (from Nodeca project)'; /* Not implemented exports.deflateBound = deflateBound; exports.deflateCopy = deflateCopy; exports.deflateParams = deflateParams; exports.deflatePending = deflatePending; exports.deflatePrime = deflatePrime; exports.deflateTune = deflateTune; */ /***/ }), /***/ "+sRJ": /***/ (function(module, exports, __webpack_require__) { "use strict"; // (C) 1995-2013 Jean-loup Gailly and Mark Adler // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. var utils = __webpack_require__("tbG5"); /* Public constants ==========================================================*/ /* ===========================================================================*/ //var Z_FILTERED = 1; //var Z_HUFFMAN_ONLY = 2; //var Z_RLE = 3; var Z_FIXED = 4; //var Z_DEFAULT_STRATEGY = 0; /* Possible values of the data_type field (though see inflate()) */ var Z_BINARY = 0; var Z_TEXT = 1; //var Z_ASCII = 1; // = Z_TEXT var Z_UNKNOWN = 2; /*============================================================================*/ function zero(buf) { var len = buf.length;while (--len >= 0) { buf[len] = 0; } } // From zutil.h var STORED_BLOCK = 0; var STATIC_TREES = 1; var DYN_TREES = 2; /* The three kinds of block type */ var MIN_MATCH = 3; var MAX_MATCH = 258; /* The minimum and maximum match lengths */ // From deflate.h /* =========================================================================== * Internal compression state. */ var LENGTH_CODES = 29; /* number of length codes, not counting the special END_BLOCK code */ var LITERALS = 256; /* number of literal bytes 0..255 */ var L_CODES = LITERALS + 1 + LENGTH_CODES; /* number of Literal or Length codes, including the END_BLOCK code */ var D_CODES = 30; /* number of distance codes */ var BL_CODES = 19; /* number of codes used to transfer the bit lengths */ var HEAP_SIZE = 2 * L_CODES + 1; /* maximum heap size */ var MAX_BITS = 15; /* All codes must not exceed MAX_BITS bits */ var Buf_size = 16; /* size of bit buffer in bi_buf */ /* =========================================================================== * Constants */ var MAX_BL_BITS = 7; /* Bit length codes must not exceed MAX_BL_BITS bits */ var END_BLOCK = 256; /* end of block literal code */ var REP_3_6 = 16; /* repeat previous bit length 3-6 times (2 bits of repeat count) */ var REPZ_3_10 = 17; /* repeat a zero length 3-10 times (3 bits of repeat count) */ var REPZ_11_138 = 18; /* repeat a zero length 11-138 times (7 bits of repeat count) */ /* eslint-disable comma-spacing,array-bracket-spacing */ var extra_lbits = /* extra bits for each length code */ [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0]; var extra_dbits = /* extra bits for each distance code */ [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13]; var extra_blbits = /* extra bits for each bit length code */ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7]; var bl_order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; /* eslint-enable comma-spacing,array-bracket-spacing */ /* The lengths of the bit length codes are sent in order of decreasing * probability, to avoid transmitting the lengths for unused bit length codes. */ /* =========================================================================== * Local data. These are initialized only once. */ // We pre-fill arrays with 0 to avoid uninitialized gaps var DIST_CODE_LEN = 512; /* see definition of array dist_code below */ // !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1 var static_ltree = new Array((L_CODES + 2) * 2); zero(static_ltree); /* The static literal tree. Since the bit lengths are imposed, there is no * need for the L_CODES extra codes used during heap construction. However * The codes 286 and 287 are needed to build a canonical tree (see _tr_init * below). */ var static_dtree = new Array(D_CODES * 2); zero(static_dtree); /* The static distance tree. (Actually a trivial tree since all codes use * 5 bits.) */ var _dist_code = new Array(DIST_CODE_LEN); zero(_dist_code); /* Distance codes. The first 256 values correspond to the distances * 3 .. 258, the last 256 values correspond to the top 8 bits of * the 15 bit distances. */ var _length_code = new Array(MAX_MATCH - MIN_MATCH + 1); zero(_length_code); /* length code for each normalized match length (0 == MIN_MATCH) */ var base_length = new Array(LENGTH_CODES); zero(base_length); /* First normalized length for each code (0 = MIN_MATCH) */ var base_dist = new Array(D_CODES); zero(base_dist); /* First normalized distance for each code (0 = distance of 1) */ function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) { this.static_tree = static_tree; /* static tree or NULL */ this.extra_bits = extra_bits; /* extra bits for each code or NULL */ this.extra_base = extra_base; /* base index for extra_bits */ this.elems = elems; /* max number of elements in the tree */ this.max_length = max_length; /* max bit length for the codes */ // show if `static_tree` has data or dummy - needed for monomorphic objects this.has_stree = static_tree && static_tree.length; } var static_l_desc; var static_d_desc; var static_bl_desc; function TreeDesc(dyn_tree, stat_desc) { this.dyn_tree = dyn_tree; /* the dynamic tree */ this.max_code = 0; /* largest code with non zero frequency */ this.stat_desc = stat_desc; /* the corresponding static tree */ } function d_code(dist) { return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; } /* =========================================================================== * Output a short LSB first on the stream. * IN assertion: there is enough room in pendingBuf. */ function put_short(s, w) { // put_byte(s, (uch)((w) & 0xff)); // put_byte(s, (uch)((ush)(w) >> 8)); s.pending_buf[s.pending++] = w & 0xff; s.pending_buf[s.pending++] = w >>> 8 & 0xff; } /* =========================================================================== * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ function send_bits(s, value, length) { if (s.bi_valid > Buf_size - length) { s.bi_buf |= value << s.bi_valid & 0xffff; put_short(s, s.bi_buf); s.bi_buf = value >> Buf_size - s.bi_valid; s.bi_valid += length - Buf_size; } else { s.bi_buf |= value << s.bi_valid & 0xffff; s.bi_valid += length; } } function send_code(s, c, tree) { send_bits(s, tree[c * 2] /*.Code*/, tree[c * 2 + 1] /*.Len*/); } /* =========================================================================== * Reverse the first len bits of a code, using straightforward code (a faster * method would use a table) * IN assertion: 1 <= len <= 15 */ function bi_reverse(code, len) { var res = 0; do { res |= code & 1; code >>>= 1; res <<= 1; } while (--len > 0); return res >>> 1; } /* =========================================================================== * Flush the bit buffer, keeping at most 7 bits in it. */ function bi_flush(s) { if (s.bi_valid === 16) { put_short(s, s.bi_buf); s.bi_buf = 0; s.bi_valid = 0; } else if (s.bi_valid >= 8) { s.pending_buf[s.pending++] = s.bi_buf & 0xff; s.bi_buf >>= 8; s.bi_valid -= 8; } } /* =========================================================================== * Compute the optimal bit lengths for a tree and update the total bit length * for the current block. * IN assertion: the fields freq and dad are set, heap[heap_max] and * above are the tree nodes sorted by increasing frequency. * OUT assertions: the field len is set to the optimal bit length, the * array bl_count contains the frequencies for each bit length. * The length opt_len is updated; static_len is also updated if stree is * not null. */ function gen_bitlen(s, desc) // deflate_state *s; // tree_desc *desc; /* the tree descriptor */ { var tree = desc.dyn_tree; var max_code = desc.max_code; var stree = desc.stat_desc.static_tree; var has_stree = desc.stat_desc.has_stree; var extra = desc.stat_desc.extra_bits; var base = desc.stat_desc.extra_base; var max_length = desc.stat_desc.max_length; var h; /* heap index */ var n, m; /* iterate over the tree elements */ var bits; /* bit length */ var xbits; /* extra bits */ var f; /* frequency */ var overflow = 0; /* number of elements with bit length too large */ for (bits = 0; bits <= MAX_BITS; bits++) { s.bl_count[bits] = 0; } /* In a first pass, compute the optimal bit lengths (which may * overflow in the case of the bit length tree). */ tree[s.heap[s.heap_max] * 2 + 1] /*.Len*/ = 0; /* root of the heap */ for (h = s.heap_max + 1; h < HEAP_SIZE; h++) { n = s.heap[h]; bits = tree[tree[n * 2 + 1] /*.Dad*/ * 2 + 1] /*.Len*/ + 1; if (bits > max_length) { bits = max_length; overflow++; } tree[n * 2 + 1] /*.Len*/ = bits; /* We overwrite tree[n].Dad which is no longer needed */ if (n > max_code) { continue; } /* not a leaf node */ s.bl_count[bits]++; xbits = 0; if (n >= base) { xbits = extra[n - base]; } f = tree[n * 2] /*.Freq*/; s.opt_len += f * (bits + xbits); if (has_stree) { s.static_len += f * (stree[n * 2 + 1] /*.Len*/ + xbits); } } if (overflow === 0) { return; } // Trace((stderr,"\nbit length overflow\n")); /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ do { bits = max_length - 1; while (s.bl_count[bits] === 0) { bits--; } s.bl_count[bits]--; /* move one leaf down the tree */ s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */ s.bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] */ overflow -= 2; } while (overflow > 0); /* Now recompute all bit lengths, scanning in increasing frequency. * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all * lengths instead of fixing only the wrong ones. This idea is taken * from 'ar' written by Haruhiko Okumura.) */ for (bits = max_length; bits !== 0; bits--) { n = s.bl_count[bits]; while (n !== 0) { m = s.heap[--h]; if (m > max_code) { continue; } if (tree[m * 2 + 1] /*.Len*/ !== bits) { // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); s.opt_len += (bits - tree[m * 2 + 1] /*.Len*/) * tree[m * 2] /*.Freq*/; tree[m * 2 + 1] /*.Len*/ = bits; } n--; } } } /* =========================================================================== * Generate the codes for a given tree and bit counts (which need not be * optimal). * IN assertion: the array bl_count contains the bit length statistics for * the given tree and the field len is set for all tree elements. * OUT assertion: the field code is set for all tree elements of non * zero code length. */ function gen_codes(tree, max_code, bl_count) // ct_data *tree; /* the tree to decorate */ // int max_code; /* largest code with non zero frequency */ // ushf *bl_count; /* number of codes at each bit length */ { var next_code = new Array(MAX_BITS + 1); /* next code value for each bit length */ var code = 0; /* running code value */ var bits; /* bit index */ var n; /* code index */ /* The distribution counts are first used to generate the code values * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { next_code[bits] = code = code + bl_count[bits - 1] << 1; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ //Assert (code + bl_count[MAX_BITS]-1 == (1< length code (0..28) */ length = 0; for (code = 0; code < LENGTH_CODES - 1; code++) { base_length[code] = length; for (n = 0; n < 1 << extra_lbits[code]; n++) { _length_code[length++] = code; } } //Assert (length == 256, "tr_static_init: length != 256"); /* Note that the length 255 (match length 258) can be represented * in two different ways: code 284 + 5 bits or code 285, so we * overwrite length_code[255] to use the best encoding: */ _length_code[length - 1] = code; /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ dist = 0; for (code = 0; code < 16; code++) { base_dist[code] = dist; for (n = 0; n < 1 << extra_dbits[code]; n++) { _dist_code[dist++] = code; } } //Assert (dist == 256, "tr_static_init: dist != 256"); dist >>= 7; /* from now on, all distances are divided by 128 */ for (; code < D_CODES; code++) { base_dist[code] = dist << 7; for (n = 0; n < 1 << extra_dbits[code] - 7; n++) { _dist_code[256 + dist++] = code; } } //Assert (dist == 256, "tr_static_init: 256+dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) { bl_count[bits] = 0; } n = 0; while (n <= 143) { static_ltree[n * 2 + 1] /*.Len*/ = 8; n++; bl_count[8]++; } while (n <= 255) { static_ltree[n * 2 + 1] /*.Len*/ = 9; n++; bl_count[9]++; } while (n <= 279) { static_ltree[n * 2 + 1] /*.Len*/ = 7; n++; bl_count[7]++; } while (n <= 287) { static_ltree[n * 2 + 1] /*.Len*/ = 8; n++; bl_count[8]++; } /* Codes 286 and 287 do not exist, but we must include them in the * tree construction to get a canonical Huffman tree (longest code * all ones) */ gen_codes(static_ltree, L_CODES + 1, bl_count); /* The static distance tree is trivial: */ for (n = 0; n < D_CODES; n++) { static_dtree[n * 2 + 1] /*.Len*/ = 5; static_dtree[n * 2] /*.Code*/ = bi_reverse(n, 5); } // Now data ready and we can init static trees static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS); static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS); static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS); //static_init_done = true; } /* =========================================================================== * Initialize a new block. */ function init_block(s) { var n; /* iterates over tree elements */ /* Initialize the trees. */ for (n = 0; n < L_CODES; n++) { s.dyn_ltree[n * 2] /*.Freq*/ = 0; } for (n = 0; n < D_CODES; n++) { s.dyn_dtree[n * 2] /*.Freq*/ = 0; } for (n = 0; n < BL_CODES; n++) { s.bl_tree[n * 2] /*.Freq*/ = 0; } s.dyn_ltree[END_BLOCK * 2] /*.Freq*/ = 1; s.opt_len = s.static_len = 0; s.last_lit = s.matches = 0; } /* =========================================================================== * Flush the bit buffer and align the output on a byte boundary */ function bi_windup(s) { if (s.bi_valid > 8) { put_short(s, s.bi_buf); } else if (s.bi_valid > 0) { //put_byte(s, (Byte)s->bi_buf); s.pending_buf[s.pending++] = s.bi_buf; } s.bi_buf = 0; s.bi_valid = 0; } /* =========================================================================== * Copy a stored block, storing first the length and its * one's complement if requested. */ function copy_block(s, buf, len, header) //DeflateState *s; //charf *buf; /* the input data */ //unsigned len; /* its length */ //int header; /* true if block header must be written */ { bi_windup(s); /* align on byte boundary */ if (header) { put_short(s, len); put_short(s, ~len); } // while (len--) { // put_byte(s, *buf++); // } utils.arraySet(s.pending_buf, s.window, buf, len, s.pending); s.pending += len; } /* =========================================================================== * Compares to subtrees, using the tree depth as tie breaker when * the subtrees have equal frequency. This minimizes the worst case length. */ function smaller(tree, n, m, depth) { var _n2 = n * 2; var _m2 = m * 2; return tree[_n2] /*.Freq*/ < tree[_m2] /*.Freq*/ || tree[_n2] /*.Freq*/ === tree[_m2] /*.Freq*/ && depth[n] <= depth[m]; } /* =========================================================================== * Restore the heap property by moving down the tree starting at node k, * exchanging a node with the smallest of its two sons if necessary, stopping * when the heap property is re-established (each father smaller than its * two sons). */ function pqdownheap(s, tree, k) // deflate_state *s; // ct_data *tree; /* the tree to restore */ // int k; /* node to move down */ { var v = s.heap[k]; var j = k << 1; /* left son of k */ while (j <= s.heap_len) { /* Set j to the smallest of the two sons: */ if (j < s.heap_len && smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) { j++; } /* Exit if v is smaller than both sons */ if (smaller(tree, v, s.heap[j], s.depth)) { break; } /* Exchange v with the smallest son */ s.heap[k] = s.heap[j]; k = j; /* And continue down the tree, setting j to the left son of k */ j <<= 1; } s.heap[k] = v; } // inlined manually // var SMALLEST = 1; /* =========================================================================== * Send the block data compressed using the given Huffman trees */ function compress_block(s, ltree, dtree) // deflate_state *s; // const ct_data *ltree; /* literal tree */ // const ct_data *dtree; /* distance tree */ { var dist; /* distance of matched string */ var lc; /* match length or unmatched char (if dist == 0) */ var lx = 0; /* running index in l_buf */ var code; /* the code to send */ var extra; /* number of extra bits to send */ if (s.last_lit !== 0) { do { dist = s.pending_buf[s.d_buf + lx * 2] << 8 | s.pending_buf[s.d_buf + lx * 2 + 1]; lc = s.pending_buf[s.l_buf + lx]; lx++; if (dist === 0) { send_code(s, lc, ltree); /* send a literal byte */ //Tracecv(isgraph(lc), (stderr," '%c' ", lc)); } else { /* Here, lc is the match length - MIN_MATCH */ code = _length_code[lc]; send_code(s, code + LITERALS + 1, ltree); /* send the length code */ extra = extra_lbits[code]; if (extra !== 0) { lc -= base_length[code]; send_bits(s, lc, extra); /* send the extra length bits */ } dist--; /* dist is now the match distance - 1 */ code = d_code(dist); //Assert (code < D_CODES, "bad d_code"); send_code(s, code, dtree); /* send the distance code */ extra = extra_dbits[code]; if (extra !== 0) { dist -= base_dist[code]; send_bits(s, dist, extra); /* send the extra distance bits */ } } /* literal or match pair ? */ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, // "pendingBuf overflow"); } while (lx < s.last_lit); } send_code(s, END_BLOCK, ltree); } /* =========================================================================== * Construct one Huffman tree and assigns the code bit strings and lengths. * Update the total bit length for the current block. * IN assertion: the field freq is set for all tree elements. * OUT assertions: the fields len and code are set to the optimal bit length * and corresponding code. The length opt_len is updated; static_len is * also updated if stree is not null. The field max_code is set. */ function build_tree(s, desc) // deflate_state *s; // tree_desc *desc; /* the tree descriptor */ { var tree = desc.dyn_tree; var stree = desc.stat_desc.static_tree; var has_stree = desc.stat_desc.has_stree; var elems = desc.stat_desc.elems; var n, m; /* iterate over heap elements */ var max_code = -1; /* largest code with non zero frequency */ var node; /* new node being created */ /* Construct the initial heap, with least frequent element in * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. * heap[0] is not used. */ s.heap_len = 0; s.heap_max = HEAP_SIZE; for (n = 0; n < elems; n++) { if (tree[n * 2] /*.Freq*/ !== 0) { s.heap[++s.heap_len] = max_code = n; s.depth[n] = 0; } else { tree[n * 2 + 1] /*.Len*/ = 0; } } /* The pkzip format requires that at least one distance code exists, * and that at least one bit should be sent even if there is only one * possible code. So to avoid special checks later on we force at least * two codes of non zero frequency. */ while (s.heap_len < 2) { node = s.heap[++s.heap_len] = max_code < 2 ? ++max_code : 0; tree[node * 2] /*.Freq*/ = 1; s.depth[node] = 0; s.opt_len--; if (has_stree) { s.static_len -= stree[node * 2 + 1] /*.Len*/; } /* node is 0 or 1 so it does not have extra bits */ } desc.max_code = max_code; /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s.heap_len >> 1 /*int /2*/; n >= 1; n--) { pqdownheap(s, tree, n); } /* Construct the Huffman tree by repeatedly combining the least two * frequent nodes. */ node = elems; /* next internal node of the tree */ do { //pqremove(s, tree, n); /* n = node of least frequency */ /*** pqremove ***/ n = s.heap[1 /*SMALLEST*/]; s.heap[1 /*SMALLEST*/] = s.heap[s.heap_len--]; pqdownheap(s, tree, 1 /*SMALLEST*/); /***/ m = s.heap[1 /*SMALLEST*/]; /* m = node of next least frequency */ s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */ s.heap[--s.heap_max] = m; /* Create a new node father of n and m */ tree[node * 2] /*.Freq*/ = tree[n * 2] /*.Freq*/ + tree[m * 2] /*.Freq*/; s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1; tree[n * 2 + 1] /*.Dad*/ = tree[m * 2 + 1] /*.Dad*/ = node; /* and insert the new node in the heap */ s.heap[1 /*SMALLEST*/] = node++; pqdownheap(s, tree, 1 /*SMALLEST*/); } while (s.heap_len >= 2); s.heap[--s.heap_max] = s.heap[1 /*SMALLEST*/]; /* At this point, the fields freq and dad are set. We can now * generate the bit lengths. */ gen_bitlen(s, desc); /* The field len is now set, we can generate the bit codes */ gen_codes(tree, max_code, s.bl_count); } /* =========================================================================== * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ function scan_tree(s, tree, max_code) // deflate_state *s; // ct_data *tree; /* the tree to be scanned */ // int max_code; /* and its largest code of non zero frequency */ { var n; /* iterates over all tree elements */ var prevlen = -1; /* last emitted length */ var curlen; /* length of current code */ var nextlen = tree[0 * 2 + 1] /*.Len*/; /* length of next code */ var count = 0; /* repeat count of the current code */ var max_count = 7; /* max repeat count */ var min_count = 4; /* min repeat count */ if (nextlen === 0) { max_count = 138; min_count = 3; } tree[(max_code + 1) * 2 + 1] /*.Len*/ = 0xffff; /* guard */ for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[(n + 1) * 2 + 1] /*.Len*/; if (++count < max_count && curlen === nextlen) { continue; } else if (count < min_count) { s.bl_tree[curlen * 2] /*.Freq*/ += count; } else if (curlen !== 0) { if (curlen !== prevlen) { s.bl_tree[curlen * 2] /*.Freq*/++; } s.bl_tree[REP_3_6 * 2] /*.Freq*/++; } else if (count <= 10) { s.bl_tree[REPZ_3_10 * 2] /*.Freq*/++; } else { s.bl_tree[REPZ_11_138 * 2] /*.Freq*/++; } count = 0; prevlen = curlen; if (nextlen === 0) { max_count = 138; min_count = 3; } else if (curlen === nextlen) { max_count = 6; min_count = 3; } else { max_count = 7; min_count = 4; } } } /* =========================================================================== * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ function send_tree(s, tree, max_code) // deflate_state *s; // ct_data *tree; /* the tree to be scanned */ // int max_code; /* and its largest code of non zero frequency */ { var n; /* iterates over all tree elements */ var prevlen = -1; /* last emitted length */ var curlen; /* length of current code */ var nextlen = tree[0 * 2 + 1] /*.Len*/; /* length of next code */ var count = 0; /* repeat count of the current code */ var max_count = 7; /* max repeat count */ var min_count = 4; /* min repeat count */ /* tree[max_code+1].Len = -1; */ /* guard already set */ if (nextlen === 0) { max_count = 138; min_count = 3; } for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[(n + 1) * 2 + 1] /*.Len*/; if (++count < max_count && curlen === nextlen) { continue; } else if (count < min_count) { do { send_code(s, curlen, s.bl_tree); } while (--count !== 0); } else if (curlen !== 0) { if (curlen !== prevlen) { send_code(s, curlen, s.bl_tree); count--; } //Assert(count >= 3 && count <= 6, " 3_6?"); send_code(s, REP_3_6, s.bl_tree); send_bits(s, count - 3, 2); } else if (count <= 10) { send_code(s, REPZ_3_10, s.bl_tree); send_bits(s, count - 3, 3); } else { send_code(s, REPZ_11_138, s.bl_tree); send_bits(s, count - 11, 7); } count = 0; prevlen = curlen; if (nextlen === 0) { max_count = 138; min_count = 3; } else if (curlen === nextlen) { max_count = 6; min_count = 3; } else { max_count = 7; min_count = 4; } } } /* =========================================================================== * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ function build_bl_tree(s) { var max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ scan_tree(s, s.dyn_ltree, s.l_desc.max_code); scan_tree(s, s.dyn_dtree, s.d_desc.max_code); /* Build the bit length tree: */ build_tree(s, s.bl_desc); /* opt_len now includes the length of the tree representations, except * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format * requires that at least 4 bit length codes be sent. (appnote.txt says * 3 but the actual value used is 4.) */ for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) { if (s.bl_tree[bl_order[max_blindex] * 2 + 1] /*.Len*/ !== 0) { break; } } /* Update opt_len to include the bit length tree and counts */ s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", // s->opt_len, s->static_len)); return max_blindex; } /* =========================================================================== * Send the header for a block using dynamic Huffman trees: the counts, the * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ function send_all_trees(s, lcodes, dcodes, blcodes) // deflate_state *s; // int lcodes, dcodes, blcodes; /* number of codes for each tree */ { var rank; /* index in bl_order */ //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, // "too many codes"); //Tracev((stderr, "\nbl counts: ")); send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ send_bits(s, dcodes - 1, 5); send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { //Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1] /*.Len*/, 3); } //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */ //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */ //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } /* =========================================================================== * Check if the data type is TEXT or BINARY, using the following algorithm: * - TEXT if the two conditions below are satisfied: * a) There are no non-portable control characters belonging to the * "black list" (0..6, 14..25, 28..31). * b) There is at least one printable character belonging to the * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). * - BINARY otherwise. * - The following partially-portable control characters form a * "gray list" that is ignored in this detection algorithm: * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). * IN assertion: the fields Freq of dyn_ltree are set. */ function detect_data_type(s) { /* black_mask is the bit mask of black-listed bytes * set bits 0..6, 14..25, and 28..31 * 0xf3ffc07f = binary 11110011111111111100000001111111 */ var black_mask = 0xf3ffc07f; var n; /* Check for non-textual ("black-listed") bytes. */ for (n = 0; n <= 31; n++, black_mask >>>= 1) { if (black_mask & 1 && s.dyn_ltree[n * 2] /*.Freq*/ !== 0) { return Z_BINARY; } } /* Check for textual ("white-listed") bytes. */ if (s.dyn_ltree[9 * 2] /*.Freq*/ !== 0 || s.dyn_ltree[10 * 2] /*.Freq*/ !== 0 || s.dyn_ltree[13 * 2] /*.Freq*/ !== 0) { return Z_TEXT; } for (n = 32; n < LITERALS; n++) { if (s.dyn_ltree[n * 2] /*.Freq*/ !== 0) { return Z_TEXT; } } /* There are no "black-listed" or "white-listed" bytes: * this stream either is empty or has tolerated ("gray-listed") bytes only. */ return Z_BINARY; } var static_init_done = false; /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ function _tr_init(s) { if (!static_init_done) { tr_static_init(); static_init_done = true; } s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); s.bi_buf = 0; s.bi_valid = 0; /* Initialize the first block of the first file: */ init_block(s); } /* =========================================================================== * Send a stored block */ function _tr_stored_block(s, buf, stored_len, last) //DeflateState *s; //charf *buf; /* input block */ //ulg stored_len; /* length of input block */ //int last; /* one if this is the last block for a file */ { send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3); /* send block type */ copy_block(s, buf, stored_len, true); /* with header */ } /* =========================================================================== * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. */ function _tr_align(s) { send_bits(s, STATIC_TREES << 1, 3); send_code(s, END_BLOCK, static_ltree); bi_flush(s); } /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static * trees or store, and output the encoded block to the zip file. */ function _tr_flush_block(s, buf, stored_len, last) //DeflateState *s; //charf *buf; /* input block, or NULL if too old */ //ulg stored_len; /* length of input block */ //int last; /* one if this is the last block for a file */ { var opt_lenb, static_lenb; /* opt_len and static_len in bytes */ var max_blindex = 0; /* index of last bit length code of non zero freq */ /* Build the Huffman trees unless a stored block is forced */ if (s.level > 0) { /* Check if the file is binary or text */ if (s.strm.data_type === Z_UNKNOWN) { s.strm.data_type = detect_data_type(s); } /* Construct the literal and distance trees */ build_tree(s, s.l_desc); // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, // s->static_len)); build_tree(s, s.d_desc); // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, // s->static_len)); /* At this point, opt_len and static_len are the total bit lengths of * the compressed block data, excluding the tree representations. */ /* Build the bit length tree for the above two trees, and get the index * in bl_order of the last bit length code to send. */ max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ opt_lenb = s.opt_len + 3 + 7 >>> 3; static_lenb = s.static_len + 3 + 7 >>> 3; // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, // s->last_lit)); if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; } } else { // Assert(buf != (char*)0, "lost buf"); opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } if (stored_len + 4 <= opt_lenb && buf !== -1) { /* 4: two words for the lengths */ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. * Otherwise we can't have processed more than WSIZE input bytes since * the last block flush, because compression would have been * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to * transform a block into a stored block. */ _tr_stored_block(s, buf, stored_len, last); } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) { send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3); compress_block(s, static_ltree, static_dtree); } else { send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3); send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1); compress_block(s, s.dyn_ltree, s.dyn_dtree); } // Assert (s->compressed_len == s->bits_sent, "bad compressed size"); /* The above check is made mod 2^32, for files larger than 512 MB * and uLong implemented on 32 bits. */ init_block(s); if (last) { bi_windup(s); } // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, // s->compressed_len-7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ function _tr_tally(s, dist, lc) // deflate_state *s; // unsigned dist; /* distance of matched string */ // unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ { //var out_length, in_length, dcode; s.pending_buf[s.d_buf + s.last_lit * 2] = dist >>> 8 & 0xff; s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff; s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff; s.last_lit++; if (dist === 0) { /* lc is the unmatched char */ s.dyn_ltree[lc * 2] /*.Freq*/++; } else { s.matches++; /* Here, lc is the match length - MIN_MATCH */ dist--; /* dist = match distance - 1 */ //Assert((ush)dist < (ush)MAX_DIST(s) && // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); s.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2] /*.Freq*/++; s.dyn_dtree[d_code(dist) * 2] /*.Freq*/++; } // (!) This block is disabled in zlib defaults, // don't enable it for binary compatibility //#ifdef TRUNCATE_BLOCK // /* Try to guess if it is profitable to stop the current block here */ // if ((s.last_lit & 0x1fff) === 0 && s.level > 2) { // /* Compute an upper bound for the compressed length */ // out_length = s.last_lit*8; // in_length = s.strstart - s.block_start; // // for (dcode = 0; dcode < D_CODES; dcode++) { // out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]); // } // out_length >>>= 3; // //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", // // s->last_lit, in_length, out_length, // // 100L - out_length*100L/in_length)); // if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) { // return true; // } // } //#endif return s.last_lit === s.lit_bufsize - 1; /* We avoid equality with lit_bufsize because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. */ } exports._tr_init = _tr_init; exports._tr_stored_block = _tr_stored_block; exports._tr_flush_block = _tr_flush_block; exports._tr_tally = _tr_tally; exports._tr_align = _tr_align; /***/ }), /***/ "/+WI": /***/ (function(module, exports, __webpack_require__) { "use strict"; // (C) 1995-2013 Jean-loup Gailly and Mark Adler // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. function GZheader() { /* true if compressed data believed to be text */ this.text = 0; /* modification time */ this.time = 0; /* extra flags (not used when writing a gzip file) */ this.xflags = 0; /* operating system */ this.os = 0; /* pointer to extra field or Z_NULL if none */ this.extra = null; /* extra field length (valid if extra != Z_NULL) */ this.extra_len = 0; // Actually, we don't need it in JS, // but leave for few code modifications // // Setup limits is not necessary because in js we should not preallocate memory // for inflate use constant limit in 65536 bytes // /* space at extra (only when reading header) */ // this.extra_max = 0; /* pointer to zero-terminated file name or Z_NULL */ this.name = ''; /* space at name (only when reading header) */ // this.name_max = 0; /* pointer to zero-terminated comment or Z_NULL */ this.comment = ''; /* space at comment (only when reading header) */ // this.comm_max = 0; /* true if there was or will be a header crc */ this.hcrc = 0; /* true when done reading gzip header (not used when writing a gzip file) */ this.done = false; } module.exports = GZheader; /***/ }), /***/ "/QFk": /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; // CONCATENATED MODULE: ../node_modules/@emmetio/config/dist/config.es.js var _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; }; var defaultSyntaxes = { markup: 'html', stylesheet: 'css' }; var knownSyntaxes = { markup: ['html', 'xml', 'xsl', 'jsx', 'js', 'pug', 'slim', 'haml'], stylesheet: ['css', 'sass', 'scss', 'less', 'sss', 'stylus'] }; /** * Config resolver: returns compiled config that can be used in * `@emmetio/expand-abbreviation` module for expanding abbreviations * @param {EmmetConfig} config Config object * @param {EmmetConfigParams} [params] Additional params like `.syntax` and `.project` for * config resolving * @returns {Object} */ function compileConfig(config, params) { params = createParams(config, params || {}); var resolved = resolveConfig(config, params); // Copy extra fields from original config var knownFields = ['globals', 'syntax', 'project']; for (var p in config) { if (knownFields.indexOf(p) === -1) { resolved[p] = config[p]; } } return resolved; } /** * Resolves config for markup syntax * @param {EmmetConfig} config * @param {EmmetConfigParams} params * @return {Object} */ function resolveConfig(config, ref) { var type = ref.type; var syntax = ref.syntax; var project = ref.project; return { syntax: syntax, type: type, project: project, format: mergeConfig(config, 'format', type, syntax, project), profile: mergeConfig(config, 'profile', type, syntax, project), options: mergeConfig(config, 'options', type, syntax, project), variables: mergeConfig(config, 'variables', type, syntax, project), snippets: getConfig(config, 'snippets', type, syntax, project).filter(Boolean) }; } /** * @param {EmmetConfig} config * @param {EmmetConfigParams} params * @returns {EmmetConfigParams} */ function createParams(config, params) { var type = params.type; var syntax = params.syntax; if (!type && !syntax) { type = 'markup'; syntax = defaultSyntaxes[type]; } else if (!type && syntax) { if (knownSyntaxes.markup.indexOf(syntax) !== -1) { type = 'markup'; } else if (knownSyntaxes.stylesheet.indexOf(syntax) !== -1) { type = 'stylesheet'; } else { type = get(config, ['syntax', syntax, 'type']) || get(config, ['project', params.project, 'syntax', syntax, 'type']); } } else if (!syntax) { syntax = defaultSyntaxes[type]; } return _extends({}, params, { type: type, syntax: syntax }); } function mergeConfig(config, key, type, syntax, project) { return getConfig(config, key, type, syntax, project).reduce(function (out, obj) { return _extends({}, out, obj); }, {}); } function getConfig(config, key, type, syntax, project) { return [get(config, ['globals', type, key]), get(config, ['project', project, 'globals', type, key]), get(config, ['syntax', syntax, key]), get(config, ['project', project, 'syntax', syntax, key])].filter(Boolean); } /** * Safe dot-property getter for `obj`: returns value of `obj` by given `key`, * separated by `.`, but doesn’t throw error if any of the property key exists * @param {Object} obj * @param {String[]} key * @param {*} [defaultValue] * @return {*} */ function get(obj, key, defaultValue) { var result = obj; for (var i = 0; i < key.length; i++) { if (result == null) { break; } result = result[key[i]]; } return result != null ? result : defaultValue; } /* harmony default export */ var config_es = (compileConfig); //# sourceMappingURL=config.es.js.map // CONCATENATED MODULE: ../node_modules/@emmetio/stream-reader/dist/stream-reader.es.js /** * A streaming, character code-based string reader */ let StreamReader = class StreamReader { constructor(string, start, end) { if (end == null && typeof string === 'string') { end = string.length; } this.string = string; this.pos = this.start = start || 0; this.end = end; } /** * Returns true only if the stream is at the end of the file. * @returns {Boolean} */ eof() { return this.pos >= this.end; } /** * Creates a new stream instance which is limited to given `start` and `end` * range. E.g. its `eof()` method will look at `end` property, not actual * stream end * @param {Point} start * @param {Point} end * @return {StreamReader} */ limit(start, end) { return new this.constructor(this.string, start, end); } /** * Returns the next character code in the stream without advancing it. * Will return NaN at the end of the file. * @returns {Number} */ peek() { return this.string.charCodeAt(this.pos); } /** * Returns the next character in the stream and advances it. * Also returns undefined 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('[]', {NAME: 'foo'}) -> "" * template('[]', {}) -> "" * ``` */ function template(str, data) { if (str == null) { return str; } // NB since token may contain inner `[` and `]`, we can’t just use regexp // for replacement, should manually parse string instead const stack = []; const replacer = (str, left, token, right) => data[token] != null ? left + data[token] + right : ''; let output = ''; let offset = 0, i = 0; let code, lastPos; while (i < str.length) { code = str.charCodeAt(i); if (code === TOKEN_OPEN) { stack.push(i); } else if (code === TOKEN_CLOSE) { lastPos = stack.pop(); if (!stack.length) { output += str.slice(offset, lastPos) + str.slice(lastPos + 1, i).replace(TOKEN, replacer); offset = i + 1; } } i++; } return output + str.slice(offset); } /** * Various utility methods used by formatters */ /** * Splits given text by lines * @param {String} text * @return {String[]} */ function markup_formatters_es_splitByLines(text) { return (text || '').split(/\r\n|\r|\n/g); } /** * Check if given node is a first child in its parent * @param {Node} node * @return {Boolean} */ function isFirstChild(node) { return node.parent.firstChild === node; } /** * Check if given node is a root node * @param {Node} node * @return {Boolean} */ function isRoot(node) { return node && !node.parent; } /** * Check if given node is a pseudo-snippet: a text-only node with explicitly * defined children * @param {Node} node * @return {Boolean} */ function isPseudoSnippet(node) { return node.isTextOnly && !!node.children.length; } /** * Handles pseudo-snippet node. * A pseudo-snippet is a text-only node with explicitly defined children. * For such case, we have to figure out if pseudo-snippet contains fields * (tab-stops) in node value and “split” it: make contents before field with * lowest index node’s “open” part and contents after lowest index — “close” * part. With this trick a final output will look like node’s children * are nested inside node value * @param {OutputNode} outNode * @return {Boolean} Returns “true” if given node is a pseudo-snippets, * `false` otherwise */ function handlePseudoSnippet(outNode) { const node = outNode.node; // original abbreviaiton node if (isPseudoSnippet(node)) { const fieldsModel = field_parser_es(node.value); const field = findLowestIndexField(fieldsModel); if (field) { const parts = splitFieldsModel(fieldsModel, field); outNode.open = outNode.renderFields(parts[0]); outNode.close = outNode.renderFields(parts[1]); } else { outNode.text = outNode.renderFields(fieldsModel); } return true; } return false; } /** * Finds field with lowest index in given text * @param {Object} model * @return {Object} */ function findLowestIndexField(model) { return model.fields.reduce((result, field) => !result || field.index < result.index ? field : result, null); } /** * Splits given fields model in two parts by given field * @param {Object} model * @param {Object} field * @return {Array} Two-items array */ function splitFieldsModel(model, field) { const ix = model.fields.indexOf(field); const left = new model.constructor(model.string.slice(0, field.location), model.fields.slice(0, ix)); const right = new model.constructor(model.string.slice(field.location + field.length), model.fields.slice(ix + 1)); return [left, right]; } const commentOptions = { // enable node commenting enabled: false, // attributes that should trigger node commenting on specific node, // if commenting is enabled trigger: ['id', 'class'], // comment before opening tag before: '', // comment after closing tag after: '\n' }; /** * Renders given parsed Emmet abbreviation as HTML, formatted according to * `profile` options * @param {Node} tree Parsed Emmet abbreviation * @param {Profile} profile Output profile * @param {Object} [options] Additional formatter options * @return {String} */ function html(tree, profile, options) { options = markup_formatters_es__extends({}, options); const format = getFormatOptions(options); return output_renderer_es(tree, options.field, outNode => { outNode = setFormatting(outNode, profile); if (!handlePseudoSnippet(outNode)) { const node = outNode.node; if (node.name) { const name = profile.name(node.name); const attrs = formatAttributes(outNode, profile); outNode.open = `<${name}${attrs}${node.selfClosing ? profile.selfClose() : ''}>`; if (!node.selfClosing) { outNode.close = ``; } commentNode(outNode, format.comment); } // Do not generate fields for nodes with empty value and children // or if node is self-closed if (node.value || !node.children.length && !node.selfClosing) { outNode.text = outNode.renderFields(node.value); } } return outNode; }); } /** * Updates formatting properties for given output node * @param {OutputNode} outNode Output wrapper of farsed abbreviation node * @param {Profile} profile Output profile * @return {OutputNode} */ function setFormatting(outNode, profile) { const node = outNode.node; if (shouldFormatNode(node, profile)) { outNode.indent = profile.indent(getIndentLevel(node, profile)); outNode.newline = '\n'; const prefix = outNode.newline + outNode.indent; // do not format the very first node in output if (!isRoot(node.parent) || !isFirstChild(node)) { outNode.beforeOpen = prefix; if (node.isTextOnly) { outNode.beforeText = prefix; } } if (hasInnerFormatting(node, profile)) { if (!node.isTextOnly) { outNode.beforeText = prefix + profile.indent(1); } outNode.beforeClose = prefix; } } return outNode; } /** * Check if given node should be formatted * @param {Node} node * @param {Profile} profile * @return {Boolean} */ function shouldFormatNode(node, profile) { if (!profile.get('format')) { return false; } if (node.parent.isTextOnly && node.parent.children.length === 1 && field_parser_es(node.parent.value).fields.length) { // Edge case: do not format the only child of text-only node, // but only if parent contains fields return false; } return isInline(node, profile) ? shouldFormatInline(node, profile) : true; } /** * Check if given inline node should be formatted as well, e.g. it contains * enough adjacent siblings that should force formatting * @param {Node} node * @param {Profile} profile * @return {Boolean} */ function shouldFormatInline(node, profile) { if (!isInline(node, profile)) { return false; } if (isPseudoSnippet(node)) { return true; } // check if inline node is the next sibling of block-level node if (node.childIndex === 0) { // first node in parent: format if it’s followed by a block-level element let next = node; while (next = next.nextSibling) { if (!isInline(next, profile)) { return true; } } } else if (!isInline(node.previousSibling, profile)) { // node is right after block-level element return true; } if (profile.get('inlineBreak')) { // check for adjacent inline elements before and after current element let adjacentInline = 1; let before = node, after = node; while (isInlineElement(before = before.previousSibling, profile)) { adjacentInline++; } while (isInlineElement(after = after.nextSibling, profile)) { adjacentInline++; } if (adjacentInline >= profile.get('inlineBreak')) { return true; } } // Another edge case: inline node contains node that should receive foramtting for (let i = 0, il = node.children.length; i < il; i++) { if (shouldFormatNode(node.children[i], profile)) { return true; } } return false; } /** * Check if given node contains inner formatting, e.g. any of its children should * be formatted * @param {Node} node * @param {Profile} profile * @return {Boolean} */ function hasInnerFormatting(node, profile) { // check if node if forced for inner formatting const nodeName = (node.name || '').toLowerCase(); if (profile.get('formatForce').indexOf(nodeName) !== -1) { return true; } // check if any of children should receive formatting // NB don’t use `childrent.some()` to reduce memory allocations for (let i = 0; i < node.children.length; i++) { if (shouldFormatNode(node.children[i], profile)) { return true; } } return false; } /** * Outputs attributes of given abbreviation node as HTML attributes * @param {OutputNode} outNode * @param {Profile} profile * @return {String} */ function formatAttributes(outNode, profile) { const node = outNode.node; return node.attributes.map(attr => { if (attr.options.implied && attr.value == null) { return null; } const attrName = profile.attribute(attr.name); let attrValue = null; // handle boolean attributes if (attr.options.boolean || profile.get('booleanAttributes').indexOf(attrName.toLowerCase()) !== -1) { if (profile.get('compactBooleanAttributes') && attr.value == null) { return ` ${attrName}`; } else if (attr.value == null) { attrValue = attrName; } } if (attrValue == null) { attrValue = outNode.renderFields(attr.value); } return ` ${attrName}=${profile.quote(attrValue)}`; }).join(''); } /** * Check if given node is inline-level * @param {Node} node * @param {Profile} profile * @return {Boolean} */ function isInline(node, profile) { return node && node.isTextOnly || isInlineElement(node, profile); } /** * Check if given node is inline-level element, e.g. element with explicitly * defined node name * @param {Node} node * @param {Profile} profile * @return {Boolean} */ function isInlineElement(node, profile) { return node && profile.isInline(node); } /** * Computes indent level for given node * @param {Node} node * @param {Profile} profile * @param {Number} level * @return {Number} */ function getIndentLevel(node, profile) { // Increase indent level IF NOT: // * parent is text-only node // * there’s a parent node with a name that is explicitly set to decrease level const skip = profile.get('formatSkip') || []; let level = node.parent.isTextOnly ? -2 : -1; let ctx = node; while (ctx = ctx.parent) { if (skip.indexOf((ctx.name || '').toLowerCase()) === -1) { level++; } } return level < 0 ? 0 : level; } /** * Comments given output node, if required * @param {OutputNode} outNode * @param {Object} options */ function commentNode(outNode, options) { const node = outNode.node; if (!options.enabled || !options.trigger || !node.name) { return; } const attrs = outNode.node.attributes.reduce((out, attr) => { if (attr.name && attr.value != null) { out[attr.name.toUpperCase().replace(/-/g, '_')] = attr.value; } return out; }, {}); // add comment only if attribute trigger is present for (let i = 0, il = options.trigger.length; i < il; i++) { if (options.trigger[i].toUpperCase() in attrs) { outNode.open = template(options.before, attrs) + outNode.open; if (outNode.close) { outNode.close += template(options.after, attrs); } break; } } } function getFormatOptions(options) { const format = markup_formatters_es__extends({}, options && options.format); format.comment = markup_formatters_es__extends({}, commentOptions, format.comment); return format; } const reId = /^id$/i; const reClass = /^class$/i; const defaultAttrOptions = { primary: attrs => attrs.join(''), secondary: attrs => attrs.map(attr => attr.isBoolean ? attr.name : `${attr.name}=${attr.value}`).join(', ') }; const defaultNodeOptions = { open: null, close: null, omitName: /^div$/i, attributes: defaultAttrOptions }; function indentFormat(outNode, profile, options) { options = markup_formatters_es__extends({}, defaultNodeOptions, options); const node = outNode.node; outNode.indent = profile.indent(getIndentLevel$1(node, profile)); outNode.newline = '\n'; // Do not format the very first node in output if (!isRoot(node.parent) || !isFirstChild(node)) { outNode.beforeOpen = outNode.newline + outNode.indent; } if (node.name) { const data = markup_formatters_es__extends({ NAME: profile.name(node.name), SELF_CLOSE: node.selfClosing ? options.selfClose : null }, getAttributes(outNode, profile, options.attributes)); // omit tag name if node has primary attributes if (options.omitName && options.omitName.test(data.NAME) && data.PRIMARY_ATTRS) { data.NAME = null; } if (options.open != null) { outNode.open = template(options.open, data); } if (options.close != null) { outNode.close = template(options.close, data); } } return outNode; } /** * Formats attributes of given node into a string. * @param {OutputNode} node Output node wrapper * @param {Profile} profile Output profile * @param {Object} options Additional formatting options * @return {String} */ function getAttributes(outNode, profile, options) { options = markup_formatters_es__extends({}, defaultAttrOptions, options); const primary = [], secondary = []; const node = outNode.node; node.attributes.forEach(attr => { if (attr.options.implied && attr.value == null) { return null; } const name = profile.attribute(attr.name); const value = outNode.renderFields(attr.value); if (reId.test(name)) { value && primary.push(`#${value}`); } else if (reClass.test(name)) { value && primary.push(`.${value.replace(/\s+/g, '.')}`); } else { const isBoolean = attr.value == null && (attr.options.boolean || profile.get('booleanAttributes').indexOf(name.toLowerCase()) !== -1); secondary.push({ name, value, isBoolean }); } }); return { PRIMARY_ATTRS: options.primary(primary) || null, SECONDARY_ATTRS: options.secondary(secondary) || null }; } /** * Computes indent level for given node * @param {Node} node * @return {Number} */ function getIndentLevel$1(node) { let level = node.parent.isTextOnly ? -2 : -1; let ctx = node; while (ctx = ctx.parent) { level++; } return level < 0 ? 0 : level; } const reNl = /\n|\r/; /** * Renders given parsed Emmet abbreviation as HAML, formatted according to * `profile` options * @param {Node} tree Parsed Emmet abbreviation * @param {Profile} profile Output profile * @param {Object} [options] Additional formatter options * @return {String} */ function haml(tree, profile, options) { options = options || {}; const nodeOptions = { open: '[%NAME][PRIMARY_ATTRS][(SECONDARY_ATTRS)][SELF_CLOSE]', selfClose: '/', attributes: { secondary(attrs) { return attrs.map(attr => attr.isBoolean ? `${attr.name}${profile.get('compactBooleanAttributes') ? '' : '=true'}` : `${attr.name}=${profile.quote(attr.value)}`).join(' '); } } }; return output_renderer_es(tree, options.field, outNode => { outNode = indentFormat(outNode, profile, nodeOptions); outNode = updateFormatting(outNode, profile); if (!handlePseudoSnippet(outNode)) { const node = outNode.node; // Do not generate fields for nodes with empty value and children // or if node is self-closed if (node.value || !node.children.length && !node.selfClosing) { outNode.text = outNode.renderFields(formatNodeValue(node, profile)); } } return outNode; }); } /** * Updates formatting properties for given output node * NB Unlike HTML, HAML is indent-based format so some formatting options from * `profile` will not take effect, otherwise output will be broken * @param {OutputNode} outNode Output wrapper of parsed abbreviation node * @param {Profile} profile Output profile * @return {OutputNode} */ function updateFormatting(outNode, profile) { const node = outNode.node; if (!node.isTextOnly && node.value) { // node with text: put a space before single-line text outNode.beforeText = reNl.test(node.value) ? outNode.newline + outNode.indent + profile.indent(1) : ' '; } return outNode; } /** * Formats value of given node: for multiline text we should add a ` |` suffix * at the end of each line. Also ensure that text is perfectly aligned. * @param {Node} node * @param {Profile} profile * @return {String|null} */ function formatNodeValue(node, profile) { if (node.value != null && reNl.test(node.value)) { const lines = markup_formatters_es_splitByLines(node.value); const indent = profile.indent(1); const maxLength = lines.reduce((prev, line) => Math.max(prev, line.length), 0); return lines.map((line, i) => `${i ? indent : ''}${pad(line, maxLength)} |`).join('\n'); } return node.value; } function pad(text, len) { while (text.length < len) { text += ' '; } return text; } const reNl$1 = /\n|\r/; const secondaryAttrs = { none: '[ SECONDARY_ATTRS]', round: '[(SECONDARY_ATTRS)]', curly: '[{SECONDARY_ATTRS}]', square: '[[SECONDARY_ATTRS]' }; /** * Renders given parsed Emmet abbreviation as Slim, formatted according to * `profile` options * @param {Node} tree Parsed Emmet abbreviation * @param {Profile} profile Output profile * @param {Object} [options] Additional formatter options * @return {String} */ function slim(tree, profile, options) { options = options || {}; const SECONDARY_ATTRS = options.attributeWrap && secondaryAttrs[options.attributeWrap] || secondaryAttrs.none; const booleanAttr = SECONDARY_ATTRS === secondaryAttrs.none ? attr => `${attr.name}=true` : attr => attr.name; const nodeOptions = { open: `[NAME][PRIMARY_ATTRS]${SECONDARY_ATTRS}[SELF_CLOSE]`, selfClose: '/', attributes: { secondary(attrs) { return attrs.map(attr => attr.isBoolean ? booleanAttr(attr) : `${attr.name}=${profile.quote(attr.value)}`).join(' '); } } }; return output_renderer_es(tree, options.field, outNode => { outNode = indentFormat(outNode, profile, nodeOptions); outNode = updateFormatting$1(outNode, profile); if (!handlePseudoSnippet(outNode)) { const node = outNode.node; // Do not generate fields for nodes with empty value and children // or if node is self-closed if (node.value || !node.children.length && !node.selfClosing) { outNode.text = outNode.renderFields(formatNodeValue$1(node, profile)); } } return outNode; }); } /** * Updates formatting properties for given output node * NB Unlike HTML, Slim is indent-based format so some formatting options from * `profile` will not take effect, otherwise output will be broken * @param {OutputNode} outNode Output wrapper of farsed abbreviation node * @param {Profile} profile Output profile * @return {OutputNode} */ function updateFormatting$1(outNode, profile) { const node = outNode.node; const parent = node.parent; // Edge case: a single inline-level child inside node without text: // allow it to be inlined if (profile.get('inlineBreak') === 0 && isInline$1(node, profile) && !isRoot(parent) && parent.value == null && parent.children.length === 1) { outNode.beforeOpen = ': '; } if (!node.isTextOnly && node.value) { // node with text: put a space before single-line text outNode.beforeText = reNl$1.test(node.value) ? outNode.newline + outNode.indent + profile.indent(1) : ' '; } return outNode; } /** * Formats value of given node: for multiline text we should precede each * line with `| ` with one-level deep indent * @param {Node} node * @param {Profile} profile * @return {String|null} */ function formatNodeValue$1(node, profile) { if (node.value != null && reNl$1.test(node.value)) { const indent = profile.indent(1); return markup_formatters_es_splitByLines(node.value).map((line, i) => `${indent}${i ? ' ' : '|'} ${line}`).join('\n'); } return node.value; } /** * Check if given node is inline-level * @param {Node} node * @param {Profile} profile * @return {Boolean} */ function isInline$1(node, profile) { return node && (node.isTextOnly || profile.isInline(node)); } const reNl$2 = /\n|\r/; /** * Renders given parsed Emmet abbreviation as Pug, formatted according to * `profile` options * @param {Node} tree Parsed Emmet abbreviation * @param {Profile} profile Output profile * @param {Object} [options] Additional formatter options * @return {String} */ function pug(tree, profile, options) { options = options || {}; const nodeOptions = { open: '[NAME][PRIMARY_ATTRS][(SECONDARY_ATTRS)]', attributes: { secondary(attrs) { return attrs.map(attr => attr.isBoolean ? attr.name : `${attr.name}=${profile.quote(attr.value)}`).join(', '); } } }; return output_renderer_es(tree, options.field, outNode => { outNode = indentFormat(outNode, profile, nodeOptions); outNode = updateFormatting$2(outNode, profile); if (!handlePseudoSnippet(outNode)) { const node = outNode.node; // Do not generate fields for nodes with empty value and children // or if node is self-closed if (node.value || !node.children.length && !node.selfClosing) { outNode.text = outNode.renderFields(formatNodeValue$2(node, profile)); } } return outNode; }); } /** * Updates formatting properties for given output node * NB Unlike HTML, Pug is indent-based format so some formatting options from * `profile` will not take effect, otherwise output will be broken * @param {OutputNode} outNode Output wrapper of parsed abbreviation node * @param {Profile} profile Output profile * @return {OutputNode} */ function updateFormatting$2(outNode, profile) { const node = outNode.node; if (!node.isTextOnly && node.value) { // node with text: put a space before single-line text outNode.beforeText = reNl$2.test(node.value) ? outNode.newline + outNode.indent + profile.indent(1) : ' '; } return outNode; } /** * Formats value of given node: for multiline text we should precede each * line with `| ` with one-level deep indent * @param {Node} node * @param {Profile} profile * @return {String|null} */ function formatNodeValue$2(node, profile) { if (node.value != null && reNl$2.test(node.value)) { const indent = profile.indent(1); return markup_formatters_es_splitByLines(node.value).map(line => `${indent}| ${line}`).join('\n'); } return node.value; } const supportedSyntaxes = { html, haml, slim, pug }; /** * Outputs given parsed abbreviation in specified syntax * @param {Node} tree Parsed abbreviation tree * @param {Profile} profile Output profile * @param {String} [syntax] Output syntax. If not given, `html` syntax is used * @param {Function} options.field A function to output field/tabstop for * host editor. This function takes two arguments: `index` and `placeholder` and * should return a string that represents tabstop in host editor. By default * only a placeholder is returned * @example * { * field(index, placeholder) { * // return field in TextMate-style, e.g. ${1} or ${2:foo} * return `\${${index}${placeholder ? ':' + placeholder : ''}}`; * } * } * @return {String} */ function markup_formatters_es_index(tree, profile, syntax, options) { if (typeof syntax === 'object') { options = syntax; syntax = null; } if (!supports(syntax)) { // fallback to HTML if given syntax is not supported syntax = 'html'; } return supportedSyntaxes[syntax](tree, profile, options); } /** * Check if given syntax is supported * @param {String} syntax * @return {Boolean} */ function supports(syntax) { return !!syntax && syntax in supportedSyntaxes; } /* harmony default export */ var markup_formatters_es = (markup_formatters_es_index); //# sourceMappingURL=markup-formatters.es.js.map // CONCATENATED MODULE: ../node_modules/@emmetio/css-abbreviation/dist/css-abbreviation.es.js /** * A wrapper for holding CSS value */ let CSSValue = class CSSValue { constructor() { this.type = 'css-value'; this.value = []; } get size() { return this.value.length; } add(value) { this.value.push(value); } has(value) { return this.value.indexOf(value) !== -1; } toString() { return this.value.join(' '); } }; const css_abbreviation_es_HASH = 35; // # const css_abbreviation_es_DOT = 46; // . /** * Consumes a color token from given string * @param {StreamReader} stream * @return {Color} Returns consumend color object, `undefined` otherwise */ function consumeColor(stream) { // supported color variations: // #abc → #aabbccc // #0 → #000000 // #fff.5 → rgba(255, 255, 255, 0.5) // #t → transparent if (stream.peek() === css_abbreviation_es_HASH) { stream.start = stream.pos; stream.next(); stream.eat(116) /* t */ || stream.eatWhile(isHex); const base = stream.current(); // a hex color can be followed by `.num` alpha value stream.start = stream.pos; if (stream.eat(css_abbreviation_es_DOT) && !stream.eatWhile(isNumber)) { throw stream.error('Unexpected character for alpha value of color'); } return new Color(base, stream.current()); } } let Color = class Color { constructor(value, alpha) { this.type = 'color'; this.raw = value; this.alpha = Number(alpha != null && alpha !== '' ? alpha : 1); value = value.slice(1); // remove # let r = 0, g = 0, b = 0; if (value === 't') { this.alpha = 0; } else { switch (value.length) { case 0: break; case 1: r = g = b = value + value; break; case 2: r = g = b = value; break; case 3: r = value[0] + value[0]; g = value[1] + value[1]; b = value[2] + value[2]; break; default: value += value; r = value.slice(0, 2); g = value.slice(2, 4); b = value.slice(4, 6); } } this.r = parseInt(r, 16); this.g = parseInt(g, 16); this.b = parseInt(b, 16); } /** * Output current color as hex value * @param {Boolean} shor Produce short value (e.g. #fff instead of #ffffff), if possible * @return {String} */ toHex(short) { const fn = short && isShortHex(this.r) && isShortHex(this.g) && isShortHex(this.b) ? toShortHex : toHex; return '#' + fn(this.r) + fn(this.g) + fn(this.b); } /** * Output current color as `rgba?(...)` CSS color * @return {String} */ toRGB() { const values = [this.r, this.g, this.b]; if (this.alpha !== 1) { values.push(this.alpha.toFixed(8).replace(/\.?0+$/, '')); } return `${values.length === 3 ? 'rgb' : 'rgba'}(${values.join(', ')})`; } toString(short) { if (!this.r && !this.g && !this.b && !this.alpha) { return 'transparent'; } return this.alpha === 1 ? this.toHex(short) : this.toRGB(); } }; /** * Check if given code is a hex value (/0-9a-f/) * @param {Number} code * @return {Boolean} */ function isHex(code) { return isNumber(code) || isAlpha(code, 65, 70); // A-F } function isShortHex(hex) { return !(hex % 17); } function toShortHex(num) { return (num >> 4).toString(16); } function toHex(num) { return css_abbreviation_es_pad(num.toString(16), 2); } function css_abbreviation_es_pad(value, len) { while (value.length < len) { value = '0' + value; } return value; } /** * @param {Number} code * @return {Boolean} */ function isAlphaNumericWord(code) { return isNumber(code) || isAlphaWord(code); } /** * @param {Number} code * @return {Boolean} */ function isAlphaWord(code) { return code === 95 /* _ */ || isAlpha(code); } const PERCENT = 37; // % const css_abbreviation_es_DOT$1 = 46; // . const css_abbreviation_es_DASH = 45; // - /** * Consumes numeric CSS value (number with optional unit) from current stream, * if possible * @param {StreamReader} stream * @return {NumericValue} */ function consumeNumericValue(stream) { stream.start = stream.pos; if (eatNumber(stream)) { const num = stream.current(); stream.start = stream.pos; // eat unit, which can be a % or alpha word stream.eat(PERCENT) || stream.eatWhile(isAlphaWord); return new NumericValue(num, stream.current()); } } /** * A numeric CSS value with optional unit */ let NumericValue = class NumericValue { constructor(value, unit) { this.type = 'numeric'; this.value = Number(value); this.unit = unit || ''; } toString() { return `${this.value}${this.unit}`; } }; /** * Eats number value from given stream * @param {StreamReader} stream * @return {Boolean} Returns `true` if number was consumed */ function eatNumber(stream) { const start = stream.pos; const negative = stream.eat(css_abbreviation_es_DASH); const afterNegative = stream.pos; stream.eatWhile(isNumber); const prevPos = stream.pos; if (stream.eat(css_abbreviation_es_DOT$1) && !stream.eatWhile(isNumber)) { // Number followed by a dot, but then no number stream.pos = prevPos; } // Edge case: consumed dash only: not a number, bail-out if (stream.pos === afterNegative) { stream.pos = start; } return stream.pos !== start; } const css_abbreviation_es_DOLLAR = 36; // $ const DASH$1 = 45; // - const AT = 64; // @ /** * Consumes a keyword: either a variable (a word that starts with $ or @) or CSS * keyword or shorthand * @param {StreamReader} stream * @param {Boolean} [short] Use short notation for consuming value. * The difference between “short” and “full” notation is that first one uses * alpha characters only and used for extracting keywords from abbreviation, * while “full” notation also supports numbers and dashes * @return {String} Consumed variable */ function consumeKeyword(stream, short) { stream.start = stream.pos; if (stream.eat(css_abbreviation_es_DOLLAR) || stream.eat(AT)) { // SCSS or LESS variable stream.eatWhile(isVariableName); } else if (short) { stream.eatWhile(isAlphaWord); } else { stream.eatWhile(isKeyword); } return stream.start !== stream.pos ? new Keyword(stream.current()) : null; } let Keyword = class Keyword { constructor(value) { this.type = 'keyword'; this.value = value; } toString() { return this.value; } }; function isKeyword(code) { return isAlphaNumericWord(code) || code === DASH$1; } function isVariableName(code) { return code === 45 /* - */ || isAlphaNumericWord(code); } const css_abbreviation_es_opt = { throws: true }; /** * Consumes 'single' or "double"-quoted string from given string, if possible * @param {StreamReader} stream * @return {String} */ function css_abbreviation_es_consumeQuoted(stream) { if (eatQuoted(stream, css_abbreviation_es_opt)) { return new QuotedString(stream.current()); } } let QuotedString = class QuotedString { constructor(value) { this.type = 'string'; this.value = value; } toString() { return this.value; } }; const LBRACE = 40; // ( const RBRACE = 41; // ) const COMMA = 44; // , /** * Consumes arguments from given string. * Arguments are comma-separated list of CSS values inside round braces, e.g. * `(1, a2, 'a3')`. Nested lists and quoted strings are supported * @param {StreamReader} stream * @return {Array} Array of arguments, `null` if arguments cannot be consumed */ function consumeArgumentList(stream) { if (!stream.eat(LBRACE)) { // not an argument list return null; } let arg; const argsList = []; while (!stream.eof()) { if (arg = consumeArgument(stream)) { argsList.push(arg); } else { // didn’t consumed argument, expect argument separator or end-of-arguments stream.eatWhile(isWhiteSpace); if (stream.eat(RBRACE)) { // end of arguments list break; } if (!stream.eat(COMMA)) { throw stream.error('Expected , or )'); } } } return argsList; } /** * Consumes a single argument. An argument is a `CSSValue`, e.g. it could be * a space-separated string of value * @param {StreamReader} stream * @return {CSSValue} */ function consumeArgument(stream) { const result = new CSSValue(); let value; while (!stream.eof()) { stream.eatWhile(isWhiteSpace); value = consumeNumericValue(stream) || consumeColor(stream) || css_abbreviation_es_consumeQuoted(stream) || consumeKeywordOrFunction(stream); if (!value) { break; } result.add(value); } return result.size ? result : null; } /** * Consumes either function call like `foo()` or keyword like `foo` * @param {StreamReader} stream * @return {Keyword|FunctionCall} */ function consumeKeywordOrFunction(stream) { const kw = consumeKeyword(stream); if (kw) { const args = consumeArgumentList(stream); return args ? new FunctionCall(kw.toString(), args) : kw; } } let FunctionCall = class FunctionCall { /** * @param {String} name Function name * @param {Array} args Function arguments */ constructor(name, args) { this.type = 'function'; this.name = name; this.args = args || []; } toString() { return `${this.name}(${this.args.join(', ')})`; } }; const css_abbreviation_es_EXCL = 33; // ! const DOLLAR$1 = 36; // $ const PLUS = 43; // + const DASH$2 = 45; // - const css_abbreviation_es_COLON = 58; // : const AT$1 = 64; // @ /** * Parses given Emmet CSS abbreviation and returns it as parsed Node tree * @param {String} abbr * @return {Node} */ function css_abbreviation_es_index(abbr) { const root = new node_es(); const stream = new stream_reader_es(abbr); while (!stream.eof()) { let node = new node_es(consumeIdent(stream)); node.value = consumeValue(stream); const args = consumeArgumentList(stream); if (args) { // technically, arguments in CSS are anonymous Emmet Node attributes, // but since Emmet can support only one anonymous, `null`-name // attribute (for good reasons), we’ll use argument index as name for (let i = 0; i < args.length; i++) { node.setAttribute(String(i), args[i]); } } // Consume `!important` modifier at the end of expression if (stream.eat(css_abbreviation_es_EXCL)) { node.value.add('!'); } root.appendChild(node); // CSS abbreviations cannot be nested, only listed if (!stream.eat(PLUS)) { break; } } if (!stream.eof()) { throw stream.error('Unexpected character'); } return root; } /** * Consumes CSS property identifier from given stream * @param {StreamReader} stream * @return {String} */ function consumeIdent(stream) { stream.start = stream.pos; stream.eatWhile(isIdentPrefix); stream.eatWhile(css_abbreviation_es_isIdent); return stream.start !== stream.pos ? stream.current() : null; } /** * Consumes embedded value from Emmet CSS abbreviation stream * @param {StreamReader} stream * @return {CSSValue} */ function consumeValue(stream) { const values = new CSSValue(); let value; while (!stream.eof()) { // use colon as value separator stream.eat(css_abbreviation_es_COLON); if (value = consumeNumericValue(stream) || consumeColor(stream)) { // edge case: a dash after unit-less numeric value or color should // be treated as value separator, not negative sign if (!value.unit) { stream.eat(DASH$2); } } else { stream.eat(DASH$2); value = consumeKeyword(stream, true); } if (!value) { break; } values.add(value); } return values; } /** * @param {Number} code * @return {Boolean} */ function css_abbreviation_es_isIdent(code) { return isAlphaWord(code); } /** * @param {Number} code * @return {Boolean} */ function isIdentPrefix(code) { return code === AT$1 || code === DOLLAR$1 || code === css_abbreviation_es_EXCL; } /* harmony default export */ var css_abbreviation_es = (css_abbreviation_es_index); // CONCATENATED MODULE: ../node_modules/@emmetio/expand-abbreviation/node_modules/@emmetio/css-snippets-resolver/dist/css-snippets-resolver.es.js var 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 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 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 === css_snippets_resolver_es_DASH; j++; } if (!found) { break; } i++; } return score && score * (i / abbrLength) / sum(stringLength); } /** * Calculates sum of first `n` natural numbers, e.g. 1+2+3+...n * @param {Number} n * @return {Number} */ function sum(n) { return n * (n + 1) / 2; } const reProperty = /^([a-z-]+)(?:\s*:\s*([^\n\r]+))?$/; const 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 cssSnippets(snippets) { return nest(snippets.map(snippet => new CSSSnippet(snippet.key, snippet.value))); } let 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(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 ? 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 = splitValue(item.value).filter(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 nest(snippets) { snippets = snippets.sort(snippetsSort); const stack = []; // For sorted list of CSS properties, create dependency graph where each // shorthand property contains its more specific one, e.g. // background -> 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) === 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 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 css_snippets_resolver_es_isKeyword(str) { return (/^\s*[\w-]+/.test(str) ); } function splitValue(value) { return String(value).split('|'); } const globalKeywords = ['auto', 'inherit', 'unset']; const unitlessProperties = ['z-index', 'line-height', 'opacity', 'font-weight', 'zoom', 'flex', 'flex-grow', 'flex-shrink']; const 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 css_snippets_resolver_es_index(tree, registry, options) { options = css_snippets_resolver_es__extends({}, css_snippets_resolver_es_defaultOptions, options); options.unitAliases = css_snippets_resolver_es__extends({}, css_snippets_resolver_es_defaultOptions.unitAliases, options && options.unitAliases); const snippets = convertToCSSSnippets(registry); tree.walk(node => css_snippets_resolver_es_resolveNode(node, snippets, options)); return tree; } function convertToCSSSnippets(registry) { return 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 css_snippets_resolver_es_resolveNode(node, snippets, options) { if (options.property) { // Resolve as value of given CSS property return resolveAsPropertyValue(node, snippets.find(snippet => snippet.property === options.property), options); } const snippet = findBestMatch(node.name, snippets, 'key', options.fuzzySearchMinScore); if (!snippet) { // Edge case: `!important` snippet return node.name === '!' ? setNodeAsText(node, '!important') : node; } return snippet.property ? resolveAsProperty(node, snippet, options) : resolveAsSnippet(node, snippet); } /** * Resolves given parsed abbreviation node as CSS property * @param {Node} node * @param {CSSSnippet} snippet * @param {Object} formatOptions * @return {Node} */ function 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 = findBestMatch(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 (isKeyword$1(token)) { token = findBestMatch(token.value, keywords) || findBestMatch(token.value, globalKeywords) || token; } else if (isNumericValue(token)) { token = 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 resolveAsSnippet(node, snippet) { return setNodeAsText(node, snippet.value); } /** * Resolves given parsed abbreviation node as property value of given `snippet`: * tries to find best matching keyword from CSS snippet * @param {Node} node * @param {CSSSnippet} snippet * @param {Object} options * @return {Node} */ function resolveAsPropertyValue(node, snippet, options) { // Possible resolved result for CSS property: // * matched snippet keyword // * color (starts with #) // Everything else should result the same as input abbreviation let keywords = globalKeywords.slice(); if (snippet) { keywords = keywords.concat(snippet.keywords()); } const values = [node.name].concat(node.value.value).filter(Boolean).map(value => { if (typeof value === 'string' || value.type === 'keyword') { value = String(value); return findBestMatch(value, keywords, null, options.fuzzySearchMinScore) || value; } return value; }); node.name = null; node.value.value = values; return node; } /** * Sets given parsed abbreviation node as a text snippet * @param {Node} node * @param {String} text * @return {Node} */ function 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 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 = stringScore(abbr, 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 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 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 isKeyword$1(token) { return tokenTypeOf(token, 'keyword'); } /** * Check if given CSS value token is a numeric value * @param {*} token * @return {Boolean} */ function isNumericValue(token) { return tokenTypeOf(token, 'numeric'); } function 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 resolveNumericValue(property, token, formatOptions) { if (token.unit) { token.unit = formatOptions.unitAliases[token.unit] || token.unit; } else if (token.value !== 0 && 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 css_snippets_resolver_es = (css_snippets_resolver_es_index); //# sourceMappingURL=css-snippets-resolver.es.js.map // CONCATENATED MODULE: ../node_modules/@emmetio/stylesheet-formatters/dist/stylesheet-formatters.es.js var stylesheet_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 defaultFormatOptions = { shortHex: true, between: ': ', after: ';' }; /** * Renders given parsed Emmet CSS abbreviation as CSS-like * stylesheet, formatted according to `profile` options * @param {Node} tree Parsed Emmet abbreviation * @param {Profile} profile Output profile * @param {Object} [options] Additional formatter options * @return {String} */ function css(tree, profile, options) { options = options || {}; const formatOpt = stylesheet_formatters_es__extends({}, defaultFormatOptions, options && options.format); return output_renderer_es(tree, options.field, outNode => { const node = outNode.node; let value = stringifyValue(node, formatOpt); if (node.attributes.length) { const fieldValues = node.attributes.map(attr => stringifyValue(attr, formatOpt)); value = injectFields(value, fieldValues); } outNode.open = node.name && profile.name(node.name); outNode.afterOpen = formatOpt.between; outNode.text = outNode.renderFields(value || null); if (outNode.open && (!outNode.text || !outNode.text.endsWith(';'))) { outNode.afterText = formatOpt.after; } if (profile.get('format')) { outNode.newline = '\n'; if (tree.lastChild !== node) { outNode.afterText += outNode.newline; } } return outNode; }); } /** * Injects given field values at each field of given string * @param {String} string * @param {String[]} attributes * @return {FieldString} */ function injectFields(string, values) { const fieldsModel = field_parser_es(string); const fieldsAmount = fieldsModel.fields.length; if (fieldsAmount) { values = values.slice(); if (values.length > fieldsAmount) { // More values that output fields: collapse rest values into // a single token values = values.slice(0, fieldsAmount - 1).concat(values.slice(fieldsAmount - 1).join(', ')); } while (values.length) { const value = values.shift(); const field = fieldsModel.fields.shift(); const delta = value.length - field.length; fieldsModel.string = fieldsModel.string.slice(0, field.location) + value + fieldsModel.string.slice(field.location + field.length); // Update location of the rest fields in string for (let i = 0, il = fieldsModel.fields.length; i < il; i++) { fieldsModel.fields[i].location += delta; } } } return fieldsModel; } function stringifyValue(node, options) { if (node.value && typeof node.value === 'object' && node.value.type === 'css-value') { return node.value.value.map(token => { if (token && typeof token === 'object') { return token.type === 'color' ? token.toString(options.shortHex) : token.toString(); } return String(token); }).join(' '); } return node.value != null ? String(node.value) : ''; } const syntaxFormat = { css: { between: ': ', after: ';' }, scss: 'css', less: 'css', sass: { between: ': ', after: '' }, stylus: { between: ' ', after: '' } }; /** * Outputs given parsed abbreviation in specified stylesheet syntax * @param {Node} tree Parsed abbreviation tree * @param {Profile} profile Output profile * @param {String} [syntax] Output syntax. If not given, `css` syntax is used * @param {Function} options.field A function to output field/tabstop for * host editor. This function takes two arguments: `index` and `placeholder` and * should return a string that represents tabstop in host editor. By default * only a placeholder is returned * @example * { * field(index, placeholder) { * // return field in TextMate-style, e.g. ${1} or ${2:foo} * return `\${${index}${placeholder ? ':' + placeholder : ''}}`; * } * } * @return {String} */ function stylesheet_formatters_es_index(tree, profile, syntax, options) { if (typeof syntax === 'object') { options = syntax; syntax = null; } if (!stylesheet_formatters_es_supports(syntax)) { // fallback to CSS if given syntax is not supported syntax = 'css'; } options = stylesheet_formatters_es__extends({}, options, { format: getFormat(syntax, options) }); // CSS abbreviations doesn’t support nesting so simply // output root node children return css(tree, profile, options); } /** * Check if given syntax is supported * @param {String} syntax * @return {Boolean} */ function stylesheet_formatters_es_supports(syntax) { return !!syntax && syntax in syntaxFormat; } /** * Returns formatter object for given syntax * @param {String} syntax * @param {Object} [options] * @return {Object} Formatter object as defined in `syntaxFormat` */ function getFormat(syntax, options) { let format = syntaxFormat[syntax]; if (typeof format === 'string') { format = syntaxFormat[format]; } return stylesheet_formatters_es__extends({}, format, options && options.format); } /* harmony default export */ var stylesheet_formatters_es = (stylesheet_formatters_es_index); //# sourceMappingURL=stylesheet-formatters.es.js.map // CONCATENATED MODULE: ../node_modules/@emmetio/snippets/dist/snippets.es.js var snippets_es_html = { "a": "a[href]", "a:link": "a[href='http://${0}']", "a:mail": "a[href='mailto:${0}']", "a:tel": "a[href='tel:+${0}']", "abbr": "abbr[title]", "acr|acronym": "acronym[title]", "base": "base[href]/", "basefont": "basefont/", "br": "br/", "frame": "frame/", "hr": "hr/", "bdo": "bdo[dir]", "bdo:r": "bdo[dir=rtl]", "bdo:l": "bdo[dir=ltr]", "col": "col/", "link": "link[rel=stylesheet href]/", "link:css": "link[href='${1:style}.css']", "link:print": "link[href='${1:print}.css' media=print]", "link:favicon": "link[rel='shortcut icon' type=image/x-icon href='${1:favicon.ico}']", "link:touch": "link[rel=apple-touch-icon href='${1:favicon.png}']", "link:rss": "link[rel=alternate type=application/rss+xml title=RSS href='${1:rss.xml}']", "link:atom": "link[rel=alternate type=application/atom+xml title=Atom href='${1:atom.xml}']", "link:im|link:import": "link[rel=import href='${1:component}.html']", "meta": "meta/", "meta:utf": "meta[http-equiv=Content-Type content='text/html;charset=UTF-8']", "meta:vp": "meta[name=viewport content='width=${1:device-width}, initial-scale=${2:1.0}']", "meta:compat": "meta[http-equiv=X-UA-Compatible content='${1:IE=7}']", "meta:edge": "meta:compat[content='${1:ie=edge}']", "meta:redirect": "meta[http-equiv=refresh content='0; url=${1:http://example.com}']", "style": "style", "script": "script[!src]", "script:src": "script[src]", "img": "img[src alt]/", "img:s|img:srcset": "img[srcset src alt]", "img:z|img:sizes": "img[sizes srcset src alt]", "picture": "picture", "src|source": "source/", "src:sc|source:src": "source[src type]", "src:s|source:srcset": "source[srcset]", "src:t|source:type": "source[srcset type='${1:image/}']", "src:z|source:sizes": "source[sizes srcset]", "src:m|source:media": "source[media='(${1:min-width: })' srcset]", "src:mt|source:media:type": "source:media[type='${2:image/}']", "src:mz|source:media:sizes": "source:media[sizes srcset]", "src:zt|source:sizes:type": "source[sizes srcset type='${1:image/}']", "iframe": "iframe[src frameborder=0]", "embed": "embed[src type]/", "object": "object[data type]", "param": "param[name value]/", "map": "map[name]", "area": "area[shape coords href alt]/", "area:d": "area[shape=default]", "area:c": "area[shape=circle]", "area:r": "area[shape=rect]", "area:p": "area[shape=poly]", "form": "form[action]", "form:get": "form[method=get]", "form:post": "form[method=post]", "label": "label[for]", "input": "input[type=${1:text}]/", "inp": "input[name=${1} id=${1}]", "input:h|input:hidden": "input[type=hidden name]", "input:t|input:text": "inp[type=text]", "input:search": "inp[type=search]", "input:email": "inp[type=email]", "input:url": "inp[type=url]", "input:p|input:password": "inp[type=password]", "input:datetime": "inp[type=datetime]", "input:date": "inp[type=date]", "input:datetime-local": "inp[type=datetime-local]", "input:month": "inp[type=month]", "input:week": "inp[type=week]", "input:time": "inp[type=time]", "input:tel": "inp[type=tel]", "input:number": "inp[type=number]", "input:color": "inp[type=color]", "input:c|input:checkbox": "inp[type=checkbox]", "input:r|input:radio": "inp[type=radio]", "input:range": "inp[type=range]", "input:f|input:file": "inp[type=file]", "input:s|input:submit": "input[type=submit value]", "input:i|input:image": "input[type=image src alt]", "input:b|input:button": "input[type=button value]", "input:reset": "input:button[type=reset]", "isindex": "isindex/", "select": "select[name=${1} id=${1}]", "select:d|select:disabled": "select[disabled.]", "opt|option": "option[value]", "textarea": "textarea[name=${1} id=${1} cols=${2:30} rows=${3:10}]", "marquee": "marquee[behavior direction]", "menu:c|menu:context": "menu[type=context]", "menu:t|menu:toolbar": "menu[type=toolbar]", "video": "video[src]", "audio": "audio[src]", "html:xml": "html[xmlns=http://www.w3.org/1999/xhtml]", "keygen": "keygen/", "command": "command/", "btn:s|button:s|button:submit": "button[type=submit]", "btn:r|button:r|button:reset": "button[type=reset]", "btn:d|button:d|button:disabled": "button[disabled.]", "fst:d|fset:d|fieldset:d|fieldset:disabled": "fieldset[disabled.]", "bq": "blockquote", "fig": "figure", "figc": "figcaption", "pic": "picture", "ifr": "iframe", "emb": "embed", "obj": "object", "cap": "caption", "colg": "colgroup", "fst": "fieldset", "btn": "button", "optg": "optgroup", "tarea": "textarea", "leg": "legend", "sect": "section", "art": "article", "hdr": "header", "ftr": "footer", "adr": "address", "dlg": "dialog", "str": "strong", "prog": "progress", "mn": "main", "tem": "template", "fset": "fieldset", "datag": "datagrid", "datal": "datalist", "kg": "keygen", "out": "output", "det": "details", "cmd": "command", "ri:d|ri:dpr": "img:s", "ri:v|ri:viewport": "img:z", "ri:a|ri:art": "pic>src:m+img", "ri:t|ri:type": "pic>src:t+img", "!!!": "{}", "doc": "html[lang=${lang}]>(head>meta[charset=${charset}]+meta:vp+meta:edge+title{${1:Document}})+body", "!|html:5": "!!!+doc", "c": "{}", "cc:ie": "{}", "cc:noie": "{${0}}" }; var snippets_es_css = { "@f": "@font-face {\n\tfont-family: ${1};\n\tsrc: url(${1});\n}", "@ff": "@font-face {\n\tfont-family: '${1:FontName}';\n\tsrc: url('${2:FileName}.eot');\n\tsrc: url('${2:FileName}.eot?#iefix') format('embedded-opentype'),\n\t\t url('${2:FileName}.woff') format('woff'),\n\t\t url('${2:FileName}.ttf') format('truetype'),\n\t\t url('${2:FileName}.svg#${1:FontName}') format('svg');\n\tfont-style: ${3:normal};\n\tfont-weight: ${4:normal};\n}", "@i|@import": "@import url(${0});", "@kf": "@keyframes ${1:identifier} {\n\t${2}\n}", "@m|@media": "@media ${1:screen} {\n\t${0}\n}", "ac": "align-content:flex-start|flex-end|center|space-between|space-around|stretch", "ai": "align-items:flex-start|flex-end|center|baseline|stretch", "anim": "animation:${1:name} ${2:duration} ${3:timing-function} ${4:delay} ${5:iteration-count} ${6:direction} ${7:fill-mode}", "animdel": "animation-delay:${1:time}", "animdir": "animation-direction:normal|reverse|alternate|alternate-reverse", "animdur": "animation-duration:${1:0}s", "animfm": "animation-fill-mode:both|forwards|backwards", "animic": "animation-iteration-count:1|infinite", "animn": "animation-name", "animps": "animation-play-state:running|paused", "animtf": "animation-timing-function:linear|ease|ease-in|ease-out|ease-in-out|cubic-bezier(${1:0.1}, ${2:0.7}, ${3:1.0}, ${3:0.1})", "ap": "appearance:none", "as": "align-self:auto|flex-start|flex-end|center|baseline|stretch", "b": "bottom", "bd": "border:${1:1px} ${2:solid} ${3:#000}", "bdb": "border-bottom:${1:1px} ${2:solid} ${3:#000}", "bdbc": "border-bottom-color:#${1:000}", "bdbi": "border-bottom-image:url(${0})", "bdbk": "border-break:close", "bdbli": "border-bottom-left-image:url(${0})|continue", "bdblrs": "border-bottom-left-radius", "bdbri": "border-bottom-right-image:url(${0})|continue", "bdbrrs": "border-bottom-right-radius", "bdbs": "border-bottom-style", "bdbw": "border-bottom-width", "bdc": "border-color:#${1:000}", "bdci": "border-corner-image:url(${0})|continue", "bdcl": "border-collapse:collapse|separate", "bdf": "border-fit:repeat|clip|scale|stretch|overwrite|overflow|space", "bdi": "border-image:url(${0})", "bdl": "border-left:${1:1px} ${2:solid} ${3:#000}", "bdlc": "border-left-color:#${1:000}", "bdlen": "border-length", "bdli": "border-left-image:url(${0})", "bdls": "border-left-style", "bdlw": "border-left-width", "bdr": "border-right:${1:1px} ${2:solid} ${3:#000}", "bdrc": "border-right-color:#${1:000}", "bdri": "border-right-image:url(${0})", "bdrs": "border-radius", "bdrst": "border-right-style", "bdrw": "border-right-width", "bds": "border-style:none|hidden|dotted|dashed|solid|double|dot-dash|dot-dot-dash|wave|groove|ridge|inset|outset", "bdsp": "border-spacing", "bdt": "border-top:${1:1px} ${2:solid} ${3:#000}", "bdtc": "border-top-color:#${1:000}", "bdti": "border-top-image:url(${0})", "bdtli": "border-top-left-image:url(${0})|continue", "bdtlrs": "border-top-left-radius", "bdtri": "border-top-right-image:url(${0})|continue", "bdtrrs": "border-top-right-radius", "bdts": "border-top-style", "bdtw": "border-top-width", "bdw": "border-width", "bfv": "backface-visibility:hidden|visible", "bg": "background:#${1:000}", "bga": "background-attachment:fixed|scroll", "bgbk": "background-break:bounding-box|each-box|continuous", "bgc": "background-color:#${1:fff}", "bgcp": "background-clip:padding-box|border-box|content-box|no-clip", "bgi": "background-image:url(${0})", "bgo": "background-origin:padding-box|border-box|content-box", "bgp": "background-position:${1:0} ${2:0}", "bgpx": "background-position-x", "bgpy": "background-position-y", "bgr": "background-repeat:no-repeat|repeat-x|repeat-y|space|round", "bgsz": "background-size:contain|cover", "bxsh": "box-shadow:${1:inset }${2:hoff} ${3:voff} ${4:blur} #${5:000}|none", "bxsz": "box-sizing:border-box|content-box|border-box", "c": "color:#${1:000}", "cl": "clear:both|left|right|none", "cm": "/* ${0} */", "cnt": "content:'${0}'|normal|open-quote|no-open-quote|close-quote|no-close-quote|attr(${0})|counter(${0})|counters({$0})", "coi": "counter-increment", "colm": "columns", "colmc": "column-count", "colmf": "column-fill", "colmg": "column-gap", "colmr": "column-rule", "colmrc": "column-rule-color", "colmrs": "column-rule-style", "colmrw": "column-rule-width", "colms": "column-span", "colmw": "column-width", "cor": "counter-reset", "cp": "clip:auto|rect(${1:top} ${2:right} ${3:bottom} ${4:left})", "cps": "caption-side:top|bottom", "cur": "cursor:pointer|auto|default|crosshair|hand|help|move|pointer|text", "d": "display:block|none|flex|inline-flex|inline|inline-block|list-item|run-in|compact|table|inline-table|table-caption|table-column|table-column-group|table-header-group|table-footer-group|table-row|table-row-group|table-cell|ruby|ruby-base|ruby-base-group|ruby-text|ruby-text-group", "ec": "empty-cells:show|hide", "f": "font:${1:1em} ${2:sans-serif}", "fef": "font-effect:none|engrave|emboss|outline", "fem": "font-emphasize", "femp": "font-emphasize-position:before|after", "fems": "font-emphasize-style:none|accent|dot|circle|disc", "ff": "font-family:serif|sans-serif|cursive|fantasy|monospace", "fl": "float:left|right|none", "fs": "font-style:italic|normal|oblique", "fsm": "font-smoothing:antialiased|subpixel-antialiased|none", "fst": "font-stretch:normal|ultra-condensed|extra-condensed|condensed|semi-condensed|semi-expanded|expanded|extra-expanded|ultra-expanded", "fv": "font-variant:normal|small-caps", "fw": "font-weight:normal|bold|bolder|lighter", "fx": "flex", "fxb": "flex-basis:fill|max-content|min-content|fit-content|content", "fxd": "flex-direction:row|row-reverse|column|column-reverse", "fxf": "flex-flow", "fxg": "flex-grow", "fxsh": "flex-shrink", "fxw": "flex-wrap:nowrap|wrap|wrap-reverse", "fz": "font-size", "fza": "font-size-adjust", "h": "height", "jc": "justify-content:flex-start|flex-end|center|space-between|space-around", "l": "left", "lg": "background-image:linear-gradient(${1})", "lh": "line-height", "lis": "list-style", "lisi": "list-style-image", "lisp": "list-style-position:inside|outside", "list": "list-style-type:disc|circle|square|decimal|decimal-leading-zero|lower-roman|upper-roman", "lts": "letter-spacing:normal", "m": "margin", "mah": "max-height", "mar": "max-resolution", "maw": "max-width", "mb": "margin-bottom", "mih": "min-height", "mir": "min-resolution", "miw": "min-width", "ml": "margin-left", "mr": "margin-right", "mt": "margin-top", "ol": "outline", "olc": "outline-color:#${1:000}|invert", "olo": "outline-offset", "ols": "outline-style:none|dotted|dashed|solid|double|groove|ridge|inset|outset", "olw": "outline-width|thin|medium|thick", "op": "opacity", "ord": "order", "ori": "orientation:landscape|portrait", "orp": "orphans", "ov": "overflow:hidden|visible|hidden|scroll|auto", "ovs": "overflow-style:scrollbar|auto|scrollbar|panner|move|marquee", "ovx": "overflow-x:hidden|visible|hidden|scroll|auto", "ovy": "overflow-y:hidden|visible|hidden|scroll|auto", "p": "padding", "pb": "padding-bottom", "pgba": "page-break-after:auto|always|left|right", "pgbb": "page-break-before:auto|always|left|right", "pgbi": "page-break-inside:auto|avoid", "pl": "padding-left", "pos": "position:relative|absolute|relative|fixed|static", "pr": "padding-right", "pt": "padding-top", "q": "quotes", "qen": "quotes:'\\201C' '\\201D' '\\2018' '\\2019'", "qru": "quotes:'\\00AB' '\\00BB' '\\201E' '\\201C'", "r": "right", "rsz": "resize:none|both|horizontal|vertical", "t": "top", "ta": "text-align:left|center|right|justify", "tal": "text-align-last:left|center|right", "tbl": "table-layout:fixed", "td": "text-decoration:none|underline|overline|line-through", "te": "text-emphasis:none|accent|dot|circle|disc|before|after", "th": "text-height:auto|font-size|text-size|max-size", "ti": "text-indent", "tj": "text-justify:auto|inter-word|inter-ideograph|inter-cluster|distribute|kashida|tibetan", "to": "text-outline:${1:0} ${2:0} ${3:#000}", "tov": "text-overflow:ellipsis|clip", "tr": "text-replace", "trf": "transform:${1}|skewX(${1:angle})|skewY(${1:angle})|scale(${1:x}, ${2:y})|scaleX(${1:x})|scaleY(${1:y})|scaleZ(${1:z})|scale3d(${1:x}, ${2:y}, ${3:z})|rotate(${1:angle})|rotateX(${1:angle})|rotateY(${1:angle})|rotateZ(${1:angle})|translate(${1:x}, ${2:y})|translateX(${1:x})|translateY(${1:y})|translateZ(${1:z})|translate3d(${1:tx}, ${2:ty}, ${3:tz})", "trfo": "transform-origin", "trfs": "transform-style:preserve-3d", "trs": "transition:${1:prop} ${2:time}", "trsde": "transition-delay:${1:time}", "trsdu": "transition-duration:${1:time}", "trsp": "transition-property:${1:prop}", "trstf": "transition-timing-function:${1:fn}", "tsh": "text-shadow:${1:hoff} ${2:voff} ${3:blur} ${4:#000}", "tt": "text-transform:uppercase|lowercase|capitalize|none", "tw": "text-wrap:none|normal|unrestricted|suppress", "us": "user-select:none", "v": "visibility:hidden|visible|collapse", "va": "vertical-align:top|super|text-top|middle|baseline|bottom|text-bottom|sub", "w": "width", "whs": "white-space:nowrap|pre|pre-wrap|pre-line|normal", "whsc": "white-space-collapse:normal|keep-all|loose|break-strict|break-all", "wid": "widows", "wm": "writing-mode:lr-tb|lr-tb|lr-bt|rl-tb|rl-bt|tb-rl|tb-lr|bt-lr|bt-rl", "wob": "word-break:normal|keep-all|break-all", "wos": "word-spacing", "wow": "word-wrap:none|unrestricted|suppress|break-word|normal", "z": "z-index", "zom": "zoom:1" }; var snippets_es_xsl = { "tm|tmatch": "xsl:template[match mode]", "tn|tname": "xsl:template[name]", "call": "xsl:call-template[name]", "ap": "xsl:apply-templates[select mode]", "api": "xsl:apply-imports", "imp": "xsl:import[href]", "inc": "xsl:include[href]", "ch": "xsl:choose", "wh|xsl:when": "xsl:when[test]", "ot": "xsl:otherwise", "if": "xsl:if[test]", "par": "xsl:param[name]", "pare": "xsl:param[name select]", "var": "xsl:variable[name]", "vare": "xsl:variable[name select]", "wp": "xsl:with-param[name select]", "key": "xsl:key[name match use]", "elem": "xsl:element[name]", "attr": "xsl:attribute[name]", "attrs": "xsl:attribute-set[name]", "cp": "xsl:copy[select]", "co": "xsl:copy-of[select]", "val": "xsl:value-of[select]", "for|each": "xsl:for-each[select]", "tex": "xsl:text", "com": "xsl:comment", "msg": "xsl:message[terminate=no]", "fall": "xsl:fallback", "num": "xsl:number[value]", "nam": "namespace-alias[stylesheet-prefix result-prefix]", "pres": "xsl:preserve-space[elements]", "strip": "xsl:strip-space[elements]", "proc": "xsl:processing-instruction[name]", "sort": "xsl:sort[select order]", "choose": "xsl:choose>xsl:when+xsl:otherwise", "xsl": "!!!+xsl:stylesheet[version=1.0 xmlns:xsl=http://www.w3.org/1999/XSL/Transform]>{\n|}", "!!!": "{}" }; var snippets_es_index = { html: snippets_es_html, css: snippets_es_css, xsl: snippets_es_xsl }; /* harmony default export */ var snippets_es = (snippets_es_index); // CONCATENATED MODULE: ../node_modules/@emmetio/lorem/dist/lorem.es.js var lorem_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; }; var latin = { "common": ["lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipisicing", "elit"], "words": ["exercitationem", "perferendis", "perspiciatis", "laborum", "eveniet", "sunt", "iure", "nam", "nobis", "eum", "cum", "officiis", "excepturi", "odio", "consectetur", "quasi", "aut", "quisquam", "vel", "eligendi", "itaque", "non", "odit", "tempore", "quaerat", "dignissimos", "facilis", "neque", "nihil", "expedita", "vitae", "vero", "ipsum", "nisi", "animi", "cumque", "pariatur", "velit", "modi", "natus", "iusto", "eaque", "sequi", "illo", "sed", "ex", "et", "voluptatibus", "tempora", "veritatis", "ratione", "assumenda", "incidunt", "nostrum", "placeat", "aliquid", "fuga", "provident", "praesentium", "rem", "necessitatibus", "suscipit", "adipisci", "quidem", "possimus", "voluptas", "debitis", "sint", "accusantium", "unde", "sapiente", "voluptate", "qui", "aspernatur", "laudantium", "soluta", "amet", "quo", "aliquam", "saepe", "culpa", "libero", "ipsa", "dicta", "reiciendis", "nesciunt", "doloribus", "autem", "impedit", "minima", "maiores", "repudiandae", "ipsam", "obcaecati", "ullam", "enim", "totam", "delectus", "ducimus", "quis", "voluptates", "dolores", "molestiae", "harum", "dolorem", "quia", "voluptatem", "molestias", "magni", "distinctio", "omnis", "illum", "dolorum", "voluptatum", "ea", "quas", "quam", "corporis", "quae", "blanditiis", "atque", "deserunt", "laboriosam", "earum", "consequuntur", "hic", "cupiditate", "quibusdam", "accusamus", "ut", "rerum", "error", "minus", "eius", "ab", "ad", "nemo", "fugit", "officia", "at", "in", "id", "quos", "reprehenderit", "numquam", "iste", "fugiat", "sit", "inventore", "beatae", "repellendus", "magnam", "recusandae", "quod", "explicabo", "doloremque", "aperiam", "consequatur", "asperiores", "commodi", "optio", "dolor", "labore", "temporibus", "repellat", "veniam", "architecto", "est", "esse", "mollitia", "nulla", "a", "similique", "eos", "alias", "dolore", "tenetur", "deleniti", "porro", "facere", "maxime", "corrupti"] }; var ru = { "common": ["далеко-далеко", "за", "словесными", "горами", "в стране", "гласных", "и согласных", "живут", "рыбные", "тексты"], "words": ["вдали", "от всех", "они", "буквенных", "домах", "на берегу", "семантика", "большого", "языкового", "океана", "маленький", "ручеек", "даль", "журчит", "по всей", "обеспечивает", "ее", "всеми", "необходимыми", "правилами", "эта", "парадигматическая", "страна", "которой", "жаренные", "предложения", "залетают", "прямо", "рот", "даже", "всемогущая", "пунктуация", "не", "имеет", "власти", "над", "рыбными", "текстами", "ведущими", "безорфографичный", "образ", "жизни", "однажды", "одна", "маленькая", "строчка", "рыбного", "текста", "имени", "lorem", "ipsum", "решила", "выйти", "большой", "мир", "грамматики", "великий", "оксмокс", "предупреждал", "о", "злых", "запятых", "диких", "знаках", "вопроса", "коварных", "точках", "запятой", "но", "текст", "дал", "сбить", "себя", "толку", "он", "собрал", "семь", "своих", "заглавных", "букв", "подпоясал", "инициал", "за", "пояс", "пустился", "дорогу", "взобравшись", "первую", "вершину", "курсивных", "гор", "бросил", "последний", "взгляд", "назад", "силуэт", "своего", "родного", "города", "буквоград", "заголовок", "деревни", "алфавит", "подзаголовок", "своего", "переулка", "грустный", "реторический", "вопрос", "скатился", "его", "щеке", "продолжил", "свой", "путь", "дороге", "встретил", "рукопись", "она", "предупредила", "моей", "все", "переписывается", "несколько", "раз", "единственное", "что", "меня", "осталось", "это", "приставка", "возвращайся", "ты", "лучше", "свою", "безопасную", "страну", "послушавшись", "рукописи", "наш", "продолжил", "свой", "путь", "вскоре", "ему", "повстречался", "коварный", "составитель", "рекламных", "текстов", "напоивший", "языком", "речью", "заманивший", "свое", "агентство", "которое", "использовало", "снова", "снова", "своих", "проектах", "если", "переписали", "то", "живет", "там", "до", "сих", "пор"] }; var sp = { "common": ["mujer", "uno", "dolor", "más", "de", "poder", "mismo", "si"], "words": ["ejercicio", "preferencia", "perspicacia", "laboral", "paño", "suntuoso", "molde", "namibia", "planeador", "mirar", "demás", "oficinista", "excepción", "odio", "consecuencia", "casi", "auto", "chicharra", "velo", "elixir", "ataque", "no", "odio", "temporal", "cuórum", "dignísimo", "facilismo", "letra", "nihilista", "expedición", "alma", "alveolar", "aparte", "león", "animal", "como", "paria", "belleza", "modo", "natividad", "justo", "ataque", "séquito", "pillo", "sed", "ex", "y", "voluminoso", "temporalidad", "verdades", "racional", "asunción", "incidente", "marejada", "placenta", "amanecer", "fuga", "previsor", "presentación", "lejos", "necesariamente", "sospechoso", "adiposidad", "quindío", "pócima", "voluble", "débito", "sintió", "accesorio", "falda", "sapiencia", "volutas", "queso", "permacultura", "laudo", "soluciones", "entero", "pan", "litro", "tonelada", "culpa", "libertario", "mosca", "dictado", "reincidente", "nascimiento", "dolor", "escolar", "impedimento", "mínima", "mayores", "repugnante", "dulce", "obcecado", "montaña", "enigma", "total", "deletéreo", "décima", "cábala", "fotografía", "dolores", "molesto", "olvido", "paciencia", "resiliencia", "voluntad", "molestias", "magnífico", "distinción", "ovni", "marejada", "cerro", "torre", "y", "abogada", "manantial", "corporal", "agua", "crepúsculo", "ataque", "desierto", "laboriosamente", "angustia", "afortunado", "alma", "encefalograma", "materialidad", "cosas", "o", "renuncia", "error", "menos", "conejo", "abadía", "analfabeto", "remo", "fugacidad", "oficio", "en", "almácigo", "vos", "pan", "represión", "números", "triste", "refugiado", "trote", "inventor", "corchea", "repelente", "magma", "recusado", "patrón", "explícito", "paloma", "síndrome", "inmune", "autoinmune", "comodidad", "ley", "vietnamita", "demonio", "tasmania", "repeler", "apéndice", "arquitecto", "columna", "yugo", "computador", "mula", "a", "propósito", "fantasía", "alias", "rayo", "tenedor", "deleznable", "ventana", "cara", "anemia", "corrupto"] }; const langs = { latin, ru, sp }; const lorem_es_defaultOptions = { wordCount: 30, skipCommon: false, lang: 'latin' }; /** * Replaces given parsed Emmet abbreviation node with nodes filled with * Lorem Ipsum stub text. * @param {Node} node * @return {Node} */ var lorem_es_index = function (node, options) { options = lorem_es__extends({}, lorem_es_defaultOptions, options); const dict = langs[options.lang] || langs.latin; const startWithCommon = !options.skipCommon && !isRepeating(node); if (!node.repeat && !lorem_es_isRoot(node.parent)) { // non-repeating element, insert text stub as a content of parent node // and remove current one node.parent.value = paragraph(dict, options.wordCount, startWithCommon); node.remove(); } else { // Replace named node with generated content node.value = paragraph(dict, options.wordCount, startWithCommon); node.name = node.parent.name ? implicit_tag_es(node.parent.name) : null; } return node; }; function lorem_es_isRoot(node) { return !node.parent; } /** * Returns random integer between 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 –
// Angular-style –
if (attr.name = eatAttributeName(stream)) { // Consumed attribute name. Can be an attribute with name // or boolean attribute. The value can be React-like expression if (stream.eat(html_matcher_es_EQUALS)) { attr.value = eatAttributeValue(stream); } else { attr.boolean = true; } attr.end = stream.pos; result.push(attr); } else if (isTerminator(stream.peek())) { // look for tag terminator in order to skip any other possible characters // (maybe junk) break; } else { stream.next(); } } return result; }; /** * Consumes attribute name from current location * @param {StreamReader} stream * @return {Token} */ function eatAttributeName(stream) { return eatPaired(stream) || html_matcher_es_token(stream, isAttributeName); } /** * Consumes attribute value from given location * @param {StreamReader} stream * @return {Token} */ function eatAttributeValue(stream) { const start = stream.pos; if (eatQuoted(stream)) { // Should return token that points to unquoted value. // Use stream readers’ public API to traverse instead of direct // manipulation const current = stream.pos; let valueStart, valueEnd; stream.pos = start; stream.next(); valueStart = stream.start = stream.pos; stream.pos = current; stream.backUp(1); valueEnd = stream.pos; const result = html_matcher_es_token(stream, valueStart, valueEnd); stream.pos = current; return result; } return eatPaired(stream) || html_matcher_es_eatUnquoted(stream); } /** * Check if given code belongs to attribute name. * NB some custom HTML variations allow non-default values in name, like `*ngFor` * @param {Number} code * @return {Boolean} */ function isAttributeName(code) { return code !== html_matcher_es_EQUALS && !isTerminator(code) && !isSpace(code); } /** * Check if given code is tag terminator * @param {Number} code * @return {Boolean} */ function isTerminator(code) { return code === RIGHT_ANGLE$1 || code === SLASH$1; } /** * Eats unquoted value from stream * @param {StreamReader} stream * @return {Token} */ function html_matcher_es_eatUnquoted(stream) { return html_matcher_es_token(stream, html_matcher_es_isUnquoted); } /** * Check if given character code is valid unquoted value * @param {Number} code * @return {Boolean} */ function html_matcher_es_isUnquoted(code) { return !isNaN(code) && !isQuote(code) && !isSpace(code) && !isTerminator(code); } const html_matcher_es_DASH = 45; // - const html_matcher_es_DOT = 46; // . const html_matcher_es_SLASH = 47; // / const html_matcher_es_COLON = 58; // : const LEFT_ANGLE = 60; // < const RIGHT_ANGLE = 62; // > const UNDERSCORE = 95; // _ /** * Parses tag definition (open or close tag) from given stream state * @param {StreamReader} stream Content stream reader * @return {Object} */ var tag = function (stream) { const start = stream.pos; if (stream.eat(LEFT_ANGLE)) { const model = { type: stream.eat(html_matcher_es_SLASH) ? 'close' : 'open' }; if (model.name = eatTagName(stream)) { if (model.type !== 'close') { model.attributes = eatAttributes(stream); stream.eatWhile(isSpace); model.selfClosing = stream.eat(html_matcher_es_SLASH); } if (stream.eat(RIGHT_ANGLE)) { // tag properly closed return html_matcher_es__extends(html_matcher_es_token(stream, start), model); } } } // invalid tag, revert to original position stream.pos = start; return null; }; /** * Eats HTML identifier (tag or attribute name) from given stream * @param {StreamReader} stream * @return {Token} */ function eatTagName(stream) { return html_matcher_es_token(stream, isTagName); } /** * Check if given character code can be used as HTML/XML tag name * @param {Number} code * @return {Boolean} */ function isTagName(code) { return isAlphaNumeric(code) || code === html_matcher_es_COLON // colon is used for namespaces || code === html_matcher_es_DOT // in rare cases declarative tag names may have dots in names || code === html_matcher_es_DASH || code === UNDERSCORE; } /** * Eats array of character codes from given stream * @param {StreamReader} stream * @param {Number[]} codes Array of character codes * @return {Boolean} */ function eatArray(stream, codes) { const start = stream.pos; for (let i = 0; i < codes.length; i++) { if (!stream.eat(codes[i])) { stream.pos = start; return false; } } stream.start = start; return true; } /** * Consumes section from given string which starts with `open` character codes * and ends with `close` character codes * @param {StreamReader} stream * @param {Number[]} open * @param {Number[]} close * @return {Boolean} Returns `true` if section was consumed */ function eatSection(stream, open, close, allowUnclosed) { const start = stream.pos; if (eatArray(stream, open)) { // consumed `'); /** * Consumes HTML comment from given stream * @param {StreamReader} stream * @return {Token} */ var comment = function (stream) { const start = stream.pos; if (eatSection(stream, html_matcher_es_open, html_matcher_es_close, true)) { const result = html_matcher_es_token(stream, start); result.type = 'comment'; return result; } return null; }; const open$1 = toCharCodes(''); /** * Consumes CDATA from given stream * @param {StreamReader} stream * @return {Token} */ var cdata = function (stream) { const start = stream.pos; if (eatSection(stream, open$1, close$1, true)) { const result = html_matcher_es_token(stream, start); result.type = 'cdata'; return result; } return null; }; const html_matcher_es_defaultOptions = { /** * Expect XML content in searching content. It alters how should-be-empty * elements are treated: for example, in XML mode parser will try to locate * closing pair for `
` tag * @type {Boolean} */ xml: false, special: ['script', 'style'], /** * List of elements that should be treated as empty (e.g. without closing tag) * in non-XML syntax * @type {Array} */ empty: ['img', 'meta', 'link', 'br', 'base', 'hr', 'area', 'wbr', 'col', 'embed', 'input', 'param', 'source', 'track'] }; /** * Parses given content into a DOM-like structure * @param {String|StreamReader} content * @param {Object} options * @return {Node} */ function html_matcher_es_parse(content, options) { options = html_matcher_es__extends({}, html_matcher_es_defaultOptions, options); const stream = typeof content === 'string' ? new stream_reader_es(content) : content; const root = new html_matcher_es_Node(stream, 'root'); const empty = new Set(options.empty); const special = options.special.reduce((map, name) => map.set(name, toCharCodes(``)), new Map()); const isEmpty = (token, name) => token.selfClosing || !options.xml && empty.has(name); let m, node, name, stack = [root]; while (!stream.eof()) { if (m = match(stream)) { name = getName(m); if (m.type === 'open') { // opening tag node = new html_matcher_es_Node(stream, 'tag', m); last(stack).addChild(node); if (special.has(name)) { node.close = consumeSpecial(stream, special.get(name)); } else if (!isEmpty(m, name)) { stack.push(node); } } else if (m.type === 'close') { // closing tag, find it’s matching opening tag for (let i = stack.length - 1; i > 0; i--) { if (stack[i].name.toLowerCase() === name) { stack[i].close = m; stack = stack.slice(0, i); break; } } } else { last(stack).addChild(new html_matcher_es_Node(stream, m.type, m)); } } else { stream.next(); } } return root; } /** * Matches known token in current state of given stream * @param {ContentStreamReader} stream * @return {Token} */ function match(stream) { // fast-path optimization: check for `<` code if (stream.peek() === 60 /* < */) { return comment(stream) || cdata(stream) || tag(stream); } } /** * @param {StreamReader} stream * @param {Number[]} codes * @return {Token} */ function consumeSpecial(stream, codes) { const start = stream.pos; let m; while (!stream.eof()) { if (eatArray(stream, codes)) { stream.pos = stream.start; return tag(stream); } stream.next(); } stream.pos = start; return null; } /** * Returns name of given matched token * @param {Token} tag * @return {String} */ function getName(tag$$1) { return tag$$1.name ? tag$$1.name.value.toLowerCase() : `#${tag$$1.type}`; } function last(arr) { return arr[arr.length - 1]; } /* harmony default export */ var html_matcher_es = (html_matcher_es_parse); // CONCATENATED MODULE: ../node_modules/@emmetio/codemirror-plugin/dist/emmet-codemirror-plugin.es.js var emmet_codemirror_plugin_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 editorField = (index, placeholder = '') => `\${${index}${placeholder ? ':' + placeholder : ''}}`; /** * Returns resolved Emmet config for `pos` location of given editor * @param {CodeMirror.Editor} editor * @param {CodeMirror.Position} [pos] Point in editor where syntax should be detected. * Uses `editor.getCursor()` if not given * @param {Object} [options] Additional options to override before config resolve * @return {Object} */ function createConfig(editor, pos, options) { pos = pos || editor.getCursor(); const syntax = getSyntax(editor, pos); /** @type {EmmetConfig} */ const config = config_es(emmet_codemirror_plugin_es__extends({ field: editorField }, editor.getOption('emmet'), options), { syntax }); const mode = editor.getModeAt(pos); if (syntax === 'jsx') { config.profile = emmet_codemirror_plugin_es__extends({ selfClosingStyle: 'xml' }, config.profile); config.options = emmet_codemirror_plugin_es__extends({ jsx: true }, config.options); } else if (mode.name === 'xml') { config.profile = emmet_codemirror_plugin_es__extends({ selfClosingStyle: mode.configuration }, config.profile); } return config; } /** * Detect Emmet syntax from given editor’s position. * @param {CodeMirror.Editor} editor * @param {CodeMirror.Position} [pos] * @return {String} Returns `null` if Emmet syntax can’t be detected */ function getSyntax(editor, pos) { const rootMode = editor.getMode(); if (rootMode.name === 'jsx' || rootMode.name === 'javascript') { return rootMode.name; } const mode = editor.getModeAt(pos); return mode.name === 'xml' ? 'html' : mode.name; } const LINE_END = 10; // \n /** * A stream reader for CodeMirror editor */ let CodeMirrorStreamReader = class CodeMirrorStreamReader extends stream_reader_es { /** * @param {CodeMirror.Editor} editor * @param {CodeMirror.Position} [pos] * @param {CodeMirror.Range} [limit] */ constructor(editor, pos, limit) { super(); const CodeMirror = editor.constructor; this.editor = editor; this.start = this.pos = pos || CodeMirror.Pos(0, 0); const lastLine = editor.lastLine(); this._eof = limit ? limit.to : CodeMirror.Pos(lastLine, this._lineLength(lastLine)); this._sof = limit ? limit.from : CodeMirror.Pos(0, 0); } /** * Returns true only if the stream is at the beginning of the file. * @returns {Boolean} */ sof() { return comparePos(this.pos, this._sof) <= 0; } /** * Returns true only if the stream is at the end of the file. * @returns {Boolean} */ eof() { return comparePos(this.pos, this._eof) >= 0; } /** * Creates a new stream instance which is limited to given `start` and `end` * points for underlying buffer * @param {CodeMirror.Pos} start * @param {CodeMirror.Pos} end * @return {CodeMirrorStreamReader} */ limit(from, to) { return new this.constructor(this.editor, from, { from, to }); } /** * Returns the next character code in the stream without advancing it. * Will return NaN at the end of the file. * @returns {Number} */ peek() { const { line, ch } = this.pos; const lineStr = this.editor.getLine(line); return ch < lineStr.length ? lineStr.charCodeAt(ch) : LINE_END; } /** * Returns the next character in the stream and advances it. * Also returns NaN when no more characters are available. * @returns {Number} */ next() { if (!this.eof()) { const code = this.peek(); this.pos = emmet_codemirror_plugin_es__extends({}, this.pos, { ch: this.pos.ch + 1 }); if (this.pos.ch >= this._lineLength(this.pos.line)) { this.pos.line++; this.pos.ch = 0; } if (this.eof()) { // handle edge case where position can move on next line // after EOF this.pos = emmet_codemirror_plugin_es__extends({}, this._eof); } return code; } return NaN; } /** * 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) { const CodeMirror = this.editor.constructor; let { line, ch } = this.pos; ch -= n || 1; while (line >= 0 && ch < 0) { line--; ch += this._lineLength(line); } this.pos = line < 0 || ch < 0 ? CodeMirror.Pos(0, 0) : CodeMirror.Pos(line, ch); return this.peek(); } /** * 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 contents for given range * @param {Point} from * @param {Point} to * @return {String} */ substring(from, to) { return this.editor.getRange(from, to); } /** * Creates error object with current stream state * @param {String} message * @return {Error} */ error(message) { const err = new Error(`${message} at line ${this.pos.line}, column ${this.pos.ch}`); err.originalMessage = message; err.pos = this.pos; err.string = this.string; return err; } /** * Returns length of given line, including line ending * @param {Number} line * @return {Number} */ _lineLength(line) { const isLast = line === this.editor.lastLine(); return this.editor.getLine(line).length + (isLast ? 0 : 1); } }; function comparePos(a, b) { return a.line - b.line || a.ch - b.ch; } /** * Returns token used for single indentation in given editor * @param {CodeMirror.Editor} editor * @return {String} */ function getIndentation(editor) { if (!editor.getOption('indentWithTabs')) { return repeatString(' ', editor.getOption('indentUnit')); } return '\t'; } /** * Normalizes text according to given CodeMirror instance indentation * preferences * @param {String} text * @param {CodeMirror.Editor} editor * @param {String} [indentation] Applies `indentText()` with given argument, if provided * @return {String} */ function normalizeText(editor, text, indentation) { let lines = emmet_codemirror_plugin_es_splitByLines(text); const indent = getIndentation(editor); if (indent !== '\t') { lines = lines.map(line => line.replace(/^\t+/, tabs => repeatString(indent, tabs.length))); } if (indentation) { lines = lines.map((line, i) => i ? indentation + line : line); } return lines.join('\n'); } /** * Splits given text by lines * @param {String} text * @return {String[]} Lines of text */ function emmet_codemirror_plugin_es_splitByLines(text) { return Array.isArray(text) ? text : text.split(/\r\n|\r|\n/g); } function repeatString(str, count) { let result = ''; while (0 < count--) { result += str; } return result; } /** * Quick and dirty way to remove fields from given string * @param {String} str * @return {String} */ function removeFields(str) { return field_parser_es(str).string; } /** * Check if given range contains point * @param {CodeMirror.Range} range * @param {CodeMirror.Position} pos * @param {Boolean} [exclude] Exclude range and and start * @return {Boolean} */ function containsPos(range, pos, exclude) { return exclude ? comparePos$1(pos, range.from) > 0 && comparePos$1(pos, range.to) < 0 : comparePos$1(pos, range.from) >= 0 && comparePos$1(pos, range.to) <= 0; } function comparePos$1(a, b) { return a.line - b.line || a.ch - b.ch; } function rangeFromNode(node) { return { from: node.start, to: node.end }; } /** * Narrows given `{from, to}` range to first non-whitespace characters in given * editor content * @param {CodeMirror.Editor} editor * @param {CodeMirror.Position} from * @param {CodeMirror.Position} [to] * @returns {Object} */ function narrowToNonSpace(editor, from, to) { const stream = new CodeMirrorStreamReader(editor, from); stream.eatWhile(isSpace); from = stream.pos; if (to) { stream.pos = to; stream.backUp(); while (!stream.sof() && isSpace(stream.peek())) { stream.backUp(); } stream.next(); to = stream.pos; } else { to = from; } return { from, to }; } /** * Returns nearest CSS property name, left to given position * @param {CodeMirror.Editor} editor * @param {CodeMirror.Position} pos * @returns {String} */ function getCSSPropertyName(editor, pos) { const line = pos.line; let ch = pos.ch, token; while (ch >= 0) { token = editor.getTokenAt({ line, ch }); if (token.type === 'property') { return token.string; } if (token.start !== ch) { ch = token.start; } else { break; } } } /** * Check if given position is inside CSS property value * @param {CodeMirror.Editor} editor * @param {CodeMirror.Position} pos * @return {Boolean} */ function isCSSPropertyValue(editor, pos) { const mode = editor.getModeAt(pos); if (mode && mode.name === 'css') { const token = editor.getTokenAt(pos); const state = token.state && token.state.localState || token.state; return state && state.context && state.context.type === 'prop'; } return false; } /** * Context-aware abbreviation extraction from given editor. * Detects syntax context in `pos` editor location and, if it allows Emmet * abbreviation to be extracted here, returns object with extracted abbreviation, * its location and config. * @param {CodeMirror.Editor} editor * @param {CodeMirror.Position} pos */ function emmet_codemirror_plugin_es_extractAbbreviation(editor, pos, contextAware) { const config = createConfig(editor, pos); if (contextAware && !canExtract(editor, pos, config)) { return null; } const extracted = extract_abbreviation_es(editor.getLine(pos.line), pos.ch, { lookAhead: true, syntax: config.type, prefix: config.syntax === 'jsx' && editor.getOption('jsxBracket') ? '<' : '' }); if (extracted) { const from = { line: pos.line, ch: extracted.start }; const to = { line: pos.line, ch: extracted.end }; if (config.type === 'stylesheet' && contextAware) { // In case of stylesheet syntaxes (CSS, LESS) we should narrow down // expand context to property value, if possible if (isCSSPropertyValue(editor, pos)) { config.options = emmet_codemirror_plugin_es__extends({ property: getCSSPropertyName(editor, pos) }, config.options); } } return { abbreviation: extracted.abbreviation, range: { from, to }, config }; } } /** * Check if abbreviation can be extracted from given position * @param {CodeMirror.Editor} editor * @param {CodeMirror.Position} pos * @param {Object} config * @return {Boolean} */ function canExtract(editor, pos, config) { const tokenType = editor.getTokenTypeAt(pos); if (config.type === 'stylesheet') { return tokenType !== 'comment' && tokenType !== 'string'; } if (config.syntax === 'html') { return tokenType === null; } if (config.syntax === 'slim' || config.syntax === 'pug') { return tokenType === null || tokenType === 'tag' || tokenType && /attribute/.test(tokenType); } if (config.syntax === 'haml') { return tokenType === null || tokenType === 'attribute'; } if (config.syntax === 'jsx') { // JSX a bit tricky, delegate it to caller return true; } return false; } /** * Replaces `range` in `editor` with `text` snippet. A snippet is a string containing * tabstops/fields like `${index:placeholder}`: this function will locate such * fields and place cursor at first one. * Inserted snippet will be automatically matched with current editor indentation * @param {CodeMirror.Editor} editor * @param {CodeMirror.Range} range * @param {String} text */ function insertSnippet(editor, range, text) { const line = editor.getLine(range.from.line); const matchIndent = line.match(/^\s+/); let snippet = normalizeText(editor, text, matchIndent && matchIndent[0]); const fieldModel = field_parser_es(snippet); return editor.operation(() => { editor.replaceRange(fieldModel.string, range.from, range.to); // Position cursor const startIx = editor.indexFromPos(range.from); if (fieldModel.fields.length) { const field = fieldModel.fields[0]; const from = editor.posFromIndex(field.location + startIx); const to = editor.posFromIndex(field.location + field.length + startIx); editor.setSelection(from, to); } else { editor.setCursor(editor.posFromIndex(startIx + fieldModel.string.length)); } return true; }); } const emmetMarkerClass = 'emmet-abbreviation'; /** * Returns parsed abbreviation from given position in `editor`, if possible. * @param {CodeMirror.Editor} editor * @param {CodeMirror.Position} pos * @param {Boolean} [contextAware] Use context-aware abbreviation detection * @returns {Abbreviation} */ function abbreviationFromPosition(editor, pos, contextAware) { // Try to find abbreviation marker from given position const marker = findMarker(editor, pos); if (marker && marker.model) { return marker.model; } // Try to extract abbreviation from given position const extracted = emmet_codemirror_plugin_es_extractAbbreviation(editor, pos, contextAware); if (extracted) { try { const abbr = new emmet_codemirror_plugin_es_Abbreviation(extracted.abbreviation, extracted.range, extracted.config); return abbr.valid(editor, contextAware) ? abbr : null; } catch (err) { // skip // console.warn(err); } } } /** * Returns *valid* Emmet abbreviation marker (if any) for given position of editor * @param {CodeMirror.Editor} editor * @param {CodeMirror.Position} [pos] * @return {CodeMirror.TextMarker} */ function findMarker(editor, pos) { const markers = editor.findMarksAt(pos); for (let i = 0, marker; i < markers.length; i++) { marker = markers[i]; if (marker.className === emmetMarkerClass) { if (isValidMarker(editor, marker)) { return marker; } marker.clear(); } } } /** * Removes Emmet abbreviation markers from given editor * @param {CodeMirror.Editor} editor */ function clearMarkers(editor) { const markers = editor.getAllMarks(); for (let i = 0; i < markers.length; i++) { if (markers[i].className === emmetMarkerClass) { markers[i].clear(); } } } /** * Marks Emmet abbreviation for given editor position, if possible * @param {CodeMirror.Editor} editor Editor where abbreviation marker should be created * @param {Abbreviation} model Parsed abbreviation model * @return {CodeMirror.TextMarker} Returns `undefined` if no valid abbreviation under caret */ function createMarker(editor, model) { const { from, to } = model.range; const marker = editor.markText(from, to, { inclusiveLeft: true, inclusiveRight: true, clearWhenEmpty: true, className: emmetMarkerClass }); marker.model = model; return marker; } /** * Ensures that given editor Emmet abbreviation marker contains valid Emmet abbreviation * and updates abbreviation model if required * @param {CodeMirror} editor * @param {CodeMirror.TextMarket} marker * @return {Boolean} `true` if marker contains valid abbreviation */ function isValidMarker(editor, marker) { const range = marker.find(); // No newlines inside abbreviation if (range.from.line !== range.to.line) { return false; } // Make sure marker contains valid abbreviation let text = editor.getRange(range.from, range.to); if (!text || /^\s|\s$/g.test(text)) { return false; } if (marker.model && marker.model.config.syntax === 'jsx' && text[0] === '<') { text = text.slice(1); } if (!marker.model || marker.model.abbreviation !== text) { // marker contents was updated, re-parse abbreviation try { marker.model = new emmet_codemirror_plugin_es_Abbreviation(text, range, marker.model.config); if (!marker.model.valid(editor, true)) { marker.model = null; } } catch (err) { console.warn(err); marker.model = null; } } return Boolean(marker.model && marker.model.snippet); } let emmet_codemirror_plugin_es_Abbreviation = class Abbreviation { /** * @param {String} abbreviation Abbreviation string * @param {CodeMirror.Range} range Abbreviation location in editor * @param {Object} [config] */ constructor(abbreviation, range, config) { this.abbreviation = abbreviation; this.range = range; this.config = config; this.ast = parse$2(abbreviation, config); this.snippet = expand$2(this.ast, config); this.preview = removeFields(this.snippet); } /** * Inserts current expanded abbreviation into given `editor` by replacing * `range` * @param {CodeMirror.Editor} editor * @param {CodeMirror.Range} [range] */ insert(editor, range) { return insertSnippet(editor, range || this.range, this.snippet); } /** * Check if parsed abbreviation is valid * @param {Boolean} [contextAware] Perform context-aware validation: ensure * that expanded result is expected at abbreviation location */ valid(editor, contextAware) { if (this.preview && this.abbreviation !== this.preview) { return contextAware && this.config.type === 'stylesheet' ? this._isValidForStylesheet(editor) : true; } return false; } _isValidForStylesheet(editor) { const pos = this.range.from; const token = editor.getTokenAt(pos); if (/^[#!]/.test(this.abbreviation)) { // Abbreviation is a property value return isCSSPropertyValue(editor, pos); } // All expanded nodes are properties? Properties has names, regular snippets don’t. const isProperty = this.ast.children.every(node => node.name); const state = token.state && token.state.localState || token.state; if (isProperty) { // Expanded abbreviation consists of properties: make sure we’re inside // block context // NB: in Sass, no actual block context since it’s indetation-based return this.config.syntax === 'sass' || state && state.context && state.context.type === 'block'; } // Expanded abbreviations are basic snippets: allow them everywhere, but forbid // if expanded result equals abbreviation (meaningless). return true; } }; /** * Expand abbreviation command * @param {CodeMirror.Editor} editor * @param {Boolean} contextAware */ function expandAbbreviation(editor, contextAware) { if (editor.somethingSelected()) { return editor.constructor.Pass; } const abbr = abbreviationFromPosition(editor, editor.getCursor(), contextAware); if (abbr) { abbr.insert(editor); clearMarkers(editor); return true; } // If no abbreviation was expanded, allow editor to handle different // action for keyboard shortcut (Tab key mostly) return editor.constructor.Pass; } function emmetInsertLineBreak(editor) { const between = editor.listSelections().map(sel => betweenTags(editor, sel)); if (!between.some(Boolean)) { return editor.constructor.Pass; } editor.operation(() => { let sels = editor.listSelections(); const singleSep = editor.doc.lineSeparator(); const doubleSep = singleSep + singleSep; // Step 1: insert newlines either single or double depending on selection for (let i = sels.length - 1; i >= 0; i--) { editor.replaceRange(between[i] ? doubleSep : singleSep, sels[i].anchor, sels[i].head, '+newline'); } // Step 2: indent inserted lines sels = editor.listSelections(); for (let i = 0; i < sels.length; i++) { editor.indentLine(sels[i].from().line, null, true); if (between[i]) { editor.indentLine(sels[i].from().line - 1, null, true); } } // Step 3: adjust caret positions editor.setSelections(editor.listSelections().map((sel, i) => { if (between[i]) { const line = sel.from().line - 1; const cursor = { line, ch: editor.getLine(line).length }; return { anchor: cursor, head: cursor }; } return sel; })); }); } /** * Check if given range is a single caret between tags * @param {CodeMirror} editor * @param {CodeMirror.range} range */ function betweenTags(editor, range) { if (equalCursorPos(range.anchor, range.head)) { const cursor = range.anchor; const mode = editor.getModeAt(cursor); if (mode.name === 'xml') { const left = editor.getTokenAt(cursor); const right = editor.getTokenAt(emmet_codemirror_plugin_es__extends({}, cursor, { ch: cursor.ch + 1 })); return left.type === 'tag bracket' && left.string === '>' && right.type === 'tag bracket' && right.string === ' line.trim()); prompt(editor, 'Enter abbreviation to wrap with:', abbr => { if (abbr) { const model = new emmet_codemirror_plugin_es_Abbreviation(abbr, range, createConfig(editor, range.from, { text })); model.insert(editor); } }); } else { console.warn('Nothing to wrap'); } } /** * Returns content range that should be wrapped * @param {CodeMirror} editor */ function getWrappingContentRange(editor) { if (editor.somethingSelected()) { const sel = editor.listSelections().filter(sel => sel.anchor !== sel.head)[0]; if (sel) { return comparePos$1(sel.anchor, sel.head) < 0 ? { from: sel.anchor, to: sel.head } : { from: sel.head, to: sel.anchor }; } } // Nothing selected, find parent HTML node and return range for its content return getTagRangeForPos(editor, editor.getCursor()); } /** * Returns either inner or outer tag range (depending on `pos` location) * for given position * @param {CodeMirror} editor * @param {Object} pos * @return {Object} */ function getTagRangeForPos(editor, pos) { const model = editor.getEmmetDocumentModel(); const tag = model && model.nodeForPoint(pos); if (!tag) { return null; } // Depending on given position, return either outer or inner tag range if (inRange(tag.open, pos) || inRange(tag.close, pos)) { // Outer range return rangeFromNode(tag); } // Inner range const from = tag.open.end; const to = tag.close ? tag.close.start : tag.open.end; return narrowToNonSpace(editor, from, to); } function inRange(tag, pos) { return tag && containsPos(rangeFromNode(tag), pos); } function defaultPrompt(editor, message, callback) { callback(window.prompt(message)); } /** * Marks Emmet abbreviation for given editor position, if possible * @param {CodeMirror.Editor} editor Editor where abbreviation marker should be created * @param {CodeMirror.Position} pos Editor position where abbreviation marker * should be created. Abbreviation will be automatically extracted from given position * @return {CodeMirror.TextMarker} Returns `undefined` if no valid abbreviation under caret */ function markAbbreviation(editor, pos) { const marker = findMarker(editor, pos); if (marker) { // there’s active marker with valid abbreviation return marker; } // No active marker: remove previous markers and create new one, if possible clearMarkers(editor); const model = abbreviationFromPosition(editor, pos, true); if (model) { return createMarker(editor, model); } } /** * Returns available completions from given editor * @param {CodeMirror.Editor} editor * @param {Abbreviation} abbrModel Parsed Emmet abbreviation model for which * completions should be populated * @param {CodeMirror.Position} abbrPos Abbreviation location in editor * @param {CodeMirror.Position} [pos] Cursor position in editor * @return {EmmetCompletion[]} */ function autocompleteProvider(editor, pos) { pos = pos || editor.getCursor(); let completions = []; // Provide two types of completions: // 1. Expanded abbreviation // 2. Snippets const abbreviation = abbreviationFromPosition(editor, pos, true); // NB: Check for edge case: expanded abbreviation equals to original // abbreviation (for example, `li.item` expands to `li.item` in Slim), // no need to provide completion for this case if (abbreviation && abbreviation.abbreviation !== abbreviation.snippet) { completions.push(expandedAbbreviationCompletion(editor, pos, abbreviation)); } const config = abbreviation ? abbreviation.config : createConfig(editor, pos); if (config.type === 'stylesheet') { completions = completions.concat(getStylesheetCompletions(editor, pos, config)); } else { completions = completions.concat(getMarkupCompletions(editor, pos, config)); } return { type: config.type, syntax: config.syntax, abbreviation, completions: completions.filter(Boolean) }; } /** * Returns completions for markup syntaxes (HTML, Slim, Pug etc.) * @param {CodeMirror} editor * @param {CodeMirror.Position} pos Cursor position in editor * @param {Object} config Resolved Emmet config * @return {EmmetCompletion[]} */ function getMarkupCompletions(editor, pos, config) { const line = editor.getLine(pos.line).slice(0, pos.ch); const prefix = extractPrefix(line, /[\w:\-$@]/); // Make sure that current position precedes element name (e.g. not attribute, // class, id etc.) if (prefix) { const prefixRange = { from: { line: pos.line, ch: pos.ch - prefix.length }, to: pos }; return getSnippetCompletions(editor, pos, config).filter(completion => completion.key !== prefix && completion.key.indexOf(prefix) === 0).map(completion => new EmmetCompletion('snippet', editor, prefixRange, completion.key, completion.preview, completion.snippet)); } return []; } /** * Returns completions for stylesheet syntaxes * @param {CodeMirror} editor * @param {CodeMirror.Position} pos Cursor position in editor * @param {Object} config Resolved Emmet config * @return {EmmetCompletion[]} */ function getStylesheetCompletions(editor, pos, config) { const line = editor.getLine(pos.line).slice(0, pos.ch); const prefix = extractPrefix(line, /[\w-@$]/); if (prefix) { // Make sure that current position precedes element name (e.g. not attribute, // class, id etc.) const prefixRange = { from: { line: pos.line, ch: pos.ch - prefix.length }, to: pos }; if (config.options && config.options.property) { const lowerProp = config.options.property.toLowerCase(); // Find matching CSS property snippet for keyword completions const completion = getSnippetCompletions(editor, pos, config).find(item => item.property && item.property === lowerProp); if (completion && completion.keywords.length) { return completion.keywords.map(kw => { return kw.key.indexOf(prefix) === 0 && new EmmetCompletion('value', editor, prefixRange, kw.key, kw.preview, kw.snippet); }).filter(Boolean); } } else { return getSnippetCompletions(editor, pos, config).filter(completion => completion.key !== prefix && completion.key.indexOf(prefix) === 0).map(completion => new EmmetCompletion('snippet', editor, prefixRange, completion.key, completion.preview, completion.snippet)); } } return []; } /** * Returns all possible snippets completions for given editor context. * Completions are cached in editor for for re-use * @param {CodeMirror.Editor} editor * @param {CodeMirror.Position} pos * @param {Object} config * @return {Array} */ function getSnippetCompletions(editor, pos, config) { const { type, syntax } = config; if (!editor.state.emmetCompletions) { editor.state.emmetCompletions = {}; } const cache = editor.state.emmetCompletions; if (!(syntax in cache)) { const registry = createSnippetsRegistry(type, syntax, config.snippets); cache[syntax] = type === 'stylesheet' ? getStylesheetSnippets(registry, config) : getMarkupSnippets(registry, config); } return cache[syntax]; } /** * Returns stylesheet snippets list * @param {SnippetsRegistry} registry * @return {Array} */ function getStylesheetSnippets(registry) { return css_snippets_resolver_es_convertToCSSSnippets(registry).map(snippet => { let preview = snippet.property; const keywords = snippet.keywords(); if (keywords.length) { preview += `: ${removeFields(keywords.join(' | '))}`; } else if (snippet.value) { preview += `: ${removeFields(snippet.value)}`; } return { key: snippet.key, value: snippet.value, snippet: snippet.key, property: snippet.property, keywords: keywords.map(kw => { const m = kw.match(/^[\w-]+/); return m && { key: m[0], preview: removeFields(kw), snippet: kw }; }).filter(Boolean), preview }; }); } /** * Returns markup snippets list * @param {SnippetsRegistry} registry * @param {Object} config * @return {Array} */ function getMarkupSnippets(registry, config) { return registry.all({ type: 'string' }).map(snippet => ({ key: snippet.key, value: snippet.value, preview: removeFields(expand$2(snippet.value, config)), snippet: snippet.key })); } function expandedAbbreviationCompletion(editor, pos, abbrModel) { let preview = abbrModel.preview; if (preview.length > 500) { preview = preview.slice(0, 500) + '...'; } return new EmmetCompletion('expanded-abbreviation', editor, abbrModel.range, 'Expand abbreviation', preview, (editor, range) => abbrModel.insert(editor, range)); } /** * Extracts prefix from the end of given string that matches `match` regexp * @param {String} str * @param {RegExp} match * @return {String} Extracted prefix */ function extractPrefix(str, match) { let offset = str.length; while (offset > 0) { if (!match.test(str[offset - 1])) { break; } offset--; } return str.slice(offset); } let EmmetCompletion = class EmmetCompletion { /** * @param {String} type * @param {CodeMirror.Editor} editor * @param {CodeMirror.Range} range * @param {String} name * @param {String} preview * @param {Function} snippet */ constructor(type, editor, range, name, preview, snippet) { this.type = type; this.editor = editor; this.range = range; this.name = name; this.preview = preview; this.snippet = snippet; this._inserted = false; } insert() { if (!this._inserted) { this._inserted = true; if (typeof this.snippet === 'function') { this.snippet(this.editor, this.range); } else { insertSnippet(this.editor, this.range, this.snippet); } clearMarkers(this.editor); } } }; /** * A syntax-specific model container, used to get unified access to underlying * parsed document */ let SyntaxModel = class SyntaxModel { /** * @param {Object} dom Parsed document tree * @param {String} type Type of document (html, stylesheet, etc.) * @param {String} [syntax] Optional document syntax like html, xhtml or xml */ constructor(dom, type, syntax) { this.dom = dom; this.type = type; this.syntax = syntax; } /** * Returns best matching node for given point * @param {CodeMirror.Pos} pos * @param {Boolean} [exclude] Exclude node’s start and end positions from * search * @return {Node} */ nodeForPoint(pos, exclude) { let ctx = this.dom.firstChild; let found = null; while (ctx) { if (containsPos(rangeFromNode(ctx), pos, exclude)) { // Found matching tag. Try to find deeper, more accurate match found = ctx; ctx = ctx.firstChild; } else { ctx = ctx.nextSibling; } } return found; } }; /** * Creates DOM-like model for given text editor * @param {CodeMirror} editor * @param {String} syntax * @return {Node} */ function create(editor, syntax) { const stream = new CodeMirrorStreamReader(editor); const xml = syntax === 'xml'; try { return new SyntaxModel(html_matcher_es(stream, { xml }), 'html', syntax || 'html'); } catch (err) { console.warn(err); } } function getModel(editor) { const syntax = getSyntax$1(editor); return create(editor, syntax); } function getCachedModel(editor) { if (!editor.state._emmetModel) { editor.state._emmetModel = getModel(editor); } return editor.state._emmetModel; } function resetCachedModel(editor) { editor.state._emmetModel = null; } /** * Returns parser-supported syntax of given editor (like 'html', 'css' etc.). * Returns `null` if editor’s syntax is unsupported * @param {CodeMirror} editor * @return {String} */ function getSyntax$1(editor) { const mode = editor.getMode(); if (mode.name === 'htmlmixed') { return 'html'; } return mode.name === 'xml' ? mode.configuration : mode.name; } const openTagMark = 'emmet-open-tag'; const closeTagMark = 'emmet-close-tag'; /** * Finds matching tag pair for given position in editor * @param {CodeMirror.Editor} editor * @param {CodeMirror.Position} pos * @return {Object} */ function matchTag(editor, pos) { pos = pos || editor.getCursor(); // First, check if there are tag markers in editor const marked = getMarkedTag(editor); // If marks found, validate them: make sure cursor is either in open // or close tag if (marked) { if (containsPos(marked.open.find(), pos)) { // Point is inside open tag, make sure if there’s a closing tag, // it matches open tag content if (!marked.close || emmet_codemirror_plugin_es_text(editor, marked.open) === emmet_codemirror_plugin_es_text(editor, marked.close)) { return marked; } } else if (marked.close) { // There’s a close tag, make sure pointer is inside it and it matches // open tag if (containsPos(marked.close.find(), pos) && emmet_codemirror_plugin_es_text(editor, marked.open) === emmet_codemirror_plugin_es_text(editor, marked.close)) { return marked; } } } // Markers are not valid anymore, remove them clearTagMatch(editor); // Find new tag pair from parsed HTML model and mark them const node = findTagPair(editor, pos); if (node && node.type === 'tag') { return { open: createTagMark(editor, node.open.name, openTagMark), close: node.close && createTagMark(editor, node.close.name, closeTagMark) }; } } function getMarkedTag(editor) { let open, close; editor.getAllMarks().forEach(mark => { if (mark.className === openTagMark) { open = mark; } else if (mark.className === closeTagMark) { close = mark; } }); return open ? { open, close } : null; } /** * Removes all matched tag pair markers from editor * @param {CodeMirror.Editor} editor */ function clearTagMatch(editor) { editor.getAllMarks().forEach(mark => { if (mark.className === openTagMark || mark.className === closeTagMark) { mark.clear(); } }); } /** * Finds tag pair (open and close, if any) form parsed HTML model of given editor * @param {CodeMirror.Editor} editor * @param {CodeMirror.Position} pos * @return {Object} */ function findTagPair(editor, pos) { const model = editor.getEmmetDocumentModel(); return model && model.nodeForPoint(pos || editor.getCursor()); } function createTagMark(editor, tag, className) { return editor.markText(tag.start, tag.end, { className, inclusiveLeft: true, inclusiveRight: true, clearWhenEmpty: false }); } function emmet_codemirror_plugin_es_text(editor, mark) { const range = mark.find(); return range ? editor.getRange(range.from, range.to) : ''; } function renameTag(editor, obj) { const tag = getMarkedTag(editor); const pos = obj.from; if (!tag) { return; } if (containsPos(tag.open.find(), pos) && tag.close) { // Update happened inside open tag, update close tag as well updateTag(editor, tag.open, tag.close); } else if (tag.close && containsPos(tag.close.find(), pos)) { // Update happened inside close tag, update open tag as well updateTag(editor, tag.close, tag.open); } } function updateTag(editor, source, dest) { const name = text$1(editor, source); const range = dest.find(); const m = name.match(/[\w:.-]+/); const newName = !name ? '' : m && m[0]; if (newName != null) { if (editor.getRange(range.from, range.to) !== newName) { editor.replaceRange(newName, range.from, range.to); } } else { // User entered something that wasn’t a valid tag name. clearTagMatch(editor); } } function text$1(editor, mark) { const range = mark.find(); return range ? editor.getRange(range.from, range.to) : ''; } /** * Registers Emmet extension on given CodeMirror constructor. * This file is designed to be imported somehow into the app (CommonJS, ES6, * Rollup/Webpack/whatever). If you simply want to add a