'use strict'; var acorn = require('acorn'); var cssTree = require('css-tree'); var tokenizer = require('css-tree/tokenizer'); var MagicString = require('magic-string'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var acorn__namespace = /*#__PURE__*/_interopNamespaceDefault(acorn); const now = typeof process !== 'undefined' && process.hrtime ? () => { const t = process.hrtime(); return t[0] * 1e3 + t[1] / 1e6; } : () => self.performance.now(); /** @param {any} timings */ function collapse_timings(timings) { const result = {}; timings.forEach( /** @param {any} timing */ (timing) => { result[timing.label] = Object.assign( { total: timing.end - timing.start }, timing.children && collapse_timings(timing.children) ); } ); return result; } class Stats { /** * @typedef {Object} Timing * @property {string} label * @property {number} start * @property {number} end * @property {Timing[]} children */ /** @type {number} */ /** @type {Timing} */ /** @type {Timing[]} */ /** @type {Timing[]} */ /** @type {Timing[]} */ constructor() { this.start_time = now(); this.stack = []; this.current_children = this.timings = []; } /** @param {any} label */ start(label) { const timing = { label, start: now(), end: null, children: [] }; this.current_children.push(timing); this.stack.push(timing); this.current_timing = timing; this.current_children = timing.children; } /** @param {any} label */ stop(label) { if (label !== this.current_timing.label) { throw new Error( `Mismatched timing labels (expected ${this.current_timing.label}, got ${label})` ); } this.current_timing.end = now(); this.stack.pop(); this.current_timing = this.stack[this.stack.length - 1]; this.current_children = this.current_timing ? this.current_timing.children : this.timings; } render() { const timings = Object.assign( { total: now() - this.start_time }, collapse_timings(this.timings) ); return { timings }; } } /** * @template T * @overload * @param {T[][]} nodes * @param {T[]} [target] * @returns {T[]} */ /** * @template T * @overload * @param {T[]} nodes * @param {T[]} [target] * @returns {T[]} */ /** * @param {any[]} nodes * @param {any[]} [target] * @returns {any[]} */ function flatten$1(nodes, target = []) { for (let i = 0; i < nodes.length; i += 1) { const node = nodes[i]; if (Array.isArray(node)) { flatten$1(node, target); } else { target.push(node); } } return target; } const regex_whitespace = /\s/; const regex_whitespaces = /\s+/; const regex_starts_with_whitespace = /^\s/; const regex_starts_with_whitespaces = /^[ \t\r\n]*/; const regex_ends_with_whitespace = /\s$/; const regex_ends_with_whitespaces = /[ \t\r\n]*$/; const regex_only_whitespaces = /^[ \t\n\r\f]+$/; const regex_whitespace_characters = /\s/g; const regex_non_whitespace_character = /\S/; const regex_starts_with_newline = /^\r?\n/; const regex_not_newline_characters = /[^\n]/g; const regex_double_quotes = /"/g; const regex_backslashes = /\\/g; const regex_starts_with_underscore = /^_/; const regex_ends_with_underscore = /_$/; const regex_dimensions = /^(?:offset|client)(?:Width|Height)$/; const regex_content_rect = /^(?:contentRect)$/; const regex_content_box_size = /^(?:contentBoxSize)$/; const regex_border_box_size = /^(?:borderBoxSize)$/; const regex_device_pixel_content_box_size = /^(?:devicePixelContentBoxSize)$/; const regex_box_size = /^(?:contentRect|contentBoxSize|borderBoxSize|devicePixelContentBoxSize)$/; const regex_svelte_ignore = /^\s*svelte-ignore\s+([\s\S]+)\s*$/m; /** * @param {string} text * @returns {string[]} */ function extract_svelte_ignore(text) { const match = regex_svelte_ignore.exec(text); return match ? match[1] .split(regex_whitespace) .map((x) => x.trim()) .filter(Boolean) : []; } /** * @param {import('estree').Node} node * @returns {string[]} */ function extract_svelte_ignore_from_comments(node) { return flatten$1( (node.leadingComments || []).map((comment) => extract_svelte_ignore(comment.value)) ); } /** * @param {number} position * @param {import('../interfaces.js').TemplateNode[]} template_nodes * @returns {string[]} */ function extract_ignores_above_position(position, template_nodes) { const previous_node_idx = template_nodes.findIndex((child) => child.end === position); if (previous_node_idx === -1) { return []; } for (let i = previous_node_idx; i >= 0; i--) { const node = template_nodes[i]; if (node.type !== 'Comment' && node.type !== 'Text') { return []; } if (node.type === 'Comment') { if (node.ignores.length) { return node.ignores; } } } return []; } /** * @param {import('../compile/nodes/interfaces.js').INode} node * @returns {string[]} */ function extract_ignores_above_node(node) { /** * This utilizes the fact that node has a prev and a next attribute * which means that it can find svelte-ignores along * the nodes on the same level as itself who share the same parent. */ let cur_node = node.prev; while (cur_node) { if (cur_node.type !== 'Comment' && cur_node.type !== 'Text') { return []; } if (cur_node.type === 'Comment' && cur_node.ignores.length) { return cur_node.ignores; } cur_node = cur_node.prev; } return []; } /** * @param {string} name * @param {string[]} names */ function fuzzymatch(name, names) { const set = new FuzzySet(names); const matches = set.get(name); return matches && matches[0] && matches[0][0] > 0.7 ? matches[0][1] : null; } // adapted from https://github.com/Glench/fuzzyset.js/blob/master/lib/fuzzyset.js // BSD Licensed const GRAM_SIZE_LOWER = 2; const GRAM_SIZE_UPPER = 3; // return an edit distance from 0 to 1 /** * @param {string} str1 * @param {string} str2 */ function _distance(str1, str2) { if (str1 === null && str2 === null) { throw 'Trying to compare two null values'; } if (str1 === null || str2 === null) return 0; str1 = String(str1); str2 = String(str2); const distance = levenshtein(str1, str2); if (str1.length > str2.length) { return 1 - distance / str1.length; } else { return 1 - distance / str2.length; } } // helper functions /** * @param {string} str1 * @param {string} str2 */ function levenshtein(str1, str2) { /** * @type {number[]} */ const current = []; let prev; let value; for (let i = 0; i <= str2.length; i++) { for (let j = 0; j <= str1.length; j++) { if (i && j) { if (str1.charAt(j - 1) === str2.charAt(i - 1)) { value = prev; } else { value = Math.min(current[j], current[j - 1], prev) + 1; } } else { value = i + j; } prev = current[j]; current[j] = value; } } return current.pop(); } const non_word_regex = /[^\w, ]+/; /** * @param {string} value * @param {any} gram_size */ function iterate_grams(value, gram_size = 2) { const simplified = '-' + value.toLowerCase().replace(non_word_regex, '') + '-'; const len_diff = gram_size - simplified.length; const results = []; if (len_diff > 0) { for (let i = 0; i < len_diff; ++i) { value += '-'; } } for (let i = 0; i < simplified.length - gram_size + 1; ++i) { results.push(simplified.slice(i, i + gram_size)); } return results; } /** * @param {string} value * @param {any} gram_size */ function gram_counter(value, gram_size = 2) { // return an object where key=gram, value=number of occurrences const result = {}; const grams = iterate_grams(value, gram_size); let i = 0; for (i; i < grams.length; ++i) { if (grams[i] in result) { result[grams[i]] += 1; } else { result[grams[i]] = 1; } } return result; } /** * @param {any} a * @param {any} b */ function sort_descending(a, b) { return b[0] - a[0]; } class FuzzySet { __init() {this.exact_set = {};} __init2() {this.match_dict = {};} __init3() {this.items = {};} /** * @param {string[]} arr */ constructor(arr) {FuzzySet.prototype.__init.call(this);FuzzySet.prototype.__init2.call(this);FuzzySet.prototype.__init3.call(this); // initialization for (let i = GRAM_SIZE_LOWER; i < GRAM_SIZE_UPPER + 1; ++i) { this.items[i] = []; } // add all the items to the set for (let i = 0; i < arr.length; ++i) { this.add(arr[i]); } } /** * @param {string} value */ add(value) { const normalized_value = value.toLowerCase(); if (normalized_value in this.exact_set) { return false; } let i = GRAM_SIZE_LOWER; for (i; i < GRAM_SIZE_UPPER + 1; ++i) { this._add(value, i); } } /** * @param {string} value * @param {number} gram_size */ _add(value, gram_size) { const normalized_value = value.toLowerCase(); const items = this.items[gram_size] || []; const index = items.length; items.push(0); const gram_counts = gram_counter(normalized_value, gram_size); let sum_of_square_gram_counts = 0; let gram; let gram_count; for (gram in gram_counts) { gram_count = gram_counts[gram]; sum_of_square_gram_counts += Math.pow(gram_count, 2); if (gram in this.match_dict) { this.match_dict[gram].push([index, gram_count]); } else { this.match_dict[gram] = [[index, gram_count]]; } } const vector_normal = Math.sqrt(sum_of_square_gram_counts); items[index] = [vector_normal, normalized_value]; this.items[gram_size] = items; this.exact_set[normalized_value] = value; } /** * @param {string} value */ get(value) { const normalized_value = value.toLowerCase(); const result = this.exact_set[normalized_value]; if (result) { return [[1, result]]; } let results = []; // start with high gram size and if there are no results, go to lower gram sizes for (let gram_size = GRAM_SIZE_UPPER; gram_size >= GRAM_SIZE_LOWER; --gram_size) { results = this.__get(value, gram_size); if (results) { return results; } } return null; } /** * @param {string} value * @param {number} gram_size */ __get(value, gram_size) { const normalized_value = value.toLowerCase(); const matches = {}; const gram_counts = gram_counter(normalized_value, gram_size); const items = this.items[gram_size]; let sum_of_square_gram_counts = 0; let gram; let gram_count; let i; let index; let other_gram_count; for (gram in gram_counts) { gram_count = gram_counts[gram]; sum_of_square_gram_counts += Math.pow(gram_count, 2); if (gram in this.match_dict) { for (i = 0; i < this.match_dict[gram].length; ++i) { index = this.match_dict[gram][i][0]; other_gram_count = this.match_dict[gram][i][1]; if (index in matches) { matches[index] += gram_count * other_gram_count; } else { matches[index] = gram_count * other_gram_count; } } } } const vector_normal = Math.sqrt(sum_of_square_gram_counts); let results = []; let match_score; // build a results list of [score, str] for (const match_index in matches) { match_score = matches[match_index]; results.push([match_score / (vector_normal * items[match_index][0]), items[match_index][1]]); } results.sort(sort_descending); let new_results = []; const end_index = Math.min(50, results.length); // truncate somewhat arbitrarily to 50 for (let i = 0; i < end_index; ++i) { new_results.push([_distance(results[i][1], normalized_value), results[i][1]]); } results = new_results; results.sort(sort_descending); new_results = []; for (let i = 0; i < results.length; ++i) { if (results[i][0] == results[0][0]) { new_results.push([results[i][0], this.exact_set[results[i][1]]]); } } return new_results; } } /** regex of all html void element names */ const void_element_names = /^(?:area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)$/; /** regex of all html element names. svg and math are omitted because they belong to the svg elements namespace */ const html_element_names = /^(?:a|abbr|address|area|article|aside|audio|b|base|bdi|bdo|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|data|datalist|dd|del|details|dfn|dialog|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|head|header|hr|html|i|iframe|img|input|ins|kbd|label|legend|li|link|main|map|mark|meta|meter|nav|noscript|object|ol|optgroup|option|output|p|param|picture|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|small|source|span|strong|style|sub|summary|sup|table|tbody|td|template|textarea|tfoot|th|thead|time|title|tr|track|u|ul|var|video|wbr)$/; /** regex of all svg element names */ const svg$1 = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|svg|switch|symbol|text|textPath|tref|tspan|unknown|use|view|vkern)$/; /** * @param {string} name * @returns {boolean} */ function is_void(name) { return void_element_names.test(name) || name.toLowerCase() === '!doctype'; } /** * @param {string} name * @returns {boolean} */ function is_html(name) { return html_element_names.test(name); } /** * @param {string} name * @returns {boolean} */ function is_svg(name) { return svg$1.test(name); } /** * @param {string[]} items * @param {string} [conjunction] */ function list(items, conjunction = 'or') { if (items.length === 1) return items[0]; return `${items.slice(0, -1).join(', ')} ${conjunction} ${items[items.length - 1]}`; } // All parser errors should be listed and accessed from here /** * @internal */ var parser_errors = { /** * @param {string} message */ css_syntax_error: (message) => ({ code: 'css-syntax-error', message }), duplicate_attribute: { code: 'duplicate-attribute', message: 'Attributes need to be unique' }, /** * @param {string} slug * @param {string} name */ duplicate_element: (slug, name) => ({ code: `duplicate-${slug}`, message: `A component can only have one <${name}> tag` }), duplicate_style: { code: 'duplicate-style', message: 'You can only have one top-level