Skip to content

Commit d3bfd50

Browse files
committed
tools: generate node_config_schema.h from the json source
Signed-off-by: Mert Can Altin <[email protected]>
1 parent 8d52ce5 commit d3bfd50

4 files changed

Lines changed: 109 additions & 2 deletions

File tree

.github/workflows/linters.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,21 @@ jobs:
283283
- run: tools/lint-readme-lists.mjs "$TEAMS"
284284
env:
285285
TEAMS: ${{ tojson(steps.team_members.outputs) }}
286+
check-config-schema-sync:
287+
if: github.event.pull_request.draft == false
288+
runs-on: ubuntu-slim
289+
steps:
290+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
291+
with:
292+
persist-credentials: false
293+
sparse-checkout: |
294+
/doc/node-config-schema.json
295+
/src/node_config_schema.h
296+
/tools/gen_node_config_schema.mjs
297+
sparse-checkout-cone-mode: false
298+
- name: Use Node.js ${{ env.NODE_VERSION }}
299+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
300+
with:
301+
node-version: ${{ env.NODE_VERSION }}
302+
- name: Verify src/node_config_schema.h matches doc/node-config-schema.json
303+
run: node tools/gen_node_config_schema.mjs --check

doc/node-config-schema.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$comment": "Edit this file. src/node_config_schema.h is regenerated from it by tools/gen_node_config_schema.mjs and verified in CI. additionalProperties:false is stripped from the runtime copy so older Node versions tolerate fields added later.",
34
"additionalProperties": false,
45
"required": [],
56
"properties": {

src/node_config_schema.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
#ifndef SRC_NODE_CONFIG_SCHEMA_H_
22
#define SRC_NODE_CONFIG_SCHEMA_H_
33

4-
static constexpr const char kNodeConfigSchema[] = R"JSON(
4+
// AUTO-GENERATED by tools/gen_node_config_schema.mjs from
5+
// doc/node-config-schema.json. Do not edit by hand.
6+
7+
static constexpr const char kNodeConfigSchema[] = R"NODECONFIG(
58
{
69
"$schema": "https://json-schema.org/draft/2020-12/schema",
10+
"$comment": "Edit this file. src/node_config_schema.h is regenerated from it by tools/gen_node_config_schema.mjs and verified in CI. additionalProperties:false is stripped from the runtime copy so older Node versions tolerate fields added later.",
711
"required": [],
812
"properties": {
913
"$schema": {
@@ -24,6 +28,10 @@ static constexpr const char kNodeConfigSchema[] = R"JSON(
2428
"type": "boolean",
2529
"description": "allow use of child process when any permissions are set"
2630
},
31+
"allow-ffi": {
32+
"type": "boolean",
33+
"description": "allow use of FFI when any permissions are set (only in builds with FFI support)"
34+
},
2735
"allow-fs-read": {
2836
"oneOf": [
2937
{
@@ -172,6 +180,10 @@ static constexpr const char kNodeConfigSchema[] = R"JSON(
172180
"type": "boolean",
173181
"description": "experimental EventSource API"
174182
},
183+
"experimental-ffi": {
184+
"type": "boolean",
185+
"description": "experimental node:ffi module (only in builds with FFI support)"
186+
},
175187
"experimental-global-navigator": {
176188
"type": "boolean",
177189
"description": "expose experimental Navigator API on the global scope"
@@ -765,6 +777,10 @@ static constexpr const char kNodeConfigSchema[] = R"JSON(
765777
"type": "boolean",
766778
"description": "allow use of addons when any permissions are set"
767779
},
780+
"allow-ffi": {
781+
"type": "boolean",
782+
"description": "allow use of FFI when any permissions are set (only in builds with FFI support)"
783+
},
768784
"allow-child-process": {
769785
"type": "boolean",
770786
"description": "allow use of child process when any permissions are set"
@@ -1021,6 +1037,6 @@ static constexpr const char kNodeConfigSchema[] = R"JSON(
10211037
},
10221038
"type": "object"
10231039
}
1024-
)JSON";
1040+
)NODECONFIG";
10251041

10261042
#endif // SRC_NODE_CONFIG_SCHEMA_H_

tools/gen_node_config_schema.mjs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/usr/bin/env node
2+
// Generates src/node_config_schema.h from doc/node-config-schema.json.
3+
// Run after editing the JSON. CI runs `--check` to fail on drift.
4+
//
5+
// Usage:
6+
// node tools/gen_node_config_schema.mjs # write the header
7+
// node tools/gen_node_config_schema.mjs --check # exit 1 if out of sync
8+
9+
import { readFileSync, writeFileSync } from 'node:fs';
10+
import { dirname, join, relative } from 'node:path';
11+
import { fileURLToPath } from 'node:url';
12+
13+
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
14+
const SOURCE_PATH = join(ROOT, 'doc/node-config-schema.json');
15+
const HEADER_PATH = join(ROOT, 'src/node_config_schema.h');
16+
17+
// `additionalProperties: false` is kept in the doc but stripped from the
18+
// runtime copy so older Node versions don't reject configs that mention
19+
// fields added in later releases.
20+
function stripAdditionalProperties(node) {
21+
if (Array.isArray(node)) return node.map(stripAdditionalProperties);
22+
if (node === null || typeof node !== 'object') return node;
23+
const out = {};
24+
for (const [key, value] of Object.entries(node)) {
25+
if (key === 'additionalProperties' && value === false) continue;
26+
out[key] = stripAdditionalProperties(value);
27+
}
28+
return out;
29+
}
30+
31+
function buildHeader(schemaJson) {
32+
return `#ifndef SRC_NODE_CONFIG_SCHEMA_H_
33+
#define SRC_NODE_CONFIG_SCHEMA_H_
34+
35+
// AUTO-GENERATED by tools/gen_node_config_schema.mjs from
36+
// doc/node-config-schema.json. Do not edit by hand.
37+
38+
static constexpr const char kNodeConfigSchema[] = R"NODECONFIG(
39+
${schemaJson}
40+
)NODECONFIG";
41+
42+
#endif // SRC_NODE_CONFIG_SCHEMA_H_
43+
`;
44+
}
45+
46+
let source;
47+
try {
48+
source = JSON.parse(readFileSync(SOURCE_PATH, 'utf8'));
49+
} catch (err) {
50+
console.error(
51+
`Failed to read or parse ${relative(ROOT, SOURCE_PATH)}: ${err.message}`,
52+
);
53+
process.exit(1);
54+
}
55+
const stripped = stripAdditionalProperties(source);
56+
const expected = buildHeader(JSON.stringify(stripped, null, 2));
57+
58+
if (process.argv.includes('--check')) {
59+
const actual = readFileSync(HEADER_PATH, 'utf8');
60+
if (actual !== expected) {
61+
console.error(
62+
`${relative(ROOT, HEADER_PATH)} is out of date with respect to ` +
63+
`${relative(ROOT, SOURCE_PATH)}.\n` +
64+
`Run \`node tools/gen_node_config_schema.mjs\` and commit the result.`,
65+
);
66+
process.exit(1);
67+
}
68+
console.log(`${relative(ROOT, HEADER_PATH)} is up to date.`);
69+
} else {
70+
writeFileSync(HEADER_PATH, expected);
71+
console.log(`Wrote ${relative(ROOT, HEADER_PATH)}`);
72+
}

0 commit comments

Comments
 (0)