@ideasonpurpose/build-tools-wordpress 2.1.1 → 2.1.3
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/CHANGELOG.md +13 -0
- package/README.md +1 -1
- package/bin/format-php-prettier.js +117 -0
- package/package.json +11 -10
- package/test/fixtures/format-php-prettier/basic-html.php +7 -0
- package/test/fixtures/format-php-prettier/single-open-php-block.php +6 -0
- package/test/format-php-prettier.test.js +51 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
|
6
6
|
|
|
7
|
+
#### v2.1.2
|
|
8
|
+
|
|
9
|
+
> 14 April 2025
|
|
10
|
+
|
|
11
|
+
- bump deps
|
|
12
|
+
- experimental html & php formatter
|
|
13
|
+
|
|
14
|
+
#### v2.1.1
|
|
15
|
+
|
|
16
|
+
> 9 April 2025
|
|
17
|
+
|
|
18
|
+
- Clean up outputs a little
|
|
19
|
+
|
|
7
20
|
#### v2.1.0
|
|
8
21
|
|
|
9
22
|
> 1 April 2025
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @ideasonpurpose/build-tools-wordpress
|
|
2
2
|
|
|
3
|
-
#### Version 2.1.
|
|
3
|
+
#### Version 2.1.3
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@ideasonpurpose/build-tools-wordpress)
|
|
6
6
|
[](https://github.com/ideasonpurpose/build-tools-wordpress#readme)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* This is an experimental proof-of-concept for formatting mixed HTML & PHP
|
|
5
|
+
* files from a single function.
|
|
6
|
+
*
|
|
7
|
+
* TODO: Testing, naming, modularization, VS Code extension
|
|
8
|
+
*/
|
|
9
|
+
import prettier from "prettier";
|
|
10
|
+
import prettierConfig from "@ideasonpurpose/prettier-config" with { type: "json" };
|
|
11
|
+
|
|
12
|
+
import { readFile, writeFile } from "fs/promises";
|
|
13
|
+
import { resolve, basename } from "path";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Prettier API doesn't recognize overrides, so we extract them
|
|
17
|
+
*/
|
|
18
|
+
const htmlOptions = prettierConfig.overrides.find(
|
|
19
|
+
(o) => o.files === "*.html",
|
|
20
|
+
)?.options;
|
|
21
|
+
|
|
22
|
+
const phpOptions = prettierConfig.overrides.find(
|
|
23
|
+
(o) => o.files === "*.php",
|
|
24
|
+
)?.options;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Replaces PHP Code Blocks with tokens, returns tokenized HTML and an object containing
|
|
28
|
+
* PHP Code Blocks
|
|
29
|
+
*
|
|
30
|
+
* For code blocks between tags (bounded by > & <) tokens will be self-closing HTML
|
|
31
|
+
* tags, similar to this: <php_14______ /> PHP Code blocks at the beginning and end of
|
|
32
|
+
* the file will be tokenized as self-closing if they preceed or follow an HTML tag.
|
|
33
|
+
*
|
|
34
|
+
* All other PHP Code Blocks are represented as HTML attribute-safe padded strings, up
|
|
35
|
+
* to 80 characters long.
|
|
36
|
+
*
|
|
37
|
+
* NOTE: Because Prettier's HTML formatter will always add a space before self-closing
|
|
38
|
+
* tags' closing slash, we just include the space in the token to prevent it from
|
|
39
|
+
* being mutilated by the HTML formatting step. Cleaner than adding a string.replace
|
|
40
|
+
* to unTokenizeHTML().
|
|
41
|
+
*/
|
|
42
|
+
export function tokenizeHTML(htmlContent) {
|
|
43
|
+
const phpCodeBlocks = {};
|
|
44
|
+
let tokenCount = 0;
|
|
45
|
+
|
|
46
|
+
// const pattern = /<\?(?:php|=)[\s\S]*?\?>/gs;
|
|
47
|
+
// const pattern =
|
|
48
|
+
// /(?<before>(?:[^\s]|\s|^)\s*)(?<php><\?(?:php|=).*?(?:\?>|$))(?<after>(?:\s*)[^\s]|$)/gs;
|
|
49
|
+
const pattern =
|
|
50
|
+
/((?:[^\s]|\s|^)\s*)(<\?(?:php|=).*?(?:\?>|$))((?:\s*)[^\s]|$)/gs;
|
|
51
|
+
|
|
52
|
+
const tokenizedHTML = htmlContent.replace(
|
|
53
|
+
pattern,
|
|
54
|
+
(string, before, phpCodeBlock, after, offset) => {
|
|
55
|
+
const start = [">", ""].includes(before.trim()) ? "<" : "_";
|
|
56
|
+
const end = ["<", ""].includes(after.trim()) ? " />" : "___";
|
|
57
|
+
|
|
58
|
+
console.log({offset, string, before, phpCodeBlock, after, offset });
|
|
59
|
+
|
|
60
|
+
// end-pad the token to the lengh of the span, up to 80 characters
|
|
61
|
+
const codeLength = Math.min(phpCodeBlock.length, 80 - end.length);
|
|
62
|
+
const token =
|
|
63
|
+
`${start}php_${tokenCount++}__`.padEnd(codeLength, "_") + end;
|
|
64
|
+
phpCodeBlocks[token] = phpCodeBlock;
|
|
65
|
+
return `${before}${token}${after}`;
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
console.log({ tokenizedHTML, phpCodeBlocks });
|
|
70
|
+
return { tokenizedHTML, phpCodeBlocks };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function unTokenizeHTML(htmlContent, tokens) {
|
|
74
|
+
let phpContent = htmlContent;
|
|
75
|
+
for (const token in tokens) {
|
|
76
|
+
phpContent = phpContent.replace(new RegExp(token, "g"), tokens[token]);
|
|
77
|
+
}
|
|
78
|
+
return phpContent;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function formatHTMLThenPHP(filepath) {
|
|
82
|
+
try {
|
|
83
|
+
const startTime = process.hrtime.bigint();
|
|
84
|
+
const rawFile = await readFile(filepath, "utf8");
|
|
85
|
+
|
|
86
|
+
const { tokenizedHTML, phpCodeBlocks } = tokenizeHTML(rawFile);
|
|
87
|
+
|
|
88
|
+
const htmlFormatted = await prettier.format(tokenizedHTML, {
|
|
89
|
+
...prettierConfig,
|
|
90
|
+
...htmlOptions,
|
|
91
|
+
parser: "html",
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const phpUnTokenized = unTokenizeHTML(htmlFormatted, phpCodeBlocks);
|
|
95
|
+
|
|
96
|
+
const phpFormatted = await prettier.format(phpUnTokenized, {
|
|
97
|
+
...prettierConfig,
|
|
98
|
+
...phpOptions,
|
|
99
|
+
parser: "php",
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
await writeFile(filepath, phpFormatted, "utf8");
|
|
103
|
+
const endTime = process.hrtime.bigint();
|
|
104
|
+
const duration = Number(endTime - startTime);
|
|
105
|
+
|
|
106
|
+
console.log(`${basename(filepath)} ${(duration / 1e6).toFixed(2)}ms`);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error("Error:", error);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (process.argv[2]) {
|
|
113
|
+
const fullPath = resolve(process.argv[2]);
|
|
114
|
+
formatHTMLThenPHP(fullPath);
|
|
115
|
+
} else {
|
|
116
|
+
console.error("Error: A filepath is required.");
|
|
117
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ideasonpurpose/build-tools-wordpress",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "Build scripts and dependencies for IOP's WordPress development environments.",
|
|
5
5
|
"homepage": "https://github.com/ideasonpurpose/build-tools-wordpress#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"bin": {
|
|
22
22
|
"iop-build-port-reporter": "./bin/port-reporter.js",
|
|
23
23
|
"iop-build-zip-archive": "./bin/zip.js",
|
|
24
|
-
"iop-project-init": "./bin/project-init.js"
|
|
24
|
+
"iop-project-init": "./bin/project-init.js",
|
|
25
|
+
"iop-html-php-prettier": "./bin/format-php-prettier.js"
|
|
25
26
|
},
|
|
26
27
|
"directories": {
|
|
27
28
|
"lib": "lib"
|
|
@@ -32,19 +33,19 @@
|
|
|
32
33
|
},
|
|
33
34
|
"prettier": "@ideasonpurpose/prettier-config",
|
|
34
35
|
"dependencies": {
|
|
35
|
-
"@ideasonpurpose/prettier-config": "^1.0.
|
|
36
|
+
"@ideasonpurpose/prettier-config": "^1.0.1",
|
|
36
37
|
"@ideasonpurpose/stylelint-config": "^1.1.1",
|
|
37
38
|
"@rollup/plugin-commonjs": "^28.0.3",
|
|
38
39
|
"@rollup/plugin-json": "^6.1.0",
|
|
39
40
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
40
41
|
"@svgr/webpack": "^8.1.0",
|
|
41
|
-
"@wordpress/dependency-extraction-webpack-plugin": "^6.
|
|
42
|
+
"@wordpress/dependency-extraction-webpack-plugin": "^6.22.0",
|
|
42
43
|
"ansi-html": "^0.0.9",
|
|
43
44
|
"archiver": "^7.0.1",
|
|
44
45
|
"auto-changelog": "^2.5.0",
|
|
45
46
|
"autoprefixer": "^10.4.21",
|
|
46
47
|
"babel-loader": "^10.0.0",
|
|
47
|
-
"caniuse-lite": "^1.0.
|
|
48
|
+
"caniuse-lite": "^1.0.30001713",
|
|
48
49
|
"chalk": "^5.4.1",
|
|
49
50
|
"chalk-cli": "^5.0.1",
|
|
50
51
|
"classnames": "^2.5.1",
|
|
@@ -54,9 +55,9 @@
|
|
|
54
55
|
"cross-env": "^7.0.3",
|
|
55
56
|
"css-loader": "^7.1.2",
|
|
56
57
|
"cssnano": "^7.0.6",
|
|
57
|
-
"dotenv": "^16.
|
|
58
|
+
"dotenv": "^16.5.0",
|
|
58
59
|
"esbuild-loader": "^4.3.0",
|
|
59
|
-
"eslint": "^9.
|
|
60
|
+
"eslint": "^9.24.0",
|
|
60
61
|
"filesize": "^10.1.6",
|
|
61
62
|
"fs-extra": "^11.3.0",
|
|
62
63
|
"globby": "^14.1.0",
|
|
@@ -73,17 +74,17 @@
|
|
|
73
74
|
"pretty-hrtime": "^1.0.3",
|
|
74
75
|
"read-package-up": "^11.0.0",
|
|
75
76
|
"replacestream": "^4.0.3",
|
|
76
|
-
"sass-embedded": "^1.86.
|
|
77
|
+
"sass-embedded": "^1.86.3",
|
|
77
78
|
"sass-loader": "^16.0.5",
|
|
78
79
|
"semver": "^7.7.1",
|
|
79
|
-
"sharp": "^0.
|
|
80
|
+
"sharp": "^0.34.1",
|
|
80
81
|
"sort-package-json": "^3.0.0",
|
|
81
82
|
"string-length": "^6.0.0",
|
|
82
83
|
"style-loader": "^4.0.0",
|
|
83
84
|
"svgo": "^3.3.2",
|
|
84
85
|
"svgo-loader": "^4.0.0",
|
|
85
86
|
"version-everything": "^0.11.4",
|
|
86
|
-
"webpack": "^5.
|
|
87
|
+
"webpack": "^5.99.5",
|
|
87
88
|
"webpack-bundle-analyzer": "^4.10.2",
|
|
88
89
|
"webpack-dev-middleware": "^7.4.2",
|
|
89
90
|
"webpack-dev-server": "^5.2.1"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
|
|
3
|
+
import { describe, expect, test } from "vitest";
|
|
4
|
+
|
|
5
|
+
import { readFile } from "node:fs/promises";
|
|
6
|
+
|
|
7
|
+
import { tokenizeHTML } from "../bin/format-php-prettier.js";
|
|
8
|
+
|
|
9
|
+
describe("HTML-PHP Prettier", () => {
|
|
10
|
+
test("All tokens exist", async () => {
|
|
11
|
+
const input = (
|
|
12
|
+
await readFile("./test/fixtures/format-php-prettier/basic-html.php")
|
|
13
|
+
).toString();
|
|
14
|
+
|
|
15
|
+
const { tokenizedHTML, phpCodeBlocks } = tokenizeHTML(input);
|
|
16
|
+
|
|
17
|
+
Object.keys(phpCodeBlocks).forEach((token) =>
|
|
18
|
+
expect(tokenizedHTML.includes(token)).toBe(true),
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("make tokens self-closing tags", async () => {
|
|
23
|
+
const input = (
|
|
24
|
+
await readFile("./test/fixtures/format-php-prettier/basic-html.php")
|
|
25
|
+
).toString();
|
|
26
|
+
|
|
27
|
+
const { phpCodeBlocks: codeBlocks } = tokenizeHTML(input);
|
|
28
|
+
|
|
29
|
+
const tokens = Object.keys(codeBlocks);
|
|
30
|
+
|
|
31
|
+
expect(tokens[0]).toMatch(/^<php_\d+_* \/>$/);
|
|
32
|
+
expect(tokens[1]).toMatch(/^_php_\d+_*$/);
|
|
33
|
+
expect(tokens[2]).toMatch(/^<php_\d+_* \/>$/);
|
|
34
|
+
expect(tokens[3]).toMatch(/^<php_\d+_* \/>$/);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("single open PHP code block #11"),
|
|
38
|
+
async () => {
|
|
39
|
+
const input = (
|
|
40
|
+
await readFile(
|
|
41
|
+
"./test/fixtures/format-php-prettier/single-open-php-block.php",
|
|
42
|
+
)
|
|
43
|
+
).toString();
|
|
44
|
+
|
|
45
|
+
const { phpCodeBlocks: codeBlocks } = tokenizeHTML(input);
|
|
46
|
+
|
|
47
|
+
const tokens = Object.keys(codeBlocks);
|
|
48
|
+
|
|
49
|
+
expect(tokens).toHaveLength(1);
|
|
50
|
+
};
|
|
51
|
+
});
|