├── example ├── .meteor │ ├── .gitignore │ ├── release │ ├── platforms │ ├── .finished-upgraders │ ├── .id │ ├── packages │ └── versions ├── packages │ ├── deanius:package-kitchen │ ├── okgrow:package-linter │ └── npm-container │ │ ├── index.js │ │ └── package.js ├── packages.json ├── layout.html ├── routes.js ├── client │ └── analytics.js ├── settings.json └── customize.js ├── .gitignore ├── client ├── templates │ ├── code.html │ ├── travis.html │ ├── readme.html │ └── packageJs.html ├── routes.js ├── allFiles.js ├── allFiles.html ├── kitchen.js ├── flair.html ├── zip.js ├── editor.js ├── kitchen.html ├── linter.html ├── linter.js ├── editor.html └── _viewmodel.js ├── tests └── index.js ├── package.json ├── TODO.md ├── .versions ├── server └── methods.js ├── package.js └── README.md /example/.meteor/.gitignore: -------------------------------------------------------------------------------- 1 | local 2 | -------------------------------------------------------------------------------- /example/.meteor/release: -------------------------------------------------------------------------------- 1 | METEOR@1.1.0.3 2 | -------------------------------------------------------------------------------- /example/.meteor/platforms: -------------------------------------------------------------------------------- 1 | server 2 | browser 3 | -------------------------------------------------------------------------------- /example/packages/deanius:package-kitchen: -------------------------------------------------------------------------------- 1 | ../.. -------------------------------------------------------------------------------- /example/packages/okgrow:package-linter: -------------------------------------------------------------------------------- 1 | ../../../meteor-package-linter -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .build* 2 | .npm* 3 | versions.json 4 | 5 | npm-debug.log 6 | -------------------------------------------------------------------------------- /client/templates/code.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/packages.json: -------------------------------------------------------------------------------- 1 | { 2 | "mkdirp": "0.5.1", 3 | "latest-version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /tests/index.js: -------------------------------------------------------------------------------- 1 | Tinytest.add("deanius:new-package", function (test) { 2 | test.equal(true, true); 3 | }); 4 | -------------------------------------------------------------------------------- /example/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/routes.js: -------------------------------------------------------------------------------- 1 | Router.route("kitchen", { 2 | path: "/kitchen", 3 | template: "package-kitchen-kitchen", 4 | data: packageModel 5 | }) 6 | -------------------------------------------------------------------------------- /example/routes.js: -------------------------------------------------------------------------------- 1 | Router.route("/", function () { 2 | this.render("package-kitchen-kitchen", {}); 3 | }); 4 | Router.route("/linter", function () { 5 | this.render("package-kitchen-linter", {}); 6 | }); 7 | -------------------------------------------------------------------------------- /example/client/analytics.js: -------------------------------------------------------------------------------- 1 | Template['package-kitchen-kitchen'].events({ 2 | "click .download" : function (e) { 3 | analytics.track("Download Package", { 4 | packageName: packageViewModel.fullPackageName() 5 | }); 6 | } 7 | }); 8 | -------------------------------------------------------------------------------- /example/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "public": { 3 | "analyticsSettings": { 4 | "Mixpanel": {"token": "bb5bb4cd34af9b759310ef33db021c12", "people": true} 5 | }, 6 | "persistent_session": { 7 | "default_method": "persistent" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /client/templates/travis.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /client/allFiles.js: -------------------------------------------------------------------------------- 1 | Template['package-kitchen-allFiles'].helpers({ 2 | isMarkdown : function () { 3 | return this.path.match(/\.md$/); 4 | }, 5 | allFilesRendered: function () { 6 | return ViewModel.byId("packageModel") && ViewModel.byId("packageModel").allFilesRendered(); 7 | } 8 | }); 9 | -------------------------------------------------------------------------------- /example/.meteor/.finished-upgraders: -------------------------------------------------------------------------------- 1 | # This file contains information which helps Meteor properly upgrade your 2 | # app when you run 'meteor update'. You should check it into version control 3 | # with your project. 4 | 5 | notices-for-0.9.0 6 | notices-for-0.9.1 7 | 0.9.4-platform-file 8 | notices-for-facebook-graph-api-2 9 | -------------------------------------------------------------------------------- /example/packages/npm-container/index.js: -------------------------------------------------------------------------------- 1 | Meteor.npmRequire = function(moduleName) { 2 | var module = Npm.require(moduleName); 3 | return module; 4 | }; 5 | 6 | Meteor.require = function(moduleName) { 7 | console.warn('Meteor.require is deprecated. Please use Meteor.npmRequire instead!'); 8 | return Meteor.npmRequire(moduleName); 9 | }; -------------------------------------------------------------------------------- /example/.meteor/.id: -------------------------------------------------------------------------------- 1 | # This file contains a token that is unique to your project. 2 | # Check it into your repository along with the rest of this directory. 3 | # It can be used for purposes such as: 4 | # - ensuring you don't accidentally deploy one app on top of another 5 | # - providing package authors with aggregated statistics 6 | 7 | 19m7g4vryo90fxbovoi 8 | -------------------------------------------------------------------------------- /client/templates/readme.html: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /client/allFiles.html: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /client/kitchen.js: -------------------------------------------------------------------------------- 1 | Template['package-kitchen-kitchen'].events({ 2 | "click .download" : zipPackage, 3 | "click .saveToApp" : function (e) { 4 | Meteor.promise( 5 | "deanius:package-kitchen#saveToApp", 6 | packageViewModel.fullPackageName(), 7 | packageViewModel.allFilesRendered() 8 | ).then( 9 | function(){ alert("Your package has been created. App will now reload.") }, 10 | function(err){ alert(err.reason); } 11 | ); 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /example/customize.js: -------------------------------------------------------------------------------- 1 | if (Meteor.isClient){ 2 | Template['package-kitchen-kitchen'].onRendered(function hideSaveToApp () { 3 | if (document.location.hostname==="package-kitchen.meteor.com") { 4 | $(".saveToApp").hide() 5 | } 6 | }); 7 | Template['package-kitchen-editor'].onRendered(function getValuesFromSession () { 8 | //XXX TODO getValuesFromSession 9 | }); 10 | // Template['package-kitchen-editor'].onRendered(function(){ 11 | // window.packageViewModel = ViewModel.byId("packageModel"); 12 | // }); 13 | } 14 | -------------------------------------------------------------------------------- /example/.meteor/packages: -------------------------------------------------------------------------------- 1 | # Meteor packages used by this project, one per line. 2 | # Check this file (and the other files in this directory) into your repository. 3 | # 4 | # 'meteor add' and 'meteor remove' will edit this file for you, 5 | # but you can also edit it by hand. 6 | 7 | meteor-platform 8 | reactive-dict 9 | promise 10 | npm-container 11 | 12 | iron:router 13 | meteorhacks:npm 14 | audit-argument-checks 15 | twbs:bootstrap 16 | u2622:persistent-session 17 | 18 | okgrow:promise 19 | okgrow:analytics 20 | perak:markdown 21 | manuel:viewmodel 22 | 23 | okgrow:package-linter 24 | deanius:package-kitchen 25 | -------------------------------------------------------------------------------- /client/flair.html: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "start": "cd example && meteor --port 3141 --settings settings.json", 4 | "shell": "cd example && meteor shell", 5 | "test": "meteor test-packages ./", 6 | "dev-mode": "rm -rf example/packages/deanius\\:package-kitchen; mkdir -p example/packages; ln -s ../.. example/packages/deanius\\:package-kitchen", 7 | "release-mode": "rm -rf example/packages/deanius\\:package-kitchen; mkdir example/packages/deanius\\:package-kitchen; cp -rf package.js client server example/packages/deanius\\:package-kitchen/", 8 | "deploy": "cd example && meteor deploy --settings settings.json package-kitchen.meteor.com" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /example/packages/npm-container/package.js: -------------------------------------------------------------------------------- 1 | var path = Npm.require('path'); 2 | var fs = Npm.require('fs'); 3 | 4 | Package.describe({ 5 | summary: 'Contains all your npm dependencies', 6 | version: '1.0.0', 7 | name: 'npm-container' 8 | }); 9 | 10 | var packagesJsonFile = path.resolve('./packages.json'); 11 | try { 12 | var fileContent = fs.readFileSync(packagesJsonFile); 13 | var packages = JSON.parse(fileContent.toString()); 14 | Npm.depends(packages); 15 | } catch (ex) { 16 | console.error('ERROR: packages.json parsing error [ ' + ex.message + ' ]'); 17 | } 18 | 19 | // Adding the app's packages.json as a used file for this package will get 20 | // Meteor to watch it and reload this package when it changes 21 | Package.onUse(function(api) { 22 | api.add_files(['index.js', '../../packages.json'], 'server'); 23 | }); -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | * [x] Make example/ app symlink to outer package, dedupe! 2 | * [x] Hide "Save Package To App" in production 3 | * [x] Meteor 1.1.0.3 4 | * [x] Add runtime resolution for MeteorJS modules (DDP to atmosphere) 5 | * [x] Split up helpers into separate files 6 | * [ ] Publish to github (or suggest Firefox - damn Chrome download-blocking fascism) 7 | * [ ] Only define saveToApp method in local environment, not hosted 8 | * [ ] Convert to ES6 - Use JS concatenation (or ES6 backquote strings) instead of templates 9 | * [ ] Different transpilation options 10 | 11 | Wonkery 12 | * [ ] Make router-independent 13 | * [ ] Separate runtime resolution of dep numbers from package model 14 | * [ ] Update to Material UI, reskin 15 | * [ ] Rebrand to OK Grow! (?) 16 | * [ ] Make something that can derive a packageModel by executing a `package.js` 17 | -------------------------------------------------------------------------------- /client/zip.js: -------------------------------------------------------------------------------- 1 | zipPackage = function () { 2 | console.log("zipping package"); 3 | var zipContent, zip = new JSZip(); 4 | 5 | packageViewModel.allFilesRendered().forEach(function (file) { 6 | zip.file(file.path, file.contents); 7 | }); 8 | 9 | var base64contents = zip.generate({type:"base64"}); 10 | window.location = "data:application/zip;base64," + base64contents; 11 | 12 | var packageDirName = packageViewModel.fullPackageName().replace(":", "\\:"); 13 | $("#packageCreateShellCode").val( 14 | "echo -n " + base64contents + " | pbcopy;\n" + 15 | "mkdir -p packages/" + packageDirName + ";\n" + 16 | "cd packages/" + packageDirName + ";\n" + 17 | "pbpaste | base64 -D > tmp.zip;\n" + 18 | "unzip tmp.zip; rm tmp.zip; cd ../..; \n" + 19 | "meteor add " + packageViewModel.fullPackageName() + "\n" 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /client/templates/packageJs.html: -------------------------------------------------------------------------------- 1 | 26 | 27 | 32 | -------------------------------------------------------------------------------- /.versions: -------------------------------------------------------------------------------- 1 | amplify@1.0.0 2 | base64@1.0.3 3 | blaze@2.1.2 4 | blaze-tools@1.0.3 5 | boilerplate-generator@1.0.3 6 | callback-hook@1.0.3 7 | check@1.0.5 8 | coffeescript@1.0.6 9 | ddp@1.1.0 10 | deanius:package-kitchen@1.3.1 11 | deanius:promise@2.0.4 12 | deps@1.0.7 13 | ejson@1.0.6 14 | geojson-utils@1.0.3 15 | html-tools@1.0.4 16 | htmljs@1.0.4 17 | id-map@1.0.3 18 | iron:controller@1.0.7 19 | iron:core@1.0.7 20 | iron:dynamic-template@1.0.7 21 | iron:layout@1.0.7 22 | iron:location@1.0.7 23 | iron:middleware-stack@1.0.7 24 | iron:router@1.0.7 25 | iron:url@1.0.7 26 | jquery@1.11.3_2 27 | json@1.0.3 28 | logging@1.0.7 29 | manuel:reactivearray@1.0.5 30 | manuel:viewmodel@1.7.4 31 | manuel:viewmodel-explorer@1.0.5 32 | meteor@1.1.6 33 | minifiers@1.1.5 34 | minimongo@1.0.8 35 | mrt:session-amplify@0.1.1 36 | observe-sequence@1.0.6 37 | ordered-dict@1.0.3 38 | perak:markdown@1.0.5 39 | random@1.0.3 40 | reactive-dict@1.1.0 41 | reactive-var@1.0.5 42 | retry@1.0.3 43 | routepolicy@1.0.5 44 | session@1.1.0 45 | spacebars@1.0.6 46 | spacebars-compiler@1.0.6 47 | templating@1.1.1 48 | tracker@1.0.7 49 | ui@1.0.6 50 | underscore@1.0.3 51 | webapp@1.2.0 52 | webapp-hashing@1.0.3 53 | -------------------------------------------------------------------------------- /client/editor.js: -------------------------------------------------------------------------------- 1 | Template['package-kitchen-editor'].events({ 2 | 'click .deleteDep': function (e, t) { 3 | var packageName = e.target.attributes['data-package-name'].value; 4 | var names = packageViewModel.meteorDepNames(); 5 | var delIdx = names.indexOf(packageName); 6 | if(delIdx > -1) names.splice(delIdx, 1); 7 | } 8 | }) 9 | 10 | Template['package-kitchen-editor'].helpers({ 11 | packagesWithVersions: function () { 12 | //this helper will be called at least once before our VM, or its global variable are defined 13 | return (ViewModel.byId("packageModel") && ViewModel.byId("packageModel").meteorDepNames()) || []; 14 | } 15 | }) 16 | 17 | function exposeVars () { 18 | window.packageModel = packageModel; 19 | window.packageViewModel = ViewModel.byId("packageModel"); 20 | } 21 | 22 | function activateButtons () { 23 | $('.btnNext').click(function(){ 24 | $('.tab-content > .active').next('li').find('a').trigger('click'); 25 | }); 26 | } 27 | 28 | function detectNewMeteorPackage () { 29 | function submitMeteorDepName (e) { 30 | e.preventDefault(); 31 | var $pkg = $("input[name=addNewPackageDep]"); 32 | var packageName = $pkg.val(); 33 | packageViewModel.meteorDepNames().push(packageName); 34 | $pkg.val(''); 35 | } 36 | $("#submitMeteorDepName").on('click', submitMeteorDepName) 37 | $("#addNewPackageDep").on('submit', submitMeteorDepName); 38 | } 39 | 40 | [exposeVars, detectNewMeteorPackage, 41 | activateButtons].forEach(function (fn) { 42 | Template['package-kitchen-editor'].onRendered(fn); 43 | }) 44 | -------------------------------------------------------------------------------- /client/kitchen.html: -------------------------------------------------------------------------------- 1 | 2 | 36 | -------------------------------------------------------------------------------- /example/.meteor/versions: -------------------------------------------------------------------------------- 1 | amplify@1.0.0 2 | audit-argument-checks@1.0.3 3 | autoupdate@1.2.1 4 | base64@1.0.3 5 | binary-heap@1.0.3 6 | blaze@2.1.2 7 | blaze-tools@1.0.3 8 | boilerplate-generator@1.0.3 9 | callback-hook@1.0.3 10 | check@1.0.5 11 | coffeescript@1.0.6 12 | ddp@1.1.0 13 | deanius:package-kitchen@1.3.2 14 | deps@1.0.7 15 | ejson@1.0.6 16 | fastclick@1.0.3 17 | geojson-utils@1.0.3 18 | html-tools@1.0.4 19 | htmljs@1.0.4 20 | http@1.1.0 21 | id-map@1.0.3 22 | iron:controller@1.0.8 23 | iron:core@1.0.8 24 | iron:dynamic-template@1.0.8 25 | iron:layout@1.0.8 26 | iron:location@1.0.9 27 | iron:middleware-stack@1.0.9 28 | iron:router@1.0.9 29 | iron:url@1.0.9 30 | jquery@1.11.3_2 31 | json@1.0.3 32 | launch-screen@1.0.2 33 | livedata@1.0.13 34 | logging@1.0.7 35 | manuel:isdev@1.0.0 36 | manuel:reactivearray@1.0.5 37 | manuel:viewmodel@1.9.10 38 | manuel:viewmodel-explorer@1.0.5 39 | meteor@1.1.6 40 | meteor-platform@1.2.2 41 | meteorhacks:async@1.0.0 42 | meteorhacks:npm@1.5.0 43 | minifiers@1.1.5 44 | minimongo@1.0.8 45 | mobile-status-bar@1.0.3 46 | mongo@1.1.0 47 | mrt:session-amplify@0.1.1 48 | npm-container@1.0.0 49 | observe-sequence@1.0.6 50 | okgrow:analytics@0.3.0 51 | okgrow:package-linter@0.1.0 52 | okgrow:promise@0.9.4 53 | ordered-dict@1.0.3 54 | perak:markdown@1.0.5 55 | promise@0.4.1 56 | random@1.0.3 57 | reactive-dict@1.1.0 58 | reactive-var@1.0.5 59 | reload@1.1.3 60 | retry@1.0.3 61 | routepolicy@1.0.5 62 | session@1.1.0 63 | spacebars@1.0.6 64 | spacebars-compiler@1.0.6 65 | templating@1.1.1 66 | tracker@1.0.7 67 | twbs:bootstrap@3.3.5 68 | u2622:persistent-session@0.4.1 69 | ui@1.0.6 70 | underscore@1.0.3 71 | url@1.0.4 72 | webapp@1.2.0 73 | webapp-hashing@1.0.3 74 | -------------------------------------------------------------------------------- /server/methods.js: -------------------------------------------------------------------------------- 1 | var fs = Npm.require('fs'); 2 | var path = Npm.require('path'); 3 | var mkdirp = Meteor.wrapAsync(Npm.require('mkdirp')); 4 | 5 | Meteor.methods({ 6 | "deanius:package-kitchen#saveToApp" : function (packageName, allFilesRendered) { 7 | check(packageName, String); 8 | check(allFilesRendered, [Match.ObjectIncluding({path: String, contents: String})]); 9 | 10 | // check - array of {path, contents} 11 | // check - make sure folder doesn't exist, or warn 12 | 13 | 14 | var packageFolder = path.join(process.env.PWD, 'packages', packageName); 15 | 16 | if (fs.existsSync(packageFolder) || 17 | fs.readFileSync(process.env.PWD+'/.meteor/packages', {encoding:'utf8'}).match(packageName) 18 | ) { 19 | throw new Meteor.Error("packageExists", "Refusing to overwrite existing package " + packageName); 20 | } 21 | 22 | //LEFTOFF - dont add package to .meteor/packages if it exists, either 23 | 24 | // make directories, files 25 | _.each(allFilesRendered, function (fileSpec) { 26 | var fileContents = fileSpec.contents, 27 | filePath = fileSpec.path, 28 | fullFilePath = path.join(packageFolder, filePath); 29 | 30 | mkdirp(path.dirname(fullFilePath)); 31 | fs.writeFileSync(fullFilePath, fileContents); 32 | }); 33 | 34 | console.log('deanius:package-kitchen - wrote out packge files'); 35 | 36 | //effectively, call "meteor add" 37 | fs.appendFileSync(process.env.PWD+'/.meteor/packages', packageName+"\n"); 38 | 39 | console.log('deanius:package-kitchen - finished package generation and registration'); 40 | //note: we hope not to get screwed by-an auto-reload breaking us up.. 41 | } 42 | }); 43 | -------------------------------------------------------------------------------- /client/linter.html: -------------------------------------------------------------------------------- 1 | 49 | -------------------------------------------------------------------------------- /package.js: -------------------------------------------------------------------------------- 1 | Package.describe({ 2 | name: "deanius:package-kitchen", 3 | summary: "Easy bootstrapping of Meteor packages, demo at: http://package-kitchen.meteor.com", 4 | version: "1.3.2", 5 | git: "https://github.com/deanius/meteor-package-kitchen" 6 | //debugOnly: true //XXX wont expose templates in production if we have debugOnly on 7 | }); 8 | 9 | Npm.depends({ 10 | "mkdirp": "0.5.0" 11 | }); 12 | 13 | Package.onUse(function(api) { 14 | api.versionsFrom("1.0.2"); 15 | api.use(["meteor", "tracker", "spacebars", "templating", "underscore", "reactive-dict", "mongo"]); 16 | api.use("iron:router@1.0.0"); 17 | api.use("manuel:viewmodel@1.7.4"); 18 | api.imply("manuel:viewmodel@1.7.4"); 19 | api.use("manuel:viewmodel-explorer@1.0.5"); 20 | 21 | api.use("okgrow:promise@0.9.0"); 22 | api.use("mrt:session-amplify@0.1.0"); 23 | 24 | // use it, and make its exports available in the app that includes us 25 | api.imply("perak:markdown@1.0.4"); 26 | 27 | api.addFiles("server/methods.js", ["server"]); 28 | api.addFiles("client/jszip.js", ["client"]); 29 | api.addFiles("client/templates/code.html", ["client"]); 30 | api.addFiles("client/templates/packageJs.html", ["client"]); 31 | api.addFiles("client/templates/readme.html", ["client"]); 32 | api.addFiles("client/templates/travis.html", ["client"]); 33 | api.addFiles("client/editor.html", ["client"]); 34 | api.addFiles("client/allFiles.html", ["client"]); 35 | api.addFiles("client/linter.html", ["client"]); 36 | api.addFiles("client/linter.js", ["client"]); 37 | api.addFiles("client/flair.html", ["client"]); 38 | api.addFiles("client/kitchen.html", ["client"]); 39 | api.addFiles("client/_viewmodel.js", ["client"]); 40 | api.addFiles("client/routes.js", ["client"]) 41 | api.addFiles("client/zip.js", ["client"]); 42 | api.addFiles("client/editor.js", ["client"]); 43 | api.addFiles("client/kitchen.js", ["client"]); 44 | api.addFiles("client/allFiles.js", ["client"]); 45 | 46 | api.export("packageModel", "client"); 47 | }); 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # deanius:package-kitchen 2 | 3 | Scaffolds out a new package, giving it to you as 4 | 5 | * source code on screen 6 | * a Zip file 7 | * (NEW) a local package installed into your app 8 | 9 | 10 | Step into the Package Kitchen to whip up your next Meteor package! 11 | 12 | [TOC] 13 | 14 | ## Online Usage 15 | 16 | Go to http://package-kitchen.meteor.com, and input the specifics of the package you want to build. You can then download a ZIP of your package, and follow the installation instructions on the site. 17 | 18 | ## 1. Using to extend an Application you are currently building 19 | 20 | Add Package Kitchen to your application: 21 | 22 | `meteor add deanius:package-kitchen` 23 | 24 | Then navigate to `/kitchen` within your application. Next, scaffold out your package, then click "Save Package to App". 25 | 26 | You will receive an error upon Save if: 27 | 28 | - There is already a local package by that name 29 | - The package name conflicts with one already listed in `.meteor/packages` (e.g. `iron:router`) 30 | 31 | ## 2. Running as an Application Locally 32 | 33 | You can spin up the app (as it deployed on http://package-kitchen.meteor.com), by running `npm start`. 34 | or, if you're old school, `cd example; meteor`. 35 | 36 | The example folder contains copies of all the templates, rather than referencing 37 | the atmosphere version. 38 | 39 | ## Further Reference 40 | [The Full Meteor Docs on Packages](http://docs.meteor.com/#/full/packagedefinition) 41 | 42 | The last [Packages Tutorial](http://themeteorchef.com/recipes/writing-a-package/) you'll ever need, by [@TheMeteorChef](http://twitter.com/themeteorchef) 43 | 44 | ## Specifying Dependencies 45 | 46 | 47 | You must specify dependencies if: 48 | 49 | * Your package must use the services of another (`api.use`) 50 | * You want to load additional functionality into the app that includes your package (`api.imply`) 51 | 52 | ### Meteor Packages 53 | 54 | Add the packages to the first `api.use([])` call, or add additional calls 55 | 56 | 57 | ### Npm 58 | 59 | Use `Npm.depend({"package": "1.0.0"})` 60 | 61 | ## Publishing Your Package 62 | 63 | TODO link to notes on how to do this. 64 | -------------------------------------------------------------------------------- /client/linter.js: -------------------------------------------------------------------------------- 1 | logObj = function (obj) { console.log(JSON.stringify(obj, null, 2)); return logObj; } 2 | window.LintErrors = new Mongo.Collection(); 3 | 4 | Template["package-kitchen-linter"].events({ 5 | 'click #lintIt' : function (e) { 6 | e.preventDefault(); 7 | LintErrors.remove({}); 8 | var packageJsCode = $("#packageJsToLint").val(); 9 | Meteor.promise("okgrow:package-linter#getPackageModel", packageJsCode) 10 | .then(function(model){ window.packageModel = model; logObj(model)}); 11 | 12 | Meteor.promise("okgrow:package-linter#getLintErrors", packageJsCode) 13 | .then(function (errs) { 14 | if(errs.length === 0) 15 | LintErrors.insert({error: "No errors detected!"}) 16 | else 17 | errs.forEach(function (err) { LintErrors.insert(err); }); 18 | }) 19 | .then(logObj) 20 | }, 21 | 'click #fixIt': function () { 22 | // set content of modal 23 | var packageJsCode = $("#packageJsToLint").val(); 24 | var lintErrors = LintErrors.find().fetch(); 25 | var replacements22 = lintErrors 26 | .filter(function (err) { return (err.code === "2.2")}) 27 | .map(function (err){ 28 | return [err.offender + "@" + err.details.oldVersion, 29 | err.details.newName + "@" + err.details.newVersion]; 30 | }); 31 | var replacements23 = lintErrors 32 | .filter(function (err) { return (err.code === "2.3")}) 33 | .map(function (err){ 34 | return [err.offender + "@" + err.details.current, 35 | err.offender + "@" + err.details.latest]; 36 | }); 37 | 38 | //important - update 2.2 - the deprecations first !! 39 | var replacements = [].concat(replacements22, replacements23); 40 | replacements.forEach(function (replaceArgs) { 41 | packageJsCode = "".replace.apply(packageJsCode, replaceArgs); 42 | }) 43 | $("#packageJSFixedCode").val(packageJsCode + 44 | "\n /* Package updated by okgrow:package-linter */\n"); 45 | } 46 | }); 47 | 48 | Template["package-kitchen-linter"].helpers({ 49 | lintErrors: function () { 50 | return LintErrors.find(); 51 | }, 52 | details: function () { 53 | return JSON.stringify(this.details); 54 | } 55 | }); 56 | -------------------------------------------------------------------------------- /client/editor.html: -------------------------------------------------------------------------------- 1 | 159 | -------------------------------------------------------------------------------- /client/_viewmodel.js: -------------------------------------------------------------------------------- 1 | var _npmVersions = new ReactiveDict("npmVersions"); 2 | var _meteorVersions = new ReactiveDict("meteorVersions"); 3 | 4 | packageModel = { 5 | atmosphereName: "deanius", 6 | githubName: "deanius", 7 | packageName: "new-package", 8 | version: "0.1.0", 9 | demoUrl: "", 10 | 11 | summary: "Description of package amazingness", 12 | "export": "log", 13 | 14 | packageType: "shared", // client, server, or shared 15 | meteorDepNames: ["ddp", "tracker"], 16 | meteorDepNamesWithVersions: function () { 17 | var self = this; 18 | 19 | return self.meteorDepNames().map(function(name){ 20 | var versionByName = _meteorVersions.get(name); 21 | 22 | return versionByName ? name + "@" + versionByName : name; 23 | }); 24 | }, 25 | meteorVersion: "1.2.0.1", 26 | npmDepsString: "", // comma-separated 27 | 28 | testFramework: "tinytest", // tinytest, mocha, "" 29 | code: "/* global log:true */\nlog = console.log.bind(console);", 30 | 31 | fullPackageName: function () { 32 | return this.atmosphereName() + ":" + this.packageName(); 33 | }, 34 | 35 | gitProject: function () { 36 | return this.githubName() + "/meteor-" + this.packageName(); 37 | }, 38 | 39 | gitPath: function () { 40 | return "https://github.com/" + this.gitProject(); 41 | }, 42 | 43 | npmDepNames: function () { 44 | if(this.npmDepsString()==="") return []; 45 | return this.npmDepsString().split(/\s*,\s*/); 46 | }, 47 | 48 | npmVersions: function () { 49 | if(this.npmDepNames().length === 0) return null; 50 | if( Object.keys(_npmVersions.keys).length > 0) return _npmVersions; 51 | 52 | this.npmDepNames().forEach(function (name) { 53 | _npmVersions.set(name, "latest"); 54 | }); 55 | return _npmVersions; 56 | }, 57 | 58 | npmDependencies: function () { 59 | var self = this; 60 | if(self.npmDepNames().length === 0) return null; 61 | 62 | var npmBlock = self.npmDepNames().reduce(function (all, name){ 63 | var version = self.npmVersions().get(name); 64 | all[name] = version; 65 | return all; 66 | }, {}); 67 | 68 | self.npmDepNames().forEach(function (name){ 69 | Meteor.promise("okgrow:package-linter#latestNpmVersionOfPackage", name).then(function (version){ 70 | if (!version) return; 71 | _npmVersions.set(name, version); 72 | }) 73 | }); 74 | return JSON.stringify(npmBlock, null, 2); 75 | }, 76 | 77 | travisBadgeMarkdown: function () { 78 | return "[![Build Status](https://secure.travis-ci.org/" + 79 | this.gitProject() + 80 | ".png?branch=master)](https://travis-ci.org/" + 81 | this.gitProject() + ")" 82 | }, 83 | 84 | // the test code to start us off with 85 | testCode: function () { 86 | if(this.testFramework() == "tinytest") 87 | return "Tinytest.add(\"" + this.packageName() + "\", function (test) {\n test.equal(true, true);\n});"; 88 | if(this.testFramework() == "mocha") 89 | return "describe(\"" + this.packageName() + "\", function () {\n it(\"should be awesome\", function (done) {\n assert.equal(1,2);\n });\n});" 90 | }, 91 | 92 | onTestCode: function () { 93 | var onTestCode; 94 | if(! this.testFramework() ) return "\n"; 95 | 96 | if(this.testFramework() === "tinytest"){ 97 | onTestCode = 'Package.onTest(function (api) {\n' + 98 | ' api.use("tinytest");\n'; 99 | } 100 | if(this.testFramework() === "mocha"){ 101 | onTestCode = 'Package.onTest(function (api) {\n' + 102 | ' api.use(["mike:mocha-package", "practicalmeteor:chai"]);\n'; 103 | } 104 | onTestCode += ' api.use("' + this.fullPackageName() + '");\n'; 105 | 106 | this.testFiles().forEach(function(testFile){ 107 | onTestCode += ' api.addFiles("' + testFile.path + '", ' + testFile.where + ');'; 108 | }); 109 | return onTestCode + "\n});"; 110 | }, 111 | 112 | fileLocation: function () { 113 | if (this.packageType() ==="shared") 114 | return '["client", "server"]'; 115 | else if (this.packageType() ==="client") 116 | return '["client"]'; 117 | else if (this.packageType() ==="server") 118 | return '["server"]'; 119 | }, 120 | 121 | apiFiles: function () { 122 | return [{ 123 | path: this.packageType() + "/index.js", 124 | where: this.fileLocation(), 125 | contents: this.code() 126 | }] 127 | }, 128 | 129 | testFiles: function () { 130 | if (! this.testFramework() ) return []; 131 | return [{ 132 | path: "tests/" + this.packageType() + "/index.js", 133 | where: this.fileLocation(), 134 | contents: this.testCode() 135 | }]; 136 | }, 137 | 138 | allFiles: function () { 139 | return [ 140 | { 141 | path: "package.js", 142 | template: Template.packageJs 143 | }, 144 | { 145 | path: "README.md", 146 | template: Template.readme 147 | } 148 | ] 149 | .concat(this.apiFiles()) 150 | .concat(this.testFiles()) 151 | .concat([ 152 | { 153 | path: ".travis.yml", 154 | template: Template.travis 155 | } 156 | ]); 157 | }, 158 | 159 | allFilesRendered: function () { 160 | var self = this; 161 | return self.allFiles().map(function (file) { 162 | return { 163 | path: file.path, 164 | contents: file.contents || Blaze.toHTMLWithData(file.template, self) 165 | }; 166 | }); 167 | }, 168 | 169 | exportSuggestion: function () { 170 | var match = this.code().match(/^(\w+)\s?=/m); 171 | return match ? match[1] : ""; 172 | }, 173 | 174 | autorun: function () { 175 | var self = this; 176 | self.meteorDepNames().list().forEach(function (name){ 177 | if (name.indexOf(":") === -1) return; 178 | 179 | 180 | savedName = _meteorVersions.get(name); 181 | if( !savedName || savedName===""){ 182 | _meteorVersions.set(name, ""); 183 | Meteor.promise("okgrow:package-linter#latestMeteorVersionOfPackage", name) 184 | .then(function (version){ 185 | _meteorVersions.set(name, version); 186 | }); 187 | }}); 188 | }, 189 | 190 | clearVersions: function () { 191 | for (var key in _meteorVersions.keys){ 192 | _meteorVersions.set(key, undefined) 193 | } 194 | for (var key in _npmVersions.keys){ 195 | _npmVersions.set(key, undefined) 196 | } 197 | } 198 | }; 199 | 200 | Template["package-kitchen-editor"].viewmodel("packageModel", packageModel); 201 | window.packageModel = packageModel; 202 | --------------------------------------------------------------------------------