html-to-gutenberg 4.2.7 → 4.2.9
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/.env +1 -0
- package/.env.example +3 -0
- package/.eslintrc.json +35 -0
- package/.github/workflows/build.yml +26 -0
- package/.github/workflows/coverage.yml +26 -0
- package/.nyc_output/1f0406b8-bb70-495d-8f8a-521fdd81b500.json +1 -0
- package/.nyc_output/6390956f-4f8a-4adb-9256-4a1c7e34a52d.json +1 -0
- package/.nyc_output/processinfo/1f0406b8-bb70-495d-8f8a-521fdd81b500.json +1 -0
- package/.nyc_output/processinfo/6390956f-4f8a-4adb-9256-4a1c7e34a52d.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -0
- package/@types.d.ts +3 -0
- package/coverage/coverage-final.json +4 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov.info +198 -0
- package/coverage-demo.test.ts +8 -0
- package/dist/coverage-demo.test.js +10 -0
- package/dist/coverage-demo.test.js.map +1 -0
- package/dist/globals.js +24 -0
- package/dist/globals.js.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.js +166 -0
- package/dist/index.test.js.map +1 -0
- package/dist/package.json +130 -0
- package/dist/snapapi-screenshot.test.js +44 -0
- package/dist/snapapi-screenshot.test.js.map +1 -0
- package/dist/src/coverage-demo.js +7 -0
- package/dist/src/coverage-demo.js.map +1 -0
- package/dist/src/utils-extra.test.js +137 -0
- package/dist/src/utils-extra.test.js.map +1 -0
- package/dist/src/utils.test.js +65 -0
- package/dist/src/utils.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/utils.js +61 -0
- package/dist/utils.js.map +1 -0
- package/index.js +87 -53
- package/index.test.ts +145 -0
- package/index.ts +47 -1527
- package/package.json +85 -14
- package/readme.md +39 -19
- package/snapapi-screenshot.test.ts +46 -0
- package/src/coverage-demo.ts +3 -0
- package/src/utils-extra.test.ts +108 -0
- package/src/utils.test.ts +36 -0
- package/temp-block-test.js +19 -0
- package/tsconfig.json +9 -3
- package/utils.ts +56 -0
package/package.json
CHANGED
|
@@ -1,37 +1,53 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dependencies": {
|
|
3
|
-
"@babel/core": "^7.
|
|
3
|
+
"@babel/core": "^7.29.0",
|
|
4
4
|
"@babel/preset-react": "^7.28.5",
|
|
5
5
|
"@svgr/core": "^8.1.0",
|
|
6
|
-
"cheerio": "^1.
|
|
7
|
-
"css-scoping": "^1.0.
|
|
8
|
-
"
|
|
6
|
+
"cheerio": "^1.2.0",
|
|
7
|
+
"css-scoping": "^1.0.5",
|
|
8
|
+
"dotenv": "^17.3.1",
|
|
9
|
+
"fetch-page-assets": "^1.2.7",
|
|
9
10
|
"fs": "^0.0.1-security",
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"node-html-to-jsx": "^1.3.7",
|
|
11
|
+
"node-fetch": "^3.3.2",
|
|
12
|
+
"node-html-to-jsx": "^1.4.4",
|
|
13
13
|
"path": "^0.12.7"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
|
+
"@eslint/js": "^10.0.1",
|
|
16
17
|
"@types/babel__core": "^7.20.5",
|
|
17
18
|
"@types/beautify": "^0.0.3",
|
|
19
|
+
"@types/chai": "^5.2.3",
|
|
18
20
|
"@types/cheerio": "^1.0.0",
|
|
19
21
|
"@types/image-to-base64": "^2.1.2",
|
|
22
|
+
"@types/mocha": "^10.0.10",
|
|
20
23
|
"@types/prettier": "^3.0.0",
|
|
21
|
-
"@types/svgo": "^3.0.0"
|
|
24
|
+
"@types/svgo": "^3.0.0",
|
|
25
|
+
"@typescript-eslint/eslint-plugin": "^8.56.1",
|
|
26
|
+
"@typescript-eslint/parser": "^8.56.1",
|
|
27
|
+
"chai": "^6.2.2",
|
|
28
|
+
"coveralls": "^3.1.1",
|
|
29
|
+
"eslint": "^10.0.2",
|
|
30
|
+
"mocha": "^11.3.0",
|
|
31
|
+
"nyc": "^18.0.0",
|
|
32
|
+
"source-map-support": "^0.5.21",
|
|
33
|
+
"ts-jest": "^29.4.6",
|
|
34
|
+
"ts-node": "^10.9.2",
|
|
35
|
+
"typescript-eslint": "^8.56.1"
|
|
22
36
|
},
|
|
23
|
-
"type": "module",
|
|
24
37
|
"types": "index.ts",
|
|
25
38
|
"name": "html-to-gutenberg",
|
|
26
|
-
"version": "4.2.
|
|
39
|
+
"version": "4.2.9",
|
|
27
40
|
"description": "Transform any valid HTML string into fully editable WP Gutenberg blocks in seconds rather than hours.",
|
|
28
41
|
"main": "index.js",
|
|
29
42
|
"directories": {
|
|
30
43
|
"test": "test"
|
|
31
44
|
},
|
|
32
45
|
"scripts": {
|
|
33
|
-
"
|
|
34
|
-
"
|
|
46
|
+
"postinstall": "mv ./node_modules/fetch-page-assets/index.ts ./node_modules/fetch-page-assets/index.ts.bak || true",
|
|
47
|
+
"test": "mocha -r ts-node/register index.test.ts",
|
|
48
|
+
"build": "tsc",
|
|
49
|
+
"coverage": "nyc mocha -r ts-node/register index.test.ts",
|
|
50
|
+
"coveralls": "nyc mocha -r ts-node/register index.test.ts && nyc report --reporter=lcov && cat coverage/lcov.info | coveralls"
|
|
35
51
|
},
|
|
36
52
|
"repository": {
|
|
37
53
|
"type": "git",
|
|
@@ -55,5 +71,60 @@
|
|
|
55
71
|
"bugs": {
|
|
56
72
|
"url": "https://github.com/DiogoAngelim/html-to-gutenberg/issues"
|
|
57
73
|
},
|
|
58
|
-
"homepage": "https://www.html-to-gutenberg.io"
|
|
59
|
-
|
|
74
|
+
"homepage": "https://www.html-to-gutenberg.io",
|
|
75
|
+
"nyc": {
|
|
76
|
+
"reporter": [
|
|
77
|
+
"lcov",
|
|
78
|
+
"text"
|
|
79
|
+
],
|
|
80
|
+
"exclude": [
|
|
81
|
+
"coverage"
|
|
82
|
+
],
|
|
83
|
+
"include": [
|
|
84
|
+
"src/*.ts",
|
|
85
|
+
"src/**/*.ts"
|
|
86
|
+
],
|
|
87
|
+
"extension": [
|
|
88
|
+
".ts",
|
|
89
|
+
".js"
|
|
90
|
+
],
|
|
91
|
+
"all": true,
|
|
92
|
+
"sourceMap": true,
|
|
93
|
+
"instrument": true,
|
|
94
|
+
"require": [
|
|
95
|
+
"ts-node/register"
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
"jest": {
|
|
99
|
+
"preset": "ts-jest/presets/js-with-ts",
|
|
100
|
+
"testEnvironment": "node",
|
|
101
|
+
"extensionsToTreatAsEsm": [
|
|
102
|
+
".ts"
|
|
103
|
+
],
|
|
104
|
+
"transform": {
|
|
105
|
+
"^.+\\.tsx?$": [
|
|
106
|
+
"ts-jest",
|
|
107
|
+
{
|
|
108
|
+
"useESM": true
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
"globals": {
|
|
113
|
+
"ts-jest": {
|
|
114
|
+
"tsconfig": "tsconfig.json",
|
|
115
|
+
"useESM": true
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"moduleNameMapper": {
|
|
119
|
+
"^(\\.{1,2}/.*)\\.js$": "$1"
|
|
120
|
+
},
|
|
121
|
+
"collectCoverage": true,
|
|
122
|
+
"collectCoverageFrom": [
|
|
123
|
+
"dist/*.js",
|
|
124
|
+
"!dist/*.test.js"
|
|
125
|
+
],
|
|
126
|
+
"testMatch": [
|
|
127
|
+
"<rootDir>/dist/*.test.js"
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
}
|
package/readme.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
|
|
2
1
|
# HTML to Gutenberg Converter
|
|
3
2
|
|
|
3
|
+
<!-- [](https://github.com/DiogoAngelim/html-to-gutenberg/actions)
|
|
4
|
+
[](https://coveralls.io/github/DiogoAngelim/html-to-gutenberg?branch=main) -->
|
|
5
|
+
[](https://github.com/DiogoAngelim/html-to-gutenberg/blob/main/LICENSE.MD)
|
|
6
|
+
|
|
4
7
|
|
|
5
8
|
|
|
6
|
-
Convert HTML strings to valid, editable WordPress Gutenberg blocks in seconds instead of hours. With this
|
|
9
|
+
Convert HTML strings to valid, editable WordPress Gutenberg blocks in seconds instead of hours. With this lib, you can create and build valid Gutenberg blocks that feature editable text, forms, inline and background images, as well as SVGs.
|
|
7
10
|
|
|
8
|
-
|
|
9
11
|
|
|
10
12
|
## Features
|
|
11
13
|
|
|
@@ -41,16 +43,25 @@ Since it returns all files as either strings or source files, you can save them
|
|
|
41
43
|
- 🧰 **Built for automation and customization**
|
|
42
44
|
Can be embedded in custom tools, UIs, or pipelines to generate Gutenberg blocks on demand.
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
## How it works
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
This package is actually an alternative when AI fails converting it, which is usually very common.
|
|
48
49
|
|
|
49
|
-
|
|
50
|
+
Most of the logic is just hard-coded patterns. It first converts from plain HTML to Jsx (using the `html-to-jsx` package), which is the supported format of Gutenberg. Then, it follows structured conversion rules that build the WordPress block, which is then validated and parsed using Babel.
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
|
|
53
|
+
## The Building Process - An Overview
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
Below is a visual overview of the block generation process:
|
|
57
|
+
|
|
58
|
+

|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
52
62
|
|
|
53
63
|
|
|
64
|
+
Install html-to-gutenberg with npm:
|
|
54
65
|
|
|
55
66
|
```bash
|
|
56
67
|
|
|
@@ -81,19 +92,11 @@ const htmlString = '<div>My content</div>';
|
|
|
81
92
|
|
|
82
93
|
|
|
83
94
|
|
|
84
|
-
When provided with a valid HTML string and the required options, the block function will generate the necessary WordPress block files with the specified configuration. To install the block and its assets, simply load the generated folder into the plugins folder and activate it.
|
|
85
95
|
|
|
96
|
+
When provided with a valid HTML string with the desired options, the block function will generate the necessary WordPress block files with the specified configuration. To install the block and its assets, simply load the generated folder into the plugins folder and activate it as a plugin.
|
|
86
97
|
|
|
87
98
|
|
|
88
|
-
##
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
[Working demo](https://www.html-to-gutenberg.io/)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
## Options object reference
|
|
99
|
+
## Options reference
|
|
97
100
|
|
|
98
101
|
|
|
99
102
|
| Option | Description | Type | Required? | Default |
|
|
@@ -103,13 +106,30 @@ When provided with a valid HTML string and the required options, the block funct
|
|
|
103
106
|
| prefix | A namespace prefix for the block name, typically aligned with your project (e.g., "wp" or "myplugins"). | string | No | wp |
|
|
104
107
|
| category | The WordPress block category where the block appears in the editor. Use an existing one or register a custom category if needed. | string | No | common |
|
|
105
108
|
| basePath | The absolute path where the output files and folders will be saved. | string | No | Current directory |
|
|
106
|
-
| generateIconPreview | If `true`,
|
|
109
|
+
| generateIconPreview | If you enable the `generateIconPreview` option by setting it to `true`, this package will generate a static image preview of your block using the [SnapAPI](https://snapapi.pics/) screenshot service. You must provide a SnapAPI key in a `.env` file (see below), which will display it a replacement for the block icons in the WP dashboard. | boolean | No | false |
|
|
107
110
|
| shouldSaveFiles | When `true`, the generated block files are saved directly to disk. When `false`, returns an object containing the file contents as strings instead. | boolean | No | true |
|
|
108
111
|
| jsFiles | An array of external JavaScript file URLs to enqueue with the block on the editor and the frontend. Useful for adding remote libraries. | string[] | No | [] |
|
|
109
112
|
| cssFiles | An array of external CSS file URLs to enqueue with the block on the editor and the frontend. Useful for adding additional remote stylesheets. | string[] | No | [] |
|
|
110
113
|
|
|
111
114
|
|
|
112
115
|
|
|
116
|
+
**Special thanks to [Alex Serebryakov](https://snapapi.pics/) for creating and maintaining SnapAPI!**
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
## Running Tests
|
|
120
|
+
|
|
121
|
+
To run the test suite, use:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
cd html-to-gutenberg && npm install
|
|
125
|
+
npm test
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
This will execute all unit and integration tests using Mocha and Chai. Make sure all dependencies are installed with `npm install` before running tests.
|
|
129
|
+
|
|
130
|
+
Some tests (such as screenshot preview generation) may require a valid SnapAPI key in your `.env` file.
|
|
131
|
+
|
|
132
|
+
|
|
113
133
|
## License
|
|
114
134
|
|
|
115
135
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import block from './index.js';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import dotenv from 'dotenv';
|
|
6
|
+
|
|
7
|
+
dotenv.config();
|
|
8
|
+
|
|
9
|
+
describe('block screenshot integration', () => {
|
|
10
|
+
const testHtml = '<html><body><h1>SnapAPI Test</h1></body></html>';
|
|
11
|
+
const testOptions = {
|
|
12
|
+
name: 'SnapAPITestBlock',
|
|
13
|
+
prefix: 'wp',
|
|
14
|
+
category: 'common',
|
|
15
|
+
basePath: process.cwd(),
|
|
16
|
+
shouldSaveFiles: true,
|
|
17
|
+
generateIconPreview: true,
|
|
18
|
+
jsFiles: [],
|
|
19
|
+
cssFiles: [],
|
|
20
|
+
source: 'https://example.com',
|
|
21
|
+
};
|
|
22
|
+
const previewPath = path.join(
|
|
23
|
+
testOptions.basePath,
|
|
24
|
+
'snapapitestblock',
|
|
25
|
+
'preview.jpeg'
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
after(function () {
|
|
29
|
+
if (fs.existsSync(previewPath)) {
|
|
30
|
+
fs.unlinkSync(previewPath);
|
|
31
|
+
// Use fs.rmSync for recursive directory removal in Node >=14
|
|
32
|
+
const dir = path.dirname(previewPath);
|
|
33
|
+
if (fs.existsSync(dir)) {
|
|
34
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should generate a preview.jpeg using SnapAPI', async function (this: Mocha.Context) {
|
|
40
|
+
this.timeout(15000); // Allow time for API call
|
|
41
|
+
await block(testHtml, testOptions);
|
|
42
|
+
expect(fs.existsSync(previewPath)).to.equal(true);
|
|
43
|
+
const stats = fs.statSync(previewPath);
|
|
44
|
+
expect(stats.size).to.be.greaterThan(1000); // Should not be empty
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import * as utils from '../utils';
|
|
3
|
+
|
|
4
|
+
describe('hasTailwindCdnSource edge cases', () => {
|
|
5
|
+
it('returns false for empty array', () => {
|
|
6
|
+
expect(utils.hasTailwindCdnSource([])).to.equal(false);
|
|
7
|
+
});
|
|
8
|
+
it('returns true for multiple tailwind URLs', () => {
|
|
9
|
+
expect(utils.hasTailwindCdnSource([
|
|
10
|
+
'https://cdn.tailwindcss.com',
|
|
11
|
+
'https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.0.0'
|
|
12
|
+
])).to.equal(true);
|
|
13
|
+
});
|
|
14
|
+
it('returns false for malformed URLs', () => {
|
|
15
|
+
expect(utils.hasTailwindCdnSource(['not-a-url'])).to.equal(false);
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('replaceSourceUrlVars edge cases', () => {
|
|
20
|
+
it('replaces matching pattern', () => {
|
|
21
|
+
const str = "var.url+'http://site.com/path'";
|
|
22
|
+
const source = 'http://site.com';
|
|
23
|
+
const expected = "${vars.url}/path";
|
|
24
|
+
expect(utils.replaceSourceUrlVars(str, source)).to.contain(expected);
|
|
25
|
+
});
|
|
26
|
+
it('returns input for empty string', () => {
|
|
27
|
+
expect(utils.replaceSourceUrlVars('', 'http://site.com')).to.equal('');
|
|
28
|
+
});
|
|
29
|
+
it('returns input for null source', () => {
|
|
30
|
+
expect(utils.replaceSourceUrlVars("var.url+'http://site.com/path'", null)).to.equal("var.url+'http://site.com/path'");
|
|
31
|
+
});
|
|
32
|
+
it('replaces multiple matches', () => {
|
|
33
|
+
const str = "var.url+'http://site.com/a' and var.url+'http://site.com/b'";
|
|
34
|
+
const source = 'http://site.com';
|
|
35
|
+
const result = utils.replaceSourceUrlVars(str, source);
|
|
36
|
+
expect(result.match(/\${vars\.url}/g)?.length).to.be.greaterThanOrEqual(2);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('sanitizeAndReplaceLeadingNumbers edge cases', () => {
|
|
41
|
+
it('returns input for no numbers', () => {
|
|
42
|
+
expect(utils.sanitizeAndReplaceLeadingNumbers('test')).to.equal('test');
|
|
43
|
+
});
|
|
44
|
+
it('handles multiple leading numbers', () => {
|
|
45
|
+
expect(utils.sanitizeAndReplaceLeadingNumbers('123abc')).to.match(/one1two2three3abc|123abc/);
|
|
46
|
+
});
|
|
47
|
+
it('handles only numbers', () => {
|
|
48
|
+
expect(utils.sanitizeAndReplaceLeadingNumbers('123')).to.match(/one1two2three3|123/);
|
|
49
|
+
});
|
|
50
|
+
it('handles special characters', () => {
|
|
51
|
+
expect(utils.sanitizeAndReplaceLeadingNumbers('1_test')).to.match(/one1test|1test/);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('replaceUnderscoresSpacesAndUppercaseLetters edge cases', () => {
|
|
56
|
+
it('handles only underscores', () => {
|
|
57
|
+
expect(utils.replaceUnderscoresSpacesAndUppercaseLetters('___')).to.equal('---');
|
|
58
|
+
});
|
|
59
|
+
it('handles only spaces', () => {
|
|
60
|
+
expect(utils.replaceUnderscoresSpacesAndUppercaseLetters(' ')).to.equal('---');
|
|
61
|
+
});
|
|
62
|
+
it('handles mixed cases', () => {
|
|
63
|
+
expect(utils.replaceUnderscoresSpacesAndUppercaseLetters('Test_Name Here')).to.equal('test-name-here');
|
|
64
|
+
});
|
|
65
|
+
it('handles empty string', () => {
|
|
66
|
+
expect(utils.replaceUnderscoresSpacesAndUppercaseLetters('')).to.equal('');
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('convertDashesSpacesAndUppercaseToUnderscoresAndLowercase edge cases', () => {
|
|
71
|
+
it('handles only dashes', () => {
|
|
72
|
+
expect(utils.convertDashesSpacesAndUppercaseToUnderscoresAndLowercase('---')).to.equal('___');
|
|
73
|
+
});
|
|
74
|
+
it('handles only spaces', () => {
|
|
75
|
+
expect(utils.convertDashesSpacesAndUppercaseToUnderscoresAndLowercase(' ')).to.equal('___');
|
|
76
|
+
});
|
|
77
|
+
it('handles mixed cases', () => {
|
|
78
|
+
expect(utils.convertDashesSpacesAndUppercaseToUnderscoresAndLowercase('Test-Name Here')).to.equal('test_name_here');
|
|
79
|
+
});
|
|
80
|
+
it('handles empty string', () => {
|
|
81
|
+
expect(utils.convertDashesSpacesAndUppercaseToUnderscoresAndLowercase('')).to.equal('');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('hasAbsoluteKeyword edge cases', () => {
|
|
86
|
+
it('detects uppercase', () => {
|
|
87
|
+
expect(utils.hasAbsoluteKeyword('ABSOLUTE')).to.equal(true);
|
|
88
|
+
});
|
|
89
|
+
it('returns false for empty string', () => {
|
|
90
|
+
expect(utils.hasAbsoluteKeyword('')).to.equal(false);
|
|
91
|
+
});
|
|
92
|
+
it('returns false for empty string', () => {
|
|
93
|
+
expect(utils.hasAbsoluteKeyword('')).to.equal(false);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('generateRandomVariableName edge cases', () => {
|
|
98
|
+
it('returns prefix only for length 0', () => {
|
|
99
|
+
expect(utils.generateRandomVariableName('prefix', 0)).to.equal('prefix');
|
|
100
|
+
});
|
|
101
|
+
it('returns only random part for empty prefix', () => {
|
|
102
|
+
expect(utils.generateRandomVariableName('', 3)).to.match(/^[a-z]{3}$/);
|
|
103
|
+
});
|
|
104
|
+
it('returns correct length', () => {
|
|
105
|
+
const result = utils.generateRandomVariableName('pre', 5);
|
|
106
|
+
expect(result.length).to.equal(8);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import * as utils from '../utils';
|
|
3
|
+
|
|
4
|
+
describe('utils.ts functions', () => {
|
|
5
|
+
it('hasTailwindCdnSource returns true for Tailwind CDN', () => {
|
|
6
|
+
expect(utils.hasTailwindCdnSource(['https://cdn.tailwindcss.com'])).to.equal(true);
|
|
7
|
+
expect(utils.hasTailwindCdnSource(['https://example.com'])).to.equal(false);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('replaceSourceUrlVars returns input if no match', () => {
|
|
11
|
+
const str = "var.url+'http://site.com/path'";
|
|
12
|
+
const expected = "${vars.url}/path";
|
|
13
|
+
expect(utils.replaceSourceUrlVars(str, 'http://site.com')).to.equal(expected);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('sanitizeAndReplaceLeadingNumbers replaces leading numbers', () => {
|
|
17
|
+
expect(utils.sanitizeAndReplaceLeadingNumbers('1test')).to.match(/one1test|1test/);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('replaceUnderscoresSpacesAndUppercaseLetters replaces underscores and spaces', () => {
|
|
21
|
+
expect(utils.replaceUnderscoresSpacesAndUppercaseLetters('Test_Name Here')).to.equal('test-name-here');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('convertDashesSpacesAndUppercaseToUnderscoresAndLowercase converts correctly', () => {
|
|
25
|
+
expect(utils.convertDashesSpacesAndUppercaseToUnderscoresAndLowercase('Test-Name Here')).to.equal('test_name_here');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('hasAbsoluteKeyword detects absolute', () => {
|
|
29
|
+
expect(utils.hasAbsoluteKeyword('absolute')).to.equal(true);
|
|
30
|
+
expect(utils.hasAbsoluteKeyword('relative')).to.equal(false);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('generateRandomVariableName returns string with prefix', () => {
|
|
34
|
+
expect(utils.generateRandomVariableName('prefix')).to.match(/^prefix/);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import block from './index.js';
|
|
3
|
+
|
|
4
|
+
(async () => {
|
|
5
|
+
const htmlContent = fs.readFileSync('index.html', 'utf8');
|
|
6
|
+
const options = {
|
|
7
|
+
name: 'TempBlockTest',
|
|
8
|
+
prefix: 'wp',
|
|
9
|
+
category: 'common',
|
|
10
|
+
basePath: process.cwd(),
|
|
11
|
+
shouldSaveFiles: true,
|
|
12
|
+
generateIconPreview: true,
|
|
13
|
+
jsFiles: [],
|
|
14
|
+
cssFiles: [],
|
|
15
|
+
source: 'https://diogoangelim.github.io/html-to-gutenberg/',
|
|
16
|
+
};
|
|
17
|
+
const result = await block(htmlContent, options);
|
|
18
|
+
console.log('Block generation result:', Object.keys(result));
|
|
19
|
+
})();
|
package/tsconfig.json
CHANGED
|
@@ -3,11 +3,17 @@
|
|
|
3
3
|
"sourceMap": true,
|
|
4
4
|
"outDir": "dist",
|
|
5
5
|
"target": "esnext",
|
|
6
|
-
"module": "
|
|
6
|
+
"module": "nodenext",
|
|
7
|
+
"moduleResolution": "nodenext",
|
|
8
|
+
"resolveJsonModule": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
7
10
|
"strict": true,
|
|
8
11
|
"lib": [
|
|
9
12
|
"esnext"
|
|
10
13
|
],
|
|
11
|
-
"esModuleInterop": true
|
|
12
|
-
}
|
|
14
|
+
"esModuleInterop": true,
|
|
15
|
+
},
|
|
16
|
+
"exclude": [
|
|
17
|
+
"node_modules"
|
|
18
|
+
]
|
|
13
19
|
}
|
package/utils.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Utility functions for html-to-gutenberg
|
|
2
|
+
export function hasTailwindCdnSource(jsFiles: string[]): boolean {
|
|
3
|
+
const tailwindCdnRegex = /https:\/\/(cdn\.tailwindcss\.com(\?[^"'\s]*)?|cdn\.jsdelivr\.net\/npm\/@tailwindcss\/browser@4(\.\d+){0,2})/;
|
|
4
|
+
return jsFiles.some((url: string) => tailwindCdnRegex.test(url));
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function replaceSourceUrlVars(str: string, source: any): string {
|
|
8
|
+
if (!source) return str;
|
|
9
|
+
const escapedSource = String(source).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
10
|
+
const pattern = new RegExp(`var\\.url\\+'${escapedSource}([^']*)'`, 'g');
|
|
11
|
+
if (!pattern.test(str)) return str;
|
|
12
|
+
return str.replace(pattern, (_match: string, path: string) => `\${vars.url}${path}`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function sanitizeAndReplaceLeadingNumbers(str: string): string {
|
|
16
|
+
const numberWords = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'];
|
|
17
|
+
let firstNumberReplaced = false;
|
|
18
|
+
return str
|
|
19
|
+
.toLowerCase()
|
|
20
|
+
.replace(/[\s\-_]/g, '')
|
|
21
|
+
.replace(/\d/g, (digit: string) => {
|
|
22
|
+
if (!firstNumberReplaced) {
|
|
23
|
+
firstNumberReplaced = true;
|
|
24
|
+
return numberWords[parseInt(digit)] + digit;
|
|
25
|
+
}
|
|
26
|
+
return digit;
|
|
27
|
+
})
|
|
28
|
+
.replace(/^[^a-z]+/, '');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function replaceUnderscoresSpacesAndUppercaseLetters(name: string = ''): string {
|
|
32
|
+
return name.replace(new RegExp(/\W|_/, 'g'), '-').toLowerCase();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function convertDashesSpacesAndUppercaseToUnderscoresAndLowercase(string: string): string {
|
|
36
|
+
if (string) {
|
|
37
|
+
return `${string.replaceAll('-', '_').replaceAll(' ', '_').toLowerCase()}`;
|
|
38
|
+
}
|
|
39
|
+
return '';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function hasAbsoluteKeyword(str: string): boolean {
|
|
43
|
+
if (typeof str !== 'string') return false;
|
|
44
|
+
return str.toLowerCase().includes('absolute');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function generateRandomVariableName(prefix: string = 'content', length: number = 3): string {
|
|
48
|
+
const chars = 'abcdefghijklmnopqrstuvwxyz';
|
|
49
|
+
let suffix = '';
|
|
50
|
+
for (let i = 0; i < length; i++) {
|
|
51
|
+
suffix += chars.charAt(
|
|
52
|
+
Math.floor(Math.random() * chars.length)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return `${prefix}${suffix}`;
|
|
56
|
+
}
|