@shapeshift-labs/frontier-lang-compiler 0.2.128 → 0.2.130

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
@@ -170,7 +170,7 @@ small and dependency-free. They cover accepted projection/replay cases, exact
170
170
  source preservation, generated/source-map boundaries, safe import/declaration
171
171
  merges, safe unordered member merges, composed top-level/member safe merges,
172
172
  and rejected unsafe cases such as stale
173
- ledger spans, import specifier reordering, computed keys, duplicate exported
173
+ ledger spans, import specifier removals, computed keys, duplicate exported
174
174
  names, duplicate object members, decorators, overload anchors, and same-anchor
175
175
  edit conflicts. Fixture failures include the fixture id and the actual
176
176
  reason-code or gate values so distributed swarm evidence can point at a stable
@@ -102,6 +102,7 @@ export interface JsTsSafeMergeAdmission {
102
102
 
103
103
  export interface JsTsSafeMergeSummary {
104
104
  readonly importSpecifierAdditions: number;
105
+ readonly importDeclarationAdditions: number;
105
106
  readonly topLevelDeclarationAdditions: number;
106
107
  readonly changedExistingDeclarations: number;
107
108
  readonly conflicts: number;
@@ -1,10 +1,13 @@
1
1
  import { JsTsSafeMergeConflictCodes, JsTsSafeMergeGateIds } from './js-ts-safe-merge-constants.js';
2
2
  import { addConflict, arraysEqual, sameStatementText } from './js-ts-safe-merge-context.js';
3
3
  import { validateCrossSideExportStarAdditions } from './js-ts-safe-merge-export-star-validation.js';
4
+ import { importEntryBindings, mergedNewImportBindings } from './js-ts-safe-merge-import-entry-utils.js';
5
+ import { validateNewImportDeclarations } from './js-ts-safe-merge-new-import-validation.js';
4
6
 
5
7
  export function analyzeVariantLedger(base, variant, baseIndex, side, context) {
6
8
  const projectedBaseKeys = [];
7
9
  const addedEntries = [];
10
+ const newImportEntries = [];
8
11
  const importAdditions = new Map();
9
12
  const baseKeys = new Set(baseIndex.orderedKeys);
10
13
 
@@ -12,13 +15,7 @@ export function analyzeVariantLedger(base, variant, baseIndex, side, context) {
12
15
  const baseEntry = baseIndex.entriesByKey.get(entry.key);
13
16
  if (!baseEntry) {
14
17
  if (entry.kind === 'import') {
15
- addConflict(context, {
16
- code: JsTsSafeMergeConflictCodes.newImportDeclaration,
17
- gateId: JsTsSafeMergeGateIds.independentImportSpecifiers,
18
- side,
19
- message: `${side} source adds a new import declaration; only specifier additions to existing imports are accepted.`,
20
- details: { key: entry.key, statement: entry.text.trim() }
21
- });
18
+ newImportEntries.push(entry);
22
19
  } else {
23
20
  addedEntries.push(entry);
24
21
  }
@@ -72,6 +69,7 @@ export function analyzeVariantLedger(base, variant, baseIndex, side, context) {
72
69
  return {
73
70
  side,
74
71
  addedEntries,
72
+ newImportEntries,
75
73
  importAdditions,
76
74
  baseKeys
77
75
  };
@@ -105,34 +103,27 @@ function analyzeImportStatementChange(baseEntry, variantEntry, side, context) {
105
103
 
106
104
  const baseSpecifiers = baseImport.specifiers;
107
105
  const variantSpecifiers = variantImport.specifiers;
108
- if (variantSpecifiers.length < baseSpecifiers.length) {
106
+ const baseSpecifiersByCanonical = new Set(baseSpecifiers.map((specifier) => specifier.canonical));
107
+ const variantSpecifiersByCanonical = new Set(variantSpecifiers.map((specifier) => specifier.canonical));
108
+ const missingBaseSpecifiers = baseSpecifiers.filter((specifier) => !variantSpecifiersByCanonical.has(specifier.canonical));
109
+ if (missingBaseSpecifiers.length) {
109
110
  addConflict(context, {
110
111
  code: JsTsSafeMergeConflictCodes.importSpecifierRemoved,
111
112
  gateId: JsTsSafeMergeGateIds.independentImportSpecifiers,
112
113
  side,
113
114
  message: `${side} source removes import specifiers.`,
114
- details: { key: baseEntry.key }
115
+ details: {
116
+ key: baseEntry.key,
117
+ missing: missingBaseSpecifiers.map((specifier) => specifier.canonical)
118
+ }
115
119
  });
116
120
  return [];
117
121
  }
118
- for (let index = 0; index < baseSpecifiers.length; index += 1) {
119
- if (variantSpecifiers[index]?.canonical !== baseSpecifiers[index].canonical) {
120
- addConflict(context, {
121
- code: JsTsSafeMergeConflictCodes.importSpecifierReordered,
122
- gateId: JsTsSafeMergeGateIds.independentImportSpecifiers,
123
- side,
124
- message: `${side} source reorders or changes existing import specifiers.`,
125
- details: {
126
- key: baseEntry.key,
127
- expected: baseSpecifiers.map((specifier) => specifier.canonical),
128
- actual: variantSpecifiers.map((specifier) => specifier.canonical)
129
- }
130
- });
131
- return [];
132
- }
133
- }
134
- const additions = variantSpecifiers.slice(baseSpecifiers.length);
122
+ const additions = variantSpecifiers.filter((specifier) => !baseSpecifiersByCanonical.has(specifier.canonical));
135
123
  if (additions.length === 0 && !sameStatementText(baseEntry.text, variantEntry.text)) {
124
+ const baseCanonicalOrder = baseSpecifiers.map((specifier) => specifier.canonical);
125
+ const variantCanonicalOrder = variantSpecifiers.map((specifier) => specifier.canonical);
126
+ if (!arraysEqual(baseCanonicalOrder, variantCanonicalOrder)) return [];
136
127
  addConflict(context, {
137
128
  code: JsTsSafeMergeConflictCodes.importFormattingChanged,
138
129
  gateId: JsTsSafeMergeGateIds.independentImportSpecifiers,
@@ -159,6 +150,7 @@ export function validateIndependentAdditions(base, workerPlan, headPlan, context
159
150
  }
160
151
  validateAddedEntryNames(workerPlan, declarationNames, context);
161
152
  validateAddedEntryNames(headPlan, declarationNames, context);
153
+ validateNewImportDeclarations(workerPlan, headPlan, context);
162
154
  validateCrossSideAddedNames(workerPlan, headPlan, context);
163
155
  validateCrossSideExportStarAdditions(workerPlan, headPlan, context);
164
156
  validateCrossSideImportAdditions(workerPlan, headPlan, context);
@@ -264,12 +256,7 @@ function validateMergedImportAndDeclarationNames(base, workerPlan, headPlan, con
264
256
  ...(workerPlan.importAdditions.get(entry.key) ?? []),
265
257
  ...(headPlan.importAdditions.get(entry.key) ?? [])
266
258
  ];
267
- for (const specifier of [
268
- ...(entry.importInfo.defaultLocalName ? [{ localName: entry.importInfo.defaultLocalName, canonical: `default:${entry.importInfo.defaultLocalName}` }] : []),
269
- ...(entry.importInfo.namespaceLocalName ? [{ localName: entry.importInfo.namespaceLocalName, canonical: `namespace:${entry.importInfo.namespaceLocalName}` }] : []),
270
- ...entry.importInfo.specifiers,
271
- ...additions
272
- ]) {
259
+ for (const specifier of [...importEntryBindings(entry), ...additions]) {
273
260
  if (importLocalNames.has(specifier.localName)) {
274
261
  addConflict(context, {
275
262
  code: JsTsSafeMergeConflictCodes.duplicateName,
@@ -289,4 +276,15 @@ function validateMergedImportAndDeclarationNames(base, workerPlan, headPlan, con
289
276
  importLocalNames.add(specifier.localName);
290
277
  }
291
278
  }
279
+ for (const specifier of mergedNewImportBindings(workerPlan, headPlan)) {
280
+ if (importLocalNames.has(specifier.localName) || topLevelBindingNames.has(specifier.localName)) {
281
+ addConflict(context, {
282
+ code: JsTsSafeMergeConflictCodes.duplicateName,
283
+ gateId: JsTsSafeMergeGateIds.uniqueNames,
284
+ message: 'Merged new imports would duplicate an existing binding name.',
285
+ details: { localName: specifier.localName, specifier: specifier.canonical, importKey: specifier.importKey }
286
+ });
287
+ }
288
+ importLocalNames.add(specifier.localName);
289
+ }
292
290
  }
@@ -106,6 +106,7 @@ function composedBlockedResult(input, phase, result, memberAnalysis) {
106
106
  },
107
107
  summary: {
108
108
  importSpecifierAdditions: 0,
109
+ importDeclarationAdditions: 0,
109
110
  topLevelDeclarationAdditions: 0,
110
111
  changedExistingDeclarations: result.summary?.changedExistingDeclarations ?? 0,
111
112
  conflicts: result.conflicts?.length ?? result.summary?.conflicts ?? 0,
@@ -35,6 +35,7 @@ export function blockedResult(context, ledgers = {}) {
35
35
  },
36
36
  summary: {
37
37
  importSpecifierAdditions: 0,
38
+ importDeclarationAdditions: 0,
38
39
  topLevelDeclarationAdditions: 0,
39
40
  changedExistingDeclarations: context.conflicts.filter((conflict) => conflict.code === JsTsSafeMergeConflictCodes.changedExistingDeclaration).length,
40
41
  conflicts: context.conflicts.length,
@@ -0,0 +1,40 @@
1
+ import { importSpecifierCanonical } from './js-ts-safe-merge-ledger.js';
2
+
3
+ export function importEntryBindings(entry) {
4
+ const importInfo = entry?.importInfo;
5
+ if (!importInfo || importInfo.sideEffectOnly) return [];
6
+ return [
7
+ ...(importInfo.defaultLocalName ? [{
8
+ localName: importInfo.defaultLocalName,
9
+ importedName: 'default',
10
+ typeOnly: importInfo.typeOnly,
11
+ canonical: `default:${importInfo.defaultLocalName}`
12
+ }] : []),
13
+ ...(importInfo.namespaceLocalName ? [{
14
+ localName: importInfo.namespaceLocalName,
15
+ importedName: '*',
16
+ typeOnly: importInfo.typeOnly,
17
+ canonical: `namespace:${importInfo.namespaceLocalName}`
18
+ }] : []),
19
+ ...importInfo.specifiers.map((specifier) => ({
20
+ localName: specifier.localName,
21
+ importedName: specifier.importedName,
22
+ typeOnly: specifier.typeOnly,
23
+ canonical: importSpecifierCanonical(specifier)
24
+ }))
25
+ ];
26
+ }
27
+
28
+ export function mergedNewImportBindings(workerPlan, headPlan) {
29
+ const seen = new Set();
30
+ const bindings = [];
31
+ for (const entry of [...(workerPlan.newImportEntries ?? []), ...(headPlan.newImportEntries ?? [])]) {
32
+ for (const binding of importEntryBindings(entry)) {
33
+ const key = `${entry.key}:${binding.canonical}`;
34
+ if (seen.has(key)) continue;
35
+ seen.add(key);
36
+ bindings.push({ ...binding, importKey: entry.key });
37
+ }
38
+ }
39
+ return bindings;
40
+ }
@@ -0,0 +1,50 @@
1
+ import { JsTsSafeMergeConflictCodes, JsTsSafeMergeGateIds } from './js-ts-safe-merge-constants.js';
2
+ import { addConflict } from './js-ts-safe-merge-context.js';
3
+ import { mergedNewImportBindings } from './js-ts-safe-merge-import-entry-utils.js';
4
+
5
+ export function validateNewImportDeclarations(workerPlan, headPlan, context) {
6
+ validateNoNewSideEffectImports(workerPlan, context);
7
+ validateNoNewSideEffectImports(headPlan, context);
8
+ validateCrossSideNewImportBindings(workerPlan, headPlan, context);
9
+ }
10
+
11
+ function validateNoNewSideEffectImports(plan, context) {
12
+ for (const entry of plan.newImportEntries ?? []) {
13
+ if (!entry.importInfo?.sideEffectOnly) continue;
14
+ addConflict(context, {
15
+ code: JsTsSafeMergeConflictCodes.sideEffectImportReorder,
16
+ gateId: JsTsSafeMergeGateIds.preserveBaseOrder,
17
+ side: plan.side,
18
+ message: `${plan.side} source adds a side-effect import; new side-effect ordering requires human review.`,
19
+ details: {
20
+ reasonCode: 'new-side-effect-import',
21
+ key: entry.key,
22
+ statement: entry.text.trim()
23
+ }
24
+ });
25
+ }
26
+ }
27
+
28
+ function validateCrossSideNewImportBindings(workerPlan, headPlan, context) {
29
+ const ownersByLocalName = new Map();
30
+ for (const binding of mergedNewImportBindings(workerPlan, headPlan)) {
31
+ const owner = ownersByLocalName.get(binding.localName);
32
+ if (!owner) {
33
+ ownersByLocalName.set(binding.localName, binding);
34
+ continue;
35
+ }
36
+ addConflict(context, {
37
+ code: JsTsSafeMergeConflictCodes.duplicateName,
38
+ gateId: JsTsSafeMergeGateIds.uniqueNames,
39
+ side: 'worker',
40
+ message: 'Worker and head add new imports with duplicate local binding names.',
41
+ details: {
42
+ localName: binding.localName,
43
+ firstImportKey: owner.importKey,
44
+ secondImportKey: binding.importKey,
45
+ firstSpecifier: owner.canonical,
46
+ secondSpecifier: binding.canonical
47
+ }
48
+ });
49
+ }
50
+ }
@@ -5,6 +5,7 @@ import { importSpecifierCanonical } from './js-ts-safe-merge-ledger.js';
5
5
  export function createSourceMergePlan(base, worker, head, workerPlan, headPlan, context) {
6
6
  const edits = [];
7
7
  let importSpecifierAdditions = 0;
8
+ let importDeclarationAdditions = 0;
8
9
  for (const baseEntry of base.entries.filter((entry) => entry.kind === 'import')) {
9
10
  const workerAdditions = workerPlan.importAdditions.get(baseEntry.key) ?? [];
10
11
  const headAdditions = headPlan.importAdditions.get(baseEntry.key) ?? [];
@@ -29,10 +30,49 @@ export function createSourceMergePlan(base, worker, head, workerPlan, headPlan,
29
30
  });
30
31
  }
31
32
 
32
- const insertionGroups = variantInsertionGroups(worker, workerPlan.baseKeys, 'worker', context);
33
- const headInsertionGroups = variantInsertionGroups(head, headPlan.baseKeys, 'head', context);
34
- const headInsertionGroupsByAnchor = new Map(headInsertionGroups.map((group) => [insertionGroupKey(group), group]));
33
+ const importInsertionGroups = variantInsertionGroups(worker, workerPlan.baseKeys, 'worker', context, {
34
+ includeEntry: (entry) => entry.kind === 'import',
35
+ label: 'import'
36
+ });
37
+ const headImportInsertionGroups = variantInsertionGroups(head, headPlan.baseKeys, 'head', context, {
38
+ includeEntry: (entry) => entry.kind === 'import',
39
+ label: 'import'
40
+ });
41
+ const headImportGroupsByAnchor = new Map(headImportInsertionGroups.map((group) => [insertionGroupKey(group), group]));
35
42
  const headEntriesByKey = new Map(head.entries.map((entry) => [entry.key, entry]));
43
+ for (const group of importInsertionGroups) {
44
+ const anchor = headEntriesByKey.get(group.anchorKey);
45
+ if (!anchor) {
46
+ addConflict(context, {
47
+ code: JsTsSafeMergeConflictCodes.insertionAnchorMissing,
48
+ gateId: JsTsSafeMergeGateIds.resolvedInsertionAnchors,
49
+ side: 'head',
50
+ message: 'Head source is missing an import insertion anchor.',
51
+ details: { anchorKey: group.anchorKey, mode: group.mode }
52
+ });
53
+ continue;
54
+ }
55
+ const headGroup = headImportGroupsByAnchor.get(insertionGroupKey(group));
56
+ const insertionSpan = declarationInsertionSpan(head.sourceText, anchor, group.mode, headGroup);
57
+ const entries = mergedImportEntries(group.entries, headGroup?.entries ?? []);
58
+ edits.push({
59
+ kind: 'insert-imports',
60
+ start: insertionSpan.start,
61
+ end: insertionSpan.end,
62
+ text: importInsertionText(entries, detectLineEnding(head.sourceText))
63
+ });
64
+ importDeclarationAdditions += group.entries.length;
65
+ }
66
+
67
+ const insertionGroups = variantInsertionGroups(worker, workerPlan.baseKeys, 'worker', context, {
68
+ includeEntry: (entry) => entry.kind !== 'import',
69
+ label: 'declaration'
70
+ });
71
+ const headInsertionGroups = variantInsertionGroups(head, headPlan.baseKeys, 'head', context, {
72
+ includeEntry: (entry) => entry.kind !== 'import',
73
+ label: 'declaration'
74
+ });
75
+ const headDeclarationGroupsByAnchor = new Map(headInsertionGroups.map((group) => [insertionGroupKey(group), group]));
36
76
  let topLevelDeclarationAdditions = 0;
37
77
  for (const group of insertionGroups) {
38
78
  const anchor = headEntriesByKey.get(group.anchorKey);
@@ -46,7 +86,7 @@ export function createSourceMergePlan(base, worker, head, workerPlan, headPlan,
46
86
  });
47
87
  continue;
48
88
  }
49
- const headGroup = headInsertionGroupsByAnchor.get(insertionGroupKey(group));
89
+ const headGroup = headDeclarationGroupsByAnchor.get(insertionGroupKey(group));
50
90
  const insertionSpan = declarationInsertionSpan(head.sourceText, anchor, group.mode, headGroup);
51
91
  const entries = mergedDeclarationEntries(group.entries, headGroup?.entries ?? []);
52
92
  edits.push({
@@ -61,21 +101,23 @@ export function createSourceMergePlan(base, worker, head, workerPlan, headPlan,
61
101
  return {
62
102
  edits,
63
103
  importSpecifierAdditions,
104
+ importDeclarationAdditions,
64
105
  topLevelDeclarationAdditions
65
106
  };
66
107
  }
67
108
 
68
- function variantInsertionGroups(variant, baseKeys, side, context) {
109
+ function variantInsertionGroups(variant, baseKeys, side, context, options = {}) {
110
+ const includeEntry = options.includeEntry ?? (() => true);
69
111
  const groups = [];
70
112
  let index = 0;
71
113
  while (index < variant.entries.length) {
72
114
  const entry = variant.entries[index];
73
- if (baseKeys.has(entry.key)) {
115
+ if (baseKeys.has(entry.key) || !includeEntry(entry)) {
74
116
  index += 1;
75
117
  continue;
76
118
  }
77
119
  const start = index;
78
- while (index < variant.entries.length && !baseKeys.has(variant.entries[index].key)) index += 1;
120
+ while (index < variant.entries.length && !baseKeys.has(variant.entries[index].key) && includeEntry(variant.entries[index])) index += 1;
79
121
  const entries = variant.entries.slice(start, index);
80
122
  const previousBase = findPreviousBaseEntry(variant.entries, start, baseKeys);
81
123
  const nextBase = findNextBaseEntry(variant.entries, index, baseKeys);
@@ -84,7 +126,7 @@ function variantInsertionGroups(variant, baseKeys, side, context) {
84
126
  code: JsTsSafeMergeConflictCodes.ambiguousInsertionPoint,
85
127
  gateId: JsTsSafeMergeGateIds.resolvedInsertionAnchors,
86
128
  side,
87
- message: `${side} additions have no stable base declaration or import anchor.`,
129
+ message: `${side} ${options.label ?? 'additions'} additions have no stable base declaration or import anchor.`,
88
130
  details: { entries: entries.map((item) => item.names?.[0] ?? item.key) }
89
131
  });
90
132
  continue;
@@ -133,6 +175,7 @@ function mergedImportSpecifiers(baseSpecifiers, workerAdditions, headAdditions)
133
175
  }
134
176
 
135
177
  function renderImportStatement(importInfo, specifiers) {
178
+ if (importInfo.sideEffectOnly) return `import ${importInfo.quote}${importInfo.moduleSpecifier}${importInfo.quote};`;
136
179
  const clause = [];
137
180
  if (importInfo.defaultLocalName) clause.push(importInfo.defaultLocalName);
138
181
  if (importInfo.namespaceLocalName) clause.push(`* as ${importInfo.namespaceLocalName}`);
@@ -141,6 +184,41 @@ function renderImportStatement(importInfo, specifiers) {
141
184
  return `import ${importType}${clause.join(', ')} from ${importInfo.quote}${importInfo.moduleSpecifier}${importInfo.quote};`;
142
185
  }
143
186
 
187
+ function importInsertionText(entries, lineEnding) {
188
+ return entries
189
+ .map((entry) => normalizeLineEndings(entry.text.trimEnd(), lineEnding))
190
+ .map((text) => text.endsWith(lineEnding) ? text : `${text}${lineEnding}`)
191
+ .join('');
192
+ }
193
+
194
+ function mergedImportEntries(workerEntries, headEntries) {
195
+ const entriesByKey = new Map();
196
+ for (const entry of [...headEntries, ...workerEntries]) {
197
+ const existing = entriesByKey.get(entry.key);
198
+ if (!existing) {
199
+ entriesByKey.set(entry.key, { ...entry, importInfo: { ...entry.importInfo, specifiers: [...entry.importInfo.specifiers] } });
200
+ continue;
201
+ }
202
+ existing.importInfo.specifiers = mergedNewImportSpecifiers(existing.importInfo.specifiers, entry.importInfo.specifiers);
203
+ existing.text = renderImportStatement(existing.importInfo, existing.importInfo.specifiers);
204
+ }
205
+ return [...entriesByKey.values()].sort(compareImportEntries);
206
+ }
207
+
208
+ function mergedNewImportSpecifiers(left, right) {
209
+ const byCanonical = new Map();
210
+ for (const specifier of [...left, ...right]) byCanonical.set(specifier.canonical, specifier);
211
+ return [...byCanonical.values()].sort((a, b) => a.canonical.localeCompare(b.canonical));
212
+ }
213
+
214
+ function compareImportEntries(left, right) {
215
+ const moduleOrder = left.importInfo.moduleSpecifier.localeCompare(right.importInfo.moduleSpecifier);
216
+ if (moduleOrder !== 0) return moduleOrder;
217
+ const typeOrder = Number(Boolean(left.importInfo.typeOnly)) - Number(Boolean(right.importInfo.typeOnly));
218
+ if (typeOrder !== 0) return typeOrder;
219
+ return left.key.localeCompare(right.key);
220
+ }
221
+
144
222
  function declarationInsertionText(entries, lineEnding) {
145
223
  return entries
146
224
  .map((entry) => normalizeLineEndings(entry.text.trimEnd(), lineEnding))
@@ -1,6 +1,7 @@
1
1
  import { hashSemanticValue } from '@shapeshift-labs/frontier-lang-kernel';
2
2
  import { idFragment } from './native-import-utils.js';
3
3
  import { detectLineEnding, normalizeLineEndings } from './js-ts-safe-merge-context.js';
4
+ import { importEntryBindings } from './js-ts-safe-merge-import-entry-utils.js';
4
5
 
5
6
  function createOperationsFromLedgers(context) {
6
7
  const headByKey = new Map(context.head.entries.map((entry) => [entry.key, entry]));
@@ -108,8 +109,8 @@ function insertionAnchorForMergedEntry(entry, index, context) {
108
109
  if (previous) return {
109
110
  mode: 'after',
110
111
  anchorKey: previous.key,
111
- anchorSymbolName: entryName(previous),
112
- anchorSymbolKind: entrySymbolKind(previous),
112
+ anchorSymbolName: insertionAnchorName(previous),
113
+ anchorSymbolKind: insertionAnchorKind(previous),
113
114
  headSpan: spanForEntry(previous),
114
115
  sourcePath: context.sourcePath
115
116
  };
@@ -117,8 +118,8 @@ function insertionAnchorForMergedEntry(entry, index, context) {
117
118
  if (next) return {
118
119
  mode: 'before',
119
120
  anchorKey: next.key,
120
- anchorSymbolName: entryName(next),
121
- anchorSymbolKind: entrySymbolKind(next),
121
+ anchorSymbolName: insertionAnchorName(next),
122
+ anchorSymbolKind: insertionAnchorKind(next),
122
123
  headSpan: spanForEntry(next),
123
124
  sourcePath: context.sourcePath
124
125
  };
@@ -162,7 +163,7 @@ function entryAnchor(entry, sourcePath, language) {
162
163
  }
163
164
 
164
165
  function entryName(entry) {
165
- if (entry.kind === 'import') return entry.importInfo?.moduleSpecifier;
166
+ if (entry.kind === 'import') return importEntryBindings(entry)[0]?.localName ?? entry.importInfo?.moduleSpecifier;
166
167
  return entry.names?.join('|') ?? entry.key;
167
168
  }
168
169
 
@@ -171,6 +172,16 @@ function entrySymbolKind(entry) {
171
172
  return entry.declarationInfo?.declarationKind ?? entry.kind;
172
173
  }
173
174
 
175
+ function insertionAnchorName(entry) {
176
+ if (entry.kind === 'import') return entry.importInfo?.moduleSpecifier;
177
+ return entryName(entry);
178
+ }
179
+
180
+ function insertionAnchorKind(entry) {
181
+ if (entry.kind === 'import') return 'module';
182
+ return entrySymbolKind(entry);
183
+ }
184
+
174
185
  function spanForEntry(entry) {
175
186
  return { start: entry.start, end: entry.end };
176
187
  }
@@ -85,6 +85,7 @@ export function safeMergeJsTsImportsAndDeclarations(input = {}) {
85
85
  },
86
86
  summary: {
87
87
  importSpecifierAdditions: mergePlan.importSpecifierAdditions,
88
+ importDeclarationAdditions: mergePlan.importDeclarationAdditions,
88
89
  topLevelDeclarationAdditions: mergePlan.topLevelDeclarationAdditions,
89
90
  changedExistingDeclarations: 0,
90
91
  conflicts: 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.128",
3
+ "version": "0.2.130",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",