1const { Buffer } = require('buffer');
2const fs = require("fs");
3const path = require("path");
4const { once } = require('events');
5
6const prettierContainerPath = process.argv[2];
7if (prettierContainerPath == null || prettierContainerPath.length == 0) {
8 console.error(`Prettier path argument was not specified or empty.\nUsage: ${process.argv[0]} ${process.argv[1]} prettier/path`);
9 process.exit(1);
10}
11fs.stat(prettierContainerPath, (err, stats) => {
12 if (err) {
13 console.error(`Path '${prettierContainerPath}' does not exist.`);
14 process.exit(1);
15 }
16
17 if (!stats.isDirectory()) {
18 console.log(`Path '${prettierContainerPath}' exists but is not a directory.`);
19 process.exit(1);
20 }
21});
22const prettierPath = path.join(prettierContainerPath, 'node_modules/prettier');
23
24
25(async () => {
26 let prettier;
27 try {
28 prettier = await loadPrettier(prettierPath);
29 } catch (error) {
30 console.error("Failed to load prettier: ", error);
31 process.exit(1);
32 }
33 console.log("Prettier loadded successfully.");
34 process.stdin.resume();
35 handleBuffer(prettier);
36})()
37
38async function handleBuffer(prettier) {
39 for await (let messageText of readStdin()) {
40 handleData(messageText, prettier).catch(e => {
41 console.error("Failed to handle formatter request", e);
42 });
43 }
44}
45
46async function* readStdin() {
47 const bufferLengthOffset = 4;
48 let buffer = Buffer.alloc(0);
49 let streamEnded = false;
50 process.stdin.on('end', () => {
51 streamEnded = true;
52 });
53 process.stdin.on('data', (data) => {
54 buffer = Buffer.concat([buffer, data]);
55 });
56
57 try {
58 main_loop: while (true) {
59 while (buffer.length < bufferLengthOffset) {
60 if (streamEnded) {
61 sendResponse(makeError(`Unexpected end of stream: less than ${bufferLengthOffset} characters passed`));
62 buffer = Buffer.alloc(0);
63 streamEnded = false;
64 await once(process.stdin, 'readable');
65 continue main_loop;
66 }
67 await once(process.stdin, 'readable');
68 }
69
70 const length = buffer.readUInt32LE(0);
71
72 while (buffer.length < (bufferLengthOffset + length)) {
73 if (streamEnded) {
74 sendResponse(makeError(
75 `Unexpected end of stream: buffer length ${buffer.length} does not match expected length ${bufferLengthOffset} + ${length}`));
76 buffer = Buffer.alloc(0);
77 streamEnded = false;
78 await once(process.stdin, 'readable');
79 continue main_loop;
80 }
81 await once(process.stdin, 'readable');
82 }
83
84 const message = buffer.subarray(4, 4 + length);
85 buffer = buffer.subarray(4 + length);
86 yield message.toString('utf8');
87 }
88 } catch (e) {
89 console.error(`Error reading stdin: ${e}`);
90 } finally {
91 process.stdin.off('data');
92 }
93}
94
95async function handleData(messageText, prettier) {
96 try {
97 const message = JSON.parse(messageText);
98 await handleMessage(prettier, message);
99 } catch (e) {
100 sendResponse(makeError(`Request JSON parse error: ${e}`));
101 return;
102 }
103}
104
105// format
106// clear_cache
107//
108// shutdown
109// error
110
111async function handleMessage(prettier, message) {
112 console.log(`message: ${message}`);
113 sendResponse({ method: "hi", result: null });
114}
115
116function makeError(message) {
117 return { method: "error", message };
118}
119
120function sendResponse(response) {
121 const message = Buffer.from(JSON.stringify(response));
122 const length = Buffer.alloc(4);
123 length.writeUInt32LE(message.length);
124 process.stdout.write(length);
125 process.stdout.write(message);
126}
127
128function loadPrettier(prettierPath) {
129 return new Promise((resolve, reject) => {
130 fs.access(prettierPath, fs.constants.F_OK, (err) => {
131 if (err) {
132 reject(`Path '${prettierPath}' does not exist.Error: ${err}`);
133 } else {
134 try {
135 resolve(require(prettierPath));
136 } catch (err) {
137 reject(`Error requiring prettier module from path '${prettierPath}'.Error: ${err}`);
138 }
139 }
140 });
141 });
142}