Skip to content

Commit 928c38e

Browse files
bulentvJochen Parmentier
authored and
Jochen Parmentier
committed
[TS] Add support for fixed length arrays on Typescript (google#5864) (google#7021) (google#7581)
* [TS] Add support for fixed length arrays on Typescript (google#5864) (google#7021) * Typescript / Javascript don't have fixed arrays but it is important to support these languages for compatibility. * Generated TS code checks the length of the given array and do truncating / padding to conform to the schema. * Supports the both standard API and Object Based API. * Added a test. Co-authored-by: Mehmet Baker <[email protected]> Signed-off-by: Bulent Vural <[email protected]> Signed-off-by: Bülent Vural <[email protected]> * Formatting & readability fixes on idl_gen_ts.cpp Signed-off-by: Bülent Vural <[email protected]> * Added array_test_complex.bfbs Signed-off-by: Bülent Vural <[email protected]> * TS arrays_test_complex: Remove bfbs and use fbs directly Signed-off-by: Bülent Vural <[email protected]> Signed-off-by: Bülent Vural <[email protected]>
1 parent ed0b2b6 commit 928c38e

14 files changed

+1670
-33
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,4 @@ flatbuffers.pc
149149
**/html/**
150150
**/latex/**
151151
# https://cmake.org/cmake/help/latest/module/FetchContent.html#variable:FETCHCONTENT_BASE_DIR
152-
_deps/
152+
_deps/

src/idl_gen_ts.cpp

Lines changed: 320 additions & 15 deletions
Large diffs are not rendered by default.

src/idl_parser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2586,7 +2586,7 @@ bool Parser::SupportsAdvancedArrayFeatures() const {
25862586
return (opts.lang_to_generate &
25872587
~(IDLOptions::kCpp | IDLOptions::kPython | IDLOptions::kJava |
25882588
IDLOptions::kCSharp | IDLOptions::kJsonSchema | IDLOptions::kJson |
2589-
IDLOptions::kBinary | IDLOptions::kRust)) == 0;
2589+
IDLOptions::kBinary | IDLOptions::kRust | IDLOptions::kTs)) == 0;
25902590
}
25912591

25922592
Namespace *Parser::UniqueNamespace(Namespace *ns) {
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/* global BigInt */
2+
3+
import assert from 'assert';
4+
import { readFileSync, writeFileSync } from 'fs';
5+
import * as flatbuffers from 'flatbuffers';
6+
import {
7+
ArrayStructT,
8+
ArrayTable,
9+
ArrayTableT,
10+
InnerStructT,
11+
NestedStructT,
12+
OuterStructT,
13+
TestEnum,
14+
} from './arrays_test_complex/arrays_test_complex_generated.js';
15+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
16+
BigInt.prototype.toJSON = function () {
17+
return this.toString();
18+
};
19+
function fbObjToObj(fbObj) {
20+
const ret = {};
21+
for (const propName of Object.keys(fbObj)) {
22+
const key = propName;
23+
const prop = fbObj[key];
24+
if (prop.valueOf) {
25+
ret[key] = prop.valueOf();
26+
} else if (typeof prop === 'object') {
27+
ret[key] = fbObjToObj(prop);
28+
}
29+
}
30+
return ret;
31+
}
32+
function testBuild(monFile, jsFile) {
33+
const arrayTable = new ArrayTableT(
34+
'Complex Array Test',
35+
new ArrayStructT(
36+
221.139008,
37+
[-700, -600, -500, -400, -300, -200, -100, 0, 100, 200, 300, 400, 500, 600, 700],
38+
13,
39+
[
40+
new NestedStructT(
41+
[233, -123],
42+
TestEnum.B,
43+
[TestEnum.A, TestEnum.C],
44+
[
45+
new OuterStructT(
46+
false,
47+
123.456,
48+
new InnerStructT(
49+
123456792.0,
50+
[13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
51+
91,
52+
BigInt('9007199254740999')
53+
),
54+
[
55+
new InnerStructT(
56+
-987654321.9876,
57+
[255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243],
58+
123,
59+
BigInt('9007199254741000')
60+
),
61+
new InnerStructT(
62+
123000987.9876,
63+
[101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113],
64+
-123,
65+
BigInt('9007199254741000')
66+
),
67+
],
68+
new InnerStructT(
69+
987654321.9876,
70+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
71+
19,
72+
BigInt('9007199254741000')
73+
),
74+
[111000111.222, 222000222.111, 333000333.333, 444000444.444]
75+
),
76+
]
77+
),
78+
],
79+
-123456789
80+
)
81+
);
82+
const builder = new flatbuffers.Builder();
83+
builder.finish(arrayTable.pack(builder));
84+
if (jsFile) {
85+
const obj = fbObjToObj(arrayTable);
86+
writeFileSync(jsFile, `export default ${JSON.stringify(obj, null, 2)}`);
87+
}
88+
if (monFile) {
89+
writeFileSync(monFile, builder.asUint8Array());
90+
}
91+
return builder.asUint8Array();
92+
}
93+
function testParse(monFile, jsFile, buffer) {
94+
if (!buffer) {
95+
if (!monFile) {
96+
console.log(`Please specify mon file read the buffer from.`);
97+
process.exit(1);
98+
}
99+
buffer = readFileSync(monFile);
100+
}
101+
const byteBuffer = new flatbuffers.ByteBuffer(new Uint8Array(buffer));
102+
const arrayTable = ArrayTable.getRootAsArrayTable(byteBuffer).unpack();
103+
const json = JSON.stringify(arrayTable, null, 2);
104+
if (jsFile) {
105+
writeFileSync(jsFile, `export default ${json}`);
106+
}
107+
return arrayTable;
108+
}
109+
if (process.argv[2] === 'build') {
110+
testBuild(process.argv[3], process.argv[4]);
111+
} else if (process.argv[2] === 'parse') {
112+
testParse(process.argv[3], process.argv[4], null);
113+
} else {
114+
const arr = testBuild(null, null);
115+
const parsed = testParse(null, null, Buffer.from(arr));
116+
assert.strictEqual(parsed.a, 'Complex Array Test', 'String Test');
117+
assert.strictEqual(parsed?.cUnderscore?.aUnderscore, 221.13900756835938, 'Float Test');
118+
assert.deepEqual(parsed?.cUnderscore?.bUnderscore, [-700, -600, -500, -400, -300, -200, -100, 0, 100, 200, 300, 400, 500, 600, 700], 'Array of signed integers');
119+
assert.strictEqual(parsed?.cUnderscore.d?.[0].dOuter[0].d[1].a, 123000987.9876, 'Float in deep');
120+
assert.deepEqual(parsed?.cUnderscore?.d[0].dOuter?.[0]?.e, {
121+
a: 987654321.9876,
122+
b: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
123+
c: 19,
124+
dUnderscore: '9007199254741000',
125+
}, 'Object in deep');
126+
assert.deepEqual(parsed?.cUnderscore.g, ['0', '0'], 'Last object');
127+
128+
console.log('Arrays test: completed successfully');
129+
}

tests/ts/TypeScriptTest.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ def flatc(options, schema, prefix=None, include=None, data=None, cwd=tests_path)
9595
include="../../",
9696
)
9797

98+
flatc(
99+
options=["--ts", "--reflect-names", "--ts-flat-files", "--gen-name-strings", "--gen-object-api"],
100+
schema="arrays_test_complex/arrays_test_complex.fbs",
101+
prefix="arrays_test_complex"
102+
)
103+
98104
flatc(
99105
options=[
100106
"--ts",
@@ -121,4 +127,5 @@ def flatc(options, schema, prefix=None, include=None, data=None, cwd=tests_path)
121127
print("Running TypeScript Tests...")
122128
check_call(NODE_CMD + ["JavaScriptTest"])
123129
check_call(NODE_CMD + ["JavaScriptUnionVectorTest"])
124-
check_call(NODE_CMD + ["JavaScriptFlexBuffersTest"])
130+
check_call(NODE_CMD + ["JavaScriptFlexBuffersTest"])
131+
check_call(NODE_CMD + ["JavaScriptComplexArraysTest"])
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
namespace MyGame.Example;
2+
3+
enum TestEnum : byte { A, B, C }
4+
5+
struct InnerStruct {
6+
a:float64;
7+
b:[ubyte:13];
8+
c:int8;
9+
d_underscore:int64;
10+
}
11+
12+
struct OuterStruct {
13+
a:bool;
14+
b:double;
15+
c_underscore:InnerStruct;
16+
d:[InnerStruct:3];
17+
e:InnerStruct;
18+
f:[float64:4];
19+
}
20+
21+
struct NestedStruct{
22+
a:[int:2];
23+
b:TestEnum;
24+
c_underscore:[TestEnum:2];
25+
d_outer:[OuterStruct:5];
26+
e:[int64:2];
27+
}
28+
29+
struct ArrayStruct{
30+
a_underscore:float;
31+
b_underscore:[int:0xF];
32+
c:byte;
33+
d:[NestedStruct:2];
34+
e:int32;
35+
f:[OuterStruct:2];
36+
g:[int64:2];
37+
}
38+
39+
table ArrayTable{
40+
a:string;
41+
c_underscore:ArrayStruct;
42+
}
43+
44+
root_type ArrayTable;
45+
file_identifier "RHUB";
46+
file_extension "mon";

0 commit comments

Comments
 (0)