@rocketmq/protobuf 0.1.0
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/.turbo/turbo-build.log +21 -0
- package/dist/index.cjs +48 -0
- package/dist/index.d.cts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +21 -0
- package/package.json +18 -0
- package/src/generator.test.ts +91 -0
- package/src/generator.ts +47 -0
- package/src/index.ts +1 -0
- package/tsconfig.json +8 -0
- package/tsup.config.ts +8 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @rocketmq/protobuf@0.1.0 build /home/edilson/learnspace/rocketmq-broker/client-ts/packages/protobuf
|
|
4
|
+
> tsup
|
|
5
|
+
|
|
6
|
+
CLI Building entry: src/index.ts
|
|
7
|
+
CLI Using tsconfig: tsconfig.json
|
|
8
|
+
CLI tsup v8.5.1
|
|
9
|
+
CLI Using tsup config: /home/edilson/learnspace/rocketmq-broker/client-ts/packages/protobuf/tsup.config.ts
|
|
10
|
+
CLI Target: es2022
|
|
11
|
+
CLI Cleaning output folder
|
|
12
|
+
ESM Build start
|
|
13
|
+
CJS Build start
|
|
14
|
+
CJS dist/index.cjs 1.65 KB
|
|
15
|
+
CJS ⚡️ Build success in 10ms
|
|
16
|
+
ESM dist/index.js 645.00 B
|
|
17
|
+
ESM ⚡️ Build success in 10ms
|
|
18
|
+
DTS Build start
|
|
19
|
+
DTS ⚡️ Build success in 896ms
|
|
20
|
+
DTS dist/index.d.ts 581.00 B
|
|
21
|
+
DTS dist/index.d.cts 581.00 B
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
toProto: () => toProto
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
|
|
27
|
+
// src/generator.ts
|
|
28
|
+
var import_schema = require("@rocketmq/schema");
|
|
29
|
+
function ensureFieldsRegistered(schema) {
|
|
30
|
+
if (import_schema.defaultRegistry.getFields(schema).length > 0) return;
|
|
31
|
+
try {
|
|
32
|
+
new schema();
|
|
33
|
+
} catch {
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function toProto(schema) {
|
|
37
|
+
ensureFieldsRegistered(schema);
|
|
38
|
+
const fields = import_schema.defaultRegistry.getFields(schema);
|
|
39
|
+
if (fields.length === 0) {
|
|
40
|
+
throw new Error(`Schema '${schema.name}' has no @Field() decorators \u2014 cannot generate proto`);
|
|
41
|
+
}
|
|
42
|
+
const body = fields.map((f) => `${f.protoType} ${f.name} = ${f.number};`).join(" ");
|
|
43
|
+
return `syntax = "proto3"; message ${schema.name} { ${body} }`;
|
|
44
|
+
}
|
|
45
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
46
|
+
0 && (module.exports = {
|
|
47
|
+
toProto
|
|
48
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a proto3 schema string from a decorated class.
|
|
3
|
+
*
|
|
4
|
+
* Reads field metadata from the default SchemaRegistry and produces
|
|
5
|
+
* the exact format the Rust broker expects in the `x-schema` queue argument.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const proto = toProto(NotificationClass);
|
|
9
|
+
* // => 'syntax = "proto3"; message Notification { string id = 1; int64 timestamp = 2; }'
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Converts a decorated schema class to a proto3 definition string.
|
|
13
|
+
*
|
|
14
|
+
* @throws Error if the class has no @Field() decorators.
|
|
15
|
+
*/
|
|
16
|
+
declare function toProto(schema: Function): string;
|
|
17
|
+
|
|
18
|
+
export { toProto };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a proto3 schema string from a decorated class.
|
|
3
|
+
*
|
|
4
|
+
* Reads field metadata from the default SchemaRegistry and produces
|
|
5
|
+
* the exact format the Rust broker expects in the `x-schema` queue argument.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const proto = toProto(NotificationClass);
|
|
9
|
+
* // => 'syntax = "proto3"; message Notification { string id = 1; int64 timestamp = 2; }'
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Converts a decorated schema class to a proto3 definition string.
|
|
13
|
+
*
|
|
14
|
+
* @throws Error if the class has no @Field() decorators.
|
|
15
|
+
*/
|
|
16
|
+
declare function toProto(schema: Function): string;
|
|
17
|
+
|
|
18
|
+
export { toProto };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// src/generator.ts
|
|
2
|
+
import { defaultRegistry } from "@rocketmq/schema";
|
|
3
|
+
function ensureFieldsRegistered(schema) {
|
|
4
|
+
if (defaultRegistry.getFields(schema).length > 0) return;
|
|
5
|
+
try {
|
|
6
|
+
new schema();
|
|
7
|
+
} catch {
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function toProto(schema) {
|
|
11
|
+
ensureFieldsRegistered(schema);
|
|
12
|
+
const fields = defaultRegistry.getFields(schema);
|
|
13
|
+
if (fields.length === 0) {
|
|
14
|
+
throw new Error(`Schema '${schema.name}' has no @Field() decorators \u2014 cannot generate proto`);
|
|
15
|
+
}
|
|
16
|
+
const body = fields.map((f) => `${f.protoType} ${f.name} = ${f.number};`).join(" ");
|
|
17
|
+
return `syntax = "proto3"; message ${schema.name} { ${body} }`;
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
toProto
|
|
21
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rocketmq/protobuf",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"import": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@rocketmq/schema": "0.1.0"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsup",
|
|
16
|
+
"test": "vitest run"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for toProto() — proto3 string generation.
|
|
3
|
+
*
|
|
4
|
+
* Covers: valid schemas, empty schemas (error), multi-field ordering,
|
|
5
|
+
* and the force-instantiation path for uninitialized classes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect } from 'vitest';
|
|
9
|
+
import { toProto } from './generator.js';
|
|
10
|
+
import { Schema, Field, defaultRegistry } from '@rocketmq/schema';
|
|
11
|
+
|
|
12
|
+
describe('toProto', () => {
|
|
13
|
+
it('generates proto3 string for a single-field class', () => {
|
|
14
|
+
@Schema()
|
|
15
|
+
class SingleField {
|
|
16
|
+
@Field()
|
|
17
|
+
id!: string;
|
|
18
|
+
}
|
|
19
|
+
new SingleField();
|
|
20
|
+
|
|
21
|
+
const proto = toProto(SingleField);
|
|
22
|
+
expect(proto).toBe('syntax = "proto3"; message SingleField { string id = 1; }');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('generates proto3 with multiple fields in order', () => {
|
|
26
|
+
@Schema()
|
|
27
|
+
class MultiField {
|
|
28
|
+
@Field()
|
|
29
|
+
name!: string;
|
|
30
|
+
|
|
31
|
+
@Field({ type: 'int32' })
|
|
32
|
+
age!: number;
|
|
33
|
+
|
|
34
|
+
@Field({ type: 'bool' })
|
|
35
|
+
active!: boolean;
|
|
36
|
+
}
|
|
37
|
+
new MultiField();
|
|
38
|
+
|
|
39
|
+
const proto = toProto(MultiField);
|
|
40
|
+
expect(proto).toBe(
|
|
41
|
+
'syntax = "proto3"; message MultiField { string name = 1; int32 age = 2; bool active = 3; }',
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('throws for class with no @Field() decorators', () => {
|
|
46
|
+
@Schema()
|
|
47
|
+
class NoFields {}
|
|
48
|
+
|
|
49
|
+
expect(() => toProto(NoFields)).toThrow(
|
|
50
|
+
"Schema 'NoFields' has no @Field() decorators — cannot generate proto",
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('forces instantiation when fields are not yet registered', () => {
|
|
55
|
+
// Simulate a class that hasn't been instantiated yet
|
|
56
|
+
@Schema()
|
|
57
|
+
class LazyInit {
|
|
58
|
+
@Field()
|
|
59
|
+
value!: string;
|
|
60
|
+
}
|
|
61
|
+
// Do NOT call `new LazyInit()` — toProto should do it internally
|
|
62
|
+
const proto = toProto(LazyInit);
|
|
63
|
+
expect(proto).toContain('string value = 1');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('handles class whose constructor throws', () => {
|
|
67
|
+
// WHY: toProto wraps instantiation in try/catch for classes
|
|
68
|
+
// that require constructor arguments
|
|
69
|
+
class ThrowingCtor {
|
|
70
|
+
@Field()
|
|
71
|
+
x!: string;
|
|
72
|
+
|
|
73
|
+
constructor() {
|
|
74
|
+
// Fields registered via addInitializer before the throw
|
|
75
|
+
throw new Error('required args');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Force-register the field store entry
|
|
79
|
+
defaultRegistry.getOrCreateFields(ThrowingCtor);
|
|
80
|
+
|
|
81
|
+
// toProto will try `new ThrowingCtor()`, catch, and check fields
|
|
82
|
+
// Since addInitializer runs before constructor body, field might be registered
|
|
83
|
+
// If not, it should throw "no @Field() decorators"
|
|
84
|
+
try {
|
|
85
|
+
const proto = toProto(ThrowingCtor);
|
|
86
|
+
expect(proto).toContain('string x = 1');
|
|
87
|
+
} catch (err) {
|
|
88
|
+
expect((err as Error).message).toContain('no @Field() decorators');
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
});
|
package/src/generator.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a proto3 schema string from a decorated class.
|
|
3
|
+
*
|
|
4
|
+
* Reads field metadata from the default SchemaRegistry and produces
|
|
5
|
+
* the exact format the Rust broker expects in the `x-schema` queue argument.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const proto = toProto(NotificationClass);
|
|
9
|
+
* // => 'syntax = "proto3"; message Notification { string id = 1; int64 timestamp = 2; }'
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { defaultRegistry } from '@rocketmq/schema';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Forces field registration by instantiating the class once.
|
|
16
|
+
*
|
|
17
|
+
* TC39 field decorators defer registration via `addInitializer`,
|
|
18
|
+
* which only runs on construction. If no instance exists yet,
|
|
19
|
+
* the registry will have zero fields for the class.
|
|
20
|
+
*/
|
|
21
|
+
function ensureFieldsRegistered(schema: Function): void {
|
|
22
|
+
if (defaultRegistry.getFields(schema).length > 0) return;
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
new (schema as new () => unknown)();
|
|
26
|
+
} catch {
|
|
27
|
+
// Constructor may throw — fields are registered via addInitializer
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Converts a decorated schema class to a proto3 definition string.
|
|
33
|
+
*
|
|
34
|
+
* @throws Error if the class has no @Field() decorators.
|
|
35
|
+
*/
|
|
36
|
+
export function toProto(schema: Function): string {
|
|
37
|
+
ensureFieldsRegistered(schema);
|
|
38
|
+
|
|
39
|
+
const fields = defaultRegistry.getFields(schema);
|
|
40
|
+
if (fields.length === 0) {
|
|
41
|
+
throw new Error(`Schema '${schema.name}' has no @Field() decorators — cannot generate proto`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const body = fields.map((f) => `${f.protoType} ${f.name} = ${f.number};`).join(' ');
|
|
45
|
+
|
|
46
|
+
return `syntax = "proto3"; message ${schema.name} { ${body} }`;
|
|
47
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { toProto } from './generator.js';
|
package/tsconfig.json
ADDED