UNPKG

css-format-monaco

Version:

css/less/scss format plugin for monaco-editor

1,327 lines (1,137 loc) 40.2 kB
/*jshint node:true */ function Options(options, merge_child_field) { this.raw_options = _mergeOpts(options, merge_child_field); // Support passing the source text back with no change this.disabled = this._get_boolean('disabled'); this.eol = this._get_characters('eol', 'auto'); this.end_with_newline = this._get_boolean('end_with_newline'); this.indent_size = this._get_number('indent_size', 4); this.indent_char = this._get_characters('indent_char', ' '); this.indent_level = this._get_number('indent_level'); this.preserve_newlines = this._get_boolean('preserve_newlines', true); this.max_preserve_newlines = this._get_number('max_preserve_newlines', 32786); if (!this.preserve_newlines) { this.max_preserve_newlines = 0; } this.indent_with_tabs = this._get_boolean('indent_with_tabs', this.indent_char === '\t'); if (this.indent_with_tabs) { this.indent_char = '\t'; // indent_size behavior changed after 1.8.6 // It used to be that indent_size would be // set to 1 for indent_with_tabs. That is no longer needed and // actually doesn't make sense - why not use spaces? Further, // that might produce unexpected behavior - tabs being used // for single-column alignment. So, when indent_with_tabs is true // and indent_size is 1, reset indent_size to 4. if (this.indent_size === 1) { this.indent_size = 4; } } // Backwards compat with 1.3.x this.wrap_line_length = this._get_number('wrap_line_length', this._get_number('max_char')); this.indent_empty_lines = this._get_boolean('indent_empty_lines'); // valid templating languages ['django', 'erb', 'handlebars', 'php', 'smarty'] // For now, 'auto' = all off for javascript, all on for html (and inline javascript). // other values ignored this.templating = this._get_selection_list('templating', ['auto', 'none', 'django', 'erb', 'handlebars', 'php', 'smarty'], ['auto']); } Options.prototype._get_array = function(name, default_value) { var option_value = this.raw_options[name]; var result = default_value || []; if (typeof option_value === 'object') { if (option_value !== null && typeof option_value.concat === 'function') { result = option_value.concat(); } } else if (typeof option_value === 'string') { result = option_value.split(/[^a-zA-Z0-9_\/\-]+/); } return result; }; Options.prototype._get_boolean = function(name, default_value) { var option_value = this.raw_options[name]; var result = option_value === undefined ? !!default_value : !!option_value; return result; }; Options.prototype._get_characters = function(name, default_value) { var option_value = this.raw_options[name]; var result = default_value || ''; if (typeof option_value === 'string') { result = option_value.replace(/\\r/, '\r').replace(/\\n/, '\n').replace(/\\t/, '\t'); } return result; }; Options.prototype._get_number = function(name, default_value) { var option_value = this.raw_options[name]; default_value = parseInt(default_value, 10); if (isNaN(default_value)) { default_value = 0; } var result = parseInt(option_value, 10); if (isNaN(result)) { result = default_value; } return result; }; Options.prototype._get_selection = function(name, selection_list, default_value) { var result = this._get_selection_list(name, selection_list, default_value); if (result.length !== 1) { throw new Error( "Invalid Option Value: The option '" + name + "' can only be one of the following values:\n" + selection_list + "\nYou passed in: '" + this.raw_options[name] + "'"); } return result[0]; }; Options.prototype._get_selection_list = function(name, selection_list, default_value) { if (!selection_list || selection_list.length === 0) { throw new Error("Selection list cannot be empty."); } default_value = default_value || [selection_list[0]]; if (!this._is_valid_selection(default_value, selection_list)) { throw new Error("Invalid Default Value!"); } var result = this._get_array(name, default_value); if (!this._is_valid_selection(result, selection_list)) { throw new Error( "Invalid Option Value: The option '" + name + "' can contain only the following values:\n" + selection_list + "\nYou passed in: '" + this.raw_options[name] + "'"); } return result; }; Options.prototype._is_valid_selection = function(result, selection_list) { return result.length && selection_list.length && !result.some(function(item) { return selection_list.indexOf(item) === -1; }); }; // merges child options up with the parent options object // Example: obj = {a: 1, b: {a: 2}} // mergeOpts(obj, 'b') // // Returns: {a: 2} function _mergeOpts(allOptions, childFieldName) { var finalOpts = {}; allOptions = _normalizeOpts(allOptions); var name; for (name in allOptions) { if (name !== childFieldName) { finalOpts[name] = allOptions[name]; } } //merge in the per type settings for the childFieldName if (childFieldName && allOptions[childFieldName]) { for (name in allOptions[childFieldName]) { finalOpts[name] = allOptions[childFieldName][name]; } } return finalOpts; } function _normalizeOpts(options) { var convertedOpts = {}; var key; for (key in options) { var newKey = key.replace(/-/g, "_"); convertedOpts[newKey] = options[key]; } return convertedOpts; } var Options_1 = Options; var normalizeOpts = _normalizeOpts; var mergeOpts = _mergeOpts; var options = { Options: Options_1, normalizeOpts: normalizeOpts, mergeOpts: mergeOpts }; /*jshint node:true */ var BaseOptions = options.Options; function Options$1(options) { BaseOptions.call(this, options, 'css'); this.selector_separator_newline = this._get_boolean('selector_separator_newline', true); this.newline_between_rules = this._get_boolean('newline_between_rules', true); var space_around_selector_separator = this._get_boolean('space_around_selector_separator'); this.space_around_combinator = this._get_boolean('space_around_combinator') || space_around_selector_separator; var brace_style_split = this._get_selection_list('brace_style', ['collapse', 'expand', 'end-expand', 'none', 'preserve-inline']); this.brace_style = 'collapse'; for (var bs = 0; bs < brace_style_split.length; bs++) { if (brace_style_split[bs] !== 'expand') { // default to collapse, as only collapse|expand is implemented for now this.brace_style = 'collapse'; } else { this.brace_style = brace_style_split[bs]; } } } Options$1.prototype = new BaseOptions(); var Options_1$1 = Options$1; var options$1 = { Options: Options_1$1 }; /*jshint node:true */ function OutputLine(parent) { this.__parent = parent; this.__character_count = 0; // use indent_count as a marker for this.__lines that have preserved indentation this.__indent_count = -1; this.__alignment_count = 0; this.__wrap_point_index = 0; this.__wrap_point_character_count = 0; this.__wrap_point_indent_count = -1; this.__wrap_point_alignment_count = 0; this.__items = []; } OutputLine.prototype.clone_empty = function() { var line = new OutputLine(this.__parent); line.set_indent(this.__indent_count, this.__alignment_count); return line; }; OutputLine.prototype.item = function(index) { if (index < 0) { return this.__items[this.__items.length + index]; } else { return this.__items[index]; } }; OutputLine.prototype.has_match = function(pattern) { for (var lastCheckedOutput = this.__items.length - 1; lastCheckedOutput >= 0; lastCheckedOutput--) { if (this.__items[lastCheckedOutput].match(pattern)) { return true; } } return false; }; OutputLine.prototype.set_indent = function(indent, alignment) { if (this.is_empty()) { this.__indent_count = indent || 0; this.__alignment_count = alignment || 0; this.__character_count = this.__parent.get_indent_size(this.__indent_count, this.__alignment_count); } }; OutputLine.prototype._set_wrap_point = function() { if (this.__parent.wrap_line_length) { this.__wrap_point_index = this.__items.length; this.__wrap_point_character_count = this.__character_count; this.__wrap_point_indent_count = this.__parent.next_line.__indent_count; this.__wrap_point_alignment_count = this.__parent.next_line.__alignment_count; } }; OutputLine.prototype._should_wrap = function() { return this.__wrap_point_index && this.__character_count > this.__parent.wrap_line_length && this.__wrap_point_character_count > this.__parent.next_line.__character_count; }; OutputLine.prototype._allow_wrap = function() { if (this._should_wrap()) { this.__parent.add_new_line(); var next = this.__parent.current_line; next.set_indent(this.__wrap_point_indent_count, this.__wrap_point_alignment_count); next.__items = this.__items.slice(this.__wrap_point_index); this.__items = this.__items.slice(0, this.__wrap_point_index); next.__character_count += this.__character_count - this.__wrap_point_character_count; this.__character_count = this.__wrap_point_character_count; if (next.__items[0] === " ") { next.__items.splice(0, 1); next.__character_count -= 1; } return true; } return false; }; OutputLine.prototype.is_empty = function() { return this.__items.length === 0; }; OutputLine.prototype.last = function() { if (!this.is_empty()) { return this.__items[this.__items.length - 1]; } else { return null; } }; OutputLine.prototype.push = function(item) { this.__items.push(item); var last_newline_index = item.lastIndexOf('\n'); if (last_newline_index !== -1) { this.__character_count = item.length - last_newline_index; } else { this.__character_count += item.length; } }; OutputLine.prototype.pop = function() { var item = null; if (!this.is_empty()) { item = this.__items.pop(); this.__character_count -= item.length; } return item; }; OutputLine.prototype._remove_indent = function() { if (this.__indent_count > 0) { this.__indent_count -= 1; this.__character_count -= this.__parent.indent_size; } }; OutputLine.prototype._remove_wrap_indent = function() { if (this.__wrap_point_indent_count > 0) { this.__wrap_point_indent_count -= 1; } }; OutputLine.prototype.trim = function() { while (this.last() === ' ') { this.__items.pop(); this.__character_count -= 1; } }; OutputLine.prototype.toString = function() { var result = ''; if (this.is_empty()) { if (this.__parent.indent_empty_lines) { result = this.__parent.get_indent_string(this.__indent_count); } } else { result = this.__parent.get_indent_string(this.__indent_count, this.__alignment_count); result += this.__items.join(''); } return result; }; function IndentStringCache(options, baseIndentString) { this.__cache = ['']; this.__indent_size = options.indent_size; this.__indent_string = options.indent_char; if (!options.indent_with_tabs) { this.__indent_string = new Array(options.indent_size + 1).join(options.indent_char); } // Set to null to continue support for auto detection of base indent baseIndentString = baseIndentString || ''; if (options.indent_level > 0) { baseIndentString = new Array(options.indent_level + 1).join(this.__indent_string); } this.__base_string = baseIndentString; this.__base_string_length = baseIndentString.length; } IndentStringCache.prototype.get_indent_size = function(indent, column) { var result = this.__base_string_length; column = column || 0; if (indent < 0) { result = 0; } result += indent * this.__indent_size; result += column; return result; }; IndentStringCache.prototype.get_indent_string = function(indent_level, column) { var result = this.__base_string; column = column || 0; if (indent_level < 0) { indent_level = 0; result = ''; } column += indent_level * this.__indent_size; this.__ensure_cache(column); result += this.__cache[column]; return result; }; IndentStringCache.prototype.__ensure_cache = function(column) { while (column >= this.__cache.length) { this.__add_column(); } }; IndentStringCache.prototype.__add_column = function() { var column = this.__cache.length; var indent = 0; var result = ''; if (this.__indent_size && column >= this.__indent_size) { indent = Math.floor(column / this.__indent_size); column -= indent * this.__indent_size; result = new Array(indent + 1).join(this.__indent_string); } if (column) { result += new Array(column + 1).join(' '); } this.__cache.push(result); }; function Output(options, baseIndentString) { this.__indent_cache = new IndentStringCache(options, baseIndentString); this.raw = false; this._end_with_newline = options.end_with_newline; this.indent_size = options.indent_size; this.wrap_line_length = options.wrap_line_length; this.indent_empty_lines = options.indent_empty_lines; this.__lines = []; this.previous_line = null; this.current_line = null; this.next_line = new OutputLine(this); this.space_before_token = false; this.non_breaking_space = false; this.previous_token_wrapped = false; // initialize this.__add_outputline(); } Output.prototype.__add_outputline = function() { this.previous_line = this.current_line; this.current_line = this.next_line.clone_empty(); this.__lines.push(this.current_line); }; Output.prototype.get_line_number = function() { return this.__lines.length; }; Output.prototype.get_indent_string = function(indent, column) { return this.__indent_cache.get_indent_string(indent, column); }; Output.prototype.get_indent_size = function(indent, column) { return this.__indent_cache.get_indent_size(indent, column); }; Output.prototype.is_empty = function() { return !this.previous_line && this.current_line.is_empty(); }; Output.prototype.add_new_line = function(force_newline) { // never newline at the start of file // otherwise, newline only if we didn't just add one or we're forced if (this.is_empty() || (!force_newline && this.just_added_newline())) { return false; } // if raw output is enabled, don't print additional newlines, // but still return True as though you had if (!this.raw) { this.__add_outputline(); } return true; }; Output.prototype.get_code = function(eol) { this.trim(true); // handle some edge cases where the last tokens // has text that ends with newline(s) var last_item = this.current_line.pop(); if (last_item) { if (last_item[last_item.length - 1] === '\n') { last_item = last_item.replace(/\n+$/g, ''); } this.current_line.push(last_item); } if (this._end_with_newline) { this.__add_outputline(); } var sweet_code = this.__lines.join('\n'); if (eol !== '\n') { sweet_code = sweet_code.replace(/[\n]/g, eol); } return sweet_code; }; Output.prototype.set_wrap_point = function() { this.current_line._set_wrap_point(); }; Output.prototype.set_indent = function(indent, alignment) { indent = indent || 0; alignment = alignment || 0; // Next line stores alignment values this.next_line.set_indent(indent, alignment); // Never indent your first output indent at the start of the file if (this.__lines.length > 1) { this.current_line.set_indent(indent, alignment); return true; } this.current_line.set_indent(); return false; }; Output.prototype.add_raw_token = function(token) { for (var x = 0; x < token.newlines; x++) { this.__add_outputline(); } this.current_line.set_indent(-1); this.current_line.push(token.whitespace_before); this.current_line.push(token.text); this.space_before_token = false; this.non_breaking_space = false; this.previous_token_wrapped = false; }; Output.prototype.add_token = function(printable_token) { this.__add_space_before_token(); this.current_line.push(printable_token); this.space_before_token = false; this.non_breaking_space = false; this.previous_token_wrapped = this.current_line._allow_wrap(); }; Output.prototype.__add_space_before_token = function() { if (this.space_before_token && !this.just_added_newline()) { if (!this.non_breaking_space) { this.set_wrap_point(); } this.current_line.push(' '); } }; Output.prototype.remove_indent = function(index) { var output_length = this.__lines.length; while (index < output_length) { this.__lines[index]._remove_indent(); index++; } this.current_line._remove_wrap_indent(); }; Output.prototype.trim = function(eat_newlines) { eat_newlines = (eat_newlines === undefined) ? false : eat_newlines; this.current_line.trim(); while (eat_newlines && this.__lines.length > 1 && this.current_line.is_empty()) { this.__lines.pop(); this.current_line = this.__lines[this.__lines.length - 1]; this.current_line.trim(); } this.previous_line = this.__lines.length > 1 ? this.__lines[this.__lines.length - 2] : null; }; Output.prototype.just_added_newline = function() { return this.current_line.is_empty(); }; Output.prototype.just_added_blankline = function() { return this.is_empty() || (this.current_line.is_empty() && this.previous_line.is_empty()); }; Output.prototype.ensure_empty_line_above = function(starts_with, ends_with) { var index = this.__lines.length - 2; while (index >= 0) { var potentialEmptyLine = this.__lines[index]; if (potentialEmptyLine.is_empty()) { break; } else if (potentialEmptyLine.item(0).indexOf(starts_with) !== 0 && potentialEmptyLine.item(-1) !== ends_with) { this.__lines.splice(index + 1, 0, new OutputLine(this)); this.previous_line = this.__lines[this.__lines.length - 2]; break; } index--; } }; var Output_1 = Output; var output = { Output: Output_1 }; /*jshint node:true */ var regexp_has_sticky = RegExp.prototype.hasOwnProperty('sticky'); function InputScanner(input_string) { this.__input = input_string || ''; this.__input_length = this.__input.length; this.__position = 0; } InputScanner.prototype.restart = function() { this.__position = 0; }; InputScanner.prototype.back = function() { if (this.__position > 0) { this.__position -= 1; } }; InputScanner.prototype.hasNext = function() { return this.__position < this.__input_length; }; InputScanner.prototype.next = function() { var val = null; if (this.hasNext()) { val = this.__input.charAt(this.__position); this.__position += 1; } return val; }; InputScanner.prototype.peek = function(index) { var val = null; index = index || 0; index += this.__position; if (index >= 0 && index < this.__input_length) { val = this.__input.charAt(index); } return val; }; // This is a JavaScript only helper function (not in python) // Javascript doesn't have a match method // and not all implementation support "sticky" flag. // If they do not support sticky then both this.match() and this.test() method // must get the match and check the index of the match. // If sticky is supported and set, this method will use it. // Otherwise it will check that global is set, and fall back to the slower method. InputScanner.prototype.__match = function(pattern, index) { pattern.lastIndex = index; var pattern_match = pattern.exec(this.__input); if (pattern_match && !(regexp_has_sticky && pattern.sticky)) { if (pattern_match.index !== index) { pattern_match = null; } } return pattern_match; }; InputScanner.prototype.test = function(pattern, index) { index = index || 0; index += this.__position; if (index >= 0 && index < this.__input_length) { return !!this.__match(pattern, index); } else { return false; } }; InputScanner.prototype.testChar = function(pattern, index) { // test one character regex match var val = this.peek(index); pattern.lastIndex = 0; return val !== null && pattern.test(val); }; InputScanner.prototype.match = function(pattern) { var pattern_match = this.__match(pattern, this.__position); if (pattern_match) { this.__position += pattern_match[0].length; } else { pattern_match = null; } return pattern_match; }; InputScanner.prototype.read = function(starting_pattern, until_pattern, until_after) { var val = ''; var match; if (starting_pattern) { match = this.match(starting_pattern); if (match) { val += match[0]; } } if (until_pattern && (match || !starting_pattern)) { val += this.readUntil(until_pattern, until_after); } return val; }; InputScanner.prototype.readUntil = function(pattern, until_after) { var val = ''; var match_index = this.__position; pattern.lastIndex = this.__position; var pattern_match = pattern.exec(this.__input); if (pattern_match) { match_index = pattern_match.index; if (until_after) { match_index += pattern_match[0].length; } } else { match_index = this.__input_length; } val = this.__input.substring(this.__position, match_index); this.__position = match_index; return val; }; InputScanner.prototype.readUntilAfter = function(pattern) { return this.readUntil(pattern, true); }; InputScanner.prototype.get_regexp = function(pattern, match_from) { var result = null; var flags = 'g'; if (match_from && regexp_has_sticky) { flags = 'y'; } // strings are converted to regexp if (typeof pattern === "string" && pattern !== '') { // result = new RegExp(pattern.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), flags); result = new RegExp(pattern, flags); } else if (pattern) { result = new RegExp(pattern.source, flags); } return result; }; InputScanner.prototype.get_literal_regexp = function(literal_string) { return RegExp(literal_string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')); }; /* css beautifier legacy helpers */ InputScanner.prototype.peekUntilAfter = function(pattern) { var start = this.__position; var val = this.readUntilAfter(pattern); this.__position = start; return val; }; InputScanner.prototype.lookBack = function(testVal) { var start = this.__position - 1; return start >= testVal.length && this.__input.substring(start - testVal.length, start) .toLowerCase() === testVal; }; var InputScanner_1 = InputScanner; var inputscanner = { InputScanner: InputScanner_1 }; /*jshint node:true */ function Directives(start_block_pattern, end_block_pattern) { start_block_pattern = typeof start_block_pattern === 'string' ? start_block_pattern : start_block_pattern.source; end_block_pattern = typeof end_block_pattern === 'string' ? end_block_pattern : end_block_pattern.source; this.__directives_block_pattern = new RegExp(start_block_pattern + / beautify( \w+[:]\w+)+ /.source + end_block_pattern, 'g'); this.__directive_pattern = / (\w+)[:](\w+)/g; this.__directives_end_ignore_pattern = new RegExp(start_block_pattern + /\sbeautify\signore:end\s/.source + end_block_pattern, 'g'); } Directives.prototype.get_directives = function(text) { if (!text.match(this.__directives_block_pattern)) { return null; } var directives = {}; this.__directive_pattern.lastIndex = 0; var directive_match = this.__directive_pattern.exec(text); while (directive_match) { directives[directive_match[1]] = directive_match[2]; directive_match = this.__directive_pattern.exec(text); } return directives; }; Directives.prototype.readIgnored = function(input) { return input.readUntilAfter(this.__directives_end_ignore_pattern); }; var Directives_1 = Directives; var directives = { Directives: Directives_1 }; /*jshint node:true */ var Options$2 = options$1.Options; var Output$1 = output.Output; var InputScanner$1 = inputscanner.InputScanner; var Directives$1 = directives.Directives; var directives_core = new Directives$1(/\/\*/, /\*\//); var lineBreak = /\r\n|[\r\n]/; var allLineBreaks = /\r\n|[\r\n]/g; // tokenizer var whitespaceChar = /\s/; var whitespacePattern = /(?:\s|\n)+/g; var block_comment_pattern = /\/\*(?:[\s\S]*?)((?:\*\/)|$)/g; var comment_pattern = /\/\/(?:[^\n\r\u2028\u2029]*)/g; function Beautifier(source_text, options) { this._source_text = source_text || ''; // Allow the setting of language/file-type specific options // with inheritance of overall settings this._options = new Options$2(options); this._ch = null; this._input = null; // https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule this.NESTED_AT_RULE = { "@page": true, "@font-face": true, "@keyframes": true, // also in CONDITIONAL_GROUP_RULE below "@media": true, "@supports": true, "@document": true }; this.CONDITIONAL_GROUP_RULE = { "@media": true, "@supports": true, "@document": true }; } Beautifier.prototype.eatString = function(endChars) { var result = ''; this._ch = this._input.next(); while (this._ch) { result += this._ch; if (this._ch === "\\") { result += this._input.next(); } else if (endChars.indexOf(this._ch) !== -1 || this._ch === "\n") { break; } this._ch = this._input.next(); } return result; }; // Skips any white space in the source text from the current position. // When allowAtLeastOneNewLine is true, will output new lines for each // newline character found; if the user has preserve_newlines off, only // the first newline will be output Beautifier.prototype.eatWhitespace = function(allowAtLeastOneNewLine) { var result = whitespaceChar.test(this._input.peek()); var newline_count = 0; while (whitespaceChar.test(this._input.peek())) { this._ch = this._input.next(); if (allowAtLeastOneNewLine && this._ch === '\n') { if (newline_count === 0 || newline_count < this._options.max_preserve_newlines) { newline_count++; this._output.add_new_line(true); } } } return result; }; // Nested pseudo-class if we are insideRule // and the next special character found opens // a new block Beautifier.prototype.foundNestedPseudoClass = function() { var openParen = 0; var i = 1; var ch = this._input.peek(i); while (ch) { if (ch === "{") { return true; } else if (ch === '(') { // pseudoclasses can contain () openParen += 1; } else if (ch === ')') { if (openParen === 0) { return false; } openParen -= 1; } else if (ch === ";" || ch === "}") { return false; } i++; ch = this._input.peek(i); } return false; }; Beautifier.prototype.print_string = function(output_string) { this._output.set_indent(this._indentLevel); this._output.non_breaking_space = true; this._output.add_token(output_string); }; Beautifier.prototype.preserveSingleSpace = function(isAfterSpace) { if (isAfterSpace) { this._output.space_before_token = true; } }; Beautifier.prototype.indent = function() { this._indentLevel++; }; Beautifier.prototype.outdent = function() { if (this._indentLevel > 0) { this._indentLevel--; } }; /*_____________________--------------------_____________________*/ Beautifier.prototype.beautify = function() { if (this._options.disabled) { return this._source_text; } var source_text = this._source_text; var eol = this._options.eol; if (eol === 'auto') { eol = '\n'; if (source_text && lineBreak.test(source_text || '')) { eol = source_text.match(lineBreak)[0]; } } // HACK: newline parsing inconsistent. This brute force normalizes the this._input. source_text = source_text.replace(allLineBreaks, '\n'); // reset var baseIndentString = source_text.match(/^[\t ]*/)[0]; this._output = new Output$1(this._options, baseIndentString); this._input = new InputScanner$1(source_text); this._indentLevel = 0; this._nestedLevel = 0; this._ch = null; var parenLevel = 0; var insideRule = false; // This is the value side of a property value pair (blue in the following ex) // label { content: blue } var insidePropertyValue = false; var enteringConditionalGroup = false; var insideAtExtend = false; var insideAtImport = false; var topCharacter = this._ch; var whitespace; var isAfterSpace; var previous_ch; while (true) { whitespace = this._input.read(whitespacePattern); isAfterSpace = whitespace !== ''; previous_ch = topCharacter; this._ch = this._input.next(); if (this._ch === '\\' && this._input.hasNext()) { this._ch += this._input.next(); } topCharacter = this._ch; if (!this._ch) { break; } else if (this._ch === '/' && this._input.peek() === '*') { // /* css comment */ // Always start block comments on a new line. // This handles scenarios where a block comment immediately // follows a property definition on the same line or where // minified code is being beautified. this._output.add_new_line(); this._input.back(); var comment = this._input.read(block_comment_pattern); // Handle ignore directive var directives = directives_core.get_directives(comment); if (directives && directives.ignore === 'start') { comment += directives_core.readIgnored(this._input); } this.print_string(comment); // Ensures any new lines following the comment are preserved this.eatWhitespace(true); // Block comments are followed by a new line so they don't // share a line with other properties this._output.add_new_line(); } else if (this._ch === '/' && this._input.peek() === '/') { // // single line comment // Preserves the space before a comment // on the same line as a rule this._output.space_before_token = true; this._input.back(); this.print_string(this._input.read(comment_pattern)); // Ensures any new lines following the comment are preserved this.eatWhitespace(true); } else if (this._ch === '@') { this.preserveSingleSpace(isAfterSpace); // deal with less propery mixins @{...} if (this._input.peek() === '{') { this.print_string(this._ch + this.eatString('}')); } else { this.print_string(this._ch); // strip trailing space, if present, for hash property checks var variableOrRule = this._input.peekUntilAfter(/[: ,;{}()[\]\/='"]/g); if (variableOrRule.match(/[ :]$/)) { // we have a variable or pseudo-class, add it and insert one space before continuing variableOrRule = this.eatString(": ").replace(/\s$/, ''); this.print_string(variableOrRule); this._output.space_before_token = true; } variableOrRule = variableOrRule.replace(/\s$/, ''); if (variableOrRule === 'extend') { insideAtExtend = true; } else if (variableOrRule === 'import') { insideAtImport = true; } // might be a nesting at-rule if (variableOrRule in this.NESTED_AT_RULE) { this._nestedLevel += 1; if (variableOrRule in this.CONDITIONAL_GROUP_RULE) { enteringConditionalGroup = true; } // might be less variable } else if (!insideRule && parenLevel === 0 && variableOrRule.indexOf(':') !== -1) { insidePropertyValue = true; this.indent(); } } } else if (this._ch === '#' && this._input.peek() === '{') { this.preserveSingleSpace(isAfterSpace); this.print_string(this._ch + this.eatString('}')); } else if (this._ch === '{') { if (insidePropertyValue) { insidePropertyValue = false; this.outdent(); } // when entering conditional groups, only rulesets are allowed if (enteringConditionalGroup) { enteringConditionalGroup = false; insideRule = (this._indentLevel >= this._nestedLevel); } else { // otherwise, declarations are also allowed insideRule = (this._indentLevel >= this._nestedLevel - 1); } if (this._options.newline_between_rules && insideRule) { if (this._output.previous_line && this._output.previous_line.item(-1) !== '{') { this._output.ensure_empty_line_above('/', ','); } } this._output.space_before_token = true; // The difference in print_string and indent order is necessary to indent the '{' correctly if (this._options.brace_style === 'expand') { this._output.add_new_line(); this.print_string(this._ch); this.indent(); this._output.set_indent(this._indentLevel); } else { this.indent(); this.print_string(this._ch); } this.eatWhitespace(true); this._output.add_new_line(); } else if (this._ch === '}') { this.outdent(); this._output.add_new_line(); if (previous_ch === '{') { this._output.trim(true); } insideAtImport = false; insideAtExtend = false; if (insidePropertyValue) { this.outdent(); insidePropertyValue = false; } this.print_string(this._ch); insideRule = false; if (this._nestedLevel) { this._nestedLevel--; } this.eatWhitespace(true); this._output.add_new_line(); if (this._options.newline_between_rules && !this._output.just_added_blankline()) { if (this._input.peek() !== '}') { this._output.add_new_line(true); } } } else if (this._ch === ":") { if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideAtExtend && parenLevel === 0) { // 'property: value' delimiter // which could be in a conditional group query this.print_string(':'); if (!insidePropertyValue) { insidePropertyValue = true; this._output.space_before_token = true; this.eatWhitespace(true); this.indent(); } } else { // sass/less parent reference don't use a space // sass nested pseudo-class don't use a space // preserve space before pseudoclasses/pseudoelements, as it means "in any child" if (this._input.lookBack(" ")) { this._output.space_before_token = true; } if (this._input.peek() === ":") { // pseudo-element this._ch = this._input.next(); this.print_string("::"); } else { // pseudo-class this.print_string(':'); } } } else if (this._ch === '"' || this._ch === '\'') { this.preserveSingleSpace(isAfterSpace); this.print_string(this._ch + this.eatString(this._ch)); this.eatWhitespace(true); } else if (this._ch === ';') { if (parenLevel === 0) { if (insidePropertyValue) { this.outdent(); insidePropertyValue = false; } insideAtExtend = false; insideAtImport = false; this.print_string(this._ch); this.eatWhitespace(true); // This maintains single line comments on the same // line. Block comments are also affected, but // a new line is always output before one inside // that section if (this._input.peek() !== '/') { this._output.add_new_line(); } } else { this.print_string(this._ch); this.eatWhitespace(true); this._output.space_before_token = true; } } else if (this._ch === '(') { // may be a url if (this._input.lookBack("url")) { this.print_string(this._ch); this.eatWhitespace(); parenLevel++; this.indent(); this._ch = this._input.next(); if (this._ch === ')' || this._ch === '"' || this._ch === '\'') { this._input.back(); } else if (this._ch) { this.print_string(this._ch + this.eatString(')')); if (parenLevel) { parenLevel--; this.outdent(); } } } else { this.preserveSingleSpace(isAfterSpace); this.print_string(this._ch); this.eatWhitespace(); parenLevel++; this.indent(); } } else if (this._ch === ')') { if (parenLevel) { parenLevel--; this.outdent(); } this.print_string(this._ch); } else if (this._ch === ',') { this.print_string(this._ch); this.eatWhitespace(true); if (this._options.selector_separator_newline && !insidePropertyValue && parenLevel === 0 && !insideAtImport && !insideAtExtend) { this._output.add_new_line(); } else { this._output.space_before_token = true; } } else if ((this._ch === '>' || this._ch === '+' || this._ch === '~') && !insidePropertyValue && parenLevel === 0) { //handle combinator spacing if (this._options.space_around_combinator) { this._output.space_before_token = true; this.print_string(this._ch); this._output.space_before_token = true; } else { this.print_string(this._ch); this.eatWhitespace(); // squash extra whitespace if (this._ch && whitespaceChar.test(this._ch)) { this._ch = ''; } } } else if (this._ch === ']') { this.print_string(this._ch); } else if (this._ch === '[') { this.preserveSingleSpace(isAfterSpace); this.print_string(this._ch); } else if (this._ch === '=') { // no whitespace before or after this.eatWhitespace(); this.print_string('='); if (whitespaceChar.test(this._ch)) { this._ch = ''; } } else if (this._ch === '!' && !this._input.lookBack("\\")) { // !important this.print_string(' '); this.print_string(this._ch); } else { this.preserveSingleSpace(isAfterSpace); this.print_string(this._ch); } } var sweetCode = this._output.get_code(eol); return sweetCode; }; var Beautifier_1 = Beautifier; var beautifier = { Beautifier: Beautifier_1 }; /*jshint node:true */ var Beautifier$1 = beautifier.Beautifier, Options$3 = options$1.Options; function css_beautify(source_text, options) { var beautifier = new Beautifier$1(source_text, options); return beautifier.beautify(); } var css = css_beautify; var defaultOptions = function() { return new Options$3(); }; css.defaultOptions = defaultOptions; // import inside js to reduce bundle size function cssFormatter(monaco, beautyOption) { if (monaco === void 0) { monaco = window.monaco; } if (beautyOption === void 0) { beautyOption = {}; } if (!monaco) { console.error("css-format-monaco: 'monaco' should be either declared on window or passed as first parameter"); return; } var documentProvider = { provideDocumentFormattingEdits: function (model) { var lineCount = model.getLineCount(); return [ { range: new monaco.Range(1, 1, lineCount, model.getLineMaxColumn(lineCount) + 1), text: css(model.getValue(), beautyOption) } ]; } }; var rangeProvider = { provideDocumentRangeFormattingEdits: function (model, range) { var fullLineRange = new monaco.Range(range.startLineNumber, 1, range.endLineNumber, model.getLineMaxColumn(range.endLineNumber) + 1); var code = model.getValueInRange(fullLineRange); return [ { range: fullLineRange, text: css(code, beautyOption) } ]; } }; var disposeArr = ["css", "less", "scss"].map(function (language) { return [ monaco.languages.registerDocumentFormattingEditProvider(language, documentProvider), monaco.languages.registerDocumentRangeFormattingEditProvider(language, rangeProvider) ]; }); return function () { disposeArr.forEach(function (arr) { return arr.forEach(function (disposable) { return disposable.dispose(); }); }); }; } export default cssFormatter;