nibula 1.6.0 → 1.6.1
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/.eleventy.js +81 -81
- package/CHANGELOG.md +384 -377
- package/LICENSE +169 -169
- package/NOTICE +4 -4
- package/README.md +110 -110
- package/bin/create.js +505 -505
- package/bin/delegate.js +57 -57
- package/bin/nibula.js +302 -302
- package/docs/Assistant CLI.md +65 -65
- package/docs/Backend.md +201 -201
- package/docs/Components.md +140 -140
- package/docs/Creating pages.md +69 -69
- package/docs/Deploy.md +210 -210
- package/docs/Head and SEO.md +139 -139
- package/docs/Javascript.md +126 -126
- package/docs/Styling with SCSS.md +139 -139
- package/nginx.conf +113 -113
- package/package.json +69 -69
- package/src/backend/.htaccess +6 -6
- package/src/backend/_core/composer.json +5 -5
- package/src/backend/_core/composer.lock +492 -492
- package/src/backend/_core/index.js +267 -267
- package/src/backend/_core/index.php +160 -160
- package/src/backend/_core/init.js +52 -52
- package/src/backend/_core/init.php +33 -33
- package/src/backend/_core/modules/RateLimiter.js +58 -58
- package/src/backend/_core/modules/RateLimiter.php +30 -30
- package/src/backend/_core/modules/Response.js +59 -59
- package/src/backend/_core/modules/Response.php +48 -48
- package/src/backend/api/protected/example-protected.js +23 -23
- package/src/backend/api/protected/example-protected.php +16 -16
- package/src/backend/api/public/example-public.js +24 -24
- package/src/backend/api/public/example-public.php +16 -16
- package/src/backend/database/Database.js +46 -46
- package/src/backend/database/Database.php +23 -23
- package/src/backend/example.config.js +37 -37
- package/src/backend/example.config.php +37 -37
- package/src/backend/package.json +17 -17
- package/src/backend/web.config +43 -43
- package/src/frontend/.htaccess +51 -51
- package/src/frontend/404.njk +17 -17
- package/src/frontend/assets/brand/favicon.svg +54 -54
- package/src/frontend/assets/brand/logo.svg +54 -54
- package/src/frontend/components/global/footer.njk +25 -25
- package/src/frontend/components/global/header.njk +6 -6
- package/src/frontend/components/welcome.njk +115 -115
- package/src/frontend/index.njk +8 -8
- package/src/frontend/js/global.js +10 -10
- package/src/frontend/js/modules/exampleModule.js +2 -2
- package/src/frontend/js/pages/404.js +8 -8
- package/src/frontend/js/pages/homepage.js +8 -8
- package/src/frontend/layouts/base.njk +136 -136
- package/src/frontend/layouts/page-components.njk +13 -13
- package/src/frontend/llms.njk +17 -17
- package/src/frontend/robots.njk +7 -7
- package/src/frontend/scss/_global.scss +46 -46
- package/src/frontend/scss/_root.scss +13 -13
- package/src/frontend/scss/modules/_animations.scss +24 -24
- package/src/frontend/scss/modules/_footer.scss +28 -28
- package/src/frontend/scss/modules/_header.scss +26 -26
- package/src/frontend/scss/modules/_mobile.scss +29 -29
- package/src/frontend/scss/modules/_typography.scss +18 -18
- package/src/frontend/scss/modules/frameworks/_bootstrap.scss +109 -109
- package/src/frontend/scss/modules/frameworks/_bulma.scss +108 -108
- package/src/frontend/scss/modules/frameworks/_foundation.scss +137 -137
- package/src/frontend/scss/modules/frameworks/_uikit.scss +109 -109
- package/src/frontend/scss/pages/404.scss +27 -27
- package/src/frontend/scss/pages/homepage.scss +22 -22
- package/src/frontend/sitemap.njk +17 -17
- package/src/frontend/ts/global.ts +11 -11
- package/src/frontend/ts/modules/exampleModule.ts +2 -2
- package/src/frontend/ts/pages/404.ts +8 -8
- package/src/frontend/ts/pages/homepage.ts +8 -8
- package/src/frontend/web.config +51 -51
- package/tools/assistant.js +122 -122
- package/tools/buildJs.js +39 -39
- package/tools/cleanOutput.js +23 -23
- package/tools/cli/prompt.js +40 -40
- package/tools/cli/ui.js +87 -87
- package/tools/config/messages.json +80 -80
- package/tools/config/settings.json +130 -130
- package/tools/lib/colors.js +17 -17
- package/tools/lib/files.js +75 -75
- package/tools/lib/logger.js +22 -22
- package/tools/lib/outputPath.js +141 -141
- package/tools/lib/pageActions.js +146 -146
- package/tools/lib/pageArtifacts.js +46 -46
- package/tools/lib/pageComponents.js +88 -88
- package/tools/lib/pagesData.js +87 -87
- package/tools/lib/paths.js +63 -63
- package/tools/lib/project.js +54 -54
- package/tools/lib/text.js +47 -47
- package/tools/lib/validation.js +40 -40
- package/tools/res/templates/template.js +7 -7
- package/tools/res/templates/template.njk +8 -8
- package/tools/res/templates/template.scss +22 -22
- package/tools/res/templates/template.ts +8 -8
- package/tsconfig.json +24 -24
- package/src/frontend/scss/pages/prova.scss +0 -23
package/tools/lib/outputPath.js
CHANGED
|
@@ -1,141 +1,141 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const settings = require('../config/settings.json');
|
|
3
|
-
const { PATHS } = require('./paths');
|
|
4
|
-
const { readText, writeText, readJson, writeJson, removeDirectory } = require('./files');
|
|
5
|
-
const { log } = require('./logger');
|
|
6
|
-
const { formatText } = require('./text');
|
|
7
|
-
const { isTypeScriptProject, scriptEntries } = require('./project');
|
|
8
|
-
|
|
9
|
-
const OUTPUT_VARIABLE = settings.eleventy.outputVariable;
|
|
10
|
-
const TYPESCRIPT_OUTPUT_KEY = settings.typescript.outputKey;
|
|
11
|
-
const OUTPUT_VARIABLE_PATTERN = new RegExp(`const ${OUTPUT_VARIABLE}\\s*=\\s*['"\`]([^'"\`]*)['"\`]`);
|
|
12
|
-
const TYPESCRIPT_OUTPUT_PATTERN = new RegExp(`"${TYPESCRIPT_OUTPUT_KEY}"\\s*:\\s*"[^"]*"`);
|
|
13
|
-
const WINDOWS_DRIVE_PATTERN = /^[a-zA-Z]:/;
|
|
14
|
-
const BACKSLASH_PATTERN = /\\/g;
|
|
15
|
-
const TRAILING_SLASH_PATTERN = /\/$/;
|
|
16
|
-
const FORWARD_SLASH = '/';
|
|
17
|
-
const RELATIVE_PREFIX = './';
|
|
18
|
-
const EMPTY = '';
|
|
19
|
-
|
|
20
|
-
function parseOutputDirectory(content) {
|
|
21
|
-
const match = content.match(OUTPUT_VARIABLE_PATTERN);
|
|
22
|
-
return match ? match[1] : null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function isAbsolutePath(target) {
|
|
26
|
-
return path.isAbsolute(target) || WINDOWS_DRIVE_PATTERN.test(target);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function updateEleventyConfig(newPath) {
|
|
30
|
-
const content = readText(PATHS.eleventyConfig);
|
|
31
|
-
const updated = content.replace(OUTPUT_VARIABLE_PATTERN, `const ${OUTPUT_VARIABLE} = "${newPath}"`);
|
|
32
|
-
|
|
33
|
-
if (content === updated) {
|
|
34
|
-
log('output.variableMissing', { variable: OUTPUT_VARIABLE, file: settings.paths.eleventyConfig });
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
writeText(PATHS.eleventyConfig, updated);
|
|
38
|
-
log('output.fileUpdated', { file: settings.paths.eleventyConfig, path: newPath });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function updatePackageJson(newPath, oldPath) {
|
|
42
|
-
const packageJson = readJson(PATHS.packageJson);
|
|
43
|
-
const entries = scriptEntries();
|
|
44
|
-
|
|
45
|
-
packageJson[settings.packageJson.outputKey] = newPath;
|
|
46
|
-
packageJson[settings.packageJson.scriptsKey] = packageJson[settings.packageJson.scriptsKey] || {};
|
|
47
|
-
|
|
48
|
-
const scripts = packageJson[settings.packageJson.scriptsKey];
|
|
49
|
-
|
|
50
|
-
for (const { name, marker, template } of settings.outputScripts) {
|
|
51
|
-
const current = scripts[name];
|
|
52
|
-
const token = oldPath ? `${oldPath}${marker}` : null;
|
|
53
|
-
|
|
54
|
-
if (current && token && current.includes(token)) {
|
|
55
|
-
scripts[name] = current.split(token).join(`${newPath}${marker}`);
|
|
56
|
-
} else {
|
|
57
|
-
scripts[name] = formatText(template, { output: newPath, entries });
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
writeJson(PATHS.packageJson, packageJson);
|
|
62
|
-
log('output.fileUpdated', { file: settings.paths.packageJson, path: newPath });
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function updateTypeScriptConfig(newPath) {
|
|
66
|
-
if (!isTypeScriptProject()) return;
|
|
67
|
-
|
|
68
|
-
const prefix = isAbsolutePath(newPath) ? EMPTY : RELATIVE_PREFIX;
|
|
69
|
-
const outputDirectory = `${prefix}${newPath}${FORWARD_SLASH}${settings.typescript.outputSubdirectory}`;
|
|
70
|
-
const content = readText(PATHS.typescriptConfig);
|
|
71
|
-
const updated = content.replace(TYPESCRIPT_OUTPUT_PATTERN, `"${TYPESCRIPT_OUTPUT_KEY}": "${outputDirectory}"`);
|
|
72
|
-
|
|
73
|
-
if (content === updated) {
|
|
74
|
-
log('output.keyMissing', { key: TYPESCRIPT_OUTPUT_KEY, file: settings.paths.typescriptConfig });
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
writeText(PATHS.typescriptConfig, updated);
|
|
78
|
-
log('output.fileUpdated', { file: settings.paths.typescriptConfig, path: outputDirectory });
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function deleteOldOutput(oldPath) {
|
|
82
|
-
if (!oldPath) return;
|
|
83
|
-
|
|
84
|
-
const target = path.resolve(PATHS.root, oldPath);
|
|
85
|
-
const insideProject = target.startsWith(PATHS.root + path.sep);
|
|
86
|
-
|
|
87
|
-
if (!insideProject || target === PATHS.root) {
|
|
88
|
-
log('output.refuseDelete', { path: target });
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
if (removeDirectory(target)) {
|
|
92
|
-
log('output.directoryDeleted', { path: target });
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function normalizeOutputPath(rawPath) {
|
|
97
|
-
const trimmed = (rawPath ?? '').trim().replace(BACKSLASH_PATTERN, FORWARD_SLASH);
|
|
98
|
-
if (!trimmed) return null;
|
|
99
|
-
|
|
100
|
-
if (trimmed === settings.project.currentDirectory) return settings.project.defaultOutputDirectory;
|
|
101
|
-
|
|
102
|
-
const parent = trimmed.replace(TRAILING_SLASH_PATTERN, EMPTY);
|
|
103
|
-
return `${parent}${FORWARD_SLASH}${path.basename(PATHS.root)}${settings.project.outputSuffix}`;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function updateOutputPath(rawPath) {
|
|
107
|
-
const normalizedPath = normalizeOutputPath(rawPath);
|
|
108
|
-
if (!normalizedPath) {
|
|
109
|
-
log('output.emptyPath');
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
let oldPath = null;
|
|
114
|
-
try {
|
|
115
|
-
oldPath = parseOutputDirectory(readText(PATHS.eleventyConfig));
|
|
116
|
-
} catch (error) {
|
|
117
|
-
log('output.readFailed', { file: settings.paths.eleventyConfig, error: error.message });
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
deleteOldOutput(oldPath);
|
|
122
|
-
log('output.updating', { path: normalizedPath });
|
|
123
|
-
|
|
124
|
-
try {
|
|
125
|
-
updatePackageJson(normalizedPath, oldPath);
|
|
126
|
-
updateEleventyConfig(normalizedPath);
|
|
127
|
-
updateTypeScriptConfig(normalizedPath);
|
|
128
|
-
} catch (error) {
|
|
129
|
-
log('output.updateFailed', { error: error.message });
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function getCurrentOutputPath() {
|
|
134
|
-
try {
|
|
135
|
-
return parseOutputDirectory(readText(PATHS.eleventyConfig));
|
|
136
|
-
} catch {
|
|
137
|
-
return null;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
module.exports = { updateOutputPath, getCurrentOutputPath };
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const settings = require('../config/settings.json');
|
|
3
|
+
const { PATHS } = require('./paths');
|
|
4
|
+
const { readText, writeText, readJson, writeJson, removeDirectory } = require('./files');
|
|
5
|
+
const { log } = require('./logger');
|
|
6
|
+
const { formatText } = require('./text');
|
|
7
|
+
const { isTypeScriptProject, scriptEntries } = require('./project');
|
|
8
|
+
|
|
9
|
+
const OUTPUT_VARIABLE = settings.eleventy.outputVariable;
|
|
10
|
+
const TYPESCRIPT_OUTPUT_KEY = settings.typescript.outputKey;
|
|
11
|
+
const OUTPUT_VARIABLE_PATTERN = new RegExp(`const ${OUTPUT_VARIABLE}\\s*=\\s*['"\`]([^'"\`]*)['"\`]`);
|
|
12
|
+
const TYPESCRIPT_OUTPUT_PATTERN = new RegExp(`"${TYPESCRIPT_OUTPUT_KEY}"\\s*:\\s*"[^"]*"`);
|
|
13
|
+
const WINDOWS_DRIVE_PATTERN = /^[a-zA-Z]:/;
|
|
14
|
+
const BACKSLASH_PATTERN = /\\/g;
|
|
15
|
+
const TRAILING_SLASH_PATTERN = /\/$/;
|
|
16
|
+
const FORWARD_SLASH = '/';
|
|
17
|
+
const RELATIVE_PREFIX = './';
|
|
18
|
+
const EMPTY = '';
|
|
19
|
+
|
|
20
|
+
function parseOutputDirectory(content) {
|
|
21
|
+
const match = content.match(OUTPUT_VARIABLE_PATTERN);
|
|
22
|
+
return match ? match[1] : null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isAbsolutePath(target) {
|
|
26
|
+
return path.isAbsolute(target) || WINDOWS_DRIVE_PATTERN.test(target);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function updateEleventyConfig(newPath) {
|
|
30
|
+
const content = readText(PATHS.eleventyConfig);
|
|
31
|
+
const updated = content.replace(OUTPUT_VARIABLE_PATTERN, `const ${OUTPUT_VARIABLE} = "${newPath}"`);
|
|
32
|
+
|
|
33
|
+
if (content === updated) {
|
|
34
|
+
log('output.variableMissing', { variable: OUTPUT_VARIABLE, file: settings.paths.eleventyConfig });
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
writeText(PATHS.eleventyConfig, updated);
|
|
38
|
+
log('output.fileUpdated', { file: settings.paths.eleventyConfig, path: newPath });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function updatePackageJson(newPath, oldPath) {
|
|
42
|
+
const packageJson = readJson(PATHS.packageJson);
|
|
43
|
+
const entries = scriptEntries();
|
|
44
|
+
|
|
45
|
+
packageJson[settings.packageJson.outputKey] = newPath;
|
|
46
|
+
packageJson[settings.packageJson.scriptsKey] = packageJson[settings.packageJson.scriptsKey] || {};
|
|
47
|
+
|
|
48
|
+
const scripts = packageJson[settings.packageJson.scriptsKey];
|
|
49
|
+
|
|
50
|
+
for (const { name, marker, template } of settings.outputScripts) {
|
|
51
|
+
const current = scripts[name];
|
|
52
|
+
const token = oldPath ? `${oldPath}${marker}` : null;
|
|
53
|
+
|
|
54
|
+
if (current && token && current.includes(token)) {
|
|
55
|
+
scripts[name] = current.split(token).join(`${newPath}${marker}`);
|
|
56
|
+
} else {
|
|
57
|
+
scripts[name] = formatText(template, { output: newPath, entries });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
writeJson(PATHS.packageJson, packageJson);
|
|
62
|
+
log('output.fileUpdated', { file: settings.paths.packageJson, path: newPath });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function updateTypeScriptConfig(newPath) {
|
|
66
|
+
if (!isTypeScriptProject()) return;
|
|
67
|
+
|
|
68
|
+
const prefix = isAbsolutePath(newPath) ? EMPTY : RELATIVE_PREFIX;
|
|
69
|
+
const outputDirectory = `${prefix}${newPath}${FORWARD_SLASH}${settings.typescript.outputSubdirectory}`;
|
|
70
|
+
const content = readText(PATHS.typescriptConfig);
|
|
71
|
+
const updated = content.replace(TYPESCRIPT_OUTPUT_PATTERN, `"${TYPESCRIPT_OUTPUT_KEY}": "${outputDirectory}"`);
|
|
72
|
+
|
|
73
|
+
if (content === updated) {
|
|
74
|
+
log('output.keyMissing', { key: TYPESCRIPT_OUTPUT_KEY, file: settings.paths.typescriptConfig });
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
writeText(PATHS.typescriptConfig, updated);
|
|
78
|
+
log('output.fileUpdated', { file: settings.paths.typescriptConfig, path: outputDirectory });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function deleteOldOutput(oldPath) {
|
|
82
|
+
if (!oldPath) return;
|
|
83
|
+
|
|
84
|
+
const target = path.resolve(PATHS.root, oldPath);
|
|
85
|
+
const insideProject = target.startsWith(PATHS.root + path.sep);
|
|
86
|
+
|
|
87
|
+
if (!insideProject || target === PATHS.root) {
|
|
88
|
+
log('output.refuseDelete', { path: target });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (removeDirectory(target)) {
|
|
92
|
+
log('output.directoryDeleted', { path: target });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function normalizeOutputPath(rawPath) {
|
|
97
|
+
const trimmed = (rawPath ?? '').trim().replace(BACKSLASH_PATTERN, FORWARD_SLASH);
|
|
98
|
+
if (!trimmed) return null;
|
|
99
|
+
|
|
100
|
+
if (trimmed === settings.project.currentDirectory) return settings.project.defaultOutputDirectory;
|
|
101
|
+
|
|
102
|
+
const parent = trimmed.replace(TRAILING_SLASH_PATTERN, EMPTY);
|
|
103
|
+
return `${parent}${FORWARD_SLASH}${path.basename(PATHS.root)}${settings.project.outputSuffix}`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function updateOutputPath(rawPath) {
|
|
107
|
+
const normalizedPath = normalizeOutputPath(rawPath);
|
|
108
|
+
if (!normalizedPath) {
|
|
109
|
+
log('output.emptyPath');
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
let oldPath = null;
|
|
114
|
+
try {
|
|
115
|
+
oldPath = parseOutputDirectory(readText(PATHS.eleventyConfig));
|
|
116
|
+
} catch (error) {
|
|
117
|
+
log('output.readFailed', { file: settings.paths.eleventyConfig, error: error.message });
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
deleteOldOutput(oldPath);
|
|
122
|
+
log('output.updating', { path: normalizedPath });
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
updatePackageJson(normalizedPath, oldPath);
|
|
126
|
+
updateEleventyConfig(normalizedPath);
|
|
127
|
+
updateTypeScriptConfig(normalizedPath);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
log('output.updateFailed', { error: error.message });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function getCurrentOutputPath() {
|
|
134
|
+
try {
|
|
135
|
+
return parseOutputDirectory(readText(PATHS.eleventyConfig));
|
|
136
|
+
} catch {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
module.exports = { updateOutputPath, getCurrentOutputPath };
|
package/tools/lib/pageActions.js
CHANGED
|
@@ -1,147 +1,147 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const settings = require('../config/settings.json');
|
|
3
|
-
const { PATHS } = require('./paths');
|
|
4
|
-
const { exists, readText, writeText, copyFile, moveFile, removeFile, removeDirectory, removeDirectoryIfEmpty } = require('./files');
|
|
5
|
-
const { log } = require('./logger');
|
|
6
|
-
const { formatText } = require('./text');
|
|
7
|
-
const { languageSettings } = require('./project');
|
|
8
|
-
const { getPageArtifacts, pageExists } = require('./pageArtifacts');
|
|
9
|
-
const { readPagesData, addPageData, removePageData, renamePageData } = require('./pagesData');
|
|
10
|
-
const { addPageBlock, removePageBlock, renamePageBlock } = require('./pageComponents');
|
|
11
|
-
|
|
12
|
-
const FRONT_MATTER_PATTERNS = Object.freeze({
|
|
13
|
-
title: /^title:.*$/m,
|
|
14
|
-
permalink: /^permalink:.*$/m,
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
function templatePath(name) {
|
|
18
|
-
return path.join(PATHS.templates, name);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function applyFrontMatter(filePath, values, keys = Object.keys(FRONT_MATTER_PATTERNS)) {
|
|
22
|
-
let content = readText(filePath);
|
|
23
|
-
|
|
24
|
-
for (const key of keys) {
|
|
25
|
-
content = content.replace(FRONT_MATTER_PATTERNS[key], formatText(settings.frontMatter[key], values));
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
writeText(filePath, content);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function addPage(pageName) {
|
|
32
|
-
if (pageExists(pageName)) {
|
|
33
|
-
log('page.alreadyExists', { name: pageName });
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const { camelName, source } = getPageArtifacts(pageName);
|
|
38
|
-
const values = { camelName, pageName };
|
|
39
|
-
|
|
40
|
-
const creations = [
|
|
41
|
-
{ destination: source.style, template: settings.page.styleTemplate, isRoute: false },
|
|
42
|
-
{ destination: source.script, template: languageSettings().template, isRoute: false },
|
|
43
|
-
{ destination: source.route, template: settings.page.routeTemplate, isRoute: true },
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
for (const { destination, template, isRoute } of creations) {
|
|
48
|
-
const templateFile = templatePath(template);
|
|
49
|
-
|
|
50
|
-
if (!exists(templateFile)) {
|
|
51
|
-
log('page.templateMissing', { path: templateFile });
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
copyFile(templateFile, destination);
|
|
56
|
-
if (isRoute) applyFrontMatter(destination, values);
|
|
57
|
-
|
|
58
|
-
log('page.fileCreated', { path: destination });
|
|
59
|
-
}
|
|
60
|
-
} catch (error) {
|
|
61
|
-
log('page.createFailed', { error: error.message });
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
addPageBlock(pageName);
|
|
66
|
-
addPageData(pageName);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function renamePage(oldName, newName) {
|
|
70
|
-
if (!pageExists(oldName)) {
|
|
71
|
-
log('page.doesNotExist', { name: oldName });
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
if (pageExists(newName)) {
|
|
75
|
-
log('page.targetExists', { name: newName });
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
if (!readPagesData()) return;
|
|
79
|
-
|
|
80
|
-
const current = getPageArtifacts(oldName);
|
|
81
|
-
const next = getPageArtifacts(newName);
|
|
82
|
-
const values = { camelName: next.camelName, pageName: newName };
|
|
83
|
-
|
|
84
|
-
const moves = [
|
|
85
|
-
{ source: current.source.style, destination: next.source.style, isRoute: false },
|
|
86
|
-
{ source: current.source.script, destination: next.source.script, isRoute: false },
|
|
87
|
-
{ source: current.source.route, destination: next.source.route, isRoute: true },
|
|
88
|
-
];
|
|
89
|
-
|
|
90
|
-
try {
|
|
91
|
-
for (const { source, destination, isRoute } of moves) {
|
|
92
|
-
if (!exists(source)) {
|
|
93
|
-
log('page.fileMissing', { path: source });
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
moveFile(source, destination);
|
|
98
|
-
log('page.fileRenamed', { source, destination });
|
|
99
|
-
|
|
100
|
-
if (isRoute) applyFrontMatter(destination, values, ['permalink']);
|
|
101
|
-
}
|
|
102
|
-
} catch (error) {
|
|
103
|
-
log('page.renameFailed', { error: error.message });
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
renamePageBlock(oldName, newName);
|
|
108
|
-
renamePageData(oldName, newName);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function removePage(pageName) {
|
|
112
|
-
if (!pageExists(pageName)) {
|
|
113
|
-
log('page.doesNotExist', { name: pageName });
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
if (!readPagesData()) return;
|
|
117
|
-
|
|
118
|
-
const { source, output } = getPageArtifacts(pageName);
|
|
119
|
-
const files = [source.style, source.script, source.route, ...output.files];
|
|
120
|
-
|
|
121
|
-
for (const file of files) {
|
|
122
|
-
try {
|
|
123
|
-
if (removeFile(file)) log('page.fileDeleted', { path: file });
|
|
124
|
-
} catch (error) {
|
|
125
|
-
log('page.deleteFailed', { path: file, error: error.message });
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
for (const directory of output.directories) {
|
|
130
|
-
try {
|
|
131
|
-
if (removeDirectory(directory)) log('page.fileDeleted', { path: directory });
|
|
132
|
-
} catch (error) {
|
|
133
|
-
log('page.deleteFailed', { path: directory, error: error.message });
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
removePageBlock(pageName);
|
|
138
|
-
removePageData(pageName);
|
|
139
|
-
|
|
140
|
-
const sourceDirectories = [source.style, source.script, source.route].map(file => path.dirname(file));
|
|
141
|
-
|
|
142
|
-
for (const directory of sourceDirectories) {
|
|
143
|
-
if (removeDirectoryIfEmpty(directory)) log('page.fileDeleted', { path: directory });
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const settings = require('../config/settings.json');
|
|
3
|
+
const { PATHS } = require('./paths');
|
|
4
|
+
const { exists, readText, writeText, copyFile, moveFile, removeFile, removeDirectory, removeDirectoryIfEmpty } = require('./files');
|
|
5
|
+
const { log } = require('./logger');
|
|
6
|
+
const { formatText } = require('./text');
|
|
7
|
+
const { languageSettings } = require('./project');
|
|
8
|
+
const { getPageArtifacts, pageExists } = require('./pageArtifacts');
|
|
9
|
+
const { readPagesData, addPageData, removePageData, renamePageData } = require('./pagesData');
|
|
10
|
+
const { addPageBlock, removePageBlock, renamePageBlock } = require('./pageComponents');
|
|
11
|
+
|
|
12
|
+
const FRONT_MATTER_PATTERNS = Object.freeze({
|
|
13
|
+
title: /^title:.*$/m,
|
|
14
|
+
permalink: /^permalink:.*$/m,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
function templatePath(name) {
|
|
18
|
+
return path.join(PATHS.templates, name);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function applyFrontMatter(filePath, values, keys = Object.keys(FRONT_MATTER_PATTERNS)) {
|
|
22
|
+
let content = readText(filePath);
|
|
23
|
+
|
|
24
|
+
for (const key of keys) {
|
|
25
|
+
content = content.replace(FRONT_MATTER_PATTERNS[key], formatText(settings.frontMatter[key], values));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
writeText(filePath, content);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function addPage(pageName) {
|
|
32
|
+
if (pageExists(pageName)) {
|
|
33
|
+
log('page.alreadyExists', { name: pageName });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const { camelName, source } = getPageArtifacts(pageName);
|
|
38
|
+
const values = { camelName, pageName };
|
|
39
|
+
|
|
40
|
+
const creations = [
|
|
41
|
+
{ destination: source.style, template: settings.page.styleTemplate, isRoute: false },
|
|
42
|
+
{ destination: source.script, template: languageSettings().template, isRoute: false },
|
|
43
|
+
{ destination: source.route, template: settings.page.routeTemplate, isRoute: true },
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
for (const { destination, template, isRoute } of creations) {
|
|
48
|
+
const templateFile = templatePath(template);
|
|
49
|
+
|
|
50
|
+
if (!exists(templateFile)) {
|
|
51
|
+
log('page.templateMissing', { path: templateFile });
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
copyFile(templateFile, destination);
|
|
56
|
+
if (isRoute) applyFrontMatter(destination, values);
|
|
57
|
+
|
|
58
|
+
log('page.fileCreated', { path: destination });
|
|
59
|
+
}
|
|
60
|
+
} catch (error) {
|
|
61
|
+
log('page.createFailed', { error: error.message });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
addPageBlock(pageName);
|
|
66
|
+
addPageData(pageName);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function renamePage(oldName, newName) {
|
|
70
|
+
if (!pageExists(oldName)) {
|
|
71
|
+
log('page.doesNotExist', { name: oldName });
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (pageExists(newName)) {
|
|
75
|
+
log('page.targetExists', { name: newName });
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (!readPagesData()) return;
|
|
79
|
+
|
|
80
|
+
const current = getPageArtifacts(oldName);
|
|
81
|
+
const next = getPageArtifacts(newName);
|
|
82
|
+
const values = { camelName: next.camelName, pageName: newName };
|
|
83
|
+
|
|
84
|
+
const moves = [
|
|
85
|
+
{ source: current.source.style, destination: next.source.style, isRoute: false },
|
|
86
|
+
{ source: current.source.script, destination: next.source.script, isRoute: false },
|
|
87
|
+
{ source: current.source.route, destination: next.source.route, isRoute: true },
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
for (const { source, destination, isRoute } of moves) {
|
|
92
|
+
if (!exists(source)) {
|
|
93
|
+
log('page.fileMissing', { path: source });
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
moveFile(source, destination);
|
|
98
|
+
log('page.fileRenamed', { source, destination });
|
|
99
|
+
|
|
100
|
+
if (isRoute) applyFrontMatter(destination, values, ['permalink']);
|
|
101
|
+
}
|
|
102
|
+
} catch (error) {
|
|
103
|
+
log('page.renameFailed', { error: error.message });
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
renamePageBlock(oldName, newName);
|
|
108
|
+
renamePageData(oldName, newName);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function removePage(pageName) {
|
|
112
|
+
if (!pageExists(pageName)) {
|
|
113
|
+
log('page.doesNotExist', { name: pageName });
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (!readPagesData()) return;
|
|
117
|
+
|
|
118
|
+
const { source, output } = getPageArtifacts(pageName);
|
|
119
|
+
const files = [source.style, source.script, source.route, ...output.files];
|
|
120
|
+
|
|
121
|
+
for (const file of files) {
|
|
122
|
+
try {
|
|
123
|
+
if (removeFile(file)) log('page.fileDeleted', { path: file });
|
|
124
|
+
} catch (error) {
|
|
125
|
+
log('page.deleteFailed', { path: file, error: error.message });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
for (const directory of output.directories) {
|
|
130
|
+
try {
|
|
131
|
+
if (removeDirectory(directory)) log('page.fileDeleted', { path: directory });
|
|
132
|
+
} catch (error) {
|
|
133
|
+
log('page.deleteFailed', { path: directory, error: error.message });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
removePageBlock(pageName);
|
|
138
|
+
removePageData(pageName);
|
|
139
|
+
|
|
140
|
+
const sourceDirectories = [source.style, source.script, source.route].map(file => path.dirname(file));
|
|
141
|
+
|
|
142
|
+
for (const directory of sourceDirectories) {
|
|
143
|
+
if (removeDirectoryIfEmpty(directory)) log('page.fileDeleted', { path: directory });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
147
|
module.exports = { addPage, removePage, renamePage };
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const settings = require('../config/settings.json');
|
|
3
|
-
const { PATHS } = require('./paths');
|
|
4
|
-
const { exists } = require('./files');
|
|
5
|
-
const { languageSettings, scriptPagesDirectory } = require('./project');
|
|
6
|
-
const { getCurrentOutputPath } = require('./outputPath');
|
|
7
|
-
const { toCamelCase, formatText } = require('./text');
|
|
8
|
-
|
|
9
|
-
const PATH_SEPARATOR = '/';
|
|
10
|
-
|
|
11
|
-
function outputRoot() {
|
|
12
|
-
return path.join(PATHS.root, getCurrentOutputPath() || settings.project.defaultOutputDirectory);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function resolveOutput(root, template, values) {
|
|
16
|
-
return path.join(root, ...formatText(template, values).split(PATH_SEPARATOR));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function routeFile(pageName) {
|
|
20
|
-
return path.join(PATHS.routes, `${pageName}.${settings.page.routeExtension}`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function pageExists(pageName) {
|
|
24
|
-
return exists(routeFile(pageName));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function getPageArtifacts(pageName) {
|
|
28
|
-
const camelName = toCamelCase(pageName);
|
|
29
|
-
const values = { camelName, pageName };
|
|
30
|
-
const root = outputRoot();
|
|
31
|
-
|
|
32
|
-
return {
|
|
33
|
-
camelName,
|
|
34
|
-
source: {
|
|
35
|
-
style: path.join(PATHS.stylePages, `${camelName}.${settings.page.styleExtension}`),
|
|
36
|
-
script: path.join(scriptPagesDirectory(), `${camelName}.${languageSettings().extension}`),
|
|
37
|
-
route: routeFile(pageName),
|
|
38
|
-
},
|
|
39
|
-
output: {
|
|
40
|
-
files: settings.page.outputFiles.map((template) => resolveOutput(root, template, values)),
|
|
41
|
-
directories: settings.page.outputDirectories.map((template) => resolveOutput(root, template, values)),
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
module.exports = { getPageArtifacts, pageExists };
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const settings = require('../config/settings.json');
|
|
3
|
+
const { PATHS } = require('./paths');
|
|
4
|
+
const { exists } = require('./files');
|
|
5
|
+
const { languageSettings, scriptPagesDirectory } = require('./project');
|
|
6
|
+
const { getCurrentOutputPath } = require('./outputPath');
|
|
7
|
+
const { toCamelCase, formatText } = require('./text');
|
|
8
|
+
|
|
9
|
+
const PATH_SEPARATOR = '/';
|
|
10
|
+
|
|
11
|
+
function outputRoot() {
|
|
12
|
+
return path.join(PATHS.root, getCurrentOutputPath() || settings.project.defaultOutputDirectory);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function resolveOutput(root, template, values) {
|
|
16
|
+
return path.join(root, ...formatText(template, values).split(PATH_SEPARATOR));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function routeFile(pageName) {
|
|
20
|
+
return path.join(PATHS.routes, `${pageName}.${settings.page.routeExtension}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function pageExists(pageName) {
|
|
24
|
+
return exists(routeFile(pageName));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getPageArtifacts(pageName) {
|
|
28
|
+
const camelName = toCamelCase(pageName);
|
|
29
|
+
const values = { camelName, pageName };
|
|
30
|
+
const root = outputRoot();
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
camelName,
|
|
34
|
+
source: {
|
|
35
|
+
style: path.join(PATHS.stylePages, `${camelName}.${settings.page.styleExtension}`),
|
|
36
|
+
script: path.join(scriptPagesDirectory(), `${camelName}.${languageSettings().extension}`),
|
|
37
|
+
route: routeFile(pageName),
|
|
38
|
+
},
|
|
39
|
+
output: {
|
|
40
|
+
files: settings.page.outputFiles.map((template) => resolveOutput(root, template, values)),
|
|
41
|
+
directories: settings.page.outputDirectories.map((template) => resolveOutput(root, template, values)),
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = { getPageArtifacts, pageExists };
|