@@ -54,6 +54,67 @@ describe("ElectronShell", () => {
5454 } ) . pipe ( Effect . provide ( ElectronShell . layer ) ) ,
5555 ) ;
5656
57+ it . effect ( "opens local editor file deep links" , ( ) =>
58+ Effect . gen ( function * ( ) {
59+ openExternalMock . mockResolvedValue ( undefined ) ;
60+
61+ const urls = [
62+ "cursor://file/Users/me/repo/file.md:186" ,
63+ "vscode://file/Users/me/repo/file.md:3:7" ,
64+ "vscode-insiders://file/Users/me/repo/file.md" ,
65+ "vscodium://file/C:/Users/me/repo/file.md:3" ,
66+ ] ;
67+ const electronShell = yield * ElectronShell . ElectronShell ;
68+ const results = yield * Effect . forEach ( urls , ( url ) => electronShell . openExternal ( url ) ) ;
69+
70+ assert . deepEqual ( results , [ true , true , true , true ] ) ;
71+ assert . deepEqual (
72+ openExternalMock . mock . calls ,
73+ urls . map ( ( url ) => [ url ] ) ,
74+ ) ;
75+ } ) . pipe ( Effect . provide ( ElectronShell . layer ) ) ,
76+ ) ;
77+
78+ it . effect ( "normalizes the scheme case of local editor file deep links" , ( ) =>
79+ Effect . gen ( function * ( ) {
80+ openExternalMock . mockResolvedValue ( undefined ) ;
81+
82+ const electronShell = yield * ElectronShell . ElectronShell ;
83+ const result = yield * electronShell . openExternal ( "VSCode://file/Users/me/repo/file.md:3" ) ;
84+
85+ assert . equal ( result , true ) ;
86+ assert . deepEqual ( openExternalMock . mock . calls , [ [ "vscode://file/Users/me/repo/file.md:3" ] ] ) ;
87+ } ) . pipe ( Effect . provide ( ElectronShell . layer ) ) ,
88+ ) ;
89+
90+ it . effect ( "does not open editor URLs that are not absolute local file links" , ( ) =>
91+ Effect . gen ( function * ( ) {
92+ openExternalMock . mockResolvedValue ( undefined ) ;
93+
94+ const electronShell = yield * ElectronShell . ElectronShell ;
95+ const results = yield * Effect . forEach (
96+ [
97+ "cursor://user@file/Users/me/repo/file.md" ,
98+ "cursor://:secret@file/Users/me/repo/file.md" ,
99+ "cursor://file:8080/Users/me/repo/file.md" ,
100+ "cursor://anysphere.cursor-deeplink/prompt?text=hi" ,
101+ "vscode://vscode.git/clone?url=https%3A%2F%2Fexample.com%2Frepo.git" ,
102+ "cursor://file" ,
103+ "cursor://file/" ,
104+ "cursor:file/Users/me/repo/file.md" ,
105+ "foo://file/Users/me/repo/file.md" ,
106+ "zed://file/Users/me/repo/file.md" ,
107+ "jetbrains://file/Users/me/repo/file.md" ,
108+ "javascript:alert(1)" ,
109+ ] ,
110+ ( url ) => electronShell . openExternal ( url ) ,
111+ ) ;
112+
113+ assert . deepEqual ( results , Array ( 12 ) . fill ( false ) ) ;
114+ assert . equal ( openExternalMock . mock . calls . length , 0 ) ;
115+ } ) . pipe ( Effect . provide ( ElectronShell . layer ) ) ,
116+ ) ;
117+
57118 it . effect ( "does not open editor URLs that mix up link shapes" , ( ) =>
58119 Effect . gen ( function * ( ) {
59120 openExternalMock . mockResolvedValue ( undefined ) ;
0 commit comments