Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(129)

Unified Diff: third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js

Issue 1511073002: DevTools: [SASS] introduce sass module, implement SCSS AST-builder. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: introduce ASTDocument Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js
diff --git a/third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js b/third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js
new file mode 100644
index 0000000000000000000000000000000000000000..4c9a9f691ae1182c23a9385a2e2a36d8fbcc84b1
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js
@@ -0,0 +1,335 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+WebInspector.SASSSupport = {}
+
+/**
+ * @constructor
+ * @param {string} url
+ * @param {string} text
+ */
+WebInspector.SASSSupport.ASTDocument = function(url, text)
+{
+ this.url = url;
+ this.text = text;
+}
+
+/**
+ * @param {string} url
+ * @param {string} text
+ * @param {!WebInspector.TokenizerFactory} tokenizerFactory
+ * @return {!WebInspector.SASSSupport.AST}
+ */
+WebInspector.SASSSupport.parseSCSS = function(url, text, tokenizerFactory)
+{
+ var document = new WebInspector.SASSSupport.ASTDocument(url, text);
+ var result = WebInspector.SASSSupport._innerParseSCSS(document, tokenizerFactory);
+
+ var rules = [
+ new WebInspector.SASSSupport.Rule(document, "variables", result.variables),
+ new WebInspector.SASSSupport.Rule(document, "properties", result.properties),
+ new WebInspector.SASSSupport.Rule(document, "mixins", result.mixins)
+ ];
+
+ return new WebInspector.SASSSupport.AST(document, rules);
+}
+
+/** @enum {string} */
+WebInspector.SASSSupport.SCSSParserStates = {
+ Initial: "Initial",
+ PropertyName: "PropertyName",
+ PropertyValue: "PropertyValue",
+ VariableName: "VariableName",
+ VariableValue: "VariableValue",
+ MixinName: "MixinName",
+ MixinValue: "MixinValue",
+ Media: "Media",
+}
+
+/**
+ * @param {!WebInspector.SASSSupport.ASTDocument} document
+ * @param {!WebInspector.TokenizerFactory} tokenizerFactory
+ * @return {!{variables: !Array<!WebInspector.SASSSupport.Property>, properties: !Array<!WebInspector.SASSSupport.Property>, mixins: !Array<!WebInspector.SASSSupport.Property>}}
+ */
+WebInspector.SASSSupport._innerParseSCSS = function(document, tokenizerFactory)
+{
+ var lines = document.text.split("\n");
+ var properties = [];
+ var variables = [];
+ var mixins = [];
+
+ var States = WebInspector.SASSSupport.SCSSParserStates;
+ var state = States.Initial;
+ var propertyName, propertyValue;
+ var variableName, variableValue;
+ var mixinName, mixinValue;
+ var UndefTokenType = {};
+
+ /**
+ * @param {string} tokenValue
+ * @param {?string} tokenTypes
+ * @param {number} column
+ * @param {number} newColumn
+ */
+ function processToken(tokenValue, tokenTypes, column, newColumn)
+ {
+ var tokenType = tokenTypes ? tokenTypes.split(" ").keySet() : UndefTokenType;
+ switch (state) {
+ case States.Initial:
+ if (tokenType["css-variable-2"]) {
+ variableName = new WebInspector.SASSSupport.TextNode(document, tokenValue, new WebInspector.TextRange(lineNumber, column, lineNumber, newColumn));
+ state = States.VariableName;
+ } else if (tokenType["css-property"] || tokenType["css-meta"]) {
+ propertyName = new WebInspector.SASSSupport.TextNode(document, tokenValue, new WebInspector.TextRange(lineNumber, column, lineNumber, newColumn));
+ state = States.PropertyName;
+ } else if (tokenType["css-def"] && tokenValue === "@include") {
+ mixinName = new WebInspector.SASSSupport.TextNode(document, tokenValue, new WebInspector.TextRange(lineNumber, column, lineNumber, newColumn));
+ state = States.MixinName;
+ } else if (tokenType["css-comment"]) {
+ // Support only a one-line comments.
+ if (tokenValue.substring(0, 2) !== "/*" || tokenValue.substring(tokenValue.length - 2) !== "*/")
+ break;
+ var uncommentedText = tokenValue.substring(2, tokenValue.length - 2);
+ var fakeRuleText = "a{\n" + uncommentedText + "}";
+ var fakeDocument = new WebInspector.SASSSupport.ASTDocument("", fakeRuleText);
+ var result = WebInspector.SASSSupport._innerParseSCSS(fakeDocument, tokenizerFactory);
+ if (result.properties.length === 1 && result.variables.length === 0 && result.mixins.length === 0) {
+ var disabledProperty = result.properties[0];
+ // We should offset property to current coordinates.
+ var offset = column + 2;
+ var nameRange = new WebInspector.TextRange(lineNumber, disabledProperty.name.range.startColumn + offset,
+ lineNumber, disabledProperty.name.range.endColumn + offset);
+ var valueRange = new WebInspector.TextRange(lineNumber, disabledProperty.value.range.startColumn + offset,
+ lineNumber, disabledProperty.value.range.endColumn + offset);
+ var name = new WebInspector.SASSSupport.TextNode(document, disabledProperty.name.text, nameRange);
+ var value = new WebInspector.SASSSupport.TextNode(document, disabledProperty.value.text, valueRange);
+ var range = new WebInspector.TextRange(lineNumber, column, lineNumber, newColumn);
+ var property = new WebInspector.SASSSupport.Property(document, name, value, range, true);
+ properties.push(property);
+ }
+ } else if (tokenType["css-def"] && tokenValue === "@media") {
+ state = States.Media;
+ }
+ break;
+ case States.VariableName:
+ if (tokenValue === ")" && tokenType === UndefTokenType) {
+ state = States.Initial;
+ } else if (tokenValue === ":" && tokenType === UndefTokenType) {
+ state = States.VariableValue;
+ variableValue = new WebInspector.SASSSupport.TextNode(document, "", WebInspector.TextRange.createFromLocation(lineNumber, newColumn));
+ } else if (tokenType !== UndefTokenType) {
+ state = States.Initial;
+ }
+ break;
+ case States.VariableValue:
+ if (tokenValue === ";" && tokenType === UndefTokenType) {
+ variableValue.range.endLine = lineNumber;
+ variableValue.range.endColumn = column;
+ var variable = new WebInspector.SASSSupport.Property(document, variableName, variableValue, variableName.range.clone(), false);
+ variable.range.endLine = lineNumber;
+ variable.range.endColumn = newColumn;
+ variables.push(variable);
+ state = States.Initial;
+ } else {
+ variableValue.text += tokenValue;
+ }
+ break;
+ case States.PropertyName:
+ if (tokenValue === ":" && tokenType === UndefTokenType) {
+ state = States.PropertyValue;
+ propertyName.range.endLine = lineNumber;
+ propertyName.range.endColumn = column;
+ propertyValue = new WebInspector.SASSSupport.TextNode(document, "", WebInspector.TextRange.createFromLocation(lineNumber, newColumn));
+ } else if (tokenType["css-property"]) {
+ propertyName.text += tokenValue;
+ }
+ break;
+ case States.PropertyValue:
+ if ((tokenValue === "}" || tokenValue === ";") && tokenType === UndefTokenType) {
+ propertyValue.range.endLine = lineNumber;
+ propertyValue.range.endColumn = column;
+ var property = new WebInspector.SASSSupport.Property(document, propertyName, propertyValue, propertyName.range.clone(), false);
+ property.range.endLine = lineNumber;
+ property.range.endColumn = newColumn;
+ properties.push(property);
+ state = States.Initial;
+ } else {
+ propertyValue.text += tokenValue;
+ }
+ break;
+ case States.MixinName:
+ if (tokenValue === "(" && tokenType === UndefTokenType) {
+ state = States.MixinValue;
+ mixinName.range.endLine = lineNumber;
+ mixinName.range.endColumn = column;
+ mixinValue = new WebInspector.SASSSupport.TextNode(document, "", WebInspector.TextRange.createFromLocation(lineNumber, newColumn));
+ } else if (tokenValue === ";" && tokenType === UndefTokenType) {
+ state = States.Initial;
+ mixinValue = null;
+ } else {
+ mixinName.text += tokenValue;
+ }
+ break;
+ case States.MixinValue:
+ if (tokenValue === ")" && tokenType === UndefTokenType) {
+ mixinValue.range.endLine = lineNumber;
+ mixinValue.range.endColumn = column;
+ var mixin = new WebInspector.SASSSupport.Property(document, mixinName, /** @type {!WebInspector.SASSSupport.TextNode} */(mixinValue), mixinName.range.clone(), false);
+ mixin.range.endLine = lineNumber;
+ mixin.range.endColumn = newColumn;
+ mixins.push(mixin);
+ state = States.Initial;
+ } else {
+ mixinValue.text += tokenValue;
+ }
+ break;
+ case States.Media:
+ if (tokenValue === "{" && tokenType === UndefTokenType)
+ state = States.Initial;
+ break;
+ default:
+ console.assert(false, "Unknown SASS parser state.");
+ }
+ }
+ var tokenizer = tokenizerFactory.createTokenizer("text/x-scss");
+ var lineNumber;
+ for (lineNumber = 0; lineNumber < lines.length; ++lineNumber) {
+ var line = lines[lineNumber];
+ tokenizer(line, processToken);
+ processToken("\n", null, line.length, line.length + 1);
+ }
+ return {
+ variables: variables,
+ properties: properties,
+ mixins: mixins
+ };
+}
+
+/**
+ * @constructor
+ * @param {!WebInspector.SASSSupport.ASTDocument} document
+ */
+WebInspector.SASSSupport.Node = function(document)
+{
+ this.document = document;
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SASSSupport.Node}
+ * @param {!WebInspector.SASSSupport.ASTDocument} document
+ * @param {string} text
+ * @param {!WebInspector.TextRange} range
+ */
+WebInspector.SASSSupport.TextNode = function(document, text, range)
+{
+ WebInspector.SASSSupport.Node.call(this, document);
+ this.text = text;
pfeldman 2015/12/09 20:13:43 Why is text necessary? You can fetch it at any mom
lushnikov 2015/12/09 21:41:54 I want to modify AST tree later, adding properties
+ this.range = range;
+}
+
+WebInspector.SASSSupport.TextNode.prototype = {
+ /**
+ * @return {!WebInspector.SASSSupport.TextNode}
+ */
+ clone: function()
+ {
+ return new WebInspector.SASSSupport.TextNode(this.document, this.text, this.range.clone());
+ },
+
+ __proto__: WebInspector.SASSSupport.Node.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SASSSupport.Node}
+ * @param {!WebInspector.SASSSupport.ASTDocument} document
+ * @param {!WebInspector.SASSSupport.TextNode} name
+ * @param {!WebInspector.SASSSupport.TextNode} value
+ * @param {!WebInspector.TextRange} range
+ * @param {boolean} disabled
+ */
+WebInspector.SASSSupport.Property = function(document, name, value, range, disabled)
+{
+ WebInspector.SASSSupport.Node.call(this, document);
+ this.name = name;
+ this.value = value;
+ this.range = range;
+ this.name.parent = this;
+ this.value.parent = this;
+ this.disabled = disabled;
+}
+
+WebInspector.SASSSupport.Property.prototype = {
+ /**
+ * @return {!WebInspector.SASSSupport.Property}
+ */
+ clone: function()
+ {
+ return new WebInspector.SASSSupport.Property(this.document, this.name.clone(), this.value.clone(), this.range.clone(), this.disabled);
+ },
+
+ __proto__: WebInspector.SASSSupport.Node.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SASSSupport.Node}
+ * @param {!WebInspector.SASSSupport.ASTDocument} document
+ * @param {string} selector
+ * @param {!Array<!WebInspector.SASSSupport.Property>} properties
+ */
+WebInspector.SASSSupport.Rule = function(document, selector, properties)
+{
+ WebInspector.SASSSupport.Node.call(this, document);
+ this.selector = selector;
+ this.properties = properties;
+ for (var i = 0; i < this.properties.length; ++i)
+ this.properties[i].parent = this;
+}
+
+WebInspector.SASSSupport.Rule.prototype = {
+ /**
+ * @return {!WebInspector.SASSSupport.Rule}
+ */
+ clone: function()
+ {
+ var properties = [];
+ for (var i = 0; i < this.properties.length; ++i)
+ properties.push(this.properties[i].clone());
+ return new WebInspector.SASSSupport.Rule(this.document, this.selector, properties);
+ },
+
+ __proto__: WebInspector.SASSSupport.Node.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SASSSupport.Node}
+ * @param {!WebInspector.SASSSupport.ASTDocument} document
+ * @param {!Array<!WebInspector.SASSSupport.Rule>} rules
+ */
+WebInspector.SASSSupport.AST = function(document, rules)
+{
+ WebInspector.SASSSupport.Node.call(this, document);
+ this.rules = rules;
+ for (var i = 0; i < rules.length; ++i)
+ rules[i].parent = this;
+}
+
+WebInspector.SASSSupport.AST.prototype = {
+ /**
+ * @return {!WebInspector.SASSSupport.AST}
+ */
+ clone: function()
+ {
+ var rules = [];
+ for (var i = 0; i < this.rules.length; ++i)
+ rules.push(this.rules[i].clone());
+ return new WebInspector.SASSSupport.AST(this.document, rules);
+ },
+
+ __proto__: WebInspector.SASSSupport.Node.prototype
+}
+

Powered by Google App Engine
This is Rietveld 408576698