create-berna-stencil 2.6.3 → 2.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/index.js +3 -0
- package/package.json +4 -27
- package/.eleventy.js +0 -94
- package/.eleventyignore +0 -4
- package/LICENSE +0 -170
- package/NOTICE +0 -5
- package/README.md +0 -53
- package/_tools/assistant.js +0 -150
- package/_tools/buildJs.js +0 -28
- package/_tools/cleanOutput.js +0 -20
- package/_tools/modules/constants.js +0 -23
- package/_tools/modules/pageComponents.js +0 -77
- package/_tools/modules/updateData.js +0 -84
- package/_tools/modules/updateOutputPath.js +0 -112
- package/_tools/modules/updatePage.js +0 -162
- package/_tools/modules/utils.js +0 -27
- package/_tools/modules/validation.js +0 -20
- package/_tools/res/templates/template.js +0 -5
- package/_tools/res/templates/template.njk +0 -9
- package/_tools/res/templates/template.scss +0 -23
- package/_tools/res/templates/template.ts +0 -5
- package/bin/create.js +0 -429
- package/docs/Assistant CLI.md +0 -61
- package/docs/Backend.md +0 -148
- package/docs/Components.md +0 -96
- package/docs/Creating pages.md +0 -65
- package/docs/Deploy.md +0 -55
- package/docs/Head and SEO.md +0 -94
- package/docs/Javascript.md +0 -53
- package/docs/Styling with SCSS.md +0 -140
- package/nginx.conf +0 -69
- package/src/backend/.htaccess +0 -7
- package/src/backend/_core/composer.json +0 -5
- package/src/backend/_core/composer.lock +0 -492
- package/src/backend/_core/index.php +0 -148
- package/src/backend/_core/init.php +0 -34
- package/src/backend/_core/modules/RateLimiter.php +0 -31
- package/src/backend/_core/modules/Response.php +0 -49
- package/src/backend/api/protected/example-protected.php +0 -17
- package/src/backend/api/public/example-public.php +0 -17
- package/src/backend/database/Database.php +0 -24
- package/src/backend/database/migrations/create_example_db.sql +0 -1
- package/src/backend/web.config +0 -17
- package/src/frontend/.htaccess +0 -16
- package/src/frontend/404.njk +0 -17
- package/src/frontend/assets/brand/favicon.svg +0 -37
- package/src/frontend/assets/brand/logo.svg +0 -37
- package/src/frontend/components/global/footer.njk +0 -27
- package/src/frontend/components/global/header.njk +0 -11
- package/src/frontend/components/welcome.njk +0 -251
- package/src/frontend/data/site.json +0 -44
- package/src/frontend/index.njk +0 -9
- package/src/frontend/js/modules/exampleModule.js +0 -3
- package/src/frontend/js/pages/404.js +0 -7
- package/src/frontend/js/pages/homepage.js +0 -7
- package/src/frontend/layouts/base.njk +0 -137
- package/src/frontend/layouts/pageComponents.njk +0 -14
- package/src/frontend/llms.njk +0 -18
- package/src/frontend/robots.njk +0 -8
- package/src/frontend/scss/modules/_animations.scss +0 -25
- package/src/frontend/scss/modules/_buttons.scss +0 -24
- package/src/frontend/scss/modules/_footer.scss +0 -32
- package/src/frontend/scss/modules/_global.scss +0 -46
- package/src/frontend/scss/modules/_header.scss +0 -33
- package/src/frontend/scss/modules/_mobile.scss +0 -30
- package/src/frontend/scss/modules/_notification.scss +0 -56
- package/src/frontend/scss/modules/_root.scss +0 -35
- package/src/frontend/scss/modules/_typography.scss +0 -15
- package/src/frontend/scss/modules/frameworks/_bootstrap.scss +0 -110
- package/src/frontend/scss/modules/frameworks/_bulma.scss +0 -109
- package/src/frontend/scss/modules/frameworks/_foundation.scss +0 -139
- package/src/frontend/scss/modules/frameworks/_uikit.scss +0 -110
- package/src/frontend/scss/pages/404.scss +0 -28
- package/src/frontend/scss/pages/homepage.scss +0 -23
- package/src/frontend/sitemap.njk +0 -17
- package/src/frontend/ts/modules/exampleModule.ts +0 -3
- package/src/frontend/ts/pages/404.ts +0 -7
- package/src/frontend/ts/pages/homepage.ts +0 -7
- package/src/frontend/web.config +0 -27
- package/tsconfig.json +0 -25
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const { PATHS } = require('./constants');
|
|
3
|
-
const { toCamelCase, toNiceTitle } = require('./utils');
|
|
4
|
-
|
|
5
|
-
function readSiteData() {
|
|
6
|
-
if (!fs.existsSync(PATHS.siteData)) {
|
|
7
|
-
console.log(`[skip] not found: ${PATHS.siteData}`);
|
|
8
|
-
return null;
|
|
9
|
-
}
|
|
10
|
-
try {
|
|
11
|
-
const data = JSON.parse(fs.readFileSync(PATHS.siteData, 'utf8'));
|
|
12
|
-
if (!data.pages || typeof data.pages !== 'object') data.pages = {};
|
|
13
|
-
return data;
|
|
14
|
-
} catch (err) {
|
|
15
|
-
console.log(`[error] cannot parse site.json: ${err.message}`);
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function writeSiteData(data) {
|
|
21
|
-
fs.writeFileSync(PATHS.siteData, `${JSON.stringify(data, null, 2)}\n`);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function addSiteData(pageName) {
|
|
25
|
-
const data = readSiteData();
|
|
26
|
-
if (!data) return;
|
|
27
|
-
|
|
28
|
-
const camelName = toCamelCase(pageName);
|
|
29
|
-
if (data.pages[camelName]) {
|
|
30
|
-
console.log(`[skip] record "${camelName}" already exists`);
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
data.pages[camelName] = {
|
|
35
|
-
seo: { title: toNiceTitle(pageName), description: 'description' },
|
|
36
|
-
cdn: { css: [], js: [] },
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
writeSiteData(data);
|
|
40
|
-
console.log(`[updated] record "${camelName}" added`);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function removeSiteData(pageName) {
|
|
44
|
-
const data = readSiteData();
|
|
45
|
-
if (!data) return;
|
|
46
|
-
|
|
47
|
-
const camelName = toCamelCase(pageName);
|
|
48
|
-
if (!data.pages[camelName]) {
|
|
49
|
-
console.log(`[skip] record "${camelName}" not found`);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
delete data.pages[camelName];
|
|
54
|
-
writeSiteData(data);
|
|
55
|
-
console.log(`[cleaned] record "${camelName}" removed`);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function renameSiteData(oldName, newName) {
|
|
59
|
-
const data = readSiteData();
|
|
60
|
-
if (!data) return;
|
|
61
|
-
|
|
62
|
-
const oldCamel = toCamelCase(oldName);
|
|
63
|
-
const newCamel = toCamelCase(newName);
|
|
64
|
-
|
|
65
|
-
if (!data.pages[oldCamel]) {
|
|
66
|
-
console.log(`[skip] record "${oldCamel}" not found`);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
if (data.pages[newCamel]) {
|
|
70
|
-
console.log(`[skip] record "${newCamel}" already exists`);
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
data.pages[newCamel] = {
|
|
75
|
-
...data.pages[oldCamel],
|
|
76
|
-
seo: { ...data.pages[oldCamel].seo, title: toNiceTitle(newName) },
|
|
77
|
-
};
|
|
78
|
-
delete data.pages[oldCamel];
|
|
79
|
-
|
|
80
|
-
writeSiteData(data);
|
|
81
|
-
console.log(`[updated] record "${oldCamel}" renamed to "${newCamel}"`);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
module.exports = { addSiteData, removeSiteData, renameSiteData };
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const { PATHS } = require('./constants');
|
|
4
|
-
const { isTypeScriptProject } = require('./utils');
|
|
5
|
-
|
|
6
|
-
const OUTPUT_DIR_REGEX = /const OUTPUT_DIR\s*=\s*['"`]([^'"`]*)['"`]/;
|
|
7
|
-
const TSCONFIG_OUTDIR_REGEX = /"outDir"\s*:\s*"[^"]*"/;
|
|
8
|
-
|
|
9
|
-
function parseOutputDir(content) {
|
|
10
|
-
const match = content.match(OUTPUT_DIR_REGEX);
|
|
11
|
-
return match ? match[1] : null;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function updateEleventyConfig(newPath) {
|
|
15
|
-
const content = fs.readFileSync(PATHS.eleventyConfig, 'utf8');
|
|
16
|
-
const updated = content.replace(OUTPUT_DIR_REGEX, `const OUTPUT_DIR = "${newPath}"`);
|
|
17
|
-
|
|
18
|
-
if (content === updated) {
|
|
19
|
-
console.log('[skip] OUTPUT_DIR not found in .eleventy.js');
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
fs.writeFileSync(PATHS.eleventyConfig, updated);
|
|
23
|
-
console.log(`[updated] .eleventy.js → ${newPath}`);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function updatePackageJson(newPath) {
|
|
27
|
-
const pkg = JSON.parse(fs.readFileSync(PATHS.packageJson, 'utf8'));
|
|
28
|
-
const scriptGlob = isTypeScriptProject()
|
|
29
|
-
? 'src/frontend/ts/pages/*.ts'
|
|
30
|
-
: 'src/frontend/js/pages/*.js';
|
|
31
|
-
|
|
32
|
-
pkg.outputDir = newPath;
|
|
33
|
-
pkg.scripts = pkg.scripts || {};
|
|
34
|
-
pkg.scripts['build:css'] = `sass src/frontend/scss:${newPath}/css --no-source-map --style=compressed --quiet`;
|
|
35
|
-
pkg.scripts['serve:css'] = `sass --watch src/frontend/scss:${newPath}/css --no-source-map --quiet`;
|
|
36
|
-
pkg.scripts['build:js'] = `esbuild "${scriptGlob}" --bundle --outdir=${newPath}/js/pages --minify`;
|
|
37
|
-
pkg.scripts['serve:js'] = `esbuild "${scriptGlob}" --bundle --outdir=${newPath}/js/pages --watch`;
|
|
38
|
-
|
|
39
|
-
fs.writeFileSync(PATHS.packageJson, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
40
|
-
console.log(`[updated] package.json → ${newPath}`);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function updateTsConfig(newPath) {
|
|
44
|
-
if (!isTypeScriptProject()) return;
|
|
45
|
-
|
|
46
|
-
const content = fs.readFileSync(PATHS.tsconfig, 'utf8');
|
|
47
|
-
const updated = content.replace(TSCONFIG_OUTDIR_REGEX, `"outDir": "./${newPath}/ts"`);
|
|
48
|
-
|
|
49
|
-
if (content === updated) {
|
|
50
|
-
console.log('[skip] outDir not found in tsconfig.json');
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
fs.writeFileSync(PATHS.tsconfig, updated);
|
|
54
|
-
console.log(`[updated] tsconfig.json → ${newPath}/ts`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function deleteOldOutput(oldPath) {
|
|
58
|
-
if (!oldPath) return;
|
|
59
|
-
|
|
60
|
-
const oldAbsPath = path.resolve(PATHS.root, oldPath);
|
|
61
|
-
const insideProject = oldAbsPath.startsWith(PATHS.root + path.sep);
|
|
62
|
-
|
|
63
|
-
if (!insideProject || oldAbsPath === PATHS.root) {
|
|
64
|
-
console.log(`[skip] refusing to delete "${oldAbsPath}" (outside project)`);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
if (fs.existsSync(oldAbsPath)) {
|
|
68
|
-
fs.rmSync(oldAbsPath, { recursive: true, force: true });
|
|
69
|
-
console.log(`[deleted] ${oldAbsPath}`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function updateOutputPath(rawPath) {
|
|
74
|
-
const trimmed = (rawPath ?? '').trim().replace(/\\/g, '/');
|
|
75
|
-
if (!trimmed) {
|
|
76
|
-
console.log('[skip] empty output path');
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const normalizedPath = trimmed === '.'
|
|
81
|
-
? 'out'
|
|
82
|
-
: `${trimmed.replace(/\/$/, '')}/${path.basename(process.cwd())}-out`;
|
|
83
|
-
|
|
84
|
-
let oldPath = null;
|
|
85
|
-
try {
|
|
86
|
-
oldPath = parseOutputDir(fs.readFileSync(PATHS.eleventyConfig, 'utf8'));
|
|
87
|
-
} catch (err) {
|
|
88
|
-
console.log(`[error] cannot read .eleventy.js: ${err.message}`);
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
deleteOldOutput(oldPath);
|
|
93
|
-
|
|
94
|
-
console.log(`\nupdating output path → "${normalizedPath}"`);
|
|
95
|
-
try {
|
|
96
|
-
updatePackageJson(normalizedPath);
|
|
97
|
-
updateEleventyConfig(normalizedPath);
|
|
98
|
-
updateTsConfig(normalizedPath);
|
|
99
|
-
} catch (err) {
|
|
100
|
-
console.log(`[error] could not update output path: ${err.message}`);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function getCurrentOutputPath() {
|
|
105
|
-
try {
|
|
106
|
-
return parseOutputDir(fs.readFileSync(PATHS.eleventyConfig, 'utf8'));
|
|
107
|
-
} catch {
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
module.exports = { updateOutputPath, getCurrentOutputPath };
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
const { PATHS } = require('./constants');
|
|
5
|
-
const { toCamelCase, isTypeScriptProject } = require('./utils');
|
|
6
|
-
const { addSiteData, removeSiteData, renameSiteData } = require('./updateData');
|
|
7
|
-
const { addPageBlock, removePageBlock, renamePageBlock } = require('./pageComponents');
|
|
8
|
-
const { getCurrentOutputPath } = require('./updateOutputPath');
|
|
9
|
-
|
|
10
|
-
function getPageArtifacts(pageName) {
|
|
11
|
-
const camelName = toCamelCase(pageName);
|
|
12
|
-
const usesTs = isTypeScriptProject();
|
|
13
|
-
const scriptDir = usesTs ? PATHS.tsPages : PATHS.jsPages;
|
|
14
|
-
const scriptExt = usesTs ? 'ts' : 'js';
|
|
15
|
-
const outputRoot = path.join(PATHS.root, getCurrentOutputPath() || 'out');
|
|
16
|
-
|
|
17
|
-
return {
|
|
18
|
-
camelName,
|
|
19
|
-
source: {
|
|
20
|
-
scss: path.join(PATHS.scssPages, `${camelName}.scss`),
|
|
21
|
-
script: path.join(scriptDir, `${camelName}.${scriptExt}`),
|
|
22
|
-
route: path.join(PATHS.routes, `${pageName}.njk`),
|
|
23
|
-
},
|
|
24
|
-
output: {
|
|
25
|
-
files: [
|
|
26
|
-
path.join(outputRoot, 'js', 'pages', `${camelName}.js`),
|
|
27
|
-
path.join(outputRoot, 'css', 'pages', `${camelName}.css`),
|
|
28
|
-
path.join(outputRoot, `${pageName}.html`),
|
|
29
|
-
path.join(outputRoot, 'pages', `${pageName}.html`),
|
|
30
|
-
],
|
|
31
|
-
folders: [
|
|
32
|
-
path.join(outputRoot, pageName),
|
|
33
|
-
path.join(outputRoot, 'pages', pageName),
|
|
34
|
-
],
|
|
35
|
-
},
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function pageExists(pageName) {
|
|
40
|
-
return fs.existsSync(path.join(PATHS.routes, `${pageName}.njk`));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function applyRouteFrontMatter(filePath, camelName, pageName) {
|
|
44
|
-
const content = fs.readFileSync(filePath, 'utf8')
|
|
45
|
-
.replace(/^title:.*$/m, `title: "${camelName}"`)
|
|
46
|
-
.replace(/^permalink:.*$/m, `permalink: "/${pageName}/"`);
|
|
47
|
-
fs.writeFileSync(filePath, content);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function addPage(pageName) {
|
|
51
|
-
if (pageExists(pageName)) {
|
|
52
|
-
console.log(`[skip] page "${pageName}" already exists`);
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const { camelName, source } = getPageArtifacts(pageName);
|
|
57
|
-
const usesTs = isTypeScriptProject();
|
|
58
|
-
|
|
59
|
-
const creations = [
|
|
60
|
-
{ dest: source.scss, template: 'template.scss', isRoute: false },
|
|
61
|
-
{ dest: source.script, template: usesTs ? 'template.ts' : 'template.js', isRoute: false },
|
|
62
|
-
{ dest: source.route, template: 'template.njk', isRoute: true },
|
|
63
|
-
];
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
creations.forEach(({ dest, template, isRoute }) => {
|
|
67
|
-
const templatePath = path.join(PATHS.templates, template);
|
|
68
|
-
if (!fs.existsSync(templatePath)) {
|
|
69
|
-
console.log(`[skip] template not found: ${templatePath}`);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
74
|
-
fs.copyFileSync(templatePath, dest);
|
|
75
|
-
if (isRoute) applyRouteFrontMatter(dest, camelName, pageName);
|
|
76
|
-
|
|
77
|
-
console.log(`[created] ${dest}`);
|
|
78
|
-
});
|
|
79
|
-
} catch (err) {
|
|
80
|
-
console.log(`[error] could not create page files: ${err.message}`);
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
addPageBlock(pageName);
|
|
85
|
-
addSiteData(pageName);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function renamePage(oldName, newName) {
|
|
89
|
-
if (!pageExists(oldName)) {
|
|
90
|
-
console.log(`[skip] page "${oldName}" does not exist`);
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
if (pageExists(newName)) {
|
|
94
|
-
console.log(`[skip] target page "${newName}" already exists`);
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const oldArtifacts = getPageArtifacts(oldName);
|
|
99
|
-
const newArtifacts = getPageArtifacts(newName);
|
|
100
|
-
|
|
101
|
-
const moves = [
|
|
102
|
-
{ src: oldArtifacts.source.scss, dest: newArtifacts.source.scss },
|
|
103
|
-
{ src: oldArtifacts.source.script, dest: newArtifacts.source.script },
|
|
104
|
-
{ src: oldArtifacts.source.route, dest: newArtifacts.source.route },
|
|
105
|
-
];
|
|
106
|
-
|
|
107
|
-
try {
|
|
108
|
-
moves.forEach(({ src, dest }) => {
|
|
109
|
-
if (!fs.existsSync(src)) {
|
|
110
|
-
console.log(`[skip] not found: ${src}`);
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
114
|
-
fs.renameSync(src, dest);
|
|
115
|
-
console.log(`[renamed] ${src} → ${dest}`);
|
|
116
|
-
|
|
117
|
-
if (dest.endsWith('.njk')) applyRouteFrontMatter(dest, newArtifacts.camelName, newName);
|
|
118
|
-
});
|
|
119
|
-
} catch (err) {
|
|
120
|
-
console.log(`[error] could not rename page files: ${err.message}`);
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
renamePageBlock(oldName, newName);
|
|
125
|
-
renameSiteData(oldName, newName);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function removePage(pageName) {
|
|
129
|
-
if (!pageExists(pageName)) {
|
|
130
|
-
console.log(`[skip] page "${pageName}" does not exist`);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const { source, output } = getPageArtifacts(pageName);
|
|
134
|
-
const filesToDelete = [source.scss, source.script, source.route, ...output.files];
|
|
135
|
-
|
|
136
|
-
filesToDelete.forEach((file) => {
|
|
137
|
-
try {
|
|
138
|
-
if (fs.existsSync(file)) {
|
|
139
|
-
fs.unlinkSync(file);
|
|
140
|
-
console.log(`[deleted] ${file}`);
|
|
141
|
-
}
|
|
142
|
-
} catch (err) {
|
|
143
|
-
console.log(`[error] ${file}: ${err.message}`);
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
output.folders.forEach((folder) => {
|
|
148
|
-
try {
|
|
149
|
-
if (fs.existsSync(folder)) {
|
|
150
|
-
fs.rmSync(folder, { recursive: true, force: true });
|
|
151
|
-
console.log(`[deleted] ${folder}`);
|
|
152
|
-
}
|
|
153
|
-
} catch (err) {
|
|
154
|
-
console.log(`[error] ${folder}: ${err.message}`);
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
removePageBlock(pageName);
|
|
159
|
-
removeSiteData(pageName);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
module.exports = { addPage, removePage, renamePage, pageExists };
|
package/_tools/modules/utils.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const { PATHS } = require('./constants');
|
|
3
|
-
|
|
4
|
-
function toCamelCase(value) {
|
|
5
|
-
return value.toLowerCase().replace(/[-_][a-z0-9]/g, (group) => group.slice(1).toUpperCase());
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
function toKebabCase(value) {
|
|
9
|
-
return value.trim().toLowerCase()
|
|
10
|
-
.replace(/[^a-z0-9\s_-]/g, '')
|
|
11
|
-
.replace(/[\s_]+/g, '-')
|
|
12
|
-
.replace(/-+/g, '-')
|
|
13
|
-
.replace(/^-+|-+$/g, '');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function toNiceTitle(pageName) {
|
|
17
|
-
return pageName.split('-')
|
|
18
|
-
.filter(Boolean)
|
|
19
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
20
|
-
.join(' ');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function isTypeScriptProject() {
|
|
24
|
-
return fs.existsSync(PATHS.tsconfig);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
module.exports = { toCamelCase, toKebabCase, toNiceTitle, isTypeScriptProject };
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
const { MAX_PAGE_NAME_LENGTH, PROTECTED_PAGES } = require('./constants');
|
|
2
|
-
|
|
3
|
-
function validatePageName(name) {
|
|
4
|
-
if (!name) return 'Invalid name.';
|
|
5
|
-
if (name.length > MAX_PAGE_NAME_LENGTH) return `Name must be ${MAX_PAGE_NAME_LENGTH} characters or fewer.`;
|
|
6
|
-
if (!/^[a-z0-9-]+$/.test(name)) return 'Page name can only contain lowercase letters, numbers, and hyphens.';
|
|
7
|
-
if (/^\d/.test(name)) return 'Page name cannot start with a number.';
|
|
8
|
-
if (PROTECTED_PAGES.includes(name)) return `"${name}" is a protected page name.`;
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function validateOutputPath(input) {
|
|
13
|
-
const value = (input ?? '').trim();
|
|
14
|
-
if (!value) return 'Invalid path.';
|
|
15
|
-
if (value.includes('..')) return 'Path cannot contain "..".';
|
|
16
|
-
if (/[<>|?*"']/.test(value)) return 'Path contains invalid characters.';
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
module.exports = { validatePageName, validateOutputPath };
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
//==========================
|
|
2
|
-
// CSS MODULES IMPORTS
|
|
3
|
-
//==========================
|
|
4
|
-
|
|
5
|
-
// Use @use with a namespace to avoid framework variable conflicts:
|
|
6
|
-
// Example: root.$primary
|
|
7
|
-
@use "../modules/root" as root;
|
|
8
|
-
|
|
9
|
-
// This global module contains the import framework, necessary modules for each page and any other common styles
|
|
10
|
-
@import "../modules/global";
|
|
11
|
-
|
|
12
|
-
// Import any other module you need by import down here
|
|
13
|
-
@import "../modules/notification";
|
|
14
|
-
|
|
15
|
-
//==========================
|
|
16
|
-
// PAGE CUSTOM CSS RULES
|
|
17
|
-
//==========================
|
|
18
|
-
|
|
19
|
-
// Add any custom rule specific to this page below
|
|
20
|
-
// These rules override the framework and module styles
|
|
21
|
-
// body {
|
|
22
|
-
// background-color: root.$primary;
|
|
23
|
-
// }
|