From 75c006cb8cc8c199bfb6be86a2179b54f1fe4c70 Mon Sep 17 00:00:00 2001 From: William Bowers Date: Sun, 19 Jan 2014 20:09:48 -0800 Subject: [PATCH] Initial commit --- .gitignore | 4 + Gruntfile.js | 102 +++ LICENSE.txt | 7 + README.md | 465 +++++++++++++ TODO.md | 38 ++ common/highlight/highlight.js | 1 + common/highlight/styles/arta.css | 158 +++++ common/highlight/styles/ascetic.css | 50 ++ common/highlight/styles/brown_paper.css | 104 +++ common/highlight/styles/brown_papersq.png | Bin 0 -> 18198 bytes common/highlight/styles/dark.css | 103 +++ common/highlight/styles/default.css | 135 ++++ common/highlight/styles/far.css | 111 +++ common/highlight/styles/github.css | 127 ++++ common/highlight/styles/googlecode.css | 144 ++++ common/highlight/styles/idea.css | 121 ++++ common/highlight/styles/ir_black.css | 104 +++ common/highlight/styles/magula.css | 121 ++++ common/highlight/styles/monokai.css | 114 ++++ common/highlight/styles/pojoaque.css | 104 +++ common/highlight/styles/pojoaque.jpg | Bin 0 -> 1186 bytes common/highlight/styles/rainbow.css | 114 ++++ common/highlight/styles/school_book.css | 111 +++ common/highlight/styles/school_book.png | Bin 0 -> 486 bytes common/highlight/styles/solarized_dark.css | 88 +++ common/highlight/styles/solarized_light.css | 88 +++ common/highlight/styles/sunburst.css | 158 +++++ .../highlight/styles/tomorrow-night-blue.css | 52 ++ .../styles/tomorrow-night-bright.css | 51 ++ .../styles/tomorrow-night-eighties.css | 51 ++ common/highlight/styles/tomorrow-night.css | 52 ++ common/highlight/styles/tomorrow.css | 49 ++ common/highlight/styles/vs.css | 86 +++ common/highlight/styles/xcode.css | 154 +++++ common/highlight/styles/zenburn.css | 115 ++++ common/vanilla.unreset.css | 138 ++++ dist/variadic.js | 598 ++++++++++++++++ dist/variadic.min.js | 2 + examples/ajax/index.html | 18 + examples/ajax/main.js | 77 +++ examples/ajax/style.css | 23 + package.json | 27 + src/variadic.js | 646 ++++++++++++++++++ tests/index.html | 55 ++ tests/setup.js | 11 + tests/style.css | 11 + tests/tests/any.js | 46 ++ tests/tests/basic.js | 51 ++ tests/tests/builtin-descriptors.js | 4 + tests/tests/chaining.js | 66 ++ tests/tests/context.js | 35 + tests/tests/custom-defaults.js | 27 + tests/tests/custom-descriptors.js | 6 + tests/tests/defaults.js | 24 + tests/tests/examples/filtering-a-list.js | 70 ++ tests/tests/form.js | 31 + tests/tests/lone-prevention.js | 81 +++ tests/tests/optional-arguments.js | 33 + tests/tests/rest.js | 31 + tests/tests/similar-forms.js | 26 + tests/tests/variadic.js | 5 + 61 files changed, 5424 insertions(+) create mode 100644 .gitignore create mode 100644 Gruntfile.js create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 TODO.md create mode 100644 common/highlight/highlight.js create mode 100644 common/highlight/styles/arta.css create mode 100644 common/highlight/styles/ascetic.css create mode 100644 common/highlight/styles/brown_paper.css create mode 100644 common/highlight/styles/brown_papersq.png create mode 100644 common/highlight/styles/dark.css create mode 100644 common/highlight/styles/default.css create mode 100644 common/highlight/styles/far.css create mode 100644 common/highlight/styles/github.css create mode 100644 common/highlight/styles/googlecode.css create mode 100644 common/highlight/styles/idea.css create mode 100644 common/highlight/styles/ir_black.css create mode 100644 common/highlight/styles/magula.css create mode 100644 common/highlight/styles/monokai.css create mode 100644 common/highlight/styles/pojoaque.css create mode 100644 common/highlight/styles/pojoaque.jpg create mode 100644 common/highlight/styles/rainbow.css create mode 100644 common/highlight/styles/school_book.css create mode 100644 common/highlight/styles/school_book.png create mode 100644 common/highlight/styles/solarized_dark.css create mode 100644 common/highlight/styles/solarized_light.css create mode 100644 common/highlight/styles/sunburst.css create mode 100644 common/highlight/styles/tomorrow-night-blue.css create mode 100644 common/highlight/styles/tomorrow-night-bright.css create mode 100644 common/highlight/styles/tomorrow-night-eighties.css create mode 100644 common/highlight/styles/tomorrow-night.css create mode 100644 common/highlight/styles/tomorrow.css create mode 100644 common/highlight/styles/vs.css create mode 100644 common/highlight/styles/xcode.css create mode 100644 common/highlight/styles/zenburn.css create mode 100644 common/vanilla.unreset.css create mode 100644 dist/variadic.js create mode 100644 dist/variadic.min.js create mode 100644 examples/ajax/index.html create mode 100644 examples/ajax/main.js create mode 100644 examples/ajax/style.css create mode 100644 package.json create mode 100644 src/variadic.js create mode 100644 tests/index.html create mode 100644 tests/setup.js create mode 100644 tests/style.css create mode 100644 tests/tests/any.js create mode 100644 tests/tests/basic.js create mode 100644 tests/tests/builtin-descriptors.js create mode 100644 tests/tests/chaining.js create mode 100644 tests/tests/context.js create mode 100644 tests/tests/custom-defaults.js create mode 100644 tests/tests/custom-descriptors.js create mode 100644 tests/tests/defaults.js create mode 100644 tests/tests/examples/filtering-a-list.js create mode 100644 tests/tests/form.js create mode 100644 tests/tests/lone-prevention.js create mode 100644 tests/tests/optional-arguments.js create mode 100644 tests/tests/rest.js create mode 100644 tests/tests/similar-forms.js create mode 100644 tests/tests/variadic.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..431bd6c --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +node_modules/ +src-cov/ +docs/ diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..0e66efc --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,102 @@ +var TAB_SIZE_CSS = 'pre{-moz-tab-size:4;-o-tab-size:4;-webkit-tab-size:4;-ms-tab-size:4;tab-size:4;}'; + +function mochaCommand(reporter) { + return "./node_modules/mocha/bin/mocha --ui tdd --reporter " + reporter + " tests"; +} + +function docsCommand(command) { + if (typeof command !== "string") { + command = command.join(" && "); + } + + return "mkdir -p docs && " + command; +} + +module.exports = function(grunt) { + grunt.initConfig({ + pkg: grunt.file.readJSON("package.json"), + + files: { + src: ["src/**/*.js"], + tests: ["tests/**/*.js"], + watch: ["Gruntfile.js", "<%= files.src %>", "<%= files.tests %>"] + }, + + concat: { + dist: { + src: ["<%= files.src %>"], + dest: "dist/<%= pkg.name %>.js" + } + }, + + jshint: { + options: { + sub: true, + boss: true, + smarttabs: true + }, + files: ["<%= files.watch %>"], + }, + + uglify: { + options: { + banner: '/* Variadic.js - by William Bowers */\n' + }, + dist: { + files: { + "dist/<%= pkg.name %>.min.js": ["<%= concat.dist.dest %>"] + } + } + }, + + exec: { + "test": { + command: mochaCommand("dot") + }, + "test-verbose": { + command: mochaCommand("spec") + }, + "coverage": { + command: docsCommand([ + "jscoverage --no-highlight src src-cov", + "COVERAGE=1 " + mochaCommand("html-cov") + " > docs/coverage.html" + ]) + }, + "docco": { + command: docsCommand([ + "./node_modules/docco/bin/docco <%= concat.dist.dest %>", + 'echo "' + TAB_SIZE_CSS + '" >> docs/docco.css' + ]) + } + }, + + watch: { + build: { + files: "<%= files.watch %>", + tasks: "build" + }, + test: { + files: "<%= files.watch %>", + tasks: "test" + } + } + }); + + grunt.loadNpmTasks("grunt-contrib-concat"); + grunt.loadNpmTasks("grunt-contrib-jshint"); + grunt.loadNpmTasks("grunt-contrib-uglify"); + grunt.loadNpmTasks("grunt-contrib-watch"); + grunt.loadNpmTasks("grunt-exec"); + + grunt.registerTask("test", "exec:test"); + grunt.registerTask("test-verbose", "exec:test-verbose"); + + grunt.registerTask("docs:annotated-source", "exec:docco"); + grunt.registerTask("docs:coverage", "exec:coverage"); + grunt.registerTask("docs", ["build", "docs:annotated-source", "docs:coverage"]); + + grunt.registerTask("lint", "jshint"); + grunt.registerTask("min", "uglify"); + grunt.registerTask("build", ["lint", "concat", "min"]); + grunt.registerTask("default", "watch:build"); +}; diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..339ecce --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,7 @@ +Copyright (C) 2013 William Bowers + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f69aec5 --- /dev/null +++ b/README.md @@ -0,0 +1,465 @@ +# Variadic.js + +A JavaScript library for expressive variadic functions. + +## Why? + +Because JavaScript doesn't have function overloading. + +Dealing with the `arguments` object is weird, argument type checking is a pain, and "optional argument soup" is...soupy. Yeah, you can do all that yourself, but Variadic gives you a terse and expressive way of allowing your functions to cleanly process different arrangements and types of arguments. Variadic's job is to take positional arguments, name them, and stick them in an object so you can access them without using `typeof` or if statements to check whether the right arguments were passed in or whether they were given in one of probably several valid arrangements — Variadic does all of that for you. + +Variadic is completely transparent to users of your functions. All they need to know is what they already do: the set of valid ways they can pass arguments to your function. + +Variadic also gives you 'rest' args (as a real-life, honest-to-goodness JavaScript Array; I'm looking at you, Arguments) and default argument values for free. + +A side effect of Variadic (or is it?) is that using it produces self-documenting code. Function configuration code acts as an inline document that is very explicit about what types of arguments can be passed in and in what orders. + +## How do I use it? + +You use Variadic by calling `variadic` when creating a variadic function. `variadic` takes + +1. a configuration function so you can tell it about your parameters and forms, +2. the function you're wrapping (your meat-and-potatoes code; the code the brings home the bacon), and +3. an optional context object + +```javascript +var yourFunctionName = variadic(function(v) { + // 'v' is the configuration object for this function. +}, function (opt, rest, form) { // Don't worry about these just yet. + // Meat and potatoes. +}, context); +``` + +## Parameters and forms? Huh? + +Here are a few Variadic terms: + +**Variadic** *(big 'V')* + +A sweet library for expressive *variadic functions*. + +**variadic** *(little 'v')* + +A *variadic function* is ["a function of indefinite arity, i.e., one which accepts a variable number of arguments"][1]. + +**Parameter** + +A *name* and *descriptor*. In Variadic, *arguments* are what function callers pass in, and *parameters* are your configuration objects used to perform type checking and more on those arguments. For example: + +```javascript +v.array("authors"); +v.func("log", function(message) { console.log(message); }); +``` + +Each of these lines represents a parameter. The first one is named "authors" (`opt.authors` when you use it in your function — more on that later) and it uses the built-in `array` descriptor. The `array` descriptor simply contains a test function to check whether an argument is an array. + +The second parameter is named "log" and matches functions. This parameter has a default value that will be used if it is not passed in. + +**Descriptor** + +A descriptor is an argument *matcher*. A descriptor tells Variadic how to test arguments to see whether a certain *form* matches what's been passed in. For example: + +```javascript +v.func("timeout"); // uses the built-in descriptor for functions +v.add("person", { + cls: Person, // a custom descriptor for a Person class (defined elsewhere) + description: "a person", + defaultGenerator: function() { + return new Person("John Doe", NaN); + } +}); +``` + +**Form** + +A declaration of *parameter names* and their order. For example: + +```javascript +v.form("url", "query"); +``` + +This says the function has a form that takes two arguments, a "url" and a "query" (defined elsewhere). + +**Best match** + +When a variadic function is called, the *best match* is the form that most closely resembles the given arguments (every parameter of the form must match its argument, there is no partial form matching). Multiple forms can match, but only one will be used. The rules for matching are pretty simple: + +* If a form has more parameters than there are arguments, it doesn't match. +* If all of a form's *N* parameters match the first *N* arguments, it matches. +* The longest matching form is the *best match*. +* If two matching forms have the same length, the first one (in order of configuration) is the *best match*. + +## Built-in descriptors + +This section needs to be written. + +## Custom descriptors + +Custom descriptors can define one of the following three argument matching properties: + +```javascript +{ + type: "boolean", // will only match booleans (uses typeof) +``` + +or: + +```javascript +{ + cls: Person, // will only match Person instances (uses instanceof) +``` + +or: + +```javascript +{ + test: function(value) { + value === "awesome"; // will only match the string "bob" + }, +``` + +They share the rest of their interface: + +```javascript + description: "a something", // should be able to be used in the sentence "must be *a something*" + defaultValue: 123, // the value to use if this argument is not passed in + defaultGenerator: function() { + return new Something(); // creates a new default value for each function call (if required) + } +} +``` + +If a `defaultGenerator` is specified, `defaultValue` will be ignored. + +## What variadic passes to your functions + +Consider the following code: + +```javascript +var query = variadic(function(v) { + v.date("start") + .date("end") + .string("category", "all items"); + + v.form("category") // form 1: string + .form("end") // form 2: date + .form("category", "end") // form 3: string, date + .form("start", "end") // form 4: date, date + .form("category", "start", "end"); // form 5: string, date, date +}, function(opt, rest, form) { + // this is "your function" +}); +``` + +If you call + +```javascript +query("bell bottoms", new Date(1975, 0, 1), "blue", "denim") +``` + +what are the values of `opt`, `rest`, and `form` inside your function? + +Well, forms 1 (string) and 3 (string, date) both match the arguments, but form 3 is the best match because it's longer. That means the value of `form` is: + +```javascript +["category", "end"] // form +``` + +Because form 3 matched, our `opt` object will have two properties: + +```javascript +{ // opt + "category": "bell bottoms", + "end": new Date(1975, 0, 1) +} +``` + +And lastly, `rest` contains the unmatched arguments: + +```javascript +["blue", "denim"] // rest +``` + +You can use all of these values in your function (let's rename `rest` to `keywords` and ditch the `form` argument because we don't need it), like so: + +```javascript +}, function(opt, keywords) { + // this is "your function" + var dateLine = makeDateLine(opt.start, opt.end); + var keywordLine = (keywords.length > 0) ? (", matching: '" + keywords.join("', '") + "'") : ""; + + return "Showing " + opt.category + " in fashion" + dateLine + keywordLine; +}); + +function makeDateLine(start, end) { + if (start && end) { + return " between" + start + " and " + end; + } else if (end) { + return " before " + end; + } else { + return ""; + } +} +``` + +This returns *Showing bell bottoms in fashion before Wed Jan 01 1975 00:00:00, matching: 'blue', 'denim'*. + +## How argument matching works + +### A basic example + +Here's a very simple function that we've likely all written 100 times: + +```javascript +// Accepts the forms randomInt(max) and randomInt(min, max). +// You have a few choices as far as argument names go, because the +// arguments will be different depending on how you call the function. +// 'a' and 'b' are meaningless, 'maxOrMin' and 'minOrMax' are just weird, +// and 'min' and 'max' suck too because sometimes they are actually +// 'max' and neither (respectively). +var randomInt = function(min, max) { + if (typeof max === "undefined") { + max = min; + min = 0; + // wat... + } + + return Math.floor(Math.random() * (max - min) + min); +}; +``` + +rewritten using variadic: + +```javascript +var randomInt = variadic(function(v) { + v.number("min", 0) + .number("max"); + + v.form("max") // form 1: number + .form("min", "max"); // form 2: number, number +}, function(opt, rest, form) { + return Math.floor(Math.random() * (opt.max - opt.min) + opt.min); +}); + +randomInt(10); // matches form 1 +randomInt(4, 15); // matches form 2 +``` + +It's a little bit more code (not by much), but it removes *all* of the plumbing code and helps the actual logic of the function stand out. You only have to look at 1 line of code to know what the function does, not 5. + +### A less basic example + +Here's another simple function (thanks to Variadic) that accepts 4 different arguments in 5 different arrangements. + +```javascript +var filterPeople = variadic(function(v) { + v.array ("list") // the list to filter + .regExp("name", /./) // default: match anything + .number("minAge", 0) // default: can't be less than zero + .number("maxAge", 999); // default: unless you've been cryogenically frozen... + + v.form("list", "name") // form 1: array, regExp + .form("list", "minAge") // form 2: array, number + .form("list", "name", "minAge") // form 3: array, regExp, number + .form("list", "minAge", "maxAge") // form 4: array, number, number + .form("list", "name", "minAge", "maxAge"); // form 5: array, regExp, number, number +}, function(opt, rest, form) { + return opt.list.filter(function(person) { + return (opt.name.test(person.name)) && + (person.age >= opt.minAge) && + (person.age <= opt.maxAge); + }); +}); + +filterPeople(/\bjoe\b/); // matches form 1 +filterPeople(18); // matches form 2 +filterPeople(/\bjoe\b/, 18); // matches form 3 +filterPeople(18, 25); // matches form 4 +filterPeople(/\bjoe\b/, 18, 25); // matches form 5 +``` + +Using Variadic's optional (`?`) and "no lone" (`*`) flags, we can simplify that down to: + +```javascript +var filterPeople = variadic(function(v) { + v.array ("list") // the list to filter + .regExp("name", /./) // default: match anything + .number("minAge", 0) // default: can't be less than zero + .number("maxAge", 999); // default: unless you've been cryogenically frozen... + + v.form("*list", "?name", "?minAge", "?maxAge"); +}, function(opt, rest, form) { + return opt.list.filter(function(person) { + return (opt.name.test(person.name)) && + (person.age >= opt.minAge) && + (person.age <= opt.maxAge); + }); +}); +``` + +This tells variadic that `list` is required and it can't be alone, and `name`, `minAge`, and `maxAge` are all optional (but because `list` can't be alone, at least one of them must be supplied; this is what Variadic calls "lone prevention"). + +### Precedence + +If two or more forms match: + +1. the first form (in order of configuration) has higher precedence than the second, which has higher precendence than the third, and so on +2. the longest form has the highest precedence, even if it comes last + +For example: + +```javascript +var strings = variadic(function(v) { + v.string("s1"); + v.string("s2"); + v.string("s3"); + + v.form("s1"); // form 1: string + v.form("s1", "s2"); // form 2: string, string + v.form("s1", "s2", "s3"); // form 3: string, string, string +}, function(opt, rest, form) { + // ... +}); + +strings("one"); // matches form 1 +strings("one", "two"); // matches form 2 +strings("one", "two", "three"); // matches form 3 +``` + +### Swapped order + +Here's the common `bind` (or `proxy`) function rewritten using Variadic: + +```javascript +var bind = variadic(function(v) { + v.func("fn"); + v.type("context", "object", "an object"); // v.object excludes arrays + + v.form("fn", "context"); // form 1: function, object + v.form("context", "fn"); // form 2: object, function +}, function(opt, rest, form) { + return function() { + return opt.fn.apply(opt.context, arguments); + }; +}); + +// Go ahead, pass your args in either order +this.button.on("click", bind(this.onClick, this)); // matches form 1 +this.button.on("click", bind(this, this.onClick)); // matches form 2 +``` + +### Forms with the same signature + +A form's signature is the ordered set of descriptors it will apply to a set of arguments. If you have two forms with the same signature, the second form will never match. + +## Variadic in action + +Here's a function that works with 5 different argument types and 6 different arrangements of arguments with absolutely no code in the function body having to distinguish between them. + +```javascript +var ajax = variadic(function(v) { + v.string("type") + .string("url") + .object("data", null) + .func ("success", function() {}) + .func ("error", function() {}); + + v.form("type", "url", "?data", "?success", "?error"); +}, function(opt, rest, form) { + // Not a 'typeof' or if statement in sight! + // Also, don't use this ajax code in production. Or anywhere. Ever. + var xhr = new XMLHttpRequest(); + xhr.open(opt.type, opt.url, true); + xhr.onreadystatechange = function() { + // Ok there are some if statements here, but you know what I meant! + if (xhr.readyState == 4) { + if (xhr.status == 200) opt.success(xhr); + else opt.error(xhr); + } + }; + xhr.send(opt.data); + return xhr; +}); + +// Valid calls to the new ajax function: +ajax("get", "http://baconipsum.com/api/?type=meat-and-filler"); +ajax("get", "http://baconipsum.com/api/?type=meat-and-filler", onSuccess); +ajax("get", "http://baconipsum.com/api/?type=meat-and-filler", { get: "data" }); +ajax("get", "http://baconipsum.com/api/?type=meat-and-filler", { get: "data" }, onSuccess); +ajax("get", "http://baconipsum.com/api/?type=meat-and-filler", onSuccess, onError); +ajax("get", "http://baconipsum.com/api/?type=meat-and-filler", { get: "data" }, onSuccess, onError); +``` + +That's it [in a nutshell.][2] Check out `/examples/ajax/` to see this code in action. + +*Note: This function takes a lot of arguments and the rules about which arguments are optional when and in what order they go are pretty complicated. This particular example is __not__ necessarily an example of good design. It merely serves to show the power, expressiveness, and terseness of Variadic.* + +## Project layout + +* **common/** - Assets shared between examples, documentation, etc. +* **dist/** - The full (development) and minified (production) versions of Variadic.js +* **docs/** - Documentation. Read the setup guide below for instructions on how to generate the docs. +* **examples/** - Examples of Variadic in action. These are separate from the tests. +* **src/** - The code. +* **tests/** - Contains the unit tests (written using Mocha and Chai). +* **Gruntfile.js** - Grunt tasks (it's like a Makefile, but for the 21st century). +* **LICENSE.txt** - MIT license. Use this code freely. +* **package.json** - Meta information about the project. +* **README.md** - You're reading it. +* **TODO.md** - Stuff I want to get done. + +## Setup + +If you want to hack on Variadic.js, you first need to get the dev dependencies: + +```shell +$ npm install +``` + +Getting the dev dependencies is enough to generate the annotated source code. If you want to generate the html coverage documentation, you need [jscoverage][3] (here are some great [setup instructions][4]) and a global installation of Mocha. + +```shell +$ npm install -g mocha +``` + +**Generating the docs** + +You can generate all documentation at once by running `grunt docs`. See the *Grunt tasks* section for how to generate individual docs. + +## Available documentation + +* `/docs/variadic.html` - Annotated source code. +* `/docs/coverage.html` - Test coverage. + +To view these docs, run a quick webserver at the project root. Here are [a few ways you can do that][5]. + +## Other project web pages + +* `/tests/index.html` - Run the tests in your browser. +* `/examples/ajax/index.html` - The ajax example in this document, put to work. + +## Grunt tasks + +* `grunt` - Default task: `grunt watch:build` +* `grunt watch:build` - Watch the source and test files (and Gruntfile.js) for changes, and build the project on change. +* `grunt watch:test` - Watch the source and test files (and Gruntfile.js) for changes, and run the headless tests on change. +* `grunt test` - Run the headless tests with compact output. +* `grunt test-verbose` - Run the headless tests with verbose output. +* `grunt docs` - Generate all documentation. +* `grunt docs:annotated-source` - Generate the annotated source. +* `grunt docs:coverage` - Generate the code coverage documentation. +* `grunt lint` - Run lint on the project source code and tests. +* `grunt build` - Concat and minify the source. +* `grunt concat` - Concat the source. +* `grunt min` - Minify the concatenated source. + +## License + +MIT licensed. See `LICENSE.txt` for the full details. + + +[1]: http://en.wikipedia.org/wiki/Variadic_function +[2]: http://www.youtube.com/watch?v=jKMK3XGO27k#t=5.2s +[3]: http://siliconforks.com/jscoverage/ +[4]: http://www.seejohncode.com/2012/03/13/setting-up-mocha-jscoverage/ +[5]: https://gist.github.com/willurd/5720255 diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..fffbbda --- /dev/null +++ b/TODO.md @@ -0,0 +1,38 @@ +# TODO + +```javascript +var fn = function(a, b) { + // the function +}.variadic(function(v) { + // config +}); +``` + +* More tests + * v.form errors if passed no parameter names + * v.type + * v.test + * v.cls + * v.regExp + * v.date + * v.match + * Configuration function chaining + * Make sure undefined args not added to opt object + * Make sure "null" doesn't match on the "object" type (v.type) + * Does Variadic work with constructor functions and 'new'? +* Features + * `any` descriptor + * Add ranking system so the `any` descriptor is given less precedence than other descriptors + * Optional parameters in forms (possibly using "?name") + * Exploding array arguments + * Exploding object arguments + * Empty form (opt == null, rest contains all arguments) +* Get the docs all set up +* Examples (try taking some beastly functions from the wild and making them better with variadic) +* Performance tests +* After configuration, generate a documentation string for the function and set it to something like: + * fn.usage + * fn.documentation + * fn.doc + * fn.forms + * fn.help diff --git a/common/highlight/highlight.js b/common/highlight/highlight.js new file mode 100644 index 0000000..cab4867 --- /dev/null +++ b/common/highlight/highlight.js @@ -0,0 +1 @@ +var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(//gm,">")}function b(p){for(var o=p.firstChild;o;o=o.nextSibling){if(o.nodeName=="CODE"){return o}if(!(o.nodeType==3&&o.nodeValue.match(/\s+/))){break}}}function h(p,o){return Array.prototype.map.call(p.childNodes,function(q){if(q.nodeType==3){return o?q.nodeValue.replace(/\n/g,""):q.nodeValue}if(q.nodeName=="BR"){return"\n"}return h(q,o)}).join("")}function a(q){var p=(q.className+" "+q.parentNode.className).split(/\s+/);p=p.map(function(r){return r.replace(/^language-/,"")});for(var o=0;o"}while(x.length||v.length){var u=t().splice(0,1)[0];y+=l(w.substr(p,u.offset-p));p=u.offset;if(u.event=="start"){y+=s(u.node);r.push(u.node)}else{if(u.event=="stop"){var o,q=r.length;do{q--;o=r[q];y+=("")}while(o!=u.node);r.splice(q,1);while(q'+L[0]+""}else{r+=L[0]}N=A.lR.lastIndex;L=A.lR.exec(K)}return r+K.substr(N)}function z(){if(A.sL&&!e[A.sL]){return l(w)}var r=A.sL?d(A.sL,w):g(w);if(A.r>0){v+=r.keyword_count;B+=r.r}return''+r.value+""}function J(){return A.sL!==undefined?z():G()}function I(L,r){var K=L.cN?'':"";if(L.rB){x+=K;w=""}else{if(L.eB){x+=l(r)+K;w=""}else{x+=K;w=r}}A=Object.create(L,{parent:{value:A}});B+=L.r}function C(K,r){w+=K;if(r===undefined){x+=J();return 0}var L=o(r,A);if(L){x+=J();I(L,r);return L.rB?0:r.length}var M=s(A,r);if(M){if(!(M.rE||M.eE)){w+=r}x+=J();do{if(A.cN){x+=""}A=A.parent}while(A!=M.parent);if(M.eE){x+=l(r)}w="";if(M.starts){I(M.starts,"")}return M.rE?0:r.length}if(t(r,A)){throw"Illegal"}w+=r;return r.length||1}var F=e[D];f(F);var A=F;var w="";var B=0;var v=0;var x="";try{var u,q,p=0;while(true){A.t.lastIndex=p;u=A.t.exec(E);if(!u){break}q=C(E.substr(p,u.index-p),u[0]);p=u.index+q}C(E.substr(p));return{r:B,keyword_count:v,value:x,language:D}}catch(H){if(H=="Illegal"){return{r:0,keyword_count:0,value:l(E)}}else{throw H}}}function g(s){var o={keyword_count:0,r:0,value:l(s)};var q=o;for(var p in e){if(!e.hasOwnProperty(p)){continue}var r=d(p,s);r.language=p;if(r.keyword_count+r.r>q.keyword_count+q.r){q=r}if(r.keyword_count+r.r>o.keyword_count+o.r){q=o;o=r}}if(q.language){o.second_best=q}return o}function i(q,p,o){if(p){q=q.replace(/^((<[^>]+>|\t)+)/gm,function(r,v,u,t){return v.replace(/\t/g,p)})}if(o){q=q.replace(/\n/g,"
")}return q}function m(r,u,p){var v=h(r,p);var t=a(r);if(t=="no-highlight"){return}var w=t?d(t,v):g(v);t=w.language;var o=c(r);if(o.length){var q=document.createElement("pre");q.innerHTML=w.value;w.value=j(o,c(q),v)}w.value=i(w.value,u,p);var s=r.className;if(!s.match("(\\s|^)(language-)?"+t+"(\\s|$)")){s=s?(s+" "+t):t}r.innerHTML=w.value;r.className=s;r.result={language:t,kw:w.keyword_count,re:w.r};if(w.second_best){r.second_best={language:w.second_best.language,kw:w.second_best.keyword_count,re:w.second_best.r}}}function n(){if(n.called){return}n.called=true;Array.prototype.map.call(document.getElementsByTagName("pre"),b).filter(Boolean).forEach(function(o){m(o,hljs.tabReplace)})}function k(){window.addEventListener("DOMContentLoaded",n,false);window.addEventListener("load",n,false)}var e={};this.LANGUAGES=e;this.highlight=d;this.highlightAuto=g;this.fixMarkup=i;this.highlightBlock=m;this.initHighlighting=n;this.initHighlightingOnLoad=k;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE],r:0};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE],r:0};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.inherit=function(q,r){var o={};for(var p in q){o[p]=q[p]}if(r){for(var p in r){o[p]=r[p]}}return o}}();hljs.LANGUAGES.javascript=function(a){return{k:{keyword:"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const",literal:"true false null undefined NaN Infinity"},c:[a.ASM,a.QSM,a.CLCM,a.CBLCLM,a.CNM,{b:"("+a.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[a.CLCM,a.CBLCLM,{cN:"regexp",b:"/",e:"/[gim]*",i:"\\n",c:[{b:"\\\\/"}]},{b:"<",e:">;",sL:"xml"}],r:0},{cN:"function",bWK:true,e:"{",k:"function",c:[{cN:"title",b:"[A-Za-z$_][0-9A-Za-z$_]*"},{cN:"params",b:"\\(",e:"\\)",c:[a.CLCM,a.CBLCLM],i:"[\"'\\(]"}],i:"\\[|%"}]}}(hljs); \ No newline at end of file diff --git a/common/highlight/styles/arta.css b/common/highlight/styles/arta.css new file mode 100644 index 0000000..b7257da --- /dev/null +++ b/common/highlight/styles/arta.css @@ -0,0 +1,158 @@ +/* +Date: 17.V.2011 +Author: pumbur +*/ + +pre code +{ + display: block; padding: 0.5em; + background: #222; +} + +pre .profile .header *, +pre .ini .title, +pre .nginx .title +{ + color: #fff; +} + +pre .comment, +pre .javadoc, +pre .preprocessor, +pre .preprocessor .title, +pre .shebang, +pre .profile .summary, +pre .diff, +pre .pi, +pre .doctype, +pre .tag, +pre .template_comment, +pre .css .rules, +pre .tex .special +{ + color: #444; +} + +pre .string, +pre .symbol, +pre .diff .change, +pre .regexp, +pre .xml .attribute, +pre .smalltalk .char, +pre .xml .value, +pre .ini .value, +pre .clojure .attribute +{ + color: #ffcc33; +} + +pre .number, +pre .addition +{ + color: #00cc66; +} + +pre .built_in, +pre .literal, +pre .vhdl .typename, +pre .go .constant, +pre .go .typename, +pre .ini .keyword, +pre .lua .title, +pre .perl .variable, +pre .php .variable, +pre .mel .variable, +pre .django .variable, +pre .css .funtion, +pre .smalltalk .method, +pre .hexcolor, +pre .important, +pre .flow, +pre .inheritance, +pre .parser3 .variable +{ + color: #32AAEE; +} + +pre .keyword, +pre .tag .title, +pre .css .tag, +pre .css .class, +pre .css .id, +pre .css .pseudo, +pre .css .attr_selector, +pre .lisp .title, +pre .clojure .built_in, +pre .winutils, +pre .tex .command, +pre .request, +pre .status +{ + color: #6644aa; +} + +pre .title, +pre .ruby .constant, +pre .vala .constant, +pre .parent, +pre .deletion, +pre .template_tag, +pre .css .keyword, +pre .objectivec .class .id, +pre .smalltalk .class, +pre .lisp .keyword, +pre .apache .tag, +pre .nginx .variable, +pre .envvar, +pre .bash .variable, +pre .go .built_in, +pre .vbscript .built_in, +pre .lua .built_in, +pre .rsl .built_in, +pre .tail, +pre .avrasm .label, +pre .tex .formula, +pre .tex .formula * +{ + color: #bb1166; +} + +pre .yardoctag, +pre .phpdoc, +pre .profile .header, +pre .ini .title, +pre .apache .tag, +pre .parser3 .title +{ + font-weight: bold; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata +{ + opacity: 0.6; +} + +pre code, +pre .javascript, +pre .css, +pre .xml, +pre .subst, +pre .diff .chunk, +pre .css .value, +pre .css .attribute, +pre .lisp .string, +pre .lisp .number, +pre .tail .params, +pre .container, +pre .haskell *, +pre .erlang *, +pre .erlang_repl * +{ + color: #aaa; +} diff --git a/common/highlight/styles/ascetic.css b/common/highlight/styles/ascetic.css new file mode 100644 index 0000000..63349b7 --- /dev/null +++ b/common/highlight/styles/ascetic.css @@ -0,0 +1,50 @@ +/* + +Original style from softwaremaniacs.org (c) Ivan Sagalaev + +*/ + +pre code { + display: block; padding: 0.5em; + background: white; color: black; +} + +pre .string, +pre .tag .value, +pre .filter .argument, +pre .addition, +pre .change, +pre .apache .tag, +pre .apache .cbracket, +pre .nginx .built_in, +pre .tex .formula { + color: #888; +} + +pre .comment, +pre .template_comment, +pre .shebang, +pre .doctype, +pre .pi, +pre .javadoc, +pre .deletion, +pre .apache .sqbracket { + color: #CCC; +} + +pre .keyword, +pre .tag .title, +pre .ini .title, +pre .lisp .title, +pre .clojure .title, +pre .http .title, +pre .nginx .title, +pre .css .tag, +pre .winutils, +pre .flow, +pre .apache .tag, +pre .tex .command, +pre .request, +pre .status { + font-weight: bold; +} diff --git a/common/highlight/styles/brown_paper.css b/common/highlight/styles/brown_paper.css new file mode 100644 index 0000000..23476da --- /dev/null +++ b/common/highlight/styles/brown_paper.css @@ -0,0 +1,104 @@ +/* + +Brown Paper style from goldblog.com.ua (c) Zaripov Yura + +*/ + +pre code { + display: block; padding: 0.5em; + background:#b7a68e url(./brown_papersq.png); +} + +pre .keyword, +pre .literal, +pre .change, +pre .winutils, +pre .flow, +pre .lisp .title, +pre .clojure .built_in, +pre .nginx .title, +pre .tex .special, +pre .request, +pre .status { + color:#005599; + font-weight:bold; +} + +pre code, +pre .subst, +pre .tag .keyword { + color: #363C69; +} + +pre .string, +pre .title, +pre .haskell .type, +pre .tag .value, +pre .css .rules .value, +pre .preprocessor, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .ruby .class .parent, +pre .built_in, +pre .sql .aggregate, +pre .django .template_tag, +pre .django .variable, +pre .smalltalk .class, +pre .javadoc, +pre .ruby .string, +pre .django .filter .argument, +pre .smalltalk .localvars, +pre .smalltalk .array, +pre .attr_selector, +pre .pseudo, +pre .addition, +pre .stream, +pre .envvar, +pre .apache .tag, +pre .apache .cbracket, +pre .tex .number { + color: #2C009F; +} + +pre .comment, +pre .java .annotation, +pre .python .decorator, +pre .template_comment, +pre .pi, +pre .doctype, +pre .deletion, +pre .shebang, +pre .apache .sqbracket, +pre .nginx .built_in, +pre .tex .formula { + color: #802022; +} + +pre .keyword, +pre .literal, +pre .css .id, +pre .phpdoc, +pre .title, +pre .haskell .type, +pre .vbscript .built_in, +pre .sql .aggregate, +pre .rsl .built_in, +pre .smalltalk .class, +pre .diff .header, +pre .chunk, +pre .winutils, +pre .bash .variable, +pre .apache .tag, +pre .tex .command { + font-weight: bold; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.8; +} diff --git a/common/highlight/styles/brown_papersq.png b/common/highlight/styles/brown_papersq.png new file mode 100644 index 0000000000000000000000000000000000000000..3813903dbf9fa7b1fb5bd11d9534c06667d9056f GIT binary patch literal 18198 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
G3S-EN>9CM!{YB*|;6wg-K3V?)eR((z#1 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 literal 0 HcmV?d00001 diff --git a/common/highlight/styles/dark.css b/common/highlight/styles/dark.css new file mode 100644 index 0000000..102a389 --- /dev/null +++ b/common/highlight/styles/dark.css @@ -0,0 +1,103 @@ +/* + +Dark style from softwaremaniacs.org (c) Ivan Sagalaev + +*/ + +pre code { + display: block; padding: 0.5em; + background: #444; +} + +pre .keyword, +pre .literal, +pre .change, +pre .winutils, +pre .flow, +pre .lisp .title, +pre .clojure .built_in, +pre .nginx .title, +pre .tex .special { + color: white; +} + +pre code, +pre .subst { + color: #DDD; +} + +pre .string, +pre .title, +pre .haskell .type, +pre .ini .title, +pre .tag .value, +pre .css .rules .value, +pre .preprocessor, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .ruby .class .parent, +pre .built_in, +pre .sql .aggregate, +pre .django .template_tag, +pre .django .variable, +pre .smalltalk .class, +pre .javadoc, +pre .ruby .string, +pre .django .filter .argument, +pre .smalltalk .localvars, +pre .smalltalk .array, +pre .attr_selector, +pre .pseudo, +pre .addition, +pre .stream, +pre .envvar, +pre .apache .tag, +pre .apache .cbracket, +pre .tex .command, +pre .prompt { + color: #D88; +} + +pre .comment, +pre .java .annotation, +pre .python .decorator, +pre .template_comment, +pre .pi, +pre .doctype, +pre .deletion, +pre .shebang, +pre .apache .sqbracket, +pre .tex .formula { + color: #777; +} + +pre .keyword, +pre .literal, +pre .title, +pre .css .id, +pre .phpdoc, +pre .haskell .type, +pre .vbscript .built_in, +pre .sql .aggregate, +pre .rsl .built_in, +pre .smalltalk .class, +pre .diff .header, +pre .chunk, +pre .winutils, +pre .bash .variable, +pre .apache .tag, +pre .tex .special, +pre .request, +pre .status { + font-weight: bold; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/common/highlight/styles/default.css b/common/highlight/styles/default.css new file mode 100644 index 0000000..e417fc1 --- /dev/null +++ b/common/highlight/styles/default.css @@ -0,0 +1,135 @@ +/* + +Original style from softwaremaniacs.org (c) Ivan Sagalaev + +*/ + +pre code { + display: block; padding: 0.5em; + background: #F0F0F0; +} + +pre code, +pre .subst, +pre .tag .title, +pre .lisp .title, +pre .clojure .built_in, +pre .nginx .title { + color: black; +} + +pre .string, +pre .title, +pre .constant, +pre .parent, +pre .tag .value, +pre .rules .value, +pre .rules .value .number, +pre .preprocessor, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .aggregate, +pre .template_tag, +pre .django .variable, +pre .smalltalk .class, +pre .addition, +pre .flow, +pre .stream, +pre .bash .variable, +pre .apache .tag, +pre .apache .cbracket, +pre .tex .command, +pre .tex .special, +pre .erlang_repl .function_or_atom, +pre .markdown .header { + color: #800; +} + +pre .comment, +pre .annotation, +pre .template_comment, +pre .diff .header, +pre .chunk, +pre .markdown .blockquote { + color: #888; +} + +pre .number, +pre .date, +pre .regexp, +pre .literal, +pre .smalltalk .symbol, +pre .smalltalk .char, +pre .go .constant, +pre .change, +pre .markdown .bullet, +pre .markdown .link_url { + color: #080; +} + +pre .label, +pre .javadoc, +pre .ruby .string, +pre .decorator, +pre .filter .argument, +pre .localvars, +pre .array, +pre .attr_selector, +pre .important, +pre .pseudo, +pre .pi, +pre .doctype, +pre .deletion, +pre .envvar, +pre .shebang, +pre .apache .sqbracket, +pre .nginx .built_in, +pre .tex .formula, +pre .erlang_repl .reserved, +pre .prompt, +pre .markdown .link_label, +pre .vhdl .attribute, +pre .clojure .attribute, +pre .coffeescript .property { + color: #88F +} + +pre .keyword, +pre .id, +pre .phpdoc, +pre .title, +pre .built_in, +pre .aggregate, +pre .css .tag, +pre .javadoctag, +pre .phpdoc, +pre .yardoctag, +pre .smalltalk .class, +pre .winutils, +pre .bash .variable, +pre .apache .tag, +pre .go .typename, +pre .tex .command, +pre .markdown .strong, +pre .request, +pre .status { + font-weight: bold; +} + +pre .markdown .emphasis { + font-style: italic; +} + +pre .nginx .built_in { + font-weight: normal; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/common/highlight/styles/far.css b/common/highlight/styles/far.css new file mode 100644 index 0000000..54859ca --- /dev/null +++ b/common/highlight/styles/far.css @@ -0,0 +1,111 @@ +/* + +FAR Style (c) MajestiC + +*/ + +pre code { + display: block; padding: 0.5em; + background: #000080; +} + +pre code, +pre .subst { + color: #0FF; +} + +pre .string, +pre .ruby .string, +pre .haskell .type, +pre .tag .value, +pre .css .rules .value, +pre .css .rules .value .number, +pre .preprocessor, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .built_in, +pre .sql .aggregate, +pre .django .template_tag, +pre .django .variable, +pre .smalltalk .class, +pre .addition, +pre .apache .tag, +pre .apache .cbracket, +pre .tex .command, +pre .clojure .title { + color: #FF0; +} + +pre .keyword, +pre .css .id, +pre .title, +pre .haskell .type, +pre .vbscript .built_in, +pre .sql .aggregate, +pre .rsl .built_in, +pre .smalltalk .class, +pre .xml .tag .title, +pre .winutils, +pre .flow, +pre .change, +pre .envvar, +pre .bash .variable, +pre .tex .special, +pre .clojure .built_in { + color: #FFF; +} + +pre .comment, +pre .phpdoc, +pre .javadoc, +pre .java .annotation, +pre .template_comment, +pre .deletion, +pre .apache .sqbracket, +pre .tex .formula { + color: #888; +} + +pre .number, +pre .date, +pre .regexp, +pre .literal, +pre .smalltalk .symbol, +pre .smalltalk .char, +pre .clojure .attribute { + color: #0F0; +} + +pre .python .decorator, +pre .django .filter .argument, +pre .smalltalk .localvars, +pre .smalltalk .array, +pre .attr_selector, +pre .pseudo, +pre .xml .pi, +pre .diff .header, +pre .chunk, +pre .shebang, +pre .nginx .built_in, +pre .prompt { + color: #008080; +} + +pre .keyword, +pre .css .id, +pre .title, +pre .haskell .type, +pre .vbscript .built_in, +pre .sql .aggregate, +pre .rsl .built_in, +pre .smalltalk .class, +pre .winutils, +pre .flow, +pre .apache .tag, +pre .nginx .built_in, +pre .tex .command, +pre .tex .special, +pre .request, +pre .status { + font-weight: bold; +} diff --git a/common/highlight/styles/github.css b/common/highlight/styles/github.css new file mode 100644 index 0000000..89b02a6 --- /dev/null +++ b/common/highlight/styles/github.css @@ -0,0 +1,127 @@ +/* + +github.com style (c) Vasily Polovnyov + +*/ + +pre code { + display: block; padding: 0.5em; + color: #333; + background: #f8f8ff +} + +pre .comment, +pre .template_comment, +pre .diff .header, +pre .javadoc { + color: #998; + font-style: italic +} + +pre .keyword, +pre .css .rule .keyword, +pre .winutils, +pre .javascript .title, +pre .nginx .title, +pre .subst, +pre .request, +pre .status { + color: #333; + font-weight: bold +} + +pre .number, +pre .hexcolor, +pre .ruby .constant { + color: #099; +} + +pre .string, +pre .tag .value, +pre .phpdoc, +pre .tex .formula { + color: #d14 +} + +pre .title, +pre .id { + color: #900; + font-weight: bold +} + +pre .javascript .title, +pre .lisp .title, +pre .clojure .title, +pre .subst { + font-weight: normal +} + +pre .class .title, +pre .haskell .type, +pre .vhdl .literal, +pre .tex .command { + color: #458; + font-weight: bold +} + +pre .tag, +pre .tag .title, +pre .rules .property, +pre .django .tag .keyword { + color: #000080; + font-weight: normal +} + +pre .attribute, +pre .variable, +pre .lisp .body { + color: #008080 +} + +pre .regexp { + color: #009926 +} + +pre .class { + color: #458; + font-weight: bold +} + +pre .symbol, +pre .ruby .symbol .string, +pre .lisp .keyword, +pre .tex .special, +pre .prompt { + color: #990073 +} + +pre .built_in, +pre .lisp .title, +pre .clojure .built_in { + color: #0086b3 +} + +pre .preprocessor, +pre .pi, +pre .doctype, +pre .shebang, +pre .cdata { + color: #999; + font-weight: bold +} + +pre .deletion { + background: #fdd +} + +pre .addition { + background: #dfd +} + +pre .diff .change { + background: #0086b3 +} + +pre .chunk { + color: #aaa +} diff --git a/common/highlight/styles/googlecode.css b/common/highlight/styles/googlecode.css new file mode 100644 index 0000000..a7b7592 --- /dev/null +++ b/common/highlight/styles/googlecode.css @@ -0,0 +1,144 @@ +/* + +Google Code style (c) Aahan Krish + +*/ + +pre code { + display: block; padding: 0.5em; + background: white; color: black; +} + +pre .comment, +pre .template_comment, +pre .javadoc, +pre .comment * { + color: #800; +} + +pre .keyword, +pre .method, +pre .list .title, +pre .clojure .built_in, +pre .nginx .title, +pre .tag .title, +pre .setting .value, +pre .winutils, +pre .tex .command, +pre .http .title, +pre .request, +pre .status { + color: #008; +} + +pre .envvar, +pre .tex .special { + color: #660; +} + +pre .string, +pre .tag .value, +pre .cdata, +pre .filter .argument, +pre .attr_selector, +pre .apache .cbracket, +pre .date, +pre .regexp { + color: #080; +} + +pre .sub .identifier, +pre .pi, +pre .tag, +pre .tag .keyword, +pre .decorator, +pre .ini .title, +pre .shebang, +pre .prompt, +pre .hexcolor, +pre .rules .value, +pre .css .value .number, +pre .literal, +pre .symbol, +pre .ruby .symbol .string, +pre .number, +pre .css .function, +pre .clojure .attribute { + color: #066; +} + +pre .class .title, +pre .haskell .type, +pre .smalltalk .class, +pre .javadoctag, +pre .yardoctag, +pre .phpdoc, +pre .typename, +pre .tag .attribute, +pre .doctype, +pre .class .id, +pre .built_in, +pre .setting, +pre .params, +pre .variable, +pre .clojure .title { + color: #606; +} + +pre .css .tag, +pre .rules .property, +pre .pseudo, +pre .subst { + color: #000; +} + +pre .css .class, pre .css .id { + color: #9B703F; +} + +pre .value .important { + color: #ff7700; + font-weight: bold; +} + +pre .rules .keyword { + color: #C5AF75; +} + +pre .annotation, +pre .apache .sqbracket, +pre .nginx .built_in { + color: #9B859D; +} + +pre .preprocessor, +pre .preprocessor * { + color: #444; +} + +pre .tex .formula { + background-color: #EEE; + font-style: italic; +} + +pre .diff .header, +pre .chunk { + color: #808080; + font-weight: bold; +} + +pre .diff .change { + background-color: #BCCFF9; +} + +pre .addition { + background-color: #BAEEBA; +} + +pre .deletion { + background-color: #FFC8BD; +} + +pre .comment .yardoctag { + font-weight: bold; +} diff --git a/common/highlight/styles/idea.css b/common/highlight/styles/idea.css new file mode 100644 index 0000000..94515c2 --- /dev/null +++ b/common/highlight/styles/idea.css @@ -0,0 +1,121 @@ +/* + +Intellij Idea-like styling (c) Vasily Polovnyov + +*/ + +pre code { + display: block; padding: 0.5em; + color: #000; + background: #fff; +} + +pre .subst, +pre .title { + font-weight: normal; + color: #000; +} + +pre .comment, +pre .template_comment, +pre .javadoc, +pre .diff .header { + color: #808080; + font-style: italic; +} + +pre .annotation, +pre .decorator, +pre .preprocessor, +pre .doctype, +pre .pi, +pre .chunk, +pre .shebang, +pre .apache .cbracket, +pre .prompt, +pre .http .title { + color: #808000; +} + +pre .tag, +pre .pi { + background: #efefef; +} + +pre .tag .title, +pre .id, +pre .attr_selector, +pre .pseudo, +pre .literal, +pre .keyword, +pre .hexcolor, +pre .css .function, +pre .ini .title, +pre .css .class, +pre .list .title, +pre .clojure .title, +pre .nginx .title, +pre .tex .command, +pre .request, +pre .status { + font-weight: bold; + color: #000080; +} + +pre .attribute, +pre .rules .keyword, +pre .number, +pre .date, +pre .regexp, +pre .tex .special { + font-weight: bold; + color: #0000ff; +} + +pre .number, +pre .regexp { + font-weight: normal; +} + +pre .string, +pre .value, +pre .filter .argument, +pre .css .function .params, +pre .apache .tag { + color: #008000; + font-weight: bold; +} + +pre .symbol, +pre .ruby .symbol .string, +pre .char, +pre .tex .formula { + color: #000; + background: #d0eded; + font-style: italic; +} + +pre .phpdoc, +pre .yardoctag, +pre .javadoctag { + text-decoration: underline; +} + +pre .variable, +pre .envvar, +pre .apache .sqbracket, +pre .nginx .built_in { + color: #660e7a; +} + +pre .addition { + background: #baeeba; +} + +pre .deletion { + background: #ffc8bd; +} + +pre .diff .change { + background: #bccff9; +} diff --git a/common/highlight/styles/ir_black.css b/common/highlight/styles/ir_black.css new file mode 100644 index 0000000..c4c09b5 --- /dev/null +++ b/common/highlight/styles/ir_black.css @@ -0,0 +1,104 @@ +/* + IR_Black style (c) Vasily Mikhailitchenko +*/ + +pre code { + display: block; padding: 0.5em; + background: #000; color: #f8f8f8; +} + +pre .shebang, +pre .comment, +pre .template_comment, +pre .javadoc { + color: #7c7c7c; +} + +pre .keyword, +pre .tag, +pre .tex .command, +pre .request, +pre .status, +pre .clojure .attribute { + color: #96CBFE; +} + +pre .sub .keyword, +pre .method, +pre .list .title, +pre .nginx .title { + color: #FFFFB6; +} + +pre .string, +pre .tag .value, +pre .cdata, +pre .filter .argument, +pre .attr_selector, +pre .apache .cbracket, +pre .date { + color: #A8FF60; +} + +pre .subst { + color: #DAEFA3; +} + +pre .regexp { + color: #E9C062; +} + +pre .title, +pre .sub .identifier, +pre .pi, +pre .decorator, +pre .tex .special, +pre .haskell .type, +pre .constant, +pre .smalltalk .class, +pre .javadoctag, +pre .yardoctag, +pre .phpdoc, +pre .nginx .built_in { + color: #FFFFB6; +} + +pre .symbol, +pre .ruby .symbol .string, +pre .number, +pre .variable, +pre .vbscript, +pre .literal { + color: #C6C5FE; +} + +pre .css .tag { + color: #96CBFE; +} + +pre .css .rules .property, +pre .css .id { + color: #FFFFB6; +} + +pre .css .class { + color: #FFF; +} + +pre .hexcolor { + color: #C6C5FE; +} + +pre .number { + color:#FF73FD; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.7; +} diff --git a/common/highlight/styles/magula.css b/common/highlight/styles/magula.css new file mode 100644 index 0000000..8766344 --- /dev/null +++ b/common/highlight/styles/magula.css @@ -0,0 +1,121 @@ +/* +Description: Magula style for highligh.js +Author: Ruslan Keba +Website: http://rukeba.com/ +Version: 1.0 +Date: 2009-01-03 +Music: Aphex Twin / Xtal +*/ + +pre code { + display: block; padding: 0.5em; + background-color: #f4f4f4; +} + +pre code, +pre .subst, +pre .lisp .title, +pre .clojure .built_in { + color: black; +} + +pre .string, +pre .title, +pre .parent, +pre .tag .value, +pre .rules .value, +pre .rules .value .number, +pre .preprocessor, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .aggregate, +pre .template_tag, +pre .django .variable, +pre .smalltalk .class, +pre .addition, +pre .flow, +pre .stream, +pre .bash .variable, +pre .apache .cbracket { + color: #050; +} + +pre .comment, +pre .annotation, +pre .template_comment, +pre .diff .header, +pre .chunk { + color: #777; +} + +pre .number, +pre .date, +pre .regexp, +pre .literal, +pre .smalltalk .symbol, +pre .smalltalk .char, +pre .change, +pre .tex .special { + color: #800; +} + +pre .label, +pre .javadoc, +pre .ruby .string, +pre .decorator, +pre .filter .argument, +pre .localvars, +pre .array, +pre .attr_selector, +pre .pseudo, +pre .pi, +pre .doctype, +pre .deletion, +pre .envvar, +pre .shebang, +pre .apache .sqbracket, +pre .nginx .built_in, +pre .tex .formula, +pre .prompt, +pre .clojure .attribute { + color: #00e; +} + +pre .keyword, +pre .id, +pre .phpdoc, +pre .title, +pre .built_in, +pre .aggregate, +pre .smalltalk .class, +pre .winutils, +pre .bash .variable, +pre .apache .tag, +pre .xml .tag, +pre .tex .command, +pre .request, +pre .status { + font-weight: bold; + color: navy; +} + +pre .nginx .built_in { + font-weight: normal; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} + +/* --- */ +pre .apache .tag { + font-weight: bold; + color: blue; +} + diff --git a/common/highlight/styles/monokai.css b/common/highlight/styles/monokai.css new file mode 100644 index 0000000..79c4f6f --- /dev/null +++ b/common/highlight/styles/monokai.css @@ -0,0 +1,114 @@ +/* +Monokai style - ported by Luigi Maselli - http://grigio.org +*/ + +pre code { + display: block; padding: 0.5em; + background: #272822; +} + +pre .tag, +pre .tag .title, +pre .keyword, +pre .literal, +pre .change, +pre .winutils, +pre .flow, +pre .lisp .title, +pre .clojure .built_in, +pre .nginx .title, +pre .tex .special { + color: #F92672; +} + +pre code { + color: #DDD; +} + +pre code .constant { + color: #66D9EF; +} + +pre .class .title { + color: white; +} + +pre .attribute, +pre .symbol, +pre .symbol .string, +pre .value, +pre .regexp { + color: #BF79DB; +} + +pre .tag .value, +pre .string, +pre .subst, +pre .title, +pre .haskell .type, +pre .preprocessor, +pre .ruby .class .parent, +pre .built_in, +pre .sql .aggregate, +pre .django .template_tag, +pre .django .variable, +pre .smalltalk .class, +pre .javadoc, +pre .django .filter .argument, +pre .smalltalk .localvars, +pre .smalltalk .array, +pre .attr_selector, +pre .pseudo, +pre .addition, +pre .stream, +pre .envvar, +pre .apache .tag, +pre .apache .cbracket, +pre .tex .command, +pre .prompt { + color: #A6E22E; +} + +pre .comment, +pre .java .annotation, +pre .python .decorator, +pre .template_comment, +pre .pi, +pre .doctype, +pre .deletion, +pre .shebang, +pre .apache .sqbracket, +pre .tex .formula { + color: #75715E; +} + +pre .keyword, +pre .literal, +pre .css .id, +pre .phpdoc, +pre .title, +pre .haskell .type, +pre .vbscript .built_in, +pre .sql .aggregate, +pre .rsl .built_in, +pre .smalltalk .class, +pre .diff .header, +pre .chunk, +pre .winutils, +pre .bash .variable, +pre .apache .tag, +pre .tex .special, +pre .request, +pre .status { + font-weight: bold; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/common/highlight/styles/pojoaque.css b/common/highlight/styles/pojoaque.css new file mode 100644 index 0000000..b9d20c2 --- /dev/null +++ b/common/highlight/styles/pojoaque.css @@ -0,0 +1,104 @@ +/* + +Pojoaque Style by Jason Tate +http://web-cms-designs.com/ftopict-10-pojoaque-style-for-highlight-js-code-highlighter.html +Based on Solarized Style from http://ethanschoonover.com/solarized + +*/ + +pre code { + display: block; padding: 0.5em; + color: #DCCF8F; + background: url(./pojoaque.jpg) repeat scroll left top #181914; +} + +pre .comment, +pre .template_comment, +pre .diff .header, +pre .doctype, +pre .lisp .string, +pre .javadoc { + color: #586e75; + font-style: italic; +} + +pre .keyword, +pre .css .rule .keyword, +pre .winutils, +pre .javascript .title, +pre .method, +pre .addition, +pre .css .tag, +pre .clojure .title, +pre .nginx .title { + color: #B64926; +} + +pre .number, +pre .command, +pre .string, +pre .tag .value, +pre .phpdoc, +pre .tex .formula, +pre .regexp, +pre .hexcolor { + color: #468966; +} + +pre .title, +pre .localvars, +pre .function .title, +pre .chunk, +pre .decorator, +pre .built_in, +pre .lisp .title, +pre .clojure .built_in, +pre .identifier, +pre .id { + color: #FFB03B; +} + +pre .attribute, +pre .variable, +pre .lisp .body, +pre .smalltalk .number, +pre .constant, +pre .class .title, +pre .parent, +pre .haskell .type { + color: #b58900; +} + +pre .css .attribute { + color: #b89859; +} + +pre .css .number,pre .css .hexcolor{ + color: #DCCF8F; +} + +pre .css .class { + color: #d3a60c; +} + +pre .preprocessor, +pre .pi, +pre .shebang, +pre .symbol, +pre .symbol .string, +pre .diff .change, +pre .special, +pre .attr_selector, +pre .important, +pre .subst, +pre .cdata { + color: #cb4b16; +} + +pre .deletion { + color: #dc322f; +} + +pre .tex .formula { + background: #073642; +} diff --git a/common/highlight/styles/pojoaque.jpg b/common/highlight/styles/pojoaque.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9c07d4ab40b6d77e90ff69f0012bcd33b21d31c3 GIT binary patch literal 1186 zcmZXSe^8Tk9LK-kXFs3)f@f?)Cddzw3v4wdZyXQ;4x3=;Ja*N#%n9ik!UGmt9H3k0 zJST|5jOc(ID$FQt3C?jQZBws#kXolO1lg9Pba9BB=Q+UEBX!nY@6Uhl&+ofe$Q$y5 z@ci`~)&qzDP(lOiQ5p?p z(`j^e7!yUAVHk%K#^GQXn?s0=VLYCI$HRoe=xCuZ>A6A3@sxEP#XqNFpIb=0)KQ#Nss_tD17;m4@$JKL;LR|K|QF3f%!L5+s(9Ft8SQ zG|~pGpEGFW5Z|OA)-O@mNHy-g@7m8JTf?kl@vUKBGmw)Y*9sDRNr3PN!IKefWaydTe1D zjzpyzPnD3}hBNaS4aFX7=0&~I*Hu7#4au@qVBglH#-m;QFOx_`=j z{EqRY#Eh*yoWP^pa4H>8GH{rO?!_+xwL0(k4yL^D%^nBkJ*UI;Lx;ped8d|f*S_s@ z3~ilcRC(&NT#9Gn#UD;o^EYSMXDMf%XcUi3>;WXXD-QX3P9wMyP7eA&RS{)h5{??W3^Rq=goFJ>?lA~J- zdYe>!xvYLW*fPT0RK7wsJRg^?x#W1*GP9_f`6t>QD_X>0d!owyN>nO2?U5}|3?hX_UZYT@^>S!9eB~bZ9U`q;`U)@L670o1g z`Hd}h<_WRvUc|n*%v4Hbb-4tJD40iyF^q%g*&!6>hkYDvi-{Uc4yTM zzcthN4Z{ka!+F_KzYV#yWi;c^X^q6g`pD8cp?$Kl?hCz0s^a|mH%P!CF%*<6k^~i` zT5Mi-t5-frUcHkk^Qh}+N)Kz1&Bi95`oNc|quI>tUi~BY>xcF9(%tv2i{G6kE9*q~ qCoAGl20`)w0rdgp9H%Q=M5|p`hOhFz6$I%Y&ncY8>c?7PXyh+SL&XXJ literal 0 HcmV?d00001 diff --git a/common/highlight/styles/rainbow.css b/common/highlight/styles/rainbow.css new file mode 100644 index 0000000..e8e098f --- /dev/null +++ b/common/highlight/styles/rainbow.css @@ -0,0 +1,114 @@ +/* + +Style with support for rainbow parens + +*/ + +pre ::-moz-selection{ background: #FF5E99; color:#fff; text-shadow: none; } +pre ::selection { background:#FF5E99; color:#fff; text-shadow: none; } + +pre code { + display: block; padding: 0.5em; + background: #474949; color: #D1D9E1; +} + + +pre .body, +pre .collection { + color: #D1D9E1; +} + +pre .comment, +pre .template_comment, +pre .diff .header, +pre .doctype, +pre .lisp .string, +pre .javadoc { + color: #969896; + font-style: italic; +} + +pre .keyword, +pre .clojure .attribute, +pre .winutils, +pre .javascript .title, +pre .addition, +pre .css .tag { + color: #cc99cc; +} + +pre .number { color: #f99157; } + +pre .command, +pre .string, +pre .tag .value, +pre .phpdoc, +pre .tex .formula, +pre .regexp, +pre .hexcolor { + color: #8abeb7; +} + +pre .title, +pre .localvars, +pre .function .title, +pre .chunk, +pre .decorator, +pre .built_in, +pre .lisp .title, +pre .identifier +{ + color: #b5bd68; +} + +pre .class .keyword +{ + color: #f2777a; +} + +pre .variable, +pre .lisp .body, +pre .smalltalk .number, +pre .constant, +pre .class .title, +pre .parent, +pre .haskell .label, +pre .id, +pre .lisp .title, +pre .clojure .title .built_in { + color: #ffcc66; +} + +pre .tag .title, +pre .rules .property, +pre .django .tag .keyword, +pre .clojure .title .built_in { + font-weight: bold; +} + +pre .attribute, +pre .clojure .title { + color: #81a2be; +} + +pre .preprocessor, +pre .pi, +pre .shebang, +pre .symbol, +pre .symbol .string, +pre .diff .change, +pre .special, +pre .attr_selector, +pre .important, +pre .subst, +pre .cdata { + color: #f99157; +} + +pre .deletion { + color: #dc322f; +} + +pre .tex .formula { + background: #eee8d5; +} diff --git a/common/highlight/styles/school_book.css b/common/highlight/styles/school_book.css new file mode 100644 index 0000000..dd07ed2 --- /dev/null +++ b/common/highlight/styles/school_book.css @@ -0,0 +1,111 @@ +/* + +School Book style from goldblog.com.ua (c) Zaripov Yura + +*/ + +pre code { + display: block; padding: 15px 0.5em 0.5em 30px; + font-size: 11px !important; + line-height:16px !important; +} + +pre{ + background:#f6f6ae url(./school_book.png); + border-top: solid 2px #d2e8b9; + border-bottom: solid 1px #d2e8b9; +} + +pre .keyword, +pre .literal, +pre .change, +pre .winutils, +pre .flow, +pre .lisp .title, +pre .clojure .built_in, +pre .nginx .title, +pre .tex .special { + color:#005599; + font-weight:bold; +} + +pre code, +pre .subst, +pre .tag .keyword { + color: #3E5915; +} + +pre .string, +pre .title, +pre .haskell .type, +pre .tag .value, +pre .css .rules .value, +pre .preprocessor, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .ruby .class .parent, +pre .built_in, +pre .sql .aggregate, +pre .django .template_tag, +pre .django .variable, +pre .smalltalk .class, +pre .javadoc, +pre .ruby .string, +pre .django .filter .argument, +pre .smalltalk .localvars, +pre .smalltalk .array, +pre .attr_selector, +pre .pseudo, +pre .addition, +pre .stream, +pre .envvar, +pre .apache .tag, +pre .apache .cbracket, +pre .nginx .built_in, +pre .tex .command { + color: #2C009F; +} + +pre .comment, +pre .java .annotation, +pre .python .decorator, +pre .template_comment, +pre .pi, +pre .doctype, +pre .deletion, +pre .shebang, +pre .apache .sqbracket { + color: #E60415; +} + +pre .keyword, +pre .literal, +pre .css .id, +pre .phpdoc, +pre .title, +pre .haskell .type, +pre .vbscript .built_in, +pre .sql .aggregate, +pre .rsl .built_in, +pre .smalltalk .class, +pre .xml .tag .title, +pre .diff .header, +pre .chunk, +pre .winutils, +pre .bash .variable, +pre .apache .tag, +pre .tex .command, +pre .request, +pre .status { + font-weight: bold; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/common/highlight/styles/school_book.png b/common/highlight/styles/school_book.png new file mode 100644 index 0000000000000000000000000000000000000000..956e9790a0e2c079b3d568348ff3accd1d9cac30 GIT binary patch literal 486 zcmeAS@N?(olHy`uVBq!ia0y~yV7?7x3vjRjNjAS6Ga$v1?&#~tz_9*=IcwKTAYZb? zHKHUqKdq!Zu_%?nF(p4KRlzeiF+DXXH8G{K@MNkD0|R4)r;B4q#jQ7Ycl#YS5MfK$ z?b^fh#qmaEhFDxvyThwfhdfkOPApt1lr{NA;Vr%uzxJuVIyzm(ed_8_-0$LLU})H&o5Re&aDemE>EG#(|F^t9_pa-H z_Mf?rMVrs}-M?S|?ZdY@c6s41zy8~}@a{v&#Ea7V)wJ$+#K|u$5UvWCdFLwGac}6w{_s*=8A6L7Rfc|9gboFyt I=akR{0OLZ+qyPW_ literal 0 HcmV?d00001 diff --git a/common/highlight/styles/solarized_dark.css b/common/highlight/styles/solarized_dark.css new file mode 100644 index 0000000..8d3a238 --- /dev/null +++ b/common/highlight/styles/solarized_dark.css @@ -0,0 +1,88 @@ +/* + +Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull + +*/ + +pre code { + display: block; padding: 0.5em; + background: #002b36; color: #839496; +} + +pre .comment, +pre .template_comment, +pre .diff .header, +pre .doctype, +pre .pi, +pre .lisp .string, +pre .javadoc { + color: #586e75; + font-style: italic; +} + +pre .keyword, +pre .winutils, +pre .method, +pre .addition, +pre .css .tag, +pre .request, +pre .status, +pre .nginx .title { + color: #859900; +} + +pre .number, +pre .command, +pre .string, +pre .tag .value, +pre .phpdoc, +pre .tex .formula, +pre .regexp, +pre .hexcolor { + color: #2aa198; +} + +pre .title, +pre .localvars, +pre .chunk, +pre .decorator, +pre .built_in, +pre .identifier, +pre .vhdl .literal, +pre .id { + color: #268bd2; +} + +pre .attribute, +pre .variable, +pre .lisp .body, +pre .smalltalk .number, +pre .constant, +pre .class .title, +pre .parent, +pre .haskell .type { + color: #b58900; +} + +pre .preprocessor, +pre .preprocessor .keyword, +pre .shebang, +pre .symbol, +pre .symbol .string, +pre .diff .change, +pre .special, +pre .attr_selector, +pre .important, +pre .subst, +pre .cdata, +pre .clojure .title { + color: #cb4b16; +} + +pre .deletion { + color: #dc322f; +} + +pre .tex .formula { + background: #073642; +} diff --git a/common/highlight/styles/solarized_light.css b/common/highlight/styles/solarized_light.css new file mode 100644 index 0000000..a92ecac --- /dev/null +++ b/common/highlight/styles/solarized_light.css @@ -0,0 +1,88 @@ +/* + +Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull + +*/ + +pre code { + display: block; padding: 0.5em; + background: #fdf6e3; color: #657b83; +} + +pre .comment, +pre .template_comment, +pre .diff .header, +pre .doctype, +pre .pi, +pre .lisp .string, +pre .javadoc { + color: #93a1a1; + font-style: italic; +} + +pre .keyword, +pre .winutils, +pre .method, +pre .addition, +pre .css .tag, +pre .request, +pre .status, +pre .nginx .title { + color: #859900; +} + +pre .number, +pre .command, +pre .string, +pre .tag .value, +pre .phpdoc, +pre .tex .formula, +pre .regexp, +pre .hexcolor { + color: #2aa198; +} + +pre .title, +pre .localvars, +pre .chunk, +pre .decorator, +pre .built_in, +pre .identifier, +pre .vhdl .literal, +pre .id { + color: #268bd2; +} + +pre .attribute, +pre .variable, +pre .lisp .body, +pre .smalltalk .number, +pre .constant, +pre .class .title, +pre .parent, +pre .haskell .type { + color: #b58900; +} + +pre .preprocessor, +pre .preprocessor .keyword, +pre .shebang, +pre .symbol, +pre .symbol .string, +pre .diff .change, +pre .special, +pre .attr_selector, +pre .important, +pre .subst, +pre .cdata, +pre .clojure .title { + color: #cb4b16; +} + +pre .deletion { + color: #dc322f; +} + +pre .tex .formula { + background: #eee8d5; +} diff --git a/common/highlight/styles/sunburst.css b/common/highlight/styles/sunburst.css new file mode 100644 index 0000000..28c4ffc --- /dev/null +++ b/common/highlight/styles/sunburst.css @@ -0,0 +1,158 @@ +/* + +Sunburst-like style (c) Vasily Polovnyov + +*/ + +pre code { + display: block; padding: 0.5em; + background: #000; color: #f8f8f8; +} + +pre .comment, +pre .template_comment, +pre .javadoc { + color: #aeaeae; + font-style: italic; +} + +pre .keyword, +pre .ruby .function .keyword, +pre .request, +pre .status, +pre .nginx .title { + color: #E28964; +} + +pre .function .keyword, +pre .sub .keyword, +pre .method, +pre .list .title { + color: #99CF50; +} + +pre .string, +pre .tag .value, +pre .cdata, +pre .filter .argument, +pre .attr_selector, +pre .apache .cbracket, +pre .date, +pre .tex .command { + color: #65B042; +} + +pre .subst { + color: #DAEFA3; +} + +pre .regexp { + color: #E9C062; +} + +pre .title, +pre .sub .identifier, +pre .pi, +pre .tag, +pre .tag .keyword, +pre .decorator, +pre .shebang, +pre .prompt { + color: #89BDFF; +} + +pre .class .title, +pre .haskell .type, +pre .smalltalk .class, +pre .javadoctag, +pre .yardoctag, +pre .phpdoc { + text-decoration: underline; +} + +pre .symbol, +pre .ruby .symbol .string, +pre .number { + color: #3387CC; +} + +pre .params, +pre .variable, +pre .clojure .attribute { + color: #3E87E3; +} + +pre .css .tag, +pre .rules .property, +pre .pseudo, +pre .tex .special { + color: #CDA869; +} + +pre .css .class { + color: #9B703F; +} + +pre .rules .keyword { + color: #C5AF75; +} + +pre .rules .value { + color: #CF6A4C; +} + +pre .css .id { + color: #8B98AB; +} + +pre .annotation, +pre .apache .sqbracket, +pre .nginx .built_in { + color: #9B859D; +} + +pre .preprocessor { + color: #8996A8; +} + +pre .hexcolor, +pre .css .value .number { + color: #DD7B3B; +} + +pre .css .function { + color: #DAD085; +} + +pre .diff .header, +pre .chunk, +pre .tex .formula { + background-color: #0E2231; + color: #F8F8F8; + font-style: italic; +} + +pre .diff .change { + background-color: #4A410D; + color: #F8F8F8; +} + +pre .addition { + background-color: #253B22; + color: #F8F8F8; +} + +pre .deletion { + background-color: #420E09; + color: #F8F8F8; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/common/highlight/styles/tomorrow-night-blue.css b/common/highlight/styles/tomorrow-night-blue.css new file mode 100644 index 0000000..7d2700c --- /dev/null +++ b/common/highlight/styles/tomorrow-night-blue.css @@ -0,0 +1,52 @@ +/* Tomorrow Night Blue Theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +.tomorrow-comment, pre .comment, pre .title { + color: #7285b7; +} + +.tomorrow-red, pre .variable, pre .attribute, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo { + color: #ff9da4; +} + +.tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .literal, pre .params, pre .constant { + color: #ffc58f; +} + +.tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute { + color: #ffeead; +} + +.tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata { + color: #d1f1a9; +} + +.tomorrow-aqua, pre .css .hexcolor { + color: #99ffff; +} + +.tomorrow-blue, pre .function, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title { + color: #bbdaff; +} + +.tomorrow-purple, pre .keyword, pre .javascript .function { + color: #ebbbff; +} + +pre code { + display: block; + background: #002451; + color: white; + padding: 0.5em; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/common/highlight/styles/tomorrow-night-bright.css b/common/highlight/styles/tomorrow-night-bright.css new file mode 100644 index 0000000..6dd88e1 --- /dev/null +++ b/common/highlight/styles/tomorrow-night-bright.css @@ -0,0 +1,51 @@ +/* Tomorrow Night Bright Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +.tomorrow-comment, pre .comment, pre .title { + color: #969896; +} + +.tomorrow-red, pre .variable, pre .attribute, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo { + color: #d54e53; +} + +.tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .literal, pre .params, pre .constant { + color: #e78c45; +} + +.tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute { + color: #e7c547; +} + +.tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata { + color: #b9ca4a; +} + +.tomorrow-aqua, pre .css .hexcolor { + color: #70c0b1; +} + +.tomorrow-blue, pre .function, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title { + color: #7aa6da; +} + +.tomorrow-purple, pre .keyword, pre .javascript .function { + color: #c397d8; +} + +pre code { + display: block; + background: black; + color: #eaeaea; + padding: 0.5em; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/common/highlight/styles/tomorrow-night-eighties.css b/common/highlight/styles/tomorrow-night-eighties.css new file mode 100644 index 0000000..48011eb --- /dev/null +++ b/common/highlight/styles/tomorrow-night-eighties.css @@ -0,0 +1,51 @@ +/* Tomorrow Night Eighties Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +.tomorrow-comment, pre .comment, pre .title { + color: #999999; +} + +.tomorrow-red, pre .variable, pre .attribute, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo { + color: #f2777a; +} + +.tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .literal, pre .params, pre .constant { + color: #f99157; +} + +.tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute { + color: #ffcc66; +} + +.tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata { + color: #99cc99; +} + +.tomorrow-aqua, pre .css .hexcolor { + color: #66cccc; +} + +.tomorrow-blue, pre .function, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title { + color: #6699cc; +} + +.tomorrow-purple, pre .keyword, pre .javascript .function { + color: #cc99cc; +} + +pre code { + display: block; + background: #2d2d2d; + color: #cccccc; + padding: 0.5em; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/common/highlight/styles/tomorrow-night.css b/common/highlight/styles/tomorrow-night.css new file mode 100644 index 0000000..cf2c44d --- /dev/null +++ b/common/highlight/styles/tomorrow-night.css @@ -0,0 +1,52 @@ +/* Tomorrow Night Theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +.tomorrow-comment, pre .comment, pre .title { + color: #969896; +} + +.tomorrow-red, pre .variable, pre .attribute, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo { + color: #cc6666; +} + +.tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .literal, pre .params, pre .constant { + color: #de935f; +} + +.tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute { + color: #f0c674; +} + +.tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata { + color: #b5bd68; +} + +.tomorrow-aqua, pre .css .hexcolor { + color: #8abeb7; +} + +.tomorrow-blue, pre .function, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title { + color: #81a2be; +} + +.tomorrow-purple, pre .keyword, pre .javascript .function { + color: #b294bb; +} + +pre code { + display: block; + background: #1d1f21; + color: #c5c8c6; + padding: 0.5em; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/common/highlight/styles/tomorrow.css b/common/highlight/styles/tomorrow.css new file mode 100644 index 0000000..a2240f2 --- /dev/null +++ b/common/highlight/styles/tomorrow.css @@ -0,0 +1,49 @@ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +.tomorrow-comment, pre .comment, pre .title { + color: #8e908c; +} + +.tomorrow-red, pre .variable, pre .attribute, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo { + color: #c82829; +} + +.tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .literal, pre .params, pre .constant { + color: #f5871f; +} + +.tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute { + color: #eab700; +} + +.tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata { + color: #718c00; +} + +.tomorrow-aqua, pre .css .hexcolor { + color: #3e999f; +} + +.tomorrow-blue, pre .function, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title { + color: #4271ae; +} + +.tomorrow-purple, pre .keyword, pre .javascript .function { + color: #8959a8; +} + +pre code { + display: block; + background: white; + color: #4d4d4c; + padding: 0.5em; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} diff --git a/common/highlight/styles/vs.css b/common/highlight/styles/vs.css new file mode 100644 index 0000000..503d698 --- /dev/null +++ b/common/highlight/styles/vs.css @@ -0,0 +1,86 @@ +/* + +Visual Studio-like style based on original C# coloring by Jason Diamond + +*/ +pre code { + display: block; padding: 0.5em; +} + +pre .comment, +pre .annotation, +pre .template_comment, +pre .diff .header, +pre .chunk, +pre .apache .cbracket { + color: rgb(0, 128, 0); +} + +pre .keyword, +pre .id, +pre .built_in, +pre .smalltalk .class, +pre .winutils, +pre .bash .variable, +pre .tex .command, +pre .request, +pre .status, +pre .nginx .title, +pre .xml .tag, +pre .xml .tag .value { + color: rgb(0, 0, 255); +} + +pre .string, +pre .title, +pre .parent, +pre .tag .value, +pre .rules .value, +pre .rules .value .number, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .aggregate, +pre .template_tag, +pre .django .variable, +pre .addition, +pre .flow, +pre .stream, +pre .apache .tag, +pre .date, +pre .tex .formula { + color: rgb(163, 21, 21); +} + +pre .ruby .string, +pre .decorator, +pre .filter .argument, +pre .localvars, +pre .array, +pre .attr_selector, +pre .pseudo, +pre .pi, +pre .doctype, +pre .deletion, +pre .envvar, +pre .shebang, +pre .preprocessor, +pre .userType, +pre .apache .sqbracket, +pre .nginx .built_in, +pre .tex .special, +pre .prompt { + color: rgb(43, 145, 175); +} + +pre .phpdoc, +pre .javadoc, +pre .xmlDocTag { + color: rgb(128, 128, 128); +} + +pre .vhdl .typename { font-weight: bold; } +pre .vhdl .string { color: #666666; } +pre .vhdl .literal { color: rgb(163, 21, 21); } +pre .vhdl .attribute { color: #00B0E8; } + +pre .xml .attribute { color: rgb(255, 0, 0); } diff --git a/common/highlight/styles/xcode.css b/common/highlight/styles/xcode.css new file mode 100644 index 0000000..04f7bf9 --- /dev/null +++ b/common/highlight/styles/xcode.css @@ -0,0 +1,154 @@ +/* + +XCode style (c) Angel Garcia + +*/ + +pre code { + display: block; padding: 0.5em; + background: #fff; color: black; +} + +pre .comment, +pre .template_comment, +pre .javadoc, +pre .comment * { + color: rgb(0,106,0); +} + +pre .keyword, +pre .literal, +pre .nginx .title { + color: rgb(170,13,145); +} +pre .method, +pre .list .title, +pre .tag .title, +pre .setting .value, +pre .winutils, +pre .tex .command, +pre .http .title, +pre .request, +pre .status { + color: #008; +} + +pre .envvar, +pre .tex .special { + color: #660; +} + +pre .string { + color: rgb(196,26,22); +} +pre .tag .value, +pre .cdata, +pre .filter .argument, +pre .attr_selector, +pre .apache .cbracket, +pre .date, +pre .regexp { + color: #080; +} + +pre .sub .identifier, +pre .pi, +pre .tag, +pre .tag .keyword, +pre .decorator, +pre .ini .title, +pre .shebang, +pre .prompt, +pre .hexcolor, +pre .rules .value, +pre .css .value .number, +pre .symbol, +pre .symbol .string, +pre .number, +pre .css .function, +pre .clojure .title, +pre .clojure .built_in { + color: rgb(28,0,207); +} + +pre .class .title, +pre .haskell .type, +pre .smalltalk .class, +pre .javadoctag, +pre .yardoctag, +pre .phpdoc, +pre .typename, +pre .tag .attribute, +pre .doctype, +pre .class .id, +pre .built_in, +pre .setting, +pre .params, +pre .clojure .attribute { + color: rgb(92,38,153); +} + +pre .variable { + color: rgb(63,110,116); +} +pre .css .tag, +pre .rules .property, +pre .pseudo, +pre .subst { + color: #000; +} + +pre .css .class, pre .css .id { + color: #9B703F; +} + +pre .value .important { + color: #ff7700; + font-weight: bold; +} + +pre .rules .keyword { + color: #C5AF75; +} + +pre .annotation, +pre .apache .sqbracket, +pre .nginx .built_in { + color: #9B859D; +} + +pre .preprocessor, +pre .preprocessor * { + color: rgb(100,56,32); +} + +pre .tex .formula { + background-color: #EEE; + font-style: italic; +} + +pre .diff .header, +pre .chunk { + color: #808080; + font-weight: bold; +} + +pre .diff .change { + background-color: #BCCFF9; +} + +pre .addition { + background-color: #BAEEBA; +} + +pre .deletion { + background-color: #FFC8BD; +} + +pre .comment .yardoctag { + font-weight: bold; +} + +pre .method .id { + color: #000; +} diff --git a/common/highlight/styles/zenburn.css b/common/highlight/styles/zenburn.css new file mode 100644 index 0000000..501d6c7 --- /dev/null +++ b/common/highlight/styles/zenburn.css @@ -0,0 +1,115 @@ +/* + +Zenburn style from voldmar.ru (c) Vladimir Epifanov +based on dark.css by Ivan Sagalaev + +*/ + +pre code { + display: block; padding: 0.5em; + background: #3F3F3F; + color: #DCDCDC; +} + +pre .keyword, +pre .tag, +pre .css .class, +pre .css .id, +pre .lisp .title, +pre .nginx .title, +pre .request, +pre .status, +pre .clojure .attribute { + color: #E3CEAB; +} + +pre .django .template_tag, +pre .django .variable, +pre .django .filter .argument { + color: #DCDCDC; +} + +pre .number, +pre .date { + color: #8CD0D3; +} + +pre .dos .envvar, +pre .dos .stream, +pre .variable, +pre .apache .sqbracket { + color: #EFDCBC; +} + +pre .dos .flow, +pre .diff .change, +pre .python .exception, +pre .python .built_in, +pre .literal, +pre .tex .special { + color: #EFEFAF; +} + +pre .diff .chunk, +pre .subst { + color: #8F8F8F; +} + +pre .dos .keyword, +pre .python .decorator, +pre .title, +pre .haskell .type, +pre .diff .header, +pre .ruby .class .parent, +pre .apache .tag, +pre .nginx .built_in, +pre .tex .command, +pre .prompt { + color: #efef8f; +} + +pre .dos .winutils, +pre .ruby .symbol, +pre .ruby .symbol .string, +pre .ruby .string { + color: #DCA3A3; +} + +pre .diff .deletion, +pre .string, +pre .tag .value, +pre .preprocessor, +pre .built_in, +pre .sql .aggregate, +pre .javadoc, +pre .smalltalk .class, +pre .smalltalk .localvars, +pre .smalltalk .array, +pre .css .rules .value, +pre .attr_selector, +pre .pseudo, +pre .apache .cbracket, +pre .tex .formula { + color: #CC9393; +} + +pre .shebang, +pre .diff .addition, +pre .comment, +pre .java .annotation, +pre .template_comment, +pre .pi, +pre .doctype { + color: #7F9F7F; +} + +pre .coffeescript .javascript, +pre .javascript .xml, +pre .tex .formula, +pre .xml .javascript, +pre .xml .vbscript, +pre .xml .css, +pre .xml .cdata { + opacity: 0.5; +} + diff --git a/common/vanilla.unreset.css b/common/vanilla.unreset.css new file mode 100644 index 0000000..9619905 --- /dev/null +++ b/common/vanilla.unreset.css @@ -0,0 +1,138 @@ +/** + * Start Vanilla CSS 1.0.2 + */ +body { + font: 9pt/1.5em sans-serif; +} +pre, code, tt { + font: 1em/1.5em 'Andale Mono', 'Lucida Console', monospace; +} +h1, h2, h3, h4, h5, h6, b, strong { + font-weight: bold; +} +em, i, dfn { + font-style: italic; +} +dfn { + font-weight:bold; +} +p, code, pre, kbd { + margin:0 0 1.5em 0; +} +blockquote { + margin:0 1.5em 1.5em 1.5em; +} +cite { + font-style: italic; +} +li ul, li ol { + margin:0 1.5em; +} +ul, ol { + margin:0 1.5em 1.5em 1.5em; +} +ul { + list-style-type:disc; +} +ol { + list-style-type:decimal; +} +ol ol { + list-style: upper-alpha; +} +ol ol ol { + list-style: lower-roman; +} +ol ol ol ol { + list-style: lower-alpha; +} +dl { + margin:0 0 1.5em 0; +} +dl dt { + font-weight:bold; +} +dd { + margin-left:1.5em; +} +table { + margin-bottom:1.4em; + width:100%; +} +th { + font-weight:bold; +} +th, td, caption { + padding:4px 10px 4px 5px; +} +tfoot { + font-style:italic; +} +sup, sub { + line-height:0; +} +abbr, acronym { + border-bottom: 1px dotted; +} +address { + margin:0 0 1.5em; + font-style:italic; +} +del { + text-decoration: line-through; +} +pre { + margin:1.5em 0; + white-space:pre; +} +img.centered, .aligncenter, div.aligncenter { + display: block; + margin-left: auto; + margin-right: auto; +} +img.alignright { + display: inline; +} +img.alignleft { + display: inline; +} +.alignright { + float: right; + margin-left: 10px; +} +.alignleft { + float: left; + margin-right: 10px; +} +img { + max-width: 100%; +} +* html .clearfix { + height: 1%; +} +* + html .clearfix { + display: inline-block; +} +.clearfix:after { + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; +} +* html .group { + height: 1%; +} +* + html .group { + display: inline-block; +} +.group:after { + content: "."; + display: block; + height: 0; + clear: both; + visibility: hidden; +} +/** +* End Vanilla CSS +*/ diff --git a/dist/variadic.js b/dist/variadic.js new file mode 100644 index 0000000..3bfa9a6 --- /dev/null +++ b/dist/variadic.js @@ -0,0 +1,598 @@ +(function() { + +// Helpers +// ------- + +// These are some utility functions variadic uses internally. +var noop = function() {}; + +var toString = Object.prototype.toString; +var slice = Array.prototype.slice; + +var isArray = Array.isArray || function(value) { + return toString.call(value) === "[object Array]"; +}; + +var isFunction = function(value) { + return typeof value === "function"; +}; + +var isString = function(value) { + return typeof value === "string"; +}; + +var isObject = function(value) { + return value && typeof value === "object" && + !isFunction(value) && !isArray(value); +}; + +var isBoolean = function(value) { + return typeof value === "boolean"; +}; + +var isNumber = function(value) { + return typeof value === "number"; +}; + +var isRegExp = function(value) { + return value instanceof RegExp; +}; + +var isNull = function(value) { + return !value && isObject(value); +}; + +var isUndefined = function(value) { + return typeof value === "undefined"; +}; + +var isDefined = function(value) { + return typeof value !== "undefined"; +}; + +var toArray = function(obj, from) { + return slice.call(obj, from || 0); +}; + +var format = function(format) { + var args = toArray(arguments, 1); + + return (args.length === 0 ? + format : + format.replace(/\{(\d+)\}/g, function(match, index) { + return args[index]; + })); +}; + +// Entry point +// ----------- + +// Call this function to configure and return a new variadic function. +function variadic(configFn, fn, context) { + var config = new Config(); + configFn(config); + + // The caller just configured variadic. Let's let them know early on if + // they've made a mistake. + config.validate(); + + // This wrapper function is what's actually returned by variadic (it's + // what callers will think of as "their" function). Its responsibility is + // to forward arguments to the config object for processing. + return function() { + return config.process(toArray(arguments), fn, context || this); + }; +} + +// Error reporting +// --------------- + +// You can override variadic's error handling by setting `variadic.error` to +// your own function. +variadic.error = function(message) { + log.error(message); +}; + +// Variadic Configuration +// ---------------------- + +variadic.config = { + optionalArgumentRegex: /^\?/ +}; + +// Function Configuration +// ---------------------- + +var exactMatch = {}; // a token for telling if a form is an exact match + +// A new instance of this object is passed into configuration functions, like so: +// +// ```javascript +// variadic(function(v) { +// // v is an instance of Config ('v' for 'variadic'). Use it to add parameters and forms. +// }, function() { +// ... +// }); +// ``` +function Config() { + this._parameterNames = []; + this._descriptors = {}; + this._forms = []; + this._formMap = {}; +} + +Config.fn = Config.prototype; + +// TODO: Make sure all of the forms are valid (no duplicates, all args have +// descriptors, etc). +Config.fn.validate = function() { +}; + +Config.fn.process = function(args, fn, context) { + var form = this.getBestMatch(args); + + if (!form) { + variadic.error(format("Arguments '{0}' do not match any specified form", args.join(", "))); + return; + } + + var result = this.processArguments(form, args); + + return fn.call(context, result.opt, result.rest, (form.names || []).slice(), args); +}; + +// Get the form that is the best match for the given arguments. This +// is necessary because multiple forms can match. Only after we have +// the best match will we actually process the arguments and pass them +// along to the user function. +Config.fn.getBestMatch = function(args) { + var bestMatch; + var bestRating; + var forms = this._forms; + + for (var i = 0, len = forms.length; i < len; i++) { + var form = forms[i]; + + if (form.nonEmpty) { + if (args.length === 0) { + return false; + } + + continue; + } + + var a = this.rateForm(form, args); + + if (a === exactMatch) { + // This is an exact match for the arguments. Nothing can + // beat this form so we might as well exit early. + return form; + } + + var b = bestMatch ? bestRating : -1; + + if (a != -1 && a > b) { + bestMatch = form; + bestRating = a; + } + } + + return bestMatch; +}; + +/** + * -1 == no match + * 1 point for each matching parameter that isn't an 'any' parameter + */ +Config.fn.rateForm = function(form, args) { + if (args.length === 0) { + if (form.empty) { + return exactMatch; + } else { + return -1; + } + } + + if (form.empty) { + return -1; + } if (form.any) { + // 0 is the lowest possible match rating. + return 0; + } + + var names = form.names; + + // `v.form("one", "two", "?three", "four", "?five")` is the same as: + // + // ```javascript + // v.form("one", "two", four") + // v.form("one", "two", four", "five") + // v.form("one", "two", "three", "four") + // v.form("one", "two", "three", "four", "five") + // ``` + + var rating = -1; + + if (args) { + for (var i = 0; i < names.length; i++) { + var arg = args[i]; + var name = names[i].replace(variadic.config.optionalArgumentRegex, ""); + var optional = names[i].match(variadic.config.optionalArgumentRegex); + var desc = this._descriptors[name]; + + if (!desc) { + variadic.error(format("Unknown parameter: {0}", name)); + return -1; + } + + if (!this.checkArg(name, desc, arg)) { + if (!optional) { + return -1; + } + } else if (!desc.any) { + rating++; + } + } + } else { + variadic.error(format("Unknown form: {0}", form)); + } + + return rating; +}; + +Config.fn.processArguments = function(form, args) { + var result = { + opt: {}, + rest: args.slice((form.names || []).length) + }; + + for (var prop in this._descriptors) { + var defaultValue = this.getDefaultValue(this._descriptors[prop]); + + if (isDefined(defaultValue)) { + result.opt[prop] = defaultValue; + } + } + + if (!form.empty) { + for (var i = 0, name; name = form.names[i]; i++) { + result.opt[name] = args[i]; + } + } + + return result; +}; + +Config.fn.getDefaultValue = function(descriptor) { + if (isFunction(descriptor.defaultGenerator)) { + return descriptor.defaultGenerator(); + } else { + return descriptor.defaultValue; + } +}; + +Config.fn.checkArg = function(name, descriptor, value) { + if (descriptor.any) { + return true; + } else if ("type" in descriptor) { + if (value !== null && typeof value === descriptor.type) { + return true; + } + } else if ("cls" in descriptor) { + if (value instanceof descriptor.cls) { + return true; + } + } else if ("test" in descriptor) { + if (descriptor.test(value)) { + return true; + } + } else { + var str = "Invalid descriptor '{0}'. Must contain a type, cls, or test property for matching arguments"; + var message = format(str, name); + variadic.error(message); + return false; + } + + return false; +}; + +Config.fn.forms = function() { + this.form.apply(this, this._parameterNames.map(function(name) { + return "?" + name; + })); +}; + +Config.fn._removeForms = function(testFn) { + var forms = this._forms; + + for (var i = forms.length - 1; i >= 0; i--) { + if (testFn(forms[i])) { + forms.splice(i, 1); + } + } + + return this; +}; + +// Adds a new form to the variadic function. Forms are just arrays of +// parameter names (parameters are specified using `.add` or one of the +// built in parameter functions like `.object`, `.array`, etc). +Config.fn.form = function(/* names */) { + var names = toArray(arguments); + var mapKey = names.join(","); + + // Don't add empty forms and don't add the same form twice. + if (this._formMap.hasOwnProperty(mapKey)) { + return this; + } + + if (names.length === 0) { + return this.empty(); + } + + // Provide an easy way to know that this form has already been added. + this._formMap[mapKey] = true; + + // Add this form. + this._forms.push({ + positional: true, + names: names.map(function(name) { + return name.replace(variadic.config.optionalArgumentRegex, ""); + }) + }); + + // Recursively add more forms if there are optional parameters. Add + // the "sub" forms backwards because we want the optional parameters + // that show up first to match first. + for (var i = names.length - 1; i >= 0; i--) { + if (names[i].match(variadic.config.optionalArgumentRegex)) { + this.form.apply(this, names.slice(0, i).concat(names.slice(i + 1))); + } + } + + return this; +}; + +// Will only match when given no arguments. When this matches it is the +// only possible match, and it's the only way to build a function that +// can accept no arguments. +Config.fn.empty = function() { + var mapKey = "*empty"; + + if (this._formMap.hasOwnProperty(mapKey)) { + return this; + } + + this._removeForms(function(form) { + return form.nonEmpty || form.empty; + }); + + this._forms.push({ + empty: true + }); + + this._formMap[mapKey] = true; + + return this; +}; + +// Will not match when given no arguments. +Config.fn.nonEmpty = function() { + var mapKey = "*nonEmpty"; + + if (this._formMap.hasOwnProperty(mapKey)) { + return this; + } + + this._removeForms(function(form) { + return form.empty; + }); + + this._forms.push({ + nonEmpty: true + }); + + this._formMap[mapKey] = true; + + return this; +}; + +// Will match any set of arguments. All arguments will be put into the +// rest array and opt will be null. This will have the lowest match rating. +Config.fn.anyForm = function() { + this._forms.push({ + any: true + }); + + return this; +}; + +Config.fn.add = function(name, descriptor) { + this._descriptors[name] = descriptor; + this._parameterNames.push(name); + return this; +}; + +// The `any` descriptor. Matches any value, but has less weight than +// more specific matching descriptors. +Config.fn.any = function(name, defaultValue) { + return this.add(name, { + any: true, + description: "any value", + defaultValue: defaultValue + }); +}; + +Config.fn.type = function(name, type, description, defaultValue) { + return this.add(name, { + type: type, + description: description, + defaultValue: defaultValue + }); +}; + +Config.fn.test = function(name, testFn, description, defaultValue) { + return this.add(name, { + test: testFn, + description: description, + defaultValue: defaultValue + }); +}; + +Config.fn.cls = function(name, cls, description, defaultValue) { + return this.add(name, { + cls: cls, + description: description, + defaultValue: defaultValue + }); +}; + +Config.fn.object = function(name, defaultValue) { + return this.add(name, { + test: isObject, + description: "an object", + defaultValue: defaultValue + }); +}; + +Config.fn.array = function(name, defaultValue) { + return this.add(name, { + test: isArray, + description: "an array", + defaultValue: defaultValue + }); +}; + +Config.fn.func = function(name, defaultValue) { + return this.add(name, { + type: "function", + description: "a function", + defaultValue: defaultValue + }); +}; + +Config.fn.string = function(name, defaultValue) { + return this.add(name, { + type: "string", + description: "a string", + defaultValue: defaultValue + }); +}; + +Config.fn.number = function(name, defaultValue) { + return this.add(name, { + type: "number", + description: "a number", + defaultValue: defaultValue + }); +}; + +Config.fn.boolean = function(name, defaultValue) { + return this.add(name, { + type: "boolean", + description: "a boolean", + defaultValue: defaultValue + }); +}; + +Config.fn.regExp = function(name, defaultValue) { + return this.add(name, { + test: isRegExp, + description: "a regular expression", + defaultValue: defaultValue + }); +}; + +Config.fn.date = function(name, defaultValue) { + return this.add(name, { + cls: Date, + description: "a date", + defaultValue: defaultValue + }); +}; + +Config.fn.match = function(name, regExp, description, defaultValue) { + return this.add(name, { + test: function(value) { + return regExp.test(value); + }, + description: description, + defaultValue: defaultValue + }); +}; + +// Debug +// ----- + +variadic.silent = true; + +variadic.debug = function() { + function formatMessage(level, method, formatString, args) { + return (level ? level + " " : "") + // level + "[variadic" + (method ? ("." + method) : "") + "] " + // category + format.apply(null, [formatString].concat(args)); // message + } + + function logFunction(name) { + var level = name.toUpperCase(); + + return function(method, format) { + var rest = toArray(arguments, 2); + return console[name](formatMessage(level, method, format, rest)); + }; + } + + function errorFunction(name) { + var level = name.toUpperCase(); + + return function(format) { + var rest = toArray(arguments, 2); + + if (variadic.silent) { + return console[name](formatMessage(level, null, format, rest)); + } else { + throw new Error(formatMessage(null, null, format, rest)); + } + }; + } + + function logRedirect(name) { + return function() { + console[name].apply(console, arguments); + }; + } + + log = { + debug: logFunction("debug"), + info: logFunction("info"), + warn: logFunction("warn"), + error: errorFunction("error"), + dir: logRedirect("dir") + }; +}; + +variadic.production = function() { + log = { + debug: noop, + info: noop, + warn: noop, + error: noop, + dir: noop + }; +}; + +variadic.production(); + +// Expose +// ------ + +if (typeof exports !== "undefined") { + if (typeof module !== "undefined") { + exports = module.exports = variadic; + } + exports.variadic = variadic; +} else { + this.variadic = variadic; +} + +}()); diff --git a/dist/variadic.min.js b/dist/variadic.min.js new file mode 100644 index 0000000..a35d0b4 --- /dev/null +++ b/dist/variadic.min.js @@ -0,0 +1,2 @@ +/* Variadic.js - by William Bowers */ +!function(){function a(a,c,d){var e=new b;return a(e),e.validate(),function(){return e.process(k(arguments),c,d||this)}}function b(){this._parameterNames=[],this._descriptors={},this._forms=[],this._formMap={}}var c=function(){},d=Object.prototype.toString,e=Array.prototype.slice,f=Array.isArray||function(a){return"[object Array]"===d.call(a)},g=function(a){return"function"==typeof a},h=function(a){return a&&"object"==typeof a&&!g(a)&&!f(a)},i=function(a){return a instanceof RegExp},j=function(a){return"undefined"!=typeof a},k=function(a,b){return e.call(a,b||0)},l=function(a){var b=k(arguments,1);return 0===b.length?a:a.replace(/\{(\d+)\}/g,function(a,c){return b[c]})};a.error=function(a){log.error(a)},a.config={optionalArgumentRegex:/^\?/};var m={};b.fn=b.prototype,b.fn.validate=function(){},b.fn.process=function(b,c,d){var e=this.getBestMatch(b);if(!e)return a.error(l("Arguments '{0}' do not match any specified form",b.join(", "))),void 0;var f=this.processArguments(e,b);return c.call(d,f.opt,f.rest,(e.names||[]).slice(),b)},b.fn.getBestMatch=function(a){for(var b,c,d=this._forms,e=0,f=d.length;f>e;e++){var g=d[e];if(g.nonEmpty){if(0===a.length)return!1}else{var h=this.rateForm(g,a);if(h===m)return g;var i=b?c:-1;-1!=h&&h>i&&(b=g,c=h)}}return b},b.fn.rateForm=function(b,c){if(0===c.length)return b.empty?m:-1;if(b.empty)return-1;if(b.any)return 0;var d=b.names,e=-1;if(c)for(var f=0;f=0;c--)a(b[c])&&b.splice(c,1);return this},b.fn.form=function(){var b=k(arguments),c=b.join(",");if(this._formMap.hasOwnProperty(c))return this;if(0===b.length)return this.empty();this._formMap[c]=!0,this._forms.push({positional:!0,names:b.map(function(b){return b.replace(a.config.optionalArgumentRegex,"")})});for(var d=b.length-1;d>=0;d--)b[d].match(a.config.optionalArgumentRegex)&&this.form.apply(this,b.slice(0,d).concat(b.slice(d+1)));return this},b.fn.empty=function(){var a="*empty";return this._formMap.hasOwnProperty(a)?this:(this._removeForms(function(a){return a.nonEmpty||a.empty}),this._forms.push({empty:!0}),this._formMap[a]=!0,this)},b.fn.nonEmpty=function(){var a="*nonEmpty";return this._formMap.hasOwnProperty(a)?this:(this._removeForms(function(a){return a.empty}),this._forms.push({nonEmpty:!0}),this._formMap[a]=!0,this)},b.fn.anyForm=function(){return this._forms.push({any:!0}),this},b.fn.add=function(a,b){return this._descriptors[a]=b,this._parameterNames.push(a),this},b.fn.any=function(a,b){return this.add(a,{any:!0,description:"any value",defaultValue:b})},b.fn.type=function(a,b,c,d){return this.add(a,{type:b,description:c,defaultValue:d})},b.fn.test=function(a,b,c,d){return this.add(a,{test:b,description:c,defaultValue:d})},b.fn.cls=function(a,b,c,d){return this.add(a,{cls:b,description:c,defaultValue:d})},b.fn.object=function(a,b){return this.add(a,{test:h,description:"an object",defaultValue:b})},b.fn.array=function(a,b){return this.add(a,{test:f,description:"an array",defaultValue:b})},b.fn.func=function(a,b){return this.add(a,{type:"function",description:"a function",defaultValue:b})},b.fn.string=function(a,b){return this.add(a,{type:"string",description:"a string",defaultValue:b})},b.fn.number=function(a,b){return this.add(a,{type:"number",description:"a number",defaultValue:b})},b.fn.boolean=function(a,b){return this.add(a,{type:"boolean",description:"a boolean",defaultValue:b})},b.fn.regExp=function(a,b){return this.add(a,{test:i,description:"a regular expression",defaultValue:b})},b.fn.date=function(a,b){return this.add(a,{cls:Date,description:"a date",defaultValue:b})},b.fn.match=function(a,b,c,d){return this.add(a,{test:function(a){return b.test(a)},description:c,defaultValue:d})},a.silent=!0,a.debug=function(){function b(a,b,c,d){return(a?a+" ":"")+"[variadic"+(b?"."+b:"")+"] "+l.apply(null,[c].concat(d))}function c(a){var c=a.toUpperCase();return function(d,e){var f=k(arguments,2);return console[a](b(c,d,e,f))}}function d(c){var d=c.toUpperCase();return function(e){var f=k(arguments,2);if(a.silent)return console[c](b(d,null,e,f));throw new Error(b(null,null,e,f))}}function e(a){return function(){console[a].apply(console,arguments)}}log={debug:c("debug"),info:c("info"),warn:c("warn"),error:d("error"),dir:e("dir")}},a.production=function(){log={debug:c,info:c,warn:c,error:c,dir:c}},a.production(),"undefined"!=typeof exports?("undefined"!=typeof module&&(exports=module.exports=a),exports.variadic=a):this.variadic=a}(); \ No newline at end of file diff --git a/examples/ajax/index.html b/examples/ajax/index.html new file mode 100644 index 0000000..e13b588 --- /dev/null +++ b/examples/ajax/index.html @@ -0,0 +1,18 @@ + + + + + Ajax | Variadic.js + + + + +

Responses

+
    +
  • Loading...
  • +
+ + + + + diff --git a/examples/ajax/main.js b/examples/ajax/main.js new file mode 100644 index 0000000..8074e41 --- /dev/null +++ b/examples/ajax/main.js @@ -0,0 +1,77 @@ +var firstResponse = true; + +function addResponse(types, response) { + var list = document.getElementById("responses"); + + if (firstResponse) { + list.innerHTML = ""; + firstResponse = false; + } + + var li = document.createElement("li"); + li.setAttribute("class", types.map(function(t) { return "response-" + t; }).join(" ")); + li.appendChild(document.createTextNode(response)); + list.appendChild(li); +} + +var noop = function(type) { + return function() { + addResponse(["noop"], "No " + type + " callback specified"); + }; +}; + +var ajax = variadic(function(v) { + v.string("type") + .string("url") + .object("data", null) + .func("success", noop("success")) + .func("error", noop("error")); + + v.form("type", "url", "?data", "?success", "?error"); +}, function(opt, rest, form) { + var xhr = new XMLHttpRequest(); + xhr.open(opt.type, opt.url, true); + + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + addResponse(["internal", "success"], "ajax-internal response for form: " + form.join(", ")); + opt.success(xhr, JSON.parse(xhr.responseText)); + } else { + addResponse(["internal", "error"], "ajax-internal response for form: " + form.join(", ")); + opt.error(xhr); + } + } + }; + + xhr.send(opt.data); + + return xhr; +}); + +window.onload = function() { + var url = "https://baconipsum.com/api/?type=all-meat&sentences=10&start-with-lorem=1"; + + function responseFunction(type, form) { + return function(xhr, json) { + var sentences = json[0].split(/\s*\.\s*/); + var sentence = sentences[Math.floor(Math.random() * (sentences.length - 1))]; + addResponse([type], form + ": " + sentence); + }; + } + + function successFunction(form) { + return responseFunction("success", form); + } + + function errorFunction(form) { + return responseFunction("error", form); + } + + ajax("get", url); + ajax("get", url, successFunction("form 2")); + ajax("get", url, { get: "data" }); + ajax("get", url, { get: "data" }, successFunction("form 4")); + ajax("get", url, successFunction("form 5"), errorFunction("form 5")); + ajax("get", url, { get: "data" }, successFunction("form 6"), errorFunction("form 6")); +}; diff --git a/examples/ajax/style.css b/examples/ajax/style.css new file mode 100644 index 0000000..2ef97b5 --- /dev/null +++ b/examples/ajax/style.css @@ -0,0 +1,23 @@ +.response-internal { + text-decoration: underline; +} + +.response-success { + color: #5BA64F; + font-weight: bold; +} + +.response-internal.response-success { + color: #61717F; + font-weight: normal; +} + +.response-error { + color: #F43430; + font-weight: bold; +} + +.response-internal.response-error { + color: #5F5F5F; + font-weight: normal; +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..213cd06 --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "name": "variadic", + "description": "A tiny library for expressive variadic functions", + "keywords": [ + "variadic", "arguments", + "util", "server", "client", "browser" + ], + "author": "William Bowers ", + "repository": { + "type": "git", + "url": "git://github.com/willurd/variadic.js" + }, + "devDependencies": { + "mocha": "*", + "grunt": "*", + "grunt-contrib-concat": "*", + "grunt-contrib-jshint": "*", + "grunt-contrib-uglify": "*", + "grunt-contrib-watch": "*", + "grunt-exec": "*", + "chai": "*", + "docco": "*" + }, + "main": "./dist/variadic.js", + "version": "0.0.1", + "license": "MIT" +} diff --git a/src/variadic.js b/src/variadic.js new file mode 100644 index 0000000..5f252a9 --- /dev/null +++ b/src/variadic.js @@ -0,0 +1,646 @@ +(function() { + +// Helpers +// ------- + +// These are some utility functions variadic uses internally. +var noop = function() {}; + +var toString = Object.prototype.toString; +var slice = Array.prototype.slice; + +var isArray = Array.isArray || function(value) { + return toString.call(value) === "[object Array]"; +}; + +var isFunction = function(value) { + return typeof value === "function"; +}; + +var isString = function(value) { + return typeof value === "string"; +}; + +var isObject = function(value) { + return value && typeof value === "object" && + !isFunction(value) && !isArray(value); +}; + +var isBoolean = function(value) { + return typeof value === "boolean"; +}; + +var isNumber = function(value) { + return typeof value === "number"; +}; + +var isRegExp = function(value) { + return value instanceof RegExp; +}; + +var isNull = function(value) { + return !value && isObject(value); +}; + +var isUndefined = function(value) { + return typeof value === "undefined"; +}; + +var isDefined = function(value) { + return typeof value !== "undefined"; +}; + +var toArray = function(obj, from) { + return slice.call(obj, from || 0); +}; + +var format = function(format) { + var args = toArray(arguments, 1); + + return (args.length === 0 ? + format : + format.replace(/\{(\d+)\}/g, function(match, index) { + return args[index]; + })); +}; + +// Entry point +// ----------- + +// Call this function to configure and return a new variadic function. +function variadic(configFn, fn, context) { + var config = new Config(); + configFn(config); + + // The caller just configured variadic. Let's let them know early on if + // they've made a mistake. + config.validate(); + + // This wrapper function is what's actually returned by variadic (it's + // what callers will think of as "their" function). Its responsibility is + // to forward arguments to the config object for processing. + return function() { + return config.process(toArray(arguments), fn, context || this); + }; +} + +// Error reporting +// --------------- + +// You can override variadic's error handling by setting `variadic.error` to +// your own function. +variadic.error = function(message) { + log.error(message); +}; + +// Function Configuration +// ---------------------- + +var exactMatch = {}; // a token for telling if a form is an exact match + +// A new instance of this object is passed into configuration functions, like so: +// +// ```javascript +// variadic(function(v) { +// // v is an instance of Config ('v' for 'variadic'). Use it to add parameters and forms. +// }, function() { +// ... +// }); +// ``` +function Config() { + this._parameterNames = []; + this._descriptors = {}; + this._forms = []; + this._formMap = {}; + this._flags = [ + { name: "optional", symbol: "?" }, + { name: "noLone", symbol: "*" } + ]; + + var flagsList = this._flags.map(function(flag) { + return "\\" + flag.symbol; + }).join(""); + this._flagsRegex = new RegExp("^([" + flagsList + "]+)"); + + this._flagsMap = {}; + for (var i = 0, len = this._flags.length; i < len; i++) { + var flag = this._flags[i]; + this._flagsMap[flag.symbol] = flag.name; + } +} + +Config.fn = Config.prototype; + +// Get the flags from a parameter name. +Config.fn.getFlags = function(name) { + var flagsObject = {}; + var match = name.match(this._flagsRegex); + + if (!match) { + return flagsObject; + } + + var flagsList = match[0].split(""); + + for (var i = 0, len = flagsList.length; i < len; i++) { + var key = this._flagsMap[flagsList[i]]; + flagsObject[key] = true; + } + + return flagsObject; +}; + +// Remove the flags from a parameter name. +Config.fn.removeFlags = function(name) { + return name.replace(this._flagsRegex, ""); +}; + +// TODO: Make sure all of the forms are valid (no duplicates, all args have +// descriptors, etc). +Config.fn.validate = function() { +}; + +Config.fn.process = function(args, fn, context) { + var form = this.getBestMatch(args); + + if (!form) { + variadic.error(format("Arguments '{0}' do not match any specified form", args.join(", "))); + return; + } + + var result = this.processArguments(form, args); + var names = form.names || []; + + return fn.call(context, result.opt, result.rest, names, args); +}; + +// Get the form that is the best match for the given arguments. This +// is necessary because multiple forms can match. Only after we have +// the best match will we actually process the arguments and pass them +// along to the user function. +Config.fn.getBestMatch = function(args) { + var bestMatch; + var bestRating; + var forms = this._forms; + + for (var i = 0, len = forms.length; i < len; i++) { + var form = forms[i]; + + if (form.nonEmpty) { + if (args.length === 0) { + return false; + } + + continue; + } + + var a = this.rateForm(form, args); + + if (a === exactMatch) { + // This is an exact match for the arguments. Nothing can + // beat this form so we might as well exit early. + return form; + } + + var b = bestMatch ? bestRating : -1; + + if (a != -1 && a > b) { + bestMatch = form; + bestRating = a; + } + } + + return bestMatch; +}; + +/** + * -1 == no match + * 1 point for each matching parameter that isn't an 'any' parameter + */ +Config.fn.rateForm = function(form, args) { + if (args.length === 0) { + if (form.empty) { + return exactMatch; + } else { + return -1; + } + } + + if (form.empty) { + return -1; + } if (form.any) { + // 0 is the lowest possible match rating. + return 0; + } + + var names = form.names; + + // `v.form("one", "two", "?three", "four", "?five")` is the same as: + // + // ```javascript + // v.form("one", "two", four") + // v.form("one", "two", four", "five") + // v.form("one", "two", "three", "four") + // v.form("one", "two", "three", "four", "five") + // ``` + + var rating = -1; + + if (args) { + for (var i = 0; i < names.length; i++) { + var arg = args[i]; + var name = names[i]; + var desc = this._descriptors[name]; + + if (!desc) { + variadic.error(format("Unknown parameter: {0}", name)); + return -1; + } + + if (!this.checkArg(name, desc, arg)) { + return -1; + } else if (!desc.any) { + rating++; + } + } + } else { + variadic.error(format("Unknown form: {0}", form)); + } + + return rating; +}; + +Config.fn.processArguments = function(form, args) { + var names = (form.names || []); + var result = { + opt: {}, + rest: args.slice(names.length) + }; + + for (var prop in this._descriptors) { + var defaultValue = this.getDefaultValue(this._descriptors[prop]); + + if (isDefined(defaultValue)) { + result.opt[prop] = defaultValue; + } + } + + if (!form.empty) { + for (var i = 0, name; name = names[i]; i++) { + result.opt[name] = args[i]; + } + } + + return result; +}; + +Config.fn.getDefaultValue = function(descriptor) { + if (isFunction(descriptor.defaultGenerator)) { + return descriptor.defaultGenerator(); + } else { + return descriptor.defaultValue; + } +}; + +Config.fn.checkArg = function(name, descriptor, value) { + if (descriptor.any) { + return true; + } else if ("type" in descriptor) { + if (value !== null && typeof value === descriptor.type) { + return true; + } + } else if ("cls" in descriptor) { + if (value instanceof descriptor.cls) { + return true; + } + } else if ("test" in descriptor) { + if (descriptor.test(value)) { + return true; + } + } else { + var str = "Invalid descriptor '{0}'. Must contain a type, cls, or test property for matching arguments"; + var message = format(str, name); + variadic.error(message); + return false; + } + + return false; +}; + +Config.fn.forms = function() { + this.form.apply(this, this._parameterNames.map(function(name) { + return "?" + name; + })); +}; + +Config.fn._removeForms = function(testFn) { + var forms = this._forms; + + for (var i = forms.length - 1; i >= 0; i--) { + if (testFn(forms[i])) { + forms.splice(i, 1); + } + } + + return this; +}; + +// Adds a new form to the variadic function. Forms are just arrays of +// parameter names (parameters are specified using `.add` or one of the +// built in parameter functions like `.object`, `.array`, etc). +Config.fn.form = function(/* names */) { + var names = toArray(arguments); + var mapKey = names.join(","); + var i; + var len = names.length; + var noLoneCount = 0; + + // Don't add empty forms and don't add the same form twice. + if (this._formMap.hasOwnProperty(mapKey)) { + return this; + } + + if (names.length === 0) { + return this.empty(); + } + + // Count the "no lone" parameters. + for (i = 0; i < len; i++) { + var flags = this.getFlags(names[i]); + + if (flags.noLone) { + noLoneCount++; + } + } + + if (noLoneCount === len) { + // You must have at least 1 non-"no lone" parameter. + return this; + } + + // Provide an easy way to know that this form has already been added. + this._formMap[mapKey] = true; + + // Add this form. + this._forms.push({ + positional: true, + names: names.map(this.removeFlags, this) + }); + + // Recursively add more forms if there are optional parameters. Add + // the "sub" forms backwards because we want the optional parameters + // that show up first to match first. + for (i = len - 1; i >= 0; i--) { + var flags = this.getFlags(names[i]); + + if (flags.optional) { + this.form.apply(this, names.slice(0, i).concat(names.slice(i + 1))); + } + } + + return this; +}; + +// Will only match when given no arguments. When this matches it is the +// only possible match, and it's the only way to build a function that +// can accept no arguments. +Config.fn.empty = function() { + var mapKey = "*empty"; + + if (this._formMap.hasOwnProperty(mapKey)) { + return this; + } + + this._removeForms(function(form) { + return form.nonEmpty || form.empty; + }); + + this._forms.push({ + empty: true + }); + + this._formMap[mapKey] = true; + + return this; +}; + +// Will not match when given no arguments. +Config.fn.nonEmpty = function() { + var mapKey = "*nonEmpty"; + + if (this._formMap.hasOwnProperty(mapKey)) { + return this; + } + + this._removeForms(function(form) { + return form.empty; + }); + + this._forms.push({ + nonEmpty: true + }); + + this._formMap[mapKey] = true; + + return this; +}; + +// Will match any set of arguments. All arguments will be put into the +// rest array and opt will be null. This will have the lowest match rating. +Config.fn.anyForm = function() { + this._forms.push({ + any: true + }); + + return this; +}; + +Config.fn.add = function(name, descriptor) { + this._descriptors[name] = descriptor; + this._parameterNames.push(name); + return this; +}; + +// The `any` descriptor. Matches any value, but has less weight than +// more specific matching descriptors. +Config.fn.any = function(name, defaultValue) { + return this.add(name, { + any: true, + description: "any value", + defaultValue: defaultValue + }); +}; + +Config.fn.type = function(name, type, description, defaultValue) { + return this.add(name, { + type: type, + description: description, + defaultValue: defaultValue + }); +}; + +Config.fn.test = function(name, testFn, description, defaultValue) { + return this.add(name, { + test: testFn, + description: description, + defaultValue: defaultValue + }); +}; + +Config.fn.cls = function(name, cls, description, defaultValue) { + return this.add(name, { + cls: cls, + description: description, + defaultValue: defaultValue + }); +}; + +Config.fn.object = function(name, defaultValue) { + return this.add(name, { + test: isObject, + description: "an object", + defaultValue: defaultValue + }); +}; + +Config.fn.array = function(name, defaultValue) { + return this.add(name, { + test: isArray, + description: "an array", + defaultValue: defaultValue + }); +}; + +Config.fn.func = function(name, defaultValue) { + return this.add(name, { + type: "function", + description: "a function", + defaultValue: defaultValue + }); +}; + +Config.fn.string = function(name, defaultValue) { + return this.add(name, { + type: "string", + description: "a string", + defaultValue: defaultValue + }); +}; + +Config.fn.number = function(name, defaultValue) { + return this.add(name, { + type: "number", + description: "a number", + defaultValue: defaultValue + }); +}; + +Config.fn.boolean = function(name, defaultValue) { + return this.add(name, { + type: "boolean", + description: "a boolean", + defaultValue: defaultValue + }); +}; + +Config.fn.regExp = function(name, defaultValue) { + return this.add(name, { + test: isRegExp, + description: "a regular expression", + defaultValue: defaultValue + }); +}; + +Config.fn.date = function(name, defaultValue) { + return this.add(name, { + cls: Date, + description: "a date", + defaultValue: defaultValue + }); +}; + +Config.fn.match = function(name, regExp, description, defaultValue) { + return this.add(name, { + test: function(value) { + return regExp.test(value); + }, + description: description, + defaultValue: defaultValue + }); +}; + +// Debug +// ----- + +variadic.silent = true; + +variadic.debug = function() { + function formatMessage(level, method, formatString, args) { + return (level ? level + " " : "") + // level + "[variadic" + (method ? ("." + method) : "") + "] " + // category + format.apply(null, [formatString].concat(args)); // message + } + + function logFunction(name) { + var level = name.toUpperCase(); + + return function(method, format) { + var rest = toArray(arguments, 2); + return console[name](formatMessage(level, method, format, rest)); + }; + } + + function errorFunction(name) { + var level = name.toUpperCase(); + + return function(format) { + var rest = toArray(arguments, 2); + + if (variadic.silent) { + return console[name](formatMessage(level, null, format, rest)); + } else { + throw new Error(formatMessage(null, null, format, rest)); + } + }; + } + + function logRedirect(name) { + return function() { + console[name].apply(console, arguments); + }; + } + + log = { + debug: logFunction("debug"), + info: logFunction("info"), + warn: logFunction("warn"), + error: errorFunction("error"), + dir: logRedirect("dir") + }; +}; + +variadic.production = function() { + log = { + debug: noop, + info: noop, + warn: noop, + error: noop, + dir: noop + }; +}; + +variadic.production(); + +// Expose +// ------ + +if (typeof exports !== "undefined") { + if (typeof module !== "undefined") { + exports = module.exports = variadic; + } + exports.variadic = variadic; +} else { + this.variadic = variadic; +} + +}()); diff --git a/tests/index.html b/tests/index.html new file mode 100644 index 0000000..4154105 --- /dev/null +++ b/tests/index.html @@ -0,0 +1,55 @@ + + + + + Variadic.js Tests + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/setup.js b/tests/setup.js new file mode 100644 index 0000000..0739980 --- /dev/null +++ b/tests/setup.js @@ -0,0 +1,11 @@ +if (typeof require === "function") { + var libpath = process.env["COVERAGE"] ? "../src-cov" : "../src"; + global.variadic = require(libpath + "/variadic"); + global.assert = require("chai").assert; +} else { + window.assert = chai.assert; +} + +// Make sure we get errors. +variadic.debug(); +variadic.silent = false; diff --git a/tests/style.css b/tests/style.css new file mode 100644 index 0000000..cbf20ff --- /dev/null +++ b/tests/style.css @@ -0,0 +1,11 @@ +#mocha .suite .test pre { + padding: 0; +} + +#mocha .test pre code { + padding: 25px; +} + +#mocha .test pre code .comment { + color: #c5c5c5; +} diff --git a/tests/tests/any.js b/tests/tests/any.js new file mode 100644 index 0000000..0172a2f --- /dev/null +++ b/tests/tests/any.js @@ -0,0 +1,46 @@ +suite("any", function() { + var Test = {}; + + function SimpleTest(property, operator, value, valueIsLiteral) { + this.property = property; + this.operator = operator; + this.value = value; + this.valueIsLiteral = valueIsLiteral; + } + + suite("any type", function() { + Test.create = variadic(function(v) { + v.string ("property") + .string ("operator") + .any ("value") + .boolean("valueIsLiteral", false) + .forms(); + }, function(opt) { + return new SimpleTest(opt.property, opt.operator, opt.value, opt.valueIsLiteral); + }); + + function testTest(p, value, valueIsLiteral) { + assert.equal(p.property, "Number"); + assert.equal(p.operator, "gt"); + assert.equal(p.value, value); + + if (valueIsLiteral) { + assert.isTrue(p.valueIsLiteral); + } else { + assert.isFalse(p.valueIsLiteral); + } + } + + test("any", function() { + testTest(Test.create("Number", "gt", 100), 100); + }); + + test("boolean", function() { + testTest(Test.create("Number", "gt", true), undefined, true); + }); + + test("any and boolean", function() { + testTest(Test.create("Number", "gt", 100, true), 100, true); + }); + }); +}); diff --git a/tests/tests/basic.js b/tests/tests/basic.js new file mode 100644 index 0000000..e008aaa --- /dev/null +++ b/tests/tests/basic.js @@ -0,0 +1,51 @@ +suite("basic use case", function() { + var fn, deps, options; + + var func = variadic(function(v) { + v.object("options"); + v.array("deps"); + v.func("fn"); + + v.form("fn"); + v.form("deps", "fn"); + v.form("options", "deps", "fn"); + }, function(opt, rest, form) { + fn = opt.fn; + deps = opt.deps; + options = opt.options; + return rest; + }); + + setup(function() { + fn = undefined; + deps = undefined; + options = undefined; + }); + + test("form 1", function() { + var theFn = function() {}; + func(theFn); + + assert.equal(theFn, fn); + }); + + test("form 2", function() { + var theDeps = []; + var theFn = function() {}; + func(theDeps, theFn); + + assert.equal(theDeps, deps); + assert.equal(theFn, fn); + }); + + test("form 3", function() { + var theOptions = {}; + var theDeps = []; + var theFn = function() {}; + func(theOptions, theDeps, theFn); + + assert.equal(theOptions, options); + assert.equal(theDeps, deps); + assert.equal(theFn, fn); + }); +}); diff --git a/tests/tests/builtin-descriptors.js b/tests/tests/builtin-descriptors.js new file mode 100644 index 0000000..bef742b --- /dev/null +++ b/tests/tests/builtin-descriptors.js @@ -0,0 +1,4 @@ +suite("builtin descriptors", function() { + // TODO: Write me. + // object, array, func, string, number, boolean +}); diff --git a/tests/tests/chaining.js b/tests/tests/chaining.js new file mode 100644 index 0000000..7be34ed --- /dev/null +++ b/tests/tests/chaining.js @@ -0,0 +1,66 @@ +suite("chaining", function() { + suite("configuration functions return the configuration object", function() { + var v; + + setup(function() { + // Get a reference to the variadic configuration object. + variadic(function(vv) { v = vv; }, function() {}); + }); + + test("form", function() { + assert.equal(v, v.form("name")); + }); + + test("add", function() { + assert.equal(v, v.add("name", { type: "string", description: "a string" })); + }); + + test("type", function() { + assert.equal(v, v.type("name", "string", "a string")); + }); + + test("test", function() { + assert.equal(v, v.test("name", function(value) {})); + }); + + test("cls", function() { + assert.equal(v, v.cls("name", Date)); + }); + + test("object", function() { + assert.equal(v, v.object("name")); + }); + + test("array", function() { + assert.equal(v, v.array("name")); + }); + + test("func", function() { + assert.equal(v, v.func("name")); + }); + + test("string", function() { + assert.equal(v, v.string("name")); + }); + + test("number", function() { + assert.equal(v, v.number("name")); + }); + + test("boolean", function() { + assert.equal(v, v.boolean("name")); + }); + + test("regExp", function() { + assert.equal(v, v.regExp("name")); + }); + + test("date", function() { + assert.equal(v, v.date("name")); + }); + + test("match", function() { + assert.equal(v, v.match("name", /./)); + }); + }); +}); diff --git a/tests/tests/context.js b/tests/tests/context.js new file mode 100644 index 0000000..424e559 --- /dev/null +++ b/tests/tests/context.js @@ -0,0 +1,35 @@ +suite("context", function() { + var MyClass = variadic(function(v) { + v.number("x") + .number("y"); + + v.form("x", "y"); + }, function(opt) { + this.x = opt.x; + this.y = opt.y; + }); + + MyClass.prototype.add = variadic(function(v) { + v.number("x") + .number("y", 5); + + v.form("x", "?y"); + }, function(opt) { + this.x += opt.x; + this.y += opt.y; + }); + + test("constructors have correct 'this'", function() { + var c = new MyClass(1, 2); + assert.equal(c.x, 1); + assert.equal(c.y, 2); + }); + + test("instance methods have correct 'this'", function() { + var c = new MyClass(1, 2); + c.add(2); // x = 3, y = 7 + c.add(7, 12); // x = 10, y = 19 + assert.equal(c.x, 10); + assert.equal(c.y, 19); + }); +}); diff --git a/tests/tests/custom-defaults.js b/tests/tests/custom-defaults.js new file mode 100644 index 0000000..2b3ee25 --- /dev/null +++ b/tests/tests/custom-defaults.js @@ -0,0 +1,27 @@ +suite("custom defaults", function() { + var defaultOptions = {}; + var defaultDeps = []; + + var func = variadic(function(v) { + v.object("options", defaultOptions); + v.array("deps", defaultDeps); + v.func("fn"); + + v.form("fn"); + v.form("deps", "fn"); + v.form("options", "deps", "fn"); + }, function(opt, rest, form) { + return opt; + }); + + test("form 1", function() { + var opt = func(function() {}); + assert.equal(opt.options, defaultOptions); + assert.equal(opt.deps, defaultDeps); + }); + + test("form 2", function() { + var opt = func([], function() {}); + assert.equal(opt.options, defaultOptions); + }); +}); diff --git a/tests/tests/custom-descriptors.js b/tests/tests/custom-descriptors.js new file mode 100644 index 0000000..be0d8d0 --- /dev/null +++ b/tests/tests/custom-descriptors.js @@ -0,0 +1,6 @@ +suite("custom descriptors", function() { + // TODO: Write me. + // v.add("person", { cls: Person, description: "a person" }); + // v.add("person", { type: "object", description: "a person" }); + // v.add("person", { test: function(value) { return value instanceof Person; }, description: "a person" }); +}); diff --git a/tests/tests/defaults.js b/tests/tests/defaults.js new file mode 100644 index 0000000..1ab75c6 --- /dev/null +++ b/tests/tests/defaults.js @@ -0,0 +1,24 @@ +suite("default defaults", function() { + var func = variadic(function(v) { + v.object("options"); + v.array("deps"); + v.func("fn"); + + v.form("fn"); + v.form("deps", "fn"); + v.form("options", "deps", "fn"); + }, function(opt, rest, form) { + return opt; + }); + + test("form 1", function() { + var opt = func(function() {}); + assert.isUndefined(opt.deps); + assert.isUndefined(opt.options); + }); + + test("form 2", function() { + var opt = func([], function() {}); + assert.isUndefined(opt.options); + }); +}); diff --git a/tests/tests/examples/filtering-a-list.js b/tests/tests/examples/filtering-a-list.js new file mode 100644 index 0000000..b272a21 --- /dev/null +++ b/tests/tests/examples/filtering-a-list.js @@ -0,0 +1,70 @@ + +suite("example: filtering a list", function() { + function Person(name, age) { + this.name = name; + this.age = age; + } + + Person.prototype.toString = function() { + return this.name; + }; + + var peopleList = [ + new Person("bob", 20), + new Person("sally", 24), + new Person("joe", 21), + new Person("joeseph", 29), + new Person("jane", 17), + new Person("sue", 26), + new Person("john", 25), + new Person("joe", 16), + new Person("joe", 29) + ]; + + var filterPeople = variadic(function(v) { + v.array ("list") + .regExp("name", /./) // default: match anything + .number("minAge", 0) // default: can't be less than zero years old + .number("maxAge", 999); // default: unless you've been cryogenically frozen... + + v.form("?name", "?minAge", "?maxAge") + .nonEmpty(); + }, function(opt, rest, form) { + return peopleList.filter(function(person) { + return (opt.name.test(person.name)) && + (person.age >= opt.minAge) && + (person.age <= opt.maxAge); + }).map(function(person) { + return person.toString() + "," + person.age; + }); + }); + + test("form 1: name", function() { + var people = filterPeople(/\bjoe\b/); + assert.deepEqual(people, ["joe,21", "joe,16", "joe,29"]); + }); + + test("form 2: minAge", function() { + var people = filterPeople(18); + assert.deepEqual(people, ["bob,20", "sally,24", "joe,21", "joeseph,29", "sue,26", "john,25", "joe,29"]); + }); + + test("form 3: name, minAge", function() { + var people = filterPeople(/\bjoe\b/, 18); + assert.deepEqual(people, ["joe,21", "joe,29"]); + }); + + test("form 4: minAge, maxAge", function() { + var people = filterPeople(18, 25); + assert.deepEqual(people, ["bob,20", "sally,24", "joe,21", "john,25"]); + }); + + test("form 5: name, minAge, maxAge", function() { + var people = filterPeople(/\bjoe\b/, 0, 18); + assert.deepEqual(people, ["joe,16"]); + }); + + test("Can't be empty", function() { + assert.throw(filterPeople, Error, "Arguments '' do not match any specified form"); + }); +}); diff --git a/tests/tests/form.js b/tests/tests/form.js new file mode 100644 index 0000000..090b41c --- /dev/null +++ b/tests/tests/form.js @@ -0,0 +1,31 @@ +suite("form", function() { + var func = variadic(function(v) { + v.object("options"); + v.array("deps"); + v.func("fn"); + + v.form("fn"); + v.form("deps", "fn"); + v.form("options", "deps", "fn"); + }, function(opt, rest, form) { + return form; + }); + + test("form 1", function() { + var form = func(function() {}); + assert.equal(form.length, 1); + assert.deepEqual(form, ["fn"]); + }); + + test("form 2", function() { + var form = func([], function() {}); + assert.equal(form.length, 2); + assert.deepEqual(form, ["deps", "fn"]); + }); + + test("form 3", function() { + var form = func({}, [], function() {}); + assert.equal(form.length, 3); + assert.deepEqual(form, ["options", "deps", "fn"]); + }); +}); diff --git a/tests/tests/lone-prevention.js b/tests/tests/lone-prevention.js new file mode 100644 index 0000000..f2e518a --- /dev/null +++ b/tests/tests/lone-prevention.js @@ -0,0 +1,81 @@ +suite("lone prevention", function() { + test("list can't be alone", function() { + function Person(name, age) { + this.name = name; + this.age = age; + } + + Person.prototype.toString = function() { + return this.name; + }; + + var peopleList = [ + new Person("bob", 20), + new Person("sally", 24), + new Person("joe", 21), + new Person("joeseph", 29), + new Person("jane", 17), + new Person("sue", 26), + new Person("john", 25), + new Person("joe", 16), + new Person("joe", 29) + ]; + + var filterPeople = variadic(function(v) { + v.array ("list") // the list to filter + .regExp("name", /./) // default: match anything + .number("minAge", 0) // default: can't be less than zero + .number("maxAge", 999); // default: unless you've been cryogenically frozen... + + v.form("*list", "?name", "?minAge", "?maxAge"); + }, function(opt, rest, form) { + console.log(opt); + return opt.list.filter(function(person) { + return (opt.name.test(person.name)) && + (person.age >= opt.minAge) && + (person.age <= opt.maxAge); + }); + }); + + assert.throw(function() { + filterPeople(peopleList); + }, Error, "do not match any specified form"); + }); + + test("multiple no-lone parameters", function() { + var testFn = variadic(function(v) { + v.string ("one") + .number ("two") + .boolean("three") + .string ("four"); + + v.form("*one", "*two", "?three", "?four"); + }, function(opt, rest, form) { + return { + opt: opt, + rest: rest, + form: form + }; + }); + + var res; + + res = testFn("one", 2, true); + assert.equal(res.opt.one, "one"); + assert.equal(res.opt.two, 2); + assert.equal(res.opt.three, true); + assert.equal(res.opt.four, undefined); + assert.deepEqual(res.form, ["one", "two", "three"]) + + res = testFn("one", 2, false, "four"); + assert.equal(res.opt.one, "one"); + assert.equal(res.opt.two, 2); + assert.equal(res.opt.three, false); + assert.equal(res.opt.four, "four"); + assert.deepEqual(res.form, ["one", "two", "three", "four"]) + + assert.throw(function() { + testFn("one", 2); + }, Error, "do not match any specified form"); + }); +}); diff --git a/tests/tests/optional-arguments.js b/tests/tests/optional-arguments.js new file mode 100644 index 0000000..f0d85d2 --- /dev/null +++ b/tests/tests/optional-arguments.js @@ -0,0 +1,33 @@ +suite("optional arguments", function() { + suite("required in-between", function() { + var fn = variadic(function(v) { + v.string ("one") + .number ("two") + .boolean("three"); + + v.form("?one", "two", "?three"); + }, function(opt, rest, form) { + return { + opt: opt, + rest: rest, + form: form + }; + }); + + test("form 1: two", function() { + var res = fn(10); + assert.equal(res.opt.one, undefined); + assert.equal(res.opt.two, 10); + assert.equal(res.opt.three, undefined); + assert.deepEqual(res.form, ["two"]); + }); + + test("form 2: one, two, three", function() { + var res = fn("one", 10, true); + assert.equal(res.opt.one, "one"); + assert.equal(res.opt.two, 10); + assert.equal(res.opt.three, true); + assert.deepEqual(res.form, ["one", "two", "three"]); + }); + }); +}); diff --git a/tests/tests/rest.js b/tests/tests/rest.js new file mode 100644 index 0000000..457facd --- /dev/null +++ b/tests/tests/rest.js @@ -0,0 +1,31 @@ +suite("rest", function() { + var func = variadic(function(v) { + v.object("options"); + v.array("deps"); + v.func("fn"); + + v.form("fn"); + v.form("deps", "fn"); + v.form("options", "deps", "fn"); + }, function(opt, rest, form) { + return rest; + }); + + test("form 1", function() { + var rest = func(function() {}, "one", "two", "three"); + assert.equal(rest.length, 3); + assert.deepEqual(rest, ["one", "two", "three"]); + }); + + test("form 2", function() { + var rest = func([], function() {}, "one", "two", "three"); + assert.equal(rest.length, 3); + assert.deepEqual(rest, ["one", "two", "three"]); + }); + + test("form 3", function() { + var rest = func({}, [], function() {}, "one", "two", "three"); + assert.equal(rest.length, 3); + assert.deepEqual(rest, ["one", "two", "three"]); + }); +}); diff --git a/tests/tests/similar-forms.js b/tests/tests/similar-forms.js new file mode 100644 index 0000000..a51686b --- /dev/null +++ b/tests/tests/similar-forms.js @@ -0,0 +1,26 @@ +suite("similar forms", function() { + var theFn = function() {}; + var theOptions = {}; + + var func = variadic(function(v) { + v.object("options"); + v.func("fn"); + + v.form("fn", "options"); + v.form("options", "fn"); + }, function(opt, rest, form) { + return opt; + }); + + test("form 1", function() { + var opt = func(theFn, theOptions); + assert.equal(opt.fn, theFn); + assert.equal(opt.options, theOptions); + }); + + test("form 2", function() { + var opt = func(theOptions, theFn); + assert.equal(opt.fn, theFn); + assert.equal(opt.options, theOptions); + }); +}); diff --git a/tests/tests/variadic.js b/tests/tests/variadic.js new file mode 100644 index 0000000..a29979f --- /dev/null +++ b/tests/tests/variadic.js @@ -0,0 +1,5 @@ +suite("variadic", function() { + test("exists", function() { + assert.isFunction(variadic); // we can probably just stop testing here + }); +});