import { relative, resolve, win32 } from 'path'; import { readdirAsync, lstatAsync } from 'fs-extra-promise'; import { fixWindowsVersion } from '../util'; export interface INsisComposerOptions { // Basic. appName: string; companyName: string; description: string; version: string; copyright: string; icon: string; unIcon: string; // Compression. compression: 'zlib' | 'bzip2' | 'lzma'; solid: boolean; languages: string[]; // Output. output: string; } export class NsisComposer { public static DIVIDER = '################################################################################'; protected fixedVersion: string; constructor(protected options: INsisComposerOptions) { if(!this.options.appName) { this.options.appName = 'NO_APPNAME'; } if(!this.options.companyName) { this.options.companyName = 'NO_COMPANYNAME'; } if(!this.options.description) { this.options.description = 'NO_DESCRIPTION'; } if(!this.options.version) { this.options.version = 'NO_VERSION'; } if(!this.options.copyright) { this.options.copyright = 'NO_COPYRIGHT'; } this.options.compression = this.options.compression || 'lzma'; this.options.solid = this.options.solid ? true : false; this.options.languages = this.options.languages && this.options.languages.length > 0 ? this.options.languages : [ 'English' ]; this.fixedVersion = fixWindowsVersion(this.options.version); } public async make(): Promise { return ` ${ NsisComposer.DIVIDER } # # Generated by nsis-gen. # ${ NsisComposer.DIVIDER } ${ await this.makeGeneralSection() } ${ await this.makeModernUISection() } ${ await this.makeVersionSection() } ${ await this.makeHookSection() } ${ await this.makeInstallSection() } ${ await this.makeUninstallSection() } `; } protected async makeGeneralSection(): Promise { return `${ NsisComposer.DIVIDER } # # General # ${ NsisComposer.DIVIDER } Unicode true Name "${ this.options.appName }" Caption "${ this.options.appName }" BrandingText "${ this.options.appName } ${ this.fixedVersion }" ${ this.options.icon ? `Icon "${ win32.normalize(resolve(this.options.icon)) }"` : '' } ${ this.options.unIcon ? `UninstallIcon "${ win32.normalize(resolve(this.options.unIcon)) }"` : '' } SetCompressor ${ this.options.solid ? '/SOLID' : '' } ${ this.options.compression } OutFile "${ win32.normalize(resolve(this.options.output)) }" InstallDir "$LOCALAPPDATA\\${ this.options.appName }" InstallDirRegKey HKCU "Software\\${ this.options.appName }" "InstallDir" RequestExecutionLevel user XPStyle on`; } protected async makeModernUISection(): Promise { return `${ NsisComposer.DIVIDER } # # Modern UI # ${ NsisComposer.DIVIDER } !include "MUI2.nsh" !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU" !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\\${ this.options.appName }" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "StartMenuFolder" !define MUI_FINISHPAGE_RUN "$INSTDIR\\${ this.options.appName }.exe" Var StartMenuFolder !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_UNPAGE_FINISH ${ this.options.languages.map((language) => { return `!insertmacro MUI_LANGUAGE "${ language }"`; }).join('\n') } ${ this.options.languages.length > 1 ? `!insertmacro MUI_RESERVEFILE_LANGDLL` : '' }`; } protected async makeVersionSection(): Promise { return `${ NsisComposer.DIVIDER } # # Versions # ${ NsisComposer.DIVIDER } VIProductVersion "${ this.fixedVersion }" VIAddVersionKey /LANG=0 "ProductName" "${ this.options.appName }" VIAddVersionKey /LANG=0 "CompanyName" "${ this.options.companyName }" VIAddVersionKey /LANG=0 "FileDescription" "${ this.options.description }" VIAddVersionKey /LANG=0 "FileVersion" "${ this.fixedVersion }" VIAddVersionKey /LANG=0 "LegalCopyright" "${ this.options.copyright }"`; } protected async makeHookSection(): Promise { return `${ NsisComposer.DIVIDER } # # Hooks # ${ NsisComposer.DIVIDER } Function .onInit ${ this.options.languages.length > 1 ? `!insertmacro MUI_LANGDLL_DISPLAY` : '' } FunctionEnd`; } protected async makeInstallSection(): Promise { return `${ NsisComposer.DIVIDER } # # Install # ${ NsisComposer.DIVIDER } Section -Install SetShellVarContext current SetOverwrite ifnewer WriteRegStr HKCU "Software\\${ this.options.appName }" "InstallDir" "$INSTDIR" ${ await this.makeInstallerFiles() } !insertmacro MUI_STARTMENU_WRITE_BEGIN Application CreateDirectory "$SMPROGRAMS\\$StartMenuFolder" CreateShortcut "$SMPROGRAMS\\$StartMenuFolder\\${ this.options.appName }.lnk" "$INSTDIR\\${ this.options.appName }.exe" CreateShortcut "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk" "$INSTDIR\\Uninstall.exe" !insertmacro MUI_STARTMENU_WRITE_END WriteUninstaller "$INSTDIR\\Uninstall.exe" SectionEnd`; } protected async makeUninstallSection(): Promise { return `${ NsisComposer.DIVIDER } # # Uninstall # ${ NsisComposer.DIVIDER } Section Uninstall # FIXME: Remove only files installed. RMDir /r "$INSTDIR" !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder Delete "$SMPROGRAMS\\$StartMenuFolder\\${ this.options.appName }.lnk" Delete "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk" RMDir "$SMPROGRAMS\\$StartMenuFolder" DeleteRegKey HKCU "Software\\${ this.options.appName }" SectionEnd`; } protected async makeInstallerFiles(): Promise { return `SetOutPath "$INSTDIR" FILE /r .\\*.*`; } }