轻松创建 Alfred 工作流
亮点
- 简单的输入↔输出。
- 内置配置和缓存处理。
- 获取远程文件,可选缓存。
- 将你的工作流发布到 npm。
- 自动更新通知。
- 轻松测试工作流。
- 查找
node
二进制文件。 - 支持顶层
await
。 - 向用户呈现未捕获的异常和未处理的 Promise 拒绝。
无需手动.catch()
顶层 Promise。
前提条件
你需要 Node.js 18+ 和 Alfred 4 或更高版本,并购买 Powerpack 升级。
安装
npm install alfy
使用方法
重要: 你的脚本将作为 ESM 运行。
-
创建一个新的空白 Alfred 工作流。
-
添加一个
Script Filter
(右键单击画布 →Inputs
→Script Filter
),将Language
设置为/bin/bash
,并添加以下脚本:
./node_modules/.bin/run-node index.js "$1"
我们不能直接调用 node
,因为 macOS 上的 GUI 应用不会继承 $PATH。
提示:你可以使用 generator-alfred 来搭建基于
alfy
的工作流框架。如果这样做,你可以跳过剩余步骤,直接转到index.js
开始你的工作。
-
设置你想要调用工作流的
Keyword
。 -
进入你的新工作流目录(在侧边栏中右键单击工作流 →
Open in Finder
)。 -
使用
npm init
初始化一个仓库。 -
在 package.json 中添加
"type": "module"
。 -
使用
npm install alfy
安装 Alfy。 -
在工作流目录中,创建一个
index.js
文件,导入alfy
,然后开始你的工作。
示例
这里我们从一个占位 API 获取一些 JSON 数据,并向用户呈现匹配的项目:
import alfy from 'alfy';
const data = await alfy.fetch('https://jsonplaceholder.typicode.com/posts');
const items = alfy
.inputMatches(data, 'title')
.map(element => ({
title: element.title,
subtitle: element.body,
arg: element.id
}));
alfy.output(items);
更多
一些实际使用的例子:alfred-npms
、alfred-emoj
、alfred-ng
。
更新通知
Alfy 在后台使用 alfred-notifier 来显示工作流有可用更新时的通知。
缓存
Alfy 提供了缓存数据的可能性,可以通过 fetch 或直接通过 cache 对象进行。
需要注意的一个重要点是,当你更新工作流时,缓存的数据会自动失效。这为开发者提供了灵活性,可以在工作流之间更改缓存数据的结构,而不必担心无效的旧数据。
发布到 npm
通过添加 alfy-init
作为 postinstall
脚本和 alfy-cleanup
作为 preuninstall
脚本,你可以将你的包发布到 npm 而不是 Packal。这样,你的包只需一个简单的 npm install
命令就可以安装。
{
"name": "alfred-unicorn",
"version": "1.0.0",
"description": "我的超棒独角兽工作流",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "https://sindresorhus.com"
},
"scripts": {
"postinstall": "alfy-init",
"preuninstall": "alfy-cleanup"
},
"dependencies": {
"alfy": "*"
}
}
提示:给你的工作流加上
alfred-
前缀,使它们在 npm 上更容易被搜索到。
你可以从 info.plist
文件中删除这些属性,因为它们会在安装时自动添加。
将你的工作流发布到 npm 后,你的用户可以轻松地安装或更新工作流。
npm install --global alfred-unicorn
提示:不要手动更新每个工作流,使用 alfred-updater 工作流来为你完成这项工作。
测试
可以使用 alfy-test 轻松测试工作流。以下是一个简单的示例。
import test from 'ava';
import alfyTest from 'alfy-test';
test('main', async t => {
const alfy = alfyTest();
const result = await alfy('workflow input');
t.deepEqual(result, [
{
title: 'foo',
subtitle: 'bar'
}
]);
});
调试
在开发工作流时,当遇到问题时能够进行调试是很有用的。这时 工作流调试器 就派上用场了。你可以在 Alfred 的工作流视图中找到它。点击昆虫图标打开它。它会显示 alfy.output()
的纯文本输出以及你用 alfy.log()
记录的任何内容:
import alfy from 'alfy';
const unicorn = getUnicorn();
alfy.log(unicorn);
环境变量
Alfred 允许用户为工作流设置 环境变量,然后该工作流可以使用这些变量。如果你需要用户为某个服务指定 API 令牌,这可能会很有用。你可以通过 process.env
访问工作流环境变量。例如 process.env.apiToken
。
API
alfy
input
类型:string
来自 Alfred 的输入。用户在输入框中输入的内容。
output(list, options?)
向 Alfred 返回输出。
list
类型:object[]
包含任何 支持属性 的 object
列表。
示例:
import alfy from 'alfy';
alfy.output([
{
title: 'Unicorn'
},
{
title: 'Rainbow'
}
]);
options
类型:object
rerunInterval
类型:number
(秒)
值:0.1...5.0
可以设置脚本在一段时间间隔后自动重新运行。只有在脚本过滤器仍然活跃且用户没有通过输入触发重新运行来改变过滤器状态时,脚本才会重新运行。更多信息。
例如,可以用来更新特定任务的进度:
import alfy from 'alfy';
alfy.output(
[
{
title: '正在下载独角兽…',
subtitle: `${progress}%`,
}
],
{
// 每3秒重新运行并更新进度。
rerunInterval: 3
}
);
log(value)
将 value
记录到 Alfred 工作流调试器。
matches(input, list, item?)
返回 list
中包含 input
的项目(不区分大小写)的 string[]
。
import alfy from 'alfy';
alfy.matches('Corn', ['foo', 'unicorn']);
//=> ['unicorn']
input
类型:string
用于匹配 list
项目的文本。
list
类型:string[]
要匹配的列表。
item
类型:string | Function
默认情况下,它会匹配 list
项目。
指定一个字符串来匹配对象属性:
import alfy from 'alfy';
const list = [
{
title: 'foo'
},
{
title: 'unicorn'
}
];
alfy.matches('Unicorn', list, 'title');
//=> [{title: 'unicorn'}]
或 嵌套属性:
import alfy from 'alfy';
const list = [
{
name: {
first: 'John',
last: 'Doe'
}
},
{
name: {
first: 'Sindre',
last: 'Sorhus'
}
}
];
alfy.matches('sindre', list, 'name.first');
//=> [{name: {first: 'Sindre', last: 'Sorhus'}}]
指定一个函数来自行处理匹配。该函数接收列表项和输入(都已转为小写)作为参数,并期望返回一个布尔值表示是否匹配:
import alfy from 'alfy';
const list = ['foo', 'unicorn'];
// 这里我们进行精确匹配。
// `Foo` 匹配该项,因为它已为你转为小写。
alfy.matches('Foo', list, (item, input) => item === input);
//=> ['foo']
inputMatches(list, item?)
与 matches()
相同,但使用 alfy.input
作为 input
。
如果你想匹配多个项目,你必须定义自己的匹配函数(如此处所示)。让我们扩展开头的例子,以搜索出现在title
或body
属性或两者中的关键词。
import alfy from 'alfy';
const data = await alfy.fetch('https://jsonplaceholder.typicode.com/posts');
const items = alfy
.inputMatches(
data,
(item, input) =>
item.title?.toLowerCase().includes(input) ||
item.body?.toLowerCase().includes(input)
)
.map((element) => ({
title: element.title,
subtitle: element.body,
arg: element.id,
}));
alfy.output(items);
error(error)
在Alfred中显示错误或错误消息。
**注意:**你不需要对顶层promise使用.catch()
。Alfy会为你处理这个问题。
error
类型:Error | string
要显示的错误或错误消息。
fetch(url, options?)
返回一个Promise
,该Promise返回响应的主体。
url
类型:string
要获取的URL。
options
类型:object
任何got
选项以及以下选项。
json
类型:boolean
默认值:true
使用JSON.parse
解析响应主体并将accept
头设置为application/json
。
maxAge
类型:number
此请求应被缓存的毫秒数。
resolveBodyOnly
类型:boolean
默认值:true
是否只解析主体还是解析完整响应。
import alfy from 'alfy';
await alfy.fetch('https://api.foo.com');
//=> {foo: 'bar'}
await alfy.fetch('https://api.foo.com', {
resolveBodyOnly: false
});
/*
{
body: {
foo: 'bar'
},
headers: {
'content-type': 'application/json'
}
}
*/
transform
类型:Function
在响应主体被缓存之前对其进行转换。
import alfy from 'alfy';
await alfy.fetch('https://api.foo.com', {
transform: body => {
body.foo = 'bar';
return body;
}
})
转换响应。
import alfy from 'alfy';
await alfy.fetch('https://api.foo.com', {
resolveBodyOnly: false,
transform: response => {
response.body.foo = 'bar';
return response;
}
})
你也可以返回一个Promise。
import alfy from 'alfy';
import xml2js from 'xml2js';
import pify from 'pify';
const parseString = pify(xml2js.parseString);
await alfy.fetch('https://api.foo.com', {
transform: body => parseString(body)
})
config
类型:object
持久化配置数据。
导出一个设置了正确配置路径的conf
实例。
示例:
import alfy from 'alfy';
alfy.config.set('unicorn', '🦄');
alfy.config.get('unicorn');
//=> '🦄'
userConfig
类型:Map
导出一个包含用户工作流配置的Map。工作流配置允许你的用户为工作流提供配置信息。例如,如果你正在开发一个GitHub工作流,你可以让你的用户提供他们自己的API令牌。
更多详情请参见alfred-config
。
示例:
import alfy from 'alfy';
alfy.userConfig.get('apiKey');
//=> '16811cad1b8547478b3e53eae2e0f083'
cache
类型:object
持久化缓存数据。
导出一个设置了正确缓存路径的修改版conf
实例。
示例:
import alfy from 'alfy';
alfy.cache.set('unicorn', '🦄');
alfy.cache.get('unicorn');
//=> '🦄'
maxAge
此实例的set
方法接受一个可选的第三个参数,你可以在其中提供maxAge
选项。maxAge
是值在缓存中有效的毫秒数。
示例:
import alfy from 'alfy';
import delay from 'delay';
alfy.cache.set('foo', 'bar', {maxAge: 5000});
alfy.cache.get('foo');
//=> 'bar'
// 等待5秒
await delay(5000);
alfy.cache.get('foo');
//=> undefined
debug
类型:boolean
用户当前是否打开了工作流调试器。
icon
类型:object
键:'info' | 'warning' | 'error' | 'alert' | 'like' | 'delete'
获取各种默认系统图标。
最有用的图标已作为键值包含在内。其余的可以通过 icon.get()
获取。在访达中前往 /System/Library/CoreServices/CoreTypes.bundle/Contents/Resources
可以查看所有图标。
示例:
import alfy from 'alfy';
console.log(alfy.icon.error);
//=> '/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/AlertStopIcon.icns'
console.log(alfy.icon.get('Clock'));
//=> '/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/Clock.icns'
meta
类型:object
示例:
{
name: 'Emoj',
version: '0.2.5',
uid: 'user.workflow.B0AC54EC-601C-479A-9428-01F9FD732959',
bundleId: 'com.sindresorhus.emoj'
}
alfred
类型:object
Alfred 元数据。
version
示例:'3.0.2'
了解用户当前运行的版本。如果你的工作流依赖于特定 Alfred 版本的功能,这可能会很有用。
theme
示例:'alfred.theme.yosemite'
当前使用的主题。
themeBackground
示例:'rgba(255,255,255,0.98)'
如果你正在动态创建图标,这可以让你了解主题背景的颜色。
themeSelectionBackground
示例:'rgba(255,255,255,0.98)'
选中结果的颜色。
themeSubtext
示例:3
了解用户在外观偏好设置中选择的副文本模式。
可用性注意:提供此选项是为了让开发者可以根据用户选择的模式调整结果文本,但工作流的结果文本不应基于此而过度膨胀,因为用户隐藏副文本的主要原因通常是为了让 Alfred 看起来更整洁。
data
示例:'/Users/sindresorhus/Library/Application Support/Alfred/Workflow Data/com.sindresorhus.npms'
非易失性数据的推荐位置。直接使用 alfy.data
,它使用这个路径。
cache
示例:'/Users/sindresorhus/Library/Caches/com.runningwithcrayons.Alfred/Workflow Data/com.sindresorhus.npms'
易失性数据的推荐位置。直接使用 alfy.cache
,它使用这个路径。
preferences
示例:'/Users/sindresorhus/Dropbox/Alfred/Alfred.alfredpreferences'
这是 Alfred.alfredpreferences
的位置。如果用户同步了他们的设置,这将允许你找到他们的设置所在位置,而不受同步状态的影响。
preferencesLocalHash
示例:'adbd4f66bc3ae8493832af61a41ee609b20d8705'
未同步的本地偏好设置存储在 Alfred.alfredpreferences
中的 …/preferences/local/${preferencesLocalHash}/
下。
用户
使用 Alfy 的 Alfred 工作流
- alfred-emoj - 从文本中查找相关表情符号
- alfred-npms - 使用npms.io搜索npm包
- alfred-dark-mode - 切换系统深色模式
- alfred-xcode - 打开Xcode项目和工作空间
- alfred-lock - 锁定Mac
- alfred-fkill - 出色地搜索和终止进程
- alfred-ng - 在angular.io上搜索Angular文档
- alfred-ionic - 搜索Ionic文档
- alfred-react-native - 访问React Native文档
- alfred-hl - 为剪贴板中的代码添加语法高亮
- alfred-workflow-docs-elastic - 搜索Elastic.co文档
- alfredinary - 捕获屏幕截图并上传到Cloudinary
- alfred-keycode - 获取JavaScript键码
- alfred-vue - 搜索Vue.js API文档
- alfred-meteor-docs - 搜索Meteor文档
- alfred-meteor-packages - Meteor包搜索
- alfred-climbing-grades-converter - 在攀岩评分系统之间转换
- alfred-hotel - 快速启动、停止和打开Hotel应用
- alfred-coolors - 查找相关颜色名称
- alfred-postico-favorites-workflow - 打开Postico收藏夹
- alfred-messages - 通过iMessage给联系人发消息
- alfred-bitbucket - 列出你和你团队的公共和私有Bitbucket仓库
- alfred-asana - 搜索你的Asana任务
- alfred-cacher - 从Cacher查找代码片段并复制到剪贴板
- alfred-loremipsum - 生成占位文本
- alfred-packagist - 使用Packagist搜索PHP包
- alfred-vpn - 连接/断开VPN
- alfred-yandex-translate - 使用Yandex翻译单词和文本
- alfred-now - 在Alfred中使用Now命令访问部署和别名
- alfred-chuck-norris-jokes - 获取Chuck Norris笑话
- alfred-show-network-info - 查看网络信息并发现本地设备
- alfred-currency-conversion - 查看外汇汇率和货币转换
- alfred-polyglot - 使用Google翻译文本
- alfred-stock-price - 显示美国市场实时股票价格
- alfred-jira - 在Markdown和Jira标记之间转换剪贴板文本
- alfred-network-location-switch - 切换macOS网络位置
- alfred-cool - 查找酷词
- alfred-google-books - 搜索Google图书
- alfred-ip - 查找你的公共IP地址
- alfred-figma - Figma团队、项目和文件的快速链接和搜索
- alfred-flutter-docs – 快速搜索和预览 Flutter 文档
- alfred-title – 将你的标题大写
- alfred-trello - 搜索你的看板,快速添加卡片,并查看 Trello 的卡片列表
- alfred-npm-versions - 查询 npm 包的最新 15 个版本
- alfred-github-trending - 搜索 GitHub 上的热门仓库
- alfred-elm - 浏览 Elm 包的文档
- alfred-imagemin - 使用 Imagemin 压缩图片
- alfred-evernote-workflow - 使用关键词和标签搜索印象笔记
- alfred-deno-doc - 访问 Deno 文档
- alfred-fly - 搜索 Google Chrome 书签
- alfred-simple-email-fetcher - 使用 IMAP 显示多个账户的未读邮件
- alfred-chrome-workflow - 搜索 Chrome 的书签、历史记录和下载日志
- alfred-code - 在 Visual Studio Code 中快速打开文件
- alfred-amphetamine - 在 Amphetamine 应用中快速开始和结束会话
- alfred-ids - 生成各种类型的 ID
- alfred-awesome-stars - 通过 awesome-stars 搜索已加星标的 GitHub 仓库
- alfred-pwgen - 生成随机和安全的密码
- alfred-bear - 在 Bear 应用中使用动态模板
- alfred-color-converter - 在 RGB 和十六进制之间转换颜色
相关项目
- alfred-simple - Alfred 的简洁主题(截图中使用)
- alfred-updater - 工作流更新器
- alfred-notifier - 工作流更新通知
- generator-alfred - Alfred 工作流脚手架