Replace Node.js version header generator with C++ implementation (#261)
Replaces the Node.js-based generate-version-header.js script with a C++
implementation to eliminate the Node.js runtime dependency from the build
process. The new C++ tool reads package.json and generates the same
version.h header file.
Also fixes Closure Compiler errors under strict mode in
extension_field_binary_info.js and map.js by properly assigning
goog.requireType calls to const variables instead of using standalone
goog.requireType calls.
Changes:
- Add generator/generate-version-header.cc with C++ implementation
- Remove generate-version-header.js
- Update generator/BUILD.bazel to use cc_binary instead of Node.js script
- Add rules_cc dependency to MODULE.bazel
- Update BUILD.bazel to remove deleted script from exports_files
- Fix goog.requireType usage in extension_field_binary_info.js and map.js
diff --git a/BUILD.bazel b/BUILD.bazel
index 6604d3a..7461adb 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -6,7 +6,7 @@
load("@rules_pkg//:pkg.bzl", "pkg_tar", "pkg_zip")
load("//:protobuf_javascript_release.bzl", "package_naming")
-exports_files(["generate-version-header.js", "package.json"])
+exports_files(["package.json"])
config_setting(
name = "x64_x86_windows",
@@ -36,13 +36,13 @@
package_naming(
name = "protobuf_javascript_pkg_naming",
platform = select({
- ":k8": "linux-x86_64", # currently the only supported build type in Github Actions
+ ":k8": "linux-x86_64", # currently the only supported build type in Github Actions
":x64_x86_windows": "win32",
":x64_windows": "win64",
":darwin_arm64": "osx-aarch_64",
":darwin_x86_64": "osx-x86_64",
- "//conditions:default": "" # continues with current behavior when no --cpu is specified allowing existing internal builds to function
- })
+ "//conditions:default": "", # continues with current behavior when no --cpu is specified allowing existing internal builds to function
+ }),
)
pkg_files(
@@ -54,15 +54,18 @@
pkg_files(
name = "dist_files",
- srcs = glob([
- "google/protobuf/*.js",
- "google/protobuf/compiler/*.js"
- ], allow_empty = True) + [
- "google-protobuf.js",
- "package.json",
- "README.md",
+ srcs = glob(
+ [
+ "google/protobuf/*.js",
+ "google/protobuf/compiler/*.js",
+ ],
+ allow_empty = True,
+ ) + [
"LICENSE.md",
"LICENSE-asserts.md",
+ "README.md",
+ "google-protobuf.js",
+ "package.json",
],
strip_prefix = strip_prefix.from_root(""),
)
@@ -93,5 +96,5 @@
srcs = [
":dist_tar",
":dist_zip",
- ]
+ ],
)
diff --git a/MODULE.bazel b/MODULE.bazel
index 2576f46..3acc005 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -1,5 +1,6 @@
module(name = "protobuf_javascript", version = "4.0.1")
-bazel_dep(name = "protobuf", version = "33.0", repo_name = "com_google_protobuf")
-bazel_dep(name = "rules_pkg", version = "1.0.1")
bazel_dep(name = "abseil-cpp", version = "20250512.1")
+bazel_dep(name = "protobuf", version = "33.0", repo_name = "com_google_protobuf")
+bazel_dep(name = "rules_cc", version = "0.2.15")
+bazel_dep(name = "rules_pkg", version = "1.0.1")
diff --git a/extension_field_binary_info.js b/extension_field_binary_info.js
index 4f79100..e8adeb1 100644
--- a/extension_field_binary_info.js
+++ b/extension_field_binary_info.js
@@ -36,15 +36,15 @@
goog.module.declareLegacyNamespace();
const ExtensionFieldInfo = goog.require('jspb.ExtensionFieldInfo');
-goog.requireType('jspb.BinaryReader');
-goog.requireType('jspb.BinaryWriter');
+const BinaryReader = goog.requireType('jspb.BinaryReader');
+const BinaryWriter = goog.requireType('jspb.BinaryWriter');
/**
* Stores binary-related information for a single extension field.
* @param {!ExtensionFieldInfo<T>} fieldInfo
- * @param {function(this:jspb.BinaryReader,number,?,?)} binaryReaderFn
- * @param {function(this:jspb.BinaryWriter,number,?)
- * |function(this:jspb.BinaryWriter,number,?,?,?,?,?)} binaryWriterFn
+ * @param {function(this:BinaryReader,number,?,?)} binaryReaderFn
+ * @param {function(this:BinaryWriter,number,?)
+ * |function(this:BinaryWriter,number,?,?,?,?,?)} binaryWriterFn
* @param {function(?,?)=} opt_binaryMessageSerializeFn
* @param {function(?,?)=} opt_binaryMessageDeserializeFn
* @param {boolean=} opt_isPacked
diff --git a/generate-version-header.js b/generate-version-header.js
deleted file mode 100644
index c21ca67..0000000
--- a/generate-version-header.js
+++ /dev/null
@@ -1,14 +0,0 @@
-const fs = require('fs');
-const path = require('path');
-
-const version = require('./package.json').version;
-const headerContent = `// Generated by generate-version-header.js
-#ifndef PROTOBUF_JAVASCRIPT_VERSION_H__
-#define PROTOBUF_JAVASCRIPT_VERSION_H__
-
-const char* const kProtobufJavascriptVersion = "${version}";
-
-#endif // PROTOBUF_JAVASCRIPT_VERSION_H__
-`;
-
-fs.writeFileSync(process.argv[2], headerContent);
diff --git a/generator/BUILD.bazel b/generator/BUILD.bazel
index ac7756d..0c42d0f 100644
--- a/generator/BUILD.bazel
+++ b/generator/BUILD.bazel
@@ -1,9 +1,16 @@
+load("@rules_cc//cc:defs.bzl", "cc_binary")
+
+cc_binary(
+ name = "generate-version-header",
+ srcs = ["generate-version-header.cc"],
+)
+
genrule(
name = "generate_version_header",
srcs = ["//:package.json"],
outs = ["version.h"],
- cmd = "node $(location //:generate-version-header.js) $(OUTS)",
- tools = ["//:generate-version-header.js"],
+ cmd = "$(location :generate-version-header) $(location //:package.json) $(OUTS)",
+ tools = [":generate-version-header"],
)
cc_binary(
@@ -18,15 +25,13 @@
],
visibility = ["//visibility:public"],
deps = [
+ "@abseil-cpp//absl/strings",
+ "@abseil-cpp//absl/strings:str_format",
"@com_google_protobuf//:protobuf",
+ "@com_google_protobuf//:protoc_lib",
"@com_google_protobuf//src/google/protobuf/compiler:code_generator",
"@com_google_protobuf//src/google/protobuf/io",
"@com_google_protobuf//src/google/protobuf/io:printer",
"@com_google_protobuf//src/google/protobuf/io:tokenizer",
- "@com_google_protobuf//:protoc_lib",
- "@abseil-cpp//absl/strings",
- "@abseil-cpp//absl/strings:str_format",
],
)
-
-
diff --git a/generator/generate-version-header.cc b/generator/generate-version-header.cc
new file mode 100644
index 0000000..adca0da
--- /dev/null
+++ b/generator/generate-version-header.cc
@@ -0,0 +1,79 @@
+// Copyright 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fstream>
+#include <iostream>
+#include <regex>
+#include <sstream>
+#include <string>
+
+std::string ReadPackageVersion(const std::string& package_json_path) {
+ std::ifstream file(package_json_path);
+ if (!file.is_open()) {
+ std::cerr << "Error: Could not open " << package_json_path << std::endl;
+ exit(1);
+ }
+
+ std::stringstream buffer;
+ buffer << file.rdbuf();
+ std::string content = buffer.str();
+
+ // Simple regex to extract version field from package.json
+ std::regex version_regex(R"#("version"\s*:\s*"([^"]+)")#");
+ std::smatch match;
+
+ if (std::regex_search(content, match, version_regex)) {
+ return match[1].str();
+ }
+
+ std::cerr << "Error: Could not find version in " << package_json_path
+ << std::endl;
+ exit(1);
+}
+
+void GenerateHeaderFile(const std::string& output_path,
+ const std::string& version) {
+ std::ofstream file(output_path);
+ if (!file.is_open()) {
+ std::cerr << "Error: Could not write to " << output_path << std::endl;
+ exit(1);
+ }
+
+ file << "// Generated by generate-version-header.cc\n"
+ << "#ifndef PROTOBUF_JAVASCRIPT_VERSION_H__\n"
+ << "#define PROTOBUF_JAVASCRIPT_VERSION_H__\n"
+ << "\n"
+ << "const char* const kProtobufJavascriptVersion = \"" << version
+ << "\";\n"
+ << "\n"
+ << "#endif // PROTOBUF_JAVASCRIPT_VERSION_H__\n";
+}
+
+int main(int argc, char* argv[]) {
+ if (argc != 3) {
+ std::cerr << "Usage: " << argv[0] << " <package_json_path> <output_header_path>" << std::endl;
+ return 1;
+ }
+
+ std::string package_json_path = argv[1];
+ std::string output_path = argv[2];
+
+ std::string version = ReadPackageVersion(package_json_path);
+ GenerateHeaderFile(output_path, version);
+
+ std::cout << "Generated " << output_path << " with version " << version
+ << std::endl;
+
+ return 0;
+}
diff --git a/map.js b/map.js
index e46087c..394d1d1 100644
--- a/map.js
+++ b/map.js
@@ -68,12 +68,8 @@
goog.module('jspb.Map');
goog.module.declareLegacyNamespace();
-
const asserts = goog.require('jspb.asserts');
-
-goog.requireType('jspb.BinaryReader');
-goog.requireType('jspb.BinaryWriter');
-
+const BinaryReader = goog.requireType('jspb.BinaryReader');
/**
@@ -268,13 +264,13 @@
/** @override @final */
ArrayIteratorIterable_.prototype.next = function () {
if (this.idx_ < this.arr_.length) {
- return {done: false, value: this.arr_[this.idx_++]};
+ return { done: false, value: this.arr_[this.idx_++] };
} else {
- return {done: true, value: undefined};
+ return { done: true, value: undefined };
}
};
-if (typeof(Symbol) != 'undefined') {
+if (typeof (Symbol) != 'undefined') {
/** @override */
ArrayIteratorIterable_.prototype[Symbol.iterator] = function () {
return this;
@@ -488,17 +484,17 @@
* we should default it to 0.
* @template K, V
* @param {!Map} map
- * @param {!jspb.BinaryReader} reader
- * @param {function(this:jspb.BinaryReader):K} keyReaderFn
+ * @param {!BinaryReader} reader
+ * @param {function(this:BinaryReader):K} keyReaderFn
* The method on BinaryReader that reads type K from the stream.
*
- * @param {function(this:jspb.BinaryReader):V|
- * function(this:jspb.BinaryReader,V,
- * function(V,!jspb.BinaryReader))} valueReaderFn
+ * @param {function(this:BinaryReader):V|
+ * function(this:BinaryReader,V,
+ * function(V,!BinaryReader))} valueReaderFn
* The method on BinaryReader that reads type V from the stream. May be
* readMessage, in which case the second callback arg form is used.
*
- * @param {?function(V,!jspb.BinaryReader)=} opt_valueReaderCallback
+ * @param {?function(V,!BinaryReader)=} opt_valueReaderCallback
* The BinaryReader parsing callback for type V, if V is a message type
*
* @param {K=} opt_defaultKey
@@ -514,8 +510,8 @@
*
*/
Map.deserializeBinary = function (map, reader, keyReaderFn, valueReaderFn,
- opt_valueReaderCallback, opt_defaultKey,
- opt_defaultValue) {
+ opt_valueReaderCallback, opt_defaultKey,
+ opt_defaultValue) {
var key = opt_defaultKey;
var value = opt_defaultValue;
@@ -540,8 +536,8 @@
valueReaderFn.call(reader, value, opt_valueReaderCallback);
} else {
value =
- (/** @type {function(this:jspb.BinaryReader):?} */ (valueReaderFn))
- .call(reader);
+ (/** @type {function(this:BinaryReader):?} */ (valueReaderFn))
+ .call(reader);
}
}
}