Skip to content

Commit 845f6bb

Browse files
committed
Move existing generators to a separate file
1 parent 14d6d45 commit 845f6bb

File tree

3 files changed

+117
-81
lines changed

3 files changed

+117
-81
lines changed

packages/weak-node-api/scripts/generate-weak-node-api.ts

Lines changed: 15 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import assert from "node:assert/strict";
12
import fs from "node:fs";
23
import path from "node:path";
34
import cp from "node:child_process";
@@ -7,6 +8,8 @@ import {
78
getNodeApiFunctions,
89
} from "../src/node-api-functions.js";
910

11+
import * as weakNodeApiGenerator from "./generators/weak-node-api.js";
12+
1013
export const OUTPUT_PATH = path.join(import.meta.dirname, "../generated");
1114

1215
type GenerateFileOptions = {
@@ -20,10 +23,18 @@ async function generateFile({
2023
fileName,
2124
generator,
2225
}: GenerateFileOptions) {
23-
const output = generator(functions);
26+
const generated = generator(functions);
27+
const output = `// This file is generated - don't edit it directly\n\n${generated}`;
2428
const outputPath = path.join(OUTPUT_PATH, fileName);
2529
await fs.promises.writeFile(outputPath, output, "utf-8");
26-
cp.spawnSync("clang-format", ["-i", outputPath], { stdio: "inherit" });
30+
const { status, stderr = "No error output" } = cp.spawnSync(
31+
"clang-format",
32+
["-i", outputPath],
33+
{
34+
encoding: "utf8",
35+
},
36+
);
37+
assert.equal(status, 0, `Failed to format ${fileName}: ${stderr}`);
2738
}
2839

2940
async function run() {
@@ -33,92 +44,15 @@ async function run() {
3344
await generateFile({
3445
functions,
3546
fileName: "weak_node_api.hpp",
36-
generator: generateHeader,
47+
generator: weakNodeApiGenerator.generateHeader,
3748
});
3849
await generateFile({
3950
functions,
4051
fileName: "weak_node_api.cpp",
41-
generator: generateSource,
52+
generator: weakNodeApiGenerator.generateSource,
4253
});
4354
}
4455

45-
export function generateFunctionDecl({
46-
returnType,
47-
name,
48-
argumentTypes,
49-
}: FunctionDecl) {
50-
return `${returnType} (*${name})(${argumentTypes.join(", ")});`;
51-
}
52-
53-
/**
54-
* Generates source code for a version script for the given Node API version.
55-
*/
56-
export function generateHeader(functions: FunctionDecl[]) {
57-
return `
58-
// This file is generated by react-native-node-api
59-
#include <node_api.h> // Node-API
60-
#include <stdio.h> // fprintf()
61-
#include <stdlib.h> // abort()
62-
63-
// Ideally we would have just used NAPI_NO_RETURN, but
64-
// __declspec(noreturn) (when building with Microsoft Visual C++) cannot be used on members of a struct
65-
// TODO: If we targeted C++23 we could use std::unreachable()
66-
67-
#if defined(__GNUC__)
68-
#define WEAK_NODE_API_UNREACHABLE __builtin_unreachable();
69-
#else
70-
#define WEAK_NODE_API_UNREACHABLE __assume(0);
71-
#endif
72-
73-
// Generate the struct of function pointers
74-
struct WeakNodeApiHost {
75-
${functions.map(generateFunctionDecl).join("\n")}
76-
};
77-
typedef void(*InjectHostFunction)(const WeakNodeApiHost&);
78-
extern "C" void inject_weak_node_api_host(const WeakNodeApiHost& host);
79-
`;
80-
}
81-
82-
function generateFunctionImpl({
83-
returnType,
84-
name,
85-
argumentTypes,
86-
noReturn,
87-
}: FunctionDecl) {
88-
return `
89-
extern "C" ${returnType} ${name}(
90-
${argumentTypes.map((type, index) => `${type} arg${index}`).join(", ")}
91-
) {
92-
if (g_host.${name} == nullptr) {
93-
fprintf(stderr, "Node-API function '${name}' called before it was injected!\\n");
94-
abort();
95-
}
96-
${returnType === "void" ? "" : "return "} g_host.${name}(
97-
${argumentTypes.map((_, index) => `arg${index}`).join(", ")}
98-
);
99-
${noReturn ? "WEAK_NODE_API_UNREACHABLE" : ""}
100-
};
101-
`;
102-
}
103-
104-
/**
105-
* Generates source code for a version script for the given Node API version.
106-
*/
107-
export function generateSource(functions: FunctionDecl[]) {
108-
return `
109-
// This file is generated by react-native-node-api
110-
#include "weak_node_api.hpp" // Generated header
111-
112-
WeakNodeApiHost g_host;
113-
void inject_weak_node_api_host(const WeakNodeApiHost& host) {
114-
g_host = host;
115-
};
116-
117-
// Generate function calling into the host
118-
${functions.map(generateFunctionImpl).join("\n")}
119-
`;
120-
}
121-
12256
run().catch((err) => {
12357
console.error(err);
12458
process.exitCode = 1;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { FunctionDecl } from "../../src/node-api-functions.js";
2+
3+
type FunctionOptions = FunctionDecl & {
4+
extern?: true;
5+
static?: true;
6+
namespace?: string;
7+
body?: string;
8+
argumentNames?: string[];
9+
};
10+
11+
export function generateFunction({
12+
extern,
13+
static: staticMember,
14+
returnType,
15+
namespace,
16+
name,
17+
argumentTypes,
18+
argumentNames = [],
19+
noReturn,
20+
body,
21+
}: FunctionOptions) {
22+
return `
23+
${staticMember ? "static " : ""}${extern ? 'extern "C" ' : ""}${returnType} ${namespace ? namespace + "::" : ""}${name}(
24+
${argumentTypes.map((type, index) => `${type} ` + (argumentNames[index] ?? `arg${index}`)).join(", ")}
25+
) ${body ? `{ ${body} ${noReturn ? "WEAK_NODE_API_UNREACHABLE;" : ""}\n}` : ""}
26+
;
27+
`;
28+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import type { FunctionDecl } from "../../src/node-api-functions.js";
2+
import { generateFunction } from "./shared.js";
3+
4+
export function generateFunctionDecl({
5+
returnType,
6+
name,
7+
argumentTypes,
8+
}: FunctionDecl) {
9+
return `${returnType} (*${name})(${argumentTypes.join(", ")});`;
10+
}
11+
12+
/**
13+
* Generates source code for a version script for the given Node API version.
14+
*/
15+
export function generateHeader(functions: FunctionDecl[]) {
16+
return `
17+
#pragma once
18+
19+
#include <node_api.h> // Node-API
20+
#include <stdio.h> // fprintf()
21+
#include <stdlib.h> // abort()
22+
23+
// Ideally we would have just used NAPI_NO_RETURN, but
24+
// __declspec(noreturn) (when building with Microsoft Visual C++) cannot be used on members of a struct
25+
// TODO: If we targeted C++23 we could use std::unreachable()
26+
27+
#if defined(__GNUC__)
28+
#define WEAK_NODE_API_UNREACHABLE __builtin_unreachable()
29+
#else
30+
#define WEAK_NODE_API_UNREACHABLE __assume(0)
31+
#endif
32+
33+
// Generate the struct of function pointers
34+
struct WeakNodeApiHost {
35+
${functions.map(generateFunctionDecl).join("\n")}
36+
};
37+
typedef void(*InjectHostFunction)(const WeakNodeApiHost&);
38+
extern "C" void inject_weak_node_api_host(const WeakNodeApiHost& host);
39+
`;
40+
}
41+
42+
function generateFunctionImpl(fn: FunctionDecl) {
43+
const { name, returnType, argumentTypes } = fn;
44+
return generateFunction({
45+
...fn,
46+
extern: true,
47+
body: `
48+
if (g_host.${name} == nullptr) {
49+
fprintf(stderr, "Node-API function '${name}' called before it was injected!\\n");
50+
abort();
51+
}
52+
${returnType === "void" ? "" : "return "} g_host.${name}(
53+
${argumentTypes.map((_, index) => `arg${index}`).join(", ")}
54+
);
55+
`,
56+
});
57+
}
58+
59+
/**
60+
* Generates source code for a version script for the given Node API version.
61+
*/
62+
export function generateSource(functions: FunctionDecl[]) {
63+
return `
64+
#include "weak_node_api.hpp"
65+
66+
WeakNodeApiHost g_host;
67+
void inject_weak_node_api_host(const WeakNodeApiHost& host) {
68+
g_host = host;
69+
};
70+
71+
// Generate function calling into the host
72+
${functions.map(generateFunctionImpl).join("\n")}
73+
`;
74+
}

0 commit comments

Comments
 (0)