Skip to content
This repository was archived by the owner on Dec 15, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions spec/apm-cli-spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -508,3 +508,49 @@ describe 'apm command line interface', ->
expect(fs.existsSync(repoPath)).toBeTruthy()
expect(fs.existsSync(linkedRepoPath)).toBeTruthy()
expect(fs.realpathSync(linkedRepoPath)).toBe fs.realpathSync(repoPath)

describe "apm init", ->
[packagePath, themePath] = []

beforeEach ->
currentDir = temp.mkdirSync('apm-init-')
spyOn(process, 'cwd').andReturn(currentDir)
packagePath = path.join(currentDir, 'fake-package')
themePath = path.join(currentDir, 'fake-theme')

describe "when creating a package", ->
it "generates the proper file structure", ->
callback = jasmine.createSpy('callback')
apm.run(['init', '--package', 'fake-package'], callback)

waitsFor 'waiting for init to complete', ->
callback.callCount is 1

runs ->
expect(fs.existsSync(packagePath)).toBeTruthy()
expect(fs.existsSync(path.join(packagePath, 'keymaps'))).toBeTruthy()
expect(fs.existsSync(path.join(packagePath, 'keymaps', 'fake-package.cson'))).toBeTruthy()
expect(fs.existsSync(path.join(packagePath, 'lib'))).toBeTruthy()
expect(fs.existsSync(path.join(packagePath, 'lib', 'fake-package-view.coffee'))).toBeTruthy()
expect(fs.existsSync(path.join(packagePath, 'lib', 'fake-package.coffee'))).toBeTruthy()
expect(fs.existsSync(path.join(packagePath, 'spec', 'fake-package-view-spec.coffee'))).toBeTruthy()
expect(fs.existsSync(path.join(packagePath, 'spec', 'fake-package-spec.coffee'))).toBeTruthy()
expect(fs.existsSync(path.join(packagePath, 'stylesheets', 'fake-package.css'))).toBeTruthy()
expect(fs.existsSync(path.join(packagePath, 'package.cson'))).toBeTruthy()

describe "when creating a theme", ->
fit "generates the proper file structure", ->
callback = jasmine.createSpy('callback')
apm.run(['init', '--theme', 'fake-theme'], callback)

waitsFor 'waiting for init to complete', ->
callback.callCount is 1

runs ->
expect(fs.existsSync(themePath)).toBeTruthy()
expect(fs.existsSync(path.join(themePath, 'stylesheets'))).toBeTruthy()
expect(fs.existsSync(path.join(themePath, 'stylesheets', 'base.less'))).toBeTruthy()
expect(fs.existsSync(path.join(themePath, 'index.less'))).toBeTruthy()
expect(fs.existsSync(path.join(themePath, 'README.md'))).toBeTruthy()
expect(fs.existsSync(path.join(themePath, 'package.json'))).toBeTruthy()

