rfbeam 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.rubocop.yml +11 -0
- data/.tool-versions +1 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +63 -0
- data/LICENSE.txt +21 -0
- data/README.md +45 -0
- data/Rakefile +16 -0
- data/lib/rfbeam/kld7/commands.rb +89 -0
- data/lib/rfbeam/kld7/detection.rb +32 -0
- data/lib/rfbeam/kld7/device_data.rb +33 -0
- data/lib/rfbeam/version.rb +5 -0
- data/lib/rfbeam.rb +28 -0
- data/node_modules/.bin/prettier +1 -0
- data/node_modules/.yarn-integrity +19 -0
- data/node_modules/@prettier/plugin-ruby/CHANGELOG.md +1351 -0
- data/node_modules/@prettier/plugin-ruby/CODE_OF_CONDUCT.md +76 -0
- data/node_modules/@prettier/plugin-ruby/CONTRIBUTING.md +185 -0
- data/node_modules/@prettier/plugin-ruby/LICENSE +21 -0
- data/node_modules/@prettier/plugin-ruby/README.md +226 -0
- data/node_modules/@prettier/plugin-ruby/docs/logo.png +0 -0
- data/node_modules/@prettier/plugin-ruby/node_modules/.bin/prettier +1 -0
- data/node_modules/@prettier/plugin-ruby/package.json +64 -0
- data/node_modules/@prettier/plugin-ruby/prettier.gemspec +36 -0
- data/node_modules/@prettier/plugin-ruby/rubocop.yml +64 -0
- data/node_modules/@prettier/plugin-ruby/src/getInfo.js +23 -0
- data/node_modules/@prettier/plugin-ruby/src/netcat.js +13 -0
- data/node_modules/@prettier/plugin-ruby/src/parseSync.js +236 -0
- data/node_modules/@prettier/plugin-ruby/src/plugin.js +172 -0
- data/node_modules/@prettier/plugin-ruby/src/server.rb +199 -0
- data/node_modules/prettier/LICENSE +5945 -0
- data/node_modules/prettier/README.md +109 -0
- data/node_modules/prettier/bin-prettier.js +62 -0
- data/node_modules/prettier/cli.js +15136 -0
- data/node_modules/prettier/doc.js +1473 -0
- data/node_modules/prettier/esm/parser-angular.mjs +2 -0
- data/node_modules/prettier/esm/parser-babel.mjs +29 -0
- data/node_modules/prettier/esm/parser-espree.mjs +26 -0
- data/node_modules/prettier/esm/parser-flow.mjs +35 -0
- data/node_modules/prettier/esm/parser-glimmer.mjs +27 -0
- data/node_modules/prettier/esm/parser-graphql.mjs +15 -0
- data/node_modules/prettier/esm/parser-html.mjs +36 -0
- data/node_modules/prettier/esm/parser-markdown.mjs +76 -0
- data/node_modules/prettier/esm/parser-meriyah.mjs +19 -0
- data/node_modules/prettier/esm/parser-postcss.mjs +76 -0
- data/node_modules/prettier/esm/parser-typescript.mjs +257 -0
- data/node_modules/prettier/esm/parser-yaml.mjs +150 -0
- data/node_modules/prettier/esm/standalone.mjs +116 -0
- data/node_modules/prettier/index.js +37885 -0
- data/node_modules/prettier/package.json +21 -0
- data/node_modules/prettier/parser-angular.js +2 -0
- data/node_modules/prettier/parser-babel.js +29 -0
- data/node_modules/prettier/parser-espree.js +26 -0
- data/node_modules/prettier/parser-flow.js +35 -0
- data/node_modules/prettier/parser-glimmer.js +27 -0
- data/node_modules/prettier/parser-graphql.js +15 -0
- data/node_modules/prettier/parser-html.js +36 -0
- data/node_modules/prettier/parser-markdown.js +76 -0
- data/node_modules/prettier/parser-meriyah.js +19 -0
- data/node_modules/prettier/parser-postcss.js +76 -0
- data/node_modules/prettier/parser-typescript.js +257 -0
- data/node_modules/prettier/parser-yaml.js +150 -0
- data/node_modules/prettier/standalone.js +116 -0
- data/node_modules/prettier/third-party.js +8978 -0
- data/package.json +6 -0
- data/sig/rfbeam.rbs +4 -0
- data/yarn.lock +15 -0
- metadata +156 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
# Disabling all Layout/* rules, as they're unnecessary when the user is using
|
2
|
+
# Syntax Tree to handle all of the formatting.
|
3
|
+
Layout:
|
4
|
+
Enabled: false
|
5
|
+
|
6
|
+
# Re-enable Layout/LineLength because certain cops that most projects use
|
7
|
+
# (e.g. Style/IfUnlessModifier) require Layout/LineLength to be enabled.
|
8
|
+
# By leaving it disabled, those rules will mis-fire.
|
9
|
+
#
|
10
|
+
# Users can always override these defaults in their own rubocop.yml files.
|
11
|
+
# https://github.com/prettier/plugin-ruby/issues/825
|
12
|
+
Layout/LineLength:
|
13
|
+
Enabled: true
|
14
|
+
|
15
|
+
Style/MultilineIfModifier:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
# Syntax Tree will expand empty methods to put the end keyword on the subsequent
|
19
|
+
# line to reduce git diff noise.
|
20
|
+
Style/EmptyMethod:
|
21
|
+
EnforcedStyle: expanded
|
22
|
+
|
23
|
+
# lambdas that are constructed with the lambda method call cannot be safely
|
24
|
+
# turned into lambda literals without removing a method call.
|
25
|
+
Style/Lambda:
|
26
|
+
Enabled: false
|
27
|
+
|
28
|
+
# When method chains with multiple blocks are chained together, rubocop will let
|
29
|
+
# them pass if they're using braces but not if they're using do and end
|
30
|
+
# keywords. Because we will break individual blocks down to using keywords if
|
31
|
+
# they are multiline, this conflicts with rubocop.
|
32
|
+
Style/MultilineBlockChain:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
# Disable the single- vs double-quotes rules as these depend on whether the user
|
36
|
+
# has added or not `plugin/single_quotes` for `syntax_tree`
|
37
|
+
Style/StringLiterals:
|
38
|
+
Enabled: false
|
39
|
+
|
40
|
+
Style/StringLiteralsInInterpolation:
|
41
|
+
Enabled: false
|
42
|
+
|
43
|
+
Style/QuotedSymbols:
|
44
|
+
Enabled: false
|
45
|
+
|
46
|
+
# We let users have a little more freedom with symbol and words arrays. If the
|
47
|
+
# user only has an individual item like ["value"] then we don't bother
|
48
|
+
# converting it because it ends up being just noise.
|
49
|
+
Style/SymbolArray:
|
50
|
+
Enabled: false
|
51
|
+
|
52
|
+
Style/WordArray:
|
53
|
+
Enabled: false
|
54
|
+
|
55
|
+
# Disable the trailing-comma rules as these depend on whether the user has added
|
56
|
+
# or not `plugin/trailing_comma` for `syntax_tree`
|
57
|
+
Style/TrailingCommaInArguments:
|
58
|
+
Enabled: false
|
59
|
+
|
60
|
+
Style/TrailingCommaInArrayLiteral:
|
61
|
+
Enabled: false
|
62
|
+
|
63
|
+
Style/TrailingCommaInHashLiteral:
|
64
|
+
Enabled: false
|
@@ -0,0 +1,23 @@
|
|
1
|
+
const { existsSync, readFileSync } = require("fs");
|
2
|
+
|
3
|
+
// This is how long to wait for the parser to spin up. For the most part, 5
|
4
|
+
// seconds is plenty of time. But in some environments, it may be necessary to
|
5
|
+
// increase this value.
|
6
|
+
const timeoutMs = parseInt(process.env.PRETTIER_RUBY_TIMEOUT_MS || "5000", 10);
|
7
|
+
|
8
|
+
const filepath = process.argv[process.argv.length - 1];
|
9
|
+
|
10
|
+
const timeout = setTimeout(() => {
|
11
|
+
clearInterval(interval);
|
12
|
+
throw new Error(`Failed to get information from parse server in time. If this
|
13
|
+
happens repeatedly, try increasing the PRETTIER_RUBY_TIMEOUT_MS environment
|
14
|
+
variable beyond 5000.`);
|
15
|
+
}, timeoutMs);
|
16
|
+
|
17
|
+
const interval = setInterval(() => {
|
18
|
+
if (existsSync(filepath)) {
|
19
|
+
process.stdout.write(readFileSync(filepath).toString("utf8"));
|
20
|
+
clearTimeout(timeout);
|
21
|
+
clearInterval(interval);
|
22
|
+
}
|
23
|
+
}, 100);
|
@@ -0,0 +1,13 @@
|
|
1
|
+
// A simple fallback when no netcat-compatible adapter is found on the system.
|
2
|
+
// On average, this is 2-3x slower than netcat, but still much faster than
|
3
|
+
// spawning a new Ruby process.
|
4
|
+
|
5
|
+
const { createConnection } = require("net");
|
6
|
+
|
7
|
+
const sock = process.argv[process.argv.length - 1];
|
8
|
+
const client = createConnection(sock, () => process.stdin.pipe(client));
|
9
|
+
|
10
|
+
client.on("data", (data) => process.stdout.write(data));
|
11
|
+
client.on("error", (error) => {
|
12
|
+
console.error(error);
|
13
|
+
});
|
@@ -0,0 +1,236 @@
|
|
1
|
+
const { spawn, spawnSync } = require("child_process");
|
2
|
+
const {
|
3
|
+
existsSync,
|
4
|
+
unlinkSync,
|
5
|
+
mkdtempSync,
|
6
|
+
copyFileSync,
|
7
|
+
mkdirSync,
|
8
|
+
rmdirSync
|
9
|
+
} = require("fs");
|
10
|
+
const os = require("os");
|
11
|
+
const path = require("path");
|
12
|
+
const process = require("process");
|
13
|
+
|
14
|
+
let parserArgs;
|
15
|
+
|
16
|
+
if (process.env.PRETTIER_RUBY_HOST) {
|
17
|
+
const [cmd, ...args] = process.env.PRETTIER_RUBY_HOST.split(" ");
|
18
|
+
parserArgs = { cmd, args };
|
19
|
+
}
|
20
|
+
|
21
|
+
// In order to properly parse ruby code, we need to tell the ruby process to
|
22
|
+
// parse using UTF-8. Unfortunately, the way that you accomplish this looks
|
23
|
+
// differently depending on your platform.
|
24
|
+
/* istanbul ignore next */
|
25
|
+
function getLang() {
|
26
|
+
const { env, platform } = process;
|
27
|
+
const envValue = env.LC_ALL || env.LC_CTYPE || env.LANG;
|
28
|
+
|
29
|
+
// If an env var is set for the locale that already includes UTF-8 in the
|
30
|
+
// name, then assume we can go with that.
|
31
|
+
if (envValue && envValue.includes("UTF-8")) {
|
32
|
+
return envValue;
|
33
|
+
}
|
34
|
+
|
35
|
+
// Otherwise, we're going to guess which encoding to use based on the system.
|
36
|
+
// This is probably not the best approach in the world, as you could be on
|
37
|
+
// linux and not have C.UTF-8, but in that case you're probably passing an env
|
38
|
+
// var for it. This object below represents all of the possible values of
|
39
|
+
// process.platform per:
|
40
|
+
// https://nodejs.org/api/process.html#process_process_platform
|
41
|
+
return {
|
42
|
+
aix: "C.UTF-8",
|
43
|
+
android: "C.UTF-8",
|
44
|
+
cygwin: "C.UTF-8",
|
45
|
+
darwin: "en_US.UTF-8",
|
46
|
+
freebsd: "C.UTF-8",
|
47
|
+
haiku: "C.UTF-8",
|
48
|
+
linux: "C.UTF-8",
|
49
|
+
netbsd: "C.UTF-8",
|
50
|
+
openbsd: "C.UTF-8",
|
51
|
+
sunos: "C.UTF-8",
|
52
|
+
win32: ".UTF-8"
|
53
|
+
}[platform];
|
54
|
+
}
|
55
|
+
|
56
|
+
// Generate the filepath that should be used to communicate the connection
|
57
|
+
// information between this process and the parser server.
|
58
|
+
function getInfoFilepath() {
|
59
|
+
return path.join(os.tmpdir(), `prettier-ruby-parser-${process.pid}.info`);
|
60
|
+
}
|
61
|
+
|
62
|
+
// Return the list of plugins that should be passed to the server process.
|
63
|
+
function getPlugins(opts) {
|
64
|
+
const plugins = new Set();
|
65
|
+
|
66
|
+
const rubyPlugins = opts.rubyPlugins.trim();
|
67
|
+
if (rubyPlugins.length > 0) {
|
68
|
+
rubyPlugins.split(",").forEach((plugin) => plugins.add(plugin.trim()));
|
69
|
+
}
|
70
|
+
|
71
|
+
if (opts.singleQuote) {
|
72
|
+
plugins.add("plugin/single_quotes");
|
73
|
+
}
|
74
|
+
|
75
|
+
if (opts.trailingComma !== "none") {
|
76
|
+
plugins.add("plugin/trailing_comma");
|
77
|
+
}
|
78
|
+
|
79
|
+
return Array.from(plugins);
|
80
|
+
}
|
81
|
+
|
82
|
+
// Create a file that will act as a communication mechanism, spawn a parser
|
83
|
+
// server with that filepath as an argument, then spawn another process that
|
84
|
+
// will read that information in order to enable us to connect to it in the
|
85
|
+
// spawnSync function.
|
86
|
+
function spawnServer(opts) {
|
87
|
+
const tempDir = mkdtempSync(path.join(os.tmpdir(), "prettier-plugin-ruby-"));
|
88
|
+
const filepath = getInfoFilepath();
|
89
|
+
|
90
|
+
let serverRbPath = path.join(__dirname, "./server.rb");
|
91
|
+
let getInfoJsPath = path.join(__dirname, "./getInfo.js");
|
92
|
+
let cleanupTempFiles;
|
93
|
+
|
94
|
+
if (runningInPnPZip()) {
|
95
|
+
// If we're running in a Yarn PnP environment inside a ZIP file, it's not possible to run
|
96
|
+
// the Ruby server or the getInfo.js script directly. Instead, we need to copy them and all
|
97
|
+
// the files they depend on to a temporary directory.
|
98
|
+
|
99
|
+
const sourceFiles = ["server.rb", "getInfo.js", "netcat.js"];
|
100
|
+
serverRbPath = path.join(tempDir, "server.rb");
|
101
|
+
getInfoJsPath = path.join(tempDir, "getInfo.js");
|
102
|
+
|
103
|
+
sourceFiles.forEach((rubyFile) => {
|
104
|
+
const destDir = path.join(tempDir, path.dirname(rubyFile));
|
105
|
+
if (!existsSync(destDir)) {
|
106
|
+
mkdirSync(destDir);
|
107
|
+
}
|
108
|
+
copyFileSync(
|
109
|
+
path.join(__dirname, "..", "src", rubyFile),
|
110
|
+
path.join(tempDir, rubyFile)
|
111
|
+
);
|
112
|
+
});
|
113
|
+
|
114
|
+
cleanupTempFiles = () => {
|
115
|
+
[
|
116
|
+
getInfoJsPath,
|
117
|
+
...sourceFiles.map((rubyFile) => path.join(tempDir, rubyFile))
|
118
|
+
].forEach((tmpFilePath) => {
|
119
|
+
if (existsSync(tmpFilePath)) {
|
120
|
+
unlinkSync(tmpFilePath);
|
121
|
+
}
|
122
|
+
});
|
123
|
+
|
124
|
+
sourceFiles.forEach((rubyFile) => {
|
125
|
+
const tempSubdir = path.join(tempDir, path.dirname(rubyFile));
|
126
|
+
if (existsSync(tempSubdir)) {
|
127
|
+
rmdirSync(tempSubdir);
|
128
|
+
}
|
129
|
+
});
|
130
|
+
|
131
|
+
if (existsSync(tempDir)) {
|
132
|
+
rmdirSync(tempDir);
|
133
|
+
}
|
134
|
+
};
|
135
|
+
}
|
136
|
+
|
137
|
+
const server = spawn(
|
138
|
+
"ruby",
|
139
|
+
[serverRbPath, `--plugins=${getPlugins(opts).join(",")}`, filepath],
|
140
|
+
{
|
141
|
+
env: Object.assign({}, process.env, { LANG: getLang() }),
|
142
|
+
detached: true,
|
143
|
+
stdio: "inherit"
|
144
|
+
}
|
145
|
+
);
|
146
|
+
|
147
|
+
server.unref();
|
148
|
+
process.on("exit", () => {
|
149
|
+
if (existsSync(filepath)) {
|
150
|
+
unlinkSync(filepath);
|
151
|
+
}
|
152
|
+
|
153
|
+
if (cleanupTempFiles != null) {
|
154
|
+
cleanupTempFiles();
|
155
|
+
}
|
156
|
+
|
157
|
+
try {
|
158
|
+
if (server.pid) {
|
159
|
+
// Kill the server process if it's still running. If we're on windows
|
160
|
+
// we're going to use the process ID number. If we're not, we're going
|
161
|
+
// to use the negative process ID to indicate the group.
|
162
|
+
const pid = process.platform === "win32" ? server.pid : -server.pid;
|
163
|
+
process.kill(pid);
|
164
|
+
}
|
165
|
+
} catch (e) {
|
166
|
+
if (process.env.PLUGIN_RUBY_CI) {
|
167
|
+
throw new Error(`Failed to kill the parser server: ${e}`);
|
168
|
+
}
|
169
|
+
}
|
170
|
+
});
|
171
|
+
|
172
|
+
const info = spawnSync("node", [getInfoJsPath, filepath]);
|
173
|
+
|
174
|
+
if (info.status !== 0) {
|
175
|
+
throw new Error(`
|
176
|
+
We failed to spawn our parser server. Please report this error on GitHub
|
177
|
+
at https://github.com/prettier/plugin-ruby. The error message was:
|
178
|
+
|
179
|
+
${info.stderr.toString()}.
|
180
|
+
`);
|
181
|
+
}
|
182
|
+
|
183
|
+
const [cmd, ...args] = info.stdout.toString().split(" ");
|
184
|
+
return { cmd, args };
|
185
|
+
}
|
186
|
+
|
187
|
+
// If we're in a yarn Plug'n'Play environment, then the relative paths being
|
188
|
+
// used by the parser server and the various scripts used to communicate
|
189
|
+
// therein are not going to work with its virtual file system.
|
190
|
+
function runningInPnPZip() {
|
191
|
+
return process.versions.pnp && __dirname.includes(".zip");
|
192
|
+
}
|
193
|
+
|
194
|
+
// Formats and sends a request to the parser server. We use netcat (or something
|
195
|
+
// like it) here since Prettier requires the results of `parse` to be
|
196
|
+
// synchronous and Node.js does not offer a mechanism for synchronous socket
|
197
|
+
// requests.
|
198
|
+
function parseSync(parser, source, opts) {
|
199
|
+
if (!parserArgs) {
|
200
|
+
parserArgs = spawnServer(opts);
|
201
|
+
}
|
202
|
+
|
203
|
+
const response = spawnSync(parserArgs.cmd, parserArgs.args, {
|
204
|
+
input: `${parser}|${opts.printWidth}|${opts.tabWidth}|${source}`,
|
205
|
+
maxBuffer: 15 * 1024 * 1024
|
206
|
+
});
|
207
|
+
|
208
|
+
const stdout = response.stdout.toString();
|
209
|
+
const stderr = response.stderr.toString();
|
210
|
+
const { status } = response;
|
211
|
+
|
212
|
+
// If we didn't receive anything over stdout or we have a bad exit status,
|
213
|
+
// then throw whatever we can.
|
214
|
+
if (stdout.length === 0 || (status !== null && status !== 0)) {
|
215
|
+
throw new Error(stderr || "An unknown error occurred");
|
216
|
+
}
|
217
|
+
|
218
|
+
const parsed = JSON.parse(stdout);
|
219
|
+
|
220
|
+
if (parsed.error) {
|
221
|
+
const error = new Error(parsed.error);
|
222
|
+
if (parsed.loc) {
|
223
|
+
error.loc = parsed.loc;
|
224
|
+
}
|
225
|
+
|
226
|
+
throw error;
|
227
|
+
}
|
228
|
+
|
229
|
+
return parsed;
|
230
|
+
}
|
231
|
+
|
232
|
+
module.exports = {
|
233
|
+
getLang,
|
234
|
+
getInfoFilepath,
|
235
|
+
parseSync
|
236
|
+
};
|
@@ -0,0 +1,172 @@
|
|
1
|
+
const { parseSync } = require("./parseSync");
|
2
|
+
|
3
|
+
/*
|
4
|
+
* metadata mostly pulled from linguist and rubocop:
|
5
|
+
* https://github.com/github/linguist/blob/master/lib/linguist/languages.yml
|
6
|
+
* https://github.com/rubocop/rubocop/blob/master/spec/rubocop/target_finder_spec.rb
|
7
|
+
*/
|
8
|
+
const plugin = {
|
9
|
+
languages: [
|
10
|
+
{
|
11
|
+
name: "Ruby",
|
12
|
+
parsers: ["ruby"],
|
13
|
+
extensions: [
|
14
|
+
".arb",
|
15
|
+
".axlsx",
|
16
|
+
".builder",
|
17
|
+
".eye",
|
18
|
+
".fcgi",
|
19
|
+
".gemfile",
|
20
|
+
".gemspec",
|
21
|
+
".god",
|
22
|
+
".jb",
|
23
|
+
".jbuilder",
|
24
|
+
".mspec",
|
25
|
+
".opal",
|
26
|
+
".pluginspec",
|
27
|
+
".podspec",
|
28
|
+
".rabl",
|
29
|
+
".rake",
|
30
|
+
".rb",
|
31
|
+
".rbi",
|
32
|
+
".rbuild",
|
33
|
+
".rbw",
|
34
|
+
".rbx",
|
35
|
+
".ru",
|
36
|
+
".ruby",
|
37
|
+
".thor",
|
38
|
+
".watchr"
|
39
|
+
],
|
40
|
+
filenames: [
|
41
|
+
".irbrc",
|
42
|
+
".pryrc",
|
43
|
+
".simplecov",
|
44
|
+
"Appraisals",
|
45
|
+
"Berksfile",
|
46
|
+
"Brewfile",
|
47
|
+
"Buildfile",
|
48
|
+
"Capfile",
|
49
|
+
"Cheffile",
|
50
|
+
"Dangerfile",
|
51
|
+
"Deliverfile",
|
52
|
+
"Fastfile",
|
53
|
+
"Gemfile",
|
54
|
+
"Guardfile",
|
55
|
+
"Jarfile",
|
56
|
+
"Mavenfile",
|
57
|
+
"Podfile",
|
58
|
+
"Puppetfile",
|
59
|
+
"Rakefile",
|
60
|
+
"Snapfile",
|
61
|
+
"Thorfile",
|
62
|
+
"Vagabondfile",
|
63
|
+
"Vagrantfile",
|
64
|
+
"buildfile"
|
65
|
+
],
|
66
|
+
interpreters: ["jruby", "macruby", "rake", "rbx", "ruby"],
|
67
|
+
linguistLanguageId: 326,
|
68
|
+
vscodeLanguageIds: ["ruby"]
|
69
|
+
},
|
70
|
+
{
|
71
|
+
name: "RBS",
|
72
|
+
parsers: ["rbs"],
|
73
|
+
extensions: [".rbs"]
|
74
|
+
},
|
75
|
+
{
|
76
|
+
name: "HAML",
|
77
|
+
parsers: ["haml"],
|
78
|
+
extensions: [".haml"],
|
79
|
+
vscodeLanguageIds: ["haml"]
|
80
|
+
}
|
81
|
+
],
|
82
|
+
parsers: {
|
83
|
+
ruby: {
|
84
|
+
parse(text, _parsers, opts) {
|
85
|
+
return parseSync("ruby", text, opts);
|
86
|
+
},
|
87
|
+
astFormat: "ruby",
|
88
|
+
hasPragma(text) {
|
89
|
+
return /^\s*#[^\S\n]*@(?:prettier|format)\s*?(?:\n|$)/m.test(text);
|
90
|
+
},
|
91
|
+
locStart() {
|
92
|
+
return 0;
|
93
|
+
},
|
94
|
+
locEnd() {
|
95
|
+
return 0;
|
96
|
+
}
|
97
|
+
},
|
98
|
+
rbs: {
|
99
|
+
parse(text, _parsers, opts) {
|
100
|
+
return parseSync("rbs", text, opts);
|
101
|
+
},
|
102
|
+
astFormat: "rbs",
|
103
|
+
hasPragma(text) {
|
104
|
+
return /^\s*#[^\S\n]*@(prettier|format)\s*(\n|$)/.test(text);
|
105
|
+
},
|
106
|
+
locStart() {
|
107
|
+
return 0;
|
108
|
+
},
|
109
|
+
locEnd() {
|
110
|
+
return 0;
|
111
|
+
}
|
112
|
+
},
|
113
|
+
haml: {
|
114
|
+
parse(text, _parsers, opts) {
|
115
|
+
return parseSync("haml", text, opts);
|
116
|
+
},
|
117
|
+
astFormat: "haml",
|
118
|
+
hasPragma(text) {
|
119
|
+
return /^\s*-#\s*@(prettier|format)/.test(text);
|
120
|
+
},
|
121
|
+
locStart() {
|
122
|
+
return 0;
|
123
|
+
},
|
124
|
+
locEnd() {
|
125
|
+
return 0;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
},
|
129
|
+
printers: {
|
130
|
+
ruby: {
|
131
|
+
print(path) {
|
132
|
+
return path.getValue();
|
133
|
+
},
|
134
|
+
insertPragma(text) {
|
135
|
+
return `# @format${text.startsWith("#") ? "\n" : "\n\n"}${text}`;
|
136
|
+
}
|
137
|
+
},
|
138
|
+
rbs: {
|
139
|
+
print(path) {
|
140
|
+
return path.getValue();
|
141
|
+
},
|
142
|
+
insertPragma(text) {
|
143
|
+
return `# @format${text.startsWith("#") ? "\n" : "\n\n"}${text}`;
|
144
|
+
}
|
145
|
+
},
|
146
|
+
haml: {
|
147
|
+
print(path) {
|
148
|
+
return path.getValue();
|
149
|
+
},
|
150
|
+
insertPragma(text) {
|
151
|
+
return `-# @format${text.startsWith("-#") ? "\n" : "\n\n"}${text}`;
|
152
|
+
}
|
153
|
+
}
|
154
|
+
},
|
155
|
+
options: {
|
156
|
+
rubyPlugins: {
|
157
|
+
type: "string",
|
158
|
+
category: "Ruby",
|
159
|
+
default: "",
|
160
|
+
description: "The comma-separated list of plugins to require",
|
161
|
+
since: "3.1.0"
|
162
|
+
}
|
163
|
+
},
|
164
|
+
defaultOptions: {
|
165
|
+
printWidth: 80,
|
166
|
+
tabWidth: 2,
|
167
|
+
trailingComma: "none",
|
168
|
+
singleQuote: false
|
169
|
+
}
|
170
|
+
};
|
171
|
+
|
172
|
+
module.exports = plugin;
|
@@ -0,0 +1,199 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "socket"
|
5
|
+
require "json"
|
6
|
+
require "fileutils"
|
7
|
+
require "open3"
|
8
|
+
|
9
|
+
require "prettier_print"
|
10
|
+
require "syntax_tree"
|
11
|
+
require "syntax_tree/haml"
|
12
|
+
require "syntax_tree/rbs"
|
13
|
+
|
14
|
+
# First, require all of the plugins that the user specified.
|
15
|
+
ARGV.shift[/^--plugins=(.*)$/, 1]
|
16
|
+
.split(",")
|
17
|
+
.each { |plugin| require "syntax_tree/#{plugin}" }
|
18
|
+
|
19
|
+
# Make sure we trap these signals to be sure we get the quit command coming from
|
20
|
+
# the parent node process
|
21
|
+
quit = false
|
22
|
+
trap(:INT) { quit = true }
|
23
|
+
trap(:TERM) { quit = true }
|
24
|
+
|
25
|
+
if Signal.list.key?("QUIT") && RUBY_ENGINE != "jruby"
|
26
|
+
trap(:QUIT) { quit = true }
|
27
|
+
end
|
28
|
+
|
29
|
+
# The information variable stores the actual connection information, which will
|
30
|
+
# either be an IP address and port or a path to a unix socket file.
|
31
|
+
information = ""
|
32
|
+
|
33
|
+
# The candidates array is a list of potential programs that could be used to
|
34
|
+
# connect to our server. We'll run through them after the server starts to find
|
35
|
+
# the best one to use.
|
36
|
+
candidates = []
|
37
|
+
|
38
|
+
if Gem.win_platform?
|
39
|
+
# If we're on windows, we're going to start up a TCP server. The 0 here means
|
40
|
+
# to bind to some available port.
|
41
|
+
server = TCPServer.new("127.0.0.1", 0)
|
42
|
+
address = server.local_address
|
43
|
+
|
44
|
+
# Ensure that we close the server when this process exits.
|
45
|
+
at_exit { server.close }
|
46
|
+
|
47
|
+
information = "#{address.ip_address} #{address.ip_port}"
|
48
|
+
candidates = %w[nc telnet]
|
49
|
+
else
|
50
|
+
# If we're not on windows, then we're going to assume we can use unix socket
|
51
|
+
# files (since they're faster than a TCP server).
|
52
|
+
filepath = "/tmp/prettier-ruby-parser-#{Process.pid}.sock"
|
53
|
+
server = UNIXServer.new(filepath)
|
54
|
+
|
55
|
+
# Ensure that we close the server and delete the socket file when this
|
56
|
+
# process exits.
|
57
|
+
at_exit do
|
58
|
+
server.close
|
59
|
+
File.unlink(filepath)
|
60
|
+
end
|
61
|
+
|
62
|
+
information = server.local_address.unix_path
|
63
|
+
candidates = ["nc -w 3 -U", "ncat -w 3 -U"]
|
64
|
+
end
|
65
|
+
|
66
|
+
# This is the actual listening thread that will be acting as our server. We have
|
67
|
+
# to start it in another thread to begin with so that we can run through our
|
68
|
+
# candidate connection programs. Eventually we'll just join into this thread
|
69
|
+
# though and it will act as a daemon.
|
70
|
+
listener =
|
71
|
+
Thread.new do
|
72
|
+
loop do
|
73
|
+
break if quit
|
74
|
+
|
75
|
+
# Start up a new thread that will handle each successive connection.
|
76
|
+
Thread.new(server.accept_nonblock) do |socket|
|
77
|
+
parser, maxwidth_string, tabwidth_string, source =
|
78
|
+
socket.read.force_encoding("UTF-8").split("|", 4)
|
79
|
+
|
80
|
+
source.each_line do |line|
|
81
|
+
case line
|
82
|
+
when /^\s*#.+?coding/
|
83
|
+
# If we've found an encoding comment, then we're going to take that
|
84
|
+
# into account and reclassify the encoding for the source.
|
85
|
+
encoding = Ripper.new(line).tap(&:parse).encoding
|
86
|
+
source = source.force_encoding(encoding)
|
87
|
+
break
|
88
|
+
when /^\s*#/
|
89
|
+
# continue
|
90
|
+
else
|
91
|
+
break
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# At the moment, we're not going to support odd tabwidths. It's going to
|
96
|
+
# have to be a multiple of 2, because of the way that the prettyprint
|
97
|
+
# gem functions. So we're going to just use integer division here.
|
98
|
+
scalar = tabwidth_string.to_i / 2
|
99
|
+
genspace = ->(n) { " " * n * scalar }
|
100
|
+
|
101
|
+
maxwidth = maxwidth_string.to_i
|
102
|
+
response =
|
103
|
+
case parser
|
104
|
+
when "ping"
|
105
|
+
"pong"
|
106
|
+
when "ruby"
|
107
|
+
formatter =
|
108
|
+
SyntaxTree::Formatter.new(source, [], maxwidth, "\n", &genspace)
|
109
|
+
SyntaxTree.parse(source).format(formatter)
|
110
|
+
formatter.flush
|
111
|
+
formatter.output.join
|
112
|
+
when "rbs"
|
113
|
+
formatter =
|
114
|
+
SyntaxTree::RBS::Formatter.new(
|
115
|
+
source,
|
116
|
+
[],
|
117
|
+
maxwidth,
|
118
|
+
"\n",
|
119
|
+
&genspace
|
120
|
+
)
|
121
|
+
SyntaxTree::RBS.parse(source).format(formatter)
|
122
|
+
formatter.flush
|
123
|
+
formatter.output.join
|
124
|
+
when "haml"
|
125
|
+
formatter_class =
|
126
|
+
if defined?(SyntaxTree::Haml::Format::Formatter)
|
127
|
+
SyntaxTree::Haml::Format::Formatter
|
128
|
+
else
|
129
|
+
PrettierPrint
|
130
|
+
end
|
131
|
+
|
132
|
+
formatter =
|
133
|
+
formatter_class.new(source, +"", maxwidth, "\n", &genspace)
|
134
|
+
|
135
|
+
SyntaxTree::Haml.parse(source).format(formatter)
|
136
|
+
formatter.flush
|
137
|
+
formatter.output
|
138
|
+
end
|
139
|
+
|
140
|
+
if response
|
141
|
+
socket.write(JSON.fast_generate(response.force_encoding("UTF-8")))
|
142
|
+
else
|
143
|
+
socket.write("{ \"error\": true }")
|
144
|
+
end
|
145
|
+
rescue SyntaxTree::Parser::ParseError => error
|
146
|
+
loc = { start: { line: error.lineno, column: error.column } }
|
147
|
+
socket.write(JSON.fast_generate(error: error.message, loc: loc))
|
148
|
+
rescue StandardError => error
|
149
|
+
begin
|
150
|
+
socket.write(JSON.fast_generate(error: error.message))
|
151
|
+
rescue Errno::EPIPE
|
152
|
+
# Do nothing, the pipe has been closed by the parent process so we don't
|
153
|
+
# actually care about writing to it anymore.
|
154
|
+
end
|
155
|
+
ensure
|
156
|
+
socket.close
|
157
|
+
end
|
158
|
+
rescue IO::WaitReadable, Errno::EINTR
|
159
|
+
# Wait for select(2) to give us a connection that has content for 1
|
160
|
+
# second. Otherwise timeout and continue on (so that we hit our
|
161
|
+
# "break if quit" pretty often).
|
162
|
+
IO.select([server], nil, nil, 1)
|
163
|
+
|
164
|
+
retry unless quit
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# Map each candidate connection method to a thread that will check if it works.
|
169
|
+
candidates.map! do |candidate|
|
170
|
+
Thread.new do
|
171
|
+
Thread.current.report_on_exception = false
|
172
|
+
|
173
|
+
# We do not care about stderr here, so throw it away
|
174
|
+
stdout, _stderr, status =
|
175
|
+
Open3.capture3("#{candidate} #{information}", stdin_data: "ping")
|
176
|
+
|
177
|
+
candidate if JSON.parse(stdout) == "pong" && status.exitstatus == 0
|
178
|
+
rescue StandardError
|
179
|
+
# We don't actually care if this fails, because we'll just skip that
|
180
|
+
# connection option.
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Find the first one prefix that successfully returned the correct value.
|
185
|
+
prefix =
|
186
|
+
candidates.detect do |candidate|
|
187
|
+
value = candidate.value
|
188
|
+
break value if value
|
189
|
+
end
|
190
|
+
|
191
|
+
# Default to running the netcat.js script that we ship with the plugin. It's a
|
192
|
+
# good fallback as it will always work, but it is slower than the other options.
|
193
|
+
prefix ||= "node #{File.expand_path("netcat.js", __dir__)}"
|
194
|
+
|
195
|
+
# Write out our connection information to the file given as the first argument
|
196
|
+
# to this script.
|
197
|
+
File.write(ARGV[0], "#{prefix} #{information}")
|
198
|
+
|
199
|
+
listener.join
|