| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| // Context parameters are typed as `any` because the generated grammar files |
| // require accepting arbitrary context types at runtime. |
| |
| import TranslateVisitor from './TranslateVisitor.js'; |
| import { TranslatorException } from './TranslatorException.js'; |
| |
| // Steps whose return type needs <object, object> |
| const DOUBLE_GENERIC_STEPS = new Set(['group', 'valueMap']); |
| |
| /** |
| * Converts a Gremlin traversal string into a C# source code representation. |
| * Mirrors the Java DotNetTranslateVisitor. |
| */ |
| export default class DotNetTranslateVisitor extends TranslateVisitor { |
| |
| constructor(graphTraversalSourceName: string = 'g') { |
| super(graphTraversalSourceName); |
| } |
| |
| protected override processGremlinSymbol(step: string): string { |
| return SymbolHelper.toCSharp(step); |
| } |
| |
| protected override getCardinalityFunctionClass(): string { |
| return 'CardinalityValue'; |
| } |
| |
| /** |
| * .NET enum values are capitalized but do NOT go through processGremlinSymbol, |
| * since the SymbolHelper mappings (bigdecimal→BigDecimal etc.) don't apply to enums. |
| */ |
| protected override appendExplicitNaming(txt: string, prefix: string): void { |
| if (!txt.startsWith(prefix + '.')) { |
| this.sb.push(prefix); |
| this.sb.push('.'); |
| this.sb.push(capitalize(txt)); |
| } else { |
| const parts = txt.split('.'); |
| this.sb.push(parts[0]); |
| this.sb.push('.'); |
| this.sb.push(capitalize(parts[1])); |
| } |
| } |
| |
| visitTraversalGType(ctx: any): void { |
| const parts: string[] = ctx.getText().split('.'); |
| this.sb.push(this.processGremlinSymbol(parts[0])); |
| this.sb.push('.'); |
| this.sb.push(this.processGremlinSymbol(parts[1].toLowerCase())); |
| } |
| |
| visitTraversalDirection(ctx: any): void { |
| const direction = ctx.getText().toLowerCase(); |
| this.sb.push('Direction.'); |
| if (direction.includes('out')) this.sb.push('Out'); |
| else if (direction.includes('in')) this.sb.push('In'); |
| else if (direction.includes('from')) this.sb.push('From'); |
| else if (direction.includes('to')) this.sb.push('To'); |
| else this.sb.push('Both'); |
| } |
| |
| visitTraversalDirectionShort(ctx: any): void { |
| this.visitTraversalDirection(ctx); |
| } |
| |
| visitTraversalDirectionLong(ctx: any): void { |
| this.visitTraversalDirection(ctx); |
| } |
| |
| visitNanLiteral(_ctx: any): void { |
| this.sb.push('Double.NaN'); |
| } |
| |
| visitInfLiteral(ctx: any): void { |
| if (ctx.SignedInfLiteral() != null && ctx.SignedInfLiteral().getText() === '-Infinity') { |
| this.sb.push('Double.NegativeInfinity'); |
| } else { |
| this.sb.push('Double.PositiveInfinity'); |
| } |
| } |
| |
| visitIntegerLiteral(ctx: any): void { |
| const integerLiteral: string = ctx.getText().toLowerCase(); |
| const lastChar = integerLiteral[integerLiteral.length - 1]; |
| |
| if (!/[a-z]/.test(lastChar)) { |
| this.sb.push(integerLiteral); |
| return; |
| } |
| |
| const num = integerLiteral.slice(0, -1); |
| switch (lastChar) { |
| case 'b': |
| this.sb.push('(sbyte) '); |
| this.sb.push(num); |
| break; |
| case 's': |
| this.sb.push('(short) '); |
| this.sb.push(num); |
| break; |
| case 'i': |
| this.sb.push(num); |
| break; |
| case 'l': |
| this.sb.push(integerLiteral); // keep the 'l' suffix for C# |
| break; |
| case 'n': |
| this.sb.push('BigInteger.Parse("'); |
| this.sb.push(num); |
| this.sb.push('")'); |
| break; |
| default: |
| this.sb.push(integerLiteral); |
| } |
| } |
| |
| visitFloatLiteral(ctx: any): void { |
| if (ctx.infLiteral() != null) { this.visit(ctx.infLiteral()); return; } |
| if (ctx.nanLiteral() != null) { this.visit(ctx.nanLiteral()); return; } |
| |
| const floatLiteral: string = ctx.getText().toLowerCase(); |
| const lastChar = floatLiteral[floatLiteral.length - 1]; |
| |
| if (!/[a-z]/.test(lastChar)) { |
| this.sb.push(floatLiteral); |
| return; |
| } |
| |
| const num = floatLiteral.slice(0, -1); |
| switch (lastChar) { |
| case 'f': |
| case 'd': |
| this.sb.push(floatLiteral); // keep the f/d suffix for C# |
| break; |
| case 'm': |
| this.sb.push('(decimal) '); |
| this.sb.push(num); |
| break; |
| default: |
| this.sb.push(floatLiteral); |
| } |
| } |
| |
| visitDateLiteral(ctx: any): void { |
| const dtString: string = ctx.getChild(2).getText(); |
| const inner = TranslateVisitor.removeFirstAndLastCharacters(dtString); |
| this.sb.push('DateTimeOffset.Parse("'); |
| this.sb.push(formatDatetimeJavaStyle(inner)); |
| this.sb.push('")'); |
| } |
| |
| visitGenericRangeLiteral(_ctx: any): void { |
| throw new TranslatorException('.NET does not support range literals'); |
| } |
| |
| visitGenericSetLiteral(ctx: any): void { |
| this.sb.push('new HashSet<object> { '); |
| const literals: any[] = ctx.genericLiteral(); |
| for (let i = 0; i < literals.length; i++) { |
| this.visit(literals[i]); |
| if (i < literals.length - 1) this.sb.push(', '); |
| } |
| this.sb.push(' }'); |
| } |
| |
| visitGenericCollectionLiteral(ctx: any): void { |
| this.sb.push('new List<object> { '); |
| const literals: any[] = ctx.genericLiteral(); |
| for (let i = 0; i < literals.length; i++) { |
| this.visit(literals[i]); |
| if (i < literals.length - 1) this.sb.push(', '); |
| } |
| this.sb.push(' }'); |
| } |
| |
| visitGenericMapLiteral(ctx: any): void { |
| this.sb.push('new Dictionary<object, object> {'); |
| const entries: any[] = ctx.mapEntry(); |
| for (let i = 0; i < entries.length; i++) { |
| this.visit(entries[i]); |
| if (i < entries.length - 1) this.sb.push(', '); |
| } |
| this.sb.push('}'); |
| } |
| |
| visitMapEntry(ctx: any): void { |
| this.sb.push('{ '); |
| this.visit(ctx.mapKey()); |
| this.sb.push(', '); |
| this.visit(ctx.genericLiteral()); |
| this.sb.push(' }'); |
| } |
| |
| visitMapKey(ctx: any): void { |
| const keyIndex = (ctx.LPAREN() != null && ctx.RPAREN() != null) ? 1 : 0; |
| this.visit(ctx.getChild(keyIndex)); |
| } |
| |
| visitUuidLiteral(ctx: any): void { |
| if (ctx.stringLiteral() == null) { |
| this.sb.push('Guid.NewGuid()'); |
| return; |
| } |
| this.sb.push('Guid.Parse('); |
| this.sb.push(ctx.stringLiteral().getText()); |
| this.sb.push(')'); |
| } |
| |
| visitCharacterLiteral(ctx: any): void { |
| const text: string = ctx.getText(); |
| const withoutSuffix = text.substring(0, text.length - 1); |
| const inner = TranslateVisitor.removeFirstAndLastCharacters(withoutSuffix); |
| this.sb.push("'"); |
| this.sb.push(inner); |
| this.sb.push("'"); |
| } |
| |
| visitDurationLiteral(ctx: any): void { |
| const seconds = parseInt(ctx.integerLiteral(0).getText(), 10); |
| const nanos = parseInt(ctx.integerLiteral(1).getText(), 10); |
| const isPositive = ctx.booleanLiteral() === null || |
| ctx.booleanLiteral().getText() === 'true'; |
| // Convert to ticks: 1 tick = 100 nanoseconds, 1 second = 10,000,000 ticks |
| const ticks = seconds * 10_000_000 + Math.floor(nanos / 100); |
| this.sb.push(`TimeSpan.FromTicks(${ticks}L)`); |
| if (!isPositive) { |
| this.sb.push('.Negate()'); |
| } |
| } |
| |
| visitBinaryLiteral(ctx: any): void { |
| this.sb.push('Convert.FromBase64String('); |
| this.sb.push(ctx.stringLiteral().getText()); |
| this.sb.push(')'); |
| } |
| |
| visitClassType(ctx: any): void { |
| this.sb.push('typeof('); |
| this.sb.push(ctx.getText()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalStrategy(ctx: any): void { |
| if (ctx.getChildCount() === 1) { |
| this.sb.push('new '); |
| this.sb.push(ctx.getText()); |
| this.sb.push('()'); |
| return; |
| } |
| |
| const firstText = ctx.getChild(0).getText(); |
| const strategyName = firstText === 'new' ? ctx.getChild(1).getText() : firstText; |
| this.sb.push('new '); |
| this.sb.push(strategyName); |
| this.sb.push('('); |
| |
| const configs: any[] = ctx.configuration(); |
| const isOptionsStrategy = ctx.children?.some((c: any) => c.getText() === 'OptionsStrategy'); |
| |
| if (configs.length > 0 && isOptionsStrategy) { |
| this.sb.push('new Dictionary<string, object> {'); |
| for (const cfg of configs) { |
| this.sb.push('{"'); |
| this.sb.push(cfg.getChild(0).getText()); |
| this.sb.push('",'); |
| this.visit(cfg.getChild(2)); |
| this.sb.push('},'); |
| } |
| this.sb.push('}'); |
| } else { |
| for (let ix = 0; ix < configs.length; ix++) { |
| this.visit(configs[ix]); |
| if (ix < configs.length - 1) this.sb.push(', '); |
| } |
| } |
| |
| this.sb.push(')'); |
| } |
| |
| visitConfiguration(ctx: any): void { |
| const key: string = ctx.getChild(0).getText(); |
| this.sb.push(key); |
| this.sb.push(': '); |
| |
| const startIdx = this.sb.length; |
| this.visit(ctx.getChild(2)); |
| |
| if (key === 'readPartitions') { |
| const added = this.sb.splice(startIdx); |
| this.sb.push(added.join('').replace('List<object>', 'HashSet<string>')); |
| } else if (key === 'keys') { |
| const added = this.sb.splice(startIdx); |
| const joined = added.join(''); |
| this.sb.push(joined.includes('HashSet<object>') ? joined.replace('HashSet<object>', 'HashSet<string>') : joined); |
| } |
| } |
| |
| visitStringNullableArgumentVarargs(ctx: any): void { |
| const n = ctx.getChildCount(); |
| for (let ix = 0; ix < n; ix++) { |
| const child = ctx.getChild(ix); |
| if (child.constructor?.name === 'StringNullableArgumentContext') { |
| this.tryAppendCastToString_StringNullableArg(child); |
| } |
| this.visit(child); |
| } |
| } |
| |
| // ─── handleGenerics helpers ───────────────────────────────────────────── |
| |
| private handleGenerics(ctx: any): void { |
| const step: string = ctx.getChild(0).getText(); |
| this.sb.push(capitalize(step)); |
| this.sb.push(DOUBLE_GENERIC_STEPS.has(step) ? '<object, object>' : '<object>'); |
| for (let ix = 1; ix < ctx.getChildCount(); ix++) { |
| this.visit(ctx.getChild(ix)); |
| } |
| } |
| |
| private handleLongArguments(ctx: any): void { |
| const step: string = ctx.getChild(0).getText(); |
| this.sb.push(capitalize(step)); |
| this.sb.push('<object>'); |
| for (let ix = 1; ix < ctx.getChildCount(); ix++) { |
| const child = ctx.getChild(ix); |
| if (child.constructor?.name === 'IntegerArgumentContext') { |
| this.tryAppendCastToLong_IntArg(child); |
| } |
| this.visit(child); |
| } |
| } |
| |
| // ─── Cast helpers ──────────────────────────────────────────────────────── |
| |
| private tryAppendCastToLong_IntArg(ctx: any): void { |
| if (ctx?.variable() != null) this.sb.push('(long) '); |
| } |
| |
| private tryAppendCastToString_StringArg(ctx: any): void { |
| if (ctx?.variable() != null || ctx?.stringLiteral() != null) this.sb.push('(string) '); |
| } |
| |
| private tryAppendCastToString_StringNullableLit(ctx: any): void { |
| if (ctx?.K_NULL != null && ctx.K_NULL() != null) this.sb.push('(string) '); |
| } |
| |
| private tryAppendCastToString_StringNullableArg(ctx: any): void { |
| if (ctx?.variable() != null || |
| (ctx?.stringNullableLiteral() != null && ctx.stringNullableLiteral()?.K_NULL != null && ctx.stringNullableLiteral().K_NULL() != null)) { |
| this.sb.push('(string) '); |
| } |
| } |
| |
| private tryAppendCastToObject_GenericArg(ctx: any): void { |
| if (ctx?.variable() != null || |
| (ctx?.genericLiteral() != null && ctx.genericLiteral()?.nullLiteral != null && ctx.genericLiteral().nullLiteral() != null)) { |
| this.sb.push('(object) '); |
| } |
| } |
| |
| private tryAppendCastToObject_GenericLit(ctx: any): void { |
| if (ctx?.nullLiteral != null && ctx.nullLiteral() != null) this.sb.push('(object) '); |
| } |
| |
| // ─── isCalledAsFirstStepInAnonymousTraversal ───────────────────────────── |
| |
| private isCalledAsFirstStepInAnonymousTraversal(ctx: any): boolean { |
| // ctx = traversalMethod_fold_EmptyContext |
| // parent = traversalMethodContext → chainedTraversalContext → nestedTraversalContext |
| const parent = ctx.parent; |
| if (!parent) return false; |
| const parentParent = parent.parent; // ChainedTraversalContext |
| if (!parentParent) return false; |
| const parentParentParent = parentParent.parent; // should be NestedTraversalContext |
| if (parentParentParent?.constructor?.name !== 'NestedTraversalContext') return false; |
| // Check if ctx is the first step: parentParent.child(0).child(0) === ctx |
| const firstChild = parentParent.getChild(0); |
| const firstGrandchild = firstChild?.getChild(0); |
| return firstGrandchild === ctx; |
| } |
| |
| // ─── Source spawn method overrides ────────────────────────────────────── |
| |
| visitTraversalSourceSpawnMethod_inject(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalSourceSpawnMethod_io(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalSourceSpawnMethod_union(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalSourceSpawnMethod_call_empty(ctx: any): void { this.handleGenerics(ctx); } |
| |
| visitTraversalSourceSpawnMethod_addV(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| for (let ix = 1; ix < ctx.getChildCount(); ix++) { |
| const child = ctx.getChild(ix); |
| if (child.constructor?.name === 'StringArgumentContext') this.tryAppendCastToString_StringArg(child); |
| this.visit(child); |
| } |
| } |
| |
| visitTraversalSourceSpawnMethod_addE(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| for (let ix = 1; ix < ctx.getChildCount(); ix++) { |
| const child = ctx.getChild(ix); |
| if (child.constructor?.name === 'StringArgumentContext') this.tryAppendCastToString_StringArg(child); |
| this.visit(child); |
| } |
| } |
| |
| visitTraversalSourceSpawnMethod_call_string(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('<object>'); |
| this.sb.push('((string) '); |
| this.visit(ctx.stringLiteral()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalSourceSpawnMethod_call_string_map(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('<object>('); |
| this.visit(ctx.stringLiteral()); |
| this.sb.push(', (IDictionary<object, object>) '); |
| this.visit(ctx.genericMapArgument()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalSourceSpawnMethod_call_string_traversal(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('<object>('); |
| this.visit(ctx.stringLiteral()); |
| this.sb.push(', (ITraversal) '); |
| this.visit(ctx.nestedTraversal()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalSourceSpawnMethod_call_string_map_traversal(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('<object>('); |
| this.visit(ctx.stringLiteral()); |
| this.sb.push(', (IDictionary<object, object>) '); |
| this.visit(ctx.genericMapArgument()); |
| this.sb.push(', (ITraversal) '); |
| this.visit(ctx.nestedTraversal()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalSourceSpawnMethod_mergeV_Map(ctx: any): void { |
| this.visit(ctx.getChild(0)); |
| this.sb.push('((IDictionary<object, object>) '); |
| this.visit(ctx.genericMapNullableArgument()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalSourceSpawnMethod_mergeV_Traversal(ctx: any): void { |
| this.visit(ctx.getChild(0)); |
| this.sb.push('((ITraversal) '); |
| this.visit(ctx.nestedTraversal()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalSourceSpawnMethod_mergeE_Map(ctx: any): void { |
| this.visit(ctx.getChild(0)); |
| this.sb.push('((IDictionary<object, object>) '); |
| this.visit(ctx.genericMapNullableArgument()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalSourceSpawnMethod_mergeE_Traversal(ctx: any): void { |
| this.visit(ctx.getChild(0)); |
| this.sb.push('((ITraversal) '); |
| this.visit(ctx.nestedTraversal()); |
| this.sb.push(')'); |
| } |
| |
| // ─── Traversal method overrides — handleGenerics ───────────────────────── |
| |
| visitTraversalMethod_asString_Scope(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_branch(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_cap(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_choose_Function(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_choose_Predicate_Traversal(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_choose_Predicate_Traversal_Traversal(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_choose_Traversal(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_choose_Traversal_Traversal(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_choose_Traversal_Traversal_Traversal(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_coalesce(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_constant(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_elementMap(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_flatMap(ctx: any): void { this.handleGenerics(ctx); } |
| |
| visitTraversalMethod_fold_Empty(ctx: any): void { |
| if (this.isCalledAsFirstStepInAnonymousTraversal(ctx)) { |
| this.handleGenerics(ctx); |
| } else { |
| this.visitChildren(ctx); // base: just output Fold() |
| } |
| } |
| |
| visitTraversalMethod_fold_Object_BiFunction(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_group_Empty(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_groupCount_Empty(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_index(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_length_Scope(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_local(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_lTrim_Scope(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_map(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_match(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_max_Empty(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_max_Scope(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_mean_Empty(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_mean_Scope(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_min_Empty(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_min_Scope(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_optional(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_profile_Empty(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_project(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_properties(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_propertyMap(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_replace_Scope_String_String(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_rTrim_Scope(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_sack_Empty(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_select_Column(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_select_Pop_String(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_select_Pop_String_String_String(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_select_Pop_Traversal(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_select_String(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_select_String_String_String(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_select_Traversal(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_split_Scope_String(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_substring_Scope_int(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_substring_Scope_int_int(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_sum_Empty(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_sum_Scope(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_tail_Empty(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_tail_Scope(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_toLower_Scope(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_toUpper_Scope(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_tree_Empty(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_trim_Scope(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_unfold(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_union(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_value(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_valueMap_String(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_valueMap_boolean_String(ctx: any): void { this.handleGenerics(ctx); } |
| visitTraversalMethod_values(ctx: any): void { this.handleGenerics(ctx); } |
| |
| // ─── Traversal method overrides — handleLongArguments ──────────────────── |
| |
| visitTraversalMethod_limit_long(ctx: any): void { this.handleLongArguments(ctx); } |
| visitTraversalMethod_limit_Scope_long(ctx: any): void { this.handleLongArguments(ctx); } |
| visitTraversalMethod_range_long_long(ctx: any): void { this.handleLongArguments(ctx); } |
| visitTraversalMethod_range_Scope_long_long(ctx: any): void { this.handleLongArguments(ctx); } |
| visitTraversalMethod_skip_long(ctx: any): void { this.handleLongArguments(ctx); } |
| visitTraversalMethod_skip_Scope_long(ctx: any): void { this.handleLongArguments(ctx); } |
| visitTraversalMethod_tail_long(ctx: any): void { this.handleLongArguments(ctx); } |
| visitTraversalMethod_tail_Scope_long(ctx: any): void { this.handleLongArguments(ctx); } |
| |
| // ─── addV / addE (string cast) ─────────────────────────────────────────── |
| |
| visitTraversalMethod_addV_String(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| for (let ix = 1; ix < ctx.getChildCount(); ix++) { |
| const child = ctx.getChild(ix); |
| if (child.constructor?.name === 'StringArgumentContext') this.tryAppendCastToString_StringArg(child); |
| this.visit(child); |
| } |
| } |
| |
| visitTraversalMethod_addE_String(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| for (let ix = 1; ix < ctx.getChildCount(); ix++) { |
| const child = ctx.getChild(ix); |
| if (child.constructor?.name === 'StringArgumentContext') this.tryAppendCastToString_StringArg(child); |
| this.visit(child); |
| } |
| } |
| |
| // ─── call variants ─────────────────────────────────────────────────────── |
| |
| visitTraversalMethod_call_string(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('<object>((string) '); |
| this.visit(ctx.stringLiteral()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_call_string_map(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('<object>('); |
| this.visit(ctx.stringLiteral()); |
| this.sb.push(', (IDictionary<object, object>) '); |
| this.visit(ctx.genericMapArgument()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_call_string_traversal(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('<object>('); |
| this.visit(ctx.stringLiteral()); |
| this.sb.push(', (ITraversal) '); |
| this.visit(ctx.nestedTraversal()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_call_string_map_traversal(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('<object>('); |
| this.visit(ctx.stringLiteral()); |
| this.sb.push(', (IDictionary<object, object>) '); |
| this.visit(ctx.genericMapArgument()); |
| this.sb.push(', (ITraversal) '); |
| this.visit(ctx.nestedTraversal()); |
| this.sb.push(')'); |
| } |
| |
| // ─── has family ────────────────────────────────────────────────────────── |
| |
| visitTraversalMethod_has_String_Object(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('('); |
| this.tryAppendCastToString_StringNullableLit(ctx.stringNullableLiteral()); |
| this.visit(ctx.stringNullableLiteral()); |
| this.sb.push(', '); |
| this.tryAppendCastToObject_GenericArg(ctx.genericArgument()); |
| this.visit(ctx.genericArgument()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_has_String_P(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('('); |
| this.tryAppendCastToString_StringNullableLit(ctx.stringNullableLiteral()); |
| this.visit(ctx.stringNullableLiteral()); |
| this.sb.push(', '); |
| this.visit(ctx.traversalPredicate()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_has_String_String_Object(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('('); |
| this.tryAppendCastToString_StringNullableArg(ctx.stringNullableArgument()); |
| this.visit(ctx.stringNullableArgument()); |
| this.sb.push(', '); |
| this.tryAppendCastToString_StringNullableLit(ctx.stringNullableLiteral()); |
| this.visit(ctx.stringNullableLiteral()); |
| this.sb.push(', '); |
| this.tryAppendCastToObject_GenericArg(ctx.genericArgument()); |
| this.visit(ctx.genericArgument()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_has_String_String_P(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('('); |
| this.tryAppendCastToString_StringNullableArg(ctx.stringNullableArgument()); |
| this.visit(ctx.stringNullableArgument()); |
| this.sb.push(', '); |
| this.tryAppendCastToString_StringNullableLit(ctx.stringNullableLiteral()); |
| this.visit(ctx.stringNullableLiteral()); |
| this.sb.push(', '); |
| this.visit(ctx.traversalPredicate()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_has_T_Object(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('('); |
| this.visit(ctx.traversalT()); |
| this.sb.push(', '); |
| this.tryAppendCastToObject_GenericArg(ctx.genericArgument()); |
| this.visit(ctx.genericArgument()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_has_T_P(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('('); |
| this.visit(ctx.traversalT()); |
| this.sb.push(', '); |
| this.visit(ctx.traversalPredicate()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_hasKey_P(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('('); |
| this.visit(ctx.traversalPredicate()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_hasKey_String_String(ctx: any): void { |
| // single arg: add (string) cast; multiple args: no cast |
| if (ctx.stringNullableLiteralVarargs() == null || ctx.stringNullableLiteralVarargs().getChildCount() === 0) { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('('); |
| this.tryAppendCastToString_StringNullableLit(ctx.stringNullableLiteral()); |
| this.visit(ctx.stringNullableLiteral()); |
| this.sb.push(')'); |
| } else { |
| this.visitChildren(ctx); |
| } |
| } |
| |
| visitTraversalMethod_hasValue_Object_Object(ctx: any): void { |
| // single arg: add (object) cast; multiple args: no cast |
| if (ctx.genericArgumentVarargs() == null || ctx.genericArgumentVarargs().getChildCount() === 0) { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('('); |
| this.tryAppendCastToObject_GenericArg(ctx.genericArgument()); |
| this.visit(ctx.genericArgument()); |
| this.sb.push(')'); |
| } else { |
| this.visitChildren(ctx); |
| } |
| } |
| |
| visitTraversalMethod_hasValue_P(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('('); |
| this.visit(ctx.traversalPredicate()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_hasLabel_P(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('('); |
| this.visit(ctx.traversalPredicate()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_hasLabel_String_String(ctx: any): void { |
| const step = capitalize(ctx.getChild(0).getText()); |
| if (ctx.stringNullableArgumentVarargs() == null || ctx.stringNullableArgumentVarargs().getChildCount() === 0) { |
| // single arg: add (string) cast if variable or null |
| this.sb.push(step); |
| this.sb.push('('); |
| this.tryAppendCastToString_StringNullableArg(ctx.stringNullableArgument()); |
| this.visit(ctx.stringNullableArgument()); |
| this.sb.push(')'); |
| } else { |
| // multiple args |
| this.sb.push(step); |
| this.sb.push('('); |
| this.tryAppendCastToString_StringNullableArg(ctx.stringNullableArgument()); |
| this.visit(ctx.stringNullableArgument()); |
| if (ctx.stringNullableArgumentVarargs().getChildCount() > 0) this.sb.push(', '); |
| this.visit(ctx.stringNullableArgumentVarargs()); |
| this.sb.push(')'); |
| } |
| } |
| |
| // ─── mergeV / mergeE ───────────────────────────────────────────────────── |
| |
| visitTraversalMethod_mergeV_Map(ctx: any): void { |
| this.visit(ctx.getChild(0)); |
| this.sb.push('((IDictionary<object, object>) '); |
| this.visit(ctx.genericMapNullableArgument()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_mergeV_Traversal(ctx: any): void { |
| this.visit(ctx.getChild(0)); |
| this.sb.push('((ITraversal) '); |
| this.visit(ctx.nestedTraversal()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_mergeE_Map(ctx: any): void { |
| this.visit(ctx.getChild(0)); |
| this.sb.push('((IDictionary<object, object>) '); |
| this.visit(ctx.genericMapNullableArgument()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_mergeE_Traversal(ctx: any): void { |
| this.visit(ctx.getChild(0)); |
| this.sb.push('((ITraversal) '); |
| this.visit(ctx.nestedTraversal()); |
| this.sb.push(')'); |
| } |
| |
| // ─── option ───────────────────────────────────────────────────────────── |
| |
| visitTraversalMethod_option_Merge_Map(ctx: any): void { |
| this.visit(ctx.getChild(0)); |
| this.sb.push('('); |
| this.visit(ctx.traversalMerge()); |
| this.sb.push(', (IDictionary<object, object>) '); |
| this.visit(ctx.genericMapNullableArgument()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_option_Merge_Traversal(ctx: any): void { |
| this.visit(ctx.getChild(0)); |
| this.sb.push('('); |
| this.visit(ctx.traversalMerge()); |
| this.sb.push(', (ITraversal) '); |
| this.visit(ctx.nestedTraversal()); |
| this.sb.push(')'); |
| } |
| |
| visitTraversalMethod_option_Object_Traversal(ctx: any): void { |
| // Only add (ITraversal) cast when the object is a traversalMerge |
| const argIsTraversalMerge = ctx.genericArgument()?.genericLiteral()?.traversalMerge != null && |
| ctx.genericArgument().genericLiteral().traversalMerge() != null; |
| if (argIsTraversalMerge) { |
| this.visit(ctx.getChild(0)); |
| this.sb.push('('); |
| this.visit(ctx.genericArgument()); |
| this.sb.push(', (ITraversal) '); |
| this.visit(ctx.nestedTraversal()); |
| this.sb.push(')'); |
| } else { |
| this.visitChildren(ctx); |
| } |
| } |
| |
| // ─── property ──────────────────────────────────────────────────────────── |
| |
| visitTraversalMethod_property_Cardinality_Object_Object_Object(ctx: any): void { |
| if (ctx.genericArgumentVarargs() == null || ctx.genericArgumentVarargs().getChildCount() === 0) { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('('); |
| this.visit(ctx.traversalCardinality()); |
| this.sb.push(', '); |
| this.tryAppendCastToObject_GenericLit(ctx.genericLiteral()); |
| this.visit(ctx.genericLiteral()); |
| this.sb.push(', '); |
| this.tryAppendCastToObject_GenericArg(ctx.genericArgument()); |
| this.visit(ctx.genericArgument()); |
| this.sb.push(')'); |
| } else { |
| this.visitChildren(ctx); |
| } |
| } |
| |
| // ─── conjoin ───────────────────────────────────────────────────────────── |
| |
| visitTraversalMethod_conjoin_String(ctx: any): void { |
| this.sb.push(capitalize(ctx.getChild(0).getText())); |
| this.sb.push('('); |
| this.tryAppendCastToString_StringLit(ctx.stringLiteral()); |
| this.visit(ctx.stringLiteral()); |
| this.sb.push(')'); |
| } |
| |
| private tryAppendCastToString_StringLit(ctx: any): void { |
| if (ctx != null) this.sb.push('(string) '); |
| } |
| } |
| |
| // ─── Helpers ───────────────────────────────────────────────────────────────── |
| |
| function capitalize(s: string): string { |
| if (!s) return s; |
| return s.charAt(0).toUpperCase() + s.slice(1); |
| } |
| |
| /** |
| * Formats a datetime string the same way Java's OffsetDateTime.toString() does: |
| * - Truncates seconds if both seconds and milliseconds are 0 |
| * - Uses 'Z' for UTC offset |
| */ |
| function formatDatetimeJavaStyle(s: string): string { |
| const d = new Date(s); |
| if (isNaN(d.getTime())) { |
| throw new TranslatorException(`Invalid datetime: ${s}`); |
| } |
| const year = d.getUTCFullYear().toString().padStart(4, '0'); |
| const month = (d.getUTCMonth() + 1).toString().padStart(2, '0'); |
| const day = d.getUTCDate().toString().padStart(2, '0'); |
| const hours = d.getUTCHours().toString().padStart(2, '0'); |
| const minutes = d.getUTCMinutes().toString().padStart(2, '0'); |
| const seconds = d.getUTCSeconds(); |
| const millis = d.getUTCMilliseconds(); |
| |
| let result = `${year}-${month}-${day}T${hours}:${minutes}`; |
| if (seconds !== 0 || millis !== 0) { |
| result += ':' + seconds.toString().padStart(2, '0'); |
| if (millis !== 0) { |
| result += '.' + millis.toString().padStart(3, '0').replace(/0+$/, ''); |
| } |
| } |
| result += 'Z'; |
| return result; |
| } |
| |
| class SymbolHelper { |
| private static readonly TO_CS_MAP: Record<string, string> = { |
| 'graphml': 'GraphML', |
| 'graphson': 'GraphSON', |
| 'bigdecimal': 'BigDecimal', |
| 'bigint': 'BigInt', |
| 'datetime': 'DateTime', |
| 'uuid': 'UUID', |
| 'vproperty': 'VProperty', |
| }; |
| |
| static toCSharp(symbol: string): string { |
| return SymbolHelper.TO_CS_MAP[symbol] ?? capitalize(symbol); |
| } |
| } |