@shapeshift-labs/frontier-lang-compiler 0.2.112 → 0.2.113

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
@@ -213,6 +213,30 @@ When `includeOutputProjectSymbolGraph` is enabled, the same
213
213
  `moduleResolution` shape is used for output graph artifacts. Resolution is
214
214
  runtime-neutral: `baseUrl`, `paths`, `aliases`, and `compilerOptions.paths`
215
215
  are matched against the supplied project files, not the host filesystem.
216
+ Bare package imports also get explicit package identity. If `packages` is
217
+ provided, package export maps can resolve back to supplied workspace sources
218
+ and record the selected export condition:
219
+
220
+ ```js
221
+ const project = safeMergeJsTsProject({
222
+ includeOutputProjectSymbolGraph: true,
223
+ moduleResolution: {
224
+ packages: {
225
+ '@pkg/core': {
226
+ root: 'packages/core',
227
+ exports: { './utils': { import: './src/utils.ts', default: './dist/utils.js' } }
228
+ }
229
+ },
230
+ packageExportConditions: ['import', 'default']
231
+ },
232
+ baseFiles,
233
+ workerFiles,
234
+ headFiles
235
+ });
236
+
237
+ console.log(project.outputProjectSymbolGraph.importEdges[0].packageName); // "@pkg/core"
238
+ console.log(project.outputProjectSymbolGraph.importEdges[0].packageExportCondition); // "import"
239
+ ```
216
240
 
217
241
  High-risk native features also have explicit evidence policies. These policies are advisory in this package: they tell a swarm or admission queue what evidence is missing without silently changing the existing readiness classification.
218
242
 
@@ -1,9 +1,26 @@
1
1
  export type NativeProjectModuleResolutionPaths = Readonly<Record<string, readonly string[] | string>>;
2
+ export type NativeProjectPackageExportTarget = string | readonly string[] | NativeProjectPackageConditionalExports;
3
+ export type NativeProjectPackageExports = NativeProjectPackageExportTarget | Readonly<Record<string, NativeProjectPackageExportTarget>>;
4
+
5
+ export interface NativeProjectPackageConditionalExports {
6
+ readonly [condition: string]: NativeProjectPackageExportTarget;
7
+ }
8
+
9
+ export interface NativeProjectPackageResolutionOptions {
10
+ readonly root?: string;
11
+ readonly sourceRoot?: string;
12
+ readonly main?: string;
13
+ readonly types?: string;
14
+ readonly exports?: NativeProjectPackageExports;
15
+ }
2
16
 
