[TS] Add single-file ts codegen & bazel rule for typescript (#7161)

The headline here is adding a flatbuffer_ts_library rule for generating
typescript code in bazel. This entails some non-trivial other changes,
but ideally none are user-visible.

In particular:
* Added a --ts-flat-file flag that generates a single *_generated.ts
  file instead of separate files for each typescript type. This makes
  bazel much happier.
* Import the bazel rules_nodejs stuff needed to support building
  typescript in bazel
* Move flatbuffers.ts to index.ts because I wasn't sure how to make
  bazel comprehend the "main" attribute of the package.json. Happy
  to take another stab at figuring that out if really needed.
* Fix another couple keyword escaping spots in typescript...
This commit is contained in:
James Kuszmaul
2022-03-10 10:08:13 -08:00
committed by GitHub
parent 2f84c60385
commit e5f331db99
19 changed files with 1549 additions and 39 deletions

View File

@@ -8,6 +8,7 @@ package(
exports_files([ exports_files([
"LICENSE", "LICENSE",
"tsconfig.json",
]) ])
config_setting( config_setting(
@@ -79,6 +80,7 @@ cc_library(
# Public flatc compiler. # Public flatc compiler.
cc_binary( cc_binary(
name = "flatc", name = "flatc",
data = ["//reflection:reflection_fbs_schema"],
deps = [ deps = [
"//src:flatc", "//src:flatc",
], ],

View File

@@ -44,3 +44,27 @@ grpc_deps()
load("@com_github_grpc_grpc//bazel:grpc_extra_deps.bzl", "grpc_extra_deps") load("@com_github_grpc_grpc//bazel:grpc_extra_deps.bzl", "grpc_extra_deps")
grpc_extra_deps() grpc_extra_deps()
http_archive(
name = "build_bazel_rules_nodejs",
sha256 = "965ee2492a2b087cf9e0f2ca472aeaf1be2eb650e0cfbddf514b9a7d3ea4b02a",
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/5.2.0/rules_nodejs-5.2.0.tar.gz"],
)
load("@build_bazel_rules_nodejs//:repositories.bzl", "build_bazel_rules_nodejs_dependencies")
build_bazel_rules_nodejs_dependencies()
load("@build_bazel_rules_nodejs//:index.bzl", "node_repositories", "yarn_install")
node_repositories()
yarn_install(
name = "npm",
exports_directories_only = False,
# Unfreeze to add/remove packages.
frozen_lockfile = True,
package_json = "//:package.json",
symlink_node_modules = False,
yarn_lock = "//:yarn.lock",
)

View File

@@ -5,6 +5,8 @@
Rules for building C++ flatbuffers with Bazel. Rules for building C++ flatbuffers with Bazel.
""" """
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
load("@npm//@bazel/typescript:index.bzl", "ts_project")
load("@rules_cc//cc:defs.bzl", "cc_library") load("@rules_cc//cc:defs.bzl", "cc_library")
flatc_path = "@com_github_google_flatbuffers//:flatc" flatc_path = "@com_github_google_flatbuffers//:flatc"
@@ -13,6 +15,7 @@ DEFAULT_INCLUDE_PATHS = [
"./", "./",
"$(GENDIR)", "$(GENDIR)",
"$(BINDIR)", "$(BINDIR)",
"$(execpath @com_github_google_flatbuffers//:flatc).runfiles/com_github_google_flatbuffers",
] ]
DEFAULT_FLATC_ARGS = [ DEFAULT_FLATC_ARGS = [
@@ -24,6 +27,15 @@ DEFAULT_FLATC_ARGS = [
"--cpp-ptr-type flatbuffers::unique_ptr", "--cpp-ptr-type flatbuffers::unique_ptr",
] ]
DEFAULT_FLATC_TS_ARGS = [
"--gen-object-api",
"--gen-mutable",
"--reflect-names",
"--gen-name-strings",
"--ts-flat-files",
"--keep-prefix",
]
def flatbuffer_library_public( def flatbuffer_library_public(
name, name,
srcs, srcs,
@@ -252,3 +264,91 @@ def flatbuffer_cc_library(
restricted_to = restricted_to, restricted_to = restricted_to,
visibility = srcs_filegroup_visibility if srcs_filegroup_visibility != None else visibility, visibility = srcs_filegroup_visibility if srcs_filegroup_visibility != None else visibility,
) )
def flatbuffer_ts_library(
name,
srcs,
compatible_with = None,
target_compatible_with = None,
deps = [],
include_paths = DEFAULT_INCLUDE_PATHS,
flatc_args = DEFAULT_FLATC_TS_ARGS,
visibility = None,
restricted_to = None,
include_reflection = True):
"""Generates a ts_library rule for a given flatbuffer definition.
Args:
name: Name of the generated ts_library rule.
srcs: Source .fbs file(s).
deps: Other flatbuffer_ts_library's to depend on. Note that currently
you must specify all your transitive dependencies manually.
include_paths: Optional, list of paths the includes files can be found in.
flatc_args: Optional list of additional arguments to pass to flatc
(e.g. --gen-mutable).
visibility: The visibility of the generated cc_library. By default, use the
default visibility of the project.
compatible_with: Optional, The list of environments this rule can be built
for, in addition to default-supported environments.
restricted_to: Optional, The list of environments this rule can be built
for, instead of default-supported environments.
target_compatible_with: Optional, The list of target platform constraints
to use.
include_reflection: Optional, Whether to depend on the flatbuffer
reflection library automatically. Only really relevant for the
target that builds the reflection library itself.
"""
srcs_lib = "%s_srcs" % (name)
outs = ["%s_generated.ts" % (s.replace(".fbs", "").split("/")[-1]) for s in srcs]
includes = [d + "_includes" for d in deps]
flatbuffer_library_public(
name = srcs_lib,
srcs = srcs,
outs = outs,
language_flag = "--ts",
includes = includes,
include_paths = include_paths,
flatc_args = flatc_args,
compatible_with = compatible_with,
restricted_to = restricted_to,
target_compatible_with = target_compatible_with,
)
ts_project(
name = name + "_ts",
srcs = outs,
declaration = True,
visibility = visibility,
compatible_with = compatible_with,
restricted_to = restricted_to,
target_compatible_with = target_compatible_with,
tsconfig = {
"compilerOptions": {
"declaration": True,
"lib": [
"ES2015",
"ES2020.BigInt",
"DOM",
],
"module": "commonjs",
"moduleResolution": "node",
"strict": True,
"types": ["node"],
},
},
deps = deps + ["//ts:flatbuffers"] + (["//reflection:reflection_ts_fbs"] if include_reflection else []),
)
js_library(
name = name,
visibility = visibility,
compatible_with = compatible_with,
restricted_to = restricted_to,
target_compatible_with = target_compatible_with,
deps = [name + "_ts"],
)
native.filegroup(
name = "%s_includes" % (name),
srcs = srcs + includes,
compatible_with = compatible_with,
restricted_to = restricted_to,
visibility = visibility,
)

View File

@@ -601,6 +601,7 @@ struct IDLOptions {
bool json_nested_flatbuffers; bool json_nested_flatbuffers;
bool json_nested_flexbuffers; bool json_nested_flexbuffers;
bool json_nested_legacy_flatbuffers; bool json_nested_legacy_flatbuffers;
bool ts_flat_file;
// Possible options for the more general generator below. // Possible options for the more general generator below.
enum Language { enum Language {
@@ -698,6 +699,7 @@ struct IDLOptions {
json_nested_flatbuffers(true), json_nested_flatbuffers(true),
json_nested_flexbuffers(true), json_nested_flexbuffers(true),
json_nested_legacy_flatbuffers(false), json_nested_legacy_flatbuffers(false),
ts_flat_file(false),
mini_reflect(IDLOptions::kNone), mini_reflect(IDLOptions::kNone),
require_explicit_ids(false), require_explicit_ids(false),
rust_serialize(false), rust_serialize(false),

View File

@@ -9,8 +9,8 @@
"mjs/**/*.d.ts", "mjs/**/*.d.ts",
"ts/**/*.ts" "ts/**/*.ts"
], ],
"main": "js/flatbuffers.js", "main": "js/index.js",
"module": "mjs/flatbuffers.js", "module": "mjs/index.js",
"directories": { "directories": {
"doc": "docs", "doc": "docs",
"test": "tests" "test": "tests"
@@ -35,9 +35,11 @@
"homepage": "https://google.github.io/flatbuffers/", "homepage": "https://google.github.io/flatbuffers/",
"dependencies": {}, "dependencies": {},
"devDependencies": { "devDependencies": {
"@bazel/typescript": "^5.2.0",
"@types/node": "17.0.21",
"@typescript-eslint/eslint-plugin": "^4.12.0", "@typescript-eslint/eslint-plugin": "^4.12.0",
"@typescript-eslint/parser": "^4.12.0", "@typescript-eslint/parser": "^4.12.0",
"eslint": "^7.17.0", "eslint": "^7.17.0",
"typescript": "^4.1.3" "typescript": "^4.5.5"
} }
} }

14
reflection/BUILD.bazel Normal file
View File

@@ -0,0 +1,14 @@
load("//:build_defs.bzl", "flatbuffer_ts_library")
filegroup(
name = "reflection_fbs_schema",
srcs = ["reflection.fbs"],
visibility = ["//visibility:public"],
)
flatbuffer_ts_library(
name = "reflection_ts_fbs",
srcs = ["reflection.fbs"],
include_reflection = False,
visibility = ["//visibility:public"],
)

View File

@@ -213,6 +213,8 @@ const static FlatCOption options[] = {
{ "", "json-nested-bytes", "", { "", "json-nested-bytes", "",
"Allow a nested_flatbuffer field to be parsed as a vector of bytes" "Allow a nested_flatbuffer field to be parsed as a vector of bytes"
"in JSON, which is unsafe unless checked by a verifier afterwards." }, "in JSON, which is unsafe unless checked by a verifier afterwards." },
{ "", "ts-flat-files", "",
"Only generated one typescript file per .fbs file." },
}; };
static void AppendTextWrappedString(std::stringstream &ss, std::string &text, static void AppendTextWrappedString(std::stringstream &ss, std::string &text,
@@ -550,6 +552,8 @@ int FlatCompiler::Compile(int argc, const char **argv) {
opts.cs_global_alias = true; opts.cs_global_alias = true;
} else if (arg == "--json-nested-bytes") { } else if (arg == "--json-nested-bytes") {
opts.json_nested_legacy_flatbuffers = true; opts.json_nested_legacy_flatbuffers = true;
} else if (arg == "--ts-flat-files") {
opts.ts_flat_file = true;
} else { } else {
for (size_t i = 0; i < params_.num_generators; ++i) { for (size_t i = 0; i < params_.num_generators; ++i) {
if (arg == "--" + params_.generators[i].option.long_opt || if (arg == "--" + params_.generators[i].option.long_opt ||
@@ -588,6 +592,10 @@ int FlatCompiler::Compile(int argc, const char **argv) {
"well."); "well.");
} }
if (opts.ts_flat_file && opts.generate_all) {
Error("Combining --ts-flat-file and --gen-all is not supported.");
}
flatbuffers::Parser conform_parser; flatbuffers::Parser conform_parser;
if (!conform_to_schema.empty()) { if (!conform_to_schema.empty()) {
std::string contents; std::string contents;

View File

@@ -33,8 +33,8 @@ struct ImportDefinition {
std::string export_statement; std::string export_statement;
std::string bare_file_path; std::string bare_file_path;
std::string rel_file_path; std::string rel_file_path;
const Definition *dependent; const Definition *dependent = nullptr;
const Definition *dependency; const Definition *dependency = nullptr;
}; };
enum AnnotationType { kParam = 0, kType = 1, kReturns = 2 }; enum AnnotationType { kParam = 0, kType = 1, kReturns = 2 };
@@ -110,6 +110,10 @@ class TsGenerator : public BaseGenerator {
for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw); for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
} }
bool generate() { bool generate() {
if (parser_.opts.ts_flat_file && parser_.opts.generate_all) {
// Not implemented; warning message should have beem emitted by flatc.
return false;
}
generateEnums(); generateEnums();
generateStructs(); generateStructs();
generateEntry(); generateEntry();
@@ -119,26 +123,38 @@ class TsGenerator : public BaseGenerator {
// Save out the generated code for a single class while adding // Save out the generated code for a single class while adding
// declaration boilerplate. // declaration boilerplate.
bool SaveType(const Definition &definition, const std::string &classcode, bool SaveType(const Definition &definition, const std::string &classcode,
import_set &imports, import_set &bare_imports) const { import_set &imports, import_set &bare_imports) {
if (!classcode.length()) return true; if (!classcode.length()) return true;
std::string code = std::string code;
"// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
for (auto it = bare_imports.begin(); it != bare_imports.end(); it++) if (!parser_.opts.ts_flat_file) {
code += it->second.import_statement + "\n"; code += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
if (!bare_imports.empty()) code += "\n";
for (auto it = imports.begin(); it != imports.end(); it++) for (auto it = bare_imports.begin(); it != bare_imports.end(); it++) {
if (it->second.dependency != &definition) // do not import itself
code += it->second.import_statement + "\n"; code += it->second.import_statement + "\n";
if (!imports.empty()) code += "\n\n"; }
if (!bare_imports.empty()) code += "\n";
for (auto it = imports.begin(); it != imports.end(); it++) {
if (it->second.dependency != &definition) {
code += it->second.import_statement + "\n";
}
}
if (!imports.empty()) code += "\n\n";
}
code += classcode; code += classcode;
auto filename = auto filename =
NamespaceDir(*definition.defined_namespace, true) + NamespaceDir(*definition.defined_namespace, true) +
ConvertCase(definition.name, Case::kDasher, Case::kUpperCamel) + ".ts"; ConvertCase(definition.name, Case::kDasher, Case::kUpperCamel) + ".ts";
return SaveFile(filename.c_str(), code, false); if (parser_.opts.ts_flat_file) {
flat_file_ += code;
flat_file_definitions_.insert(&definition);
return true;
} else {
return SaveFile(filename.c_str(), code, false);
}
} }
private: private:
@@ -150,6 +166,18 @@ class TsGenerator : public BaseGenerator {
import_set imports_all_; import_set imports_all_;
// The following three members are used when generating typescript code into a
// single file rather than creating separate files for each type.
// flat_file_ contains the aggregated contents of the file prior to being
// written to disk.
std::string flat_file_;
// flat_file_definitions_ tracks which types have been written to flat_file_.
std::unordered_set<const Definition *> flat_file_definitions_;
// This maps from import names to types to import.
std::map<std::string, std::map<std::string, std::string>>
flat_file_import_declarations_;
// Generate code for all enums. // Generate code for all enums.
void generateEnums() { void generateEnums() {
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
@@ -183,10 +211,48 @@ class TsGenerator : public BaseGenerator {
// Generate code for a single entry point module. // Generate code for a single entry point module.
void generateEntry() { void generateEntry() {
std::string code; std::string code;
for (auto it = imports_all_.begin(); it != imports_all_.end(); it++) if (parser_.opts.ts_flat_file) {
code += it->second.export_statement + "\n"; code += "import * as flatbuffers from 'flatbuffers';\n";
std::string path = "./" + path_ + file_name_ + ".ts"; for (const auto &it : flat_file_import_declarations_) {
SaveFile(path.c_str(), code, false); // Note that we do end up generating an import for ourselves, which
// should generally be harmless.
// TODO: Make it so we don't generate a self-import; this will also
// require modifying AddImport to ensure that we don't use
// namespace-prefixed names anywhere...
std::string file = it.first;
if (file.empty()) {
continue;
}
std::string noext = flatbuffers::StripExtension(file);
std::string basename = flatbuffers::StripPath(noext);
std::string include_file = GeneratedFileName(
parser_.opts.include_prefix,
parser_.opts.keep_include_path ? noext : basename, parser_.opts);
// TODO: what is the right behavior when different include flags are
// specified here? Should we always be adding the "./" for a relative
// path or turn it off if --include-prefix is specified, or something
// else?
std::string include_name = "./" + flatbuffers::StripExtension(include_file);
code += "import {";
for (const auto &pair : it.second) {
code += EscapeKeyword(pair.first) + " as " +
EscapeKeyword(pair.second) + ", ";
}
code.resize(code.size() - 2);
code += "} from '" + include_name + "';\n";
}
code += "\n\n";
code += flat_file_;
const std::string filename =
GeneratedFileName(path_, file_name_, parser_.opts);
SaveFile(filename.c_str(), code, false);
} else {
for (auto it = imports_all_.begin(); it != imports_all_.end(); it++) {
code += it->second.export_statement + "\n";
}
std::string path = "./" + path_ + file_name_ + ".ts";
SaveFile(path.c_str(), code, false);
}
} }
// Generate a documentation comment, if available. // Generate a documentation comment, if available.
@@ -553,7 +619,9 @@ class TsGenerator : public BaseGenerator {
const StructDef &dependency) { const StructDef &dependency) {
std::string ns; std::string ns;
const auto &depc_comps = dependency.defined_namespace->components; const auto &depc_comps = dependency.defined_namespace->components;
for (auto it = depc_comps.begin(); it != depc_comps.end(); it++) ns += *it; for (auto it = depc_comps.begin(); it != depc_comps.end(); it++) {
ns += *it;
}
std::string unique_name = ns + dependency.name; std::string unique_name = ns + dependency.name;
std::string import_name = dependency.name; std::string import_name = dependency.name;
std::string long_import_name; std::string long_import_name;
@@ -565,6 +633,20 @@ class TsGenerator : public BaseGenerator {
break; break;
} }
} }
if (parser_.opts.ts_flat_file) {
std::string file = dependency.declaration_file == nullptr
? dependency.file
: dependency.declaration_file->substr(2);
file = RelativeToRootPath(StripFileName(AbsolutePath(dependent.file)),
dependency.file).substr(2);
long_import_name = ns + import_name;
flat_file_import_declarations_[file][import_name] = long_import_name;
if (parser_.opts.generate_object_based_api) {
flat_file_import_declarations_[file][import_name + "T"] = long_import_name + "T";
}
}
std::string import_statement; std::string import_statement;
std::string export_statement; std::string export_statement;
import_statement += "import { "; import_statement += "import { ";
@@ -616,18 +698,32 @@ class TsGenerator : public BaseGenerator {
const EnumDef &dependency) { const EnumDef &dependency) {
std::string ns; std::string ns;
const auto &depc_comps = dependency.defined_namespace->components; const auto &depc_comps = dependency.defined_namespace->components;
for (auto it = depc_comps.begin(); it != depc_comps.end(); it++) ns += *it; for (auto it = depc_comps.begin(); it != depc_comps.end(); it++) {
ns += *it;
}
std::string unique_name = ns + dependency.name; std::string unique_name = ns + dependency.name;
std::string import_name = EscapeKeyword(dependency.name); std::string import_name = EscapeKeyword(dependency.name);
std::string long_import_name; std::string long_import_name;
if (imports.find(unique_name) != imports.end()) if (imports.find(unique_name) != imports.end()) {
return imports.find(unique_name)->second.name; return imports.find(unique_name)->second.name;
}
for (auto it = imports.begin(); it != imports.end(); it++) { for (auto it = imports.begin(); it != imports.end(); it++) {
if (it->second.name == import_name) { if (it->second.name == import_name) {
long_import_name = ns + import_name; long_import_name = ns + import_name;
break; break;
} }
} }
if (parser_.opts.ts_flat_file) {
std::string file = dependency.declaration_file == nullptr
? dependency.file
: dependency.declaration_file->substr(2);
file = RelativeToRootPath(StripFileName(AbsolutePath(dependent.file)),
dependency.file).substr(2);
long_import_name = ns + import_name;
flat_file_import_declarations_[file][import_name] = long_import_name;
}
std::string import_statement; std::string import_statement;
std::string export_statement; std::string export_statement;
import_statement += "import { "; import_statement += "import { ";
@@ -636,7 +732,8 @@ class TsGenerator : public BaseGenerator {
if (long_import_name.empty()) if (long_import_name.empty())
symbols_expression += import_name; symbols_expression += import_name;
else else
symbols_expression += dependency.name + " as " + long_import_name; symbols_expression += EscapeKeyword(dependency.name) + " as " +
EscapeKeyword(long_import_name);
if (dependency.is_union) { if (dependency.is_union) {
symbols_expression += ", unionTo" + import_name; symbols_expression += ", unionTo" + import_name;
symbols_expression += ", unionListTo" + import_name; symbols_expression += ", unionListTo" + import_name;
@@ -966,7 +1063,8 @@ class TsGenerator : public BaseGenerator {
switch (field.value.type.base_type) { switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT: { case BASE_TYPE_STRUCT: {
const auto &sd = *field.value.type.struct_def; const auto &sd = *field.value.type.struct_def;
field_type += GetObjApiClassName(sd, parser.opts); field_type += GetObjApiClassName(AddImport(imports, struct_def, sd),
parser.opts);
const std::string field_accessor = const std::string field_accessor =
"this." + field_name_escaped + "()"; "this." + field_name_escaped + "()";
@@ -1008,12 +1106,15 @@ class TsGenerator : public BaseGenerator {
field_offset_decl = field_offset_decl =
"builder.createStructOffsetList(this." + "builder.createStructOffsetList(this." +
field_name_escaped + ", " + field_name_escaped + ", " +
AddImport(imports, struct_def, struct_def) + ".start" + EscapeKeyword(
ConvertCase(field_name, Case::kUpperCamel) + "Vector)"; AddImport(imports, struct_def, struct_def)) +
".start" + ConvertCase(field_name, Case::kUpperCamel) +
"Vector)";
} else { } else {
field_offset_decl = field_offset_decl =
AddImport(imports, struct_def, struct_def) + ".create" + EscapeKeyword(
ConvertCase(field_name, Case::kUpperCamel) + AddImport(imports, struct_def, struct_def)) +
".create" + ConvertCase(field_name, Case::kUpperCamel) +
"Vector(builder, builder.createObjectOffsetList(" + "Vector(builder, builder.createObjectOffsetList(" +
"this." + field_name_escaped + "))"; "this." + field_name_escaped + "))";
} }
@@ -1027,8 +1128,8 @@ class TsGenerator : public BaseGenerator {
field_binded_method + ", this." + field_name + field_binded_method + ", this." + field_name +
"Length())"; "Length())";
field_offset_decl = field_offset_decl =
AddImport(imports, struct_def, struct_def) + ".create" + EscapeKeyword(AddImport(imports, struct_def, struct_def)) +
ConvertCase(field_name, Case::kUpperCamel) + ".create" + ConvertCase(field_name, Case::kUpperCamel) +
"Vector(builder, builder.createObjectOffsetList(" + "Vector(builder, builder.createObjectOffsetList(" +
"this." + field_name_escaped + "))"; "this." + field_name_escaped + "))";
break; break;
@@ -1042,8 +1143,8 @@ class TsGenerator : public BaseGenerator {
GenUnionValTS(imports, field_name, vectortype, true); GenUnionValTS(imports, field_name, vectortype, true);
field_offset_decl = field_offset_decl =
AddImport(imports, struct_def, struct_def) + ".create" + EscapeKeyword(AddImport(imports, struct_def, struct_def)) +
ConvertCase(field_name, Case::kUpperCamel) + ".create" + ConvertCase(field_name, Case::kUpperCamel) +
"Vector(builder, builder.createObjectOffsetList(" + "Vector(builder, builder.createObjectOffsetList(" +
"this." + field_name_escaped + "))"; "this." + field_name_escaped + "))";
@@ -1062,8 +1163,8 @@ class TsGenerator : public BaseGenerator {
"Length())"; "Length())";
field_offset_decl = field_offset_decl =
AddImport(imports, struct_def, struct_def) + ".create" + EscapeKeyword(AddImport(imports, struct_def, struct_def)) +
ConvertCase(field_name, Case::kUpperCamel) + ".create" + ConvertCase(field_name, Case::kUpperCamel) +
"Vector(builder, this." + field_name_escaped + ")"; "Vector(builder, this." + field_name_escaped + ")";
break; break;

View File

@@ -1,5 +1,5 @@
load("@rules_cc//cc:defs.bzl", "cc_test") load("@rules_cc//cc:defs.bzl", "cc_test")
load("//:build_defs.bzl", "flatbuffer_cc_library") load("//:build_defs.bzl", "flatbuffer_cc_library", "flatbuffer_ts_library")
package(default_visibility = ["//visibility:private"]) package(default_visibility = ["//visibility:private"])
@@ -190,3 +190,12 @@ flatbuffer_cc_library(
"--cpp-ptr-type flatbuffers::unique_ptr", "--cpp-ptr-type flatbuffers::unique_ptr",
], ],
) )
flatbuffer_ts_library(
name = "typescript_ts_fbs",
srcs = ["typescript_keywords.fbs"],
deps = [
"//tests/test_dir:include_ts_fbs",
"//tests/test_dir:typescript_transitive_ts_fbs",
],
)

View File

@@ -25,7 +25,8 @@ if [ -x ../flatc ]; then
../flatc --gen-object-api -b -I include_test monster_test.fbs unicode_test.json ../flatc --gen-object-api -b -I include_test monster_test.fbs unicode_test.json
../flatc --ts --gen-name-strings --gen-mutable --gen-object-api -o union_vector union_vector/union_vector.fbs ../flatc --ts --gen-name-strings --gen-mutable --gen-object-api -o union_vector union_vector/union_vector.fbs
../flatc --ts --gen-name-strings optional_scalars.fbs ../flatc --ts --gen-name-strings optional_scalars.fbs
../flatc --ts --gen-name-strings --gen-object-api --gen-mutable typescript_keywords.fbs ../flatc --ts --gen-name-strings --gen-object-api --gen-mutable -I ../ ./typescript_keywords.fbs test_dir/typescript_include.fbs test_dir/typescript_transitive_include.fbs ../reflection/reflection.fbs
../flatc --ts --gen-name-strings --gen-object-api --gen-mutable --ts-flat-files -I ../ ./typescript_keywords.fbs test_dir/typescript_include.fbs test_dir/typescript_transitive_include.fbs ../reflection/reflection.fbs
fi fi
tsc tsc
node -r esm JavaScriptTest node -r esm JavaScriptTest

View File

@@ -498,11 +498,39 @@ export class Monster {
const offset = this.bb.__offset(this.bb_pos, 104); const offset = this.bb.__offset(this.bb_pos, 104);
return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
} }
nativeInline(obj) {
const offset = this.bb.__offset(this.bb_pos, 106);
return offset ? (obj || new Test()).__init(this.bb_pos + offset, this.bb) : null;
}
longEnumNonEnumDefault() {
const offset = this.bb.__offset(this.bb_pos, 108);
return offset ? this.bb.readUint64(this.bb_pos + offset) : BigInt('0');
}
mutate_long_enum_non_enum_default(value) {
const offset = this.bb.__offset(this.bb_pos, 108);
if (offset === 0) {
return false;
}
this.bb.writeUint64(this.bb_pos + offset, value);
return true;
}
longEnumNormalDefault() {
const offset = this.bb.__offset(this.bb_pos, 110);
return offset ? this.bb.readUint64(this.bb_pos + offset) : BigInt('2');
}
mutate_long_enum_normal_default(value) {
const offset = this.bb.__offset(this.bb_pos, 110);
if (offset === 0) {
return false;
}
this.bb.writeUint64(this.bb_pos + offset, value);
return true;
}
static getFullyQualifiedName() { static getFullyQualifiedName() {
return 'MyGame.Example.Monster'; return 'MyGame.Example.Monster';
} }
static startMonster(builder) { static startMonster(builder) {
builder.startObject(51); builder.startObject(54);
} }
static addPos(builder, posOffset) { static addPos(builder, posOffset) {
builder.addFieldStruct(0, posOffset, 0); builder.addFieldStruct(0, posOffset, 0);
@@ -833,6 +861,15 @@ export class Monster {
static startScalarKeySortedTablesVector(builder, numElems) { static startScalarKeySortedTablesVector(builder, numElems) {
builder.startVector(4, numElems, 4); builder.startVector(4, numElems, 4);
} }
static addNativeInline(builder, nativeInlineOffset) {
builder.addFieldStruct(51, nativeInlineOffset, 0);
}
static addLongEnumNonEnumDefault(builder, longEnumNonEnumDefault) {
builder.addFieldInt64(52, longEnumNonEnumDefault, BigInt('0'));
}
static addLongEnumNormalDefault(builder, longEnumNormalDefault) {
builder.addFieldInt64(53, longEnumNormalDefault, BigInt('2'));
}
static endMonster(builder) { static endMonster(builder) {
const offset = builder.endObject(); const offset = builder.endObject();
builder.requiredField(offset, 10); // name builder.requiredField(offset, 10); // name
@@ -869,7 +906,7 @@ export class Monster {
return null; return null;
} }
return temp.unpack(); return temp.unpack();
})(), this.bb.createScalarList(this.vectorOfEnums.bind(this), this.vectorOfEnumsLength()), this.signedEnum(), this.bb.createScalarList(this.testrequirednestedflatbuffer.bind(this), this.testrequirednestedflatbufferLength()), this.bb.createObjList(this.scalarKeySortedTables.bind(this), this.scalarKeySortedTablesLength())); })(), this.bb.createScalarList(this.vectorOfEnums.bind(this), this.vectorOfEnumsLength()), this.signedEnum(), this.bb.createScalarList(this.testrequirednestedflatbuffer.bind(this), this.testrequirednestedflatbufferLength()), this.bb.createObjList(this.scalarKeySortedTables.bind(this), this.scalarKeySortedTablesLength()), (this.nativeInline() !== null ? this.nativeInline().unpack() : null), this.longEnumNonEnumDefault(), this.longEnumNormalDefault());
} }
unpackTo(_o) { unpackTo(_o) {
_o.pos = (this.pos() !== null ? this.pos().unpack() : null); _o.pos = (this.pos() !== null ? this.pos().unpack() : null);
@@ -940,10 +977,13 @@ export class Monster {
_o.signedEnum = this.signedEnum(); _o.signedEnum = this.signedEnum();
_o.testrequirednestedflatbuffer = this.bb.createScalarList(this.testrequirednestedflatbuffer.bind(this), this.testrequirednestedflatbufferLength()); _o.testrequirednestedflatbuffer = this.bb.createScalarList(this.testrequirednestedflatbuffer.bind(this), this.testrequirednestedflatbufferLength());
_o.scalarKeySortedTables = this.bb.createObjList(this.scalarKeySortedTables.bind(this), this.scalarKeySortedTablesLength()); _o.scalarKeySortedTables = this.bb.createObjList(this.scalarKeySortedTables.bind(this), this.scalarKeySortedTablesLength());
_o.nativeInline = (this.nativeInline() !== null ? this.nativeInline().unpack() : null);
_o.longEnumNonEnumDefault = this.longEnumNonEnumDefault();
_o.longEnumNormalDefault = this.longEnumNormalDefault();
} }
} }
export class MonsterT { export class MonsterT {
constructor(pos = null, mana = 150, hp = 100, name = null, inventory = [], color = Color.Blue, testType = Any.NONE, test = null, test4 = [], testarrayofstring = [], testarrayoftables = [], enemy = null, testnestedflatbuffer = [], testempty = null, testbool = false, testhashs32Fnv1 = 0, testhashu32Fnv1 = 0, testhashs64Fnv1 = BigInt('0'), testhashu64Fnv1 = BigInt('0'), testhashs32Fnv1a = 0, testhashu32Fnv1a = 0, testhashs64Fnv1a = BigInt('0'), testhashu64Fnv1a = BigInt('0'), testarrayofbools = [], testf = 3.14159, testf2 = 3.0, testf3 = 0.0, testarrayofstring2 = [], testarrayofsortedstruct = [], flex = [], test5 = [], vectorOfLongs = [], vectorOfDoubles = [], parentNamespaceTest = null, vectorOfReferrables = [], singleWeakReference = BigInt('0'), vectorOfWeakReferences = [], vectorOfStrongReferrables = [], coOwningReference = BigInt('0'), vectorOfCoOwningReferences = [], nonOwningReference = BigInt('0'), vectorOfNonOwningReferences = [], anyUniqueType = AnyUniqueAliases.NONE, anyUnique = null, anyAmbiguousType = AnyAmbiguousAliases.NONE, anyAmbiguous = null, vectorOfEnums = [], signedEnum = Race.None, testrequirednestedflatbuffer = [], scalarKeySortedTables = []) { constructor(pos = null, mana = 150, hp = 100, name = null, inventory = [], color = Color.Blue, testType = Any.NONE, test = null, test4 = [], testarrayofstring = [], testarrayoftables = [], enemy = null, testnestedflatbuffer = [], testempty = null, testbool = false, testhashs32Fnv1 = 0, testhashu32Fnv1 = 0, testhashs64Fnv1 = BigInt('0'), testhashu64Fnv1 = BigInt('0'), testhashs32Fnv1a = 0, testhashu32Fnv1a = 0, testhashs64Fnv1a = BigInt('0'), testhashu64Fnv1a = BigInt('0'), testarrayofbools = [], testf = 3.14159, testf2 = 3.0, testf3 = 0.0, testarrayofstring2 = [], testarrayofsortedstruct = [], flex = [], test5 = [], vectorOfLongs = [], vectorOfDoubles = [], parentNamespaceTest = null, vectorOfReferrables = [], singleWeakReference = BigInt('0'), vectorOfWeakReferences = [], vectorOfStrongReferrables = [], coOwningReference = BigInt('0'), vectorOfCoOwningReferences = [], nonOwningReference = BigInt('0'), vectorOfNonOwningReferences = [], anyUniqueType = AnyUniqueAliases.NONE, anyUnique = null, anyAmbiguousType = AnyAmbiguousAliases.NONE, anyAmbiguous = null, vectorOfEnums = [], signedEnum = Race.None, testrequirednestedflatbuffer = [], scalarKeySortedTables = [], nativeInline = null, longEnumNonEnumDefault = BigInt('0'), longEnumNormalDefault = BigInt('2')) {
this.pos = pos; this.pos = pos;
this.mana = mana; this.mana = mana;
this.hp = hp; this.hp = hp;
@@ -994,6 +1034,9 @@ export class MonsterT {
this.signedEnum = signedEnum; this.signedEnum = signedEnum;
this.testrequirednestedflatbuffer = testrequirednestedflatbuffer; this.testrequirednestedflatbuffer = testrequirednestedflatbuffer;
this.scalarKeySortedTables = scalarKeySortedTables; this.scalarKeySortedTables = scalarKeySortedTables;
this.nativeInline = nativeInline;
this.longEnumNonEnumDefault = longEnumNonEnumDefault;
this.longEnumNormalDefault = longEnumNormalDefault;
} }
pack(builder) { pack(builder) {
const name = (this.name !== null ? builder.createString(this.name) : 0); const name = (this.name !== null ? builder.createString(this.name) : 0);
@@ -1074,6 +1117,9 @@ export class MonsterT {
Monster.addSignedEnum(builder, this.signedEnum); Monster.addSignedEnum(builder, this.signedEnum);
Monster.addTestrequirednestedflatbuffer(builder, testrequirednestedflatbuffer); Monster.addTestrequirednestedflatbuffer(builder, testrequirednestedflatbuffer);
Monster.addScalarKeySortedTables(builder, scalarKeySortedTables); Monster.addScalarKeySortedTables(builder, scalarKeySortedTables);
Monster.addNativeInline(builder, (this.nativeInline !== null ? this.nativeInline.pack(builder) : 0));
Monster.addLongEnumNonEnumDefault(builder, this.longEnumNonEnumDefault);
Monster.addLongEnumNormalDefault(builder, this.longEnumNormalDefault);
return Monster.endMonster(builder); return Monster.endMonster(builder);
} }
} }

View File

@@ -0,0 +1,14 @@
load("//:build_defs.bzl", "flatbuffer_ts_library")
flatbuffer_ts_library(
name = "typescript_transitive_ts_fbs",
srcs = ["typescript_transitive_include.fbs"],
visibility = ["//visibility:public"],
)
flatbuffer_ts_library(
name = "include_ts_fbs",
srcs = ["typescript_include.fbs"],
visibility = ["//visibility:public"],
deps = [":typescript_transitive_ts_fbs"],
)

View File

@@ -0,0 +1,6 @@
include 'typescript_transitive_include.fbs';
namespace foobar;
enum class: int {
arguments,
}

View File

@@ -0,0 +1,5 @@
namespace foobar;
enum Abc: int {
a,
}

View File

@@ -15,6 +15,7 @@
"include": [ "include": [
"monster_test.ts", "monster_test.ts",
"typescript_keywords.ts", "typescript_keywords.ts",
"typescript_keywords_generated.ts",
"my-game/**/*.ts", "my-game/**/*.ts",
"typescript/**/*.ts", "typescript/**/*.ts",
"optional_scalars/**/*.ts", "optional_scalars/**/*.ts",

View File

@@ -1,3 +1,6 @@
include 'test_dir/typescript_include.fbs';
include 'reflection/reflection.fbs';
// This file includes a variety of keywords meant to deliberately interfere // This file includes a variety of keywords meant to deliberately interfere
// with typescript keywords. // with typescript keywords.
namespace typescript; namespace typescript;
@@ -12,4 +15,7 @@ table Object {
if:int; if:int;
switch:int; switch:int;
enum:class; enum:class;
enum2:foobar.class;
enum3:foobar.Abc;
reflect:reflection.Schema;
} }

39
ts/BUILD.bazel Normal file
View File

@@ -0,0 +1,39 @@
load("@npm//@bazel/typescript:index.bzl", "ts_project")
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
ts_project(
name = "flatbuffers_ts",
srcs = [
"builder.ts",
"byte-buffer.ts",
"constants.ts",
"encoding.ts",
"index.ts",
"types.ts",
"utils.ts",
],
declaration = True,
tsconfig = {
"compilerOptions": {
"module": "commonjs",
"declaration": True,
"moduleResolution": "node",
"lib": [
"ES2015",
"ES2020.BigInt",
"DOM",
],
"types": ["node"],
"strict": True,
},
},
visibility = ["//visibility:public"],
deps = ["@npm//@types/node"],
)
js_library(
name = "flatbuffers",
package_name = "flatbuffers",
visibility = ["//visibility:public"],
deps = [":flatbuffers_ts"],
)

1130
yarn.lock Normal file

File diff suppressed because it is too large Load Diff