From 833edb6bb0ebf558dd00bebd616edd499da6d9d8 Mon Sep 17 00:00:00 2001 From: Paul Johnston Date: Wed, 17 Dec 2025 15:21:51 -0700 Subject: [PATCH] Replace Node.js version header generator with C++ implementation 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 --- BUILD.bazel | 27 +++++----- MODULE.bazel | 3 +- extension_field_binary_info.js | 10 ++-- generate-version-header.js | 14 ----- generator/BUILD.bazel | 19 ++++--- generator/generate-version-header.cc | 79 ++++++++++++++++++++++++++++ map.js | 32 +++++------ 7 files changed, 127 insertions(+), 57 deletions(-) delete mode 100644 generate-version-header.js create mode 100644 generator/generate-version-header.cc 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//:mappings.bzl", "pkg_attributes", "pkg_files", "strip_prefix") 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 @@ config_setting( 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( 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 @@ filegroup( 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 = "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") -bazel_dep(name = "abseil-cpp", version = "20250512.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('jspb.ExtensionFieldBinaryInfo'); 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} 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 @@ cc_binary( ], 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 +#include +#include +#include +#include + +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] << " " << 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 @@ const ArrayIteratorIterable_ = function (arr) { /** @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 @@ Map.prototype.has = function (key) { * 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.prototype.has = function (key) { * */ 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 @@ Map.deserializeBinary = function (map, reader, keyReaderFn, valueReaderFn, valueReaderFn.call(reader, value, opt_valueReaderCallback); } else { value = - (/** @type {function(this:jspb.BinaryReader):?} */ (valueReaderFn)) - .call(reader); + (/** @type {function(this:BinaryReader):?} */ (valueReaderFn)) + .call(reader); } } }