3
17
  export interface NativeProjectModuleResolutionOptions {
4
18
  readonly baseUrl?: string;
5
19
  readonly paths?: NativeProjectModuleResolutionPaths;
6
20
  readonly aliases?: NativeProjectModuleResolutionPaths;
21
+ readonly packages?: Readonly<Record<string, NativeProjectPackageResolutionOptions>>;
22
+ readonly conditions?: readonly string[];
23
+ readonly packageExportConditions?: readonly string[];
7
24
  readonly compilerOptions?: {
8
25
  readonly baseUrl?: string;
9
26
  readonly paths?: NativeProjectModuleResolutionPaths;
@@ -79,8 +79,6 @@ export interface ImportNativeProjectOptions {
79
79
  }
80
80
 
81
81
  export type NativeProjectSymbolGraphRemainingField =
82
- | 'moduleEdges[].packageName'
83
- | 'moduleEdges[].packageExportCondition'
84
82
  | 'reExportIdentities[].originSymbolId'
85
83
  | 'reExportIdentities[].exportedSymbolId'
86
84
  | 'reExportIdentities[].localSymbolId'
@@ -112,13 +110,15 @@ export interface NativeProjectSymbolGraphModuleEdgeRecord {
112
110
  readonly resolvedModulePath?: string;
113
111
  readonly targetDocumentId?: string;
114
112
  readonly resolvedTargetSymbolId?: string;
115
- readonly resolutionKind?: 'relative-source' | 'relative-missing' | 'alias-source' | 'alias-missing' | 'path-alias-source' | 'path-alias-missing' | 'base-url-source' | 'base-url-missing' | string;
113
+ readonly resolutionKind?: 'relative-source' | 'relative-missing' | 'alias-source' | 'alias-missing' | 'path-alias-source' | 'path-alias-missing' | 'base-url-source' | 'base-url-missing' | 'package-source' | 'package-missing' | 'package-external' | string;
114
+ readonly packageName?: string;
115
+ readonly packageSubpath?: string;
116
+ readonly packageExportCondition?: string;
116
117
  readonly importKind?: string;
117
118
  readonly exportKind?: string;
118
119
  readonly importedName?: string;
119
120
  readonly exportedName?: string;
120
- readonly localName?: string;
121
- readonly namespace?: string;
121
+ readonly localName?: string; readonly namespace?: string;
122
122
  readonly isTypeOnly?: boolean;
123
123
  readonly isReExport?: boolean;
124
124
  readonly publicContract?: boolean;
@@ -141,8 +141,6 @@ export function createNativeProjectImportResult(input, imports) {
141
141
  }
142
142
 
143
143
  const PROJECT_SYMBOL_GRAPH_REMAINING_FIELDS = Object.freeze([
144
- 'moduleEdges[].packageName',
145
- 'moduleEdges[].packageExportCondition',
146
144
  'reExportIdentities[].originSymbolId',
147
145
  'reExportIdentities[].exportedSymbolId',
148
146
  'reExportIdentities[].localSymbolId',
@@ -244,6 +242,9 @@ function moduleEdgeRecord(relation, moduleEdgeByRelation, symbolsById, documents
244
242
  resolvedModulePath: resolution?.path,
245
243
  targetDocumentId: resolution?.documentId,
246
244
  resolutionKind: resolution?.kind,
245
+ packageName: resolution?.packageName,
246
+ packageSubpath: resolution?.packageSubpath,
247
+ packageExportCondition: resolution?.packageExportCondition,
247
248
  importKind: firstString(moduleEdge.importKind, value.importKind, symbolMetadata.importKind),
248
249
  exportKind: firstString(moduleEdge.exportKind, value.exportKind, symbolMetadata.exportKind),
249
250
  importedName: firstString(moduleEdge.importedName, value.importedName, symbolMetadata.importedName),
@@ -34,22 +34,25 @@ export function createProjectModuleSymbolResolver(symbols, documents) {
34
34
  }
35
35
 
36
36
  function resolveConfiguredProjectModule(moduleSpecifier, documentsByPath, moduleResolution) {
37
- const candidates = configuredModuleCandidates(moduleSpecifier, moduleResolution);
37
+ const packageInfo = packageSpecifierInfo(moduleSpecifier);
38
+ const candidates = configuredModuleCandidates(moduleSpecifier, moduleResolution, packageInfo);
38
39
  let firstMissing;
39
40
  for (const candidate of candidates) {
40
41
  const target = moduleTargetDocument(candidate.path, documentsByPath);
41
- if (target) return { path: target.path, documentId: target.id, kind: `${candidate.kind}-source` };
42
- firstMissing ??= { path: candidate.path, kind: `${candidate.kind}-missing` };
42
+ const packageFields = packageResolutionFields(candidate, packageInfo);
43
+ if (target) return { path: target.path, documentId: target.id, kind: `${candidate.kind}-source`, ...packageFields };
44
+ firstMissing ??= { path: candidate.path, kind: `${candidate.kind}-missing`, ...packageFields };
43
45
  }
44
- return firstMissing;
46
+ return firstMissing ?? (packageInfo ? { kind: 'package-external', ...packageInfo } : undefined);
45
47
  }
46
48
 
47
- function configuredModuleCandidates(moduleSpecifier, moduleResolution = {}) {
49
+ function configuredModuleCandidates(moduleSpecifier, moduleResolution = {}, packageInfo) {
48
50
  const compilerOptions = moduleResolution.compilerOptions ?? {};
49
51
  const baseUrl = normalizeProjectPath(moduleResolution.baseUrl ?? compilerOptions.baseUrl ?? '');
50
52
  return uniquePaths([
51
53
  ...aliasCandidates(moduleSpecifier, moduleResolution.aliases, 'alias', baseUrl),
52
54
  ...aliasCandidates(moduleSpecifier, moduleResolution.paths ?? compilerOptions.paths, 'path-alias', baseUrl),
55
+ ...packageCandidates(packageInfo, moduleResolution),
53
56
  ...baseUrlCandidates(moduleSpecifier, baseUrl)
54
57
  ]);
55
58
  }
@@ -71,6 +74,74 @@ function baseUrlCandidates(moduleSpecifier, baseUrl) {
71
74
  return [{ kind: 'base-url', path: normalizeProjectPath(joinProjectPath(baseUrl, moduleSpecifier)) }];
72
75
  }
73
76
 
77
+ function packageCandidates(packageInfo, moduleResolution = {}) {
78
+ if (!packageInfo) return [];
79
+ const options = moduleResolution.packages?.[packageInfo.packageName];
80
+ if (!options) return [];
81
+ const root = normalizeProjectPath(options.root ?? '');
82
+ const subpath = packageInfo.packageSubpath === '.' ? '' : packageInfo.packageSubpath.slice(2);
83
+ return uniquePaths([
84
+ ...packageExportCandidates(packageInfo, options, moduleResolution).map((candidate) => ({
85
+ ...candidate,
86
+ path: normalizeProjectPath(joinProjectPath(root, candidate.path))
87
+ })),
88
+ ...packageFallbackTargets(options, subpath).map((path) => ({
89
+ kind: 'package',
90
+ path: normalizeProjectPath(joinProjectPath(root, path)),
91
+ ...packageInfo
92
+ }))
93
+ ]);
94
+ }
95
+
96
+ function packageExportCandidates(packageInfo, options, moduleResolution) {
97
+ const targets = packageExportTargets(options.exports, packageInfo.packageSubpath, packageConditions(moduleResolution));
98
+ return targets.map((target) => ({
99
+ kind: 'package',
100
+ path: target.path,
101
+ packageExportCondition: target.condition,
102
+ ...packageInfo
103
+ }));
104
+ }
105
+
106
+ function packageExportTargets(exportsValue, subpath, conditions) {
107
+ if (!exportsValue) return [];
108
+ return exportTargetsForValue(exportMapValue(exportsValue, subpath), conditions);
109
+ }
110
+
111
+ function exportMapValue(exportsValue, subpath) {
112
+ if (!isRecord(exportsValue) || !Object.keys(exportsValue).some((key) => key.startsWith('.'))) return subpath === '.' ? exportsValue : undefined;
113
+ return exportsValue[subpath] ?? patternExportMapValue(exportsValue, subpath);
114
+ }
115
+
116
+ function patternExportMapValue(exportsValue, subpath) {
117
+ for (const [pattern, target] of Object.entries(exportsValue)) {
118
+ const capture = patternCapture(subpath, pattern);
119
+ if (capture !== undefined) return replaceExportTargetCapture(target, capture);
120
+ }
121
+ return undefined;
122
+ }
123
+
124
+ function replaceExportTargetCapture(target, capture) {
125
+ if (typeof target === 'string') return target.replace('*', capture);
126
+ if (Array.isArray(target)) return target.map((entry) => replaceExportTargetCapture(entry, capture));
127
+ if (!isRecord(target)) return target;
128
+ return Object.fromEntries(Object.entries(target).map(([key, value]) => [key, replaceExportTargetCapture(value, capture)]));
129
+ }
130
+
131
+ function exportTargetsForValue(value, conditions, condition) {
132
+ if (!value) return [];
133
+ if (typeof value === 'string') return [{ path: value, condition }];
134
+ if (Array.isArray(value)) return value.flatMap((entry) => exportTargetsForValue(entry, conditions, condition));
135
+ if (!isRecord(value)) return [];
136
+ return conditions.flatMap((key) => exportTargetsForValue(value[key], conditions, key));
137
+ }
138
+
139
+ function packageFallbackTargets(options, subpath) {
140
+ const sourceRoot = normalizeProjectPath(options.sourceRoot ?? 'src');
141
+ if (subpath) return [joinProjectPath(sourceRoot, subpath), subpath];
142
+ return [options.types, options.main, joinProjectPath(sourceRoot, 'index')].filter(Boolean);
143
+ }
144
+
74
145
  function moduleTargetDocument(path, documentsByPath) {
75
146
  for (const candidate of modulePathCandidates(path)) {
76
147
  const document = documentsByPath.get(candidate);
@@ -80,7 +151,7 @@ function moduleTargetDocument(path, documentsByPath) {
80
151
  }
81
152
 
82
153
  function modulePathCandidates(path) {
83
- return [path, `${path}.js`, `${path}.ts`, `${path}.tsx`, `${path}.jsx`, `${path}/index.js`, `${path}/index.ts`];
154
+ return [path, `${path}.js`, `${path}.ts`, `${path}.tsx`, `${path}.jsx`, `${path}.d.ts`, `${path}/index.js`, `${path}/index.ts`, `${path}/index.d.ts`];
84
155
  }
85
156
 
86
157
  function targetExportName(edge) {
@@ -114,6 +185,34 @@ function joinProjectPath(left, right) {
114
185
  return left ? `${left}/${right}` : String(right);
115
186
  }
116
187
 
188
+ function packageSpecifierInfo(moduleSpecifier) {
189
+ if (!moduleSpecifier || String(moduleSpecifier).startsWith('#')) return undefined;
190
+ const parts = String(moduleSpecifier).split('/');
191
+ if (!parts[0] || parts[0] === '.' || parts[0] === '..') return undefined;
192
+ const scoped = parts[0].startsWith('@');
193
+ if (scoped && parts.length < 2) return undefined;
194
+ const packageName = scoped ? `${parts[0]}/${parts[1]}` : parts[0];
195
+ const rest = parts.slice(scoped ? 2 : 1).join('/');
196
+ return { packageName, packageSubpath: rest ? `./${rest}` : '.' };
197
+ }
198
+
199
+ function packageResolutionFields(candidate, packageInfo) {
200
+ if (!candidate.packageName && candidate.kind !== 'package') return {};
201
+ return {
202
+ packageName: candidate.packageName ?? packageInfo?.packageName,
203
+ packageSubpath: candidate.packageSubpath ?? packageInfo?.packageSubpath,
204
+ packageExportCondition: candidate.packageExportCondition
205
+ };
206
+ }
207
+
208
+ function packageConditions(moduleResolution = {}) {
209
+ return moduleResolution.packageExportConditions ?? moduleResolution.conditions ?? ['types', 'import', 'module', 'require', 'default'];
210
+ }
211
+
212
+ function isRecord(value) {
213
+ return value && typeof value === 'object' && !Array.isArray(value);
214
+ }
215
+
117
216
  function normalizeProjectPath(path) {
118
217
  const parts = [];
119
218
  for (const part of String(path).split('/')) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shapeshift-labs/frontier-lang-compiler",
3
- "version": "0.2.112",
3
+ "version": "0.2.113",
4
4
  "description": "Compiler facade for Frontier Lang source documents and language projection adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",