@shapeshift-labs/frontier-lang-compiler 0.2.28 → 0.2.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -333,6 +333,7 @@ Use injected parser adapters when a real language parser is available but should
333
333
  import {
334
334
  createBabelNativeImporterAdapter,
335
335
  createClangAstNativeImporterAdapter,
336
+ createGoAstNativeImporterAdapter,
336
337
  createPythonAstNativeImporterAdapter,
337
338
  createRustSynNativeImporterAdapter,
338
339
  importNativeProject,
@@ -354,6 +355,10 @@ const clangAstAdapter = createClangAstNativeImporterAdapter({
354
355
  cStandard: 'c11',
355
356
  compileFlags: ['-std=c11']
356
357
  });
358
+ const goAstAdapter = createGoAstNativeImporterAdapter({
359
+ parserModule: hostGoAstParser,
360
+ goVersion: '1.22'
361
+ });
357
362
 
358
363
  const imported = await runNativeImporterAdapter(babelAdapter, {
359
364
  sourcePath: 'src/todo.ts',
@@ -362,12 +367,13 @@ const imported = await runNativeImporterAdapter(babelAdapter, {
362
367
 
363
368
  const project = await importNativeProject({
364
369
  projectRoot: 'src',
365
- adapters: [babelAdapter, pythonAstAdapter, rustSynAdapter, clangAstAdapter],
370
+ adapters: [babelAdapter, pythonAstAdapter, rustSynAdapter, clangAstAdapter, goAstAdapter],
366
371
  sources: [
367
372
  { language: 'typescript', adapter: babelAdapter.id, sourcePath: 'src/todo.ts', sourceText },
368
373
  { language: 'python', adapter: pythonAstAdapter.id, sourcePath: 'tools/todo.py', sourceText: pythonSource },
369
374
  { language: 'rust', adapter: rustSynAdapter.id, sourcePath: 'src/todo.rs', sourceText: rustSource },
370
- { language: 'c', adapter: clangAstAdapter.id, sourcePath: 'native/todo.c', sourceText: cSource }
375
+ { language: 'c', adapter: clangAstAdapter.id, sourcePath: 'native/todo.c', sourceText: cSource },
376
+ { language: 'go', adapter: goAstAdapter.id, sourcePath: 'cmd/todo/main.go', sourceText: goSource }
371
377
  ]
372
378
  });
373
379
 
@@ -389,6 +395,7 @@ The built-in adapter factories are dependency-light wrappers for caller-owned pa
389
395
  - `createPythonAstNativeImporterAdapter`
390
396
  - `createRustSynNativeImporterAdapter`
391
397
  - `createClangAstNativeImporterAdapter`
398
+ - `createGoAstNativeImporterAdapter`
392
399
  - `createTreeSitterNativeImporterAdapter`
393
400
 
394
401
  Adapter summaries include a structured `coverage` record so merge queues can distinguish exact parser AST imports from declaration scans. The record declares exactness, parser token/trivia support, diagnostics support, source-range and generated-range support, and semantic coverage. Built-in wrappers normalize native AST/CST nodes and declaration-level semantic indexes; they do not claim resolved references, types, control flow, generated ranges, or token/trivia fidelity unless the host adapter supplies that evidence.
package/bench/smoke.mjs CHANGED
@@ -4,6 +4,7 @@ import {
4
4
  compileFrontierSource,
5
5
  createClangAstNativeImporterAdapter,
6
6
  createEstreeNativeImporterAdapter,
7
+ createGoAstNativeImporterAdapter,
7
8
  createNativeImportCoverageMatrix,
8
9
  createNativeParserAstFormatMatrix,
9
10
  createProjectionTargetLossMatrix,
@@ -80,7 +81,7 @@ const matrixDurationMs = performance.now() - matrixStart;
80
81
  const parserFormatMatrixStart = performance.now();
81
82
  const parserFormatMatrix = createNativeParserAstFormatMatrix({
82
83
  imports: nativeImportResults,
83
- adapters: [estreeAdapter, createPythonAstNativeImporterAdapter(), createRustSynNativeImporterAdapter(), createClangAstNativeImporterAdapter()]
84
+ adapters: [estreeAdapter, createPythonAstNativeImporterAdapter(), createRustSynNativeImporterAdapter(), createClangAstNativeImporterAdapter(), createGoAstNativeImporterAdapter()]
84
85
  });
85
86
  const parserFormatMatrixDurationMs = performance.now() - parserFormatMatrixStart;
86
87
 
package/dist/index.d.ts CHANGED
@@ -1435,6 +1435,36 @@ export interface ClangAstNativeImporterAdapterOptions {
1435
1435
  readonly maxNodes?: number;
1436
1436
  }
1437
1437
 
1438
+ export interface GoAstNativeImporterAdapterOptions {
1439
+ readonly id?: string;
1440
+ readonly language?: FrontierSourceLanguage;
1441
+ readonly parser?: string;
1442
+ readonly version?: string;
1443
+ readonly capabilities?: readonly string[];
1444
+ readonly coverage?: NativeImporterAdapterCoverageInput;
1445
+ readonly supportedExtensions?: readonly string[];
1446
+ readonly diagnostics?: readonly NativeImporterAdapterDiagnostic[];
1447
+ readonly ast?: unknown;
1448
+ readonly file?: unknown;
1449
+ readonly sourceFile?: unknown;
1450
+ readonly package?: unknown;
1451
+ readonly parse?: (sourceText: string, options: Record<string, unknown>) => unknown;
1452
+ readonly parserModule?: { readonly parse: (sourceText: string, options: Record<string, unknown>) => unknown };
1453
+ readonly goAst?: { readonly parse: (sourceText: string, options: Record<string, unknown>) => unknown };
1454
+ readonly goParser?: { readonly parse: (sourceText: string, options: Record<string, unknown>) => unknown };
1455
+ readonly parserOptions?: Record<string, unknown>;
1456
+ readonly mode?: string | number;
1457
+ readonly goVersion?: string;
1458
+ readonly packageName?: string;
1459
+ readonly fileSet?: unknown;
1460
+ readonly fset?: unknown;
1461
+ readonly includeComments?: boolean;
1462
+ readonly buildTags?: readonly string[];
1463
+ readonly generated?: boolean;
1464
+ readonly typeEvidence?: unknown;
1465
+ readonly maxNodes?: number;
1466
+ }
1467
+
1438
1468
  export interface TreeSitterNativeImporterAdapterOptions {
1439
1469
  readonly id?: string;
1440
1470
  readonly language?: FrontierSourceLanguage;
@@ -1807,6 +1837,7 @@ export declare function createTypeScriptCompilerNativeImporterAdapter(options?:
1807
1837
  export declare function createPythonAstNativeImporterAdapter(options?: PythonAstNativeImporterAdapterOptions): NativeImporterAdapter;
1808
1838
  export declare function createRustSynNativeImporterAdapter(options?: RustSynNativeImporterAdapterOptions): NativeImporterAdapter;
1809
1839
  export declare function createClangAstNativeImporterAdapter(options?: ClangAstNativeImporterAdapterOptions): NativeImporterAdapter;
1840
+ export declare function createGoAstNativeImporterAdapter(options?: GoAstNativeImporterAdapterOptions): NativeImporterAdapter;
1810
1841
  export declare function createTreeSitterNativeImporterAdapter(options?: TreeSitterNativeImporterAdapterOptions): NativeImporterAdapter;
1811
1842
  export declare function runNativeImporterAdapter(adapter: NativeImporterAdapter, input: RunNativeImporterAdapterOptions): Promise<NativeImporterAdapterImportResult>;
1812
1843
  export declare function runNativeTargetProjectionAdapter(adapter: NativeTargetProjectionAdapter, input: NativeTargetProjectionAdapterInput): NativeTargetProjectionResult;
package/dist/index.js CHANGED
@@ -415,6 +415,18 @@ export const NativeParserAstFormatProfiles = Object.freeze([
415
415
  supportsErrorRecovery: false,
416
416
  notes: ['Clang JSON AST dumps expose compiler AST declarations and source ranges after preprocessing; compile commands, macros, inactive branches, type checking, and lossless formatting remain host-owned evidence.']
417
417
  }),
418
+ nativeParserAstFormatProfile('go-ast', {
419
+ aliases: ['go/parser', 'goast', 'golang-ast'],
420
+ kind: 'compiler-ast',
421
+ languages: ['go'],
422
+ parserAdapters: ['go/ast', 'go/parser', 'go-ast'],
423
+ exactness: 'exact-parser-ast',
424
+ sourceRangeModel: 'token-position',
425
+ preservesTokens: false,
426
+ preservesTrivia: false,
427
+ supportsErrorRecovery: true,
428
+ notes: ['Go go/ast trees expose parser syntax nodes and token positions; FileSet, build tags, generated-code classification, package loading, go/types, comments/trivia, and control-flow evidence remain host-owned.']
429
+ }),
418
430
  nativeParserAstFormatProfile('tree-sitter', {
419
431
  kind: 'concrete-syntax-tree',
420
432
  languages: ['mixed'],
@@ -2781,6 +2793,68 @@ export function createClangAstNativeImporterAdapter(options = {}) {
2781
2793
  };
2782
2794
  }
2783
2795
 
2796
+ export function createGoAstNativeImporterAdapter(options = {}) {
2797
+ return {
2798
+ id: options.id ?? 'frontier.go-ast-native-importer',
2799
+ language: options.language ?? 'go',
2800
+ parser: options.parser ?? 'go/parser',
2801
+ version: options.version,
2802
+ capabilities: uniqueStrings(['nativeAst', 'semanticIndex', 'sourceMaps', 'diagnostics', ...(options.capabilities ?? [])]),
2803
+ coverage: nativeImporterAdapterCoverage({
2804
+ exactness: 'exact-parser-ast',
2805
+ exactAst: true,
2806
+ tokens: false,
2807
+ trivia: false,
2808
+ diagnostics: true,
2809
+ sourceRanges: true,
2810
+ generatedRanges: false,
2811
+ semanticCoverage: declarationSemanticCoverage(),
2812
+ notes: [
2813
+ 'Normalizes caller-owned Go go/ast-shaped File or Package trees into native AST nodes and declaration-level semantic index records.',
2814
+ 'Go AST imports do not resolve types, imports, build tags, generated code, or control flow by themselves; attach FileSet, go/types, go/packages, and build context evidence for those claims.'
2815
+ ]
2816
+ }, options.coverage),
2817
+ supportedExtensions: options.supportedExtensions ?? ['.go'],
2818
+ diagnostics: options.diagnostics,
2819
+ parse(input) {
2820
+ const parsed = input.options?.ast
2821
+ ?? input.options?.nativeAst
2822
+ ?? input.options?.file
2823
+ ?? input.options?.sourceFile
2824
+ ?? input.options?.package
2825
+ ?? options.ast
2826
+ ?? options.file
2827
+ ?? options.sourceFile
2828
+ ?? options.package
2829
+ ?? parseGoAstSource(input, options);
2830
+ const root = goAstRoot(parsed);
2831
+ if (!root) {
2832
+ return missingInjectedParserResult(input, {
2833
+ parser: options.parser ?? 'go/parser',
2834
+ adapterId: options.id ?? 'frontier.go-ast-native-importer',
2835
+ message: 'createGoAstNativeImporterAdapter requires an injected Go ast.File/Package-shaped object, parserModule.parse function, parse function, or adapterOptions.ast.'
2836
+ });
2837
+ }
2838
+ const parseDiagnostics = normalizeParserErrors(parsed?.errors ?? parsed?.diagnostics, input, {
2839
+ parser: options.parser ?? 'go/parser'
2840
+ });
2841
+ return createNativeImportFromGoAst(root, input, {
2842
+ parser: options.parser ?? 'go/parser',
2843
+ astFormat: 'go-ast',
2844
+ maxNodes: options.maxNodes,
2845
+ diagnostics: parseDiagnostics,
2846
+ goVersion: options.goVersion ?? input.options?.goVersion ?? parsed?.goVersion,
2847
+ packageName: options.packageName ?? input.options?.packageName ?? parsed?.packageName ?? root?.Name?.Name ?? root?.Name,
2848
+ fileSet: input.options?.fileSet ?? input.options?.fset ?? options.fileSet ?? options.fset ?? parsed?.fileSet ?? parsed?.fset,
2849
+ includeComments: options.includeComments ?? input.options?.includeComments,
2850
+ buildTags: input.options?.buildTags ?? options.buildTags ?? parsed?.buildTags,
2851
+ generated: input.options?.generated ?? options.generated ?? parsed?.generated,
2852
+ typeEvidence: input.options?.typeEvidence ?? options.typeEvidence ?? parsed?.typeEvidence
2853
+ });
2854
+ }
2855
+ };
2856
+ }
2857
+
2784
2858
  export function createTreeSitterNativeImporterAdapter(options = {}) {
2785
2859
  return {
2786
2860
  id: options.id ?? `frontier.tree-sitter-${idFragment(options.language ?? 'source')}-native-importer`,
@@ -7222,6 +7296,7 @@ function parserAstFormatIdForParser(parser) {
7222
7296
  if (text === 'syn' || text.includes('rust-syn')) return 'rust-syn';
7223
7297
  if (text.includes('rust-analyzer') || text.includes('rowan')) return 'rust-analyzer-rowan';
7224
7298
  if (text.includes('clang') || text.includes('libclang')) return 'clang-ast-json';
7299
+ if (text === 'go' || text.includes('go-parser') || text.includes('go-ast') || text.includes('go/parser') || text.includes('go/ast')) return 'go-ast';
7225
7300
  if (text.includes('tree-sitter') || text.includes('treesitter')) return 'tree-sitter';
7226
7301
  if (text.includes('babel')) return 'babel';
7227
7302
  if (text.includes('estree')) return 'estree';
@@ -8287,6 +8362,22 @@ function parseClangAstSource(input, options) {
8287
8362
  return parse(input.sourceText, parserOptions);
8288
8363
  }
8289
8364
 
8365
+ function parseGoAstSource(input, options) {
8366
+ const parse = options.parse ?? options.parserModule?.parse ?? options.goAst?.parse ?? options.goParser?.parse;
8367
+ if (typeof parse !== 'function') return undefined;
8368
+ const parserOptions = {
8369
+ sourcePath: input.sourcePath,
8370
+ filename: input.sourcePath,
8371
+ mode: options.mode ?? input.options?.mode ?? 'ParseComments',
8372
+ goVersion: options.goVersion ?? input.options?.goVersion,
8373
+ packageName: options.packageName ?? input.options?.packageName,
8374
+ includeComments: options.includeComments ?? input.options?.includeComments,
8375
+ ...(options.parserOptions ?? {}),
8376
+ ...(input.options?.parserOptions ?? {})
8377
+ };
8378
+ return parse(input.sourceText, parserOptions);
8379
+ }
8380
+
8290
8381
  function createNativeImportFromSyntaxAst(ast, input, options) {
8291
8382
  const root = normalizeSyntaxAstRoot(ast, options.astFormat);
8292
8383
  if (!root) {
@@ -8443,6 +8534,41 @@ function createNativeImportFromClangAst(root, input, options) {
8443
8534
  };
8444
8535
  }
8445
8536
 
8537
+ function createNativeImportFromGoAst(root, input, options) {
8538
+ const context = createAstNormalizationContext(input, options);
8539
+ visitGoAstNode(root, context, 'root');
8540
+ if (context.truncated) {
8541
+ context.losses.push(truncatedAstLoss(input, context, options));
8542
+ }
8543
+ const semantic = semanticIndexFromNativeDeclarations(context.declarations, input, options);
8544
+ return {
8545
+ rootId: context.rootId,
8546
+ nodes: context.nodes,
8547
+ semanticIndex: semantic.semanticIndex,
8548
+ mappings: semantic.mappings,
8549
+ losses: mergeNativeLosses(context.losses, options.diagnostics?.map((diagnostic, index) => adapterDiagnosticToLoss(diagnostic, index, {
8550
+ id: input.adapterId,
8551
+ version: input.adapterVersion
8552
+ }, input)) ?? []),
8553
+ evidence: semantic.evidence,
8554
+ diagnostics: options.diagnostics,
8555
+ metadata: {
8556
+ astFormat: options.astFormat,
8557
+ parser: options.parser,
8558
+ goVersion: options.goVersion,
8559
+ packageName: options.packageName,
8560
+ includeComments: Boolean(options.includeComments),
8561
+ buildTags: Array.isArray(options.buildTags) ? options.buildTags.slice() : options.buildTags,
8562
+ generated: options.generated,
8563
+ fileSetEvidence: Boolean(options.fileSet),
8564
+ typeEvidence: goTypeEvidenceSummary(options.typeEvidence),
8565
+ normalizedNodeCount: Object.keys(context.nodes).length,
8566
+ declarationCount: context.declarations.length,
8567
+ truncated: context.truncated
8568
+ }
8569
+ };
8570
+ }
8571
+
8446
8572
  function createNativeImportFromTreeSitter(root, input, options) {
8447
8573
  const context = createAstNormalizationContext(input, options);
8448
8574
  visitTreeSitterNode(root, context, 'root');
@@ -8748,6 +8874,104 @@ function visitClangAstNode(node, context, propertyPath) {
8748
8874
  return id;
8749
8875
  }
8750
8876
 
8877
+ function visitGoAstNode(node, context, propertyPath) {
8878
+ if (!isGoAstNode(node) || context.truncated) return undefined;
8879
+ if (context.objectIds.has(node)) return context.objectIds.get(node);
8880
+ if (context.counter >= context.maxNodes) {
8881
+ context.truncated = true;
8882
+ return undefined;
8883
+ }
8884
+ const kind = goAstKind(node);
8885
+ const span = spanFromGoAstNode(node, context.input, context.options);
8886
+ const id = nativeNodeId(context, kind, { start: { line: span?.startLine, column: span?.startColumn } }, propertyPath);
8887
+ context.objectIds.set(node, id);
8888
+ if (!context.rootId) context.rootId = id;
8889
+ const children = [];
8890
+ for (const [field, value] of goAstChildEntries(node)) {
8891
+ if (Array.isArray(value)) {
8892
+ value.forEach((entry, index) => {
8893
+ const childId = visitGoAstNode(entry, context, `${propertyPath}.${field}[${index}]`);
8894
+ if (childId) children.push(childId);
8895
+ });
8896
+ } else {
8897
+ const childId = visitGoAstNode(value, context, `${propertyPath}.${field}`);
8898
+ if (childId) children.push(childId);
8899
+ }
8900
+ }
8901
+ const declarations = goAstDeclarations(node, kind, id, context.input);
8902
+ const declaration = declarations[0];
8903
+ const nativeNode = {
8904
+ id,
8905
+ kind,
8906
+ languageKind: `${context.input.language}.${kind}`,
8907
+ span,
8908
+ value: declaration?.name ?? goAstNodeValue(node),
8909
+ fields: primitiveGoAstFields(node, kind),
8910
+ children,
8911
+ metadata: {
8912
+ astFormat: context.options.astFormat,
8913
+ propertyPath,
8914
+ positionKind: goAstPositionKind(node),
8915
+ packageName: context.options.packageName
8916
+ }
8917
+ };
8918
+ context.nodes[id] = nativeNode;
8919
+ for (const entry of declarations) {
8920
+ context.declarations.push({ ...entry, nativeNode });
8921
+ }
8922
+ if (goBadAstKind(kind)) {
8923
+ context.losses.push({
8924
+ id: `loss_${idFragment(id)}_go_bad_node`,
8925
+ severity: 'error',
8926
+ phase: 'parse',
8927
+ sourceFormat: context.input.language,
8928
+ kind: 'unsupportedSyntax',
8929
+ message: 'Go parser recovered a BadDecl/BadExpr/BadStmt node; semantic import is partial until syntax errors are resolved.',
8930
+ span,
8931
+ nodeId: id,
8932
+ metadata: {
8933
+ parser: context.options.parser,
8934
+ astFormat: context.options.astFormat,
8935
+ nodeKind: kind
8936
+ }
8937
+ });
8938
+ }
8939
+ if (kind === 'FuncDecl' && goReceiverFieldCount(node) > 1) {
8940
+ context.losses.push({
8941
+ id: `loss_${idFragment(id)}_go_multiple_receivers`,
8942
+ severity: 'warning',
8943
+ phase: 'parse',
8944
+ sourceFormat: context.input.language,
8945
+ kind: 'unsupportedSyntax',
8946
+ message: 'Go parser accepted multiple receiver fields; valid method ownership requires a single receiver.',
8947
+ span,
8948
+ nodeId: id,
8949
+ metadata: {
8950
+ parser: context.options.parser,
8951
+ astFormat: context.options.astFormat,
8952
+ receiverFieldCount: goReceiverFieldCount(node)
8953
+ }
8954
+ });
8955
+ }
8956
+ if (goGeneratedCodeMarker(node, kind)) {
8957
+ context.losses.push({
8958
+ id: `loss_${idFragment(id)}_go_generated_code`,
8959
+ severity: 'warning',
8960
+ phase: 'parse',
8961
+ sourceFormat: context.input.language,
8962
+ kind: 'generatedCode',
8963
+ message: 'Go generated-code marker was imported; regeneration provenance and source ownership require host evidence.',
8964
+ span,
8965
+ nodeId: id,
8966
+ metadata: {
8967
+ parser: context.options.parser,
8968
+ astFormat: context.options.astFormat
8969
+ }
8970
+ });
8971
+ }
8972
+ return id;
8973
+ }
8974
+
8751
8975
  function visitTreeSitterNode(node, context, propertyPath) {
8752
8976
  if (!node || typeof node !== 'object' || context.truncated) return undefined;
8753
8977
  if (context.objectIds.has(node)) return context.objectIds.get(node);
@@ -10657,6 +10881,332 @@ function serializableIncludeGraphSummary(value) {
10657
10881
  return Object.keys(summary).length ? summary : { present: true };
10658
10882
  }
10659
10883
 
10884
+ function goAstRoot(value) {
10885
+ if (!value || typeof value !== 'object') return undefined;
10886
+ if (isGoAstNode(value)) return value;
10887
+ if (isGoAstNode(value.ast)) return value.ast;
10888
+ if (isGoAstNode(value.file)) return value.file;
10889
+ if (isGoAstNode(value.sourceFile)) return value.sourceFile;
10890
+ if (isGoAstNode(value.root)) return value.root;
10891
+ if (isGoAstNode(value.package)) return value.package;
10892
+ if (value.files && typeof value.files === 'object') return { kind: 'Package', Name: value.name ?? value.packageName, Files: value.files };
10893
+ return undefined;
10894
+ }
10895
+
10896
+ function isGoAstNode(value) {
10897
+ return Boolean(value && typeof value === 'object' && typeof goAstKind(value) === 'string');
10898
+ }
10899
+
10900
+ function goAstKind(node) {
10901
+ if (!node || typeof node !== 'object') return undefined;
10902
+ const declared = node.kind ?? node._type ?? node.type ?? node.nodeType ?? node.astKind;
10903
+ if (typeof declared === 'string') return normalizeGoAstKind(declared);
10904
+ if (Array.isArray(node.Decls) || Array.isArray(node.decls)) return 'File';
10905
+ if (node.Files || node.files) return 'Package';
10906
+ if (node.Name && node.Type && (node.Body || node.Recv !== undefined || node.recv !== undefined)) return 'FuncDecl';
10907
+ if (node.Tok && (node.Specs || node.specs)) return 'GenDecl';
10908
+ if (node.Path && (node.Name !== undefined || node.EndPos !== undefined)) return 'ImportSpec';
10909
+ if (node.Names && node.Type !== undefined) return 'ValueSpec';
10910
+ if (node.Name && node.Type !== undefined) return 'TypeSpec';
10911
+ if (node.List && (node.Opening !== undefined || node.Closing !== undefined)) return 'FieldList';
10912
+ return undefined;
10913
+ }
10914
+
10915
+ function normalizeGoAstKind(kind) {
10916
+ const text = String(kind).replace(/^(?:ast\.)?\*/, '').replace(/^(?:go\/ast\.)/, '');
10917
+ if (/^file$/i.test(text)) return 'File';
10918
+ if (/^package$/i.test(text)) return 'Package';
10919
+ if (/^funcdecl$/i.test(text) || /^func_decl$/i.test(text)) return 'FuncDecl';
10920
+ if (/^gendecl$/i.test(text) || /^gen_decl$/i.test(text)) return 'GenDecl';
10921
+ if (/^importspec$/i.test(text) || /^import_spec$/i.test(text)) return 'ImportSpec';
10922
+ if (/^typespec$/i.test(text) || /^type_spec$/i.test(text)) return 'TypeSpec';
10923
+ if (/^valuespec$/i.test(text) || /^value_spec$/i.test(text)) return 'ValueSpec';
10924
+ if (/^structtype$/i.test(text) || /^struct_type$/i.test(text)) return 'StructType';
10925
+ if (/^interfacetype$/i.test(text) || /^interface_type$/i.test(text)) return 'InterfaceType';
10926
+ if (/^fieldlist$/i.test(text) || /^field_list$/i.test(text)) return 'FieldList';
10927
+ return text;
10928
+ }
10929
+
10930
+ function ignoredGoAstField(key) {
10931
+ return key === '_type'
10932
+ || key === 'type'
10933
+ || key === 'kind'
10934
+ || key === 'nodeType'
10935
+ || key === 'astKind'
10936
+ || key === 'parent'
10937
+ || key === 'Obj'
10938
+ || key === 'object'
10939
+ || key === 'Scope'
10940
+ || key === 'scope'
10941
+ || key === 'Unresolved'
10942
+ || key === 'unresolved'
10943
+ || key === 'FileStart'
10944
+ || key === 'FileEnd'
10945
+ || key === 'Package'
10946
+ || key === 'Name'
10947
+ || key === 'Path'
10948
+ || key === 'Pos'
10949
+ || key === 'End'
10950
+ || key === 'pos'
10951
+ || key === 'end';
10952
+ }
10953
+
10954
+ function primitiveGoAstFields(node, kind) {
10955
+ const fields = { kind };
10956
+ const name = goAstDeclarationName(node);
10957
+ if (name) fields.name = name;
10958
+ const type = goAstTypeName(node.Type ?? node.type);
10959
+ if (type) fields.type = type;
10960
+ const tok = goAstTokenName(node.Tok ?? node.tok);
10961
+ if (tok) fields.token = tok;
10962
+ const importPath = goAstImportPath(node);
10963
+ if (importPath) fields.importPath = importPath;
10964
+ const receiver = goAstReceiverName(node);
10965
+ if (receiver) fields.receiver = receiver;
10966
+ for (const key of ['Incomplete', 'Doc', 'Comment']) {
10967
+ const value = node[key] ?? node[key[0].toLowerCase() + key.slice(1)];
10968
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || value === null) fields[key[0].toLowerCase() + key.slice(1)] = value;
10969
+ }
10970
+ if (Array.isArray(node.Names ?? node.names)) {
10971
+ fields.names = (node.Names ?? node.names).map(goAstIdentName).filter(Boolean).join(',');
10972
+ }
10973
+ return fields;
10974
+ }
10975
+
10976
+ function spanFromGoAstNode(node, input, options = {}) {
10977
+ const start = goAstPosition(node.Pos ?? node.pos ?? node.Name?.NamePos ?? node.name?.namePos ?? node.Package, options);
10978
+ const end = goAstPosition(node.End ?? node.end ?? node.EndPos ?? node.endPos, options);
10979
+ if (!start) return undefined;
10980
+ return {
10981
+ sourceId: input.sourceHash,
10982
+ path: start.path ?? end?.path ?? input.sourcePath,
10983
+ startLine: start.line,
10984
+ startColumn: start.column,
10985
+ endLine: end?.line,
10986
+ endColumn: end?.column
10987
+ };
10988
+ }
10989
+
10990
+ function goAstPosition(value, options = {}) {
10991
+ if (!value) return undefined;
10992
+ if (typeof value === 'object') {
10993
+ const position = value.position ?? value.Position ?? value.pos ?? value.Pos ?? value;
10994
+ const line = position.Line ?? position.line;
10995
+ const column = position.Column ?? position.column ?? position.Col ?? position.col;
10996
+ if (typeof line === 'number') {
10997
+ return {
10998
+ path: position.Filename ?? position.filename ?? position.file ?? position.path,
10999
+ line,
11000
+ column: typeof column === 'number' ? column : undefined
11001
+ };
11002
+ }
11003
+ }
11004
+ const fileSet = options.fileSet ?? options.fset;
11005
+ const positionFor = typeof fileSet?.PositionFor === 'function'
11006
+ ? fileSet.PositionFor.bind(fileSet)
11007
+ : typeof fileSet?.positionFor === 'function'
11008
+ ? fileSet.positionFor.bind(fileSet)
11009
+ : typeof fileSet?.Position === 'function'
11010
+ ? fileSet.Position.bind(fileSet)
11011
+ : typeof fileSet?.position === 'function'
11012
+ ? fileSet.position.bind(fileSet)
11013
+ : undefined;
11014
+ if (positionFor) {
11015
+ const resolved = positionFor(value, true);
11016
+ return goAstPosition(resolved, options);
11017
+ }
11018
+ return undefined;
11019
+ }
11020
+
11021
+ function goAstPositionKind(node) {
11022
+ const pos = node.Pos ?? node.pos ?? node.Name?.NamePos ?? node.name?.namePos;
11023
+ if (!pos) return undefined;
11024
+ if (typeof pos === 'object') return 'token.Position';
11025
+ return 'token.Pos';
11026
+ }
11027
+
11028
+ function goAstDeclarations(node, kind, nativeNodeId, input) {
11029
+ if (kind === 'ImportSpec') {
11030
+ const name = goAstImportPath(node);
11031
+ return name ? [declarationRecord(input, nativeNodeId, name, 'module', 'import')] : [];
11032
+ }
11033
+ if (kind === 'FuncDecl') {
11034
+ const name = goAstDeclarationName(node);
11035
+ if (!name) return [];
11036
+ const receiver = goAstReceiverName(node);
11037
+ return [declarationRecord(input, nativeNodeId, receiver ? `${receiver}.${name}` : name, receiver ? 'method' : 'function', node.Body || node.body ? 'definition' : 'declaration')];
11038
+ }
11039
+ if (kind === 'TypeSpec') {
11040
+ const name = goAstDeclarationName(node);
11041
+ return name ? [declarationRecord(input, nativeNodeId, name, goAstTypeSpecSymbolKind(node), 'definition')] : [];
11042
+ }
11043
+ if (kind === 'ValueSpec') {
11044
+ const names = goAstValueSpecNames(node);
11045
+ const token = goAstTokenName(node.parentTok ?? node.Tok ?? node.tok);
11046
+ return names.map((name) => declarationRecord(input, nativeNodeId, name, token === 'CONST' || token === 'const' ? 'constant' : 'variable', 'definition'));
11047
+ }
11048
+ if (kind === 'Field') {
11049
+ return goAstValueSpecNames(node).map((name) => declarationRecord(input, nativeNodeId, name, 'property', 'definition'));
11050
+ }
11051
+ if (kind === 'Package' || kind === 'File') {
11052
+ const name = goAstPackageName(node);
11053
+ return name ? [declarationRecord(input, nativeNodeId, name, 'module', 'definition')] : [];
11054
+ }
11055
+ return [];
11056
+ }
11057
+
11058
+ function goAstChildEntries(node) {
11059
+ const fieldNames = Object.keys(node).filter((key) => !ignoredGoAstField(key));
11060
+ const entries = [];
11061
+ for (const field of fieldNames) {
11062
+ const value = node[field];
11063
+ if (field === 'Files' || field === 'files') {
11064
+ if (value && typeof value === 'object') entries.push([field, Array.isArray(value) ? value : Object.values(value)]);
11065
+ continue;
11066
+ }
11067
+ if (field === 'Specs' || field === 'specs') {
11068
+ const token = goAstTokenName(node.Tok ?? node.tok);
11069
+ entries.push([field, Array.isArray(value)
11070
+ ? value.map((entry) => entry && typeof entry === 'object' ? { parentTok: token, ...entry } : entry)
11071
+ : value]);
11072
+ continue;
11073
+ }
11074
+ entries.push([field, value]);
11075
+ }
11076
+ return entries.filter(([, value]) => Array.isArray(value)
11077
+ ? value.some(isGoAstNode)
11078
+ : isGoAstNode(value));
11079
+ }
11080
+
11081
+ function goAstNodeValue(node) {
11082
+ return goAstDeclarationName(node)
11083
+ ?? goAstImportPath(node)
11084
+ ?? goAstTypeName(node.Type ?? node.type)
11085
+ ?? goAstLiteralValue(node);
11086
+ }
11087
+
11088
+ function goAstDeclarationName(node) {
11089
+ if (!node || typeof node !== 'object') return undefined;
11090
+ return goAstIdentName(node.Name ?? node.name)
11091
+ ?? goAstIdentName(node.Ident ?? node.ident)
11092
+ ?? goAstIdentName(node.Sel ?? node.sel)
11093
+ ?? (typeof node.Name === 'string' ? node.Name : undefined)
11094
+ ?? (typeof node.name === 'string' ? node.name : undefined);
11095
+ }
11096
+
11097
+ function goAstPackageName(node) {
11098
+ if (!node || typeof node !== 'object') return undefined;
11099
+ return goAstIdentName(node.Name ?? node.name) ?? node.PackageName ?? node.packageName;
11100
+ }
11101
+
11102
+ function goAstIdentName(value) {
11103
+ if (!value) return undefined;
11104
+ if (typeof value === 'string') return value;
11105
+ return value.Name ?? value.name ?? value.Value ?? value.value;
11106
+ }
11107
+
11108
+ function goAstImportPath(node) {
11109
+ if (!node || typeof node !== 'object') return undefined;
11110
+ const path = node.Path ?? node.path;
11111
+ const raw = typeof path === 'string' ? path : path?.Value ?? path?.value ?? path?.Kind;
11112
+ if (typeof raw !== 'string') return undefined;
11113
+ return raw.replace(/^"|"$/g, '').replace(/^`|`$/g, '');
11114
+ }
11115
+
11116
+ function goAstReceiverName(node) {
11117
+ const recv = node?.Recv ?? node?.recv;
11118
+ const list = recv?.List ?? recv?.list;
11119
+ if (!Array.isArray(list) || !list.length) return undefined;
11120
+ const first = list[0];
11121
+ return goAstTypeName(first?.Type ?? first?.type);
11122
+ }
11123
+
11124
+ function goAstValueSpecName(node) {
11125
+ return goAstValueSpecNames(node)[0];
11126
+ }
11127
+
11128
+ function goAstValueSpecNames(node) {
11129
+ const names = node.Names ?? node.names;
11130
+ if (Array.isArray(names)) return names.map(goAstIdentName).filter(Boolean);
11131
+ const name = goAstDeclarationName(node);
11132
+ return name ? [name] : [];
11133
+ }
11134
+
11135
+ function goAstTypeSpecSymbolKind(node) {
11136
+ const type = node.Type ?? node.type;
11137
+ const kind = goAstKind(type);
11138
+ if (kind === 'InterfaceType') return 'interface';
11139
+ if (kind === 'StructType') return 'class';
11140
+ return 'type';
11141
+ }
11142
+
11143
+ function goAstTypeName(value) {
11144
+ if (!value) return undefined;
11145
+ if (typeof value === 'string') return value;
11146
+ const kind = goAstKind(value);
11147
+ if (kind === 'Ident') return goAstIdentName(value);
11148
+ if (kind === 'StarExpr') {
11149
+ const inner = goAstTypeName(value.X ?? value.x);
11150
+ return inner ? `*${inner}` : '*';
11151
+ }
11152
+ if (kind === 'SelectorExpr') {
11153
+ const left = goAstTypeName(value.X ?? value.x);
11154
+ const right = goAstIdentName(value.Sel ?? value.sel);
11155
+ return [left, right].filter(Boolean).join('.');
11156
+ }
11157
+ if (kind === 'ArrayType') {
11158
+ const inner = goAstTypeName(value.Elt ?? value.elt);
11159
+ return `[]${inner ?? 'unknown'}`;
11160
+ }
11161
+ if (kind === 'MapType') {
11162
+ return `map[${goAstTypeName(value.Key ?? value.key) ?? 'unknown'}]${goAstTypeName(value.Value ?? value.value) ?? 'unknown'}`;
11163
+ }
11164
+ if (kind === 'StructType') return 'struct';
11165
+ if (kind === 'InterfaceType') return 'interface';
11166
+ if (kind === 'FuncType') return 'func';
11167
+ return goAstDeclarationName(value);
11168
+ }
11169
+
11170
+ function goAstTokenName(value) {
11171
+ if (!value) return undefined;
11172
+ if (typeof value === 'string') return value;
11173
+ if (typeof value === 'number') return String(value);
11174
+ return value.String ?? value.string ?? value.Name ?? value.name;
11175
+ }
11176
+
11177
+ function goAstLiteralValue(node) {
11178
+ const value = node.Value ?? node.value;
11179
+ if (value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return value;
11180
+ return undefined;
11181
+ }
11182
+
11183
+ function goGeneratedCodeMarker(node, kind) {
11184
+ if (kind !== 'File') return false;
11185
+ if (node.Generated || node.generated) return true;
11186
+ const comments = node.Comments ?? node.comments;
11187
+ if (!Array.isArray(comments)) return false;
11188
+ return comments.some((group) => JSON.stringify(group).includes('Code generated') && JSON.stringify(group).includes('DO NOT EDIT'));
11189
+ }
11190
+
11191
+ function goBadAstKind(kind) {
11192
+ return kind === 'BadDecl' || kind === 'BadExpr' || kind === 'BadStmt';
11193
+ }
11194
+
11195
+ function goReceiverFieldCount(node) {
11196
+ const list = (node?.Recv ?? node?.recv)?.List ?? (node?.Recv ?? node?.recv)?.list;
11197
+ return Array.isArray(list) ? list.length : 0;
11198
+ }
11199
+
11200
+ function goTypeEvidenceSummary(value) {
11201
+ if (!value || typeof value !== 'object') return undefined;
11202
+ const summary = {};
11203
+ if (typeof value.packagePath === 'string') summary.packagePath = value.packagePath;
11204
+ if (typeof value.hash === 'string') summary.hash = value.hash;
11205
+ if (Array.isArray(value.types)) summary.typeCount = value.types.length;
11206
+ if (Array.isArray(value.references)) summary.referenceCount = value.references.length;
11207
+ return Object.keys(summary).length ? summary : { present: true };
11208
+ }
11209
+
10660
11210
  function declarationRecord(input, nativeNodeId, name, symbolKind, role = 'definition') {
10661
11211
  return {
10662
11212
  name: String(name),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.28",
3
+ "version": "0.2.29",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",