├── .gitignore ├── lib ├── shortcut │ ├── Shortcut.exe │ └── ReadMe.txt ├── windows-shortcuts.d.ts └── windows-shortcuts.js ├── package.json ├── README.md └── test └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /lib/shortcut/Shortcut.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j201/windows-shortcuts/HEAD/lib/shortcut/Shortcut.exe -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "windows-shortcuts", 3 | "version": "0.1.6", 4 | "description": "Create, edit, and query Windows shortcuts (.lnk files)", 5 | "scripts": { 6 | "test": "node test/test.js" 7 | }, 8 | "keywords": [ 9 | "shortcut", 10 | "windows", 11 | "lnk" 12 | ], 13 | "license": "MIT", 14 | "author": "j201 (http://j201.github.io)", 15 | "main": "./lib/windows-shortcuts", 16 | "typings": "./lib/windows-shortcuts.d.ts", 17 | "repository": { 18 | "type": "git", 19 | "url": "git://github.com/j201/windows-shortcuts.git" 20 | }, 21 | "homepage": "http://github.com/j201/windows-shortcuts", 22 | "devDependencies": { 23 | "signal-exit": "^2.1.2", 24 | "tape": "^4.4.0", 25 | "tmp": "0.0.28", 26 | "touch": "^1.0.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/shortcut/ReadMe.txt: -------------------------------------------------------------------------------- 1 | 2 | Shortcut [Version 1.11] 3 | 4 | Creates, modifies or queries Windows shell links (shortcuts) 5 | 6 | 7 | The syntax of this command is: 8 | 9 | Shortcut.exe /F:filename /A:C|E|Q [/T:target] [/P:parameters] [/W:workingdir] 10 | [/R:runstyle] [/I:icon,index] [/H:hotkey] [/D:description] 11 | 12 | /F:filename : Specifies the .LNK shortcut file. 13 | /A:action : Defines the action to take (C=Create, E=Edit or Q=Query). 14 | /T:target : Defines the target path and file name the shortcut points to. 15 | /P:parameters : Defines the command-line parameters to pass to the target. 16 | /W:working dir : Defines the working directory the target starts with. 17 | /R:run style : Defines the window state (1=Normal, 3=Max, 7=Min). 18 | /I:icon,index : Defines the icon and optional index (file.exe or file.exe,0). 19 | /H:hotkey : Defines the hotkey, a numeric value of the keyboard shortcut. 20 | /D:description : Defines the description (or comment) for the shortcut. 21 | 22 | Notes: 23 | - Any argument that contains spaces must be enclosed in "double quotes". 24 | - If Query is specified (/A:Q), all arguments except /F: are ignored. 25 | - To find the numeric hotkey value, use Explorer to set a hotkey and then /A:Q 26 | - To prevent an environment variable from being expanded until the shortcut 27 | is launched, use the ^ carat escape character like this: ^%WINDIR^% 28 | 29 | Examples: 30 | /f:"%ALLUSERSPROFILE%\Start Menu\Programs\My App.lnk" /a:q 31 | /f:"%USERPROFILE%\Desktop\Notepad.lnk" /a:c /t:^%WINDIR^%\Notepad.exe /h:846 32 | /f:"%USERPROFILE%\Desktop\Notepad.lnk" /a:e /p:C:\Setup.log /r:3 33 | 34 | An argument of /? or -? displays this syntax and returns 1. 35 | A successful completion will return 0. 36 | 37 | 38 | Copyright 2000-2005 Marty List, www.OptimumX.com 39 | 40 | 41 | ================================================================== 42 | 43 | 44 | Revision History: 45 | 46 | 1.11 07/04/2005 47 | - Fixed display problem for hotkeys with extended characters. 48 | - Removed reference to .URL files in the syntax, since URL files are not supported yet. 49 | 50 | 1.10 12/20/2003 51 | - Fixed COM memory leak, enhanced exit/result codes, enhanced syntax. 52 | 53 | 1.00 10/02/2000 54 | - Initial release. 55 | 56 | -------------------------------------------------------------------------------- /lib/windows-shortcuts.d.ts: -------------------------------------------------------------------------------- 1 | export var NORMAL: 1; 2 | export var MAX: 3; 3 | export var MIN: 7; 4 | 5 | interface ShortcutOptions { 6 | /** The file path to the shortcut's target. See above about environment variables. **/ 7 | target?: string; 8 | /** The arguments to be passed to the shortcut, as a string. **/ 9 | args?: string; 10 | /** The working directory of the shortcut. **/ 11 | workingDir?: string; 12 | /** State to open the window in: ws.NORMAL (1), ws.MAX (3), or ws.MIN (7). **/ 13 | runStyle?: 1 | 3 | 7; 14 | /** The path to the shortcut icon file. **/ 15 | icon?: string; 16 | /** An optional index for the image in the icon file. **/ 17 | iconIndex?: number; 18 | /** 19 | * A number representing a hotkey. 20 | * To find out this value, create a shortcut manually and use ws.query on it. 21 | * Sorry about that inconvenience, but there isn't any more documentation either with shortcut.exe or from Microsoft. 22 | **/ 23 | hotkey?: number; 24 | /** A string description of the shortcut. **/ 25 | desc?: string; 26 | } 27 | 28 | interface CreateOrEditCallback { 29 | /** 30 | * @param error null if there was no error, or a string error message if there was. 31 | */ 32 | (error: string | null): void; 33 | } 34 | 35 | interface QueryCallback { 36 | /** 37 | * @param error A string error message if there was an error, otherwise null 38 | * 39 | * @param options 40 | * The options set on the shortcut with the same properties as above, 41 | * except an additional property expanded is added which contains the file name properties with any environment variables expanded. 42 | * For example, if options.target is "%WINDIR%/foo.exe", options.expanded.target would be "C:/Windows/foo.exe". 43 | */ 44 | (error: string | null, options?: ShortcutOptions): void; 45 | } 46 | 47 | /** 48 | * Creates a new shortcut. 49 | * 50 | * @param path 51 | * The file path to the new shortcut. 52 | * This can be a folder, in which case a .lnk file will be created in that folder 53 | * with the name of the target file, or the name of a .lnk file, which will be created. 54 | * Note that a folder that does not exist will not be created. 55 | * Environment variables like %WINDIR% can be used, but they will be expanded when the shortcut is created. 56 | * If you want them to be expanded when the shortcut is clicked, use carets before the percent signs: ^%WINDIR^%. 57 | * 58 | * @param target 59 | * If a string is passed as the second parameter, it is used as the options.target value (see above). 60 | * 61 | * @param callback 62 | * A function to be executed when ws.create is finished executing. 63 | */ 64 | export function create(path: string, target: string, callback?: CreateOrEditCallback): void; 65 | 66 | /** 67 | * Creates a new shortcut. 68 | * 69 | * @param path 70 | * The file path to the new shortcut. 71 | * This can be a folder, in which case a .lnk file will be created in that folder 72 | * with the name of the target file, or the name of a .lnk file, which will be created. 73 | * Note that a folder that does not exist will not be created. 74 | * Environment variables like %WINDIR% can be used, but they will be expanded when the shortcut is created. 75 | * If you want them to be expanded when the shortcut is clicked, use carets before the percent signs: ^%WINDIR^%. 76 | * 77 | * @param options 78 | * An object with optional parameters 79 | * 80 | * @param callback 81 | * A function to be executed when ws.create is finished executing. 82 | */ 83 | export function create(path: string, options: ShortcutOptions, callback?: CreateOrEditCallback): void; 84 | 85 | /** 86 | * Edits an existing shortcut, applying new options. 87 | * @param path The file path to an existing shortcut 88 | * @param options An object with optional parameters 89 | * @param callback A function to be executed when ws.edit is finished executing 90 | */ 91 | export function edit(path: string, options: ShortcutOptions, callback?: CreateOrEditCallback): void; 92 | 93 | /** 94 | * Collects information about an existing shortcut. 95 | * @param path The file path to an existing shortcut 96 | * @param callback A function to be executed when ws.query is finished executing 97 | */ 98 | export function query(path: string, callback: (error: string | null, options?: ShortcutOptions) => void): void; 99 | 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## windows-shortcuts 2 | ### Create, edit, and query Windows shortcuts (.lnk files) 3 | A Node.js API for [shortcut.exe](http://www.optimumx.com/downloads.html) by Optimum X. 4 | 5 | Note that this will not work for Electron apps - the [`shell.writeShortcutLink` or `shell.readShortcutLink` function](https://www.electronjs.org/docs/api/shell#shellreadshortcutlinkshortcutpath-windows) should be used instead. 6 | 7 | ## Simple Usage Example 8 | 9 | Creating a shortcut to notepad.exe in the current user's Start Menu: 10 | 11 | ```javascript 12 | var ws = require('windows-shortcuts'); 13 | 14 | ws.create("%APPDATA%/Microsoft/Windows/Start Menu/Programs/Notepad.lnk", "%WINDIR%/notepad.exe"); 15 | ``` 16 | 17 | ## API 18 | #### ws.create(path, [options], [callback]) 19 | #### ws.create(path, target, [callback]) 20 | Creates a new shortcut. 21 | 22 | - path - The file path to the new shortcut. This can be a folder, in which case a .lnk file will be created in that folder with the name of the target file, or the name of a .lnk file, which will be created. Note that a folder that does not exist will not be created. Environment variables like %WINDIR% can be used, but they will be expanded when the shortcut is created. If you want them to be expanded when the shortcut is clicked, use carets before the percent signs: ^%WINDIR^%. 23 | - options - An object with the following optional parameters: 24 | - target - The file path to the shortcut's target. See above about environment variables. 25 | - args - The arguments to be passed to the shortcut, as a string. 26 | - workingDir - The working directory of the shortcut. 27 | - runStyle - State to open the window in: ws.NORMAL (1), ws.MAX (3), or ws.MIN (7). 28 | - icon - The path to the shortcut icon file. 29 | - iconIndex - An optional index for the image in the icon file. 30 | - hotkey - A number representing a hotkey. To find out this value, create a shortcut manually and use ws.query on it. Sorry about that inconvenience, but there isn't any more documentation either with shortcut.exe or from Microsoft. 31 | - desc - A string description of the shortcut. 32 | - target - If a string is passed as the second parameter, it is used as the options.target value (see above). 33 | - callback - A function to be executed when ws.create is finished executing. One argument is passed to it: `null` if there was no error, or a string error message if there was. 34 | 35 | Example: 36 | 37 | ```javascript 38 | var ws = require('windows-shortcuts'); 39 | 40 | ws.create("foo.lnk", { 41 | target : "%APPDATA%/Bar/foo.js", 42 | args : '2 "baz quux"', 43 | runStyle : ws.MIN, 44 | desc : "Does cool stuff." 45 | }, function(err) { 46 | if (err) 47 | throw Error(err); 48 | else 49 | console.log("Shortcut created!"); 50 | }); 51 | ``` 52 | 53 | #### ws.edit(path, options, [callback]) 54 | Edits an existing shortcut, applying new options. Parameters are the same as above. 55 | 56 | Example: 57 | 58 | ```javascript 59 | ws.edit("foo.lnk", {runStyle : ws.MAX}); 60 | ``` 61 | 62 | #### ws.query(path, callback) 63 | Collects information about an existing shortcut. The callback is called with two parameters: 64 | 65 | - error - A string error message if there was an error, otherwise `null` 66 | - options - The options set on the shortcut with the same properties as above, except an additional property `expanded` is added which contains the file name properties with any environment variables expanded. For example, if `options.target` is `"%WINDIR%/foo.exe"`, `options.expanded.target` would be `"C:/Windows/foo.exe"`. 67 | 68 | Example: 69 | 70 | ```javascript 71 | ws.query("C:/ProgramData/Microsoft/Windows/Start Menu/Windows Update.lnk", console.log); 72 | 73 | /* From console: 74 | null { expanded: 75 | { args: 'startmenu', 76 | workingDir: 'C:\\Windows\\system32', 77 | icon: 'C:\\Windows\\system32\\wucltux.dll' }, 78 | target: '%windir%\\system32\\wuapp.exe', 79 | args: 'startmenu', 80 | workingDir: '%windir%\\system32', 81 | runStyle: 1, 82 | icon: '%windir%\\system32\\wucltux.dll', 83 | iconIndex: '0', 84 | hotkey: 0, 85 | desc: 'Delivers software updates and drivers, and provides automatic updating options.' } 86 | */ 87 | ``` 88 | 89 | ## Testing 90 | 91 | ``` 92 | npm test 93 | ``` 94 | 95 | ## Compatibility 96 | Only tested on Windows 7, but shortcut.exe says is compatible with Windows 95 or later, so it should work on modern versions of Windows. 97 | 98 | --- 99 | 100 | Licensed under [the MIT License](http://opensource.org/licenses/MIT). 101 | -------------------------------------------------------------------------------- /lib/windows-shortcuts.js: -------------------------------------------------------------------------------- 1 | var execFile = require('child_process').execFile; 2 | var pathUtils = require('path'); 3 | 4 | /* 5 | * options object (also passed by query()) 6 | * target : The path the shortcut points to 7 | * args : The arguments passed to the target as a string 8 | * workingDir : The working directory of the target 9 | * runStyle : State to open the window in: ws.NORMAL (1), ws.MAX (3), or ws.MIN (7) 10 | * icon : The path to the shortcut icon file 11 | * iconIndex : An optional index for the image in the icon file 12 | * hotkey : A numerical hotkey 13 | * desc : A description 14 | */ 15 | 16 | function parseQuery(stdout) { 17 | // Parses the stdout of a shortcut.exe query into a JS object 18 | var result = {}; 19 | result.expanded = {}; 20 | stdout.split(/[\r\n]+/) 21 | .filter(function(line) { return line.indexOf('=') !== -1; }) 22 | .forEach(function(line) { 23 | var pair = line.split('=', 2), 24 | key = pair[0], 25 | value = pair[1]; 26 | if (key === "TargetPath") 27 | result.target = value; 28 | else if (key === "TargetPathExpanded") 29 | result.expanded.target = value; 30 | else if (key === "Arguments") 31 | result.args = value; 32 | else if (key === "ArgumentsExpanded") 33 | result.expanded.args = value; 34 | else if (key === "WorkingDirectory") 35 | result.workingDir = value; 36 | else if (key === "WorkingDirectoryExpanded") 37 | result.expanded.workingDir = value; 38 | else if (key === "RunStyle") 39 | result.runStyle = +value; 40 | else if (key === "IconLocation") { 41 | result.icon = value.split(',')[0]; 42 | result.iconIndex = value.split(',')[1]; 43 | } else if (key === "IconLocationExpanded") { 44 | result.expanded.icon = value.split(',')[0]; 45 | } else if (key === "HotKey") 46 | result.hotkey = +value.match(/\d+/)[0]; 47 | else if (key === "Description") 48 | result.desc = value; 49 | }); 50 | Object.keys(result.expanded).forEach(function(key) { 51 | result.expanded[key] = result.expanded[key] || result[key]; 52 | }); 53 | return result; 54 | } 55 | 56 | // This function is supposed to act like a windows shell for compatibility with v0.1.2 57 | // Meaning, treat carets as escape characters (replace ^ with ) and expand env vars 58 | function expandEnv(path) { 59 | var envRE = /(^|[^^])%((?:\^.|[^^%])*)%/g; // Matches env vars, accounting for escaped chars. I feel dirty. 60 | return path.replace(envRE, function(_, g1, g2) { 61 | return g1 + process.env[g2]; 62 | }).replace(/\^(.)/g,"$1"); 63 | } 64 | 65 | function commandArgs(type, path, options) { 66 | // Generates a command for shortcut.exe 67 | var args = ['/A:' + type, '/F:' + expandEnv(path)]; 68 | 69 | if (options) { 70 | if (options.target) 71 | args.push('/T:' + expandEnv(options.target)); 72 | if (options.args) 73 | args.push('/P:' + expandEnv(options.args)); 74 | if (options.workingDir) 75 | args.push('/W:' + expandEnv(options.workingDir) + ''); 76 | if (options.runStyle) 77 | args.push('/R:' + options.runStyle); 78 | if (options.icon) { 79 | args.push('/I:' + expandEnv(options.icon) + ('iconIndex' in options ? ',' + options.iconIndex : '')); 80 | } 81 | if (options.hotkey) 82 | args.push('/H:' + options.hotkey); 83 | if (options.desc) 84 | args.push('/D:' + expandEnv(options.desc) + ''); 85 | } 86 | return args; 87 | } 88 | 89 | function isString(x) { 90 | return Object.prototype.toString.call(x) === "[object String]"; 91 | } 92 | 93 | exports.query = function(path, callback) { 94 | execFile(__dirname + '/shortcut/Shortcut.exe', 95 | ['/A:Q', '/F:' + expandEnv(path)], 96 | function(error, stdout, stderr) { 97 | var result = parseQuery(stdout); 98 | callback(error ? stderr || stdout : null, result); 99 | }); 100 | }; 101 | 102 | exports.create = function(path, optionsOrCallbackOrTarget, callback) { 103 | var options = isString(optionsOrCallbackOrTarget) ? {target : optionsOrCallbackOrTarget} : optionsOrCallbackOrTarget; 104 | callback = typeof optionsOrCallbackOrTarget === 'function' ? optionsOrCallbackOrTarget : callback; 105 | 106 | if (pathUtils.extname(path) !== ".lnk") { // Automatically generate shortcut if a .lnk file name is not given 107 | if (options && options.target) { 108 | var targetObj = pathUtils.parse(options.target); // TODO: deal with parse failure? 109 | var basename = targetObj.ext === ".lnk" ? 110 | options.target : 111 | targetObj.name + ".lnk"; 112 | path = pathUtils.join(path, basename); 113 | } else { 114 | path = pathUtils.join(path, "New Shortcut.lnk"); 115 | } 116 | } 117 | 118 | execFile(__dirname + '\\shortcut\\Shortcut.exe', 119 | commandArgs('C', path, options), 120 | function(error, stdout, stderr) { 121 | if (callback) 122 | callback(error ? stderr || stdout : null); 123 | }); 124 | }; 125 | 126 | exports.edit = function(path, options, callback) { 127 | execFile(__dirname + '/shortcut/Shortcut.exe', 128 | commandArgs('E', path, options), 129 | function(error, stdout, stderr) { 130 | if (callback) 131 | callback(error ? stderr || stdout : null); 132 | }); 133 | }; 134 | 135 | // Shortcut open states 136 | exports.NORMAL = 1; 137 | exports.MAX = 3; 138 | exports.MIN = 7; 139 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var ws = require('../lib/windows-shortcuts'); 2 | var tape = require('tape'); 3 | var tmp = require('tmp'); 4 | var touch = require("touch"); 5 | var path = require("path"); 6 | var onExit = require('signal-exit'); 7 | var fs = require('fs'); 8 | 9 | tmp.setGracefulCleanup(); 10 | 11 | var filesToDelete = []; 12 | 13 | onExit(function() { 14 | filesToDelete.forEach(function(f) { 15 | try { 16 | fs.unlinkSync(f.replace("%TEMP%", process.env.TEMP)); 17 | } catch (e) { 18 | console.log('Deleting ' + f + ' failed.'); 19 | } 20 | }); 21 | }); 22 | 23 | tape("create->query", function(t) { 24 | var target = tmp.tmpNameSync({postfix: ".txt"}); 25 | touch.sync(target); 26 | filesToDelete.push(target); 27 | var lnkName = tmp.tmpNameSync({postfix: ".lnk"}); 28 | var lnkOpts = { 29 | target : target, 30 | args : '2 "baz quux"', 31 | workingDir: "C:\\Windows", 32 | runStyle : ws.MIN, 33 | hotkey: 100, 34 | desc : "Does cool stuff." 35 | }; 36 | ws.create(lnkName, lnkOpts, function(err) { 37 | t.notOk(err, "No errors on create"); 38 | if (!err) filesToDelete.push(lnkName); 39 | ws.query(lnkName, function(err, opts) { 40 | t.notOk(err, "No errors on query"); 41 | Object.keys(lnkOpts).forEach(function(k) { 42 | t.equal(opts[k], lnkOpts[k]); 43 | }); 44 | t.end(); 45 | }); 46 | }); 47 | }); 48 | 49 | tape("create->edit->query", function(t) { 50 | var target = tmp.tmpNameSync({postfix: ".txt"}); 51 | touch.sync(target); 52 | filesToDelete.push(target); 53 | var lnkName = tmp.tmpNameSync({postfix: ".lnk"}); 54 | var lnkOpts = { 55 | target : target, 56 | args : '2 "baz quux"', 57 | workingDir: "C:\\Windows", 58 | runStyle : ws.MIN, 59 | hotkey: 100, 60 | desc : "Does cool stuff." 61 | }; 62 | var lnkNewOpts = { 63 | runStyle : ws.MAX, 64 | args: '3 4' 65 | }; 66 | ws.create(lnkName, lnkOpts, function(err) { 67 | t.notOk(err, "No errors on create"); 68 | if (!err) filesToDelete.push(lnkName); 69 | ws.edit(lnkName, lnkNewOpts, function(err) { 70 | t.notOk(err, "No errors on edit"); 71 | ws.query(lnkName, function(err, opts) { 72 | t.notOk(err, "No errors on query"); 73 | Object.keys(lnkOpts).forEach(function(k) { 74 | if (k in lnkNewOpts) { 75 | t.equal(opts[k], lnkNewOpts[k]); 76 | } else { 77 | t.equal(opts[k], lnkOpts[k]); 78 | } 79 | }); 80 | t.end(); 81 | }); 82 | }); 83 | }); 84 | }); 85 | 86 | tape("create->query without target extension", function(t) { 87 | var target = tmp.tmpNameSync(); 88 | touch.sync(target); 89 | filesToDelete.push(target); 90 | var lnkName = tmp.tmpNameSync({postfix: ".lnk"}); 91 | var lnkOpts = { 92 | target : target, 93 | args : '2 "baz quux"', 94 | workingDir: "C:\\Windows", 95 | runStyle : ws.MIN, 96 | hotkey: 100, 97 | desc : "Does cool stuff." 98 | }; 99 | ws.create(lnkName, lnkOpts, function(err) { 100 | t.notOk(err, "No errors on create"); 101 | if (!err) filesToDelete.push(lnkName); 102 | ws.query(lnkName, function(err, opts) { 103 | t.notOk(err, "No errors on query"); 104 | Object.keys(lnkOpts).forEach(function(k) { 105 | t.equal(opts[k], lnkOpts[k]); 106 | }); 107 | t.end(); 108 | }); 109 | }); 110 | }); 111 | 112 | tape("create->query in directory", function(t) { 113 | var target = tmp.tmpNameSync({postfix: ".txt"}); 114 | var targetObj = path.parse(target); 115 | touch.sync(target); 116 | filesToDelete.push(target); 117 | var lnk = tmp.dirSync(); 118 | var lnkOpts = { 119 | target : target, 120 | args : '2 "baz quux"', 121 | workingDir: "C:\\Windows", 122 | runStyle : ws.MIN, 123 | hotkey: 100, 124 | desc : "Does cool stuff." 125 | }; 126 | ws.create(lnk.name, lnkOpts, function(err) { 127 | t.notOk(err, "No errors on create"); 128 | var lnkName = lnk.name + "\\" + targetObj.name + ".lnk"; 129 | if (!err) filesToDelete.push(lnkName); 130 | ws.query(lnkName, function(err, opts) { 131 | t.notOk(err, "No errors on query"); 132 | Object.keys(lnkOpts).forEach(function(k) { 133 | t.equal(opts[k], lnkOpts[k]); 134 | }); 135 | t.end(); 136 | }); 137 | }); 138 | }); 139 | 140 | tape("create->query in directory with spaces", function(t) { 141 | var tmpDir = tmp.dirSync(); 142 | var spacedDir = tmpDir.name + "\\spaced dir"; 143 | fs.mkdirSync(spacedDir); 144 | var target = tmp.tmpNameSync({ dir: spacedDir, postfix: ".txt" }); 145 | var targetObj = path.parse(target); 146 | touch.sync(target); 147 | filesToDelete.push(target); 148 | var lnk = tmp.dirSync({dir: spacedDir}); 149 | var lnkOpts = { 150 | target : target, 151 | args : '2 "baz quux"', 152 | workingDir: "C:\\Windows", 153 | runStyle : ws.MIN, 154 | hotkey: 100, 155 | desc : "Does cool stuff." 156 | }; 157 | ws.create(lnk.name, lnkOpts, function(err) { 158 | t.notOk(err, "No errors on create"); 159 | var lnkName = lnk.name + "\\" + targetObj.name + ".lnk"; 160 | if (!err) filesToDelete.push(lnkName); 161 | ws.query(lnkName, function(err, opts) { 162 | t.notOk(err, "No errors on query"); 163 | Object.keys(lnkOpts).forEach(function(k) { 164 | t.equal(opts[k], lnkOpts[k]); 165 | }); 166 | t.end(); 167 | }); 168 | }); 169 | }); 170 | 171 | tape("create->query with environment variables", function(t) { 172 | var target = tmp.tmpNameSync({ dir: "%TEMP%", postfix: ".txt" }); 173 | t.ok(target.indexOf("%TEMP%") !== -1, "tmp doesn't expand env variables"); 174 | var expandedTarget = target.replace("%TEMP%", process.env.TEMP); 175 | touch.sync(expandedTarget); 176 | filesToDelete.push(target); 177 | var lnkName = tmp.tmpNameSync({ dir: "%TEMP%", postfix: ".lnk" }); 178 | var lnkOpts = { 179 | target : target, 180 | args : '2 "baz quux"', 181 | workingDir: "^%SOMEDIR^%", 182 | runStyle : ws.MIN, 183 | hotkey: 100, 184 | desc : "Does cool stuff." 185 | }; 186 | ws.create(lnkName, lnkOpts, function(err) { 187 | t.notOk(err, "No errors on create"); 188 | if (!err) filesToDelete.push(lnkName); 189 | ws.query(lnkName, function(err, opts) { 190 | t.notOk(err, "No errors on query"); 191 | Object.keys(lnkOpts).forEach(function(k) { 192 | if (k === 'workingDir') 193 | t.equal(opts[k], "%SOMEDIR%"); 194 | else if (k === 'target') 195 | t.equal(opts[k], expandedTarget); 196 | else 197 | t.equal(opts[k], lnkOpts[k]); 198 | }); 199 | t.end(); 200 | }); 201 | }); 202 | }); 203 | --------------------------------------------------------------------------------