alfy 2.1.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +27 -5
- package/index.js +20 -7
- package/lib/update-notification.js +1 -1
- package/package.json +11 -11
- package/readme.md +27 -2
- package/run-node.sh +19 -1
package/index.d.ts
CHANGED
|
@@ -20,9 +20,32 @@ export type OutputOptions = {
|
|
|
20
20
|
The script will only be re-run if the script filter is still active and the user hasn't changed the state of the filter by typing and triggering a re-run. For example, it could be used to update the progress of a particular task:
|
|
21
21
|
*/
|
|
22
22
|
readonly rerunInterval?: number;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
Variables passed out of the script filter and accessible throughout the current session as environment variables.
|
|
26
|
+
|
|
27
|
+
These are session-level variables that persist for the duration of the user action. Individual items can also have their own `variables` which override these when selected.
|
|
28
|
+
|
|
29
|
+
@example
|
|
30
|
+
```
|
|
31
|
+
import alfy from 'alfy';
|
|
32
|
+
|
|
33
|
+
alfy.output(
|
|
34
|
+
[
|
|
35
|
+
{
|
|
36
|
+
title: 'Unicorn',
|
|
37
|
+
arg: 'unicorn',
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
{
|
|
41
|
+
variables: {animal: 'unicorn'}
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
```
|
|
45
|
+
*/
|
|
46
|
+
readonly variables?: Record<string, string>;
|
|
23
47
|
};
|
|
24
48
|
|
|
25
|
-
// eslint-disable-next-line unicorn/prevent-abbreviations
|
|
26
49
|
export type CacheConfGetOptions = {
|
|
27
50
|
/**
|
|
28
51
|
Get the item for the key provided without taking the `maxAge` of the item into account.
|
|
@@ -30,7 +53,6 @@ export type CacheConfGetOptions = {
|
|
|
30
53
|
readonly ignoreMaxAge?: boolean;
|
|
31
54
|
};
|
|
32
55
|
|
|
33
|
-
// eslint-disable-next-line unicorn/prevent-abbreviations
|
|
34
56
|
export type CacheConfSetOptions = {
|
|
35
57
|
/**
|
|
36
58
|
Number of milliseconds the cached value is valid.
|
|
@@ -39,7 +61,7 @@ export type CacheConfSetOptions = {
|
|
|
39
61
|
};
|
|
40
62
|
|
|
41
63
|
// TODO: Rename this in the next major version.
|
|
42
|
-
|
|
64
|
+
|
|
43
65
|
export type CacheConf<T extends Record<string, any> = Record<string, unknown>> = {
|
|
44
66
|
isExpired: (key: keyof T) => boolean;
|
|
45
67
|
|
|
@@ -367,9 +389,9 @@ export type Alfy = {
|
|
|
367
389
|
/**
|
|
368
390
|
Log value to the Alfred workflow debugger.
|
|
369
391
|
|
|
370
|
-
@param
|
|
392
|
+
@param value
|
|
371
393
|
*/
|
|
372
|
-
log: (
|
|
394
|
+
log: (value: unknown) => void;
|
|
373
395
|
|
|
374
396
|
/**
|
|
375
397
|
Display an error or error message in Alfred.
|
package/index.js
CHANGED
|
@@ -3,18 +3,20 @@ import process from 'node:process';
|
|
|
3
3
|
import {createRequire} from 'node:module';
|
|
4
4
|
import Conf from 'conf';
|
|
5
5
|
import got from 'got';
|
|
6
|
-
import {hookStderr} from 'hook-std';
|
|
7
6
|
import loudRejection from 'loud-rejection';
|
|
8
7
|
import cleanStack from 'clean-stack';
|
|
9
8
|
import {getProperty} from 'dot-prop';
|
|
10
9
|
import AlfredConfig from 'alfred-config';
|
|
11
|
-
import updateNotification from './lib/update-notification.js'; // eslint-disable-line import/order
|
|
10
|
+
import updateNotification from './lib/update-notification.js'; // eslint-disable-line import-x/order
|
|
12
11
|
|
|
13
12
|
const require = createRequire(import.meta.url);
|
|
14
13
|
const CacheConf = require('cache-conf');
|
|
15
14
|
|
|
16
15
|
const alfy = {};
|
|
17
16
|
|
|
17
|
+
// Track if output has been generated to avoid empty JSON
|
|
18
|
+
let hasOutput = false;
|
|
19
|
+
|
|
18
20
|
updateNotification();
|
|
19
21
|
|
|
20
22
|
const getIcon = name => `/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/${name}.icns`;
|
|
@@ -41,8 +43,9 @@ alfy.alfred = {
|
|
|
41
43
|
|
|
42
44
|
alfy.input = process.argv[2];
|
|
43
45
|
|
|
44
|
-
alfy.output = (items, {rerunInterval} = {}) => {
|
|
45
|
-
|
|
46
|
+
alfy.output = (items, {rerunInterval, variables} = {}) => {
|
|
47
|
+
hasOutput = true;
|
|
48
|
+
console.log(JSON.stringify({items, rerun: rerunInterval, variables}, null, '\t'));
|
|
46
49
|
};
|
|
47
50
|
|
|
48
51
|
alfy.matches = (input, list, item) => {
|
|
@@ -73,6 +76,7 @@ alfy.log = text => {
|
|
|
73
76
|
|
|
74
77
|
alfy.error = error => {
|
|
75
78
|
const stack = cleanStack(error.stack || error);
|
|
79
|
+
const title = error.stack ? `${error.name}: ${error.message}` : String(error);
|
|
76
80
|
|
|
77
81
|
const copy = `
|
|
78
82
|
\`\`\`
|
|
@@ -86,7 +90,7 @@ ${process.platform} ${os.release()}
|
|
|
86
90
|
`.trim();
|
|
87
91
|
|
|
88
92
|
alfy.output([{
|
|
89
|
-
title
|
|
93
|
+
title,
|
|
90
94
|
subtitle: 'Press ⌘L to see the full error and ⌘C to copy it.',
|
|
91
95
|
valid: false,
|
|
92
96
|
text: {
|
|
@@ -97,6 +101,9 @@ ${process.platform} ${os.release()}
|
|
|
97
101
|
path: alfy.icon.error,
|
|
98
102
|
},
|
|
99
103
|
}]);
|
|
104
|
+
|
|
105
|
+
// Also output to stderr for the debugger (as requested in issue #86)
|
|
106
|
+
console.error(stack);
|
|
100
107
|
};
|
|
101
108
|
|
|
102
109
|
alfy.config = new Conf({
|
|
@@ -133,7 +140,7 @@ alfy.fetch = async (url, options) => {
|
|
|
133
140
|
delete options.transform;
|
|
134
141
|
delete options.maxAge;
|
|
135
142
|
|
|
136
|
-
const key = rawKey.replaceAll('.',
|
|
143
|
+
const key = rawKey.replaceAll('.', String.raw`\.`);
|
|
137
144
|
const cachedResponse = alfy.cache.get(key, {ignoreMaxAge: true});
|
|
138
145
|
|
|
139
146
|
if (cachedResponse && !alfy.cache.isExpired(key)) {
|
|
@@ -181,6 +188,12 @@ alfy.icon = {
|
|
|
181
188
|
|
|
182
189
|
loudRejection(alfy.error);
|
|
183
190
|
process.on('uncaughtException', alfy.error);
|
|
184
|
-
|
|
191
|
+
|
|
192
|
+
// Ensure valid JSON output even if user forgets to call alfy.output() (fixes #82)
|
|
193
|
+
process.on('beforeExit', () => {
|
|
194
|
+
if (!hasOutput) {
|
|
195
|
+
alfy.output([]);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
185
198
|
|
|
186
199
|
export default alfy;
|
|
@@ -2,7 +2,7 @@ import {readPackageUp} from 'read-package-up';
|
|
|
2
2
|
import alfredNotifier from 'alfred-notifier';
|
|
3
3
|
|
|
4
4
|
export default async function updateNotification() {
|
|
5
|
-
const {package: package_} = await readPackageUp();
|
|
5
|
+
const {package: package_} = (await readPackageUp()) ?? {};
|
|
6
6
|
const alfy = package_?.alfy ?? {};
|
|
7
7
|
|
|
8
8
|
if (alfy.updateNotification !== false) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alfy",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "Create Alfred workflows with ease",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "sindresorhus/alfy",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
"sideEffects": false,
|
|
19
19
|
"engines": {
|
|
20
|
-
"node": ">=
|
|
20
|
+
"node": ">=20"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
23
|
"test": "xo && ava && tsd"
|
|
@@ -47,21 +47,21 @@
|
|
|
47
47
|
"alfred-notifier": "^0.2.3",
|
|
48
48
|
"cache-conf": "^0.6.0",
|
|
49
49
|
"clean-stack": "^5.2.0",
|
|
50
|
-
"conf": "^
|
|
51
|
-
"dot-prop": "^
|
|
52
|
-
"execa": "^9.
|
|
53
|
-
"got": "^14.4.
|
|
54
|
-
"hook-std": "^
|
|
50
|
+
"conf": "^14.0.0",
|
|
51
|
+
"dot-prop": "^10.0.0",
|
|
52
|
+
"execa": "^9.6.0",
|
|
53
|
+
"got": "^14.4.8",
|
|
54
|
+
"hook-std": "^4.0.0",
|
|
55
55
|
"loud-rejection": "^2.2.0",
|
|
56
56
|
"read-package-up": "^11.0.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"ava": "^6.1
|
|
59
|
+
"ava": "^6.4.1",
|
|
60
60
|
"delay": "^6.0.0",
|
|
61
|
-
"nock": "^
|
|
61
|
+
"nock": "^14.0.10",
|
|
62
62
|
"tempfile": "^5.0.0",
|
|
63
|
-
"tsd": "^0.
|
|
64
|
-
"xo": "^
|
|
63
|
+
"tsd": "^0.33.0",
|
|
64
|
+
"xo": "^1.2.2"
|
|
65
65
|
},
|
|
66
66
|
"tsd": {
|
|
67
67
|
"compilerOptions": {
|
package/readme.md
CHANGED
|
@@ -151,13 +151,16 @@ test('main', async t => {
|
|
|
151
151
|
|
|
152
152
|
## Debugging
|
|
153
153
|
|
|
154
|
-
When developing your workflow it can be useful to be able to debug it when something is not working. This is when the [workflow debugger](https://www.alfredapp.com/help/workflows/advanced/debugger/) comes in handy. You can find it in your workflow view in Alfred. Press the insect icon to open it. It will show you the plain text output of `alfy.output()` and anything you log with `alfy.log()`:
|
|
154
|
+
When developing your workflow it can be useful to be able to debug it when something is not working. This is when the [workflow debugger](https://www.alfredapp.com/help/workflows/advanced/debugger/) comes in handy. You can find it in your workflow view in Alfred. Press the insect icon to open it. It will show you the plain text output of `alfy.output()` and anything you log with `alfy.log()` or `console.error()`:
|
|
155
155
|
|
|
156
156
|
```js
|
|
157
157
|
import alfy from 'alfy';
|
|
158
158
|
|
|
159
159
|
const unicorn = getUnicorn();
|
|
160
160
|
alfy.log(unicorn);
|
|
161
|
+
|
|
162
|
+
// You can also use console.error() for debugging
|
|
163
|
+
console.error('Debug info:', {data: someData});
|
|
161
164
|
```
|
|
162
165
|
|
|
163
166
|
## Environment variables
|
|
@@ -231,13 +234,35 @@ alfy.output(
|
|
|
231
234
|
|
|
232
235
|
<img src="media/screenshot-output.png" width="694">
|
|
233
236
|
|
|
237
|
+
###### variables
|
|
238
|
+
|
|
239
|
+
Type: `object`
|
|
240
|
+
|
|
241
|
+
Variables passed out of the script filter and accessible throughout the current session as environment variables. These are session-level variables that persist for the duration of the user action. Individual items can also have their own `variables` which override these when selected.
|
|
242
|
+
|
|
243
|
+
```js
|
|
244
|
+
import alfy from 'alfy';
|
|
245
|
+
|
|
246
|
+
alfy.output(
|
|
247
|
+
[
|
|
248
|
+
{
|
|
249
|
+
title: 'Unicorn',
|
|
250
|
+
arg: 'unicorn',
|
|
251
|
+
}
|
|
252
|
+
],
|
|
253
|
+
{
|
|
254
|
+
variables: {animal: 'unicorn'}
|
|
255
|
+
}
|
|
256
|
+
);
|
|
257
|
+
```
|
|
258
|
+
|
|
234
259
|
#### log(value)
|
|
235
260
|
|
|
236
261
|
Log `value` to the [Alfred workflow debugger](https://www.alfredapp.com/help/workflows/advanced/debugger/).
|
|
237
262
|
|
|
238
263
|
#### matches(input, list, item?)
|
|
239
264
|
|
|
240
|
-
Returns
|
|
265
|
+
Returns a `string[]` of items in `list` that case-insensitively contains `input`.
|
|
241
266
|
|
|
242
267
|
```js
|
|
243
268
|
import alfy from 'alfy';
|
package/run-node.sh
CHANGED
|
@@ -13,7 +13,25 @@ PATH_CACHE="$alfred_workflow_cache"/node_path
|
|
|
13
13
|
|
|
14
14
|
get_user_path() {
|
|
15
15
|
eval $(/usr/libexec/path_helper -s)
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
# Use delimiters to reliably extract PATH from shell startup noise (inspired by `shell-env`).
|
|
18
|
+
# Disable Oh My Zsh plugins that can block the process.
|
|
19
|
+
local delimiter="_ALFY_ENV_DELIMITER_"
|
|
20
|
+
local raw_env
|
|
21
|
+
raw_env="$(DISABLE_AUTO_UPDATE=true ZSH_TMUX_AUTOSTARTED=true ZSH_TMUX_AUTOSTART=false $SHELL -ilc "echo -n $delimiter; command env; echo -n $delimiter; exit" 2>/dev/null)"
|
|
22
|
+
|
|
23
|
+
# Extract the env output between the delimiters.
|
|
24
|
+
local env_output="${raw_env#*"$delimiter"}"
|
|
25
|
+
env_output="${env_output%%"$delimiter"*}"
|
|
26
|
+
|
|
27
|
+
# Extract PATH from the env output.
|
|
28
|
+
local user_path
|
|
29
|
+
user_path="$(echo "$env_output" | sed -n 's/^PATH=//p')"
|
|
30
|
+
|
|
31
|
+
# Only write cache if we got a non-empty result.
|
|
32
|
+
if [[ -n "$user_path" ]]; then
|
|
33
|
+
echo "PATH=\"${user_path}:\$PATH\"" > "$PATH_CACHE"
|
|
34
|
+
fi
|
|
17
35
|
}
|
|
18
36
|
|
|
19
37
|
set_path() {
|