create-template-html-css 1.6.3 → 1.6.4
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/bin/cli.js +1 -1
- package/package.json +1 -1
- package/src/generator.js +168 -165
- package/src/inserter.js +355 -352
- package/INSERT-QUICK-REFERENCE.md +0 -147
- package/PUBLISHED.md +0 -234
- package/RELEASE-NOTES-v1.6.1.md +0 -129
- package/RELEASE-STATUS.md +0 -203
- package/RELEASE-v1.6.2.md +0 -169
- package/SECURITY-AUDIT.md +0 -157
- package/TEST-REPORT.md +0 -110
- package/VERIFICATION-REPORT.md +0 -162
- package/v1.6.2-IMPROVEMENTS.md +0 -185
package/bin/cli.js
CHANGED
package/package.json
CHANGED
package/src/generator.js
CHANGED
|
@@ -1,165 +1,168 @@
|
|
|
1
|
-
const fs = require("fs").promises;
|
|
2
|
-
const path = require("path");
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Formats HTML content with prettier
|
|
6
|
-
*/
|
|
7
|
-
async function formatHtml(htmlContent) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
return await prettier.format(htmlContent, { parser: "html" });
|
|
11
|
-
} catch (error) {
|
|
12
|
-
return
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return jsContent;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
|
|
1
|
+
const fs = require("fs").promises;
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Formats HTML content with prettier (optional - falls back to original if not available)
|
|
6
|
+
*/
|
|
7
|
+
async function formatHtml(htmlContent) {
|
|
8
|
+
try {
|
|
9
|
+
const prettier = require("prettier");
|
|
10
|
+
return await prettier.format(htmlContent, { parser: "html" });
|
|
11
|
+
} catch (error) {
|
|
12
|
+
// Prettier not installed or error formatting - return original content
|
|
13
|
+
return htmlContent;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Formats CSS content with prettier (optional - falls back to original if not available)
|
|
19
|
+
*/
|
|
20
|
+
async function formatCss(cssContent) {
|
|
21
|
+
try {
|
|
22
|
+
const prettier = require("prettier");
|
|
23
|
+
return await prettier.format(cssContent, { parser: "css" });
|
|
24
|
+
} catch (error) {
|
|
25
|
+
// Prettier not installed or error formatting - return original content
|
|
26
|
+
return cssContent;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Formats JavaScript content with prettier (optional - falls back to original if not available)
|
|
32
|
+
*/
|
|
33
|
+
async function formatJs(jsContent) {
|
|
34
|
+
try {
|
|
35
|
+
const prettier = require("prettier");
|
|
36
|
+
return await prettier.format(jsContent, { parser: "babel" });
|
|
37
|
+
} catch (error) {
|
|
38
|
+
// Prettier not installed or error formatting - return original content
|
|
39
|
+
return jsContent;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Security: Validate component name against whitelist
|
|
44
|
+
const VALID_COMPONENTS = [
|
|
45
|
+
"button",
|
|
46
|
+
"card",
|
|
47
|
+
"form",
|
|
48
|
+
"navigation",
|
|
49
|
+
"modal",
|
|
50
|
+
"footer",
|
|
51
|
+
"hero",
|
|
52
|
+
"slider",
|
|
53
|
+
"table",
|
|
54
|
+
"spinner",
|
|
55
|
+
"animated-card",
|
|
56
|
+
"typing-effect",
|
|
57
|
+
"fade-gallery",
|
|
58
|
+
"grid-layout",
|
|
59
|
+
"masonry-grid",
|
|
60
|
+
"dashboard-grid",
|
|
61
|
+
"flex-layout",
|
|
62
|
+
"flex-cards",
|
|
63
|
+
"flex-dashboard",
|
|
64
|
+
"todo-list",
|
|
65
|
+
"counter",
|
|
66
|
+
"accordion",
|
|
67
|
+
"tabs",
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
// Security: Sanitize filename to prevent path traversal
|
|
71
|
+
function sanitizeFilename(filename) {
|
|
72
|
+
// Remove any path separators and parent directory references
|
|
73
|
+
const sanitized = filename.replace(/[\/\\]/g, "").replace(/\.\.+/g, ".");
|
|
74
|
+
|
|
75
|
+
// Additional validation: ensure name contains at least one alphanumeric character
|
|
76
|
+
if (!sanitized || !/[a-zA-Z0-9]/.test(sanitized)) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Remove any remaining dangerous characters
|
|
81
|
+
return sanitized.replace(/[<>:"|?*]/g, "").trim();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function generateTemplate(options) {
|
|
85
|
+
const { component, name, includeJs } = options;
|
|
86
|
+
|
|
87
|
+
// Security: Validate component name
|
|
88
|
+
if (!VALID_COMPONENTS.includes(component)) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`Invalid component: ${component}. Must be one of: ${VALID_COMPONENTS.join(", ")}`,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Security: Sanitize name to prevent path traversal
|
|
95
|
+
const safeName = sanitizeFilename(name);
|
|
96
|
+
if (!safeName || safeName.length === 0) {
|
|
97
|
+
throw new Error("Invalid name provided");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Create output directory structure
|
|
101
|
+
const outputDir = path.join(process.cwd(), safeName);
|
|
102
|
+
const cssDir = path.join(outputDir, "css");
|
|
103
|
+
const jsDir = path.join(outputDir, "js");
|
|
104
|
+
|
|
105
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
106
|
+
await fs.mkdir(cssDir, { recursive: true });
|
|
107
|
+
await fs.mkdir(jsDir, { recursive: true });
|
|
108
|
+
|
|
109
|
+
// Get template content
|
|
110
|
+
const templateDir = path.join(__dirname, "..", "templates", component);
|
|
111
|
+
|
|
112
|
+
// Copy HTML file
|
|
113
|
+
let htmlContent = await fs.readFile(
|
|
114
|
+
path.join(templateDir, "index.html"),
|
|
115
|
+
"utf-8",
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
// Replace placeholder name
|
|
119
|
+
htmlContent = htmlContent.replace(/{{name}}/g, safeName);
|
|
120
|
+
|
|
121
|
+
// Add script tag if JavaScript is included (pointing to js/ folder)
|
|
122
|
+
if (includeJs) {
|
|
123
|
+
// Insert script tag before closing </body> tag
|
|
124
|
+
htmlContent = htmlContent.replace(
|
|
125
|
+
"</body>",
|
|
126
|
+
' <script src="js/script.js"></script>\n</body>',
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Update CSS link to point to css/ folder
|
|
131
|
+
htmlContent = htmlContent.replace(
|
|
132
|
+
/<link[^>]*href="style\.css"[^>]*>/g,
|
|
133
|
+
' <link rel="stylesheet" href="css/style.css">',
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
// Format HTML before writing
|
|
137
|
+
htmlContent = await formatHtml(htmlContent);
|
|
138
|
+
|
|
139
|
+
await fs.writeFile(path.join(outputDir, "index.html"), htmlContent);
|
|
140
|
+
|
|
141
|
+
// Copy CSS file to css/ folder
|
|
142
|
+
const cssContent = await fs.readFile(
|
|
143
|
+
path.join(templateDir, "style.css"),
|
|
144
|
+
"utf-8",
|
|
145
|
+
);
|
|
146
|
+
const formattedCss = await formatCss(cssContent);
|
|
147
|
+
await fs.writeFile(path.join(cssDir, "style.css"), formattedCss);
|
|
148
|
+
|
|
149
|
+
// Copy JS file to js/ folder if requested
|
|
150
|
+
if (includeJs) {
|
|
151
|
+
try {
|
|
152
|
+
const jsContent = await fs.readFile(
|
|
153
|
+
path.join(templateDir, "script.js"),
|
|
154
|
+
"utf-8",
|
|
155
|
+
);
|
|
156
|
+
const formattedJs = await formatJs(jsContent);
|
|
157
|
+
await fs.writeFile(path.join(jsDir, "script.js"), formattedJs);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
// If no JS template exists, create a basic one
|
|
160
|
+
const basicJs = await formatJs("// Add your JavaScript here\n");
|
|
161
|
+
await fs.writeFile(path.join(jsDir, "script.js"), basicJs);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return outputDir;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
module.exports = { generateTemplate };
|