diff --git a/v2/internal/frontend/desktop/darwin/AppDelegate.h b/v2/internal/frontend/desktop/darwin/AppDelegate.h index e2dd841c9..7b533ad5f 100644 --- a/v2/internal/frontend/desktop/darwin/AppDelegate.h +++ b/v2/internal/frontend/desktop/darwin/AppDelegate.h @@ -11,7 +11,7 @@ #import #import "WailsContext.h" -@interface AppDelegate : NSResponder +@interface AppDelegate : NSResponder @property bool alwaysOnTop; @property bool startHidden; @@ -20,4 +20,6 @@ @end +extern void HandleOpenFile(char *); + #endif /* AppDelegate_h */ diff --git a/v2/internal/frontend/desktop/darwin/AppDelegate.m b/v2/internal/frontend/desktop/darwin/AppDelegate.m index b66979e76..6a9f5a4c3 100644 --- a/v2/internal/frontend/desktop/darwin/AppDelegate.m +++ b/v2/internal/frontend/desktop/darwin/AppDelegate.m @@ -11,9 +11,17 @@ #import "AppDelegate.h" @implementation AppDelegate -- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender { - return NO; +-(BOOL)application:(NSApplication *)sender openFile:(NSString *)filename +{ + const char* utf8FileName = filename.UTF8String; + HandleOpenFile((char*)utf8FileName); + return YES; } + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender { + return NO; +} + - (void)applicationWillFinishLaunching:(NSNotification *)aNotification { [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; if (self.alwaysOnTop) { diff --git a/v2/internal/frontend/desktop/darwin/frontend.go b/v2/internal/frontend/desktop/darwin/frontend.go index a6a0808fd..66e5dc0cf 100644 --- a/v2/internal/frontend/desktop/darwin/frontend.go +++ b/v2/internal/frontend/desktop/darwin/frontend.go @@ -38,6 +38,7 @@ const startURL = "wails://wails/" var messageBuffer = make(chan string, 100) var requestBuffer = make(chan webview.Request, 100) var callbackBuffer = make(chan uint, 10) +var openFilepathBuffer = make(chan string, 100) type Frontend struct { @@ -107,15 +108,23 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger. go result.startMessageProcessor() go result.startCallbackProcessor() + go result.startFileOpenProcessor() return result } +func (f *Frontend) startFileOpenProcessor() { + for filePath := range openFilepathBuffer { + f.ProcessOpenFileEvent(filePath) + } +} + func (f *Frontend) startMessageProcessor() { for message := range messageBuffer { f.processMessage(message) } } + func (f *Frontend) startRequestProcessor() { for request := range requestBuffer { f.assets.ServeWebViewRequest(request) @@ -355,6 +364,12 @@ func (f *Frontend) processMessage(message string) { } +func (f *Frontend) ProcessOpenFileEvent(filePath string) { + if f.frontendOptions.Mac != nil && f.frontendOptions.Mac.OnFileOpen != nil { + f.frontendOptions.Mac.OnFileOpen(filePath) + } +} + func (f *Frontend) Callback(message string) { escaped, err := json.Marshal(message) if err != nil { @@ -398,3 +413,9 @@ func processCallback(callbackID uint) { func processURLRequest(_ unsafe.Pointer, wkURLSchemeTask unsafe.Pointer) { requestBuffer <- webview.NewRequest(wkURLSchemeTask) } + +//export HandleOpenFile +func HandleOpenFile(filePath *C.char) { + goFilepath := C.GoString(filePath) + openFilepathBuffer <- goFilepath +} diff --git a/v2/internal/project/project.go b/v2/internal/project/project.go index 023ca1dfe..a0bf518a9 100644 --- a/v2/internal/project/project.go +++ b/v2/internal/project/project.go @@ -216,11 +216,20 @@ type Author struct { } type Info struct { - CompanyName string `json:"companyName"` - ProductName string `json:"productName"` - ProductVersion string `json:"productVersion"` - Copyright *string `json:"copyright"` - Comments *string `json:"comments"` + CompanyName string `json:"companyName"` + ProductName string `json:"productName"` + ProductVersion string `json:"productVersion"` + Copyright *string `json:"copyright"` + Comments *string `json:"comments"` + FileAssociations []FileAssociation `json:"fileAssociations"` +} + +type FileAssociation struct { + Ext string `json:"ext"` + Name string `json:"name"` + Description string `json:"description"` + IconName string `json:"iconName"` + Role string `json:"role"` } type Bindings struct { diff --git a/v2/pkg/buildassets/build/darwin/Info.dev.plist b/v2/pkg/buildassets/build/darwin/Info.dev.plist index 02e7358ee..9d4096f4f 100644 --- a/v2/pkg/buildassets/build/darwin/Info.dev.plist +++ b/v2/pkg/buildassets/build/darwin/Info.dev.plist @@ -23,10 +23,29 @@ true NSHumanReadableCopyright {{.Info.Copyright}} + {{if .Info.FileAssociations}} + CFBundleDocumentTypes + + {{range .Info.FileAssociations}} + + CFBundleTypeExtensions + + {{.Ext}} + + CFBundleTypeName + {{.Name}} + CFBundleTypeRole + {{.Role}} + CFBundleTypeIconFile + {{.IconName}} + + {{end}} + + {{end}} NSAppTransportSecurity NSAllowsLocalNetworking - \ No newline at end of file + diff --git a/v2/pkg/buildassets/build/darwin/Info.plist b/v2/pkg/buildassets/build/darwin/Info.plist index e7819a7e8..079bdafa9 100644 --- a/v2/pkg/buildassets/build/darwin/Info.plist +++ b/v2/pkg/buildassets/build/darwin/Info.plist @@ -23,5 +23,24 @@ true NSHumanReadableCopyright {{.Info.Copyright}} + {{if .Info.FileAssociations}} + CFBundleDocumentTypes + + {{range .Info.FileAssociations}} + + CFBundleTypeExtensions + + {{.Ext}} + + CFBundleTypeName + {{.Name}} + CFBundleTypeRole + {{.Role}} + CFBundleTypeIconFile + {{.IconName}} + + {{end}} + + {{end}} - \ No newline at end of file + diff --git a/v2/pkg/buildassets/build/windows/installer/project.nsi b/v2/pkg/buildassets/build/windows/installer/project.nsi index 13cc4f023..f18f2b5df 100644 --- a/v2/pkg/buildassets/build/windows/installer/project.nsi +++ b/v2/pkg/buildassets/build/windows/installer/project.nsi @@ -3,10 +3,10 @@ Unicode true #### ## Please note: Template replacements don't work in this file. They are provided with default defines like ## mentioned underneath. -## If the keyword is not defined, "wails_tools.nsh" will populate them with the values from ProjectInfo. -## If they are defined here, "wails_tools.nsh" will not touch them. This allows to use this project.nsi manually +## If the keyword is not defined, "wails_tools.nsh" will populate them with the values from ProjectInfo. +## If they are defined here, "wails_tools.nsh" will not touch them. This allows to use this project.nsi manually ## from outside of Wails for debugging and development of the installer. -## +## ## For development first make a wails nsis build to populate the "wails_tools.nsh": ## > wails build --target windows/amd64 --nsis ## Then you can call makensis on this file with specifying the path to your binary: @@ -17,7 +17,7 @@ Unicode true ## For a installer with both architectures: ## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app-amd64.exe -DARG_WAILS_ARM64_BINARY=..\..\bin\app-arm64.exe #### -## The following information is taken from the ProjectInfo file, but they can be overwritten here. +## The following information is taken from the ProjectInfo file, but they can be overwritten here. #### ## !define INFO_PROJECTNAME "MyProject" # Default "{{.Name}}" ## !define INFO_COMPANYNAME "MyCompany" # Default "{{.Info.CompanyName}}" @@ -85,16 +85,18 @@ Section !insertmacro wails.webview2runtime SetOutPath $INSTDIR - + !insertmacro wails.files CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" + !insertmacro wails.associateFiles + !insertmacro wails.writeUninstaller SectionEnd -Section "uninstall" +Section "uninstall" !insertmacro wails.setShellContext RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath @@ -104,5 +106,7 @@ Section "uninstall" Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk" + !insertmacro wails.unassociateFiles + !insertmacro wails.deleteUninstaller SectionEnd diff --git a/v2/pkg/buildassets/build/windows/installer/wails_tools.nsh b/v2/pkg/buildassets/build/windows/installer/wails_tools.nsh index 467c349ac..bc79fb395 100644 --- a/v2/pkg/buildassets/build/windows/installer/wails_tools.nsh +++ b/v2/pkg/buildassets/build/windows/installer/wails_tools.nsh @@ -163,17 +163,58 @@ RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}" Goto ok ${EndIf} ${EndIf} - + SetDetailsPrint both DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}" SetDetailsPrint listonly - + InitPluginsDir CreateDirectory "$pluginsdir\webview2bootstrapper" SetOutPath "$pluginsdir\webview2bootstrapper" File "tmp\MicrosoftEdgeWebview2Setup.exe" ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install' - + SetDetailsPrint both ok: -!macroend \ No newline at end of file +!macroend + +# Copy of APP_ASSOCIATE and APP_UNASSOCIATE macros from here https://gist.github.com/nikku/281d0ef126dbc215dd58bfd5b3a5cd5b +!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND + ; Backup the previously associated file class + ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" "" + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0" + + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}" + + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" "open" + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open" "" `${COMMANDTEXT}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open\command" "" `${COMMAND}` +!macroend + +!macro APP_UNASSOCIATE EXT FILECLASS + ; Backup the previously associated file class + ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" `${FILECLASS}_backup` + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "$R0" + + DeleteRegKey SHELL_CONTEXT `Software\Classes\${FILECLASS}` +!macroend + +!macro wails.associateFiles + ; Create file associations + {{range .Info.FileAssociations}} + !insertmacro APP_ASSOCIATE "{{.Ext}}" "{{.Name}}" "{{.Description}}" "$INSTDIR\{{.IconName}}.ico" "Open with ${INFO_PRODUCTNAME}" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\"" + + File "..\{{.IconName}}.ico" + {{end}} +!macroend + +!macro wails.unassociateFiles + ; Delete app associations + {{range .Info.FileAssociations}} + !insertmacro APP_UNASSOCIATE "{{.Ext}}" "{{.Name}}" + + Delete "$INSTDIR\{{.IconName}}.ico" + {{end}} +!macroend diff --git a/v2/pkg/commands/build/packager.go b/v2/pkg/commands/build/packager.go index 92ce37e90..beca47c5b 100644 --- a/v2/pkg/commands/build/packager.go +++ b/v2/pkg/commands/build/packager.go @@ -6,6 +6,7 @@ import ( "github.com/leaanthony/winicon" "github.com/tc-hib/winres" "github.com/tc-hib/winres/version" + "github.com/wailsapp/wails/v2/internal/project" "image" "os" "path/filepath" @@ -95,12 +96,20 @@ func packageApplicationForDarwin(options *Options) error { return err } - // Generate Icons - err = processApplicationIcon(options, resourceDir) + // Generate App Icon + err = processDarwinIcon(options.ProjectData, "appicon", resourceDir, "iconfile") if err != nil { return err } + // Generate FileAssociation Icons + for _, fileAssociation := range options.ProjectData.Info.FileAssociations { + err = processDarwinIcon(options.ProjectData, fileAssociation.IconName, resourceDir, "") + if err != nil { + return err + } + } + options.CompiledBinary = packedBinaryPath return nil @@ -124,8 +133,8 @@ func processPList(options *Options, contentsDirectory string) error { return os.WriteFile(targetFile, content, 0644) } -func processApplicationIcon(options *Options, resourceDir string) (err error) { - appIcon, err := buildassets.ReadFile(options.ProjectData, "appicon.png") +func processDarwinIcon(projectData *project.Project, iconName string, resourceDir string, destIconName string) (err error) { + appIcon, err := buildassets.ReadFile(projectData, iconName+".png") if err != nil { return err } @@ -135,7 +144,11 @@ func processApplicationIcon(options *Options, resourceDir string) (err error) { return err } - tgtBundle := filepath.Join(resourceDir, "iconfile.icns") + if destIconName == "" { + destIconName = iconName + } + + tgtBundle := filepath.Join(resourceDir, destIconName+".icns") dest, err := os.Create(tgtBundle) if err != nil { return err @@ -151,13 +164,21 @@ func processApplicationIcon(options *Options, resourceDir string) (err error) { } func packageApplicationForWindows(options *Options) error { - // Generate icon + // Generate app icon var err error - err = generateIcoFile(options) + err = generateIcoFile(options, "appicon", "icon") if err != nil { return err } + // Generate FileAssociation Icons + for _, fileAssociation := range options.ProjectData.Info.FileAssociations { + err = generateIcoFile(options, fileAssociation.IconName, "") + if err != nil { + return err + } + } + // Create syso file err = compileResources(options) if err != nil { @@ -171,13 +192,18 @@ func packageApplicationForLinux(_ *Options) error { return nil } -func generateIcoFile(options *Options) error { - content, err := buildassets.ReadFile(options.ProjectData, "appicon.png") +func generateIcoFile(options *Options, iconName string, destIconName string) error { + content, err := buildassets.ReadFile(options.ProjectData, iconName+".png") if err != nil { return err } + + if destIconName == "" { + destIconName = iconName + } + // Check ico file exists already - icoFile := buildassets.GetLocalPath(options.ProjectData, "windows/icon.ico") + icoFile := buildassets.GetLocalPath(options.ProjectData, "windows/"+destIconName+".ico") if !fs.FileExists(icoFile) { if dir := filepath.Dir(icoFile); !fs.DirExists(dir) { if err := fs.MkDirs(dir, 0755); err != nil { diff --git a/v2/pkg/options/mac/mac.go b/v2/pkg/options/mac/mac.go index 9838b145b..ecd2923fb 100644 --- a/v2/pkg/options/mac/mac.go +++ b/v2/pkg/options/mac/mac.go @@ -22,6 +22,7 @@ type Options struct { WindowIsTranslucent bool Preferences *Preferences //ActivationPolicy ActivationPolicy - About *AboutInfo + About *AboutInfo + OnFileOpen func(filePath string) `json:"-"` //URLHandlers map[string]func(string) } diff --git a/website/docs/guides/file-association.mdx b/website/docs/guides/file-association.mdx new file mode 100644 index 000000000..ff3ca6e6b --- /dev/null +++ b/website/docs/guides/file-association.mdx @@ -0,0 +1,184 @@ +# File Association + +File association feature allows you to associate specific file types with your app so that when users open those files, +your app is launched to handle them. This can be particularly useful for text editors, image viewers, or any application +that works with specific file formats. In this guide, we'll walk through the steps to implement file association in Wails app. + + +## Set Up File Association: +To set up file association, you need to modify your application's wails.json file. +In "info" section add a "fileAssociations" section specifying the file types your app should be associated with. + +For example: +```json +{ + "info": { + "fileAssociations": [ + { + "ext": "wails", + "name": "Wails", + "description": "Wails Application File", + "iconName": "wailsFileIcon", + "role": "Editor" + }, + { + "ext": "jpg", + "name": "JPEG", + "description": "Image File", + "iconName": "jpegFileIcon", + "role": "Editor" + } + ] + } +} +``` + +| Property | Description | +|:------------|:---------------------------------------------------------------------------------------------------------------------------------------------------| +| ext | The extension (minus the leading period). e.g. png | +| name | The name. e.g. PNG File | +| iconName | The icon name without extension. Icons should be located in build folder. Proper icons will be generated from .png file for both macOS and Windows | +| description | Windows-only. The description. It is displayed on the `Type` column on Windows Explorer. | +| role | macOS-only. The app’s role with respect to the type. Corresponds to CFBundleTypeRole. | + +## Platform Specifics: + +### macOS +When you open file (or files) with your app, the system will launch your app and call the `OnFileOpen` function in your Wails app. Example: +```go title="main.go" +func main() { + // Create application with options + err := wails.Run(&options.App{ + Title: "wails-open-file", + Width: 1024, + Height: 768, + AssetServer: &assetserver.Options{ + Assets: assets, + }, + BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, + Mac: &mac.Options{ + OnFileOpen: func(filePaths []string) { println(filestring) }, + }, + Bind: []interface{}{ + app, + }, + }) + + if err != nil { + println("Error:", err.Error()) + } +} +``` + + +### Windows +On Windows file association is supported only with NSIS installer. During installation, the installer will create a +registry entry for your file associations. When you open file with your app, new instance of app is launched and file path is passed +as argument to your app. To handle this you should parse command line arguments in your app. Example: +```go title="main.go" +func main() { + argsWithoutProg := os.Args[1:] + + if len(argsWithoutProg) != 0 { + println("launchArgs", argsWithoutProg) + } +} +``` + +### Linux +Currently, Wails doesn't support bundling for Linux. So, you need to create file associations manually. +For example if you distribute your app as a .deb package, you can create file associations by adding required files in you bundle. +You can use [nfpm](https://nfpm.goreleaser.com/) to create .deb package for your app. + +1. Create a .desktop file for your app and specify file associations there. Example: +```ini +[Desktop Entry] +Categories=Office +Exec=/usr/bin/wails-open-file %u +Icon=wails-open-file.png +Name=wails-open-file +Terminal=false +Type=Application +MimeType=application/x-wails;application/x-test +``` + +2. Create mime types file. Example: +```xml + + + + Wails Application File + + + +``` + +3. Create icons for your file types. SVG icons are recommended. +4. Prepare postInstall/postRemove scripts for your package. Example: +```sh +# reload mime types to register file associations +update-mime-database /usr/share/mime +# reload desktop database to load app in list of available +update-desktop-database /usr/share/applications +# update icons +update-icon-caches /usr/share/icons/* +``` +5. Configure nfpm to use your scripts and files. Example: +```yaml +name: "wails-open-file" +arch: "arm64" +platform: "linux" +version: "1.0.0" +section: "default" +priority: "extra" +maintainer: "FooBarCorp " +description: "Sample Package" +vendor: "FooBarCorp" +homepage: "http://example.com" +license: "MIT" +contents: +- src: ../bin/wails-open-file + dst: /usr/bin/wails-open-file +- src: ./main.desktop + dst: /usr/share/applications/wails-open-file.desktop +- src: ./application-wails-mime.xml + dst: /usr/share/mime/packages/application-x-wails.xml +- src: ./application-test-mime.xml + dst: /usr/share/mime/packages/application-x-test.xml +- src: ../appicon.svg + dst: /usr/share/icons/hicolor/scalable/apps/wails-open-file.svg +- src: ../wailsFileIcon.svg + dst: /usr/share/icons/hicolor/scalable/mimetypes/application-x-wails.svg +- src: ../testFileIcon.svg + dst: /usr/share/icons/hicolor/scalable/mimetypes/application-x-test.svg +# copy icons to Yaru theme as well. For some reason Ubuntu didn't pick up fileicons from hicolor theme +- src: ../appicon.svg + dst: /usr/share/icons/Yaru/scalable/apps/wails-open-file.svg +- src: ../wailsFileIcon.svg + dst: /usr/share/icons/Yaru/scalable/mimetypes/application-x-wails.svg +- src: ../testFileIcon.svg + dst: /usr/share/icons/Yaru/scalable/mimetypes/application-x-test.svg +scripts: + postinstall: ./postInstall.sh + postremove: ./postRemove.sh +``` +6. Build your .deb package using nfpm: +```sh +nfpm pkg --packager deb --target . +``` +7. Now when your package is installed, your app will be associated with specified file types. When you open file with your app, +new instance of app is launched and file path is passed as argument to your app. +To handle this you should parse command line arguments in your app. Example: +```go title="main.go" +func main() { + argsWithoutProg := os.Args[1:] + + if len(argsWithoutProg) != 0 { + println("launchArgs", argsWithoutProg) + } +} +``` + +## Limitations: +On Windows and Linux when associated file is opened, new instance of your app is launched. +Currently, Wails doesn't support opening files in already running app. There is plugin for single instance support for v3 in development. diff --git a/website/src/pages/changelog.mdx b/website/src/pages/changelog.mdx index 7da2b65f8..1b0fe038d 100644 --- a/website/src/pages/changelog.mdx +++ b/website/src/pages/changelog.mdx @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added support for enabling/disabling swipe gestures for Windows WebView2. Added by @leaanthony in [PR](https://github.com/wailsapp/wails/pull/2878) - When building with `-devtools` flag, CMD/CTRL+SHIFT+F12 can be used to open the devtools. Added by @leaanthony in [PR](https://github.com/wailsapp/wails/pull/2915) +– Added file association support for macOS and Windows. Added by @APshenkin in [PR](https://github.com/wailsapp/wails/pull/2918) - Added support for setting some of the Webview preferences, `textInteractionEnabled` and `tabFocusesLinks` on Mac. Added by @fkhadra in [PR](https://github.com/wailsapp/wails/pull/2937) - Added support for enabling/disabling fullscreen of the Webview on Mac. Added by @fkhadra in [PR](https://github.com/wailsapp/wails/pull/2953) - Added French README.fr.md page. Added by @nejos97 in [PR](https://github.com/wailsapp/wails/pull/2943) diff --git a/website/static/schemas/config.v2.json b/website/static/schemas/config.v2.json index 22a74d562..7ab40d95f 100644 --- a/website/static/schemas/config.v2.json +++ b/website/static/schemas/config.v2.json @@ -72,10 +72,17 @@ "frontend:dev:serverUrl": { "type": "string", "description": "URL to a 3rd party dev server to be used to serve assets (eg. Vite). If this is set to 'auto', then the devServerUrl will be inferred from the Vite output", - "examples": [ "auto", "http://localhost:3000" ], + "examples": [ + "auto", + "http://localhost:3000" + ], "oneOf": [ - { "format": "uri" }, - { "const": "auto" } + { + "format": "uri" + }, + { + "const": "auto" + } ] }, "wailsjsdir": { @@ -87,7 +94,9 @@ "version": { "description": "Project config version", "default": "2", - "enum": [ "2" ] + "enum": [ + "2" + ] }, "outputfilename": { "type": "string", @@ -123,7 +132,9 @@ "type": "object", "description": "The application author", "properties": { - "name": { "type": "string" }, + "name": { + "type": "string" + }, "email": { "type": "string", "format": "email" @@ -156,6 +167,39 @@ "type": "string", "description": "A short comment for the app", "default": "Built using Wails (https://wails.io)" + }, + "fileAssociations": { + "type": "array", + "description": "File associations for the app", + "items": { + "type": "object", + "properties": { + "ext": { + "type": "string", + "description": "The extension (minus the leading period). e.g. png" + }, + "name": { + "type": "string", + "description": "The name. e.g. PNG File" + }, + "description": { + "type": "string", + "description": "Windows-only. The description. It is displayed on the `Type` column on Windows Explorer." + }, + "iconName": { + "type": "string", + "description": "The icon name without extension. Icons should be located in build folder. Proper icons will be generated from .png file for both macOS and Windows)" + }, + "role": { + "description": "macOS-only. The app’s role with respect to the type. Corresponds to CFBundleTypeRole.", + "allOf": [ + { + "$ref": "#/definitions/BundleTypeRole" + } + ] + } + } + } } } }, @@ -185,7 +229,9 @@ } }, "dependencies": { - "garbleargs": ["obfuscated"] + "garbleargs": [ + "obfuscated" + ] }, "definitions": { "OsHook": { @@ -203,11 +249,21 @@ "description": "Build hooks for different targets.", "additionalProperties": false, "properties": { - "{GOOS}/{GOARCH}": { "$ref": "#/definitions/OsArchHook" }, - "{GOOS}/*": { "$ref": "#/definitions/OsHook" }, - "windows/*": { "$ref": "#/definitions/OsHook" }, - "linux/*": { "$ref": "#/definitions/OsHook" }, - "darwin/*": { "$ref": "#/definitions/OsHook" }, + "{GOOS}/{GOARCH}": { + "$ref": "#/definitions/OsArchHook" + }, + "{GOOS}/*": { + "$ref": "#/definitions/OsHook" + }, + "windows/*": { + "$ref": "#/definitions/OsHook" + }, + "linux/*": { + "$ref": "#/definitions/OsHook" + }, + "darwin/*": { + "$ref": "#/definitions/OsHook" + }, "*/*": { "type": "string", "description": "Executed at build level before/after a build" @@ -225,26 +281,66 @@ "description": "Executed at build level before/after a build of the specific platform" } } + }, + "BundleTypeRole": { + "description": "macOS-only. Corresponds to CFBundleTypeRole", + "oneOf": [ + { + "description": "CFBundleTypeRole.Editor. Files can be read and edited.", + "type": "string", + "enum": [ + "Editor" + ] + }, + { + "description": "CFBundleTypeRole.Viewer. Files can be read.", + "type": "string", + "enum": [ + "Viewer" + ] + }, + { + "description": "CFBundleTypeRole.Shell", + "type": "string", + "enum": [ + "Shell" + ] + }, + { + "description": "CFBundleTypeRole.QLGenerator", + "type": "string", + "enum": [ + "QLGenerator" + ] + }, + { + "description": "CFBundleTypeRole.None", + "type": "string", + "enum": [ + "None" + ] + } + ] } }, - "bindings": { - "type": "object", - "description": "Bindings configurations", - "properties": { - "ts_generation": { - "type": "object", - "description": "model.ts file generation config", - "properties": { - "prefix": { - "type": "string", - "description": "All generated JavaScript entities will be prefixed with this value" - }, - "suffix": { - "type": "string", - "description": "All generated JavaScript entities will be suffixed with this value" - } - } - } - } - } + "bindings": { + "type": "object", + "description": "Bindings configurations", + "properties": { + "ts_generation": { + "type": "object", + "description": "model.ts file generation config", + "properties": { + "prefix": { + "type": "string", + "description": "All generated JavaScript entities will be prefixed with this value" + }, + "suffix": { + "type": "string", + "description": "All generated JavaScript entities will be suffixed with this value" + } + } + } + } + } }