@dusted/anqst 1.5.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/app.js +31 -9
- package/dist/src/base93.js +0 -72
- package/dist/src/boundary-codec-analysis.js +468 -0
- package/dist/src/boundary-codec-leaves.js +602 -0
- package/dist/src/boundary-codec-model.js +77 -0
- package/dist/src/boundary-codec-plan.js +522 -0
- package/dist/src/boundary-codec-render.js +1738 -0
- package/dist/src/boundary-codecs.js +174 -0
- package/dist/src/emit.js +580 -90
- package/dist/src/program.js +1 -1
- package/package.json +2 -2
- package/dist/src/codecgenerators/basecodecemitters/bigint-qint64/decoder.js +0 -35
- package/dist/src/codecgenerators/basecodecemitters/bigint-qint64/encoder.js +0 -36
- package/dist/src/codecgenerators/basecodecemitters/bigint-quint64/decoder.js +0 -26
- package/dist/src/codecgenerators/basecodecemitters/bigint-quint64/encoder.js +0 -38
- package/dist/src/codecgenerators/basecodecemitters/binary-blob/decoder.js +0 -28
- package/dist/src/codecgenerators/basecodecemitters/binary-blob/encoder.js +0 -34
- package/dist/src/codecgenerators/basecodecemitters/binary-buffer/decoder.js +0 -29
- package/dist/src/codecgenerators/basecodecemitters/binary-buffer/encoder.js +0 -36
- package/dist/src/codecgenerators/basecodecemitters/binary-float32Array/decoder.js +0 -46
- package/dist/src/codecgenerators/basecodecemitters/binary-float32Array/encoder.js +0 -49
- package/dist/src/codecgenerators/basecodecemitters/binary-float64Array/decoder.js +0 -46
- package/dist/src/codecgenerators/basecodecemitters/binary-float64Array/encoder.js +0 -47
- package/dist/src/codecgenerators/basecodecemitters/binary-int16Array/decoder.js +0 -46
- package/dist/src/codecgenerators/basecodecemitters/binary-int16Array/encoder.js +0 -49
- package/dist/src/codecgenerators/basecodecemitters/binary-int32Array/decoder.js +0 -50
- package/dist/src/codecgenerators/basecodecemitters/binary-int32Array/encoder.js +0 -52
- package/dist/src/codecgenerators/basecodecemitters/binary-int8Array/decoder.js +0 -38
- package/dist/src/codecgenerators/basecodecemitters/binary-int8Array/encoder.js +0 -44
- package/dist/src/codecgenerators/basecodecemitters/binary-typedArray/decoder.js +0 -33
- package/dist/src/codecgenerators/basecodecemitters/binary-typedArray/encoder.js +0 -34
- package/dist/src/codecgenerators/basecodecemitters/binary-uint16Array/decoder.js +0 -46
- package/dist/src/codecgenerators/basecodecemitters/binary-uint16Array/encoder.js +0 -49
- package/dist/src/codecgenerators/basecodecemitters/binary-uint32Array/decoder.js +0 -46
- package/dist/src/codecgenerators/basecodecemitters/binary-uint32Array/encoder.js +0 -49
- package/dist/src/codecgenerators/basecodecemitters/binary-uint8Array/decoder.js +0 -28
- package/dist/src/codecgenerators/basecodecemitters/binary-uint8Array/encoder.js +0 -34
- package/dist/src/codecgenerators/basecodecemitters/boolean/decoder.js +0 -34
- package/dist/src/codecgenerators/basecodecemitters/boolean/encoder.js +0 -40
- package/dist/src/codecgenerators/basecodecemitters/dynamic-json/decoder.js +0 -43
- package/dist/src/codecgenerators/basecodecemitters/dynamic-json/encoder.js +0 -45
- package/dist/src/codecgenerators/basecodecemitters/dynamic-object/decoder.js +0 -44
- package/dist/src/codecgenerators/basecodecemitters/dynamic-object/encoder.js +0 -46
- package/dist/src/codecgenerators/basecodecemitters/integer-int16/decoder.js +0 -32
- package/dist/src/codecgenerators/basecodecemitters/integer-int16/encoder.js +0 -43
- package/dist/src/codecgenerators/basecodecemitters/integer-int32/decoder.js +0 -26
- package/dist/src/codecgenerators/basecodecemitters/integer-int32/encoder.js +0 -37
- package/dist/src/codecgenerators/basecodecemitters/integer-int8/decoder.js +0 -26
- package/dist/src/codecgenerators/basecodecemitters/integer-int8/encoder.js +0 -37
- package/dist/src/codecgenerators/basecodecemitters/integer-qint16/decoder.js +0 -36
- package/dist/src/codecgenerators/basecodecemitters/integer-qint16/encoder.js +0 -36
- package/dist/src/codecgenerators/basecodecemitters/integer-qint32/decoder.js +0 -25
- package/dist/src/codecgenerators/basecodecemitters/integer-qint32/encoder.js +0 -36
- package/dist/src/codecgenerators/basecodecemitters/integer-qint8/decoder.js +0 -36
- package/dist/src/codecgenerators/basecodecemitters/integer-qint8/encoder.js +0 -36
- package/dist/src/codecgenerators/basecodecemitters/integer-quint16/decoder.js +0 -26
- package/dist/src/codecgenerators/basecodecemitters/integer-quint16/encoder.js +0 -38
- package/dist/src/codecgenerators/basecodecemitters/integer-quint32/decoder.js +0 -27
- package/dist/src/codecgenerators/basecodecemitters/integer-quint32/encoder.js +0 -39
- package/dist/src/codecgenerators/basecodecemitters/integer-quint8/decoder.js +0 -26
- package/dist/src/codecgenerators/basecodecemitters/integer-quint8/encoder.js +0 -38
- package/dist/src/codecgenerators/basecodecemitters/integer-uint16/decoder.js +0 -30
- package/dist/src/codecgenerators/basecodecemitters/integer-uint16/encoder.js +0 -42
- package/dist/src/codecgenerators/basecodecemitters/integer-uint32/decoder.js +0 -31
- package/dist/src/codecgenerators/basecodecemitters/integer-uint32/encoder.js +0 -43
- package/dist/src/codecgenerators/basecodecemitters/integer-uint8/decoder.js +0 -30
- package/dist/src/codecgenerators/basecodecemitters/integer-uint8/encoder.js +0 -40
- package/dist/src/codecgenerators/basecodecemitters/number/decoder.js +0 -26
- package/dist/src/codecgenerators/basecodecemitters/number/encoder.js +0 -38
- package/dist/src/codecgenerators/basecodecemitters/shared/comments.js +0 -13
- package/dist/src/codecgenerators/basecodecemitters/shared/contracts.js +0 -2
- package/dist/src/codecgenerators/basecodecemitters/shared/fixedwidth.js +0 -53
- package/dist/src/codecgenerators/basecodecemitters/shared/index.js +0 -21
- package/dist/src/codecgenerators/basecodecemitters/shared/positionalBase93.js +0 -48
- package/dist/src/codecgenerators/basecodecemitters/shared/rawbytes.js +0 -30
- package/dist/src/codecgenerators/basecodecemitters/string/decoder.js +0 -43
- package/dist/src/codecgenerators/basecodecemitters/string/encoder.js +0 -43
- package/dist/src/codecgenerators/basecodecemitters/stringArray/decoder.js +0 -80
- package/dist/src/codecgenerators/basecodecemitters/stringArray/encoder.js +0 -57
- package/dist/src/structured-top-level-codecs.js +0 -1305
package/dist/src/app.js
CHANGED
|
@@ -19,6 +19,12 @@ const project_1 = require("./project");
|
|
|
19
19
|
const layout_1 = require("./layout");
|
|
20
20
|
const parser_1 = require("./parser");
|
|
21
21
|
const verify_1 = require("./verify");
|
|
22
|
+
class CliUsageError extends Error {
|
|
23
|
+
constructor(message) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = "CliUsageError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
22
28
|
const ANQSTGEN_ACTIVE_STAMP_FILE = ".anqstgen-version-active.json";
|
|
23
29
|
function renderHelp() {
|
|
24
30
|
const version = readActiveBuildStamp();
|
|
@@ -296,12 +302,12 @@ function parseSpecCommandArg(commandName, specArg, extraArgs) {
|
|
|
296
302
|
const positional = [];
|
|
297
303
|
for (const arg of allArgs) {
|
|
298
304
|
if (arg.startsWith("-")) {
|
|
299
|
-
throw new
|
|
305
|
+
throw new CliUsageError(`Unknown ${commandName} flag '${arg}'. ${usageFor(commandName)}`);
|
|
300
306
|
}
|
|
301
307
|
positional.push(arg);
|
|
302
308
|
}
|
|
303
309
|
if (positional.length !== 1) {
|
|
304
|
-
throw new
|
|
310
|
+
throw new CliUsageError(usageFor(commandName));
|
|
305
311
|
}
|
|
306
312
|
return positional[0];
|
|
307
313
|
}
|
|
@@ -328,12 +334,12 @@ function parseBuildCommandArgs(specArg, extraArgs) {
|
|
|
328
334
|
continue;
|
|
329
335
|
}
|
|
330
336
|
if (arg.startsWith("-")) {
|
|
331
|
-
throw new
|
|
337
|
+
throw new CliUsageError(`Unknown build flag '${arg}'. ${usageFor("build")}`);
|
|
332
338
|
}
|
|
333
339
|
positional.push(arg);
|
|
334
340
|
}
|
|
335
341
|
if (positional.length > 0) {
|
|
336
|
-
throw new
|
|
342
|
+
throw new CliUsageError(`Unexpected extra argument '${positional[0]}'. ${usageFor("build")}`);
|
|
337
343
|
}
|
|
338
344
|
return { designerPlugin };
|
|
339
345
|
}
|
|
@@ -347,15 +353,15 @@ function parseCleanCommandArgs(specArg, extraArgs) {
|
|
|
347
353
|
continue;
|
|
348
354
|
}
|
|
349
355
|
if (arg.startsWith("-")) {
|
|
350
|
-
throw new
|
|
356
|
+
throw new CliUsageError(`Unknown clean flag '${arg}'. Use -f or --force.`);
|
|
351
357
|
}
|
|
352
358
|
if (targetPathArg !== null) {
|
|
353
|
-
throw new
|
|
359
|
+
throw new CliUsageError(`Unexpected extra argument '${arg}'. Usage: anqst clean <path> [-f|--force]`);
|
|
354
360
|
}
|
|
355
361
|
targetPathArg = arg;
|
|
356
362
|
}
|
|
357
363
|
if (targetPathArg === null) {
|
|
358
|
-
throw new
|
|
364
|
+
throw new CliUsageError("Usage: anqst clean <path> [-f|--force]");
|
|
359
365
|
}
|
|
360
366
|
return { targetPathArg, force };
|
|
361
367
|
}
|
|
@@ -476,6 +482,19 @@ function renderInstallAliasMessage() {
|
|
|
476
482
|
return text;
|
|
477
483
|
return `\x1b[38;5;214m${text}\x1b[0m`;
|
|
478
484
|
}
|
|
485
|
+
function formatUnexpectedError(error) {
|
|
486
|
+
if (!(error instanceof Error)) {
|
|
487
|
+
return `[AnQst] ${String(error)}`;
|
|
488
|
+
}
|
|
489
|
+
const lines = [`[AnQst] ${error.message}`];
|
|
490
|
+
const stack = typeof error.stack === "string" ? error.stack.trim() : "";
|
|
491
|
+
if (stack.length > 0) {
|
|
492
|
+
lines.push("");
|
|
493
|
+
lines.push("Stack trace:");
|
|
494
|
+
lines.push(stack);
|
|
495
|
+
}
|
|
496
|
+
return lines.join("\n");
|
|
497
|
+
}
|
|
479
498
|
function runCommand(command, specArg, extraArgs = []) {
|
|
480
499
|
try {
|
|
481
500
|
if (!command) {
|
|
@@ -545,8 +564,11 @@ function runCommand(command, specArg, extraArgs = []) {
|
|
|
545
564
|
console.error((0, errors_1.formatVerifyError)(error));
|
|
546
565
|
return 1;
|
|
547
566
|
}
|
|
548
|
-
|
|
549
|
-
|
|
567
|
+
if (error instanceof CliUsageError) {
|
|
568
|
+
console.error(error.message);
|
|
569
|
+
return 1;
|
|
570
|
+
}
|
|
571
|
+
console.error(formatUnexpectedError(error));
|
|
550
572
|
return 1;
|
|
551
573
|
}
|
|
552
574
|
}
|
package/dist/src/base93.js
CHANGED
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.BASE93_ALPHABET = void 0;
|
|
4
4
|
exports.emitBase93Encoder = emitBase93Encoder;
|
|
5
5
|
exports.emitBase93Decoder = emitBase93Decoder;
|
|
6
|
-
exports.emitBase93CppFunctions = emitBase93CppFunctions;
|
|
7
6
|
exports.BASE93_ALPHABET = Array.from({ length: 95 }, (_, i) => String.fromCharCode(0x20 + i))
|
|
8
7
|
.filter(c => c !== '"' && c !== '\\')
|
|
9
8
|
.join('');
|
|
@@ -51,74 +50,3 @@ for (i = r - 2; i >= 0; i--) { o[p + i] = v & 255; v = (v / 256) | 0; }
|
|
|
51
50
|
return o;
|
|
52
51
|
}`;
|
|
53
52
|
}
|
|
54
|
-
function emitBase93CppFunctions() {
|
|
55
|
-
return `inline int base93AlphabetIndex(char c) {
|
|
56
|
-
const unsigned char uc = static_cast<unsigned char>(c);
|
|
57
|
-
return static_cast<int>(uc) - 32 - (uc > 34) - (uc > 92);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
inline std::string base93Encode(const std::vector<std::uint8_t>& d) {
|
|
61
|
-
static constexpr char A[] = "${exports.BASE93_ALPHABET}";
|
|
62
|
-
const std::size_t n = d.size();
|
|
63
|
-
const std::size_t f = n >> 2;
|
|
64
|
-
const std::size_t r = n & 3;
|
|
65
|
-
std::string o(f * 5 + (r ? r + 1 : 0), '\\0');
|
|
66
|
-
std::size_t p = 0;
|
|
67
|
-
for (std::size_t i = 0; i < f; ++i) {
|
|
68
|
-
const std::size_t b = i << 2;
|
|
69
|
-
std::uint32_t v =
|
|
70
|
-
(static_cast<std::uint32_t>(d[b]) << 24) |
|
|
71
|
-
(static_cast<std::uint32_t>(d[b + 1]) << 16) |
|
|
72
|
-
(static_cast<std::uint32_t>(d[b + 2]) << 8) |
|
|
73
|
-
static_cast<std::uint32_t>(d[b + 3]);
|
|
74
|
-
o[p + 4] = A[v % 93u]; v /= 93u;
|
|
75
|
-
o[p + 3] = A[v % 93u]; v /= 93u;
|
|
76
|
-
o[p + 2] = A[v % 93u]; v /= 93u;
|
|
77
|
-
o[p + 1] = A[v % 93u];
|
|
78
|
-
o[p] = A[v / 93u];
|
|
79
|
-
p += 5;
|
|
80
|
-
}
|
|
81
|
-
if (r) {
|
|
82
|
-
const std::size_t b = f << 2;
|
|
83
|
-
std::uint32_t v = 0;
|
|
84
|
-
for (std::size_t j = 0; j < r; ++j) v = (v << 8) | d[b + j];
|
|
85
|
-
for (std::size_t j = r + 1; j-- > 0;) {
|
|
86
|
-
o[p + j] = A[v % 93u];
|
|
87
|
-
v /= 93u;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return o;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
inline std::vector<std::uint8_t> base93Decode(const std::string& s) {
|
|
94
|
-
const std::size_t n = s.size();
|
|
95
|
-
const std::size_t f = n / 5;
|
|
96
|
-
const std::size_t r = n - f * 5;
|
|
97
|
-
std::vector<std::uint8_t> o(f * 4 + (r ? r - 1 : 0));
|
|
98
|
-
std::size_t p = 0;
|
|
99
|
-
for (std::size_t i = 0; i < f; ++i) {
|
|
100
|
-
const std::size_t b = i * 5;
|
|
101
|
-
std::uint32_t v = static_cast<std::uint32_t>(base93AlphabetIndex(s[b]));
|
|
102
|
-
v = v * 93u + static_cast<std::uint32_t>(base93AlphabetIndex(s[b + 1]));
|
|
103
|
-
v = v * 93u + static_cast<std::uint32_t>(base93AlphabetIndex(s[b + 2]));
|
|
104
|
-
v = v * 93u + static_cast<std::uint32_t>(base93AlphabetIndex(s[b + 3]));
|
|
105
|
-
v = v * 93u + static_cast<std::uint32_t>(base93AlphabetIndex(s[b + 4]));
|
|
106
|
-
o[p] = static_cast<std::uint8_t>(v >> 24);
|
|
107
|
-
o[p + 1] = static_cast<std::uint8_t>((v >> 16) & 255u);
|
|
108
|
-
o[p + 2] = static_cast<std::uint8_t>((v >> 8) & 255u);
|
|
109
|
-
o[p + 3] = static_cast<std::uint8_t>(v & 255u);
|
|
110
|
-
p += 4;
|
|
111
|
-
}
|
|
112
|
-
if (r) {
|
|
113
|
-
std::uint32_t v = 0;
|
|
114
|
-
for (std::size_t i = 0; i < r; ++i) {
|
|
115
|
-
v = v * 93u + static_cast<std::uint32_t>(base93AlphabetIndex(s[f * 5 + i]));
|
|
116
|
-
}
|
|
117
|
-
for (std::size_t i = r - 1; i-- > 0;) {
|
|
118
|
-
o[p + i] = static_cast<std::uint8_t>(v & 255u);
|
|
119
|
-
v /= 256u;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return o;
|
|
123
|
-
}`;
|
|
124
|
-
}
|
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.BoundaryTransportAnalyzer = void 0;
|
|
7
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
+
const errors_1 = require("./errors");
|
|
9
|
+
const boundary_codec_model_1 = require("./boundary-codec-model");
|
|
10
|
+
const boundary_codec_leaves_1 = require("./boundary-codec-leaves");
|
|
11
|
+
const BUILTIN_TYPE_REFS = new Set(["Array", "ReadonlyArray", "Record", "Map", "Partial", "Promise"]);
|
|
12
|
+
function isStringLikeUnion(node) {
|
|
13
|
+
return node.types.every((part) => {
|
|
14
|
+
if (typescript_1.default.isLiteralTypeNode(part) && typescript_1.default.isStringLiteral(part.literal))
|
|
15
|
+
return true;
|
|
16
|
+
return part.kind === typescript_1.default.SyntaxKind.StringKeyword;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function isBooleanLikeUnion(node) {
|
|
20
|
+
return node.types.every((part) => {
|
|
21
|
+
if (typescript_1.default.isLiteralTypeNode(part)) {
|
|
22
|
+
return part.literal.kind === typescript_1.default.SyntaxKind.TrueKeyword || part.literal.kind === typescript_1.default.SyntaxKind.FalseKeyword;
|
|
23
|
+
}
|
|
24
|
+
return part.kind === typescript_1.default.SyntaxKind.BooleanKeyword;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function isNumberLikeUnion(node) {
|
|
28
|
+
return node.types.every((part) => {
|
|
29
|
+
if (typescript_1.default.isLiteralTypeNode(part) && typescript_1.default.isNumericLiteral(part.literal))
|
|
30
|
+
return true;
|
|
31
|
+
return part.kind === typescript_1.default.SyntaxKind.NumberKeyword || part.kind === typescript_1.default.SyntaxKind.BigIntKeyword;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function filterNullishUnionParts(types) {
|
|
35
|
+
return types.filter((part) => part.kind !== typescript_1.default.SyntaxKind.NullKeyword && part.kind !== typescript_1.default.SyntaxKind.UndefinedKeyword);
|
|
36
|
+
}
|
|
37
|
+
function collectFiniteStringLiterals(node) {
|
|
38
|
+
const values = [];
|
|
39
|
+
for (const part of node.types) {
|
|
40
|
+
if (!typescript_1.default.isLiteralTypeNode(part) || !typescript_1.default.isStringLiteral(part.literal))
|
|
41
|
+
return null;
|
|
42
|
+
values.push(part.literal.text);
|
|
43
|
+
}
|
|
44
|
+
return values;
|
|
45
|
+
}
|
|
46
|
+
function collectFiniteBooleanLiterals(node) {
|
|
47
|
+
const values = [];
|
|
48
|
+
for (const part of node.types) {
|
|
49
|
+
if (!typescript_1.default.isLiteralTypeNode(part))
|
|
50
|
+
return null;
|
|
51
|
+
if (part.literal.kind === typescript_1.default.SyntaxKind.TrueKeyword) {
|
|
52
|
+
values.push(true);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (part.literal.kind === typescript_1.default.SyntaxKind.FalseKeyword) {
|
|
56
|
+
values.push(false);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
return values;
|
|
62
|
+
}
|
|
63
|
+
function collectFiniteNumberLiterals(node) {
|
|
64
|
+
const values = [];
|
|
65
|
+
for (const part of node.types) {
|
|
66
|
+
if (!typescript_1.default.isLiteralTypeNode(part) || !typescript_1.default.isNumericLiteral(part.literal))
|
|
67
|
+
return null;
|
|
68
|
+
values.push(Number(part.literal.text));
|
|
69
|
+
}
|
|
70
|
+
return values;
|
|
71
|
+
}
|
|
72
|
+
function finiteDomainSymbolForValue(value) {
|
|
73
|
+
if (typeof value === "boolean")
|
|
74
|
+
return value ? "True" : "False";
|
|
75
|
+
if (typeof value === "number") {
|
|
76
|
+
const text = Number.isInteger(value) ? `${value}` : `${value}`.replace(/\./g, "_");
|
|
77
|
+
return (0, boundary_codec_model_1.sanitizeIdentifier)(`Value_${text.replace(/-/g, "neg_")}`);
|
|
78
|
+
}
|
|
79
|
+
const trimmed = value.trim();
|
|
80
|
+
if (trimmed.length === 0)
|
|
81
|
+
return "Empty";
|
|
82
|
+
const direct = (0, boundary_codec_model_1.sanitizeIdentifier)(trimmed);
|
|
83
|
+
return direct.length > 0 ? direct : "Value";
|
|
84
|
+
}
|
|
85
|
+
function buildFiniteDomain(primitive, values) {
|
|
86
|
+
const seen = new Set();
|
|
87
|
+
const variants = [];
|
|
88
|
+
for (const value of values) {
|
|
89
|
+
const key = `${typeof value}:${String(value)}`;
|
|
90
|
+
if (seen.has(key))
|
|
91
|
+
continue;
|
|
92
|
+
seen.add(key);
|
|
93
|
+
variants.push({
|
|
94
|
+
code: variants.length,
|
|
95
|
+
symbolicName: finiteDomainSymbolForValue(value),
|
|
96
|
+
tsLiteralText: typeof value === "string" ? JSON.stringify(value) : `${value}`,
|
|
97
|
+
value
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return { primitive, variants };
|
|
101
|
+
}
|
|
102
|
+
function unsupported(path, typeText, reason) {
|
|
103
|
+
throw new errors_1.VerifyError(`Boundary codec planning failed for '${path.join(".") || typeText}': ${reason} (${typeText}).`);
|
|
104
|
+
}
|
|
105
|
+
class BoundaryTransportAnalyzer {
|
|
106
|
+
constructor(spec) {
|
|
107
|
+
this.spec = spec;
|
|
108
|
+
this.declNodes = new Map();
|
|
109
|
+
this.namedNodes = new Map();
|
|
110
|
+
for (const decl of this.collectDecls()) {
|
|
111
|
+
const node = (0, boundary_codec_model_1.parseTypeDeclNode)(decl.nodeText);
|
|
112
|
+
if (node) {
|
|
113
|
+
this.declNodes.set(decl.name, node);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
analyzeTypeText(typeText, path) {
|
|
118
|
+
const rootNode = (0, boundary_codec_model_1.parseTypeNodeFromText)(typeText);
|
|
119
|
+
const root = this.resolveTypeNode(rootNode, typeText, path, [], this.defaultIdentityParts(rootNode, typeText, path));
|
|
120
|
+
return {
|
|
121
|
+
typeText,
|
|
122
|
+
tsTypeText: (0, boundary_codec_model_1.stripAnQstType)(typeText),
|
|
123
|
+
root,
|
|
124
|
+
summary: summarizeAnalysis(root)
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
collectDecls() {
|
|
128
|
+
const out = new Map();
|
|
129
|
+
for (const decl of this.spec.namespaceTypeDecls)
|
|
130
|
+
out.set(decl.name, decl);
|
|
131
|
+
for (const decl of this.spec.importedTypeDecls.values())
|
|
132
|
+
out.set(decl.name, decl);
|
|
133
|
+
return [...out.values()];
|
|
134
|
+
}
|
|
135
|
+
nodeMeta(typeText, path, identityParts) {
|
|
136
|
+
const normalizedParts = identityParts.filter((part) => part.trim().length > 0);
|
|
137
|
+
return {
|
|
138
|
+
typeText,
|
|
139
|
+
path,
|
|
140
|
+
typeIdentityKey: normalizedParts.join("::") || (0, boundary_codec_model_1.stripAnQstType)(typeText).trim(),
|
|
141
|
+
cppNameHintParts: normalizedParts.length > 0 ? normalizedParts : (path.length > 0 ? path : [(0, boundary_codec_model_1.stripAnQstType)(typeText).trim() || "AnonymousType"])
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
defaultIdentityParts(node, typeText, path) {
|
|
145
|
+
if (typescript_1.default.isTypeReferenceNode(node)) {
|
|
146
|
+
const name = (0, boundary_codec_model_1.qNameText)(node.typeName);
|
|
147
|
+
if (!name.startsWith("AnQst.Type.") && !BUILTIN_TYPE_REFS.has(name)) {
|
|
148
|
+
return [name];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return path.length > 0 ? [...path] : [(0, boundary_codec_model_1.stripAnQstType)(typeText).trim() || "AnonymousType"];
|
|
152
|
+
}
|
|
153
|
+
createFiniteDomainAnalysis(typeText, path, identityParts, domain) {
|
|
154
|
+
return {
|
|
155
|
+
nodeKind: "finite-domain",
|
|
156
|
+
...this.nodeMeta(typeText, path, identityParts),
|
|
157
|
+
domain
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
createStructAnalysis(typeText, path, members, stack, identityParts) {
|
|
161
|
+
const fields = members
|
|
162
|
+
.filter((member) => {
|
|
163
|
+
return typescript_1.default.isPropertySignature(member) && !!member.type && typescript_1.default.isIdentifier(member.name);
|
|
164
|
+
})
|
|
165
|
+
.map((member) => {
|
|
166
|
+
const fieldPath = [...path, member.name.text];
|
|
167
|
+
const fieldIdentityParts = [...identityParts, member.name.text];
|
|
168
|
+
const child = this.resolveTypeNode(member.type, member.type.getText(), fieldPath, stack, fieldIdentityParts);
|
|
169
|
+
return {
|
|
170
|
+
name: member.name.text,
|
|
171
|
+
optional: !!member.questionToken,
|
|
172
|
+
typeText: member.type.getText(),
|
|
173
|
+
path: fieldPath,
|
|
174
|
+
typeIdentityKey: child.typeIdentityKey,
|
|
175
|
+
cppNameHintParts: child.cppNameHintParts,
|
|
176
|
+
reconstructionKey: member.name.text,
|
|
177
|
+
node: child
|
|
178
|
+
};
|
|
179
|
+
});
|
|
180
|
+
return {
|
|
181
|
+
nodeKind: "struct",
|
|
182
|
+
...this.nodeMeta(typeText, path, identityParts),
|
|
183
|
+
fields,
|
|
184
|
+
reconstruction: "object"
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
resolveNamedReference(name, decl) {
|
|
188
|
+
const existing = this.namedNodes.get(name);
|
|
189
|
+
if (existing) {
|
|
190
|
+
return existing;
|
|
191
|
+
}
|
|
192
|
+
const placeholder = {
|
|
193
|
+
nodeKind: "named",
|
|
194
|
+
...this.nodeMeta(name, [name], [name]),
|
|
195
|
+
name,
|
|
196
|
+
target: null
|
|
197
|
+
};
|
|
198
|
+
this.namedNodes.set(name, placeholder);
|
|
199
|
+
placeholder.target = typescript_1.default.isInterfaceDeclaration(decl)
|
|
200
|
+
? this.createStructAnalysis(name, [name], decl.members, [name], [name])
|
|
201
|
+
: this.resolveTypeNode(decl.type, name, [name], [name], [name]);
|
|
202
|
+
return placeholder;
|
|
203
|
+
}
|
|
204
|
+
resolveTypeNode(node, typeText, path, stack, identityParts) {
|
|
205
|
+
if (typescript_1.default.isParenthesizedTypeNode(node)) {
|
|
206
|
+
return this.resolveTypeNode(node.type, typeText, path, stack, identityParts);
|
|
207
|
+
}
|
|
208
|
+
if (typescript_1.default.isTypeLiteralNode(node)) {
|
|
209
|
+
return this.createStructAnalysis(typeText, path, node.members, stack, identityParts);
|
|
210
|
+
}
|
|
211
|
+
if (typescript_1.default.isArrayTypeNode(node)) {
|
|
212
|
+
return {
|
|
213
|
+
nodeKind: "array",
|
|
214
|
+
...this.nodeMeta(typeText, path, identityParts),
|
|
215
|
+
elementTypeText: node.elementType.getText(),
|
|
216
|
+
element: this.resolveTypeNode(node.elementType, node.elementType.getText(), [...path, "Item"], stack, [...identityParts, "Item"]),
|
|
217
|
+
requiresCountMetadata: true,
|
|
218
|
+
reconstruction: "array"
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
if (typescript_1.default.isTupleTypeNode(node)) {
|
|
222
|
+
unsupported(path, typeText, "tuple transport is not supported by the whole-boundary planner");
|
|
223
|
+
}
|
|
224
|
+
if (typescript_1.default.isLiteralTypeNode(node)) {
|
|
225
|
+
if (typescript_1.default.isStringLiteral(node.literal)) {
|
|
226
|
+
return this.createFiniteDomainAnalysis(typeText, path, identityParts, buildFiniteDomain("string", [node.literal.text]));
|
|
227
|
+
}
|
|
228
|
+
if (typescript_1.default.isNumericLiteral(node.literal)) {
|
|
229
|
+
return this.createFiniteDomainAnalysis(typeText, path, identityParts, buildFiniteDomain("number", [Number(node.literal.text)]));
|
|
230
|
+
}
|
|
231
|
+
if (node.literal.kind === typescript_1.default.SyntaxKind.TrueKeyword || node.literal.kind === typescript_1.default.SyntaxKind.FalseKeyword) {
|
|
232
|
+
return this.createFiniteDomainAnalysis(typeText, path, identityParts, buildFiniteDomain("boolean", [node.literal.kind === typescript_1.default.SyntaxKind.TrueKeyword]));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (typescript_1.default.isUnionTypeNode(node)) {
|
|
236
|
+
const filtered = filterNullishUnionParts(node.types);
|
|
237
|
+
if (filtered.length !== node.types.length) {
|
|
238
|
+
unsupported(path, typeText, "nullish unions are not supported; use explicit optional members instead");
|
|
239
|
+
}
|
|
240
|
+
const finiteStringVariants = collectFiniteStringLiterals(node);
|
|
241
|
+
if (finiteStringVariants) {
|
|
242
|
+
return this.createFiniteDomainAnalysis(typeText, path, identityParts, buildFiniteDomain("string", finiteStringVariants));
|
|
243
|
+
}
|
|
244
|
+
const finiteBooleanVariants = collectFiniteBooleanLiterals(node);
|
|
245
|
+
if (finiteBooleanVariants) {
|
|
246
|
+
return this.createFiniteDomainAnalysis(typeText, path, identityParts, buildFiniteDomain("boolean", finiteBooleanVariants));
|
|
247
|
+
}
|
|
248
|
+
const finiteNumberVariants = collectFiniteNumberLiterals(node);
|
|
249
|
+
if (finiteNumberVariants) {
|
|
250
|
+
return this.createFiniteDomainAnalysis(typeText, path, identityParts, buildFiniteDomain("number", finiteNumberVariants));
|
|
251
|
+
}
|
|
252
|
+
if (isStringLikeUnion(node)) {
|
|
253
|
+
return {
|
|
254
|
+
nodeKind: "leaf",
|
|
255
|
+
...this.nodeMeta(typeText, path, identityParts),
|
|
256
|
+
leaf: (0, boundary_codec_leaves_1.resolveLeafCapability)("string", "string"),
|
|
257
|
+
fixedWidth: false
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
if (isBooleanLikeUnion(node)) {
|
|
261
|
+
return {
|
|
262
|
+
nodeKind: "leaf",
|
|
263
|
+
...this.nodeMeta(typeText, path, identityParts),
|
|
264
|
+
leaf: (0, boundary_codec_leaves_1.resolveLeafCapability)("boolean", "boolean"),
|
|
265
|
+
fixedWidth: true
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
if (isNumberLikeUnion(node)) {
|
|
269
|
+
return {
|
|
270
|
+
nodeKind: "leaf",
|
|
271
|
+
...this.nodeMeta(typeText, path, identityParts),
|
|
272
|
+
leaf: (0, boundary_codec_leaves_1.resolveLeafCapability)("number", "number"),
|
|
273
|
+
fixedWidth: true
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
unsupported(path, typeText, "union transport is only supported for string, boolean, or number-like unions");
|
|
277
|
+
}
|
|
278
|
+
if (typescript_1.default.isTypeReferenceNode(node)) {
|
|
279
|
+
const name = (0, boundary_codec_model_1.qNameText)(node.typeName);
|
|
280
|
+
const rawText = node.getText();
|
|
281
|
+
if (name === "Array" || name === "ReadonlyArray") {
|
|
282
|
+
const arg = node.typeArguments?.[0];
|
|
283
|
+
if (!arg) {
|
|
284
|
+
unsupported(path, rawText, "array type is missing its element type");
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
nodeKind: "array",
|
|
288
|
+
...this.nodeMeta(typeText, path, identityParts),
|
|
289
|
+
elementTypeText: arg.getText(),
|
|
290
|
+
element: this.resolveTypeNode(arg, arg.getText(), [...path, "Item"], stack, [...identityParts, "Item"]),
|
|
291
|
+
requiresCountMetadata: true,
|
|
292
|
+
reconstruction: "array"
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
if (name === "Record" || name === "Map") {
|
|
296
|
+
const leaf = (0, boundary_codec_leaves_1.resolveLeafCapability)("object", "object");
|
|
297
|
+
return {
|
|
298
|
+
nodeKind: "leaf",
|
|
299
|
+
...this.nodeMeta(typeText, path, identityParts),
|
|
300
|
+
leaf: leaf,
|
|
301
|
+
fixedWidth: false
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
if (name === "Partial") {
|
|
305
|
+
unsupported(path, rawText, "generic Partial<T> transport is not supported");
|
|
306
|
+
}
|
|
307
|
+
if (name === "Promise") {
|
|
308
|
+
unsupported(path, rawText, "Promise transport is not supported");
|
|
309
|
+
}
|
|
310
|
+
if (rawText.trim() === "AnQst.Type.stringArray") {
|
|
311
|
+
const leaf = (0, boundary_codec_leaves_1.resolveLeafCapability)("string", "string");
|
|
312
|
+
return {
|
|
313
|
+
nodeKind: "array",
|
|
314
|
+
...this.nodeMeta(typeText, path, identityParts),
|
|
315
|
+
elementTypeText: "string",
|
|
316
|
+
element: {
|
|
317
|
+
nodeKind: "leaf",
|
|
318
|
+
...this.nodeMeta("string", [...path, "Item"], [...identityParts, "Item"]),
|
|
319
|
+
leaf: leaf,
|
|
320
|
+
fixedWidth: false
|
|
321
|
+
},
|
|
322
|
+
requiresCountMetadata: true,
|
|
323
|
+
reconstruction: "array"
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
const leaf = (0, boundary_codec_leaves_1.resolveLeafCapability)(rawText, name);
|
|
327
|
+
if (leaf) {
|
|
328
|
+
return {
|
|
329
|
+
nodeKind: "leaf",
|
|
330
|
+
...this.nodeMeta(typeText, path, identityParts),
|
|
331
|
+
leaf,
|
|
332
|
+
fixedWidth: leaf.fixedByteWidth !== null
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
const decl = this.declNodes.get(name);
|
|
336
|
+
if (decl) {
|
|
337
|
+
return this.resolveNamedReference(name, decl);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
switch (node.kind) {
|
|
341
|
+
case typescript_1.default.SyntaxKind.StringKeyword:
|
|
342
|
+
return {
|
|
343
|
+
nodeKind: "leaf",
|
|
344
|
+
...this.nodeMeta(typeText, path, identityParts),
|
|
345
|
+
leaf: (0, boundary_codec_leaves_1.resolveLeafCapability)("string", "string"),
|
|
346
|
+
fixedWidth: false
|
|
347
|
+
};
|
|
348
|
+
case typescript_1.default.SyntaxKind.BooleanKeyword:
|
|
349
|
+
return {
|
|
350
|
+
nodeKind: "leaf",
|
|
351
|
+
...this.nodeMeta(typeText, path, identityParts),
|
|
352
|
+
leaf: (0, boundary_codec_leaves_1.resolveLeafCapability)("boolean", "boolean"),
|
|
353
|
+
fixedWidth: true
|
|
354
|
+
};
|
|
355
|
+
case typescript_1.default.SyntaxKind.NumberKeyword:
|
|
356
|
+
return {
|
|
357
|
+
nodeKind: "leaf",
|
|
358
|
+
...this.nodeMeta(typeText, path, identityParts),
|
|
359
|
+
leaf: (0, boundary_codec_leaves_1.resolveLeafCapability)("number", "number"),
|
|
360
|
+
fixedWidth: true
|
|
361
|
+
};
|
|
362
|
+
case typescript_1.default.SyntaxKind.BigIntKeyword:
|
|
363
|
+
return {
|
|
364
|
+
nodeKind: "leaf",
|
|
365
|
+
...this.nodeMeta(typeText, path, identityParts),
|
|
366
|
+
leaf: (0, boundary_codec_leaves_1.resolveLeafCapability)("bigint", "bigint"),
|
|
367
|
+
fixedWidth: true
|
|
368
|
+
};
|
|
369
|
+
case typescript_1.default.SyntaxKind.ObjectKeyword:
|
|
370
|
+
return {
|
|
371
|
+
nodeKind: "leaf",
|
|
372
|
+
...this.nodeMeta(typeText, path, identityParts),
|
|
373
|
+
leaf: (0, boundary_codec_leaves_1.resolveLeafCapability)("object", "object"),
|
|
374
|
+
fixedWidth: false
|
|
375
|
+
};
|
|
376
|
+
default:
|
|
377
|
+
unsupported(path, typeText, "no transport analysis rule exists for this type");
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
exports.BoundaryTransportAnalyzer = BoundaryTransportAnalyzer;
|
|
382
|
+
function summarizeAnalysis(node) {
|
|
383
|
+
const used = new Set();
|
|
384
|
+
const visitedNamed = new Set();
|
|
385
|
+
const visit = (current) => {
|
|
386
|
+
switch (current.nodeKind) {
|
|
387
|
+
case "leaf":
|
|
388
|
+
used.add(current.leaf.key);
|
|
389
|
+
return {
|
|
390
|
+
hasBlobLeaves: current.leaf.region === "blob",
|
|
391
|
+
hasStringLeaves: current.leaf.region === "string",
|
|
392
|
+
hasBinaryLeaves: current.leaf.region === "binary",
|
|
393
|
+
hasDynamicLeaves: current.leaf.region === "dynamic",
|
|
394
|
+
hasRepeatedStructures: false,
|
|
395
|
+
hasOptionalPresence: false,
|
|
396
|
+
hasFiniteDomains: false,
|
|
397
|
+
usedLeafCapabilities: []
|
|
398
|
+
};
|
|
399
|
+
case "named":
|
|
400
|
+
if (visitedNamed.has(current.name)) {
|
|
401
|
+
return {
|
|
402
|
+
hasBlobLeaves: false,
|
|
403
|
+
hasStringLeaves: false,
|
|
404
|
+
hasBinaryLeaves: false,
|
|
405
|
+
hasDynamicLeaves: false,
|
|
406
|
+
hasRepeatedStructures: false,
|
|
407
|
+
hasOptionalPresence: false,
|
|
408
|
+
hasFiniteDomains: false,
|
|
409
|
+
usedLeafCapabilities: []
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
visitedNamed.add(current.name);
|
|
413
|
+
return visit(current.target);
|
|
414
|
+
case "finite-domain":
|
|
415
|
+
return {
|
|
416
|
+
hasBlobLeaves: false,
|
|
417
|
+
hasStringLeaves: false,
|
|
418
|
+
hasBinaryLeaves: false,
|
|
419
|
+
hasDynamicLeaves: false,
|
|
420
|
+
hasRepeatedStructures: false,
|
|
421
|
+
hasOptionalPresence: false,
|
|
422
|
+
hasFiniteDomains: true,
|
|
423
|
+
usedLeafCapabilities: []
|
|
424
|
+
};
|
|
425
|
+
case "array": {
|
|
426
|
+
const inner = visit(current.element);
|
|
427
|
+
return {
|
|
428
|
+
hasBlobLeaves: inner.hasBlobLeaves,
|
|
429
|
+
hasStringLeaves: inner.hasStringLeaves,
|
|
430
|
+
hasBinaryLeaves: inner.hasBinaryLeaves,
|
|
431
|
+
hasDynamicLeaves: inner.hasDynamicLeaves,
|
|
432
|
+
hasRepeatedStructures: true,
|
|
433
|
+
hasOptionalPresence: inner.hasOptionalPresence,
|
|
434
|
+
hasFiniteDomains: inner.hasFiniteDomains,
|
|
435
|
+
usedLeafCapabilities: []
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
case "struct":
|
|
439
|
+
return current.fields.reduce((acc, field) => {
|
|
440
|
+
const next = visit(field.node);
|
|
441
|
+
return {
|
|
442
|
+
hasBlobLeaves: acc.hasBlobLeaves || next.hasBlobLeaves,
|
|
443
|
+
hasStringLeaves: acc.hasStringLeaves || next.hasStringLeaves,
|
|
444
|
+
hasBinaryLeaves: acc.hasBinaryLeaves || next.hasBinaryLeaves,
|
|
445
|
+
hasDynamicLeaves: acc.hasDynamicLeaves || next.hasDynamicLeaves,
|
|
446
|
+
hasRepeatedStructures: acc.hasRepeatedStructures || next.hasRepeatedStructures,
|
|
447
|
+
hasOptionalPresence: acc.hasOptionalPresence || field.optional || next.hasOptionalPresence,
|
|
448
|
+
hasFiniteDomains: acc.hasFiniteDomains || next.hasFiniteDomains,
|
|
449
|
+
usedLeafCapabilities: []
|
|
450
|
+
};
|
|
451
|
+
}, {
|
|
452
|
+
hasBlobLeaves: false,
|
|
453
|
+
hasStringLeaves: false,
|
|
454
|
+
hasBinaryLeaves: false,
|
|
455
|
+
hasDynamicLeaves: false,
|
|
456
|
+
hasRepeatedStructures: false,
|
|
457
|
+
hasOptionalPresence: false,
|
|
458
|
+
hasFiniteDomains: false,
|
|
459
|
+
usedLeafCapabilities: []
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
const summary = visit(node);
|
|
464
|
+
return {
|
|
465
|
+
...summary,
|
|
466
|
+
usedLeafCapabilities: [...used]
|
|
467
|
+
};
|
|
468
|
+
}
|