prettier 0.15.1 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +47 -1
- data/CONTRIBUTING.md +127 -96
- data/README.md +31 -7
- data/node_modules/prettier/bin-prettier.js +28420 -26950
- data/node_modules/prettier/index.js +28307 -26856
- data/node_modules/prettier/third-party.js +813 -580
- data/package.json +2 -2
- data/src/haml.js +21 -0
- data/src/haml/embed.js +58 -0
- data/src/haml/nodes/comment.js +27 -0
- data/src/haml/nodes/doctype.js +32 -0
- data/src/haml/nodes/filter.js +16 -0
- data/src/haml/nodes/hamlComment.js +21 -0
- data/src/haml/nodes/script.js +29 -0
- data/src/haml/nodes/silentScript.js +30 -0
- data/src/haml/nodes/tag.js +151 -0
- data/src/haml/parse.js +18 -0
- data/src/haml/parse.rb +65 -0
- data/src/haml/print.js +38 -0
- data/src/nodes.js +1 -0
- data/src/nodes/conditionals.js +45 -30
- data/src/nodes/flow.js +1 -34
- data/src/nodes/massign.js +16 -17
- data/src/nodes/return.js +60 -0
- data/src/nodes/statements.js +1 -4
- data/src/nodes/strings.js +57 -5
- data/src/ripper.rb +27 -1
- data/src/ruby.js +18 -0
- metadata +19 -6
data/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@prettier/plugin-ruby",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.16.0",
|
4
4
|
"description": "prettier plugin for the Ruby programming language",
|
5
5
|
"main": "src/ruby.js",
|
6
6
|
"scripts": {
|
@@ -19,7 +19,7 @@
|
|
19
19
|
},
|
20
20
|
"homepage": "https://github.com/prettier/plugin-ruby#readme",
|
21
21
|
"dependencies": {
|
22
|
-
"prettier": "
|
22
|
+
"prettier": ">=1.10"
|
23
23
|
},
|
24
24
|
"devDependencies": {
|
25
25
|
"all-contributors-cli": "^6.1.2",
|
data/src/haml.js
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
const embed = require("./haml/embed");
|
2
|
+
const parse = require("./haml/parse");
|
3
|
+
const print = require("./haml/print");
|
4
|
+
|
5
|
+
const pragmaPattern = /^\s*-#\s*@(prettier|format)/;
|
6
|
+
const hasPragma = text => pragmaPattern.test(text);
|
7
|
+
|
8
|
+
// These functions are just placeholders until we can actually perform this
|
9
|
+
// properly. The functions are necessary otherwise the format with cursor
|
10
|
+
// functions break.
|
11
|
+
const locStart = _node => 0;
|
12
|
+
const locEnd = _node => 0;
|
13
|
+
|
14
|
+
module.exports = {
|
15
|
+
embed,
|
16
|
+
hasPragma,
|
17
|
+
locStart,
|
18
|
+
locEnd,
|
19
|
+
parse,
|
20
|
+
print
|
21
|
+
};
|
data/src/haml/embed.js
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
const {
|
2
|
+
concat,
|
3
|
+
hardline,
|
4
|
+
indent,
|
5
|
+
literalline,
|
6
|
+
mapDoc,
|
7
|
+
markAsRoot,
|
8
|
+
stripTrailingHardline
|
9
|
+
} = require("../prettier");
|
10
|
+
|
11
|
+
const parsers = {
|
12
|
+
css: "css",
|
13
|
+
javascript: "babel",
|
14
|
+
less: "less",
|
15
|
+
markdown: "markdown",
|
16
|
+
ruby: "ruby",
|
17
|
+
scss: "scss"
|
18
|
+
};
|
19
|
+
|
20
|
+
const replaceNewlines = doc =>
|
21
|
+
mapDoc(doc, currentDoc =>
|
22
|
+
typeof currentDoc === "string" && currentDoc.includes("\n")
|
23
|
+
? concat(
|
24
|
+
currentDoc
|
25
|
+
.split(/(\n)/g)
|
26
|
+
.map((v, i) => (i % 2 === 0 ? v : literalline))
|
27
|
+
)
|
28
|
+
: currentDoc
|
29
|
+
);
|
30
|
+
|
31
|
+
const embed = (path, print, textToDoc, _opts) => {
|
32
|
+
const node = path.getValue();
|
33
|
+
if (node.type !== "filter") {
|
34
|
+
return null;
|
35
|
+
}
|
36
|
+
|
37
|
+
const parser = parsers[node.value.name];
|
38
|
+
if (!parser) {
|
39
|
+
return null;
|
40
|
+
}
|
41
|
+
|
42
|
+
return markAsRoot(
|
43
|
+
concat([
|
44
|
+
":",
|
45
|
+
node.value.name,
|
46
|
+
indent(
|
47
|
+
concat([
|
48
|
+
hardline,
|
49
|
+
replaceNewlines(
|
50
|
+
stripTrailingHardline(textToDoc(node.value.text, { parser }))
|
51
|
+
)
|
52
|
+
])
|
53
|
+
)
|
54
|
+
])
|
55
|
+
);
|
56
|
+
};
|
57
|
+
|
58
|
+
module.exports = embed;
|
@@ -0,0 +1,27 @@
|
|
1
|
+
const { concat, group, hardline, indent, join } = require("../../prettier");
|
2
|
+
|
3
|
+
// http://haml.info/docs/yardoc/file.REFERENCE.html#html-comments-
|
4
|
+
const comment = (path, opts, print) => {
|
5
|
+
const { children, value } = path.getValue();
|
6
|
+
const parts = ["/"];
|
7
|
+
|
8
|
+
if (value.revealed) {
|
9
|
+
parts.push("!");
|
10
|
+
}
|
11
|
+
|
12
|
+
if (value.conditional) {
|
13
|
+
parts.push(value.conditional);
|
14
|
+
} else if (value.text) {
|
15
|
+
parts.push(" ", value.text);
|
16
|
+
}
|
17
|
+
|
18
|
+
if (children.length > 0) {
|
19
|
+
parts.push(
|
20
|
+
indent(concat([hardline, join(hardline, path.map(print, "children"))]))
|
21
|
+
);
|
22
|
+
}
|
23
|
+
|
24
|
+
return group(concat(parts));
|
25
|
+
};
|
26
|
+
|
27
|
+
module.exports = comment;
|
@@ -0,0 +1,32 @@
|
|
1
|
+
const { join } = require("../../prettier");
|
2
|
+
|
3
|
+
const types = {
|
4
|
+
basic: "Basic",
|
5
|
+
frameset: "Frameset",
|
6
|
+
mobile: "Mobile",
|
7
|
+
rdfa: "RDFa",
|
8
|
+
strict: "Strict",
|
9
|
+
xml: "XML"
|
10
|
+
};
|
11
|
+
|
12
|
+
const versions = ["1.1", "5"];
|
13
|
+
|
14
|
+
// http://haml.info/docs/yardoc/file.REFERENCE.html#doctype-
|
15
|
+
const doctype = (path, _opts, _print) => {
|
16
|
+
const { value } = path.getValue();
|
17
|
+
const parts = ["!!!"];
|
18
|
+
|
19
|
+
if (value.type in types) {
|
20
|
+
parts.push(types[value.type]);
|
21
|
+
} else if (value.version in versions) {
|
22
|
+
parts.push(versions[value.version]);
|
23
|
+
}
|
24
|
+
|
25
|
+
if (value.encoding) {
|
26
|
+
parts.push(value.encoding);
|
27
|
+
}
|
28
|
+
|
29
|
+
return join(" ", parts);
|
30
|
+
};
|
31
|
+
|
32
|
+
module.exports = doctype;
|
@@ -0,0 +1,16 @@
|
|
1
|
+
const { concat, group, hardline, indent, join } = require("../../prettier");
|
2
|
+
|
3
|
+
// http://haml.info/docs/yardoc/file.REFERENCE.html#filters
|
4
|
+
const filter = (path, _opts, _print) => {
|
5
|
+
const { value } = path.getValue();
|
6
|
+
|
7
|
+
return group(
|
8
|
+
concat([
|
9
|
+
":",
|
10
|
+
value.name,
|
11
|
+
indent(concat([hardline, join(hardline, value.text.trim().split("\n"))]))
|
12
|
+
])
|
13
|
+
);
|
14
|
+
};
|
15
|
+
|
16
|
+
module.exports = filter;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
const { concat, hardline, indent, join } = require("../../prettier");
|
2
|
+
|
3
|
+
// http://haml.info/docs/yardoc/file.REFERENCE.html#haml-comments--
|
4
|
+
const hamlComment = (path, opts, _print) => {
|
5
|
+
const node = path.getValue();
|
6
|
+
const parts = ["-#"];
|
7
|
+
|
8
|
+
if (node.value.text) {
|
9
|
+
if (opts.originalText.split("\n")[node.line - 1].trim() === "-#") {
|
10
|
+
const lines = node.value.text.trim().split("\n");
|
11
|
+
|
12
|
+
parts.push(indent(concat([hardline, join(hardline, lines)])));
|
13
|
+
} else {
|
14
|
+
parts.push(" ", node.value.text.trim());
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
return concat(parts);
|
19
|
+
};
|
20
|
+
|
21
|
+
module.exports = hamlComment;
|
@@ -0,0 +1,29 @@
|
|
1
|
+
const { concat, group, hardline, indent, join } = require("../../prettier");
|
2
|
+
|
3
|
+
// http://haml.info/docs/yardoc/file.REFERENCE.html#inserting-ruby-
|
4
|
+
const script = (path, opts, print) => {
|
5
|
+
const { children, value } = path.getValue();
|
6
|
+
const parts = [];
|
7
|
+
|
8
|
+
if (value.escape_html) {
|
9
|
+
parts.unshift("&");
|
10
|
+
}
|
11
|
+
|
12
|
+
if (value.preserve) {
|
13
|
+
parts.push("~");
|
14
|
+
} else if (!value.interpolate) {
|
15
|
+
parts.push("=");
|
16
|
+
}
|
17
|
+
|
18
|
+
parts.push(" ", value.text.trim());
|
19
|
+
|
20
|
+
if (children.length > 0) {
|
21
|
+
parts.push(
|
22
|
+
indent(concat([hardline, join(hardline, path.map(print, "children"))]))
|
23
|
+
);
|
24
|
+
}
|
25
|
+
|
26
|
+
return group(concat(parts));
|
27
|
+
};
|
28
|
+
|
29
|
+
module.exports = script;
|
@@ -0,0 +1,30 @@
|
|
1
|
+
const { concat, group, hardline, indent, join } = require("../../prettier");
|
2
|
+
|
3
|
+
// http://haml.info/docs/yardoc/file.REFERENCE.html#running-ruby--
|
4
|
+
const silentScript = (path, opts, print) => {
|
5
|
+
const { children, value } = path.getValue();
|
6
|
+
const parts = [`- ${value.text.trim()}`];
|
7
|
+
|
8
|
+
if (children.length > 0) {
|
9
|
+
const scripts = path.map(print, "children");
|
10
|
+
|
11
|
+
if (value.keyword === "case") {
|
12
|
+
parts.push(
|
13
|
+
join(
|
14
|
+
"",
|
15
|
+
scripts.map((script, index) => {
|
16
|
+
const concated = concat([hardline, script]);
|
17
|
+
|
18
|
+
return index % 2 === 0 ? concated : indent(concated);
|
19
|
+
})
|
20
|
+
)
|
21
|
+
);
|
22
|
+
} else {
|
23
|
+
parts.push(indent(concat([hardline, join(hardline, scripts)])));
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
return group(concat(parts));
|
28
|
+
};
|
29
|
+
|
30
|
+
module.exports = silentScript;
|
@@ -0,0 +1,151 @@
|
|
1
|
+
const {
|
2
|
+
align,
|
3
|
+
concat,
|
4
|
+
fill,
|
5
|
+
group,
|
6
|
+
hardline,
|
7
|
+
indent,
|
8
|
+
join,
|
9
|
+
line,
|
10
|
+
softline
|
11
|
+
} = require("../../prettier");
|
12
|
+
|
13
|
+
const getDynamicAttributes = (header, attributes) => {
|
14
|
+
const pairs = attributes
|
15
|
+
.slice(1, -2)
|
16
|
+
.split(",")
|
17
|
+
.map(pair => pair.slice(1).split('" => '));
|
18
|
+
const parts = [concat([pairs[0][0], "=", pairs[0][1]])];
|
19
|
+
|
20
|
+
pairs.slice(1).forEach(pair => {
|
21
|
+
parts.push(line, concat([pair[0], "=", pair[1]]));
|
22
|
+
});
|
23
|
+
|
24
|
+
return group(concat(["(", align(header + 1, fill(parts)), ")"]));
|
25
|
+
};
|
26
|
+
|
27
|
+
const getHashValue = (value, opts) => {
|
28
|
+
if (typeof value === "string") {
|
29
|
+
const quote = opts.preferSingleQuotes ? "'" : '"';
|
30
|
+
return `${quote}${value}${quote}`;
|
31
|
+
}
|
32
|
+
|
33
|
+
return value;
|
34
|
+
};
|
35
|
+
|
36
|
+
const getHashRocket = (key, value, opts) => {
|
37
|
+
const quote = opts.preferSingleQuotes ? "'" : '"';
|
38
|
+
const leftSide = key.includes(":") ? `:${quote}${key}${quote}` : `:${key}`;
|
39
|
+
|
40
|
+
return `${leftSide} => ${getHashValue(value, opts)}`;
|
41
|
+
};
|
42
|
+
|
43
|
+
const getHashLabel = (key, value, opts) => {
|
44
|
+
const quote = opts.preferSingleQuotes ? "'" : '"';
|
45
|
+
const leftSide = key.includes(":") ? `${quote}${key}${quote}` : key;
|
46
|
+
|
47
|
+
return `${leftSide}: ${getHashValue(value, opts)}`;
|
48
|
+
};
|
49
|
+
|
50
|
+
const getStaticAttributes = (header, attributes, opts) => {
|
51
|
+
const keys = Object.keys(attributes).filter(
|
52
|
+
name => !["class", "id"].includes(name)
|
53
|
+
);
|
54
|
+
|
55
|
+
const getKeyValuePair = opts.preferHashLabels ? getHashLabel : getHashRocket;
|
56
|
+
const parts = [getKeyValuePair(keys[0], attributes[keys[0]], opts)];
|
57
|
+
|
58
|
+
keys.slice(1).forEach(key => {
|
59
|
+
parts.push(",", line, getKeyValuePair(key, attributes[key], opts));
|
60
|
+
});
|
61
|
+
|
62
|
+
return group(concat(["{", align(header + 1, fill(parts)), "}"]));
|
63
|
+
};
|
64
|
+
|
65
|
+
const getHeader = (value, opts) => {
|
66
|
+
const { attributes } = value;
|
67
|
+
const parts = [];
|
68
|
+
|
69
|
+
if (value.name !== "div") {
|
70
|
+
parts.push(`%${value.name}`);
|
71
|
+
}
|
72
|
+
|
73
|
+
if (attributes.class) {
|
74
|
+
parts.push(`.${attributes.class.replace(" ", ".")}`);
|
75
|
+
}
|
76
|
+
|
77
|
+
if (attributes.id) {
|
78
|
+
parts.push(`#${attributes.id}`);
|
79
|
+
}
|
80
|
+
|
81
|
+
if (value.dynamic_attributes.new) {
|
82
|
+
parts.push(
|
83
|
+
getDynamicAttributes(parts.join("").length, value.dynamic_attributes.new)
|
84
|
+
);
|
85
|
+
}
|
86
|
+
|
87
|
+
if (Object.keys(attributes).some(name => name !== "class" && name !== "id")) {
|
88
|
+
parts.push(getStaticAttributes(parts.join("").length, attributes, opts));
|
89
|
+
}
|
90
|
+
|
91
|
+
if (value.dynamic_attributes.old) {
|
92
|
+
parts.push(value.dynamic_attributes.old);
|
93
|
+
}
|
94
|
+
|
95
|
+
if (value.object_ref) {
|
96
|
+
if (parts.length === 0) {
|
97
|
+
parts.push("%div");
|
98
|
+
}
|
99
|
+
parts.push(value.object_ref);
|
100
|
+
}
|
101
|
+
|
102
|
+
if (value.nuke_outer_whitespace) {
|
103
|
+
parts.push(">");
|
104
|
+
}
|
105
|
+
|
106
|
+
if (value.nuke_inner_whitespace) {
|
107
|
+
parts.push("<");
|
108
|
+
}
|
109
|
+
|
110
|
+
if (value.self_closing) {
|
111
|
+
parts.push("/");
|
112
|
+
}
|
113
|
+
|
114
|
+
if (value.value) {
|
115
|
+
const prefix = value.parse ? "=" : "";
|
116
|
+
|
117
|
+
return group(
|
118
|
+
concat([
|
119
|
+
group(concat(parts)),
|
120
|
+
indent(concat([softline, `${prefix} ${value.value}`]))
|
121
|
+
])
|
122
|
+
);
|
123
|
+
}
|
124
|
+
|
125
|
+
// In case none of the other if statements have matched and we're printing a
|
126
|
+
// div, we need to explicitly add it back into the array.
|
127
|
+
if (parts.length === 0 && value.name === "div") {
|
128
|
+
parts.push("%div");
|
129
|
+
}
|
130
|
+
|
131
|
+
return group(concat(parts));
|
132
|
+
};
|
133
|
+
|
134
|
+
// http://haml.info/docs/yardoc/file.REFERENCE.html#element-name-
|
135
|
+
const tag = (path, opts, print) => {
|
136
|
+
const { children, value } = path.getValue();
|
137
|
+
const header = getHeader(value, opts);
|
138
|
+
|
139
|
+
if (children.length === 0) {
|
140
|
+
return header;
|
141
|
+
}
|
142
|
+
|
143
|
+
return group(
|
144
|
+
concat([
|
145
|
+
header,
|
146
|
+
indent(concat([hardline, join(hardline, path.map(print, "children"))]))
|
147
|
+
])
|
148
|
+
);
|
149
|
+
};
|
150
|
+
|
151
|
+
module.exports = tag;
|
data/src/haml/parse.js
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
const { spawnSync } = require("child_process");
|
2
|
+
const path = require("path");
|
3
|
+
|
4
|
+
const parse = (text, _parsers, _opts) => {
|
5
|
+
const child = spawnSync("ruby", [path.join(__dirname, "./parse.rb")], {
|
6
|
+
input: text
|
7
|
+
});
|
8
|
+
|
9
|
+
const error = child.stderr.toString();
|
10
|
+
if (error) {
|
11
|
+
throw new Error(error);
|
12
|
+
}
|
13
|
+
|
14
|
+
const response = child.stdout.toString();
|
15
|
+
return JSON.parse(response);
|
16
|
+
};
|
17
|
+
|
18
|
+
module.exports = parse;
|
data/src/haml/parse.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'haml'
|
5
|
+
|
6
|
+
class Haml::Parser::ParseNode
|
7
|
+
ESCAPE = /Haml::Helpers.html_escape\(\((.+)\)\)/.freeze
|
8
|
+
|
9
|
+
def as_json
|
10
|
+
case type
|
11
|
+
when :comment, :doctype, :plain, :silent_script
|
12
|
+
to_h.tap do |json|
|
13
|
+
json.delete(:parent)
|
14
|
+
json[:children] = children.map(&:as_json)
|
15
|
+
end
|
16
|
+
when :filter, :haml_comment
|
17
|
+
to_h.tap { |json| json.delete(:parent) }
|
18
|
+
when :root
|
19
|
+
to_h.tap { |json| json[:children] = children.map(&:as_json) }
|
20
|
+
when :script
|
21
|
+
to_h.tap do |json|
|
22
|
+
json.delete(:parent)
|
23
|
+
json[:children] = children.map(&:as_json)
|
24
|
+
|
25
|
+
if json[:value][:text].match?(ESCAPE)
|
26
|
+
json[:value][:text].gsub!(ESCAPE) { $1 }
|
27
|
+
json[:value].merge!(escape_html: 'escape_html', interpolate: true)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
when :tag
|
31
|
+
to_h.tap do |json|
|
32
|
+
json.delete(:parent)
|
33
|
+
|
34
|
+
# For some reason this is actually using a symbol to represent a null
|
35
|
+
# object ref instead of nil itself, so just replacing it here for
|
36
|
+
# simplicity in the printer
|
37
|
+
json[:value][:object_ref] = nil if json[:value][:object_ref] == :nil
|
38
|
+
|
39
|
+
json.merge!(
|
40
|
+
children: children.map(&:as_json),
|
41
|
+
value:
|
42
|
+
value.merge(dynamic_attributes: value[:dynamic_attributes].to_h)
|
43
|
+
)
|
44
|
+
end
|
45
|
+
else
|
46
|
+
raise ArgumentError, "Unsupported type: #{type}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.to_json(template)
|
51
|
+
parser = Haml::Parser.new({})
|
52
|
+
JSON.fast_generate(parser.call(template).as_json)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# If this is the main file we're executing, then most likely this is being
|
57
|
+
# executed from the haml.js spawn. In that case, read the ruby source from
|
58
|
+
# stdin and report back the AST over stdout.
|
59
|
+
|
60
|
+
if $0 == __FILE__
|
61
|
+
parser = Haml::Parser.new({})
|
62
|
+
template = $stdin.read
|
63
|
+
|
64
|
+
puts JSON.fast_generate(parser.call(template).as_json)
|
65
|
+
end
|