nibula 1.2.2 → 1.2.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.
Files changed (50) hide show
  1. package/.eleventy.js +0 -5
  2. package/CHANGELOG.md +21 -9
  3. package/README.md +1 -1
  4. package/bin/create.js +1 -2
  5. package/bin/nibula.js +2 -5
  6. package/nginx.conf +75 -75
  7. package/package.json +74 -74
  8. package/src/backend/_core/index.js +267 -267
  9. package/src/backend/_core/init.js +52 -52
  10. package/src/backend/_core/modules/RateLimiter.js +58 -58
  11. package/src/backend/_core/modules/Response.js +59 -59
  12. package/src/backend/api/protected/example-protected.js +23 -23
  13. package/src/backend/api/public/example-public.js +24 -24
  14. package/src/backend/backend-node.service.example +30 -30
  15. package/src/backend/database/Database.js +46 -46
  16. package/src/backend/example.config.js +37 -37
  17. package/src/backend/package.json +18 -18
  18. package/src/frontend/.htaccess +51 -51
  19. package/src/frontend/assets/brand/favicon.svg +54 -54
  20. package/src/frontend/assets/brand/logo.svg +54 -54
  21. package/src/frontend/data/site.json +48 -48
  22. package/src/frontend/web.config +55 -55
  23. package/tools/assistant.js +122 -151
  24. package/tools/buildJs.js +39 -37
  25. package/tools/cleanOutput.js +23 -25
  26. package/tools/cli/prompt.js +40 -0
  27. package/tools/cli/ui.js +74 -0
  28. package/tools/config/messages.json +76 -0
  29. package/tools/config/settings.json +135 -0
  30. package/tools/lib/colors.js +17 -0
  31. package/tools/lib/files.js +65 -0
  32. package/tools/lib/logger.js +22 -0
  33. package/tools/lib/outputPath.js +141 -0
  34. package/tools/lib/pageActions.js +138 -0
  35. package/tools/lib/pageArtifacts.js +46 -0
  36. package/tools/lib/pageComponents.js +88 -0
  37. package/tools/lib/paths.js +61 -0
  38. package/tools/lib/project.js +54 -0
  39. package/tools/lib/siteData.js +93 -0
  40. package/tools/lib/text.js +47 -0
  41. package/tools/lib/validation.js +39 -0
  42. package/tools/res/templates/template.js +3 -1
  43. package/tools/res/templates/template.ts +3 -1
  44. package/tools/modules/constants.js +0 -66
  45. package/tools/modules/pageComponents.js +0 -77
  46. package/tools/modules/updateData.js +0 -90
  47. package/tools/modules/updateOutputPath.js +0 -112
  48. package/tools/modules/updatePage.js +0 -162
  49. package/tools/modules/utils.js +0 -27
  50. package/tools/modules/validation.js +0 -30
@@ -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 };
@@ -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,30 +0,0 @@
1
- const fs = require('fs');
2
- const { PATHS, PROTECTED_PAGES } = require('./constants');
3
-
4
- function validatePageName(name) {
5
- if (!name) return 'Invalid name.';
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 (/[<>|?*"']/.test(value)) return 'Path contains invalid characters.';
16
- return null;
17
- }
18
-
19
- function checkRequiredFiles() {
20
- const required = [
21
- { label: '.eleventy.js', path: PATHS.eleventyConfig },
22
- { label: 'package.json', path: PATHS.packageJson },
23
- { label: 'src/frontend/data/site.json', path: PATHS.siteData },
24
- { label: 'src/frontend/layouts/page-components.njk', path: PATHS.pageComponents },
25
- { label: 'CLI page templates', path: PATHS.templates },
26
- ];
27
- return required.filter((item) => !fs.existsSync(item.path));
28
- }
29
-
30
- module.exports = { validatePageName, validateOutputPath, checkRequiredFiles };