1- import fs from "node:fs" ;
2- import os from "node:os" ;
3- import path from "node:path" ;
4-
5- import { assert , describe , it } from "@effect/vitest" ;
1+ import * as NodeServices from "@effect/platform-node/NodeServices" ;
2+ import { assert , it } from "@effect/vitest" ;
3+ import { assertSuccess } from "@effect/vitest/utils" ;
4+ import { FileSystem , Path , Effect } from "effect" ;
65
76import {
87 isCommandAvailable ,
98 launchDetached ,
109 resolveAvailableEditors ,
1110 resolveEditorLaunch ,
1211} from "./open" ;
13- import { Effect } from "effect" ;
14- import { assertSuccess } from "@effect/vitest/utils" ;
1512
16- describe ( "resolveEditorLaunch" , ( ) => {
13+ it . layer ( NodeServices . layer ) ( "resolveEditorLaunch" , ( it ) => {
1714 it . effect ( "returns commands for command-based editors" , ( ) =>
1815 Effect . gen ( function * ( ) {
16+ const antigravityLaunch = yield * resolveEditorLaunch (
17+ { cwd : "/tmp/workspace" , editor : "antigravity" } ,
18+ "darwin" ,
19+ ) ;
20+ assert . deepEqual ( antigravityLaunch , {
21+ command : "agy" ,
22+ args : [ "/tmp/workspace" ] ,
23+ } ) ;
24+
1925 const cursorLaunch = yield * resolveEditorLaunch (
2026 { cwd : "/tmp/workspace" , editor : "cursor" } ,
2127 "darwin" ,
@@ -117,7 +123,7 @@ describe("resolveEditorLaunch", () => {
117123 ) ;
118124} ) ;
119125
120- describe ( "launchDetached" , ( ) => {
126+ it . layer ( NodeServices . layer ) ( "launchDetached" , ( it ) => {
121127 it . effect ( "resolves when command can be spawned" , ( ) =>
122128 Effect . gen ( function * ( ) {
123129 const result = yield * launchDetached ( {
@@ -139,26 +145,20 @@ describe("launchDetached", () => {
139145 ) ;
140146} ) ;
141147
142- describe ( "isCommandAvailable" , ( ) => {
143- function withTempDir ( run : ( dir : string ) => void ) : void {
144- const dir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , "t3-open-" ) ) ;
145- try {
146- run ( dir ) ;
147- } finally {
148- fs . rmSync ( dir , { recursive : true , force : true } ) ;
149- }
150- }
151-
152- it ( "resolves win32 commands with PATHEXT" , ( ) => {
153- withTempDir ( ( dir ) => {
154- fs . writeFileSync ( path . join ( dir , "code.CMD" ) , "@echo off\r\n" , "utf8" ) ;
148+ it . layer ( NodeServices . layer ) ( "isCommandAvailable" , ( it ) => {
149+ it . effect ( "resolves win32 commands with PATHEXT" , ( ) =>
150+ Effect . gen ( function * ( ) {
151+ const fs = yield * FileSystem . FileSystem ;
152+ const path = yield * Path . Path ;
153+ const dir = yield * fs . makeTempDirectoryScoped ( { prefix : "t3-open-test-" } ) ;
154+ yield * fs . writeFileString ( path . join ( dir , "code.CMD" ) , "@echo off\r\n" ) ;
155155 const env = {
156156 PATH : dir ,
157157 PATHEXT : ".COM;.EXE;.BAT;.CMD" ,
158158 } satisfies NodeJS . ProcessEnv ;
159159 assert . equal ( isCommandAvailable ( "code" , { platform : "win32" , env } ) , true ) ;
160- } ) ;
161- } ) ;
160+ } ) ,
161+ ) ;
162162
163163 it ( "returns false when a command is not on PATH" , ( ) => {
164164 const env = {
@@ -168,55 +168,65 @@ describe("isCommandAvailable", () => {
168168 assert . equal ( isCommandAvailable ( "definitely-not-installed" , { platform : "win32" , env } ) , false ) ;
169169 } ) ;
170170
171- it ( "does not treat bare files without executable extension as available on win32" , ( ) => {
172- withTempDir ( ( dir ) => {
173- fs . writeFileSync ( path . join ( dir , "npm" ) , "echo nope\r\n" , "utf8" ) ;
171+ it . effect ( "does not treat bare files without executable extension as available on win32" , ( ) =>
172+ Effect . gen ( function * ( ) {
173+ const fs = yield * FileSystem . FileSystem ;
174+ const path = yield * Path . Path ;
175+ const dir = yield * fs . makeTempDirectoryScoped ( { prefix : "t3-open-test-" } ) ;
176+ yield * fs . writeFileString ( path . join ( dir , "npm" ) , "echo nope\r\n" ) ;
174177 const env = {
175178 PATH : dir ,
176179 PATHEXT : ".COM;.EXE;.BAT;.CMD" ,
177180 } satisfies NodeJS . ProcessEnv ;
178181 assert . equal ( isCommandAvailable ( "npm" , { platform : "win32" , env } ) , false ) ;
179- } ) ;
180- } ) ;
182+ } ) ,
183+ ) ;
181184
182- it ( "appends PATHEXT for commands with non-executable extensions on win32" , ( ) => {
183- withTempDir ( ( dir ) => {
184- fs . writeFileSync ( path . join ( dir , "my.tool.CMD" ) , "@echo off\r\n" , "utf8" ) ;
185+ it . effect ( "appends PATHEXT for commands with non-executable extensions on win32" , ( ) =>
186+ Effect . gen ( function * ( ) {
187+ const fs = yield * FileSystem . FileSystem ;
188+ const path = yield * Path . Path ;
189+ const dir = yield * fs . makeTempDirectoryScoped ( { prefix : "t3-open-test-" } ) ;
190+ yield * fs . writeFileString ( path . join ( dir , "my.tool.CMD" ) , "@echo off\r\n" ) ;
185191 const env = {
186192 PATH : dir ,
187193 PATHEXT : ".COM;.EXE;.BAT;.CMD" ,
188194 } satisfies NodeJS . ProcessEnv ;
189195 assert . equal ( isCommandAvailable ( "my.tool" , { platform : "win32" , env } ) , true ) ;
190- } ) ;
191- } ) ;
196+ } ) ,
197+ ) ;
192198
193- it ( "uses platform-specific PATH delimiter for platform overrides" , ( ) => {
194- withTempDir ( ( firstDir ) => {
195- withTempDir ( ( secondDir ) => {
196- fs . writeFileSync ( path . join ( secondDir , "code.CMD" ) , "@echo off\r\n" , "utf8" ) ;
197- const env = {
198- PATH : `${ firstDir } ;${ secondDir } ` ,
199- PATHEXT : ".COM;.EXE;.BAT;.CMD" ,
200- } satisfies NodeJS . ProcessEnv ;
201- assert . equal ( isCommandAvailable ( "code" , { platform : "win32" , env } ) , true ) ;
202- } ) ;
203- } ) ;
204- } ) ;
199+ it . effect ( "uses platform-specific PATH delimiter for platform overrides" , ( ) =>
200+ Effect . gen ( function * ( ) {
201+ const fs = yield * FileSystem . FileSystem ;
202+ const path = yield * Path . Path ;
203+ const firstDir = yield * fs . makeTempDirectoryScoped ( { prefix : "t3-open-test-" } ) ;
204+ const secondDir = yield * fs . makeTempDirectoryScoped ( { prefix : "t3-open-test-" } ) ;
205+ yield * fs . writeFileString ( path . join ( firstDir , "code.CMD" ) , "@echo off\r\n" ) ;
206+ yield * fs . writeFileString ( path . join ( secondDir , "code.CMD" ) , "MZ" ) ;
207+ const env = {
208+ PATH : `${ firstDir } ;${ secondDir } ` ,
209+ PATHEXT : ".COM;.EXE;.BAT;.CMD" ,
210+ } satisfies NodeJS . ProcessEnv ;
211+ assert . equal ( isCommandAvailable ( "code" , { platform : "win32" , env } ) , true ) ;
212+ } ) ,
213+ ) ;
205214} ) ;
206215
207- describe ( "resolveAvailableEditors" , ( ) => {
208- it ( "returns only editors whose launch commands are available" , ( ) => {
209- const dir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , "t3-editors-" ) ) ;
210- try {
211- fs . writeFileSync ( path . join ( dir , "cursor.CMD" ) , "@echo off\r\n" , "utf8" ) ;
212- fs . writeFileSync ( path . join ( dir , "explorer.EXE" ) , "MZ" , "utf8" ) ;
216+ it . layer ( NodeServices . layer ) ( "resolveAvailableEditors" , ( it ) => {
217+ it . effect ( "returns installed editors for command launches" , ( ) =>
218+ Effect . gen ( function * ( ) {
219+ const fs = yield * FileSystem . FileSystem ;
220+ const path = yield * Path . Path ;
221+ const dir = yield * fs . makeTempDirectoryScoped ( { prefix : "t3-editors-" } ) ;
222+
223+ yield * fs . writeFileString ( path . join ( dir , "cursor.CMD" ) , "@echo off\r\n" ) ;
224+ yield * fs . writeFileString ( path . join ( dir , "explorer.CMD" ) , "MZ" ) ;
213225 const editors = resolveAvailableEditors ( "win32" , {
214226 PATH : dir ,
215227 PATHEXT : ".COM;.EXE;.BAT;.CMD" ,
216228 } ) ;
217229 assert . deepEqual ( editors , [ "cursor" , "file-manager" ] ) ;
218- } finally {
219- fs . rmSync ( dir , { recursive : true , force : true } ) ;
220- }
221- } ) ;
230+ } ) ,
231+ ) ;
222232} ) ;
0 commit comments