diff --git a/.github/workflows/js.yml b/.github/workflows/js.yml index a4c94e89..16ed872f 100644 --- a/.github/workflows/js.yml +++ b/.github/workflows/js.yml @@ -8,7 +8,6 @@ on: jobs: build: - if: false # disable the entire workflow runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 diff --git a/messgen/json_generator.py b/messgen/json_generator.py index a1e3fb09..c2e67e6c 100644 --- a/messgen/json_generator.py +++ b/messgen/json_generator.py @@ -1,10 +1,8 @@ import json -import os from dataclasses import asdict from pathlib import Path -from .common import write_file_if_diff from .protocol_version import version_hash from .validation import validate_protocol @@ -31,17 +29,27 @@ def validate(self, types: dict[str, MessgenType], protocols: dict[str, Protocol] validate_protocol(proto_def, types) def generate_types(self, out_dir: Path, types: dict[str, MessgenType]) -> None: - for type_name, type_def in types.items(): - if type_def.type_class not in [TypeClass.struct, TypeClass.enum]: - continue - file_name = out_dir / (type_name + self._FILE_EXT) - file_name.parent.mkdir(parents=True, exist_ok=True) - write_file_if_diff(file_name, json.dumps(asdict(type_def), indent=2).splitlines()) + combined: list = [] + + for type_def in types.values(): + if type_def.type_class in [TypeClass.struct, TypeClass.enum]: + combined.append(asdict(type_def)) + + self._write_file(out_dir, "types", combined) def generate_protocols(self, out_dir: Path, protocols: dict[str, Protocol]) -> None: - for proto_name, proto_def in protocols.items(): - file_name = out_dir / (proto_name + self._FILE_EXT) - file_name.parent.mkdir(parents=True, exist_ok=True) + combined: list = [] + + for proto_def in protocols.values(): proto_dict = asdict(proto_def) proto_dict["version"] = version_hash(proto_dict) - write_file_if_diff(file_name, json.dumps(asdict(proto_def), indent=2).splitlines()) + combined.append(proto_dict) + + self._write_file(out_dir, "protocols", combined) + + def _write_file(self, out_dir: Path, name: str, data: list) -> None: + file_name = out_dir / (name + self._FILE_EXT) + file_name.parent.mkdir(parents=True, exist_ok=True) + + with open(file_name, "w", encoding="utf-8") as f: json.dump(data, f, indent=2) + diff --git a/messgen/ts_generator.py b/messgen/ts_generator.py index e26f3299..3452bb70 100644 --- a/messgen/ts_generator.py +++ b/messgen/ts_generator.py @@ -1,9 +1,14 @@ import os -from typing import Dict, Set, List, Tuple from .common import SEPARATOR +from pathlib import Path -class Protocols: # fake - pass +from .validation import validate_protocol + +from .model import ( + MessgenType, + Protocol, + TypeClass, +) class TypeScriptTypes: TYPE_MAP = { @@ -45,230 +50,118 @@ def get_typed_array(cls, type_name): return cls.TYPED_ARRAY_MAP.get(type_name, None) class TypeScriptGenerator: - _protocols: Protocols - _options: dict + _TYPES_FILE = "types.ts" + _PROTOCOLS_FILE = "protocols.ts" def __init__(self, options): - self._protocols = None # FIXME: - self._reset_state() self._options = options - - def _reset_state(self) -> None: - self.generated_types: Dict[Tuple[str, str], bool] = {} - self.imports: Set[Tuple[str, str]] = set() - self.code_lines: List[str] = [] - - def generate(self, out_dir, proto_name, proto) -> None: - self._reset_state() - - types = proto.get("types", {}) - proto_comment = proto.get("comment", "") - proto_version = proto.get("version", "") - proto_name = proto.get("proto_name", proto_name) - - output_path = self._create_output_dirs(out_dir, proto_name) - - for type_name in types: - self._generate_type(proto_name, type_name, types) - - self._generate_types_map(proto_name, types) - - code = self._generate_file_content( - proto_name=proto_name, - proto_comment=proto_comment, - proto_version=proto_version, - out_dir=out_dir, - output_path=output_path - ) - - self._write_output_file(output_path, proto_name, code) - - def _create_output_dirs(self, out_dir, proto_name): - output_path = os.path.join(out_dir, proto_name.replace(SEPARATOR, os.sep)) - os.makedirs(output_path, exist_ok=True) - return output_path - - def _generate_file_content(self, proto_name, proto_comment, proto_version, out_dir, output_path): - header_lines = ['// === AUTO GENERATED CODE ==='] - if proto_comment: - header_lines.append(f'// {proto_comment}') - header_lines.append(f'// Protocol: {proto_name}') - - if proto_version: - header_lines.append(f'// Version: {proto_version}') - header_lines.append('') - - import_lines = [] - if self.imports: - import_lines = self._generate_imports(out_dir, output_path) - import_lines.append('') - - code_lines = header_lines + import_lines + self.code_lines - - return '\n'.join(code_lines) - - - def _generate_type(self, proto_name, type_name, types) -> None: - if (proto_name, type_name) in self.generated_types: - return - self.generated_types[(proto_name, type_name)] = True - - type_def = types[type_name] - type_class = type_def.get("type_class") - comment = type_def.get("comment", "") - interface_name = self._to_camel_case(type_name) - - self._handle_type_dependencies(type_def, type_class, proto_name) - self._generate_type_definition( - type_class=type_class, - interface_name=interface_name, - type_def=type_def, - comment=comment - ) - - def _handle_type_dependencies(self, type_def, type_class, proto_name): - if type_class == "struct": - fields = type_def.get("fields") or [] - - for field in fields: - field_type = field["type"] - base_types = self._extract_all_base_types(field_type) - for base_type in base_types: - if not self._is_builtin_type(base_type): - self._handle_custom_type(base_type, proto_name) - - def _generate_type_definition(self, type_class, interface_name, type_def, comment): - if comment: - self.code_lines.append(f"/** {comment} */") - if type_class == "struct": - self._generate_interface(interface_name, type_def) - elif type_class == "enum": - self._generate_enum(interface_name, type_def) - - def _generate_interface(self, interface_name, type_def): - self.code_lines.append(f"export interface {interface_name} {{") - fields = type_def.get("fields") or [] - - for field in fields: - if field.get("comment"): - self.code_lines.append(f" /** {field['comment']} */") - - field_name = field["name"] - field_type = self._get_ts_type(field["type"], type_def.get("proto_name", "")) - self.code_lines.append(f" {field_name}: {field_type};") - - self.code_lines.append("}") - self.code_lines.append("") + self._types = [] + + + def generate(self, out_dir: Path, types: dict[str, MessgenType], protocols: dict[str, Protocol]) -> None: + self.validate(types, protocols) + self.generate_types(out_dir, types) + self.generate_protocols(out_dir, protocols) + + def validate(self, types: dict[str, MessgenType], protocols: dict[str, Protocol]): + for proto_def in protocols.values(): + validate_protocol(proto_def, types) + + def generate_protocols(self, out_dir: Path, protocols: dict[str, Protocol]) -> None: + types = set() + code = [] + + for proto_name, proto_def in protocols.items(): + code.append(f"export interface {self._to_camel_case(proto_name)} {{") + code.append(f" '{proto_name}': {{") + for struct_name in proto_def.types.values(): + ts_struct_name = self._to_camel_case(struct_name) + code.append(f" '{struct_name}': {ts_struct_name};") + types.add(ts_struct_name) + code.append(' }') + code.append('}') + code.append('') + + import_statements = self._generate_protocol_imports(types) + protocol_types = ' | '.join(self._to_camel_case(proto_name) for proto_name in protocols.keys()) + final_code = '\n'.join(import_statements + code) + f'export type Protocol = {protocol_types};' + + + self._write_output_file(out_dir, self._PROTOCOLS_FILE, final_code) + + def _generate_protocol_imports(self, types: set[str]) -> list[str]: + import_statements = ["import type {"] + for struct_name in types: + import_statements.append(f" {struct_name},") + import_statements.append("} from './types';") + import_statements.append('') + return import_statements + + def generate_types(self, out_dir: Path, types: dict[str, MessgenType]) -> None: + self._types.clear() + + for type_name, type_def in types.items(): + if type_def.type_class == TypeClass.struct: + self._generate_struct(type_name, type_def) + elif type_def.type_class == TypeClass.enum: + self._generate_enum(type_name, type_def) + + code = '\n'.join(self._types) + + self._write_output_file(out_dir, self._TYPES_FILE, code) def _generate_enum(self, enum_name, type_def): - self.code_lines.append(f"export enum {enum_name} {{") - - for value in type_def.get("values", []): - if value.get("comment"): - self.code_lines.append(f" /** {value['comment']} */") - value_name = self._to_camel_case(value['name']) - self.code_lines.append(f" {value_name} = {value['value']},") - - self.code_lines.append("}") - self.code_lines.append("") - - def _write_output_file(self, output_path, proto_name, content): - output_file = os.path.join( - output_path, - f"{proto_name.split(SEPARATOR)[-1]}.ts" - ) - with open(output_file, 'w', encoding='utf-8') as f: - f.write(content) - - def _calculate_import_path(self, out_dir, output_path, proto_name): - output_dir = os.path.dirname(output_path) - proto_dir = os.path.join(out_dir, proto_name.replace(SEPARATOR, os.sep)) - proto_dir = os.path.dirname(proto_dir) - imported_file_name = proto_name.split(SEPARATOR)[-1] - import_path = '../' + self._types.append(f"export enum {self._to_camel_case(enum_name)} {{") - if proto_dir in output_dir: - import_path += proto_name.split(SEPARATOR)[-1] - else: - import_path += proto_name.replace(SEPARATOR, '/') + for value in type_def.values or []: + if value.comment != None: + self._types.append(f" /** {value.comment} */") + value_name = self._to_camel_case(value.name) + self._types.append(f" {value_name} = {value.value},") - return f"{import_path}/{imported_file_name}".replace(SEPARATOR, os.sep) - def calculate_import_path(self, out_dir, output_path, proto_name): - proto_filename = proto_name.split(SEPARATOR)[-1] - proto_dir = os.path.dirname(os.path.join(out_dir, proto_name.replace(SEPARATOR, os.sep))) - output_dir = os.path.dirname(output_path) + self._types.append("}") + self._types.append("") + + def _generate_struct(self, name: str, type_def: MessgenType): + self._types.append(f"export interface {self._to_camel_case(name)} {{") + fields = getattr(type_def, 'fields', []) or [] - relative_path = proto_filename if proto_dir in output_dir else proto_name.replace(SEPARATOR, '/') + for field in fields: + if field.comment != None: + self._types.append(f" /** {field.comment} */") - return os.path.join('..', relative_path, proto_filename) + field_name = field.name + field_type = self._get_ts_type(field.type) + self._types.append(f" {field_name}: {field_type};") - def _generate_imports(self, out_dir, output_path): - sorted_imports = sorted(self.imports) - return [ - f'import {{ {self._to_camel_case(type_name)} }} ' - f'from "{self._calculate_import_path(out_dir, output_path, proto_name)}";' - for proto_name, type_name in sorted_imports - ] + self._types.append("}") + self._types.append("") - def _get_ts_type(self, field_type, current_proto_name): + def _get_ts_type(self, field_type: str): typed_array_type = self._is_typed_array(field_type) if typed_array_type: return typed_array_type if field_type.endswith('[]'): base_type = field_type[:-2] - ts_base_type = self._get_ts_type(base_type, current_proto_name) + ts_base_type = self._get_ts_type(base_type) return f"{ts_base_type}[]" if '[' in field_type and field_type.endswith(']'): base_type = field_type[:field_type.find('[')] - ts_base_type = self._get_ts_type(base_type, current_proto_name) + ts_base_type = self._get_ts_type(base_type) return f"{ts_base_type}[]" if '{' in field_type and field_type.endswith('}'): base_type = field_type[:field_type.find('{')] key_type = field_type[field_type.find('{')+1:-1] - ts_value_type = self._get_ts_type(base_type, current_proto_name) - ts_key_type = self._get_ts_type(key_type, current_proto_name) + ts_value_type = self._get_ts_type(base_type) + ts_key_type = self._get_ts_type(key_type) return f"Map<{ts_key_type}, {ts_value_type}>" if field_type in TypeScriptTypes.TYPE_MAP: return TypeScriptTypes.get_type(field_type) - return self._handle_custom_type(field_type, current_proto_name) - - def _handle_custom_type(self, type_name, current_proto_name): - if SEPARATOR in type_name: - parts = type_name.split(SEPARATOR) - proto_name = SEPARATOR.join(parts[:-1]) - imported_type_name = parts[-1] - self.imports.add((proto_name, imported_type_name)) - return self._to_camel_case(imported_type_name) - else: - return self._to_camel_case(type_name) - - - def _extract_all_base_types(self, field_type) -> List[str]: - base_types = [] - stack = [field_type] - while stack: - current_type = stack.pop() - if current_type.endswith('[]'): - base_type = current_type[:-2] - stack.append(base_type) - elif '[' in current_type and current_type.endswith(']'): - base_type = current_type[:current_type.find('[')] - stack.append(base_type) - elif '{' in current_type and current_type.endswith('}'): - value_type = current_type[:current_type.find('{')] - key_type = current_type[current_type.find('{')+1:-1] - stack.append(value_type) - stack.append(key_type) - else: - base_types.append(current_type) - return base_types - - def _is_builtin_type(self, type_name): - return type_name in TypeScriptTypes.TYPE_MAP or type_name in TypeScriptTypes.TYPED_ARRAY_MAP + return self._to_camel_case(field_type) def _is_typed_array(self, field_type): if field_type.endswith('[]'): @@ -282,35 +175,16 @@ def _is_typed_array(self, field_type): if typed_array: return typed_array return None + + def _write_output_file(self, output_path, file, content): + output_file = os.path.join(output_path, f"{file}") - @staticmethod - def _to_camel_case(s): - return ''.join(word.capitalize() for word in s.split('_')) - - def _generate_types_map(self, proto_name, types): - interface_name = self._to_camel_case(proto_name.replace(SEPARATOR, '_') + '_types_map') - self.code_lines.append(f"export interface {interface_name} {{") - for type_name in sorted(types.keys()): - ts_type_name = self._to_camel_case(type_name) - self.code_lines.append(f' {type_name}: {ts_type_name};') - self.code_lines.append('}') - self.code_lines.append('') - - def generate_root_types_file(self, out_dir, proto_files): - root_file_path = os.path.join(out_dir, 'types.ts') - import_lines = [] - interface_names = [] + with open(output_file, 'w', encoding='utf-8') as f: + f.write(content) - for proto in proto_files: - proto_name = proto.get('proto_name') - module_path = proto_name.replace(SEPARATOR, '/') - interface_name = self._to_camel_case(proto_name.replace('/', '_') + '_types_map') - import_path = f'./{module_path}/{proto_name.split(SEPARATOR)[-1]}' - import_lines.append(f'import {{ {interface_name} }} from "{import_path}";') - interface_names.append(interface_name) + @staticmethod + def _to_camel_case(s: str): + name = '_'.join(s.split(SEPARATOR)) + return ''.join(word.capitalize() for word in name.split('_')) + - with open(root_file_path, 'w', encoding='utf-8') as f: - f.write('// === AUTO GENERATED CODE ===\n') - f.write('\n'.join(import_lines)) - f.write('\n\n') - f.write(f"type CommonProtocolTypeMap = {' & '.join(interface_names)};\n") diff --git a/port/js/benchmarks/perf-process/index.ts b/port/js/benchmarks/perf-process/index.ts index 8363c1e7..7c3f1d32 100644 --- a/port/js/benchmarks/perf-process/index.ts +++ b/port/js/benchmarks/perf-process/index.ts @@ -79,7 +79,7 @@ const srcDataFn = () => ({ }); const srcData = srcDataFn(); -const structConverter = new StructConverter('testStruct', schema, initGetType()); +const structConverter = new StructConverter(schema, initGetType()); const size = structConverter.size(srcData); const buffer = new Buffer(new ArrayBuffer(size)); diff --git a/port/js/package.json b/port/js/package.json index 1f240906..4faddc1f 100644 --- a/port/js/package.json +++ b/port/js/package.json @@ -6,10 +6,9 @@ "test": "vitest", "benchmark": "vitest bench", "coverage": "vitest run --coverage", - "gen": "python3 ../../messgen-generate.py --types ../../tests/data/types --protocol ../../tests/data/protocols/test_proto --protocol ../../tests/data/protocols/another_proto --outdir ./tests", + "gen": "python3 ../../messgen-generate.py --types ../../tests/data/types --protocol ../../tests/data/protocols:test_proto --protocol ../../tests/data/protocols:nested/another_proto --outdir ./tests", "gen:json": "npm run gen -- --lang json", - "gen:ts": "npm run gen-json && npm run gen -- --lang ts", - "gen:cpp": "npm run gen -- --lang cpp", + "gen:ts": "npm run gen:json && npm run gen -- --lang ts", "gen:md": "npm run gen -- --lang md", "generate-bit": "cd ../.. && python3 tests/python/generate_serialized_data.py", "check:lint": "eslint --ext .ts src", @@ -60,4 +59,4 @@ "dist", "src" ] -} \ No newline at end of file +} diff --git a/port/js/src/Codec.ts b/port/js/src/Codec.ts index 21ab8794..9c223c91 100644 --- a/port/js/src/Codec.ts +++ b/port/js/src/Codec.ts @@ -1,4 +1,4 @@ -import { type ProtocolJSON, Protocols } from './protocol'; +import { type RawType, type Protocol, Protocols } from './protocol'; import { type Converter, ConverterFactory } from './converters'; import type { ExtractPayload, GenericConfig, TypeToIdMap, TypeToNameMap } from './Codec.types'; import { Buffer } from './Buffer'; @@ -7,31 +7,24 @@ import type { ProtocolId, MessageId } from './types'; export class Codec { private typesByName: TypeToNameMap = new Map(); private typesById: TypeToIdMap = new Map(); - private protocols: Protocols; + private protocols = new Protocols(); - constructor(schema: ProtocolJSON[]) { - this.protocols = new Protocols(schema); + constructor(rawTypes: RawType[] = [], protocols: Protocol[] = []) { + this.protocols.load(rawTypes); const converterFactory = new ConverterFactory(this.protocols); - const items = this.protocols.getProtocols(); - for (const [protoName, proto] of items) { + for (const { name, proto_id: protoId, types } of protocols) { const typeMap = new Map(); const idMap = new Map(); - const types = Array.from(proto.types.entries()); - for (const [typeName] of types) { - const converter = converterFactory.toConverter(protoName, typeName); - typeMap.set(typeName, converter); - - const messageId = proto.messageIds.get(typeName); + for (const [messageId, typeName] of Object.entries(types)) { + const converter = converterFactory.toConverter(typeName); - if (messageId !== undefined) { - idMap.set(messageId, converter); - } + typeMap.set(typeName, converter); + idMap.set(parseInt(messageId, 10), converter); } - - this.typesByName.set(proto.name, typeMap); - this.typesById.set(proto.id, idMap); + this.typesByName.set(name, typeMap); + this.typesById.set(protoId, idMap); } } diff --git a/port/js/src/converters/ConverterFactory.ts b/port/js/src/converters/ConverterFactory.ts index 55e829da..c1f67d9a 100644 --- a/port/js/src/converters/ConverterFactory.ts +++ b/port/js/src/converters/ConverterFactory.ts @@ -1,4 +1,3 @@ -import type { ProtocolName } from '../types'; import type { Converter } from './Converter'; import { Protocols } from '../protocol/Protocols'; import { @@ -11,30 +10,30 @@ import { } from './base'; export class ConverterFactory { - constructor(private protocols: Protocols = new Protocols([])) { + constructor(private protocols: Protocols = new Protocols()) { } - toConverter(protocolName: ProtocolName, typeName: string): Converter { - const typeDef = this.protocols.getType(protocolName, typeName); + toConverter(typeName: string): Converter { + const typeDef = this.protocols.getType(typeName); const getType = this.toConverter.bind(this); switch (typeDef.typeClass) { case 'scalar': return new ScalarConverter(typeDef.type); case 'enum': - return new EnumConverter(protocolName, typeDef, getType); + return new EnumConverter(typeDef, getType); case 'struct': - return new StructConverter(protocolName, typeDef, getType); + return new StructConverter(typeDef, getType); case 'array': - return new ArrayConverter(protocolName, typeDef, getType); + return new ArrayConverter(typeDef, getType); case 'typed-array': - return new TypedArrayConverter(protocolName, typeDef, getType); + return new TypedArrayConverter(typeDef, getType); case 'map': - return new MapConverter(protocolName, typeDef, getType); + return new MapConverter(typeDef, getType); default: throw new Error(`Unsupported type class ${typeName}`); } } } -export type GetType = (protocolName: ProtocolName, typeName: string) => Converter; +export type GetType = (typeName: string) => Converter; diff --git a/port/js/src/converters/base/ArrayConverter.ts b/port/js/src/converters/base/ArrayConverter.ts index 48e81b87..05c8d137 100644 --- a/port/js/src/converters/base/ArrayConverter.ts +++ b/port/js/src/converters/base/ArrayConverter.ts @@ -9,10 +9,10 @@ export class ArrayConverter extends Converter { private sizeConverter: Converter; private arraySize?: number; - constructor(protocolName: string, typeDef: ArrayTypeDefinition, getType: GetType) { + constructor(typeDef: ArrayTypeDefinition, getType: GetType) { super(typeDef.type + typeDef.elementType); - this.converter = getType(protocolName, typeDef.elementType); - this.sizeConverter = getType(protocolName, SIZE_TYPE); + this.converter = getType(typeDef.elementType); + this.sizeConverter = getType(SIZE_TYPE); this.arraySize = typeDef.arraySize; } diff --git a/port/js/src/converters/base/EnumConverter.ts b/port/js/src/converters/base/EnumConverter.ts index faf4ba45..0b012043 100644 --- a/port/js/src/converters/base/EnumConverter.ts +++ b/port/js/src/converters/base/EnumConverter.ts @@ -8,10 +8,10 @@ export class EnumConverter extends Converter { private enumsByName: Record; private enumsByValue: string[]; - constructor(protocolName: string, typeDef: EnumTypeDefinition, getType: GetType) { + constructor(typeDef: EnumTypeDefinition, getType: GetType) { super(typeDef.typeName); - this.converter = getType(protocolName, typeDef.type); + this.converter = getType(typeDef.type); this.enumsByName = typeDef.values.reduce((acc, value) => { acc[value.name] = value.value; diff --git a/port/js/src/converters/base/MapConverter.ts b/port/js/src/converters/base/MapConverter.ts index 59abe2d8..b0cb04fd 100644 --- a/port/js/src/converters/base/MapConverter.ts +++ b/port/js/src/converters/base/MapConverter.ts @@ -9,11 +9,11 @@ export class MapConverter extends Converter { protected valueConverter: Converter; protected dynamicSizeConverter: Converter; - constructor(protocolName: string, typeDef: MapTypeDefinition, getType: GetType) { + constructor(typeDef: MapTypeDefinition, getType: GetType) { super(typeDef.typeClass); - this.keyConverter = getType(protocolName, typeDef.keyType); - this.valueConverter = getType(protocolName, typeDef.valueType); - this.dynamicSizeConverter = getType(protocolName, SIZE_TYPE); + this.keyConverter = getType(typeDef.keyType); + this.valueConverter = getType(typeDef.valueType); + this.dynamicSizeConverter = getType(SIZE_TYPE); } serialize(value: Map | Record, buffer: Buffer): void { diff --git a/port/js/src/converters/base/StructConverter.ts b/port/js/src/converters/base/StructConverter.ts index f56a1241..847e125a 100644 --- a/port/js/src/converters/base/StructConverter.ts +++ b/port/js/src/converters/base/StructConverter.ts @@ -8,7 +8,7 @@ export class StructConverter extends Converter { private static RESERVED_WORDS: Set = new Set(Object.getOwnPropertyNames(Object.prototype)); parentObject: Record; - constructor(protocolName: string, typeDef: StructTypeDefinition, getType: GetType) { + constructor(typeDef: StructTypeDefinition, getType: GetType) { super(typeDef.typeName); const fieldsSet = new Set(); @@ -22,7 +22,7 @@ export class StructConverter extends Converter { throw new Error(`Field ${field.name} is a reserved word in JavaScript`); } - const converter = getType(protocolName, field.type); + const converter = getType(field.type); if (!converter) { throw new Error(`Converter for type ${field.type} is not found in ${this.name}`); } diff --git a/port/js/src/converters/base/TypedArrayConverter.ts b/port/js/src/converters/base/TypedArrayConverter.ts index d7c5b047..376c122e 100644 --- a/port/js/src/converters/base/TypedArrayConverter.ts +++ b/port/js/src/converters/base/TypedArrayConverter.ts @@ -23,10 +23,10 @@ export class TypedArrayConverter extends Converter { private arraySize?: number; private TypedArrayConstructor: TypedArrayConstructor; - constructor(protocolName: string, typeDef: TypedArrayTypeDefinition, getType: GetType) { + constructor(typeDef: TypedArrayTypeDefinition, getType: GetType) { super(typeDef.type); - this.converter = getType(protocolName, typeDef.elementType); - this.sizeConverter = getType(protocolName, SIZE_TYPE); + this.converter = getType(typeDef.elementType); + this.sizeConverter = getType(SIZE_TYPE); this.arraySize = typeDef.arraySize; const arrayConstructor = TYPED_ARRAY_MAP.get(typeDef.elementType); diff --git a/port/js/src/protocol/Protocols.ts b/port/js/src/protocol/Protocols.ts index 5b968ef1..5ef492ea 100644 --- a/port/js/src/protocol/Protocols.ts +++ b/port/js/src/protocol/Protocols.ts @@ -1,5 +1,5 @@ -import type { IBasicType, IName, IType, ProtocolName, TypeDefinition } from '../types'; -import type { ProtocolConfig, ProtocolJSON, StructureType } from './Protocols.types'; +import type { IBasicType, IName, IType, TypeDefinition } from '../types'; +import { type RawType, TypeClass } from './Protocols.types'; const SCALAR_TYPES_INFO = new Map([ ['int8', true], @@ -19,90 +19,63 @@ const SCALAR_TYPES_INFO = new Map([ ]); export class Protocols { - private static SEPARATOR = '/'; - private protocols = new Map(); - - constructor(jsons: ProtocolJSON[]) { - for (const json of jsons) { - const types = new Map(Object.entries(json.types) - .map(([name, info]) => [name, this.resiolveHeadtypes(name, info)])); - - const messageIds = new Map(Object.entries(json.types_map || {}).map(([id, name]) => [name, parseInt(id, 10)])); - - this.protocols.set(json.proto_name, { - id: json.proto_id, - name: json.proto_name, - types, - messageIds, - } as ProtocolConfig); - } - } - - getProtocols(): [ProtocolName, ProtocolConfig][] { - return Array.from(this.protocols.entries()); - } - - private resiolveHeadtypes(name: IName, definition: StructureType): TypeDefinition { - if (definition.type_class === 'struct') { - return { - typeClass: 'struct', - fields: definition.fields, - typeName: name, - }; - } - return { - typeClass: 'enum', - type: definition.base_type, - typeName: name, - values: definition.values, - }; + private types = new Map(); + + load(types: RawType[]): void { + types.forEach((type) => { + if (type.type_class === TypeClass.STRUCT) { + this.types.set(type.type, { + typeClass: 'struct', + fields: type.fields, + typeName: type.type, + }); + } else if (type.type_class === TypeClass.ENUM) { + this.types.set(type.type, { + typeClass: 'enum', + type: type.base_type, + typeName: type.type, + values: type.values, + }); + } + }); } - getType(currProtoName: ProtocolName, typeName: IType): TypeDefinition { + getType(typeName: IType): TypeDefinition { if (SCALAR_TYPES_INFO.has(typeName)) { - return { - type: typeName as IBasicType, - typeClass: 'scalar', - }; + return { type: typeName as IBasicType, typeClass: 'scalar' }; } - if (typeName.endsWith(']')) { - const [elementType, size] = this.parseArrayType(typeName); - - if (SCALAR_TYPES_INFO.get(elementType)) { - return { - type: typeName, - typeClass: 'typed-array', - elementType, - arraySize: size, - }; - } - - return { - type: typeName, - typeClass: 'array', - elementType, - arraySize: size, - }; + return this.parseArrayType(typeName); } - if (typeName.endsWith('}')) { - const [valueType, keyType] = this.parseMapType(typeName); - return { - type: typeName, - typeClass: 'map', - keyType, - valueType, - }; + return this.parseMapType(typeName); } + return this.resolveType(typeName); + } - const [, type] = this.resolveType(currProtoName, typeName); - if (!type) { throw new Error(`Type not found: ${typeName} in ${currProtoName}`); } + private parseArrayType(typeName: string): TypeDefinition { + const [elementType, size] = this.parseArray(typeName); + + const isTyped = SCALAR_TYPES_INFO.get(elementType); + return { + type: typeName, + typeClass: isTyped ? 'typed-array' : 'array', + elementType, + arraySize: size, + }; + } - return type; + private parseMapType(typeName: string): TypeDefinition { + const [keyType, valueType] = this.parseMap(typeName); + return { + type: typeName, + typeClass: 'map', + keyType, + valueType, + }; } - private parseArrayType(typeName: string): [string, number | undefined] { + private parseArray(typeName: string): [string, number | undefined] { const parts = typeName.slice(0, -1).split('['); return [ parts.slice(0, -1).join('['), @@ -110,31 +83,16 @@ export class Protocols { ]; } - private parseMapType(typeName: string): [string, string] { + private parseMap(typeName: string): [string, string] { const parts = typeName.slice(0, -1).split('{'); - return [parts.slice(0, -1).join('{'), parts[parts.length - 1]]; + return [parts[parts.length - 1], parts.slice(0, -1).join('{')]; } - private resolveType(currProtoName: string, typeName: string): [ProtocolConfig, TypeDefinition | undefined] { - if (typeName.includes(Protocols.SEPARATOR)) { - const parts = typeName.split(Protocols.SEPARATOR); - const localType = parts.pop()!; - const protoName = parts.join(Protocols.SEPARATOR); - const proto = this.protocols.get(protoName); - - if (!proto) { - throw new Error(`Unknown type: ${typeName} not found at protocol ${currProtoName}`); - } - - return [proto, proto.types.get(localType)]; + private resolveType(typeName: string): TypeDefinition { + const typeDefinition = this.types.get(typeName); + if (!typeDefinition) { + throw new Error(`Unknown type: ${typeName} not found`); } - - const proto = this.protocols.get(currProtoName); - - if (!proto) { - throw new Error(`Unknown type: ${typeName} not found at protocol ${currProtoName}`); - } - - return [proto, proto.types.get(typeName)]; + return typeDefinition; } } diff --git a/port/js/src/protocol/Protocols.types.ts b/port/js/src/protocol/Protocols.types.ts index ca3b1658..e3df3713 100644 --- a/port/js/src/protocol/Protocols.types.ts +++ b/port/js/src/protocol/Protocols.types.ts @@ -1,11 +1,31 @@ -import type { IName, INumberType, MessageId, ProtocolId, ProtocolName, TypeDefinition, Field } from '../types'; +import type { IName, INumberType, Field } from '../types'; + +export interface RawStructType { + type: string; + type_class: '8' + fields: Field[]; +} + +export interface RawEnumType { + type: string; + type_class: '7'; + base_type: INumberType; + values: EnumValue[]; +} + +export type RawType = RawStructType | RawEnumType; interface EnumValue { name: IName; value: number; } -export interface TypeClass { +export enum TypeClass { + STRUCT = '8', + ENUM = '7', +} + +export interface StructTypeClass { type_class: 'struct'; comment?: string; fields: Field[] | null; @@ -18,23 +38,10 @@ export interface EnumTypeClass { values: EnumValue[]; } -export interface Types { - [key: string]: TypeClass | EnumTypeClass; -} - -export interface ProtocolJSON { - proto_id: ProtocolId; - proto_name: ProtocolName; - types: Types; - types_map?: Record; - version: string; -} +export type StructureType = StructTypeClass | EnumTypeClass; -export interface ProtocolConfig { - id: ProtocolId; - name: ProtocolName; - types: Map; - messageIds: Map; +export interface Protocol { + name: string; + proto_id: number; + types: Record; } - -export type StructureType = TypeClass | EnumTypeClass; diff --git a/port/js/tests/Codec.test.ts b/port/js/tests/Codec.test.ts index 9c450cdc..7e089545 100644 --- a/port/js/tests/Codec.test.ts +++ b/port/js/tests/Codec.test.ts @@ -3,23 +3,23 @@ import { describe, it, expect, beforeAll } from 'vitest'; import { execSync } from 'child_process'; import { Codec } from '../src/Codec'; -import { uploadShema } from './utils'; -import type { ProtocolJSON } from '../src/protocol/Protocols.types'; +import { uploadTypes, uploadProtocols } from './utils'; +import type { Protocol, RawType } from '../src/protocol'; describe('Codec', () => { - let testProtoData: ProtocolJSON; - let anotherProtoData: ProtocolJSON; + let types: RawType[]; + let protocols: Protocol[]; let codec: Codec; beforeAll(() => { execSync('npm run gen:json'); - testProtoData = uploadShema('./messgen/test_proto/protocol.json'); - anotherProtoData = uploadShema('./another_proto/protocol.json'); - codec = new Codec([testProtoData, anotherProtoData]); + types = uploadTypes('./types.json'); + protocols = uploadProtocols('./protocols.json'); + codec = new Codec(types, protocols); }); describe('init example', () => { it('should initialize the messages', () => { - expect(new Codec([testProtoData, anotherProtoData])).toBeDefined(); + expect(new Codec(types, protocols)).toBeDefined(); }); it('should serialize and deserialize a message', () => { @@ -38,7 +38,7 @@ describe('Codec', () => { f9: true, }; - const message = codec.serialize('messgen/test_proto', 'simple_struct', rawData); + const message = codec.serialize('test_proto', 'messgen/test/simple_struct', rawData); expect(codec.deserialize(1, 0, message.buffer)).toEqual({ ...rawData, diff --git a/port/js/tests/ConverterFactory.test.ts b/port/js/tests/ConverterFactory.test.ts index 77334cf0..d03e781e 100644 --- a/port/js/tests/ConverterFactory.test.ts +++ b/port/js/tests/ConverterFactory.test.ts @@ -1,9 +1,8 @@ import { describe, it, expect } from 'vitest'; -import { ConverterFactory } from "../src/converters/ConverterFactory"; -import { IType } from "../src/types"; -import { Converter } from "../src/converters/Converter"; -import { Buffer } from "../src/Buffer"; -import { Protocols } from '../src/protocol/Protocols'; +import { ConverterFactory } from '../src/converters/ConverterFactory'; +import type { IType } from '../src/types'; +import type { Converter } from '../src/converters/Converter'; +import { Buffer } from '../src/Buffer'; describe('ConverterFactory', () => { it('should serialize scalar correctly', () => { @@ -53,11 +52,11 @@ describe('ConverterFactory', () => { }); it('should throw an error when the basis type is not found in the converters map', () => { - expect(() => getConverter('customType')).toThrowError('Unknown type: customType not found at protocol test'); + expect(() => getConverter('customType')).toThrowError('Unknown type: customType not found'); }); it('should throw an error when the map key type is not found in the converters map', () => { - expect(() => { getConverter('int32{customType}') }).toThrowError(`Unknown type: customType not found at protocol test`); + expect(() => { getConverter('int32{customType}'); }).toThrowError('Unknown type: customType not found'); }); it('should serialize multidimensional array', () => { @@ -89,13 +88,12 @@ describe('ConverterFactory', () => { expect(converter.deserialize(buffer)).toEqual(value); }); - it('should serialize map of scalar typess', () => { const converter = getConverter('string{int32}'); const value = new Map([ - [1, "one"], - [2, "two"], - [3, "three"] + [1, 'one'], + [2, 'two'], + [3, 'three'], ]); const buffer = new Buffer(new ArrayBuffer(converter.size(value))); @@ -104,13 +102,12 @@ describe('ConverterFactory', () => { expect(buffer.offset).toEqual(39); }); - it('should serialize and deserialize a map of basic types correctly', () => { const converter = getConverter('string{int32}'); const value = new Map([ - [1, "one"], - [2, "two"], - [3, "three"] + [1, 'one'], + [2, 'two'], + [3, 'three'], ]); const buffer = new Buffer(new ArrayBuffer(converter.size(value))); @@ -120,8 +117,6 @@ describe('ConverterFactory', () => { expect(converter.deserialize(buffer)).is.deep.eq(value); }); - - it('should calculate the correct size for flat array', () => { const converter = getConverter('int32[5]'); const value = new Int32Array([1, 2, 3, 4, 5]); @@ -139,10 +134,9 @@ describe('ConverterFactory', () => { it('should throw an error for unknown map key type', () => { const serializeFn = () => getConverter('int32{undefined}'); - expect(serializeFn).toThrowError('Unknown type: undefined not found at protocol test'); + expect(serializeFn).toThrowError('Unknown type: undefined not found'); }); - it('should throw an error when the array length is out of bounds', () => { const converter = getConverter('int32[3]'); const value = [1, 2, 3, 4]; // Array length is out of bounds @@ -151,13 +145,12 @@ describe('ConverterFactory', () => { expect(serialize).toThrowError('Array length mismatch: 4 !== 3'); }); - it('it should serialize nested maps with nested structs', () => { const converter = getConverter('int32[3][]{string}{string}'); const value = new Map>([ - ["key1", new Map([ - ["key2", [new Int32Array([1, 2, 3]), new Int32Array([4, 5, 6])]] - ])] + ['key1', new Map([ + ['key2', [new Int32Array([1, 2, 3]), new Int32Array([4, 5, 6])]], + ])], ]); const buffer = new Buffer(new ArrayBuffer(converter.size(value))); @@ -168,9 +161,9 @@ describe('ConverterFactory', () => { it('it should deserialize nested maps with nested structs', () => { const converter = getConverter('int32[3][]{string}{string}'); const value = new Map>([ - ["key1", new Map([ - ["key2", [new Int32Array([1, 2, 3]), new Int32Array([4, 5, 6])]] - ])] + ['key1', new Map([ + ['key2', [new Int32Array([1, 2, 3]), new Int32Array([4, 5, 6])]], + ])], ]); const buffer = new Buffer(new ArrayBuffer(converter.size(value))); @@ -181,7 +174,7 @@ describe('ConverterFactory', () => { }); function getConverter(type: IType): Converter { - const factory = new ConverterFactory(new Protocols([])); - return factory.toConverter('test', type); + const factory = new ConverterFactory(); + return factory.toConverter(type); } }); diff --git a/port/js/tests/EnumConverter.test.ts b/port/js/tests/EnumConverter.test.ts index 50db14a1..ffea098e 100644 --- a/port/js/tests/EnumConverter.test.ts +++ b/port/js/tests/EnumConverter.test.ts @@ -52,7 +52,7 @@ describe('EnumConverter', () => { function intiEnumConverter(values: EnumValue[], type?: IBasicType): EnumConverter { const schema = createSchema(values, type); const getType = initGetType(); - return new EnumConverter('testStruct', schema, getType); + return new EnumConverter(schema, getType); } function createSchema(values: EnumValue[] = [], type: IBasicType = 'int8'): EnumTypeDefinition { diff --git a/port/js/tests/Integration.test.ts b/port/js/tests/Integration.test.ts index c476328d..18763172 100644 --- a/port/js/tests/Integration.test.ts +++ b/port/js/tests/Integration.test.ts @@ -3,23 +3,18 @@ import { describe, it, expect, beforeAll } from 'vitest'; import { execSync } from 'child_process'; import { Codec } from '../src/Codec'; -import { uploadShema, uploadBinary } from './utils'; -import type { ProtocolJSON } from '../src/protocol/Protocols.types'; +import { uploadBinary, uploadTypes, uploadProtocols } from './utils'; describe('integration', () => { - let protocolData: ProtocolJSON; let codec: Codec; const bigint = BigInt('0x1234567890abcdef'); beforeAll(() => { execSync(' npm run generate-bit'); execSync(' npm run gen:json'); - protocolData = uploadShema('./messgen/test_proto/protocol.json'); - codec = new Codec([protocolData]); - }); - - it('should initialize codec with protocols', () => { - expect(() => new Codec([protocolData])).not.toThrow(); + const types = uploadTypes('./types.json'); + const protocols = uploadProtocols('./protocols.json'); + codec = new Codec(types, protocols); }); it('shpuld parse simple_struct (flat structure)', () => { @@ -38,7 +33,7 @@ describe('integration', () => { }; const rawDataBit = uploadBinary('../../../tests/data/serialized/bin/simple_struct.bin'); - const buffer = codec.serialize('messgen/test_proto', 'simple_struct', rawData); + const buffer = codec.serialize('test_proto', 'messgen/test/simple_struct', rawData); const result = codec.deserialize(1, 0, new Uint8Array(rawDataBit).buffer); expect(result).toEqual({ ...rawData, f5: expect.closeTo(rawData.f5, 5) }); @@ -54,7 +49,7 @@ describe('integration', () => { }; const rawDataBit = uploadBinary('../../../tests/data/serialized/bin/var_size_struct.bin'); - const buffer = codec.serialize('messgen/test_proto', 'var_size_struct', rawData); + const buffer = codec.serialize('test_proto', 'messgen/test/var_size_struct', rawData); const result = codec.deserialize(1, 2, new Uint8Array(rawDataBit).buffer); expect(result).toEqual(rawData); @@ -66,7 +61,7 @@ describe('integration', () => { const rawData = { f0: bigint, f1: bigint, e0: 1 }; const rawDataBit = uploadBinary('../../../tests/data/serialized/bin/struct_with_enum.bin'); - const buffer = codec.serialize('messgen/test_proto', 'struct_with_enum', rawData); + const buffer = codec.serialize('test_proto', 'messgen/test/struct_with_enum', rawData); const result = codec.deserialize(1, 3, new Uint8Array(rawDataBit).buffer); expect(result).toEqual(rawData); @@ -78,7 +73,7 @@ describe('integration', () => { const rawData = {}; const rawDataBit = uploadBinary('../../../tests/data/serialized/bin/empty_struct.bin'); - const buffer = codec.serialize('messgen/test_proto', 'empty_struct', rawData); + const buffer = codec.serialize('test_proto', 'messgen/test/empty_struct', rawData); const result = codec.deserialize(1, 4, new Uint8Array(rawDataBit).buffer); expect(result).toEqual(rawData); @@ -110,7 +105,7 @@ describe('integration', () => { }; const rawDataBit = uploadBinary('../../../tests/data/serialized/bin/complex_struct_with_empty.bin'); - const buffer = codec.serialize('messgen/test_proto', 'complex_struct_with_empty', rawData); + const buffer = codec.serialize('test_proto', 'messgen/test/complex_struct_with_empty', rawData); const result = codec.deserialize(1, 5, new Uint8Array(rawDataBit).buffer); expect(result).toEqual(rawData); @@ -167,7 +162,7 @@ describe('integration', () => { }; const rawDataBit = uploadBinary('../../../tests/data/serialized/bin/complex_struct_nostl.bin'); - const buffer = codec.serialize('messgen/test_proto', 'complex_struct_nostl', rawData); + const buffer = codec.serialize('test_proto', 'messgen/test/complex_struct_nostl', rawData); const result = codec.deserialize(1, 6, new Uint8Array(rawDataBit).buffer); simpleStruct.f5 = expect.closeTo(simpleStruct.f5, 4); @@ -225,7 +220,7 @@ describe('integration', () => { }; const rawDataBit = uploadBinary('../../../tests/data/serialized/bin/complex_struct.bin'); - const buffer = codec.serialize('messgen/test_proto', 'complex_struct', rawData); + const buffer = codec.serialize('test_proto', 'messgen/test/complex_struct', rawData); const result = codec.deserialize(1, 1, new Uint8Array(rawDataBit).buffer); simpleStruct.f5 = expect.closeTo(simpleStruct.f5, 4); @@ -250,7 +245,7 @@ describe('integration', () => { }; const rawDataBit = uploadBinary('../../../tests/data/serialized/bin/flat_struct.bin'); - const buffer = codec.serialize('messgen/test_proto', 'flat_struct', rawData); + const buffer = codec.serialize('test_proto', 'messgen/test/flat_struct', rawData); const result = codec.deserialize(1, 7, new Uint8Array(rawDataBit).buffer); rawData.f5 = expect.closeTo(rawData.f5, 5); diff --git a/port/js/tests/Protocols.test.ts b/port/js/tests/Protocols.test.ts index 728a1fa1..83e17d5c 100644 --- a/port/js/tests/Protocols.test.ts +++ b/port/js/tests/Protocols.test.ts @@ -1,56 +1,35 @@ import { describe, it, expect, beforeAll } from 'vitest'; import { Protocols } from '../src/protocol/Protocols'; -import type { ProtocolJSON } from '../src/protocol/Protocols.types'; describe('Protocols', () => { - let testProtoData: ProtocolJSON; let protocols: Protocols; beforeAll(() => { - testProtoData = { - proto_id: 1, - proto_name: 'messgen/test_proto', - types: { - simple_struct: { - type_class: 'struct', - fields: [ - { name: 'f0', type: 'uint64' }, - { name: 'f1', type: 'int64' }, - ], - }, - simple_enum: { - type_class: 'enum', - base_type: 'uint8', - values: [ - { name: 'one_value', value: 0 }, - { name: 'another_value', value: 1 }, - ], - }, + protocols = new Protocols(); + protocols.load([ + { + type: 'simple_struct', + type_class: '8', + fields: [ + { name: 'f0', type: 'uint64' }, + { name: 'f1', type: 'int64' }, + ], }, - types_map: { - 0: 'simple_struct', - 1: 'simple_enum', + { + type: 'simple_enum', + type_class: '7', + base_type: 'uint8', + values: [ + { name: 'one_value', value: 0 }, + { name: 'another_value', value: 1 }, + ], }, - } as unknown as ProtocolJSON; - protocols = new Protocols([testProtoData]); - }); - - describe('#constructor', () => { - it('should correctly initialize protocols from JSON', () => { - const protoMap = protocols.getProtocols(); - const [, proto] = protoMap.find(([name]) => name === 'messgen/test_proto') || []; - - expect(proto).toBeDefined(); - expect(proto?.id).toBe(1); - expect(proto?.name).toBe('messgen/test_proto'); - expect(proto?.types.size).toBe(2); - expect(proto?.messageIds.size).toBe(2); - }); + ]); }); describe('#getType', () => { it('should resolve scalar types', () => { - const type = protocols.getType('messgen/test_proto', 'uint64'); + const type = protocols.getType('uint64'); expect(type).toEqual({ type: 'uint64', typeClass: 'scalar', @@ -58,7 +37,7 @@ describe('Protocols', () => { }); it('should resolve array types', () => { - const type = protocols.getType('messgen/test_proto', 'uint64[4]'); + const type = protocols.getType('uint64[4]'); expect(type).toEqual({ type: 'uint64[4]', typeClass: 'typed-array', @@ -68,7 +47,7 @@ describe('Protocols', () => { }); it('should resolve dynamic array types', () => { - const type = protocols.getType('messgen/test_proto', 'uint64[]'); + const type = protocols.getType('uint64[]'); expect(type).toEqual({ type: 'uint64[]', typeClass: 'typed-array', @@ -78,7 +57,7 @@ describe('Protocols', () => { }); it('should resolve map types', () => { - const type = protocols.getType('messgen/test_proto', 'string{int32}'); + const type = protocols.getType('string{int32}'); expect(type).toEqual({ type: 'string{int32}', typeClass: 'map', @@ -88,7 +67,7 @@ describe('Protocols', () => { }); it('should resolve struct types', () => { - const type = protocols.getType('messgen/test_proto', 'simple_struct'); + const type = protocols.getType('simple_struct'); expect(type).toEqual({ typeClass: 'struct', typeName: 'simple_struct', @@ -100,7 +79,7 @@ describe('Protocols', () => { }); it('should resolve enum types', () => { - const type = protocols.getType('messgen/test_proto', 'simple_enum'); + const type = protocols.getType('simple_enum'); expect(type).toEqual({ typeClass: 'enum', typeName: 'simple_enum', @@ -114,12 +93,12 @@ describe('Protocols', () => { it('should throw error for unknown types', () => { expect(() => { - protocols.getType('messgen/test_proto', 'unknown_type'); - }).toThrow('Type not found: unknown_type in messgen/test_proto'); + protocols.getType('unknown_type'); + }).toThrow('Unknown type: unknown_type not found'); }); it('should resolve cross-protocol type references', () => { - const type = protocols.getType('messgen/test_proto', 'messgen/test_proto/simple_struct'); + const type = protocols.getType('simple_struct'); expect(type).toBeDefined(); expect(type.typeClass).toBe('struct'); }); diff --git a/port/js/tests/StructConvertert.test.ts b/port/js/tests/StructConvertert.test.ts index afac43a2..b046c77a 100644 --- a/port/js/tests/StructConvertert.test.ts +++ b/port/js/tests/StructConvertert.test.ts @@ -143,7 +143,7 @@ describe('StructConverter', () => { ): StructConverter { const schema = createSchema(fields); const getType = initGetType(); - return new StructConverter('testStruct', schema, getType); + return new StructConverter(schema, getType); } function createSchema(fields: Field[] = []): StructTypeDefinition { diff --git a/port/js/tests/utf8.test.ts b/port/js/tests/utf8.test.ts index 8689531c..6d9d9840 100644 --- a/port/js/tests/utf8.test.ts +++ b/port/js/tests/utf8.test.ts @@ -1,11 +1,11 @@ -import { describe, expect, it } from 'vitest' -import { encodeUTF8, decodeUTF8 } from '../src/utils/utf8.ts' +import { describe, expect, it } from 'vitest'; +import { encodeUTF8, decodeUTF8 } from '../src/utils/utf8.ts'; describe('UTF8 function test', () => { - it('Encoding decoding test', () => { - let testStr = '✈✈✈ Hello world! ✈✈✈' - let byteArr = encodeUTF8(testStr) - let dstStr = decodeUTF8(byteArr) - expect(testStr).toBe(dstStr) - }) -}) + it('Encoding decoding test', () => { + const testStr = '✈✈✈ Hello world! ✈✈✈'; + const byteArr = encodeUTF8(testStr); + const dstStr = decodeUTF8(byteArr); + expect(testStr).toBe(dstStr); + }); +}); diff --git a/port/js/tests/utils.ts b/port/js/tests/utils.ts index bb770cba..d6be1323 100644 --- a/port/js/tests/utils.ts +++ b/port/js/tests/utils.ts @@ -2,13 +2,21 @@ import * as path from 'path'; import { readFileSync } from 'fs'; import { execSync } from 'child_process'; import { ConverterFactory } from '../src/converters/ConverterFactory'; -import type { ProtocolJSON } from '../src/protocol/Protocols.types'; +import type { Protocol, RawType } from '../src/protocol/Protocols.types'; import { Protocols } from '../src/protocol/Protocols'; -export function uploadShema(filePath: string): ProtocolJSON { +const uploadFile = (filePath: string): T => { const protocolPath = path.resolve(__dirname, filePath); const rawData = readFileSync(protocolPath, 'utf8'); - return JSON.parse(rawData) as ProtocolJSON; + return JSON.parse(rawData) as T; +}; + +export function uploadTypes(filePath: string): RawType[] { + return uploadFile(filePath); +} + +export function uploadProtocols(filePath: string): Protocol[] { + return uploadFile(filePath); } export function uploadBinary(filePath: string): Buffer { @@ -21,7 +29,7 @@ export function generateTestData() { } export function initGetType() { - const protocol = new Protocols([]); + const protocol = new Protocols(); const factory = new ConverterFactory(protocol); return factory.toConverter.bind(factory); }