├── .gitignore
├── app
├── templates
│ ├── gitignore
│ ├── gitattributes
│ ├── travis.yml
│ ├── index.js
│ ├── editorconfig
│ ├── test.js
│ ├── readme.md
│ ├── _package.json
│ ├── license
│ └── info.plist
├── utils.js
└── index.js
├── .gitattributes
├── .travis.yml
├── .editorconfig
├── test
├── test-generate-uuid.js
└── test.js
├── readme.md
├── license
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/app/templates/gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.js text eol=lf
3 |
--------------------------------------------------------------------------------
/app/templates/gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.js text eol=lf
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '6'
4 | - '4'
5 |
--------------------------------------------------------------------------------
/app/templates/travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '6'
4 | - '4'
5 |
--------------------------------------------------------------------------------
/app/templates/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const alfy = require('alfy');
3 |
4 | alfy.output([
5 | {
6 | title: 'Unicorn',
7 | subtitle: alfy.input
8 | }
9 | ]);
10 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = tab
5 | end_of_line = lf
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 |
10 | [{package.json,*.yml}]
11 | indent_style = space
12 | indent_size = 2
13 |
--------------------------------------------------------------------------------
/app/templates/editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = tab
5 | end_of_line = lf
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 |
10 | [{package.json,*.yml}]
11 | indent_style = space
12 | indent_size = 2
13 |
--------------------------------------------------------------------------------
/app/templates/test.js:
--------------------------------------------------------------------------------
1 | import test from 'ava';
2 | import alfyTest from 'alfy-test';
3 |
4 | test(async t => {
5 | const alfy = alfyTest();
6 | const result = await alfy('Rainbow');
7 |
8 | t.deepEqual(result, [
9 | {
10 | title: 'Unicorn',
11 | subtitle: 'Rainbow'
12 | }
13 | ]);
14 | });
15 |
--------------------------------------------------------------------------------
/test/test-generate-uuid.js:
--------------------------------------------------------------------------------
1 | import test from 'ava';
2 | import {generateUuid} from '../app/utils';
3 |
4 | test('remembers UUIDs by key', t => {
5 | const foo1 = generateUuid('foo');
6 | const foo2 = generateUuid('foo');
7 | const bar = generateUuid('bar');
8 |
9 | t.is(foo1, foo2);
10 | t.not(foo1, bar);
11 | });
12 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # generator-alfred [](https://travis-ci.org/SamVerschueren/generator-alfred)
2 |
3 | > Scaffold out an [Alfred](https://www.alfredapp.com/) workflow
4 |
5 |
6 | ## Install
7 |
8 | ```
9 | $ npm install --global generator-alfred
10 | ```
11 |
12 |
13 | ## Usage
14 |
15 | With [yo](https://github.com/yeoman/yo):
16 |
17 | ```
18 | $ yo alfred
19 | ```
20 |
21 |
22 | ## License
23 |
24 | MIT © [Sam Verschueren](https://github.com/SamVerschueren)
25 |
--------------------------------------------------------------------------------
/app/templates/readme.md:
--------------------------------------------------------------------------------
1 | # <%= repoName %> [](https://travis-ci.org/<%= githubUsername %>/<%= repoName %>)
2 |
3 | > <%= moduleDescription %>
4 |
5 |
6 | ## Install
7 |
8 | ```
9 | $ npm install --global <%= moduleName %>
10 | ```
11 |
12 | *Requires [Node.js](https://nodejs.org) 4+ and the Alfred [Powerpack](https://www.alfredapp.com/powerpack/).*
13 |
14 |
15 | ## Usage
16 |
17 | In Alfred, type `<%= alfredKeyword %>`, Enter, and your query.
18 |
19 |
20 | ## License
21 |
22 | MIT © [<%= name %>](<%= website %>)
23 |
--------------------------------------------------------------------------------
/app/templates/_package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "<%= moduleName %>",
3 | "version": "0.0.0",
4 | "description": "<%= moduleDescription %>",
5 | "license": "MIT",
6 | "repository": "<%= githubUsername %>/<%= repoName %>",
7 | "author": {
8 | "name": "<%= name %>",
9 | "email": "<%= email %>",
10 | "url": "<%= humanizedWebsite %>"
11 | },
12 | "engines": {
13 | "node": ">=4"
14 | },
15 | "scripts": {
16 | "test": "xo && ava",
17 | "postinstall": "alfy-init",
18 | "preuninstall": "alfy-cleanup"
19 | },
20 | "files": [
21 | "index.js",
22 | "icon.png",
23 | "info.plist"
24 | ],
25 | "keywords": [
26 | "alfred",
27 | "workflow",
28 | "alfy"
29 | ],
30 | "dependencies": {
31 | "alfy": "^0.6.0"
32 | },
33 | "devDependencies": {
34 | "alfy-test": "^0.3.0",
35 | "ava": "^0.18.0",
36 | "xo": "^0.17.0"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const url = require('url');
3 | const uuid = require('uuid');
4 | const _s = require('underscore.string');
5 | const isScoped = require('is-scoped');
6 |
7 | const uuids = new Map();
8 |
9 | exports.generateUuid = key => {
10 | if (key && uuids.has(key)) {
11 | return uuids.get(key);
12 | }
13 |
14 | const id = uuid.v4().toUpperCase();
15 |
16 | if (key) {
17 | uuids.set(key, id);
18 | }
19 |
20 | return id;
21 | };
22 |
23 | exports.bundleId = props => {
24 | const parsed = url.parse(props.website);
25 |
26 | if (parsed.hostname === 'github.com') {
27 | return `com.${props.githubUsername.toLowerCase()}.${props.alfredName}`;
28 | }
29 |
30 | // Reverse hostname
31 | const parts = parsed.hostname.split('.');
32 | return `${parts[1]}.${parts[0]}.${props.alfredName}`;
33 | };
34 |
35 | exports.repoName = name => isScoped(name) ? name.split('/')[1] : name;
36 |
37 | exports.slugifyPackageName = name => isScoped(name) ? name : _s.slugify(name);
38 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import test from 'ava';
3 | import helpers from 'yeoman-test';
4 | import assert from 'yeoman-assert';
5 | import pify from 'pify';
6 | import tempfile from 'tempfile';
7 |
8 | test.beforeEach(async t => {
9 | await pify(helpers.testDirectory)(tempfile());
10 | t.context.generator = helpers.createGenerator('alfred', [path.join(__dirname, '../app')], null, {skipInstall: true});
11 | });
12 |
13 | test.serial('generates expected files', async t => {
14 | const generator = t.context.generator;
15 |
16 | helpers.mockPrompt(generator, {
17 | moduleName: 'test',
18 | githubUsername: 'test',
19 | website: 'http://test.com'
20 | });
21 |
22 | await pify(generator.run.bind(generator))();
23 |
24 | assert.file([
25 | '.editorconfig',
26 | '.git',
27 | '.gitattributes',
28 | '.gitignore',
29 | '.travis.yml',
30 | 'index.js',
31 | 'license',
32 | 'package.json',
33 | 'readme.md',
34 | 'test.js',
35 | 'info.plist'
36 | ]);
37 |
38 | assert.noFile('cli.js');
39 | });
40 |
--------------------------------------------------------------------------------
/app/templates/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) <%= name %> <<%= email %>> (<%= humanizedWebsite %>)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Sam Verschueren (github.com/SamVerschueren)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "generator-alfred",
3 | "version": "0.5.0",
4 | "description": "Scaffold out an Alfred workflow",
5 | "license": "MIT",
6 | "repository": "SamVerschueren/generator-alfred",
7 | "author": {
8 | "name": "Sam Verschueren",
9 | "email": "sam.verschueren@gmail.com",
10 | "url": "github.com/SamVerschueren"
11 | },
12 | "maintainers": [
13 | {
14 | "name": "Sindre Sorhus",
15 | "email": "sindresorhus@gmail.com",
16 | "url": "sindresorhus.com"
17 | }
18 | ],
19 | "engines": {
20 | "node": ">=4"
21 | },
22 | "scripts": {
23 | "test": "xo && ava"
24 | },
25 | "files": [
26 | "app"
27 | ],
28 | "keywords": [
29 | "yeoman-generator",
30 | "plugin",
31 | "boilerplate",
32 | "template",
33 | "scaffold",
34 | "alfred",
35 | "alfy",
36 | "workflow",
37 | "init"
38 | ],
39 | "dependencies": {
40 | "humanize-url": "^1.0.1",
41 | "is-scoped": "^1.0.0",
42 | "normalize-url": "^1.6.0",
43 | "superb": "^1.3.0",
44 | "underscore.string": "^3.3.4",
45 | "uuid": "^3.0.1",
46 | "yeoman-generator": "^1.1.0"
47 | },
48 | "devDependencies": {
49 | "ava": "*",
50 | "pify": "^2.3.0",
51 | "tempfile": "^1.1.1",
52 | "xo": "*",
53 | "yeoman-assert": "^2.2.1",
54 | "yeoman-test": "^1.4.0"
55 | },
56 | "ava": {
57 | "failWithoutAssertions": false
58 | },
59 | "xo": {
60 | "ignores": [
61 | "app/templates/**"
62 | ]
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/templates/info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | name
6 | <%= alfredName %>
7 | bundleid
8 | <%= alfredBundleId %>
9 | category
10 | <%= alfredCategory %>
11 | connections
12 |
13 | <%= uuid('uid') %>
14 |
15 |
16 | destinationuid
17 | <%= uuid('destinationuid') %>
18 | modifiers
19 | 0
20 | modifiersubtext
21 |
22 | vitoclose
23 |
24 |
25 |
26 |
27 | disabled
28 |
29 | objects
30 |
31 |
32 | config
33 |
34 | browser
35 |
36 | spaces
37 |
38 | url
39 | {query}
40 | utf8
41 |
42 |
43 | type
44 | alfred.workflow.action.openurl
45 | uid
46 | <%= uuid('destinationuid') %>
47 | version
48 | 1
49 |
50 |
51 | config
52 |
53 | alfredfiltersresults
54 |
55 | argumenttype
56 | 0
57 | escaping
58 | 102
59 | keyword
60 | <%= alfredKeyword %>
61 | queuedelaycustom
62 | 3
63 | queuedelayimmediatelyinitially
64 |
65 | queuedelaymode
66 | 0
67 | queuemode
68 | 2
69 | runningsubtext
70 | Searching...
71 | script
72 | ./node_modules/.bin/run-node index.js "$1"
73 | scriptargtype
74 | 1
75 | scriptfile
76 | index.js
77 | subtext
78 |
79 | title
80 | <%= alfredTitle %>
81 | type
82 | 0
83 | withspace
84 |
85 |
86 | type
87 | alfred.workflow.input.scriptfilter
88 | uid
89 | <%= uuid('uid') %>
90 | version
91 | 2
92 |
93 |
94 | readme
95 |
96 | uidata
97 |
98 | <%= uuid('destinationuid') %>
99 |
100 | xpos
101 | 150
102 | ypos
103 | 10
104 |
105 | <%= uuid('uid') %>
106 |
107 | xpos
108 | 10
109 | ypos
110 | 10
111 |
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/app/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const superb = require('superb');
3 | const normalizeUrl = require('normalize-url');
4 | const humanizeUrl = require('humanize-url');
5 | const Generator = require('yeoman-generator');
6 | const _s = require('underscore.string');
7 | const utils = require('./utils');
8 |
9 | module.exports = class extends Generator {
10 | init() {
11 | return this.prompt([
12 | {
13 | name: 'moduleName',
14 | message: 'What do you want to name your module?',
15 | default: _s.slugify(this.appname),
16 | filter: x => {
17 | let name = utils.slugifyPackageName(x);
18 |
19 | if (!name.startsWith('alfred-')) {
20 | name = `alfred-${name}`;
21 | }
22 |
23 | return name;
24 | }
25 | },
26 | {
27 | name: 'moduleDescription',
28 | message: 'What is your module description?',
29 | default: `My ${superb()} module`
30 | },
31 | {
32 | name: 'alfredKeyword',
33 | message: 'What is the Alfred activation keyword?',
34 | default: props => props.moduleName.replace(/^alfred-/, '')
35 | },
36 | {
37 | name: 'alfredTitle',
38 | message: 'What is the Alfred title?',
39 | default: props => props.moduleDescription
40 | },
41 | {
42 | name: 'alfredCategory',
43 | message: 'What is the Alfred category?',
44 | type: 'list',
45 | default: 'Uncategorised',
46 | choices: [
47 | 'Tools',
48 | 'Internet',
49 | 'Productivity',
50 | 'Uncategorised'
51 | ]
52 | },
53 | {
54 | name: 'githubUsername',
55 | message: 'What is your GitHub username?',
56 | store: true,
57 | validate: x => x.length > 0 ? true : 'You have to provide a username'
58 | },
59 | {
60 | name: 'website',
61 | message: 'What is the URL of your website?',
62 | store: true,
63 | validate: x => x.length > 0 ? true : 'You have to provide a website URL',
64 | filter: x => normalizeUrl(x)
65 | }
66 | ]).then(props => {
67 | props.alfredName = props.moduleName.replace(/^alfred-/, '');
68 |
69 | const tpl = {
70 | moduleName: props.moduleName,
71 | moduleDescription: props.moduleDescription,
72 | alfredName: props.alfredName,
73 | alfredBundleId: utils.bundleId(props),
74 | alfredCategory: props.alfredCategory,
75 | alfredKeyword: props.alfredKeyword,
76 | alfredTitle: props.alfredTitle,
77 | githubUsername: this.options.org || props.githubUsername,
78 | repoName: utils.repoName(props.moduleName),
79 | name: this.user.git.name(),
80 | email: this.user.git.email(),
81 | website: props.website,
82 | humanizedWebsite: humanizeUrl(props.website),
83 | uuid: utils.generateUuid
84 | };
85 |
86 | const mv = (from, to) => {
87 | this.fs.move(this.destinationPath(from), this.destinationPath(to));
88 | };
89 |
90 | this.fs.copyTpl([
91 | `${this.templatePath()}/**`
92 | ], this.destinationPath(), tpl);
93 |
94 | mv('editorconfig', '.editorconfig');
95 | mv('gitattributes', '.gitattributes');
96 | mv('gitignore', '.gitignore');
97 | mv('travis.yml', '.travis.yml');
98 | mv('_package.json', 'package.json');
99 | });
100 | }
101 |
102 | git() {
103 | this.spawnCommandSync('git', ['init']);
104 | }
105 |
106 | install() {
107 | this.npmInstall(null, {ignoreScripts: true});
108 | }
109 | };
110 |
--------------------------------------------------------------------------------