nibula 1.2.3 → 1.2.5
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/.eleventyignore +3 -3
- package/.github/workflows/publish.yml +37 -0
- package/CHANGELOG.md +166 -135
- package/LICENSE +169 -169
- package/NOTICE +4 -4
- package/README.md +120 -123
- package/bin/create.js +507 -507
- package/bin/nibula.js +316 -307
- package/docs/Assistant CLI.md +65 -65
- package/docs/Backend.md +295 -295
- package/docs/Components.md +84 -84
- package/docs/Creating pages.md +64 -64
- package/docs/Deploy.md +189 -189
- package/docs/Head and SEO.md +138 -138
- package/docs/Javascript.md +50 -50
- package/docs/Styling with SCSS.md +141 -141
- package/nginx.conf +75 -75
- package/package.json +1 -1
- 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 +147 -147
- 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/backend-node.service.example +30 -30
- 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 +27 -27
- package/src/backend/package.json +18 -18
- package/src/backend/web.config +16 -16
- 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 +114 -114
- package/src/frontend/data/site.json +48 -48
- package/src/frontend/index.njk +8 -8
- package/src/frontend/js/modules/exampleModule.js +2 -2
- package/src/frontend/js/pages/404.js +6 -6
- package/src/frontend/js/pages/homepage.js +6 -6
- package/src/frontend/layouts/base.njk +132 -132
- 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/modules/_animations.scss +24 -24
- package/src/frontend/scss/modules/_footer.scss +27 -27
- package/src/frontend/scss/modules/_global.scss +47 -47
- package/src/frontend/scss/modules/_header.scss +27 -27
- package/src/frontend/scss/modules/_mobile.scss +29 -29
- package/src/frontend/scss/modules/_root.scss +34 -34
- package/src/frontend/scss/modules/_typography.scss +14 -14
- 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 +138 -139
- 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/modules/exampleModule.ts +2 -2
- package/src/frontend/ts/pages/404.ts +6 -6
- package/src/frontend/ts/pages/homepage.ts +6 -6
- package/src/frontend/web.config +55 -55
- package/tools/assistant.js +122 -151
- package/tools/buildJs.js +39 -37
- package/tools/cleanOutput.js +23 -25
- package/tools/cli/prompt.js +40 -0
- package/tools/cli/ui.js +74 -0
- package/tools/config/messages.json +78 -0
- package/tools/config/settings.json +135 -0
- package/tools/lib/colors.js +17 -0
- package/tools/lib/files.js +65 -0
- package/tools/lib/logger.js +22 -0
- package/tools/lib/outputPath.js +141 -0
- package/tools/lib/pageActions.js +138 -0
- package/tools/lib/pageArtifacts.js +46 -0
- package/tools/lib/pageComponents.js +88 -0
- package/tools/lib/paths.js +61 -0
- package/tools/lib/project.js +54 -0
- package/tools/lib/siteData.js +93 -0
- package/tools/lib/text.js +47 -0
- package/tools/lib/validation.js +39 -0
- package/tools/res/templates/template.js +7 -5
- package/tools/res/templates/template.njk +8 -8
- package/tools/res/templates/template.scss +22 -22
- package/tools/res/templates/template.ts +7 -5
- package/tsconfig.json +24 -24
- package/tools/modules/constants.js +0 -66
- package/tools/modules/pageComponents.js +0 -77
- package/tools/modules/updateData.js +0 -90
- package/tools/modules/updateOutputPath.js +0 -133
- package/tools/modules/updatePage.js +0 -162
- package/tools/modules/utils.js +0 -27
- package/tools/modules/validation.js +0 -30
package/src/frontend/sitemap.njk
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
---
|
|
2
|
-
permalink: /sitemap.xml
|
|
3
|
-
eleventyExcludeFromCollections: true
|
|
4
|
-
---
|
|
5
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
6
|
-
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
7
|
-
{% for page in collections.all %}
|
|
8
|
-
{% set pageMeta = site.pages[page.data.title] %}
|
|
9
|
-
{% if not page.data.draft and '/404' not in page.url and not (pageMeta and pageMeta.seo.noindex) %}
|
|
10
|
-
<url>
|
|
11
|
-
<loc>{{ site.url }}{{ page.url | lower }}</loc>
|
|
12
|
-
<lastmod>{{ page.date.toISOString() }}</lastmod>
|
|
13
|
-
<changefreq>weekly</changefreq>
|
|
14
|
-
<priority>{{ '1.0' if page.url == '/' else '0.8' }}</priority>
|
|
15
|
-
</url>
|
|
16
|
-
{% endif %}
|
|
17
|
-
{% endfor %}
|
|
1
|
+
---
|
|
2
|
+
permalink: /sitemap.xml
|
|
3
|
+
eleventyExcludeFromCollections: true
|
|
4
|
+
---
|
|
5
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
6
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
7
|
+
{% for page in collections.all %}
|
|
8
|
+
{% set pageMeta = site.pages[page.data.title] %}
|
|
9
|
+
{% if not page.data.draft and '/404' not in page.url and not (pageMeta and pageMeta.seo.noindex) %}
|
|
10
|
+
<url>
|
|
11
|
+
<loc>{{ site.url }}{{ page.url | lower }}</loc>
|
|
12
|
+
<lastmod>{{ page.date.toISOString() }}</lastmod>
|
|
13
|
+
<changefreq>weekly</changefreq>
|
|
14
|
+
<priority>{{ '1.0' if page.url == '/' else '0.8' }}</priority>
|
|
15
|
+
</url>
|
|
16
|
+
{% endif %}
|
|
17
|
+
{% endfor %}
|
|
18
18
|
</urlset>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export function initExampleModule(): void {
|
|
2
|
-
// Module logic here
|
|
1
|
+
export function initExampleModule(): void {
|
|
2
|
+
// Module logic here
|
|
3
3
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// import { initExampleModule } from '../modules/exampleModule';
|
|
2
|
-
|
|
3
|
-
document.addEventListener("DOMContentLoaded", (): void => {
|
|
4
|
-
// initExampleModule();
|
|
5
|
-
});
|
|
6
|
-
|
|
1
|
+
// import { initExampleModule } from '../modules/exampleModule';
|
|
2
|
+
|
|
3
|
+
document.addEventListener("DOMContentLoaded", (): void => {
|
|
4
|
+
// initExampleModule();
|
|
5
|
+
});
|
|
6
|
+
|
|
7
7
|
// Page logic here
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// import { initExampleModule } from '../modules/exampleModule';
|
|
2
|
-
|
|
3
|
-
document.addEventListener("DOMContentLoaded", (): void => {
|
|
4
|
-
// initExampleModule();
|
|
5
|
-
});
|
|
6
|
-
|
|
1
|
+
// import { initExampleModule } from '../modules/exampleModule';
|
|
2
|
+
|
|
3
|
+
document.addEventListener("DOMContentLoaded", (): void => {
|
|
4
|
+
// initExampleModule();
|
|
5
|
+
});
|
|
6
|
+
|
|
7
7
|
// Page logic here
|
package/src/frontend/web.config
CHANGED
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<!--
|
|
3
|
-
IIS config for a Nibula site — covers BOTH backends.
|
|
4
|
-
|
|
5
|
-
IIS (like Apache, unlike nginx) cannot health-check an upstream, so it cannot
|
|
6
|
-
auto-fall back from Node to PHP. URL Rewrite processes rules top-down and the
|
|
7
|
-
first match with stopProcessing="true" wins:
|
|
8
|
-
|
|
9
|
-
- "ApiToNode" wins if present -> /api is reverse-proxied to the Node backend
|
|
10
|
-
(requires the Application Request Routing + URL Rewrite modules, with proxy
|
|
11
|
-
enabled: ARR > Server Proxy Settings > Enable proxy).
|
|
12
|
-
- To use the PHP backend instead, remove or comment the "ApiToNode" rule;
|
|
13
|
-
"ApiToPhp" then rewrites /api to the PHP front controller.
|
|
14
|
-
|
|
15
|
-
On Windows shared hosting without ARR, keep only "ApiToPhp".
|
|
16
|
-
-->
|
|
17
|
-
<configuration>
|
|
18
|
-
<system.webServer>
|
|
19
|
-
<rewrite>
|
|
20
|
-
<rules>
|
|
21
|
-
|
|
22
|
-
<!-- Block sensitive files -->
|
|
23
|
-
<rule name="BlockSensitive" stopProcessing="true">
|
|
24
|
-
<match url="^(web\.config|\..*)$" ignoreCase="true" />
|
|
25
|
-
<action type="CustomResponse" statusCode="404" />
|
|
26
|
-
</rule>
|
|
27
|
-
|
|
28
|
-
<!-- Node backend (requires ARR). Remove this rule to use PHP. -->
|
|
29
|
-
<rule name="ApiToNode" stopProcessing="true">
|
|
30
|
-
<match url="^api/(.*)" ignoreCase="true" />
|
|
31
|
-
<action type="Rewrite" url="http://127.0.0.1:3000/api/{R:1}" appendQueryString="true" />
|
|
32
|
-
<serverVariables>
|
|
33
|
-
<set name="HTTP_X_FORWARDED_PROTO" value="https" />
|
|
34
|
-
</serverVariables>
|
|
35
|
-
</rule>
|
|
36
|
-
|
|
37
|
-
<!-- PHP backend fallback: rewrite /api to the PHP front controller. -->
|
|
38
|
-
<rule name="ApiToPhp" stopProcessing="true">
|
|
39
|
-
<match url="^api/(.*)" ignoreCase="true" />
|
|
40
|
-
<action type="Rewrite" url="backend/_core/index.php" appendQueryString="true" />
|
|
41
|
-
</rule>
|
|
42
|
-
|
|
43
|
-
</rules>
|
|
44
|
-
</rewrite>
|
|
45
|
-
|
|
46
|
-
<directoryBrowse enabled="false" />
|
|
47
|
-
|
|
48
|
-
<httpErrors errorMode="Custom" existingResponse="Replace">
|
|
49
|
-
<remove statusCode="404" />
|
|
50
|
-
<remove statusCode="403" />
|
|
51
|
-
<error statusCode="404" path="/404.html" responseMode="ExecuteURL" />
|
|
52
|
-
<error statusCode="403" path="/404.html" responseMode="ExecuteURL" />
|
|
53
|
-
</httpErrors>
|
|
54
|
-
</system.webServer>
|
|
55
|
-
</configuration>
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
IIS config for a Nibula site — covers BOTH backends.
|
|
4
|
+
|
|
5
|
+
IIS (like Apache, unlike nginx) cannot health-check an upstream, so it cannot
|
|
6
|
+
auto-fall back from Node to PHP. URL Rewrite processes rules top-down and the
|
|
7
|
+
first match with stopProcessing="true" wins:
|
|
8
|
+
|
|
9
|
+
- "ApiToNode" wins if present -> /api is reverse-proxied to the Node backend
|
|
10
|
+
(requires the Application Request Routing + URL Rewrite modules, with proxy
|
|
11
|
+
enabled: ARR > Server Proxy Settings > Enable proxy).
|
|
12
|
+
- To use the PHP backend instead, remove or comment the "ApiToNode" rule;
|
|
13
|
+
"ApiToPhp" then rewrites /api to the PHP front controller.
|
|
14
|
+
|
|
15
|
+
On Windows shared hosting without ARR, keep only "ApiToPhp".
|
|
16
|
+
-->
|
|
17
|
+
<configuration>
|
|
18
|
+
<system.webServer>
|
|
19
|
+
<rewrite>
|
|
20
|
+
<rules>
|
|
21
|
+
|
|
22
|
+
<!-- Block sensitive files -->
|
|
23
|
+
<rule name="BlockSensitive" stopProcessing="true">
|
|
24
|
+
<match url="^(web\.config|\..*)$" ignoreCase="true" />
|
|
25
|
+
<action type="CustomResponse" statusCode="404" />
|
|
26
|
+
</rule>
|
|
27
|
+
|
|
28
|
+
<!-- Node backend (requires ARR). Remove this rule to use PHP. -->
|
|
29
|
+
<rule name="ApiToNode" stopProcessing="true">
|
|
30
|
+
<match url="^api/(.*)" ignoreCase="true" />
|
|
31
|
+
<action type="Rewrite" url="http://127.0.0.1:3000/api/{R:1}" appendQueryString="true" />
|
|
32
|
+
<serverVariables>
|
|
33
|
+
<set name="HTTP_X_FORWARDED_PROTO" value="https" />
|
|
34
|
+
</serverVariables>
|
|
35
|
+
</rule>
|
|
36
|
+
|
|
37
|
+
<!-- PHP backend fallback: rewrite /api to the PHP front controller. -->
|
|
38
|
+
<rule name="ApiToPhp" stopProcessing="true">
|
|
39
|
+
<match url="^api/(.*)" ignoreCase="true" />
|
|
40
|
+
<action type="Rewrite" url="backend/_core/index.php" appendQueryString="true" />
|
|
41
|
+
</rule>
|
|
42
|
+
|
|
43
|
+
</rules>
|
|
44
|
+
</rewrite>
|
|
45
|
+
|
|
46
|
+
<directoryBrowse enabled="false" />
|
|
47
|
+
|
|
48
|
+
<httpErrors errorMode="Custom" existingResponse="Replace">
|
|
49
|
+
<remove statusCode="404" />
|
|
50
|
+
<remove statusCode="403" />
|
|
51
|
+
<error statusCode="404" path="/404.html" responseMode="ExecuteURL" />
|
|
52
|
+
<error statusCode="403" path="/404.html" responseMode="ExecuteURL" />
|
|
53
|
+
</httpErrors>
|
|
54
|
+
</system.webServer>
|
|
55
|
+
</configuration>
|
package/tools/assistant.js
CHANGED
|
@@ -1,152 +1,123 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
const {
|
|
4
|
-
const {
|
|
5
|
-
const {
|
|
6
|
-
const {
|
|
7
|
-
const {
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
const
|
|
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
|
-
console.log(`\n${color.dim}The project may be incomplete or created with a different Nibula version.${color.reset}`);
|
|
125
|
-
rl.close();
|
|
126
|
-
process.exit(1);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
while (true) {
|
|
130
|
-
renderMenu();
|
|
131
|
-
|
|
132
|
-
const choice = await ask(`${color.cyan}❯${color.reset} Choose an option: `);
|
|
133
|
-
if (choice === null) break;
|
|
134
|
-
|
|
135
|
-
const action = MENU_ACTIONS[choice];
|
|
136
|
-
if (!action) {
|
|
137
|
-
console.log(`\n${color.red}✖ Invalid option.${color.reset}`);
|
|
138
|
-
continue;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
await action();
|
|
143
|
-
} catch (err) {
|
|
144
|
-
console.log(`\n${color.red}✖ Unexpected error: ${err.message}${color.reset}`);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
rl.close();
|
|
149
|
-
process.exit(0);
|
|
150
|
-
}
|
|
151
|
-
|
|
1
|
+
const settings = require('./config/settings.json');
|
|
2
|
+
const { message } = require('./lib/logger');
|
|
3
|
+
const { toKebabCase } = require('./lib/text');
|
|
4
|
+
const { validatePageName, validateOutputPath, checkRequiredFiles } = require('./lib/validation');
|
|
5
|
+
const { addPage, removePage, renamePage } = require('./lib/pageActions');
|
|
6
|
+
const { pageExists } = require('./lib/pageArtifacts');
|
|
7
|
+
const { updateOutputPath, getCurrentOutputPath } = require('./lib/outputPath');
|
|
8
|
+
const { ask, confirm, close } = require('./cli/prompt');
|
|
9
|
+
const ui = require('./cli/ui');
|
|
10
|
+
|
|
11
|
+
const NEW_LINE = '\n';
|
|
12
|
+
const NO_PREFIX = '';
|
|
13
|
+
|
|
14
|
+
async function askPageName(prompt) {
|
|
15
|
+
const raw = await ask(prompt);
|
|
16
|
+
if (raw === null) return null;
|
|
17
|
+
|
|
18
|
+
const name = toKebabCase(raw);
|
|
19
|
+
const error = validatePageName(name);
|
|
20
|
+
if (error) {
|
|
21
|
+
ui.error(error);
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return name;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function handleCreate() {
|
|
28
|
+
const name = await askPageName(ui.promptLine(message('cli.createPrompt')));
|
|
29
|
+
if (name) addPage(name);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function handleRemove() {
|
|
33
|
+
const name = await askPageName(ui.promptLine(message('cli.removePrompt')));
|
|
34
|
+
if (!name) return;
|
|
35
|
+
|
|
36
|
+
if (!pageExists(name)) {
|
|
37
|
+
ui.warning(message('cli.pageNotFound', { name }));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const confirmed = await confirm(message('cli.confirmRemove', { name }));
|
|
42
|
+
if (!confirmed) {
|
|
43
|
+
ui.notice(message('cli.cancelled'));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
removePage(name);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function handleRename() {
|
|
50
|
+
const oldName = await askPageName(ui.promptLine(message('cli.renameFromPrompt')));
|
|
51
|
+
if (!oldName) return;
|
|
52
|
+
|
|
53
|
+
const newName = await askPageName(ui.promptLine(message('cli.renameToPrompt'), NO_PREFIX));
|
|
54
|
+
if (!newName) return;
|
|
55
|
+
|
|
56
|
+
if (oldName === newName) {
|
|
57
|
+
ui.warning(message('cli.sameName'));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
renamePage(oldName, newName);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function handleOutputPath() {
|
|
64
|
+
const current = getCurrentOutputPath();
|
|
65
|
+
const prefix = current
|
|
66
|
+
? ui.noticePrefix(message('cli.currentOutputPath', { path: current }))
|
|
67
|
+
: NEW_LINE;
|
|
68
|
+
|
|
69
|
+
const input = await ask(ui.promptLine(message('cli.outputPathPrompt'), prefix));
|
|
70
|
+
if (input === null) return;
|
|
71
|
+
|
|
72
|
+
const error = validateOutputPath(input);
|
|
73
|
+
if (error) {
|
|
74
|
+
ui.error(error);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
updateOutputPath(input);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const ACTIONS = {
|
|
81
|
+
createPage: handleCreate,
|
|
82
|
+
removePage: handleRemove,
|
|
83
|
+
renamePage: handleRename,
|
|
84
|
+
outputPath: handleOutputPath,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
function findAction(choice) {
|
|
88
|
+
const item = settings.cli.menu.find((entry) => entry.key === choice);
|
|
89
|
+
return item ? ACTIONS[item.action] : null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function main() {
|
|
93
|
+
const missing = checkRequiredFiles();
|
|
94
|
+
if (missing.length > 0) {
|
|
95
|
+
ui.renderMissingFiles(missing);
|
|
96
|
+
close();
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
while (true) {
|
|
101
|
+
ui.renderMenu();
|
|
102
|
+
|
|
103
|
+
const choice = await ask(ui.promptLine(message('cli.menuPrompt'), NO_PREFIX));
|
|
104
|
+
if (choice === null) break;
|
|
105
|
+
|
|
106
|
+
const action = findAction(choice);
|
|
107
|
+
if (!action) {
|
|
108
|
+
ui.error(message('cli.invalidOption'));
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
await action();
|
|
114
|
+
} catch (error) {
|
|
115
|
+
ui.error(message('cli.unexpectedError', { error: error.message }));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
close();
|
|
120
|
+
process.exit(0);
|
|
121
|
+
}
|
|
122
|
+
|
|
152
123
|
main();
|
package/tools/buildJs.js
CHANGED
|
@@ -1,37 +1,39 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
esbuild.
|
|
37
|
-
}
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const esbuild = require('esbuild');
|
|
3
|
+
const glob = require('glob');
|
|
4
|
+
const settings = require('./config/settings.json');
|
|
5
|
+
const { PATHS } = require('./lib/paths');
|
|
6
|
+
const { readPackageJson, allScriptEntries } = require('./lib/project');
|
|
7
|
+
|
|
8
|
+
const WATCH_FLAG = '--watch';
|
|
9
|
+
const PATH_SEPARATOR = '/';
|
|
10
|
+
|
|
11
|
+
function toPosix(target) {
|
|
12
|
+
return target.split(path.sep).join(PATH_SEPARATOR);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function collectEntryPoints() {
|
|
16
|
+
return allScriptEntries().flatMap((entries) => glob.sync(toPosix(path.join(PATHS.root, entries))));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const packageJson = readPackageJson();
|
|
20
|
+
const outputDirectory = packageJson[settings.packageJson.outputKey] || settings.project.defaultOutputDirectory;
|
|
21
|
+
const watch = process.argv.includes(WATCH_FLAG);
|
|
22
|
+
const entryPoints = collectEntryPoints();
|
|
23
|
+
|
|
24
|
+
if (entryPoints.length === 0) {
|
|
25
|
+
process.exit(0);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const options = {
|
|
29
|
+
entryPoints,
|
|
30
|
+
bundle: true,
|
|
31
|
+
outdir: path.join(PATHS.root, outputDirectory, ...settings.build.scriptOutput.split(PATH_SEPARATOR)),
|
|
32
|
+
minify: !watch,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
if (watch) {
|
|
36
|
+
esbuild.context(options).then((context) => context.watch()).catch(() => process.exit(1));
|
|
37
|
+
} else {
|
|
38
|
+
esbuild.build(options).catch(() => process.exit(1));
|
|
39
|
+
}
|
package/tools/cleanOutput.js
CHANGED
|
@@ -1,25 +1,23 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
console.log(`(i) nothing to clean → ${outputDir}`);
|
|
25
|
-
}
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const settings = require('./config/settings.json');
|
|
3
|
+
const { PATHS } = require('./lib/paths');
|
|
4
|
+
const { readPackageJson } = require('./lib/project');
|
|
5
|
+
const { removeDirectory } = require('./lib/files');
|
|
6
|
+
const { log } = require('./lib/logger');
|
|
7
|
+
|
|
8
|
+
const OUTPUT_KEY = settings.packageJson.outputKey;
|
|
9
|
+
|
|
10
|
+
const packageJson = readPackageJson();
|
|
11
|
+
|
|
12
|
+
if (!packageJson[OUTPUT_KEY]) {
|
|
13
|
+
log('output.missingConfiguration', { key: OUTPUT_KEY, file: settings.paths.packageJson });
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const outputDirectory = path.resolve(PATHS.root, packageJson[OUTPUT_KEY]);
|
|
18
|
+
|
|
19
|
+
if (removeDirectory(outputDirectory)) {
|
|
20
|
+
log('output.cleaned', { path: outputDirectory });
|
|
21
|
+
} else {
|
|
22
|
+
log('output.nothingToClean', { path: outputDirectory });
|
|
23
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const readline = require('readline');
|
|
2
|
+
const settings = require('../config/settings.json');
|
|
3
|
+
const { color } = require('../lib/colors');
|
|
4
|
+
|
|
5
|
+
const CONTROL_CHARACTERS_PATTERN = /[\x00-\x1F\x7F]/g;
|
|
6
|
+
const AFFIRMATIVE_PATTERN = /^y(es)?$/i;
|
|
7
|
+
const CONFIRM_HINT = settings.cli.confirmHint;
|
|
8
|
+
const EMPTY = '';
|
|
9
|
+
|
|
10
|
+
const readlineInterface = readline.createInterface({
|
|
11
|
+
input: process.stdin,
|
|
12
|
+
output: process.stdout,
|
|
13
|
+
terminal: true,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
function sanitizeInput(value) {
|
|
17
|
+
return (value ?? EMPTY).replace(CONTROL_CHARACTERS_PATTERN, EMPTY).trim();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function ask(prompt) {
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
const onClose = () => resolve(null);
|
|
23
|
+
readlineInterface.once('close', onClose);
|
|
24
|
+
readlineInterface.question(prompt, (answer) => {
|
|
25
|
+
readlineInterface.off('close', onClose);
|
|
26
|
+
resolve(sanitizeInput(answer));
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function confirm(prompt) {
|
|
32
|
+
const answer = await ask(`${prompt} ${color.dim}${CONFIRM_HINT}${color.reset} `);
|
|
33
|
+
return AFFIRMATIVE_PATTERN.test((answer ?? EMPTY).trim());
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function close() {
|
|
37
|
+
readlineInterface.close();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = { ask, confirm, close };
|