pg-proto-parser
Version:
The LaunchQL Proto parser
347 lines (346 loc) • 20 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateEnumToStringFunctions = exports.generateEnumToStringFunctionsNested = exports.generateEnumToIntFunctionsNested = exports.generateEnumToIntFunctions = exports.generateEnumValueFunctions = exports.convertEnumToTsUnionType = exports.generateEnumImports = exports.convertEnumToTsEnumDeclaration = void 0;
const t = __importStar(require("@babel/types"));
const utils_1 = require("../../utils");
/**
* Converts a protobuf Enum into a TypeScript enum declaration.
* Example output: export enum MyEnum { VALUE1 = 0, VALUE2 = 1, ... }
* This is the traditional enum format that creates both type and value in TypeScript.
*/
const convertEnumToTsEnumDeclaration = (enumData) => {
const members = Object.entries(enumData.values).map(([key, value]) => t.tsEnumMember(t.identifier(key), t.numericLiteral(value)));
const enumDeclaration = t.tsEnumDeclaration(t.identifier(enumData.name), members);
return t.exportNamedDeclaration(enumDeclaration);
};
exports.convertEnumToTsEnumDeclaration = convertEnumToTsEnumDeclaration;
/**
* Generates import statements for enums from a specified source module.
* Used when enums need to be imported into other generated files (like types.ts).
* Example output: import { Enum1, Enum2, ... } from './enums';
*/
const generateEnumImports = (enums, source) => {
return (0, utils_1.createNamedImport)(enums.map(e => e.name), source);
};
exports.generateEnumImports = generateEnumImports;
/**
* Converts a protobuf Enum into a TypeScript union type of string literals.
* Example output: export type MyEnum = 'VALUE1' | 'VALUE2' | ...
* This creates a type-only representation without runtime values.
*/
const convertEnumToTsUnionType = (enumData) => {
const literals = Object.keys(enumData.values).map(key => t.tsLiteralType(t.stringLiteral(key)));
const unionType = t.tsUnionType(literals);
const typeAlias = t.tsTypeAliasDeclaration(t.identifier(enumData.name), null, unionType);
return t.exportNamedDeclaration(typeAlias);
};
exports.convertEnumToTsUnionType = convertEnumToTsUnionType;
/**
* Generates a bidirectional enum value converter function that can convert between string keys and numeric values.
* Creates getEnumValue(enumType, key) that accepts either string or number and returns the corresponding value.
* Example: getEnumValue('MyEnum', 'VALUE1') => 0, getEnumValue('MyEnum', 0) => 'VALUE1'
*/
const generateEnumValueFunctions = (enumData) => {
// Create the union type for EnumType
const enumTypeIdentifier = t.identifier('EnumType');
const enumTypeUnion = t.tsUnionType(enumData.map(enumDef => t.tsLiteralType(t.stringLiteral(enumDef.name))));
const enumTypeAlias = t.tsTypeAliasDeclaration(enumTypeIdentifier, null, enumTypeUnion);
// Create the function parameter and its type
const enumTypeParam = t.identifier('enumType');
const enumTypeParamAnnotation = t.tsTypeAnnotation(t.tsTypeReference(enumTypeIdentifier));
enumTypeParam.typeAnnotation = enumTypeParamAnnotation;
const keyParam = t.identifier('key');
const keyParamAnnotation = t.tsTypeAnnotation(t.tsUnionType([t.tsStringKeyword(), t.tsNumberKeyword()]));
keyParam.typeAnnotation = keyParamAnnotation;
// Create the switch cases for the outer switch statement
const outerCases = enumData.map(enumDef => {
const innerCases = Object.entries(enumDef.values).map(([key, value]) => {
return t.switchCase(t.stringLiteral(key), [t.returnStatement(t.numericLiteral(value))]);
});
// Add the reverse mapping cases
innerCases.push(...Object.entries(enumDef.values).map(([key, value]) => {
return t.switchCase(t.numericLiteral(value), [t.returnStatement(t.stringLiteral(key))]);
}));
// Add the default case for the inner switch
innerCases.push(t.switchCase(null, [
t.throwStatement(t.newExpression(t.identifier('Error'), [t.stringLiteral(`Key not recognized in enum ${enumDef.name}`)]))
]));
return t.switchCase(t.stringLiteral(enumDef.name), [
t.blockStatement([t.switchStatement(keyParam, innerCases)])
]);
});
// Add the default case for the outer switch
outerCases.push(t.switchCase(null, [
t.throwStatement(t.newExpression(t.identifier('Error'), [t.stringLiteral('Enum type not recognized')]))
]));
// Create the outer switch statement
const switchStatement = t.switchStatement(enumTypeParam, outerCases);
// Create the function body
const functionBody = t.blockStatement([switchStatement]);
// Create the arrow function expression
const arrowFunctionExpression = t.arrowFunctionExpression([enumTypeParam, keyParam], functionBody);
// Create the variable declarator for the function
const variableDeclarator = t.variableDeclarator(t.identifier('getEnumValue'), arrowFunctionExpression);
// Create the variable declaration (const getEnumValue = ...)
const variableDeclaration = t.variableDeclaration('const', [variableDeclarator]);
// Export the arrow function
const exportedFunction = t.exportNamedDeclaration(variableDeclaration, []);
// Export the type
const exportedEnumTypeAlias = t.exportNamedDeclaration(enumTypeAlias, []);
// Return the entire AST
return [exportedEnumTypeAlias, exportedFunction];
};
exports.generateEnumValueFunctions = generateEnumValueFunctions;
/**
* Generates a unidirectional function that converts enum string keys to their numeric values.
* Creates getEnumInt(enumType, key) that only accepts string keys and returns numbers.
* Example: getEnumInt('MyEnum', 'VALUE1') => 0
*/
const generateEnumToIntFunctions = (enumData) => {
// Create the union type for EnumType
const enumTypeIdentifier = t.identifier('EnumType');
const enumTypeUnion = t.tsUnionType(enumData.map(enumDef => t.tsLiteralType(t.stringLiteral(enumDef.name))));
const enumTypeAlias = t.tsTypeAliasDeclaration(enumTypeIdentifier, null, enumTypeUnion);
// Create the function parameter and its type
const enumTypeParam = t.identifier('enumType');
const enumTypeParamAnnotation = t.tsTypeAnnotation(t.tsTypeReference(enumTypeIdentifier));
enumTypeParam.typeAnnotation = enumTypeParamAnnotation;
const keyParam = t.identifier('key');
const keyParamAnnotation = t.tsTypeAnnotation(t.tsStringKeyword());
keyParam.typeAnnotation = keyParamAnnotation;
// Create return type annotation
const returnTypeAnnotation = t.tsTypeAnnotation(t.tsNumberKeyword());
// Create the switch cases for the outer switch statement
const outerCases = enumData.map(enumDef => {
const innerCases = Object.entries(enumDef.values).map(([key, value]) => {
return t.switchCase(t.stringLiteral(key), [t.returnStatement(t.numericLiteral(value))]);
});
// Add the default case for the inner switch
innerCases.push(t.switchCase(null, [
t.throwStatement(t.newExpression(t.identifier('Error'), [t.stringLiteral(`Key not recognized in enum ${enumDef.name}`)]))
]));
return t.switchCase(t.stringLiteral(enumDef.name), [
t.blockStatement([t.switchStatement(keyParam, innerCases)])
]);
});
// Add the default case for the outer switch
outerCases.push(t.switchCase(null, [
t.throwStatement(t.newExpression(t.identifier('Error'), [t.stringLiteral('Enum type not recognized')]))
]));
// Create the outer switch statement
const switchStatement = t.switchStatement(enumTypeParam, outerCases);
// Create the function body
const functionBody = t.blockStatement([switchStatement]);
// Create the arrow function expression with return type
const arrowFunctionExpression = t.arrowFunctionExpression([enumTypeParam, keyParam], functionBody);
arrowFunctionExpression.returnType = returnTypeAnnotation;
// Create the variable declarator for the function
const variableDeclarator = t.variableDeclarator(t.identifier('getEnumInt'), arrowFunctionExpression);
// Create the variable declaration (const getEnumInt = ...)
const variableDeclaration = t.variableDeclaration('const', [variableDeclarator]);
// Export the arrow function
const exportedFunction = t.exportNamedDeclaration(variableDeclaration, []);
// Export the type
const exportedEnumTypeAlias = t.exportNamedDeclaration(enumTypeAlias, []);
// Return the entire AST
return [exportedEnumTypeAlias, exportedFunction];
};
exports.generateEnumToIntFunctions = generateEnumToIntFunctions;
/**
* Generates a nested object structure with individual converter functions for each enum.
* Creates enumToIntMap object where each enum has its own converter: enumToIntMap.MyEnum('VALUE1') => 0
* This format provides better type safety and autocomplete for specific enums.
*/
const generateEnumToIntFunctionsNested = (enumData) => {
// Create the union type for EnumType
const enumTypeIdentifier = t.identifier('EnumType');
const enumTypeUnion = t.tsUnionType(enumData.map(enumDef => t.tsLiteralType(t.stringLiteral(enumDef.name))));
const enumTypeAlias = t.tsTypeAliasDeclaration(enumTypeIdentifier, null, enumTypeUnion);
// Create individual enum converter functions
const enumConverters = enumData.map(enumDef => {
// Create the switch cases for this enum
const cases = Object.entries(enumDef.values).map(([key, value]) => {
return t.switchCase(t.stringLiteral(key), [t.returnStatement(t.numericLiteral(value))]);
});
// Add the default case
cases.push(t.switchCase(null, [
t.throwStatement(t.newExpression(t.identifier('Error'), [t.stringLiteral(`Key not recognized in enum ${enumDef.name}`)]))
]));
// Create the switch statement
const switchStatement = t.switchStatement(t.identifier('key'), cases);
// Create the arrow function
const arrowFunction = t.arrowFunctionExpression([t.identifier('key')], t.blockStatement([switchStatement]));
// Add type annotations
const keyParam = arrowFunction.params[0];
keyParam.typeAnnotation = t.tsTypeAnnotation(t.tsStringKeyword());
arrowFunction.returnType = t.tsTypeAnnotation(t.tsNumberKeyword());
// Create the property
return t.objectProperty(t.stringLiteral(enumDef.name), arrowFunction);
});
// Create the object expression
const enumToIntObject = t.objectExpression(enumConverters);
// Create the type for the object
const enumToIntMapType = t.tsTypeLiteral(enumData.map(enumDef => {
const functionType = t.tsFunctionType(null, [t.identifier('key')], t.tsTypeAnnotation(t.tsNumberKeyword()));
const keyParam = functionType.parameters[0];
keyParam.typeAnnotation = t.tsTypeAnnotation(t.tsStringKeyword());
return t.tsPropertySignature(t.stringLiteral(enumDef.name), t.tsTypeAnnotation(functionType));
}));
// Create the type alias for the map
const enumToIntMapTypeAlias = t.tsTypeAliasDeclaration(t.identifier('EnumToIntMap'), null, enumToIntMapType);
// Create the const assertion for better type inference
const enumToIntIdentifier = t.identifier('enumToIntMap');
enumToIntIdentifier.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('EnumToIntMap')));
const enumToIntDeclarator = t.variableDeclarator(enumToIntIdentifier, enumToIntObject);
const enumToIntDeclaration = t.variableDeclaration('const', [enumToIntDeclarator]);
// Export the object
const exportedObject = t.exportNamedDeclaration(enumToIntDeclaration, []);
// Export the types
const exportedEnumType = t.exportNamedDeclaration(enumTypeAlias, []);
const exportedMapType = t.exportNamedDeclaration(enumToIntMapTypeAlias, []);
return [exportedEnumType, exportedMapType, exportedObject];
};
exports.generateEnumToIntFunctionsNested = generateEnumToIntFunctionsNested;
/**
* Generates a nested object structure with functions to convert enum numeric values to string keys.
* Creates enumToStringMap object where each enum has its own converter: enumToStringMap.MyEnum(0) => 'VALUE1'
* Provides type-safe reverse mapping from numbers to string keys.
*/
const generateEnumToStringFunctionsNested = (enumData) => {
// Create the union type for EnumType
const enumTypeIdentifier = t.identifier('EnumType');
const enumTypeUnion = t.tsUnionType(enumData.map(enumDef => t.tsLiteralType(t.stringLiteral(enumDef.name))));
const enumTypeAlias = t.tsTypeAliasDeclaration(enumTypeIdentifier, null, enumTypeUnion);
// Create individual enum converter functions
const enumConverters = enumData.map(enumDef => {
// Create the switch cases for this enum
const cases = Object.entries(enumDef.values).map(([key, value]) => {
return t.switchCase(t.numericLiteral(value), [t.returnStatement(t.stringLiteral(key))]);
});
// Add the default case
cases.push(t.switchCase(null, [
t.throwStatement(t.newExpression(t.identifier('Error'), [t.stringLiteral(`Value not recognized in enum ${enumDef.name}`)]))
]));
// Create the switch statement
const switchStatement = t.switchStatement(t.identifier('value'), cases);
// Create the arrow function
const arrowFunction = t.arrowFunctionExpression([t.identifier('value')], t.blockStatement([switchStatement]));
// Add type annotations
const valueParam = arrowFunction.params[0];
valueParam.typeAnnotation = t.tsTypeAnnotation(t.tsNumberKeyword());
arrowFunction.returnType = t.tsTypeAnnotation(t.tsStringKeyword());
// Create the property
return t.objectProperty(t.stringLiteral(enumDef.name), arrowFunction);
});
// Create the object expression
const enumToStringObject = t.objectExpression(enumConverters);
// Create the type for the object
const enumToStringMapType = t.tsTypeLiteral(enumData.map(enumDef => {
const functionType = t.tsFunctionType(null, [t.identifier('value')], t.tsTypeAnnotation(t.tsStringKeyword()));
const valueParam = functionType.parameters[0];
valueParam.typeAnnotation = t.tsTypeAnnotation(t.tsNumberKeyword());
return t.tsPropertySignature(t.stringLiteral(enumDef.name), t.tsTypeAnnotation(functionType));
}));
// Create the type alias for the map
const enumToStringMapTypeAlias = t.tsTypeAliasDeclaration(t.identifier('EnumToStringMap'), null, enumToStringMapType);
// Create the const assertion for better type inference
const enumToStringIdentifier = t.identifier('enumToStringMap');
enumToStringIdentifier.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('EnumToStringMap')));
const enumToStringDeclarator = t.variableDeclarator(enumToStringIdentifier, enumToStringObject);
const enumToStringDeclaration = t.variableDeclaration('const', [enumToStringDeclarator]);
// Export the object
const exportedObject = t.exportNamedDeclaration(enumToStringDeclaration, []);
// Export the types
const exportedEnumType = t.exportNamedDeclaration(enumTypeAlias, []);
const exportedMapType = t.exportNamedDeclaration(enumToStringMapTypeAlias, []);
return [exportedEnumType, exportedMapType, exportedObject];
};
exports.generateEnumToStringFunctionsNested = generateEnumToStringFunctionsNested;
/**
* Generates a unidirectional function that converts enum numeric values to their string keys.
* Creates getEnumString(enumType, key) that only accepts numbers and returns string keys.
* Example: getEnumString('MyEnum', 0) => 'VALUE1'
*/
const generateEnumToStringFunctions = (enumData) => {
// Create the union type for EnumType
const enumTypeIdentifier = t.identifier('EnumType');
const enumTypeUnion = t.tsUnionType(enumData.map(enumDef => t.tsLiteralType(t.stringLiteral(enumDef.name))));
const enumTypeAlias = t.tsTypeAliasDeclaration(enumTypeIdentifier, null, enumTypeUnion);
// Create the function parameter and its type
const enumTypeParam = t.identifier('enumType');
const enumTypeParamAnnotation = t.tsTypeAnnotation(t.tsTypeReference(enumTypeIdentifier));
enumTypeParam.typeAnnotation = enumTypeParamAnnotation;
const keyParam = t.identifier('key');
const keyParamAnnotation = t.tsTypeAnnotation(t.tsNumberKeyword());
keyParam.typeAnnotation = keyParamAnnotation;
// Create return type annotation
const returnTypeAnnotation = t.tsTypeAnnotation(t.tsStringKeyword());
// Create the switch cases for the outer switch statement
const outerCases = enumData.map(enumDef => {
const innerCases = Object.entries(enumDef.values).map(([key, value]) => {
return t.switchCase(t.numericLiteral(value), [t.returnStatement(t.stringLiteral(key))]);
});
// Add the default case for the inner switch
innerCases.push(t.switchCase(null, [
t.throwStatement(t.newExpression(t.identifier('Error'), [t.stringLiteral(`Value not recognized in enum ${enumDef.name}`)]))
]));
return t.switchCase(t.stringLiteral(enumDef.name), [
t.blockStatement([t.switchStatement(keyParam, innerCases)])
]);
});
// Add the default case for the outer switch
outerCases.push(t.switchCase(null, [
t.throwStatement(t.newExpression(t.identifier('Error'), [t.stringLiteral('Enum type not recognized')]))
]));
// Create the outer switch statement
const switchStatement = t.switchStatement(enumTypeParam, outerCases);
// Create the function body
const functionBody = t.blockStatement([switchStatement]);
// Create the arrow function expression with return type
const arrowFunctionExpression = t.arrowFunctionExpression([enumTypeParam, keyParam], functionBody);
arrowFunctionExpression.returnType = returnTypeAnnotation;
// Create the variable declarator for the function
const variableDeclarator = t.variableDeclarator(t.identifier('getEnumString'), arrowFunctionExpression);
// Create the variable declaration (const getEnumString = ...)
const variableDeclaration = t.variableDeclaration('const', [variableDeclarator]);
// Export the arrow function
const exportedFunction = t.exportNamedDeclaration(variableDeclaration, []);
// Export the type
const exportedEnumTypeAlias = t.exportNamedDeclaration(enumTypeAlias, []);
// Return the entire AST
return [exportedEnumTypeAlias, exportedFunction];
};
exports.generateEnumToStringFunctions = generateEnumToStringFunctions;