@@ -3,6 +3,7 @@ import { readFileSync } from 'node:fs';
33import path from 'node:path' ;
44import { test } from 'node:test' ;
55import { listSourceFiles } from './check.ts' ;
6+ import { workspaceSpecifierTargets } from './package-boundaries.ts' ;
67import {
78 fieldClassificationDrift ,
89 findSessionStateWrites ,
@@ -167,63 +168,65 @@ test('parseImports records TSImportType edges separately from dynamic imports',
167168 ) ;
168169} ) ;
169170
171+ const RECORDED_IMPORT_TYPE_CASES = [
172+ [
173+ 'packages/contracts/src/platform-runtime.ts' ,
174+ 'packages/contracts/src/device-shutdown-runtime.ts' ,
175+ './device-shutdown-runtime.ts' ,
176+ 'DeviceShutdownRuntime' ,
177+ ] ,
178+ [
179+ 'packages/platform-apple/src/runner/runner-provider.ts' ,
180+ 'packages/platform-apple/src/runner/runner-artifact.ts' ,
181+ './runner-artifact.ts' ,
182+ 'RunnerStartAdmission' ,
183+ ] ,
184+ [
185+ 'src/daemon/interaction/index.ts' ,
186+ 'src/daemon/gesture-runtime.ts' ,
187+ '../gesture-runtime.ts' ,
188+ 'BoundGestureExecutor' ,
189+ ] ,
190+ [
191+ 'src/daemon/interaction/index.ts' ,
192+ 'src/daemon/touch-runtime.ts' ,
193+ '../touch-runtime.ts' ,
194+ 'BoundTouchExecutor' ,
195+ ] ,
196+ [
197+ 'src/daemon/interaction/internal/interaction.ts' ,
198+ 'packages/contracts/src/android-observation.ts' ,
199+ '@agent-device/contracts/android-observation' ,
200+ 'AndroidObservationAdapter' ,
201+ ] ,
202+ [
203+ 'src/daemon/snapshot-runtime-binding.ts' ,
204+ 'packages/contracts/src/focus-runtime.ts' ,
205+ '@agent-device/contracts/focus-runtime' ,
206+ 'FocusPointInput' ,
207+ ] ,
208+ [
209+ 'src/daemon/snapshot-runtime-binding.ts' ,
210+ 'packages/contracts/src/interactor-types.ts' ,
211+ '@agent-device/contracts/interactor-types' ,
212+ 'TypeTextBackendResult' ,
213+ ] ,
214+ [
215+ 'src/daemon/snapshot-runtime-binding.ts' ,
216+ 'packages/contracts/src/type-text-runtime.ts' ,
217+ '@agent-device/contracts/type-text-runtime' ,
218+ 'TypeTextInput' ,
219+ ] ,
220+ [
221+ 'src/sdk/artifacts.ts' ,
222+ 'packages/platform-android/src/mechanics.ts' ,
223+ '@agent-device/platform-android/mechanics' ,
224+ 'resolveAndroidArchivePackageName' ,
225+ ] ,
226+ ] as const ;
227+
170228test ( 'the nine recorded TSImportType shapes resolve with source-side symbols' , ( ) => {
171- const cases = [
172- [
173- 'packages/contracts/src/platform-runtime.ts' ,
174- 'packages/contracts/src/device-shutdown-runtime.ts' ,
175- './device-shutdown-runtime.ts' ,
176- 'DeviceShutdownRuntime' ,
177- ] ,
178- [
179- 'packages/platform-apple/src/runner/runner-provider.ts' ,
180- 'packages/platform-apple/src/runner/runner-artifact.ts' ,
181- './runner-artifact.ts' ,
182- 'RunnerStartAdmission' ,
183- ] ,
184- [
185- 'src/daemon/interaction/index.ts' ,
186- 'src/daemon/gesture-runtime.ts' ,
187- '../gesture-runtime.ts' ,
188- 'BoundGestureExecutor' ,
189- ] ,
190- [
191- 'src/daemon/interaction/index.ts' ,
192- 'src/daemon/touch-runtime.ts' ,
193- '../touch-runtime.ts' ,
194- 'BoundTouchExecutor' ,
195- ] ,
196- [
197- 'src/daemon/interaction/internal/interaction.ts' ,
198- 'packages/contracts/src/android-observation.ts' ,
199- '@agent-device/contracts/android-observation' ,
200- 'AndroidObservationAdapter' ,
201- ] ,
202- [
203- 'src/daemon/snapshot-runtime-binding.ts' ,
204- 'packages/contracts/src/focus-runtime.ts' ,
205- '@agent-device/contracts/focus-runtime' ,
206- 'FocusPointInput' ,
207- ] ,
208- [
209- 'src/daemon/snapshot-runtime-binding.ts' ,
210- 'packages/contracts/src/interactor-types.ts' ,
211- '@agent-device/contracts/interactor-types' ,
212- 'TypeTextBackendResult' ,
213- ] ,
214- [
215- 'src/daemon/snapshot-runtime-binding.ts' ,
216- 'packages/contracts/src/type-text-runtime.ts' ,
217- '@agent-device/contracts/type-text-runtime' ,
218- 'TypeTextInput' ,
219- ] ,
220- [
221- 'src/sdk/artifacts.ts' ,
222- 'packages/platform-android/src/mechanics.ts' ,
223- '@agent-device/platform-android/mechanics' ,
224- 'resolveAndroidArchivePackageName' ,
225- ] ,
226- ] as const ;
229+ const cases = RECORDED_IMPORT_TYPE_CASES ;
227230 const sources = new Map < string , string > ( ) ;
228231 const exports = new Map < string , string > ( ) ;
229232 for ( const [ index , [ file , target , spec , symbol ] ] of cases . entries ( ) ) {
@@ -253,6 +256,32 @@ test('the nine recorded TSImportType shapes resolve with source-side symbols', (
253256 ) ;
254257} ) ;
255258
259+ test ( 'the recorded production type dependencies resolve from their owning declarations' , ( ) => {
260+ const sources = new Map (
261+ listSourceFiles ( ) . map ( ( file ) => [ file , readFileSync ( path . resolve ( file ) , 'utf8' ) ] ) ,
262+ ) ;
263+ const edges = resolveImportEdges ( sources , workspaceSpecifierTargets ( process . cwd ( ) ) ) ;
264+ for ( const [ recordedFile , target , , recordedSymbol ] of RECORDED_IMPORT_TYPE_CASES ) {
265+ // #3304 moved the shutdown declaration to an ordinary type import in the operations module.
266+ const movedShutdown = recordedFile === 'packages/contracts/src/platform-runtime.ts' ;
267+ const file = movedShutdown
268+ ? 'packages/contracts/src/platform-runtime-operations.ts'
269+ : recordedFile ;
270+ const symbol = movedShutdown ? 'DeviceShutdownRuntimeOperations' : recordedSymbol ;
271+ assert . ok (
272+ edges . some (
273+ ( edge ) =>
274+ edge . file === file &&
275+ edge . target === target &&
276+ ! edge . dynamic &&
277+ edge . typeOnly &&
278+ edge . symbols . includes ( symbol ) ,
279+ ) ,
280+ `missing production type dependency: ${ file } -> ${ target } (${ symbol } )` ,
281+ ) ;
282+ }
283+ } ) ;
284+
256285test ( 'parseImports detects multiline dynamic imports' , ( ) => {
257286 const edges = parseImports ( [ 'void import(' , " '../multiline.ts'" , ');' ] . join ( '\n' ) ) ;
258287
0 commit comments