rclnodejs 1.8.3 → 1.9.0-alpha.0
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 +46 -37
- package/index.js +29 -0
- package/lib/action/client.js +61 -3
- package/lib/message_info.js +94 -0
- package/lib/node.js +53 -3
- package/lib/parameter_event_handler.js +468 -0
- package/lib/parameter_watcher.js +12 -12
- package/lib/subscription.js +38 -5
- package/lib/timer.js +2 -1
- package/lib/wait_for_message.js +111 -0
- package/package.json +6 -3
- package/prebuilds/linux-arm64/humble-jammy-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-arm64/jazzy-noble-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-arm64/kilted-noble-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/humble-jammy-x64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/jazzy-noble-x64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/kilted-noble-x64-rclnodejs.node +0 -0
- package/scripts/run_asan_test.sh +118 -0
- package/src/executor.cpp +36 -2
- package/src/executor.h +11 -0
- package/src/rcl_action_client_bindings.cpp +70 -1
- package/src/rcl_context_bindings.cpp +3 -3
- package/src/rcl_graph_bindings.cpp +2 -2
- package/src/rcl_subscription_bindings.cpp +70 -2
- package/src/rcl_utilities.cpp +2 -2
- package/tools/jsdoc/Makefile +5 -0
- package/tools/jsdoc/README.md +96 -0
- package/tools/jsdoc/build-index.js +610 -0
- package/tools/jsdoc/publish.js +854 -0
- package/tools/jsdoc/regenerate-published-docs.js +605 -0
- package/tools/jsdoc/static/fonts/OpenSans-Bold-webfont.eot +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-Bold-webfont.svg +1830 -0
- package/tools/jsdoc/static/fonts/OpenSans-Bold-webfont.woff +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-BoldItalic-webfont.svg +1830 -0
- package/tools/jsdoc/static/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-Italic-webfont.eot +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-Italic-webfont.svg +1830 -0
- package/tools/jsdoc/static/fonts/OpenSans-Italic-webfont.woff +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-Light-webfont.eot +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-Light-webfont.svg +1831 -0
- package/tools/jsdoc/static/fonts/OpenSans-Light-webfont.woff +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-LightItalic-webfont.eot +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-LightItalic-webfont.svg +1835 -0
- package/tools/jsdoc/static/fonts/OpenSans-LightItalic-webfont.woff +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-Regular-webfont.eot +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-Regular-webfont.svg +1831 -0
- package/tools/jsdoc/static/fonts/OpenSans-Regular-webfont.woff +0 -0
- package/tools/jsdoc/static/scripts/linenumber.js +25 -0
- package/tools/jsdoc/static/scripts/prettify/Apache-License-2.0.txt +202 -0
- package/tools/jsdoc/static/scripts/prettify/lang-css.js +36 -0
- package/tools/jsdoc/static/scripts/prettify/prettify.js +738 -0
- package/tools/jsdoc/static/styles/jsdoc-default.css +1012 -0
- package/tools/jsdoc/static/styles/prettify-jsdoc.css +111 -0
- package/tools/jsdoc/static/styles/prettify-tomorrow.css +132 -0
- package/tools/jsdoc/tmpl/augments.tmpl +10 -0
- package/tools/jsdoc/tmpl/container.tmpl +193 -0
- package/tools/jsdoc/tmpl/details.tmpl +143 -0
- package/tools/jsdoc/tmpl/example.tmpl +2 -0
- package/tools/jsdoc/tmpl/examples.tmpl +13 -0
- package/tools/jsdoc/tmpl/exceptions.tmpl +17 -0
- package/tools/jsdoc/tmpl/layout.tmpl +83 -0
- package/tools/jsdoc/tmpl/mainpage.tmpl +163 -0
- package/tools/jsdoc/tmpl/members.tmpl +43 -0
- package/tools/jsdoc/tmpl/method.tmpl +124 -0
- package/tools/jsdoc/tmpl/params.tmpl +133 -0
- package/tools/jsdoc/tmpl/properties.tmpl +110 -0
- package/tools/jsdoc/tmpl/returns.tmpl +12 -0
- package/tools/jsdoc/tmpl/source.tmpl +8 -0
- package/tools/jsdoc/tmpl/tutorial.tmpl +19 -0
- package/tools/jsdoc/tmpl/type.tmpl +7 -0
- package/types/action_client.d.ts +8 -0
- package/types/index.d.ts +34 -0
- package/types/message_info.d.ts +72 -0
- package/types/node.d.ts +21 -0
- package/types/parameter_event_handler.d.ts +139 -0
- package/types/subscription.d.ts +14 -2
- package/test_data_integrity.js +0 -108
- package/test_repro_exact.js +0 -57
- package/test_repro_hz.js +0 -86
- package/test_repro_pub.js +0 -36
- package/test_repro_stress.js +0 -83
- package/test_repro_sub.js +0 -64
- package/test_xproc_data.js +0 -64
- package/types/interfaces.d.ts +0 -8895
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# JSDoc Workflow
|
|
2
|
+
|
|
3
|
+
This directory contains the custom JSDoc template, the landing-page generator,
|
|
4
|
+
and the staging script used to prepare the docs content that is published to the
|
|
5
|
+
`gh-pages` branch.
|
|
6
|
+
|
|
7
|
+
## Commands
|
|
8
|
+
|
|
9
|
+
### `npm run docs`
|
|
10
|
+
|
|
11
|
+
Build local docs for the current workspace version.
|
|
12
|
+
|
|
13
|
+
Output:
|
|
14
|
+
|
|
15
|
+
- `docs/<current-version>/`
|
|
16
|
+
- `docs/index.html`
|
|
17
|
+
|
|
18
|
+
Use this to verify the docs for the version currently declared in
|
|
19
|
+
`package.json`.
|
|
20
|
+
|
|
21
|
+
### `npm run docs:gh-pages`
|
|
22
|
+
|
|
23
|
+
Stage the publishable docs tree under `build/gh-pages-docs/`.
|
|
24
|
+
|
|
25
|
+
Behavior:
|
|
26
|
+
|
|
27
|
+
- reads the currently published version set from `origin/gh-pages`
|
|
28
|
+
- preserves that published history
|
|
29
|
+
- regenerates docs for the current workspace version
|
|
30
|
+
- rebuilds the staged landing page index
|
|
31
|
+
|
|
32
|
+
This is the normal command to use for a new release.
|
|
33
|
+
|
|
34
|
+
If you delete `build/` and rerun `npm run docs:gh-pages`, the staged tree will
|
|
35
|
+
still contain all currently published versions. That command recreates
|
|
36
|
+
`build/gh-pages-docs/` by copying the published docs snapshot from
|
|
37
|
+
`origin/gh-pages`, then regenerating only the current workspace version.
|
|
38
|
+
|
|
39
|
+
### `npm run docs:gh-pages:full`
|
|
40
|
+
|
|
41
|
+
Fully rebuild the currently published docs history under
|
|
42
|
+
`build/gh-pages-docs/`.
|
|
43
|
+
|
|
44
|
+
Behavior:
|
|
45
|
+
|
|
46
|
+
- reads the published version set from `origin/gh-pages`
|
|
47
|
+
- rebuilds only those published versions from tags
|
|
48
|
+
- regenerates docs for the current workspace version
|
|
49
|
+
- rebuilds the staged landing page index
|
|
50
|
+
|
|
51
|
+
This does **not** rebuild docs for every historical `rclnodejs` tag. It only
|
|
52
|
+
rebuilds the subset that is actually published online.
|
|
53
|
+
|
|
54
|
+
## New Release Example
|
|
55
|
+
|
|
56
|
+
For a new release such as `1.9.0`:
|
|
57
|
+
|
|
58
|
+
1. Update `package.json` to `1.9.0`.
|
|
59
|
+
2. Run `npm run docs`.
|
|
60
|
+
3. Verify the local output in `docs/1.9.0/` and `docs/index.html`.
|
|
61
|
+
4. Run `npm run docs:gh-pages`.
|
|
62
|
+
5. Verify the staged output in:
|
|
63
|
+
- `build/gh-pages-docs/docs/1.9.0/`
|
|
64
|
+
- `build/gh-pages-docs/docs/index.html`
|
|
65
|
+
- `build/gh-pages-docs/.nojekyll`
|
|
66
|
+
6. Publish the contents of `build/gh-pages-docs/` to the `gh-pages` branch.
|
|
67
|
+
|
|
68
|
+
## Manual Landing Page Rebuild
|
|
69
|
+
|
|
70
|
+
If the staged docs tree already exists and you only want to rebuild
|
|
71
|
+
`build/gh-pages-docs/docs/index.html`, run `tools/jsdoc/build-index.js` against
|
|
72
|
+
that docs root and point it at the package metadata for the latest published
|
|
73
|
+
version.
|
|
74
|
+
|
|
75
|
+
Example for published version `1.8.0`:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
mkdir -p build/gh-pages-docs/.tmp
|
|
79
|
+
git show 1.8.0:package.json > build/gh-pages-docs/.tmp/package-1.8.0.json
|
|
80
|
+
|
|
81
|
+
export RCLNODEJS_DOCS_ROOT="$PWD/build/gh-pages-docs/docs"
|
|
82
|
+
export RCLNODEJS_DOCS_INDEX_PATH="$PWD/build/gh-pages-docs/docs/index.html"
|
|
83
|
+
export RCLNODEJS_LOCAL_INDEX_PATH=''
|
|
84
|
+
export RCLNODEJS_PACKAGE_JSON_PATH="$PWD/build/gh-pages-docs/.tmp/package-1.8.0.json"
|
|
85
|
+
|
|
86
|
+
node tools/jsdoc/build-index.js
|
|
87
|
+
rm -rf build/gh-pages-docs/.tmp
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Notes
|
|
91
|
+
|
|
92
|
+
- The staged publish output keeps shared assets in `build/gh-pages-docs/docs/_static/`.
|
|
93
|
+
- `.nojekyll` must remain in the staged output because the published docs tree
|
|
94
|
+
uses an underscore-prefixed directory.
|
|
95
|
+
- The live docs index is the source of truth for which versions should remain
|
|
96
|
+
published.
|
|
@@ -0,0 +1,610 @@
|
|
|
1
|
+
// Copyright (c) 2026 The Robot Web Tools Contributors. All rights reserved.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const childProcess = require('child_process');
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
const repoRoot = path.resolve(__dirname, '../..');
|
|
22
|
+
const docsRoot = path.resolve(
|
|
23
|
+
process.env.RCLNODEJS_DOCS_ROOT || path.join(repoRoot, 'docs')
|
|
24
|
+
);
|
|
25
|
+
const packageJsonPath = path.resolve(
|
|
26
|
+
process.env.RCLNODEJS_PACKAGE_JSON_PATH || path.join(repoRoot, 'package.json')
|
|
27
|
+
);
|
|
28
|
+
const localIndexPath = process.env.RCLNODEJS_LOCAL_INDEX_PATH
|
|
29
|
+
? path.resolve(process.env.RCLNODEJS_LOCAL_INDEX_PATH)
|
|
30
|
+
: null;
|
|
31
|
+
const docsIndexPath = path.resolve(
|
|
32
|
+
process.env.RCLNODEJS_DOCS_INDEX_PATH || path.join(docsRoot, 'index.html')
|
|
33
|
+
);
|
|
34
|
+
const gitCwd = path.resolve(process.env.RCLNODEJS_GIT_CWD || repoRoot);
|
|
35
|
+
|
|
36
|
+
function readPackageInfo() {
|
|
37
|
+
return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function isVersionDirectory(entryName) {
|
|
41
|
+
return /^\d+\.\d+\.\d+$/.test(entryName);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function compareVersionsDesc(left, right) {
|
|
45
|
+
const leftParts = left.split('.').map(Number);
|
|
46
|
+
const rightParts = right.split('.').map(Number);
|
|
47
|
+
const maxLength = Math.max(leftParts.length, rightParts.length);
|
|
48
|
+
|
|
49
|
+
for (let index = 0; index < maxLength; index += 1) {
|
|
50
|
+
const leftValue = leftParts[index] || 0;
|
|
51
|
+
const rightValue = rightParts[index] || 0;
|
|
52
|
+
|
|
53
|
+
if (leftValue !== rightValue) {
|
|
54
|
+
return rightValue - leftValue;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getAvailableVersions() {
|
|
62
|
+
return fs
|
|
63
|
+
.readdirSync(docsRoot, { withFileTypes: true })
|
|
64
|
+
.filter((entry) => entry.isDirectory() && isVersionDirectory(entry.name))
|
|
65
|
+
.map((entry) => entry.name)
|
|
66
|
+
.sort(compareVersionsDesc);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function runGitCommand(args) {
|
|
70
|
+
try {
|
|
71
|
+
return childProcess
|
|
72
|
+
.execFileSync('git', args, {
|
|
73
|
+
cwd: gitCwd,
|
|
74
|
+
encoding: 'utf8',
|
|
75
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
76
|
+
})
|
|
77
|
+
.trim();
|
|
78
|
+
} catch {
|
|
79
|
+
return '';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getGitTags() {
|
|
84
|
+
const tagsOutput = runGitCommand(['tag', '--list']);
|
|
85
|
+
|
|
86
|
+
return new Set(tagsOutput ? tagsOutput.split('\n').filter(Boolean) : []);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function getTagReleaseDate(tagName) {
|
|
90
|
+
const commitSha = runGitCommand(['rev-list', '-n', '1', tagName]);
|
|
91
|
+
|
|
92
|
+
if (!commitSha) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
runGitCommand(['show', '-s', '--format=%ad', '--date=short', commitSha]) ||
|
|
98
|
+
null
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function buildVersionEntries(packageInfo, versions) {
|
|
103
|
+
const gitTags = getGitTags();
|
|
104
|
+
|
|
105
|
+
return versions.map((version) => {
|
|
106
|
+
const hasTag = gitTags.has(version);
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
version,
|
|
110
|
+
releasedOn: hasTag ? getTagReleaseDate(version) : null,
|
|
111
|
+
docsUrl: `./${version}/index.html`,
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function escapeHtml(value) {
|
|
117
|
+
return String(value)
|
|
118
|
+
.replace(/&/g, '&')
|
|
119
|
+
.replace(/</g, '<')
|
|
120
|
+
.replace(/>/g, '>')
|
|
121
|
+
.replace(/"/g, '"')
|
|
122
|
+
.replace(/'/g, ''');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function renderVersionCards(versionEntries, latestVersion) {
|
|
126
|
+
return versionEntries
|
|
127
|
+
.map((entry) => {
|
|
128
|
+
const latestBadge =
|
|
129
|
+
entry.version === latestVersion
|
|
130
|
+
? '<span class="version-badge">Latest</span>'
|
|
131
|
+
: '';
|
|
132
|
+
const releaseMeta = entry.releasedOn
|
|
133
|
+
? `<p class="version-meta">Released ${escapeHtml(entry.releasedOn)}</p>`
|
|
134
|
+
: '';
|
|
135
|
+
|
|
136
|
+
return `
|
|
137
|
+
<a class="version-card" href="${escapeHtml(entry.docsUrl)}">
|
|
138
|
+
<div class="version-card-header">
|
|
139
|
+
<span class="version-label">Release</span>
|
|
140
|
+
${latestBadge}
|
|
141
|
+
</div>
|
|
142
|
+
<strong class="version-number">v${escapeHtml(entry.version)}</strong>
|
|
143
|
+
${releaseMeta}
|
|
144
|
+
<p class="version-copy">Browse the generated API reference for rclnodejs ${escapeHtml(entry.version)}.</p>
|
|
145
|
+
</a>`;
|
|
146
|
+
})
|
|
147
|
+
.join('');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function renderIndexHtml(packageInfo, versionEntries) {
|
|
151
|
+
const latestEntry = versionEntries[0] || {
|
|
152
|
+
version: packageInfo.version,
|
|
153
|
+
releasedOn: null,
|
|
154
|
+
};
|
|
155
|
+
const latestVersion = latestEntry.version;
|
|
156
|
+
const versionCards = renderVersionCards(versionEntries, latestVersion);
|
|
157
|
+
const versionCount = versionEntries.length;
|
|
158
|
+
const latestReleaseDate = latestEntry.releasedOn
|
|
159
|
+
? `<p>Released on <strong>${escapeHtml(latestEntry.releasedOn)}</strong></p>`
|
|
160
|
+
: '<p>Release date unavailable for this version.</p>';
|
|
161
|
+
|
|
162
|
+
return `<!DOCTYPE html>
|
|
163
|
+
<html lang="en">
|
|
164
|
+
<head>
|
|
165
|
+
<meta charset="utf-8">
|
|
166
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
167
|
+
<title>rclnodejs Documentation</title>
|
|
168
|
+
<style>
|
|
169
|
+
:root {
|
|
170
|
+
--bg: #f3f7fb;
|
|
171
|
+
--bg-deep: #dfeaf4;
|
|
172
|
+
--surface: rgba(255, 255, 255, 0.86);
|
|
173
|
+
--surface-strong: rgba(255, 255, 255, 0.96);
|
|
174
|
+
--border: rgba(28, 53, 77, 0.12);
|
|
175
|
+
--border-strong: rgba(28, 53, 77, 0.18);
|
|
176
|
+
--text: #12263a;
|
|
177
|
+
--text-soft: #486277;
|
|
178
|
+
--text-muted: #667f92;
|
|
179
|
+
--accent: #0b84c9;
|
|
180
|
+
--accent-strong: #08679b;
|
|
181
|
+
--accent-soft: rgba(11, 132, 201, 0.12);
|
|
182
|
+
--shadow-lg: 0 24px 60px rgba(14, 31, 53, 0.14);
|
|
183
|
+
--shadow-md: 0 12px 30px rgba(14, 31, 53, 0.1);
|
|
184
|
+
--radius-xl: 28px;
|
|
185
|
+
--radius-lg: 20px;
|
|
186
|
+
--radius-md: 14px;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
* {
|
|
190
|
+
box-sizing: border-box;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
html {
|
|
194
|
+
background: linear-gradient(180deg, #eff5fa 0%, #f7fbff 100%);
|
|
195
|
+
color: var(--text);
|
|
196
|
+
font-size: 16px;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
body {
|
|
200
|
+
margin: 0;
|
|
201
|
+
font-family: "Open Sans", "Segoe UI", sans-serif;
|
|
202
|
+
line-height: 1.6;
|
|
203
|
+
color: var(--text);
|
|
204
|
+
background: transparent;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
a {
|
|
208
|
+
color: inherit;
|
|
209
|
+
text-decoration: none;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.site-backdrop {
|
|
213
|
+
position: fixed;
|
|
214
|
+
inset: 0;
|
|
215
|
+
background:
|
|
216
|
+
radial-gradient(circle at top left, rgba(11, 132, 201, 0.18), transparent 32%),
|
|
217
|
+
radial-gradient(circle at right 10%, rgba(0, 128, 106, 0.12), transparent 24%),
|
|
218
|
+
linear-gradient(180deg, rgba(255, 255, 255, 0.6), rgba(243, 247, 251, 0.95));
|
|
219
|
+
pointer-events: none;
|
|
220
|
+
z-index: -2;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.site-grid {
|
|
224
|
+
position: fixed;
|
|
225
|
+
inset: 0;
|
|
226
|
+
background-image:
|
|
227
|
+
linear-gradient(rgba(18, 38, 58, 0.03) 1px, transparent 1px),
|
|
228
|
+
linear-gradient(90deg, rgba(18, 38, 58, 0.03) 1px, transparent 1px);
|
|
229
|
+
background-size: 32px 32px;
|
|
230
|
+
mask-image: linear-gradient(180deg, rgba(0, 0, 0, 0.28), transparent 75%);
|
|
231
|
+
pointer-events: none;
|
|
232
|
+
z-index: -1;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.page-shell {
|
|
236
|
+
max-width: 1320px;
|
|
237
|
+
margin: 0 auto;
|
|
238
|
+
padding: 24px;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.hero,
|
|
242
|
+
.panel,
|
|
243
|
+
.footer {
|
|
244
|
+
background: var(--surface-strong);
|
|
245
|
+
border: 1px solid var(--border);
|
|
246
|
+
border-radius: var(--radius-xl);
|
|
247
|
+
box-shadow: var(--shadow-lg);
|
|
248
|
+
backdrop-filter: blur(18px);
|
|
249
|
+
-webkit-backdrop-filter: blur(18px);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.hero {
|
|
253
|
+
display: grid;
|
|
254
|
+
grid-template-columns: minmax(0, 1.35fr) minmax(280px, 0.8fr);
|
|
255
|
+
gap: 24px;
|
|
256
|
+
padding: 34px;
|
|
257
|
+
overflow: hidden;
|
|
258
|
+
position: relative;
|
|
259
|
+
background:
|
|
260
|
+
linear-gradient(135deg, rgba(255, 255, 255, 0.96), rgba(231, 243, 250, 0.9)),
|
|
261
|
+
linear-gradient(120deg, rgba(11, 132, 201, 0.16), transparent 42%);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.hero::after {
|
|
265
|
+
content: "";
|
|
266
|
+
position: absolute;
|
|
267
|
+
top: -50px;
|
|
268
|
+
right: -50px;
|
|
269
|
+
width: 200px;
|
|
270
|
+
height: 200px;
|
|
271
|
+
border-radius: 50%;
|
|
272
|
+
background: radial-gradient(circle, rgba(11, 132, 201, 0.16), transparent 68%);
|
|
273
|
+
pointer-events: none;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.eyebrow {
|
|
277
|
+
margin: 0 0 10px;
|
|
278
|
+
text-transform: uppercase;
|
|
279
|
+
letter-spacing: 0.18em;
|
|
280
|
+
font-size: 0.74rem;
|
|
281
|
+
font-weight: 700;
|
|
282
|
+
color: var(--accent-strong);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.hero h1 {
|
|
286
|
+
margin: 0;
|
|
287
|
+
font-size: clamp(2.8rem, 5vw, 4.8rem);
|
|
288
|
+
line-height: 0.95;
|
|
289
|
+
letter-spacing: -0.07em;
|
|
290
|
+
font-weight: 300;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.hero h1 span {
|
|
294
|
+
display: block;
|
|
295
|
+
margin-top: 8px;
|
|
296
|
+
color: var(--text-muted);
|
|
297
|
+
font-size: 0.42em;
|
|
298
|
+
font-weight: 700;
|
|
299
|
+
letter-spacing: 0;
|
|
300
|
+
text-transform: uppercase;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.hero-copy {
|
|
304
|
+
position: relative;
|
|
305
|
+
z-index: 1;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.hero-description,
|
|
309
|
+
.panel p,
|
|
310
|
+
.summary-card p,
|
|
311
|
+
.version-copy,
|
|
312
|
+
.version-meta,
|
|
313
|
+
.footer {
|
|
314
|
+
color: var(--text-soft);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.hero-description {
|
|
318
|
+
max-width: 48rem;
|
|
319
|
+
margin: 18px 0 0;
|
|
320
|
+
font-size: 1.02rem;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.hero-actions {
|
|
324
|
+
display: flex;
|
|
325
|
+
flex-wrap: wrap;
|
|
326
|
+
gap: 12px;
|
|
327
|
+
margin-top: 22px;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.hero-action {
|
|
331
|
+
display: inline-flex;
|
|
332
|
+
align-items: center;
|
|
333
|
+
justify-content: center;
|
|
334
|
+
min-height: 48px;
|
|
335
|
+
padding: 0 16px;
|
|
336
|
+
border-radius: 14px;
|
|
337
|
+
border: 1px solid var(--border-strong);
|
|
338
|
+
background: rgba(255, 255, 255, 0.72);
|
|
339
|
+
color: var(--text);
|
|
340
|
+
font-weight: 700;
|
|
341
|
+
transition: transform 160ms ease, background-color 160ms ease, border-color 160ms ease;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.hero-action:hover {
|
|
345
|
+
transform: translateY(-1px);
|
|
346
|
+
background: rgba(255, 255, 255, 0.94);
|
|
347
|
+
border-color: rgba(11, 132, 201, 0.22);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.hero-action.primary {
|
|
351
|
+
background: linear-gradient(135deg, var(--accent), var(--accent-strong));
|
|
352
|
+
border-color: transparent;
|
|
353
|
+
color: #fff;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.panel {
|
|
357
|
+
padding: 22px;
|
|
358
|
+
position: relative;
|
|
359
|
+
z-index: 1;
|
|
360
|
+
background: rgba(248, 252, 255, 0.82);
|
|
361
|
+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.panel-title {
|
|
365
|
+
margin: 0 0 14px;
|
|
366
|
+
color: var(--text);
|
|
367
|
+
font-size: 0.92rem;
|
|
368
|
+
font-weight: 700;
|
|
369
|
+
text-transform: uppercase;
|
|
370
|
+
letter-spacing: 0.12em;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.summary-grid,
|
|
374
|
+
.versions-grid {
|
|
375
|
+
display: grid;
|
|
376
|
+
gap: 18px;
|
|
377
|
+
margin-top: 24px;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.summary-grid {
|
|
381
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.summary-card,
|
|
385
|
+
.version-card {
|
|
386
|
+
background: var(--surface-strong);
|
|
387
|
+
border: 1px solid var(--border);
|
|
388
|
+
border-radius: var(--radius-lg);
|
|
389
|
+
box-shadow: var(--shadow-md);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.summary-card {
|
|
393
|
+
padding: 22px;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.summary-number {
|
|
397
|
+
display: block;
|
|
398
|
+
font-size: 2.2rem;
|
|
399
|
+
line-height: 1;
|
|
400
|
+
letter-spacing: -0.06em;
|
|
401
|
+
font-weight: 300;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.summary-label {
|
|
405
|
+
display: block;
|
|
406
|
+
margin-top: 8px;
|
|
407
|
+
font-weight: 700;
|
|
408
|
+
color: var(--text);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.versions {
|
|
412
|
+
margin-top: 24px;
|
|
413
|
+
padding: 28px 30px;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.section-heading {
|
|
417
|
+
margin: 0;
|
|
418
|
+
font-size: clamp(1.8rem, 2.6vw, 2.6rem);
|
|
419
|
+
line-height: 1.04;
|
|
420
|
+
letter-spacing: -0.05em;
|
|
421
|
+
font-weight: 300;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.section-copy {
|
|
425
|
+
margin: 12px 0 0;
|
|
426
|
+
max-width: 46rem;
|
|
427
|
+
color: var(--text-soft);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
.versions-grid {
|
|
431
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
432
|
+
margin-top: 22px;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.version-card {
|
|
436
|
+
padding: 22px;
|
|
437
|
+
transition: transform 160ms ease, border-color 160ms ease, box-shadow 160ms ease;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.version-card:hover {
|
|
441
|
+
transform: translateY(-2px);
|
|
442
|
+
border-color: rgba(11, 132, 201, 0.24);
|
|
443
|
+
box-shadow: 0 18px 36px rgba(14, 31, 53, 0.12);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
.version-card-header {
|
|
447
|
+
display: flex;
|
|
448
|
+
align-items: center;
|
|
449
|
+
justify-content: space-between;
|
|
450
|
+
gap: 10px;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.version-label,
|
|
454
|
+
.version-badge {
|
|
455
|
+
display: inline-flex;
|
|
456
|
+
align-items: center;
|
|
457
|
+
padding: 0.35rem 0.75rem;
|
|
458
|
+
border-radius: 999px;
|
|
459
|
+
font-size: 0.78rem;
|
|
460
|
+
font-weight: 700;
|
|
461
|
+
text-transform: uppercase;
|
|
462
|
+
letter-spacing: 0.12em;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.version-label {
|
|
466
|
+
background: var(--accent-soft);
|
|
467
|
+
color: var(--accent-strong);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.version-badge {
|
|
471
|
+
background: rgba(0, 128, 106, 0.12);
|
|
472
|
+
color: #0d6a59;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.version-number {
|
|
476
|
+
display: block;
|
|
477
|
+
margin-top: 18px;
|
|
478
|
+
font-size: 2rem;
|
|
479
|
+
line-height: 1;
|
|
480
|
+
letter-spacing: -0.06em;
|
|
481
|
+
font-weight: 300;
|
|
482
|
+
color: var(--text);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.version-meta {
|
|
486
|
+
margin: 10px 0 0;
|
|
487
|
+
font-size: 0.92rem;
|
|
488
|
+
font-weight: 700;
|
|
489
|
+
color: var(--text-muted);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.version-copy {
|
|
493
|
+
margin: 12px 0 0;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.footer {
|
|
497
|
+
margin-top: 24px;
|
|
498
|
+
padding: 18px 22px;
|
|
499
|
+
font-size: 0.92rem;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
@media (max-width: 1100px) {
|
|
503
|
+
.hero,
|
|
504
|
+
.versions-grid,
|
|
505
|
+
.summary-grid {
|
|
506
|
+
grid-template-columns: 1fr 1fr;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
.hero > :first-child {
|
|
510
|
+
grid-column: 1 / -1;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
@media (max-width: 720px) {
|
|
515
|
+
.page-shell {
|
|
516
|
+
padding: 14px;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
.hero,
|
|
520
|
+
.versions-grid,
|
|
521
|
+
.summary-grid {
|
|
522
|
+
grid-template-columns: 1fr;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.hero,
|
|
526
|
+
.versions,
|
|
527
|
+
.panel,
|
|
528
|
+
.footer,
|
|
529
|
+
.summary-card,
|
|
530
|
+
.version-card {
|
|
531
|
+
border-radius: 22px;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.hero,
|
|
535
|
+
.versions {
|
|
536
|
+
padding: 22px 20px;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
</style>
|
|
540
|
+
</head>
|
|
541
|
+
<body>
|
|
542
|
+
<div class="site-backdrop"></div>
|
|
543
|
+
<div class="site-grid"></div>
|
|
544
|
+
<div class="page-shell">
|
|
545
|
+
<section class="hero">
|
|
546
|
+
<div class="hero-copy">
|
|
547
|
+
<p class="eyebrow">Versioned API Reference</p>
|
|
548
|
+
<h1>rclnodejs <span>ROS 2 JavaScript Client</span></h1>
|
|
549
|
+
<p class="hero-description">Browse published API references across released versions. The latest version is highlighted, and every docs build refreshes this landing page automatically.</p>
|
|
550
|
+
<div class="hero-actions">
|
|
551
|
+
<a class="hero-action primary" href="./${escapeHtml(latestVersion)}/index.html">Open Latest Docs</a>
|
|
552
|
+
<a class="hero-action" href="#versions">Browse Versions</a>
|
|
553
|
+
</div>
|
|
554
|
+
</div>
|
|
555
|
+
|
|
556
|
+
<aside class="panel">
|
|
557
|
+
<p class="panel-title">Current Release</p>
|
|
558
|
+
<h2 class="section-heading">v${escapeHtml(latestVersion)}</h2>
|
|
559
|
+
<p>Package version from package.json: <strong>${escapeHtml(packageInfo.version)}</strong></p>
|
|
560
|
+
${latestReleaseDate}
|
|
561
|
+
</aside>
|
|
562
|
+
</section>
|
|
563
|
+
|
|
564
|
+
<section class="summary-grid">
|
|
565
|
+
<article class="summary-card">
|
|
566
|
+
<strong class="summary-number">${versionCount}</strong>
|
|
567
|
+
<span class="summary-label">Published Versions</span>
|
|
568
|
+
<p>All discovered version directories under the docs output root.</p>
|
|
569
|
+
</article>
|
|
570
|
+
|
|
571
|
+
<article class="summary-card">
|
|
572
|
+
<strong class="summary-number">v${escapeHtml(latestVersion)}</strong>
|
|
573
|
+
<span class="summary-label">Latest Version</span>
|
|
574
|
+
<p>The newest semantic version discovered during index generation, with release date information when available.</p>
|
|
575
|
+
</article>
|
|
576
|
+
</section>
|
|
577
|
+
|
|
578
|
+
<section class="panel versions" id="versions">
|
|
579
|
+
<p class="eyebrow">Releases</p>
|
|
580
|
+
<h2 class="section-heading">Choose a documentation snapshot</h2>
|
|
581
|
+
<p class="section-copy">Version entries are generated automatically from the directories currently present in the docs output, so new releases appear after <code>npm run docs</code> without manual HTML edits.</p>
|
|
582
|
+
<div class="versions-grid">${versionCards}</div>
|
|
583
|
+
</section>
|
|
584
|
+
|
|
585
|
+
<footer class="footer">
|
|
586
|
+
Documentation index for ${escapeHtml(packageInfo.name)}. Generated automatically by <code>tools/jsdoc/build-index.js</code>.
|
|
587
|
+
</footer>
|
|
588
|
+
</div>
|
|
589
|
+
</body>
|
|
590
|
+
</html>
|
|
591
|
+
`;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
function writeIndexFiles(html) {
|
|
595
|
+
if (localIndexPath) {
|
|
596
|
+
fs.writeFileSync(localIndexPath, html, 'utf8');
|
|
597
|
+
}
|
|
598
|
+
fs.writeFileSync(docsIndexPath, html, 'utf8');
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
function main() {
|
|
602
|
+
const packageInfo = readPackageInfo();
|
|
603
|
+
const versions = getAvailableVersions();
|
|
604
|
+
const versionEntries = buildVersionEntries(packageInfo, versions);
|
|
605
|
+
const html = renderIndexHtml(packageInfo, versionEntries);
|
|
606
|
+
|
|
607
|
+
writeIndexFiles(html);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
main();
|