@ideasonpurpose/build-tools-wordpress 2.6.6 → 2.8.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.
- package/.github/workflows/release-from-version-tag.yml +1 -1
- package/AGENTS.md +68 -0
- package/CHANGELOG.md +15 -0
- package/README.md +7 -2
- package/bin/format-php-prettier.js +8 -6
- package/bin/format-wp-block-pattern.js +38 -30
- package/boilerplate/.env.sample +77 -0
- package/boilerplate/composer.json +42 -0
- package/boilerplate/package.json +74 -0
- package/boilerplate/svgo.config.mjs +32 -0
- package/example/docker-compose.yml +6 -302
- package/package.json +20 -22
- package/test/devserver-proxy.test.js +31 -201
- package/test/fixtures/format-wp-block-pattern/nested-list.php +6 -0
- package/test/fixtures/format-wp-block-pattern/nested-list__formatted.php +6 -0
- package/test/fixtures/format-wp-block-pattern/paragraph-whitespace.php +14 -0
- package/test/fixtures/format-wp-block-pattern/paragraph-whitespace__formatted.php +9 -0
- package/test/format-wp-block-pattern.test.js +64 -5
- package/tooling/docker-compose.yml +277 -0
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
//@ts-check
|
|
2
2
|
|
|
3
|
-
import { afterEach, beforeEach,
|
|
4
|
-
|
|
5
|
-
import fs from "fs";
|
|
6
|
-
import dns from "dns";
|
|
3
|
+
import { afterEach, beforeEach, expect, test, vi } from "vitest";
|
|
7
4
|
|
|
8
5
|
import { EventEmitter } from "events";
|
|
9
6
|
|
|
10
7
|
import { devserverProxy } from "../lib/devserver-proxy.js";
|
|
11
8
|
import { findLocalPort } from "../lib/find-local-docker-port.js";
|
|
12
9
|
|
|
13
|
-
const expected = "11.22.33.44";
|
|
14
|
-
|
|
15
10
|
const expectedPort = 56789;
|
|
16
11
|
const expectedHostName = "stella.dog";
|
|
17
12
|
const expectedTarget = `http://${expectedHostName}:${expectedPort}`;
|
|
18
13
|
|
|
19
14
|
vi.mock("../lib/find-local-docker-port.js");
|
|
20
15
|
|
|
16
|
+
/** @type {Promise<{port:number,hostname:string}>} */
|
|
21
17
|
let localPort;
|
|
22
18
|
|
|
23
19
|
beforeEach(() => {
|
|
@@ -33,80 +29,6 @@ beforeEach(() => {
|
|
|
33
29
|
afterEach(() => {
|
|
34
30
|
vi.restoreAllMocks();
|
|
35
31
|
});
|
|
36
|
-
// beforeEach(() => {
|
|
37
|
-
// jest.spyOn(dns, "promises", "get").mockImplementation(() => {
|
|
38
|
-
// return { resolve: async () => [expected] };
|
|
39
|
-
// });
|
|
40
|
-
|
|
41
|
-
// console.log = jest.fn();
|
|
42
|
-
// });
|
|
43
|
-
|
|
44
|
-
// afterEach(() => {
|
|
45
|
-
// jest.clearAllMocks();
|
|
46
|
-
// jest.resetAllMocks();
|
|
47
|
-
// // mockResolve.mockResolvedValue(["11.22.33.44"]);
|
|
48
|
-
// });
|
|
49
|
-
|
|
50
|
-
// disabled because we're now mocking the library
|
|
51
|
-
// test.skip("dns works normally", async () => {
|
|
52
|
-
// const actual = await dns.promises.resolve("apple.com");
|
|
53
|
-
// expect(actual[0]).toMatch(/^17\.253/);
|
|
54
|
-
// });
|
|
55
|
-
|
|
56
|
-
// test("mock dns.promises.resolve", async () => {
|
|
57
|
-
// const actual = await dns.promises.resolve("hello");
|
|
58
|
-
// expect(actual).toBe(expected);
|
|
59
|
-
// });
|
|
60
|
-
|
|
61
|
-
// test("resolve from file", async () => {
|
|
62
|
-
// const actual = await resolveFromFile("wordpress");
|
|
63
|
-
// expect(actual).toBe(expected);
|
|
64
|
-
// });
|
|
65
|
-
|
|
66
|
-
// test("Send legacy token where there's no wordpress service", async () => {
|
|
67
|
-
// jest.spyOn(dns, "promises", "get").mockImplementation(() => {
|
|
68
|
-
// // console.log("ONLY ONCE");
|
|
69
|
-
// return { resolve: () => new Promise((resolve, reject) => reject()) };
|
|
70
|
-
// });
|
|
71
|
-
|
|
72
|
-
// let proxy =
|
|
73
|
-
// "http://devserver-proxy-token--d939bef2a41c4aa154ddb8db903ce19fff338b61";
|
|
74
|
-
|
|
75
|
-
// const logSpy = jest.spyOn(console, "log");
|
|
76
|
-
// const actual = await devserverProxy({ proxy });
|
|
77
|
-
|
|
78
|
-
// expect(actual).toStrictEqual({});
|
|
79
|
-
// // expect(logSpy).toHaveBeenCalledWith(expect.stringContaining("ONCE"));
|
|
80
|
-
// expect(logSpy).toHaveBeenCalledWith(
|
|
81
|
-
// expect.any(String),
|
|
82
|
-
// expect.stringContaining("devserver-proxy-token"),
|
|
83
|
-
// expect.any(String)
|
|
84
|
-
// );
|
|
85
|
-
// });
|
|
86
|
-
|
|
87
|
-
// test("prefix http onto string", async () => {
|
|
88
|
-
// jest.spyOn(dns, "promises", "get").mockImplementation(() => {
|
|
89
|
-
// return {
|
|
90
|
-
// resolve: () => new Promise((resolve, reject) => resolve(["fake-url"])),
|
|
91
|
-
// };
|
|
92
|
-
// });
|
|
93
|
-
|
|
94
|
-
// let proxy = "placeholder string";
|
|
95
|
-
// const actual = await devserverProxy({ proxy });
|
|
96
|
-
// expect(actual).toHaveProperty("proxy.**.target", "http://fake-url");
|
|
97
|
-
// });
|
|
98
|
-
|
|
99
|
-
// test("fail to prefix http onto string", async () => {
|
|
100
|
-
// jest.spyOn(dns, "promises", "get").mockImplementation(() => {
|
|
101
|
-
// return {
|
|
102
|
-
// resolve: () => new Promise((resolve, reject) => reject()),
|
|
103
|
-
// };
|
|
104
|
-
// });
|
|
105
|
-
|
|
106
|
-
// let proxy = "placeholder string";
|
|
107
|
-
// const actual = await devserverProxy({ proxy });
|
|
108
|
-
// expect(actual).toStrictEqual({});
|
|
109
|
-
// });
|
|
110
32
|
|
|
111
33
|
test("Test proxy settings", async () => {
|
|
112
34
|
let proxy = true;
|
|
@@ -134,6 +56,13 @@ test("proxy is a plain string", async () => {
|
|
|
134
56
|
expect(findLocalPort).toHaveBeenCalledWith(proxy);
|
|
135
57
|
});
|
|
136
58
|
|
|
59
|
+
test("plain string proxy with no local port", async () => {
|
|
60
|
+
vi.mocked(findLocalPort).mockReturnValue(Promise.resolve(null));
|
|
61
|
+
const result = await devserverProxy({ proxy: "sandwich" });
|
|
62
|
+
expect(result.proxy).toHaveLength(1);
|
|
63
|
+
expect(result.proxy[0].target).toBeUndefined();
|
|
64
|
+
});
|
|
65
|
+
|
|
137
66
|
test("Proxy boolean true", async () => {
|
|
138
67
|
vi.mocked(findLocalPort).mockReturnValue(localPort);
|
|
139
68
|
const proxy = true;
|
|
@@ -141,6 +70,13 @@ test("Proxy boolean true", async () => {
|
|
|
141
70
|
expect(actual).toHaveProperty("target", expectedTarget);
|
|
142
71
|
});
|
|
143
72
|
|
|
73
|
+
test("Proxy boolean true with no local port", async () => {
|
|
74
|
+
vi.mocked(findLocalPort).mockReturnValue(Promise.resolve(null));
|
|
75
|
+
const result = await devserverProxy({ proxy: true });
|
|
76
|
+
expect(result.proxy).toHaveLength(1);
|
|
77
|
+
expect(result.proxy[0].target).toBeUndefined();
|
|
78
|
+
});
|
|
79
|
+
|
|
144
80
|
test("Proxy boolean false", async () => {
|
|
145
81
|
const proxy = false;
|
|
146
82
|
expect(await devserverProxy({ proxy })).toStrictEqual({ proxy: [] });
|
|
@@ -216,7 +152,6 @@ test("onProxyRes Handler", async () => {
|
|
|
216
152
|
);
|
|
217
153
|
});
|
|
218
154
|
|
|
219
|
-
|
|
220
155
|
test("onProxyRes Handler passthrough", async () => {
|
|
221
156
|
const config = { proxy: "http://localhost:3000" };
|
|
222
157
|
const result = await devserverProxy(config);
|
|
@@ -224,9 +159,9 @@ test("onProxyRes Handler passthrough", async () => {
|
|
|
224
159
|
|
|
225
160
|
const mockProxyRes = new EventEmitter();
|
|
226
161
|
mockProxyRes.statusCode = 200;
|
|
227
|
-
mockProxyRes.statusMessage = "OK";
|
|
228
162
|
mockProxyRes.headers = {
|
|
229
163
|
"content-type": "nope/nope",
|
|
164
|
+
"x-num": 42,
|
|
230
165
|
};
|
|
231
166
|
const mockReq = {
|
|
232
167
|
headers: { host: "example.com" },
|
|
@@ -255,124 +190,19 @@ test("onProxyRes Handler passthrough", async () => {
|
|
|
255
190
|
);
|
|
256
191
|
});
|
|
257
192
|
|
|
193
|
+
test("onProxyReqWs handler", async () => {
|
|
194
|
+
const result = await devserverProxy({ proxy: "http://example.com" });
|
|
195
|
+
const onProxyReqWs = result.proxy[0].onProxyReqWs;
|
|
196
|
+
|
|
197
|
+
const socket = new EventEmitter();
|
|
198
|
+
const errSpy = vi.spyOn(console, "error");
|
|
258
199
|
|
|
200
|
+
onProxyReqWs(null, null, socket, null, null);
|
|
201
|
+
socket.emit("error", { code: "EPIPE" });
|
|
202
|
+
expect(errSpy).not.toHaveBeenCalled();
|
|
259
203
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
// const route = actual.proxy["**"];
|
|
266
|
-
// const mockProxyRes = fs.createReadStream(new URL(import.meta.url));
|
|
267
|
-
|
|
268
|
-
// mockProxyRes.headers = {
|
|
269
|
-
// headerKey: "value",
|
|
270
|
-
// host: "example.com",
|
|
271
|
-
// "content-type": "text/html; charset=utf-8",
|
|
272
|
-
// };
|
|
273
|
-
// mockProxyRes.statusCode = "statusCode";
|
|
274
|
-
// mockProxyRes.statusMessage = "statusMessage";
|
|
275
|
-
|
|
276
|
-
// const events = {};
|
|
277
|
-
// jest.spyOn(mockProxyRes, "on").mockImplementation((event, handler) => {
|
|
278
|
-
// events[event] = handler;
|
|
279
|
-
// return mockProxyRes;
|
|
280
|
-
// });
|
|
281
|
-
|
|
282
|
-
// const setHeader = jest.fn();
|
|
283
|
-
// const end = jest.fn();
|
|
284
|
-
|
|
285
|
-
// const res = { setHeader, end };
|
|
286
|
-
// const req = {
|
|
287
|
-
// headers: { host: "req.headers.host" },
|
|
288
|
-
// path: "path",
|
|
289
|
-
// };
|
|
290
|
-
|
|
291
|
-
// route.onProxyRes(mockProxyRes, req, res);
|
|
292
|
-
// events.data(Buffer.from("A string with 28 characters."));
|
|
293
|
-
// events.end();
|
|
294
|
-
|
|
295
|
-
// expect(res.statusCode).toBe(mockProxyRes.statusCode);
|
|
296
|
-
// expect(res.statusMessage).toBe(mockProxyRes.statusMessage);
|
|
297
|
-
// expect(req.headers.host).toBe("req.headers.host");
|
|
298
|
-
// expect(setHeader).toHaveBeenLastCalledWith("Content-Length", 28);
|
|
299
|
-
// });
|
|
300
|
-
|
|
301
|
-
// test("test proxy's onProxyRes handler onEnd passthrough", async () => {
|
|
302
|
-
// let proxy = "https://example.com";
|
|
303
|
-
// // const logSpy = jest.spyOn(console, "log");
|
|
304
|
-
// const actual = await devserverProxy({ proxy });
|
|
305
|
-
|
|
306
|
-
// const route = actual.proxy["**"];
|
|
307
|
-
// const mockProxyRes = fs.createReadStream(new URL(import.meta.url));
|
|
308
|
-
|
|
309
|
-
// console.log("hello");
|
|
310
|
-
// mockProxyRes.headers = {
|
|
311
|
-
// headerKey: "value",
|
|
312
|
-
// host: "example.com",
|
|
313
|
-
// "Content-Length": 123,
|
|
314
|
-
// };
|
|
315
|
-
|
|
316
|
-
// const events = {};
|
|
317
|
-
// jest.spyOn(mockProxyRes, "on").mockImplementation((event, handler) => {
|
|
318
|
-
// events[event] = handler;
|
|
319
|
-
// return mockProxyRes;
|
|
320
|
-
// });
|
|
321
|
-
|
|
322
|
-
// const setHeader = jest.fn();
|
|
323
|
-
// const end = jest.fn();
|
|
324
|
-
|
|
325
|
-
// const res = { setHeader, end };
|
|
326
|
-
// const req = {
|
|
327
|
-
// headers: { host: "req.headers.host" },
|
|
328
|
-
// path: "/wp-admin/fake.css",
|
|
329
|
-
// };
|
|
330
|
-
|
|
331
|
-
// route.onProxyRes(mockProxyRes, req, res);
|
|
332
|
-
// events.end();
|
|
333
|
-
|
|
334
|
-
// expect(end).toHaveBeenCalled();
|
|
335
|
-
// });
|
|
336
|
-
|
|
337
|
-
// test("proxy should rewrite http:// and http:\\/\\/", async () => {
|
|
338
|
-
// let proxy = "wordpress";
|
|
339
|
-
|
|
340
|
-
// const logSpy = jest.spyOn(console, "log");
|
|
341
|
-
// const actual = await devserverProxy({ proxy });
|
|
342
|
-
// const route = actual.proxy["**"];
|
|
343
|
-
// const mockProxyRes = fs.createReadStream(new URL(import.meta.url));
|
|
344
|
-
|
|
345
|
-
// mockProxyRes.headers = {
|
|
346
|
-
// headerKey: "value",
|
|
347
|
-
// host: "example.com",
|
|
348
|
-
// "content-type": "text/html; charset=utf-8",
|
|
349
|
-
// };
|
|
350
|
-
|
|
351
|
-
// const events = {};
|
|
352
|
-
// jest.spyOn(mockProxyRes, "on").mockImplementation((event, handler) => {
|
|
353
|
-
// events[event] = handler;
|
|
354
|
-
// return mockProxyRes;
|
|
355
|
-
// });
|
|
356
|
-
|
|
357
|
-
// const setHeader = jest.fn();
|
|
358
|
-
// const end = jest.fn();
|
|
359
|
-
|
|
360
|
-
// const res = { setHeader, end };
|
|
361
|
-
// const req = {
|
|
362
|
-
// headers: { host: "req.headers.host" },
|
|
363
|
-
// path: "path",
|
|
364
|
-
// };
|
|
365
|
-
|
|
366
|
-
// route.onProxyRes(mockProxyRes, req, res);
|
|
367
|
-
// events.data(Buffer.from("http://11.22.33.44\n"));
|
|
368
|
-
// events.data(Buffer.from("http:\\/\\/11.22.33.44\n"));
|
|
369
|
-
// events.end();
|
|
370
|
-
|
|
371
|
-
// expect(end.mock.calls[0][0].toString("utf8")).toMatch(
|
|
372
|
-
// /http:\/\/req.headers.host/
|
|
373
|
-
// );
|
|
374
|
-
|
|
375
|
-
// expect(end.mock.calls[0][0].toString("utf8")).toMatch(
|
|
376
|
-
// /http:\\\/\\\/req.headers.host/
|
|
377
|
-
// );
|
|
378
|
-
// });
|
|
204
|
+
socket.emit("error", { code: "OTHER" });
|
|
205
|
+
expect(errSpy).toHaveBeenCalledWith("WebSocket proxy error:", {
|
|
206
|
+
code: "OTHER",
|
|
207
|
+
});
|
|
208
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* Title: Paragraph Whitespace Test
|
|
4
|
+
*/
|
|
5
|
+
?>
|
|
6
|
+
|
|
7
|
+
<!-- wp:paragraph -->
|
|
8
|
+
<p>
|
|
9
|
+
There are four button styles. Default, Primary, Secondary and Text. Each
|
|
10
|
+
style can include an icon which can be positioned on either side by changing
|
|
11
|
+
the button's text-alignment. Button colors can be customized by selecting
|
|
12
|
+
different Text and Background colors.
|
|
13
|
+
</p>
|
|
14
|
+
<!-- /wp:paragraph -->
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* Title: Paragraph Whitespace Test
|
|
4
|
+
*/
|
|
5
|
+
?>
|
|
6
|
+
|
|
7
|
+
<!-- wp:paragraph -->
|
|
8
|
+
<p>There are four button styles. Default, Primary, Secondary and Text. Each style can include an icon which can be positioned on either side by changing the button's text-alignment. Button colors can be customized by selecting different Text and Background colors.</p>
|
|
9
|
+
<!-- /wp:paragraph -->
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
//@ts-check
|
|
2
2
|
|
|
3
|
-
import { describe, expect, test } from "vitest";
|
|
3
|
+
import { describe, expect, test, vi } from "vitest";
|
|
4
|
+
import prettier from "prettier";
|
|
5
|
+
|
|
6
|
+
vi.mock("prettier", () => ({
|
|
7
|
+
default: {
|
|
8
|
+
format: vi.fn().mockResolvedValue("<formatted/>"),
|
|
9
|
+
},
|
|
10
|
+
}));
|
|
4
11
|
|
|
5
12
|
import { readFile } from "node:fs/promises";
|
|
6
13
|
|
|
@@ -9,6 +16,11 @@ import {
|
|
|
9
16
|
formatAllWpComments,
|
|
10
17
|
normalizeCommentTagSpacing,
|
|
11
18
|
trimInsideListElements,
|
|
19
|
+
normalizeNewlines,
|
|
20
|
+
trimInsideHeadings,
|
|
21
|
+
formatWithPrettier,
|
|
22
|
+
formatWPBlockPattern,
|
|
23
|
+
main,
|
|
12
24
|
} from "../bin/format-wp-block-pattern.js";
|
|
13
25
|
|
|
14
26
|
describe("Format JSON in WP Block comments", () => {
|
|
@@ -106,15 +118,62 @@ describe("Normalize whitespace", () => {
|
|
|
106
118
|
await readFile("./test/fixtures/format-wp-block-pattern/nested-list.php")
|
|
107
119
|
).toString();
|
|
108
120
|
|
|
109
|
-
|
|
110
|
-
await readFile(
|
|
121
|
+
const expected = (
|
|
122
|
+
await readFile(
|
|
123
|
+
"./test/fixtures/format-wp-block-pattern/nested-list__formatted.php",
|
|
124
|
+
)
|
|
111
125
|
).toString();
|
|
112
126
|
|
|
113
127
|
const actual = trimInsideListElements(input);
|
|
114
|
-
|
|
128
|
+
expect(actual).toMatch(/<li>UL/);
|
|
129
|
+
|
|
130
|
+
expect(actual).toBe(expected);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("Whitespace handling in paragraphs", async () => {
|
|
134
|
+
const input = (
|
|
135
|
+
await readFile(
|
|
136
|
+
"./test/fixtures/format-wp-block-pattern/paragraph-whitespace.php",
|
|
137
|
+
)
|
|
138
|
+
).toString();
|
|
139
|
+
|
|
140
|
+
const expected = (
|
|
141
|
+
await readFile(
|
|
142
|
+
"./test/fixtures/format-wp-block-pattern/paragraph-whitespace__formatted.php",
|
|
143
|
+
)
|
|
144
|
+
).toString();
|
|
145
|
+
|
|
146
|
+
const actual = normalizeCommentTagSpacing(input);
|
|
147
|
+
expect(actual).toBe(expected);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("normalizeNewlines for coverage", async () => {
|
|
151
|
+
const input = "Line 1\nLine 2\n \n \n\n\n\nLine 3\nLine 4";
|
|
152
|
+
const expected = "Line 1\nLine 2\n\nLine 3\nLine 4\n";
|
|
153
|
+
|
|
154
|
+
const actual = normalizeNewlines(input);
|
|
155
|
+
expect(actual).toBe(expected);
|
|
156
|
+
});
|
|
115
157
|
|
|
158
|
+
test("trimInsideHeadings for coverage", async () => {
|
|
159
|
+
const input = "<h2> Heading with extra spaces </h2>";
|
|
160
|
+
const expected = "<h2>Heading with extra spaces</h2>";
|
|
161
|
+
|
|
162
|
+
const actual = trimInsideHeadings(input);
|
|
116
163
|
expect(actual).toBe(expected);
|
|
117
164
|
});
|
|
165
|
+
|
|
166
|
+
test("formatWithPrettier for coverage", async () => {
|
|
167
|
+
const input = "<div>foo</div>";
|
|
168
|
+
await formatWithPrettier(input);
|
|
169
|
+
expect(prettier.format).toHaveBeenCalled();
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("main requires filepath", async () => {
|
|
173
|
+
const spy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
174
|
+
await main();
|
|
175
|
+
expect(spy).toHaveBeenCalled();
|
|
176
|
+
spy.mockRestore();
|
|
177
|
+
});
|
|
118
178
|
});
|
|
119
179
|
|
|
120
|
-
// {"align":"full","className":"group-name"}
|