@rocket/js 0.1.0 → 0.1.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/README.md +14 -5
- package/dist-types/exports/components.d.ts +1 -1
- package/dist-types/exports/icons.d.ts +1 -1
- package/dist-types/exports/layout.d.ts +1 -1
- package/dist-types/src/cli/RocketBuild.d.ts.map +1 -1
- package/dist-types/src/cli/RocketInit.d.ts.map +1 -1
- package/dist-types/src/cli/RocketStart.d.ts +34 -2
- package/dist-types/src/cli/RocketStart.d.ts.map +1 -1
- package/dist-types/src/components.d.ts +2 -0
- package/dist-types/src/components.d.ts.map +1 -1
- package/dist-types/src/icons.d.ts +12 -0
- package/dist-types/src/icons.d.ts.map +1 -1
- package/dist-types/src/layouts/atlas/atlasDocLayout.d.ts.map +1 -1
- package/dist-types/src/layouts/atlas/atlasHeroLayout.d.ts.map +1 -1
- package/dist-types/src/layouts/layout.d.ts +2 -4
- package/dist-types/src/layouts/layout.d.ts.map +1 -1
- package/dist-types/src/standalone-demo-url.d.ts.map +1 -1
- package/dist-types/src/transform.d.ts.map +1 -1
- package/dist-types/src/wds-plugin.d.ts +1 -0
- package/dist-types/src/wds-plugin.d.ts.map +1 -1
- package/exports/components.js +1 -1
- package/exports/icons.js +3 -0
- package/exports/layout.js +1 -1
- package/package.json +1 -1
- package/src/cli/RocketBuild.js +38 -2
- package/src/cli/RocketInit.js +337 -24
- package/src/cli/RocketStart.js +96 -30
- package/src/components.js +19 -0
- package/src/icons.js +15 -0
- package/src/layouts/atlas/atlasDocLayout.js +2 -15
- package/src/layouts/atlas/atlasHeroLayout.js +3 -12
- package/src/layouts/layout.js +2 -12
- package/src/main.js +21 -4
- package/src/standalone-demo-url.js +21 -8
- package/src/transform.js +89 -2
- package/src/wds-plugin.js +14 -9
package/src/cli/RocketInit.js
CHANGED
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
-
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
|
|
5
5
|
const ROCKET_CONFIG_PATH = 'rocket-config.js';
|
|
6
6
|
const INDEX_PAGE_PATH = 'docs/pages/index.rocket.md';
|
|
7
|
+
const SHARED_DATA_PATH = 'docs/pages/sharedData.js';
|
|
8
|
+
const DOCS_PAGE_PATH = 'docs/pages/docs.rocket.md';
|
|
9
|
+
const JAVASCRIPT_DEMO_PAGE_PATH = 'docs/pages/javascript-demo.rocket.md';
|
|
10
|
+
const REQUEST_DEMO_PAGE_PATH = 'docs/pages/request-demo.rocket.md';
|
|
11
|
+
const SITE_STATUS_PAGE_PATH = 'docs/pages/site-status.rocket.js';
|
|
7
12
|
const ROCKET_AGENT_SKILL_PATH = '.agents/skills/rocket/SKILL.md';
|
|
13
|
+
const EXISTING_ROCKET_PAGE_NOISE_THRESHOLD = 3;
|
|
14
|
+
const STARTER_PAGE_FILES = [
|
|
15
|
+
SHARED_DATA_PATH,
|
|
16
|
+
INDEX_PAGE_PATH,
|
|
17
|
+
DOCS_PAGE_PATH,
|
|
18
|
+
JAVASCRIPT_DEMO_PAGE_PATH,
|
|
19
|
+
REQUEST_DEMO_PAGE_PATH,
|
|
20
|
+
SITE_STATUS_PAGE_PATH,
|
|
21
|
+
];
|
|
8
22
|
|
|
9
23
|
const rocketConfigSource = `/** @type {import('@rocket/js/types.js').RocketConfig} */
|
|
10
24
|
export default {
|
|
@@ -12,6 +26,86 @@ export default {
|
|
|
12
26
|
};
|
|
13
27
|
`;
|
|
14
28
|
|
|
29
|
+
const sharedDataSource = `import { resolve } from '@rocket/js/resolve.js';
|
|
30
|
+
|
|
31
|
+
export const headerData = {
|
|
32
|
+
logo: [
|
|
33
|
+
resolve('@rocket/js/docs/assets/rocket-logo-light.svg', import.meta),
|
|
34
|
+
resolve('@rocket/js/docs/assets/rocket-text-no-logo.svg', import.meta),
|
|
35
|
+
],
|
|
36
|
+
homeLink: '/',
|
|
37
|
+
navLinks: [
|
|
38
|
+
{ text: 'Docs', href: '/docs' },
|
|
39
|
+
{ text: 'Demos', href: '/javascript-demo' },
|
|
40
|
+
],
|
|
41
|
+
socials: [],
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/** @type {import('@rocket/js/types.js').FooterSection[]} */
|
|
45
|
+
export const footerData = [];
|
|
46
|
+
|
|
47
|
+
export const heroData = {
|
|
48
|
+
headerData,
|
|
49
|
+
footerData,
|
|
50
|
+
heroMainData: {
|
|
51
|
+
logoNoText: resolve('@rocket/js/docs/assets/rocket-logo-light.svg', import.meta),
|
|
52
|
+
eyebrow: 'ROCKET STARTER',
|
|
53
|
+
title: 'Rocket Site',
|
|
54
|
+
body: 'A static documentation site built with Rocket Pages and Atlas layouts.',
|
|
55
|
+
documentationLink: '/docs',
|
|
56
|
+
documentationText: 'Read the docs',
|
|
57
|
+
setupLink: '/javascript-demo',
|
|
58
|
+
setupText: 'View demos',
|
|
59
|
+
installLabel: 'Build',
|
|
60
|
+
installCommand: 'npm run build',
|
|
61
|
+
},
|
|
62
|
+
whyRocketData: [
|
|
63
|
+
{
|
|
64
|
+
icon: 'file-earmark-text',
|
|
65
|
+
title: 'Plain Pages',
|
|
66
|
+
description: 'Author durable content in Markdown and keep routes explicit.',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
icon: 'play-btn',
|
|
70
|
+
title: 'Live Demos',
|
|
71
|
+
description: 'Use JavaScript Demos for browser examples with standalone URLs.',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
icon: 'arrow-left-right',
|
|
75
|
+
title: 'Request Demos',
|
|
76
|
+
description: 'Show concrete same-site responses without leaving the docs.',
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
quickStartData: {
|
|
80
|
+
title: 'Quick start',
|
|
81
|
+
subtitle: 'From this project:',
|
|
82
|
+
command: ['npm start', 'npm run build'],
|
|
83
|
+
description: 'Edit docs/pages, then run the build before publishing.',
|
|
84
|
+
},
|
|
85
|
+
workflowData: {
|
|
86
|
+
title: 'Starter workflow',
|
|
87
|
+
steps: [
|
|
88
|
+
{
|
|
89
|
+
icon: 'pencil-square',
|
|
90
|
+
title: 'Edit Pages',
|
|
91
|
+
description: 'Update the Markdown and JavaScript Pages under docs/pages.',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
icon: 'terminal',
|
|
95
|
+
title: 'Build',
|
|
96
|
+
description: 'Run npm run build and fix any errors before publishing.',
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export const docData = {
|
|
103
|
+
headerData,
|
|
104
|
+
footerData,
|
|
105
|
+
navigationIconServerBudget: 35,
|
|
106
|
+
};
|
|
107
|
+
`;
|
|
108
|
+
|
|
15
109
|
const indexPageSource = `\`\`\`js server
|
|
16
110
|
export const config = {
|
|
17
111
|
path: '/',
|
|
@@ -19,23 +113,165 @@ export const config = {
|
|
|
19
113
|
title: 'Rocket Site',
|
|
20
114
|
description: 'Documentation built with Rocket.',
|
|
21
115
|
},
|
|
116
|
+
menu: {
|
|
117
|
+
iconName: 'house',
|
|
118
|
+
order: 0,
|
|
119
|
+
},
|
|
22
120
|
};
|
|
23
121
|
|
|
24
|
-
|
|
122
|
+
import { atlasHeroLayout, atlasHeroComponents } from '@rocket/js/layouts/atlasHero.js';
|
|
123
|
+
import { heroData } from './sharedData.js';
|
|
124
|
+
|
|
125
|
+
export const components = atlasHeroComponents;
|
|
126
|
+
export const layout = pageData => atlasHeroLayout(pageData, heroData);
|
|
25
127
|
\`\`\`
|
|
26
128
|
|
|
27
129
|
# Rocket Site
|
|
28
130
|
|
|
29
|
-
This
|
|
131
|
+
This starter is rendered with Rocket's Atlas hero layout.
|
|
30
132
|
|
|
31
133
|
## Next steps
|
|
32
134
|
|
|
33
135
|
- Edit this Page in \`docs/pages/index.rocket.md\`.
|
|
34
|
-
-
|
|
35
|
-
- Add
|
|
136
|
+
- Edit the shared Atlas data in \`docs/pages/sharedData.js\`.
|
|
137
|
+
- Add general documentation Pages under \`docs/pages\` with the Atlas docs layout.
|
|
138
|
+
- Add component reference Pages next to the components they document under \`src\`.
|
|
36
139
|
- Run \`npm run build\` to verify the site.
|
|
37
140
|
`;
|
|
38
141
|
|
|
142
|
+
const docsPageSource = `\`\`\`js server
|
|
143
|
+
export const config = {
|
|
144
|
+
path: '/docs',
|
|
145
|
+
metadata: {
|
|
146
|
+
title: 'Docs',
|
|
147
|
+
description: 'A first Atlas docs Page generated by rocket init.',
|
|
148
|
+
},
|
|
149
|
+
menu: {
|
|
150
|
+
iconName: 'book',
|
|
151
|
+
order: 10,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
import { atlasDocLayout, atlasDocComponents } from '@rocket/js/layouts/atlasDoc.js';
|
|
156
|
+
import { docData } from './sharedData.js';
|
|
157
|
+
|
|
158
|
+
export const components = atlasDocComponents;
|
|
159
|
+
export const layout = pageData => atlasDocLayout(pageData, docData);
|
|
160
|
+
\`\`\`
|
|
161
|
+
|
|
162
|
+
# Docs
|
|
163
|
+
|
|
164
|
+
This Page uses Rocket's package-provided Atlas docs layout.
|
|
165
|
+
|
|
166
|
+
## Authoring Pages
|
|
167
|
+
|
|
168
|
+
Every Page owns its URL with \`config.path\`. General documentation Pages belong under
|
|
169
|
+
\`docs/pages\`, and component reference Pages can live next to the source files they document.
|
|
170
|
+
|
|
171
|
+
## Navigation Icons
|
|
172
|
+
|
|
173
|
+
Atlas docs navigation reads \`menu.iconName\` from Page config. Use Bootstrap Icon names for Pages
|
|
174
|
+
that appear in the left navigation.
|
|
175
|
+
`;
|
|
176
|
+
|
|
177
|
+
const javascriptDemoPageSource = `\`\`\`js server
|
|
178
|
+
export const config = {
|
|
179
|
+
path: '/javascript-demo',
|
|
180
|
+
metadata: {
|
|
181
|
+
title: 'JavaScript Demo',
|
|
182
|
+
description: 'A starter JavaScript Demo with a generated Standalone Demo URL.',
|
|
183
|
+
},
|
|
184
|
+
menu: {
|
|
185
|
+
iconName: 'window',
|
|
186
|
+
order: 20,
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
import { atlasDocLayout, atlasDocComponents } from '@rocket/js/layouts/atlasDoc.js';
|
|
191
|
+
import { docData } from './sharedData.js';
|
|
192
|
+
|
|
193
|
+
export const components = atlasDocComponents;
|
|
194
|
+
export const layout = pageData => atlasDocLayout(pageData, docData);
|
|
195
|
+
\`\`\`
|
|
196
|
+
|
|
197
|
+
# JavaScript Demo
|
|
198
|
+
|
|
199
|
+
Use a \`js demo\` block for browser-rendered examples. Rocket also generates a Standalone Demo URL
|
|
200
|
+
at \`/javascript-demo/_demo/starterButton/\`.
|
|
201
|
+
|
|
202
|
+
\`\`\`js demo label="docs/pages/javascript-demo.rocket.md"
|
|
203
|
+
import { html } from 'lit';
|
|
204
|
+
|
|
205
|
+
export const starterButton = () => html\`<button type="button">Rocket demo</button>\`;
|
|
206
|
+
\`\`\`
|
|
207
|
+
`;
|
|
208
|
+
|
|
209
|
+
const requestDemoPageSource = `\`\`\`js server
|
|
210
|
+
export const config = {
|
|
211
|
+
path: '/request-demo',
|
|
212
|
+
metadata: {
|
|
213
|
+
title: 'Request Demo',
|
|
214
|
+
description: 'A starter Request Demo pointed at a concrete static JSON Page.',
|
|
215
|
+
},
|
|
216
|
+
menu: {
|
|
217
|
+
iconName: 'arrow-left-right',
|
|
218
|
+
order: 30,
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
import { atlasDocLayout, atlasDocComponents } from '@rocket/js/layouts/atlasDoc.js';
|
|
223
|
+
import { docData } from './sharedData.js';
|
|
224
|
+
|
|
225
|
+
export const components = atlasDocComponents;
|
|
226
|
+
export const layout = pageData => atlasDocLayout(pageData, docData);
|
|
227
|
+
\`\`\`
|
|
228
|
+
|
|
229
|
+
# Request Demo
|
|
230
|
+
|
|
231
|
+
Use a Request Demo when readers need to inspect a same-site \`GET\` response. Static Request Demo
|
|
232
|
+
examples should point at concrete paths and avoid query-dependent output.
|
|
233
|
+
|
|
234
|
+
\`\`\`js request-demo url="/api/site-status.json" label="docs/pages/site-status.rocket.js" height=220
|
|
235
|
+
export const config = {
|
|
236
|
+
path: '/api/site-status.json',
|
|
237
|
+
metadata: { title: 'Site Status' },
|
|
238
|
+
menu: false,
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
export default function siteStatusPage() {
|
|
242
|
+
return {
|
|
243
|
+
status: 'ready',
|
|
244
|
+
generatedBy: 'Rocket',
|
|
245
|
+
pages: ['/docs', '/javascript-demo', '/request-demo'],
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
\`\`\`
|
|
249
|
+
`;
|
|
250
|
+
|
|
251
|
+
const siteStatusPageSource = `export const config = {
|
|
252
|
+
path: '/api/site-status.json',
|
|
253
|
+
metadata: { title: 'Site Status' },
|
|
254
|
+
menu: false,
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
export default function siteStatusPage() {
|
|
258
|
+
return {
|
|
259
|
+
status: 'ready',
|
|
260
|
+
generatedBy: 'Rocket',
|
|
261
|
+
pages: ['/docs', '/javascript-demo', '/request-demo'],
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
`;
|
|
265
|
+
|
|
266
|
+
const STARTER_PAGE_SOURCES = new Map([
|
|
267
|
+
[SHARED_DATA_PATH, sharedDataSource],
|
|
268
|
+
[INDEX_PAGE_PATH, indexPageSource],
|
|
269
|
+
[DOCS_PAGE_PATH, docsPageSource],
|
|
270
|
+
[JAVASCRIPT_DEMO_PAGE_PATH, javascriptDemoPageSource],
|
|
271
|
+
[REQUEST_DEMO_PAGE_PATH, requestDemoPageSource],
|
|
272
|
+
[SITE_STATUS_PAGE_PATH, siteStatusPageSource],
|
|
273
|
+
]);
|
|
274
|
+
|
|
39
275
|
const rocketAgentSkillSource = `---
|
|
40
276
|
name: rocket
|
|
41
277
|
description: Use when editing Rocket Pages, config, layouts, component reference Pages, or build behavior in this project.
|
|
@@ -43,18 +279,21 @@ description: Use when editing Rocket Pages, config, layouts, component reference
|
|
|
43
279
|
|
|
44
280
|
# Rocket
|
|
45
281
|
|
|
46
|
-
Use this skill when working on this project's Rocket site.
|
|
47
|
-
|
|
48
282
|
## Rules
|
|
49
283
|
|
|
50
|
-
- Read \`rocket-config.js\`
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
284
|
+
- Read \`rocket-config.js\` first; Page discovery follows \`includeGlobs\`.
|
|
285
|
+
- Every Page owns its URL through \`config.path\`; put general docs in \`docs/pages\` and component docs next to the component.
|
|
286
|
+
- Prefer Markdown for durable content; use JavaScript Pages for request-time or programmatic output.
|
|
287
|
+
- Prefer interactive examples for component and behavior docs; use \`js demo\` when readers benefit from trying the UI.
|
|
288
|
+
- Prefer Atlas docs layouts: \`atlasDocLayout\` for docs, \`atlasHeroLayout\` for a standalone docs home, with matching \`components\` exports.
|
|
289
|
+
- Markdown using Rocket custom elements needs a \`components\` export; use Atlas component maps or \`rocketDemoComponents\`.
|
|
290
|
+
- Add \`menu.iconName\` to Atlas docs navigation Pages so the left navigation has icons.
|
|
291
|
+
- Direct layout re-exports are supported when no local wrapper function is needed.
|
|
292
|
+
- Custom layouts rendering \`rocket-icon\` need \`addBootstrapIconLibrary(pageData)\` before \`document()\`.
|
|
293
|
+
- Static JavaScript Pages render once per concrete path; query/header/cookie/live-data output needs \`render: 'server'\`.
|
|
294
|
+
- Static Request Demos should target concrete non-query URLs.
|
|
295
|
+
- After adding a \`js demo\`, verify the parent Page and Standalone Demo URL \`/page/_demo/demoName/\`.
|
|
296
|
+
- Keep \`npm run build\` passing; record Rocket package issues separately from local workarounds.
|
|
58
297
|
`;
|
|
59
298
|
|
|
60
299
|
export class RocketInit {
|
|
@@ -64,7 +303,7 @@ export class RocketInit {
|
|
|
64
303
|
async setupCommand(program) {
|
|
65
304
|
program
|
|
66
305
|
.command('init')
|
|
67
|
-
.description('create a
|
|
306
|
+
.description('create a Rocket docs starter')
|
|
68
307
|
.action(() => {
|
|
69
308
|
const result = this.init();
|
|
70
309
|
reportInitResult(result);
|
|
@@ -89,8 +328,15 @@ export class RocketInit {
|
|
|
89
328
|
writeJsonFile('package.json', packageJsonUpdate.packageJson);
|
|
90
329
|
}
|
|
91
330
|
|
|
331
|
+
const shouldCreateStarterPages =
|
|
332
|
+
existingRocketPageFileCount(process.cwd()) < EXISTING_ROCKET_PAGE_NOISE_THRESHOLD;
|
|
333
|
+
|
|
92
334
|
writeFileIfMissing(ROCKET_CONFIG_PATH, rocketConfigSource, result);
|
|
93
|
-
|
|
335
|
+
if (shouldCreateStarterPages) {
|
|
336
|
+
for (const filePath of STARTER_PAGE_FILES) {
|
|
337
|
+
writeFileIfMissing(filePath, STARTER_PAGE_SOURCES.get(filePath) || '', result);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
94
340
|
writeFileIfMissing(ROCKET_AGENT_SKILL_PATH, rocketAgentSkillSource, result);
|
|
95
341
|
|
|
96
342
|
return result;
|
|
@@ -204,7 +450,7 @@ function addRocketScript(scripts, { genericName, fallbackName, command, updated,
|
|
|
204
450
|
updated.push(`scripts.${genericName}`);
|
|
205
451
|
return;
|
|
206
452
|
}
|
|
207
|
-
if (scripts[genericName]
|
|
453
|
+
if (scriptRunsRocketCommand(scripts[genericName], genericName)) {
|
|
208
454
|
skipped.push(`scripts.${genericName}`);
|
|
209
455
|
return;
|
|
210
456
|
}
|
|
@@ -237,8 +483,8 @@ function rocketNextSteps(packageJson) {
|
|
|
237
483
|
return ['npx rocket start', 'npx rocket build'];
|
|
238
484
|
}
|
|
239
485
|
return [
|
|
240
|
-
npmScriptCommand(packageJson.scripts, 'start', 'rocket:start'
|
|
241
|
-
npmScriptCommand(packageJson.scripts, 'build', 'rocket:build'
|
|
486
|
+
npmScriptCommand(packageJson.scripts, 'start', 'rocket:start'),
|
|
487
|
+
npmScriptCommand(packageJson.scripts, 'build', 'rocket:build'),
|
|
242
488
|
];
|
|
243
489
|
}
|
|
244
490
|
|
|
@@ -246,18 +492,85 @@ function rocketNextSteps(packageJson) {
|
|
|
246
492
|
* @param {Record<string, any>} scripts
|
|
247
493
|
* @param {string} genericName
|
|
248
494
|
* @param {string} fallbackName
|
|
249
|
-
* @param {string} command
|
|
250
495
|
*/
|
|
251
|
-
function npmScriptCommand(scripts, genericName, fallbackName
|
|
252
|
-
if (scripts[genericName]
|
|
496
|
+
function npmScriptCommand(scripts, genericName, fallbackName) {
|
|
497
|
+
if (scriptRunsRocketCommand(scripts[genericName], genericName)) {
|
|
253
498
|
return genericName === 'start' ? 'npm start' : `npm run ${genericName}`;
|
|
254
499
|
}
|
|
255
|
-
if (scripts[fallbackName]
|
|
500
|
+
if (scriptRunsRocketCommand(scripts[fallbackName], genericName)) {
|
|
256
501
|
return `npm run ${fallbackName}`;
|
|
257
502
|
}
|
|
258
503
|
return `npx rocket ${genericName}`;
|
|
259
504
|
}
|
|
260
505
|
|
|
506
|
+
/**
|
|
507
|
+
* @param {unknown} script
|
|
508
|
+
* @param {string} commandName
|
|
509
|
+
* @returns {boolean}
|
|
510
|
+
*/
|
|
511
|
+
function scriptRunsRocketCommand(script, commandName) {
|
|
512
|
+
if (typeof script !== 'string') {
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
const shellBoundary = '[\\s"\\\'`;&|()]';
|
|
516
|
+
return new RegExp(
|
|
517
|
+
`(^|${shellBoundary})(?:npx\\s+)?rocket\\s+${commandName}(?=$|${shellBoundary})`,
|
|
518
|
+
).test(script);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* @param {string} directory
|
|
523
|
+
* @returns {number}
|
|
524
|
+
*/
|
|
525
|
+
function existingRocketPageFileCount(directory) {
|
|
526
|
+
if (!existsSync(directory)) {
|
|
527
|
+
return 0;
|
|
528
|
+
}
|
|
529
|
+
return countRocketPageFiles(directory, { count: 0 });
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* @param {string} directory
|
|
534
|
+
* @param {{ count: number }} state
|
|
535
|
+
* @returns {number}
|
|
536
|
+
*/
|
|
537
|
+
function countRocketPageFiles(directory, state) {
|
|
538
|
+
if (state.count >= EXISTING_ROCKET_PAGE_NOISE_THRESHOLD) {
|
|
539
|
+
return state.count;
|
|
540
|
+
}
|
|
541
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
542
|
+
if (shouldIgnoreRocketPageScanEntry(entry.name)) {
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
545
|
+
const entryPath = path.join(directory, entry.name);
|
|
546
|
+
if (entry.isDirectory()) {
|
|
547
|
+
countRocketPageFiles(entryPath, state);
|
|
548
|
+
} else if (isRocketPageFile(entry.name)) {
|
|
549
|
+
state.count += 1;
|
|
550
|
+
}
|
|
551
|
+
if (state.count >= EXISTING_ROCKET_PAGE_NOISE_THRESHOLD) {
|
|
552
|
+
return state.count;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
return state.count;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* @param {string} name
|
|
560
|
+
* @returns {boolean}
|
|
561
|
+
*/
|
|
562
|
+
function shouldIgnoreRocketPageScanEntry(name) {
|
|
563
|
+
return ['.git', '.netlify', 'coverage', 'dist', 'node_modules', 'temp'].includes(name);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* @param {string} fileName
|
|
568
|
+
* @returns {boolean}
|
|
569
|
+
*/
|
|
570
|
+
function isRocketPageFile(fileName) {
|
|
571
|
+
return fileName.endsWith('.rocket.md') || fileName.endsWith('.rocket.js');
|
|
572
|
+
}
|
|
573
|
+
|
|
261
574
|
/**
|
|
262
575
|
* @param {string} filePath
|
|
263
576
|
* @param {string} contents
|
package/src/cli/RocketStart.js
CHANGED
|
@@ -5,6 +5,9 @@ import { debounce } from '../debounce.js';
|
|
|
5
5
|
import path from 'path';
|
|
6
6
|
|
|
7
7
|
export class RocketStart {
|
|
8
|
+
/** @type {RocketStartOptions} */
|
|
9
|
+
startOptions = {};
|
|
10
|
+
|
|
8
11
|
/**
|
|
9
12
|
* @param {import('commander').Command} program
|
|
10
13
|
* @param {import('./RocketCli.js').RocketCli} cli
|
|
@@ -12,17 +15,29 @@ export class RocketStart {
|
|
|
12
15
|
async setupCommand(program, cli) {
|
|
13
16
|
this.cli = cli;
|
|
14
17
|
|
|
15
|
-
program
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
program
|
|
19
|
+
.command('start')
|
|
20
|
+
.option('-p, --port <port>', 'port for the development server')
|
|
21
|
+
.option('--no-open', 'do not open the browser')
|
|
22
|
+
.option('--no-watch', 'disable automatic file watching and reloads')
|
|
23
|
+
.action(async options => {
|
|
24
|
+
const startOptions = normalizeStartOptions(options);
|
|
25
|
+
await cli.getConfig();
|
|
26
|
+
await this.start(startOptions);
|
|
27
|
+
});
|
|
19
28
|
}
|
|
20
29
|
|
|
21
|
-
|
|
30
|
+
/**
|
|
31
|
+
* @param {RocketStartOptions} [options]
|
|
32
|
+
*/
|
|
33
|
+
spawnServer(options = {}) {
|
|
22
34
|
process.stdin.setRawMode?.(true);
|
|
23
35
|
return spawn(
|
|
24
36
|
'node',
|
|
25
|
-
|
|
37
|
+
startServerArgs({
|
|
38
|
+
configFilePath: this.cli?.configFilePath,
|
|
39
|
+
options,
|
|
40
|
+
}),
|
|
26
41
|
{
|
|
27
42
|
stdio: 'inherit',
|
|
28
43
|
cwd: process.cwd(),
|
|
@@ -32,36 +47,42 @@ export class RocketStart {
|
|
|
32
47
|
|
|
33
48
|
restartServer() {
|
|
34
49
|
this.server?.kill();
|
|
35
|
-
this.server = this.spawnServer();
|
|
50
|
+
this.server = this.spawnServer(this.startOptions);
|
|
36
51
|
console.clear();
|
|
37
52
|
console.log('Restarting rocket server...');
|
|
38
53
|
}
|
|
39
54
|
|
|
40
|
-
|
|
41
|
-
|
|
55
|
+
/**
|
|
56
|
+
* @param {RocketStartOptions} [options]
|
|
57
|
+
*/
|
|
58
|
+
async start(options = {}) {
|
|
59
|
+
this.startOptions = options;
|
|
60
|
+
this.server = this.spawnServer(options);
|
|
42
61
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
if (options.watch !== false) {
|
|
63
|
+
// watch config
|
|
64
|
+
watch(
|
|
65
|
+
path.join(process.cwd(), this.cli?.configFilePath || 'rocket-config.js'),
|
|
66
|
+
debounce(async (_, filename) => {
|
|
67
|
+
if (!filename) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
this.restartServer();
|
|
71
|
+
}, 100),
|
|
72
|
+
);
|
|
53
73
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
// watch src
|
|
75
|
+
watch(
|
|
76
|
+
import.meta.dirname,
|
|
77
|
+
{ recursive: true },
|
|
78
|
+
debounce(async (_, filename) => {
|
|
79
|
+
if (!filename) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
this.restartServer();
|
|
83
|
+
}, 100),
|
|
84
|
+
);
|
|
85
|
+
}
|
|
65
86
|
|
|
66
87
|
process.stdin.on('data', data => {
|
|
67
88
|
const char = data.toString();
|
|
@@ -77,3 +98,48 @@ export class RocketStart {
|
|
|
77
98
|
console.log('Restart the server with Ctrl+R');
|
|
78
99
|
}
|
|
79
100
|
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @typedef {{ port?: number; open?: boolean; watch?: boolean }} RocketStartOptions
|
|
104
|
+
*/
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @param {{ port?: string; open?: boolean; watch?: boolean }} options
|
|
108
|
+
* @returns {RocketStartOptions}
|
|
109
|
+
*/
|
|
110
|
+
export function normalizeStartOptions(options) {
|
|
111
|
+
return {
|
|
112
|
+
...(options.port !== undefined ? { port: parsePortOption(options.port) } : {}),
|
|
113
|
+
...(options.open !== undefined ? { open: options.open } : {}),
|
|
114
|
+
...(options.watch !== undefined ? { watch: options.watch } : {}),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @param {{ configFilePath?: string; options?: RocketStartOptions }} input
|
|
120
|
+
*/
|
|
121
|
+
export function startServerArgs({ configFilePath, options = {} }) {
|
|
122
|
+
return [
|
|
123
|
+
path.join(import.meta.dirname, '../main.js'),
|
|
124
|
+
configFilePath || '',
|
|
125
|
+
JSON.stringify(options),
|
|
126
|
+
];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @param {string} value
|
|
131
|
+
*/
|
|
132
|
+
function parsePortOption(value) {
|
|
133
|
+
if (!/^\d+$/.test(value)) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`Invalid --port ${JSON.stringify(value)}. Expected an integer from 1 to 65535.`,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
const port = Number(value);
|
|
139
|
+
if (port < 1 || port > 65535) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Invalid --port ${JSON.stringify(value)}. Expected an integer from 1 to 65535.`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
return port;
|
|
145
|
+
}
|
package/src/components.js
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import { resolve } from '@rocket/js/resolve.js';
|
|
2
2
|
import { createComponentHydration } from './component-hydration.js';
|
|
3
3
|
|
|
4
|
+
/** @type {import('@rocket/js/types.js').Components} */
|
|
5
|
+
export const rocketDemoComponents = {
|
|
6
|
+
'rocket-code-block': {
|
|
7
|
+
file: './RocketCodeBlock.js',
|
|
8
|
+
className: 'RocketCodeBlock',
|
|
9
|
+
loading: 'hydrate:onVisible',
|
|
10
|
+
},
|
|
11
|
+
'rocket-js-demo': {
|
|
12
|
+
file: './RocketJsDemo.js',
|
|
13
|
+
className: 'RocketJsDemo',
|
|
14
|
+
loading: 'client',
|
|
15
|
+
},
|
|
16
|
+
'rocket-request-demo': {
|
|
17
|
+
file: './RocketRequestDemo.js',
|
|
18
|
+
className: 'RocketRequestDemo',
|
|
19
|
+
loading: 'client',
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
4
23
|
/**
|
|
5
24
|
* @param {import('@rocket/js/types.js').Components} components
|
|
6
25
|
*/
|
package/src/icons.js
CHANGED
|
@@ -46,6 +46,21 @@ export function iconsFromPath(files) {
|
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
export const rocketBootstrapIconLibraries = {
|
|
50
|
+
bootstrap: iconsFromPackage('bootstrap-icons', 'icons/*.svg'),
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const rocketDefaultBootstrapIconLibrary = 'bootstrap';
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @param {{ addIconLibraries: (iconLibraries: import('@rocket/js/types.js').IconLibrariesConfig, options?: { defaultIconLibrary?: string }) => void }} pageData
|
|
57
|
+
*/
|
|
58
|
+
export function addBootstrapIconLibrary(pageData) {
|
|
59
|
+
pageData.addIconLibraries(rocketBootstrapIconLibraries, {
|
|
60
|
+
defaultIconLibrary: rocketDefaultBootstrapIconLibrary,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
49
64
|
export class IconAssetStore {
|
|
50
65
|
constructor() {
|
|
51
66
|
/** @type {Map<string, { url: string; svg: string; library: string; name: string }>} */
|
|
@@ -5,6 +5,7 @@ import { resolve } from '../../resolve.js';
|
|
|
5
5
|
import { webAwesomeComponents } from '@rocket/js/components/web-awesome.js';
|
|
6
6
|
import { addBootstrapIconLibrary } from '../layout.js';
|
|
7
7
|
import { pageNavigationLinks } from '../../menus/pageNavigation.js';
|
|
8
|
+
import { rocketDemoComponents } from '../../components.js';
|
|
8
9
|
|
|
9
10
|
export const DEFAULT_ATLAS_DOC_NAVIGATION_ICON_SERVER_BUDGET = 35;
|
|
10
11
|
|
|
@@ -35,21 +36,7 @@ export const atlasDocComponents = {
|
|
|
35
36
|
className: 'RocketSocialLink',
|
|
36
37
|
loading: 'server',
|
|
37
38
|
},
|
|
38
|
-
|
|
39
|
-
file: './RocketCodeBlock.js',
|
|
40
|
-
className: 'RocketCodeBlock',
|
|
41
|
-
loading: 'hydrate:onVisible',
|
|
42
|
-
},
|
|
43
|
-
'rocket-js-demo': {
|
|
44
|
-
file: './RocketJsDemo.js',
|
|
45
|
-
className: 'RocketJsDemo',
|
|
46
|
-
loading: 'client',
|
|
47
|
-
},
|
|
48
|
-
'rocket-request-demo': {
|
|
49
|
-
file: './RocketRequestDemo.js',
|
|
50
|
-
className: 'RocketRequestDemo',
|
|
51
|
-
loading: 'client',
|
|
52
|
-
},
|
|
39
|
+
...rocketDemoComponents,
|
|
53
40
|
...webAwesomeComponents,
|
|
54
41
|
};
|
|
55
42
|
|