1 change: 1 addition & 0 deletions src/apm-cli.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ commandClasses = [
require './cleaner'
require './developer'
require './fetcher'
require './init'
require './installer'
require './link-lister'
require './linker'
Expand Down
3 changes: 3 additions & 0 deletions src/fs.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ fsAdditions =
else
[]

listRecursive: (directoryPath) ->
wrench.readdirSyncRecursive(directoryPath)

rm: (pathToRemove) ->
rimraf.sync(pathToRemove)

Expand Down
98 changes: 98 additions & 0 deletions src/init.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
path = require 'path'

optimist = require 'optimist'

Command = require './command'
fs = require './fs'

module.exports =
class Generator extends Command
@commandNames: ['init']

parseOptions: (argv) ->
options = optimist(argv)

options.usage """
Usage:
apm init -p <package-name>
apm init -t <theme-name>

Generates code scaffolding for either a theme or package depending
on option selected.
"""
options.alias('p', 'package').describe('package', 'Generates a basic package')
options.alias('t', 'theme').describe('theme', 'Generates a basic theme')
options.alias('h', 'help').describe('help', 'Print this usage message')

showHelp: (argv) -> @parseOptions(argv).showHelp()

run: (options) ->
{callback} = options
options = @parseOptions(options.commandArgs)
if options.argv.package?
packagePath = path.resolve(options.argv.package)
templatePath = path.resolve(__dirname, '..', 'templates', 'package')
@generateFromTemplate(packagePath, templatePath)
callback()
else if options.argv.theme?
themePath = path.resolve(options.argv.theme)
templatePath = path.resolve(__dirname, '..', 'templates', 'theme')
@generateFromTemplate(themePath, templatePath)
callback()
else
callback('Error: You must specify either --package or --theme to `apm init`')

generateFromTemplate: (packagePath, templatePath) ->
packageName = path.basename(packagePath)

fs.mkdir(packagePath)

for childPath in fs.listRecursive(templatePath)
templateChildPath = path.resolve(templatePath, childPath)
relativePath = templateChildPath.replace(templatePath, "")
relativePath = relativePath.replace(/^\//, '')
relativePath = relativePath.replace(/\.template$/, '')
relativePath = @replacePackageNamePlaceholders(relativePath, packageName)

sourcePath = path.join(packagePath, relativePath)
if fs.isDirectory(templateChildPath)
fs.mkdir(sourcePath)
else if fs.isFile(templateChildPath)
fs.mkdir(path.dirname(sourcePath))
contents = fs.readFileSync(templateChildPath).toString()
content = @replacePackageNamePlaceholders(contents, packageName)
fs.writeFileSync(sourcePath, content)

replacePackageNamePlaceholders: (string, packageName) ->
placeholderRegex = /__(?:(package-name)|([pP]ackageName)|(package_name))__/g
string = string.replace placeholderRegex, (match, dash, camel, underscore) =>
if dash
@dasherize(packageName)
else if camel
if /[a-z]/.test(camel[0])
packageName = packageName[0].toLowerCase() + packageName[1...]
else if /[A-Z]/.test(camel[0])
packageName = packageName[0].toUpperCase() + packageName[1...]
@camelize(packageName)

else if underscore
@underscore(packageName)

dasherize: (string) ->
string = string[0].toLowerCase() + string[1..]
string.replace /([A-Z])|(_)/g, (m, letter, underscore) ->
if letter
"-" + letter.toLowerCase()
else
"-"

camelize: (string) ->
string.replace /[_-]+(\w)/g, (m) -> m[1].toUpperCase()

underscore: (string) ->
string = string[0].toLowerCase() + string[1..]
string.replace /([A-Z])|(-)/g, (m, letter, dash) ->
if letter
"_" + letter.toLowerCase()
else
"_"
3 changes: 3 additions & 0 deletions templates/package/keymaps/__package-name__.cson.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# DOCUMENT: link to keymap documentation
'body':
'meta-alt-ctrl-o': '__package-name__:toggle'
25 changes: 25 additions & 0 deletions templates/package/lib/__package-name__-view.coffee.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{$$, View} = require 'space-pen'

module.exports =
class __PackageName__View extends View
@content: ->
@div class: '__package-name__ overlay from-top', =>
@div "The __PackageName__ package is Alive! It's ALIVE!", class: "message"

initialize: (serializeState) ->
rootView.command "__package-name__:toggle", => @toggle()

# Returns an object that can be retrieved when package is activated
serialize: ->

# Tear down any state and detach
destroy: ->
@detach()

toggle: ->
console.log "__PackageName__View was toggled!"
if @hasParent()
@detach()
else
rootView.append(this)

13 changes: 13 additions & 0 deletions templates/package/lib/__package-name__.coffee.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
__PackageName__View = require './__package-name__-view'

module.exports =
__packageName__View: null

activate: (state) ->
@__packageName__View = new __PackageName__View(state.__packageName__ViewState)

deactivate: ->
@__packageName__View.destroy()

serialize: ->
__packageName__ViewState: @__packageName__View.serialize()
2 changes: 2 additions & 0 deletions templates/package/package.cson
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
'main': './lib/__package-name__'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should really be a package.json and have a "name" key set to __package-name__

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to do an update to the templates in a separate pull.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, cool, sounds good.

'activationEvents': ['__package-name__:toggle']
5 changes: 5 additions & 0 deletions templates/package/spec/__package-name__-spec.coffee.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
__PackageName__ = require '../lib/__package-name__'

describe "__PackageName__", ->
it "has one valid test", ->
expect("life").toBe "easy"
21 changes: 21 additions & 0 deletions templates/package/spec/__package-name__-view-spec.coffee.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
__PackageName__View = require '../lib/__package-name__-view'
RootView = require 'root-view'

# This spec is focused because it starts with an `f`. Remove the `f`
# to unfocus the spec.
#
# Press meta-alt-ctrl-s to run the specs
fdescribe "__PackageName__View", ->
__packageName__ = null

beforeEach ->
window.rootView = new RootView
__packageName__ = atom.activatePackage('__packageName__', immediate: true)

describe "when the __package-name__:toggle event is triggered", ->
it "attaches and then detaches the view", ->
expect(rootView.find('.__package-name__')).not.toExist()
rootView.trigger '__package-name__:toggle'
expect(rootView.find('.__package-name__')).toExist()
rootView.trigger '__package-name__:toggle'
expect(rootView.find('.__package-name__')).not.toExist()
2 changes: 2 additions & 0 deletions templates/package/stylesheets/__package-name__.css.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.__package-name__ {
}
3 changes: 3 additions & 0 deletions templates/theme/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## __package-name__ Theme

A short description of your theme.
1 change: 1 addition & 0 deletions templates/theme/index.less
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import "./stylesheets/base.less";
19 changes: 19 additions & 0 deletions templates/theme/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "__package-name__",
"theme": true,
"version": "0.0.0",
"description": "A short description of your theme",
"repository": {
"type": "git",
"url": "https://github.com/your/repo.git"
},
"bugs": {
"url": "https://github.com/your/repo/issues"
},
"engines": {
"atom": ">26.0"
},
"publishConfig": {
"registry": "https://atom.iriscouch.com/registry/_design/app/_rewrite"
}
}
9 changes: 9 additions & 0 deletions templates/theme/stylesheets/base.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// The ui-variables file is provided by base themes provided by Atom.
//
// See https://github.com/atom/atom-dark-ui/blob/master/stylesheets/ui-variables.less
// for a full listing of what's available.
@import "ui-variables";

.editor {
color: fade(@text-color, 20%);
}