diff --git a/d3/d3-tests.ts b/d3/d3-tests.ts
index 36ac355fe..bf500d409 100644
--- a/d3/d3-tests.ts
+++ b/d3/d3-tests.ts
@@ -1,129 +1,615 @@
-///
-
-d3.selectAll("p").style("color", "white");
-d3.select("body").style("background-color", "black");
-d3.selectAll("p").style("color", function () {
- return "hsl(" + Math.random() * 360 + ",100%,50%)";
-});
-d3.selectAll("p").style("color", function (d, i) {
- return i % 2 ? "#fff" : "#eee";
-});
-d3.selectAll("p")
- .data([4, 8, 15, 16, 23, 42])
- .style("font-size", function (d) { return d + "px"; });
-d3.select("body").selectAll("p")
- .data([4, 8, 15, 16, 23, 42])
- .enter().append("p")
- .text(function (d) { return "I’m number " + d + "!"; });
-var p = d3.select("body").selectAll("p")
- .data([4, 8, 15, 16, 23, 42])
- .text(String);
-p.enter().append("p")
- .text(String);
-p.exit().remove();
-d3.select("body").transition()
- .style("background-color", "black");
-d3.selectAll("circle").transition()
- .duration(750)
- .delay(function (d, i) { return i * 10; })
- .attr("r", function (d) { return Math.sqrt(d * scale); });
-
-function testOrdinalScale() {
- var x = d3.scale.ordinal().range(["foo", "bar"]);
- x.domain([0, 1]);
- var result = x(0);
-
- var x = d3.scale.ordinal().domain(["a", "b", "c"]).rangePoints([120, 0]);
- var x = d3.scale.ordinal().domain(["a", "b", "c"]).rangePoints([120, 0], 1);
-
- var x = d3.scale.ordinal().domain(["a", "b", "c"]).rangeBands([120, 0]);
- var x = d3.scale.ordinal().domain(["a", "b", "c"]).rangeBands([120, 0], .2);
- var x = d3.scale.ordinal().domain(["a", "b", "c"]).rangeBands([120, 0], .2, .1);
-
- var x = d3.scale.ordinal().domain(["a", "b", "c"]).rangeRoundBands([0, 100]);
- var x = d3.scale.ordinal().domain(["a", "b", "c"]).rangeRoundBands([0, 100], .2);
- var x = d3.scale.ordinal().domain(["a", "b", "c"]).rangeRoundBands([120, 0], .2, .1);
-}
-
-
-function testKeys() {
- var x = d3.keys({ a: 1, b: 1 });
-
- function abc() {
- this.a = 1;
- this.b = 2;
- }
- var x = d3.keys(new abc());
-}
-
-function testSVGArc() {
- var a = d3.svg.arc().innerRadius(100).outerRadius(200);
- var a = d3.svg.arc().outerRadius(100).startAngle(0).endAngle(Math.PI);
-
- var f = function () => {
- return 42;
- }
- var a = d3.svg.arc().innerRadius(0).outerRadius(f).startAngle(f).endAngle(f() * 2)
-
- var str = a();
- var str = a({ outerRadius: 50 });
- var str = a.outerRadius(100)();
- var str = a.endAngle(Math.PI / 2)()
- var str = a({ startAngle: Math.PI / 2 });
-
- var c = d3.svg.arc().innerRadius(0).outerRadius(100).startAngle(0).endAngle(2 * Math.PI).centroid();
- var num = c[0];
-}
-
-function testPieLayout() {
- var p = d3.layout.pie().sort(null).value(function (d) { return d.value; });
- var data = [1, 2, 3, 4];
- var arcs = p(data);
-}
-
-//Example from http://bl.ocks.org/3887235
-function testPieChart() {
- var width = 960,
- height = 500,
- radius = Math.min(width, height) / 2;
-
- var color = d3.scale.ordinal()
- .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
-
- var arc = d3.svg.arc()
- .outerRadius(radius - 10)
- .innerRadius(0);
-
- var pie = d3.layout.pie()
- .sort(null)
- .value(function (d) { return d.population; });
-
- var svg = d3.select("body").append("svg")
- .attr("width", width)
- .attr("height", height)
- .append("g")
- .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
-
- d3.csv("data.csv", function (error, data) {
-
- data.forEach(function (d) {
- d.population = +d.population;
- });
-
- var g = svg.selectAll(".arc")
- .data(pie(data))
- .enter().append("g")
- .attr("class", "arc");
-
- g.append("path")
- .attr("d", arc)
- .style("fill", function (d) { return color(d.data.age); });
-
- g.append("text")
- .attr("transform", function (d) { return "translate(" + arc.centroid(d) + ")"; })
- .attr("dy", ".35em")
- .style("text-anchor", "middle")
- .text(function (d) { return d.data.age; });
-
- });
-}
+///
+
+//Example from http://bl.ocks.org/3887235
+function testPieChart() {
+ var width = 960,
+ height = 500,
+ radius = Math.min(width, height) / 2;
+
+ var color = d3.scale.ordinal()
+ .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
+
+ var arc = d3.svg.arc()
+ .outerRadius(radius - 10)
+ .innerRadius(0);
+
+ var pie = d3.layout.pie()
+ .sort(null)
+ .value(function (d) { return d.population; });
+
+ var svg = d3.select("body").append("svg")
+ .attr("width", width)
+ .attr("height", height)
+ .append("g")
+ .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
+
+ d3.csv("data.csv", function (error, data) {
+
+ data.forEach(function (d) {
+ d.population = +d.population;
+ });
+
+ var g = svg.selectAll(".arc")
+ .data(pie(data))
+ .enter().append("g")
+ .attr("class", "arc");
+
+ g.append("path")
+ .attr("d", arc)
+ .style("fill", function (d) { return color(d.data.age); });
+
+ g.append("text")
+ .attr("transform", function (d) { return "translate(" + arc.centroid(d) + ")"; })
+ .attr("dy", ".35em")
+ .style("text-anchor", "middle")
+ .text(function (d) { return d.data.age; });
+
+ });
+}
+
+//Example from http://bl.ocks.org/3887051
+function groupedBarChart() => {
+ var margin = { top: 20, right: 20, bottom: 30, left: 40 },
+ width = 960 - margin.left - margin.right,
+ height = 500 - margin.top - margin.bottom;
+
+ var x0 = d3.scale.ordinal()
+ .rangeRoundBands([0, width], .1);
+
+ var x1 = d3.scale.ordinal();
+
+ var y = d3.scale.linear()
+ .range([height, 0]);
+
+ var color = d3.scale.ordinal()
+ .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
+
+ var xAxis = d3.svg.axis()
+ .scale(x0)
+ .orient("bottom");
+
+ var yAxis = d3.svg.axis()
+ .scale(y)
+ .orient("left")
+ .tickFormat(d3.format(".2s"));
+
+ var svg = d3.select("body").append("svg")
+ .attr("width", width + margin.left + margin.right)
+ .attr("height", height + margin.top + margin.bottom)
+ .append("g")
+ .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+
+ d3.csv("data.csv", function (error, data) {
+ var ageNames = d3.keys(data[0]).filter(function (key) { return key !== "State"; });
+
+ data.forEach(function (d) {
+ d.ages = ageNames.map(function (name) { return { name: name, value: +d[name] }; });
+ });
+
+ x0.domain(data.map(function (d) { return d.State; }));
+ x1.domain(ageNames).rangeRoundBands([0, x0.rangeBand()]);
+ y.domain([0, d3.max(data, function (d) { return d3.max(d.ages, function (d) { return d.value; }); })]);
+
+ svg.append("g")
+ .attr("class", "x axis")
+ .attr("transform", "translate(0," + height + ")")
+ .call(xAxis);
+
+ svg.append("g")
+ .attr("class", "y axis")
+ .call(yAxis)
+ .append("text")
+ .attr("transform", "rotate(-90)")
+ .attr("y", 6)
+ .attr("dy", ".71em")
+ .style("text-anchor", "end")
+ .text("Population");
+
+ var state = svg.selectAll(".state")
+ .data(data)
+ .enter().append("g")
+ .attr("class", "g")
+ .attr("transform", function (d) { return "translate(" + x0(d.State) + ",0)"; });
+
+ state.selectAll("rect")
+ .data(function (d) { return d.ages; })
+ .enter().append("rect")
+ .attr("width", x1.rangeBand())
+ .attr("x", function (d) { return x1(d.name); })
+ .attr("y", function (d) { return y(d.value); })
+ .attr("height", function (d) { return height - y(d.value); })
+ .style("fill", function (d) { return color(d.name); });
+
+ var legend = svg.selectAll(".legend")
+ .data(ageNames.reverse())
+ .enter().append("g")
+ .attr("class", "legend")
+ .attr("transform", function (d, i) { return "translate(0," + i * 20 + ")"; });
+
+ legend.append("rect")
+ .attr("x", width - 18)
+ .attr("width", 18)
+ .attr("height", 18)
+ .style("fill", color);
+
+ legend.append("text")
+ .attr("x", width - 24)
+ .attr("y", 9)
+ .attr("dy", ".35em")
+ .style("text-anchor", "end")
+ .text(function (d) { return d; });
+
+ });
+}
+
+//Example from http://bl.ocks.org/3886208
+function stackedBarChart() {
+ var margin = { top: 20, right: 20, bottom: 30, left: 40 },
+ width = 960 - margin.left - margin.right,
+ height = 500 - margin.top - margin.bottom;
+
+ var x = d3.scale.ordinal()
+ .rangeRoundBands([0, width], .1);
+
+ var y = d3.scale.linear()
+ .rangeRound([height, 0]);
+
+ var color = d3.scale.ordinal()
+ .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
+
+ var xAxis = d3.svg.axis()
+ .scale(x)
+ .orient("bottom");
+
+ var yAxis = d3.svg.axis()
+ .scale(y)
+ .orient("left")
+ .tickFormat(d3.format(".2s"));
+
+ var svg = d3.select("body").append("svg")
+ .attr("width", width + margin.left + margin.right)
+ .attr("height", height + margin.top + margin.bottom)
+ .append("g")
+ .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+
+ d3.csv("data.csv", function (error, data) {
+ color.domain(d3.keys(data[0]).filter(function (key) { return key !== "State"; }));
+
+ data.forEach(function (d) {
+ var y0 = 0;
+ d.ages = color.domain().map(function (name) { return { name: name, y0: y0, y1: y0 += +d[name] }; });
+ d.total = d.ages[d.ages.length - 1].y1;
+ });
+
+ data.sort(function (a, b) { return b.total - a.total; });
+
+ x.domain(data.map(function (d) { return d.State; }));
+ y.domain([0, d3.max(data, function (d) { return d.total; })]);
+
+ svg.append("g")
+ .attr("class", "x axis")
+ .attr("transform", "translate(0," + height + ")")
+ .call(xAxis);
+
+ svg.append("g")
+ .attr("class", "y axis")
+ .call(yAxis)
+ .append("text")
+ .attr("transform", "rotate(-90)")
+ .attr("y", 6)
+ .attr("dy", ".71em")
+ .style("text-anchor", "end")
+ .text("Population");
+
+ var state = svg.selectAll(".state")
+ .data(data)
+ .enter().append("g")
+ .attr("class", "g")
+ .attr("transform", function (d) { return "translate(" + x(d.State) + ",0)"; });
+
+ state.selectAll("rect")
+ .data(function (d) { return d.ages; })
+ .enter().append("rect")
+ .attr("width", x.rangeBand())
+ .attr("y", function (d) { return y(d.y1); })
+ .attr("height", function (d) { return y(d.y0) - y(d.y1); })
+ .style("fill", function (d) { return color(d.name); });
+
+ var legend = svg.selectAll(".legend")
+ .data(color.domain().reverse())
+ .enter().append("g")
+ .attr("class", "legend")
+ .attr("transform", function (d, i) { return "translate(0," + i * 20 + ")"; });
+
+ legend.append("rect")
+ .attr("x", width - 18)
+ .attr("width", 18)
+ .attr("height", 18)
+ .style("fill", color);
+
+ legend.append("text")
+ .attr("x", width - 24)
+ .attr("y", 9)
+ .attr("dy", ".35em")
+ .style("text-anchor", "end")
+ .text(function (d) { return d; });
+
+ });
+}
+
+// example from http://bl.ocks.org/3886394
+function normalizedBarChart() {
+ var margin = { top: 20, right: 100, bottom: 30, left: 40 },
+ width = 960 - margin.left - margin.right,
+ height = 500 - margin.top - margin.bottom;
+
+ var x = d3.scale.ordinal()
+ .rangeRoundBands([0, width], .1);
+
+ var y = d3.scale.linear()
+ .rangeRound([height, 0]);
+
+ var color = d3.scale.ordinal()
+ .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
+
+ var xAxis = d3.svg.axis()
+ .scale(x)
+ .orient("bottom");
+
+ var yAxis = d3.svg.axis()
+ .scale(y)
+ .orient("left")
+ .tickFormat(d3.format(".0%"));
+
+ var svg = d3.select("body").append("svg")
+ .attr("width", width + margin.left + margin.right)
+ .attr("height", height + margin.top + margin.bottom)
+ .append("g")
+ .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+
+ d3.csv("data.csv", function (error, data) {
+ color.domain(d3.keys(data[0]).filter(function (key) { return key !== "State"; }));
+
+ data.forEach(function (d) {
+ var y0 = 0;
+ d.ages = color.domain().map(function (name) { return { name: name, y0: y0, y1: y0 += +d[name] }; });
+ d.ages.forEach(function (d) { d.y0 /= y0; d.y1 /= y0; });
+ });
+
+ data.sort(function (a, b) { return b.ages[0].y1 - a.ages[0].y1; });
+
+ x.domain(data.map(function (d) { return d.State; }));
+
+ svg.append("g")
+ .attr("class", "x axis")
+ .attr("transform", "translate(0," + height + ")")
+ .call(xAxis);
+
+ svg.append("g")
+ .attr("class", "y axis")
+ .call(yAxis);
+
+ var state = svg.selectAll(".state")
+ .data(data)
+ .enter().append("g")
+ .attr("class", "state")
+ .attr("transform", function (d) { return "translate(" + x(d.State) + ",0)"; });
+
+ state.selectAll("rect")
+ .data(function (d) { return d.ages; })
+ .enter().append("rect")
+ .attr("width", x.rangeBand())
+ .attr("y", function (d) { return y(d.y1); })
+ .attr("height", function (d) { return y(d.y0) - y(d.y1); })
+ .style("fill", function (d) { return color(d.name); });
+
+ var legend = svg.select(".state:last-child").selectAll(".legend")
+ .data(function (d) { return d.ages; })
+ .enter().append("g")
+ .attr("class", "legend")
+ .attr("transform", function (d) { return "translate(" + x.rangeBand() / 2 + "," + y((d.y0 + d.y1) / 2) + ")"; });
+
+ legend.append("line")
+ .attr("x2", 10);
+
+ legend.append("text")
+ .attr("x", 13)
+ .attr("dy", ".35em")
+ .text(function (d) { return d.name; });
+
+ });
+}
+
+// example from http://bl.ocks.org/3885705
+function sortablebarChart() {
+ var margin = { top: 20, right: 20, bottom: 30, left: 40 },
+ width = 960 - margin.left - margin.right,
+ height = 500 - margin.top - margin.bottom;
+
+ var formatPercent = d3.format(".0%");
+
+ var x = d3.scale.ordinal()
+ .rangeRoundBands([0, width], .1, 1);
+
+ var y = d3.scale.linear()
+ .range([height, 0]);
+
+ var xAxis = d3.svg.axis()
+ .scale(x)
+ .orient("bottom");
+
+ var yAxis = d3.svg.axis()
+ .scale(y)
+ .orient("left")
+ .tickFormat(formatPercent);
+
+ var svg = d3.select("body").append("svg")
+ .attr("width", width + margin.left + margin.right)
+ .attr("height", height + margin.top + margin.bottom)
+ .append("g")
+ .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+
+ d3.tsv("data.tsv", function (error, data) {
+
+ data.forEach(function (d) {
+ d.frequency = +d.frequency;
+ });
+
+ x.domain(data.map(function (d) { return d.letter; }));
+ y.domain([0, d3.max(data, function (d) { return d.frequency; })]);
+
+ svg.append("g")
+ .attr("class", "x axis")
+ .attr("transform", "translate(0," + height + ")")
+ .call(xAxis);
+
+ svg.append("g")
+ .attr("class", "y axis")
+ .call(yAxis)
+ .append("text")
+ .attr("transform", "rotate(-90)")
+ .attr("y", 6)
+ .attr("dy", ".71em")
+ .style("text-anchor", "end")
+ .text("Frequency");
+
+ svg.selectAll(".bar")
+ .data(data)
+ .enter().append("rect")
+ .attr("class", "bar")
+ .attr("x", function (d) { return x(d.letter); })
+ .attr("width", x.rangeBand())
+ .attr("y", function (d) { return y(d.frequency); })
+ .attr("height", function (d) { return height - y(d.frequency); });
+
+ d3.select("input").on("change", change);
+
+ var sortTimeout = setTimeout(function () {
+ d3.select("input").property("checked", true).each(change);
+ }, 2000);
+
+ function change() {
+ clearTimeout(sortTimeout);
+
+ var x0 = x.domain(data.sort(this.checked
+ ? function (a, b) { return b.frequency - a.frequency; }
+ : function (a, b) { return d3.ascending(a.letter, b.letter); })
+ .map(function (d) { return d.letter; }))
+ .copy();
+
+ var transition = svg.transition().duration(750),
+ delay = function (d, i) { return i * 50; };
+
+ transition.selectAll(".bar")
+ .delay(delay)
+ .attr("x", function (d) { return x0(d.letter); });
+
+ transition.select(".x.axis")
+ .call(xAxis)
+ .selectAll("g")
+ .delay(delay);
+ }
+ });
+}
+
+//example from http://bl.ocks.org/4063318
+function callenderView() {
+ var width = 960,
+ height = 136,
+ cellSize = 17; // cell size
+
+ var day = d3.time.format("%w"),
+ week = d3.time.format("%U"),
+ percent = d3.format(".1%"),
+ format = d3.time.format("%Y-%m-%d");
+
+ var color = d3.scale.quantize()
+ .domain([-.05, .05])
+ .range(d3.range(11).map(function (d) { return "q" + d + "-11"; }));
+
+ var svg = d3.select("body").selectAll("svg")
+ .data(d3.range(1990, 2011))
+ .enter().append("svg")
+ .attr("width", width)
+ .attr("height", height)
+ .attr("class", "RdYlGn")
+ .append("g")
+ .attr("transform", "translate(" + ((width - cellSize * 53) / 2) + "," + (height - cellSize * 7 - 1) + ")");
+
+ svg.append("text")
+ .attr("transform", "translate(-6," + cellSize * 3.5 + ")rotate(-90)")
+ .style("text-anchor", "middle")
+ .text(function (d) { return d; });
+
+ var rect = svg.selectAll(".day")
+ .data(function (d) { return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
+ .enter().append("rect")
+ .attr("class", "day")
+ .attr("width", cellSize)
+ .attr("height", cellSize)
+ .attr("x", function (d) { return parseInt(week(d)) * cellSize; })
+ .attr("y", function (d) { return parseInt(day(d)) * cellSize; })
+ .datum(format);
+
+ rect.append("title")
+ .text(function (d) { return d; });
+
+ svg.selectAll(".month")
+ .data(function (d) { return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
+ .enter().append("path")
+ .attr("class", "month")
+ .attr("d", monthPath);
+
+ d3.csv("dji.csv", function (error, csv) {
+ var data = d3.nest()
+ .key(function (d) { return d.Date; })
+ .rollup(function (d) { return (d[0].Close - d[0].Open) / d[0].Open; })
+ .map(csv);
+
+ rect.filter(function (d) { return d in data; })
+ .attr("class", function (d) { return "day " + color(data[d]); })
+ .select("title")
+ .text(function (d) { return d + ": " + percent(data[d]); });
+ });
+
+ function monthPath(t0) {
+ var t1 = new Date(t0.getFullYear(), t0.getMonth() + 1, 0),
+ d0 = +day(t0), w0 = +week(t0),
+ d1 = +day(t1), w1 = +week(t1);
+ return "M" + (w0 + 1) * cellSize + "," + d0 * cellSize
+ + "H" + w0 * cellSize + "V" + 7 * cellSize
+ + "H" + w1 * cellSize + "V" + (d1 + 1) * cellSize
+ + "H" + (w1 + 1) * cellSize + "V" + 0
+ + "H" + (w0 + 1) * cellSize + "Z";
+ }
+
+ d3.select(self.frameElement).style("height", "2910px");
+}
+
+// example from http://bl.ocks.org/3883245
+function lineChart {
+ var margin = { top: 20, right: 20, bottom: 30, left: 50 },
+ width = 960 - margin.left - margin.right,
+ height = 500 - margin.top - margin.bottom;
+
+ var parseDate = d3.time.format("%d-%b-%y").parse;
+
+ var x = d3.time.scale()
+ .range([0, width]);
+
+ var y = d3.scale.linear()
+ .range([height, 0]);
+
+ var xAxis = d3.svg.axis()
+ .scale(x)
+ .orient("bottom");
+
+ var yAxis = d3.svg.axis()
+ .scale(y)
+ .orient("left");
+
+ var line = d3.svg.line()
+ .x(function (d) { return x(d.date); })
+ .y(function (d) { return y(d.close); });
+
+ var svg = d3.select("body").append("svg")
+ .attr("width", width + margin.left + margin.right)
+ .attr("height", height + margin.top + margin.bottom)
+ .append("g")
+ .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+
+ d3.tsv("data.tsv", function (error, data) {
+ data.forEach(function (d) {
+ d.date = parseDate(d.date);
+ d.close = +d.close;
+ });
+
+ x.domain(d3.extent(data, function (d) { return d.date; }));
+ y.domain(d3.extent(data, function (d) { return d.close; }));
+
+ svg.append("g")
+ .attr("class", "x axis")
+ .attr("transform", "translate(0," + height + ")")
+ .call(xAxis);
+
+ svg.append("g")
+ .attr("class", "y axis")
+ .call(yAxis)
+ .append("text")
+ .attr("transform", "rotate(-90)")
+ .attr("y", 6)
+ .attr("dy", ".71em")
+ .style("text-anchor", "end")
+ .text("Price ($)");
+
+ svg.append("path")
+ .datum(data)
+ .attr("class", "line")
+ .attr("d", line);
+ });
+}
+
+//example from http://bl.ocks.org/3884914
+function bivariateAreaChart {
+ var margin = { top: 20, right: 20, bottom: 30, left: 50 },
+ width = 960 - margin.left - margin.right,
+ height = 500 - margin.top - margin.bottom;
+
+ var parseDate = d3.time.format("%Y%m%d").parse;
+
+ var x = d3.time.scale()
+ .range([0, width]);
+
+ var y = d3.scale.linear()
+ .range([height, 0]);
+
+ var xAxis = d3.svg.axis()
+ .scale(x)
+ .orient("bottom");
+
+ var yAxis = d3.svg.axis()
+ .scale(y)
+ .orient("left");
+
+ var area = d3.svg.area()
+ .x(function (d) { return x(d.date); })
+ .y0(function (d) { return y(d.low); })
+ .y1(function (d) { return y(d.high); });
+
+ var svg = d3.select("body").append("svg")
+ .attr("width", width + margin.left + margin.right)
+ .attr("height", height + margin.top + margin.bottom)
+ .append("g")
+ .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+
+ d3.tsv("data.tsv", function (error, data) {
+ data.forEach(function (d) {
+ d.date = parseDate(d.date);
+ d.low = +d.low;
+ d.high = +d.high;
+ });
+
+ x.domain(d3.extent(data, function (d) { return d.date; }));
+ y.domain([d3.min(data, function (d) { return d.low; }), d3.max(data, function (d) { return d.high; })]);
+
+ svg.append("path")
+ .datum(data)
+ .attr("class", "area")
+ .attr("d", area);
+
+ svg.append("g")
+ .attr("class", "x axis")
+ .attr("transform", "translate(0," + height + ")")
+ .call(xAxis);
+
+ svg.append("g")
+ .attr("class", "y axis")
+ .call(yAxis)
+ .append("text")
+ .attr("transform", "rotate(-90)")
+ .attr("y", 6)
+ .attr("dy", ".71em")
+ .style("text-anchor", "end")
+ .text("Temperature (şF)");
+ });
+}
diff --git a/d3/d3.d.ts b/d3/d3.d.ts
index 10b084d8c..939ea0df4 100644
--- a/d3/d3.d.ts
+++ b/d3/d3.d.ts
@@ -1,387 +1,727 @@
-interface ID3Selectors {
- select: (selector: string) => ID3Selection;
- selectAll: (selector: string) => ID3Selection;
-}
-
-interface ID3behavior
-{
- drag: () => any;
- zoom: () => any;
-}
-
-interface ID3event
-{
- dx: number;
- dy: number;
- clientX: number;
- clientY: number;
- translate:number[];
- scale: number;
- sourceEvent: ID3event;
-}
-
-interface ID3Base extends ID3Selectors {
- // behavior
- behavior: ID3behavior;
- event: ID3event;
- // Array Helpers
- ascending: (a: number, b: number) => number;
- descending: (a: number, b: number) => number;
- min: (arr: any[], map?: (v: any) => any ) => any;
- max: (arr: any[], map?: (v: any) => any ) => any;
- extent: (arr: any[], map?: (v: any) => any ) => any[];
- quantile: (arr: number[], p: number) => number;
- bisectLeft: (arr: any[], x: any, low?: number, high?: number) => number;
- bisect: (arr: any[], x: any, low?: number, high?: number) => number;
- bisectRight: (arr: any[], x: any, low?: number, high?: number) => number;
- first: (arr: any[], comparator: (a: any, b: any) => any ) => any;
- last: (arr: any[], comparator: (a: any, b:any) => any ) => any;
-
- // Loading resources
- xhr: {
- (url: string, callback: (xhr: XMLHttpRequest) => void): void;
- (url: string, mime: string, callback: (xhr: XMLHttpRequest) => void): void;
- };
- text: {
- (url: string, callback: (response: string) => void): void;
- (url: string, mime: string, callback: (response: string) => void): void;
- };
- json: (url: string, callback: (response: any) => void) => void;
- xml: {
- (url: string, callback: (response: Document) => void): void;
- (url: string, mime: string, callback: (response: Document) => void): void;
- };
- html: (url: string, callback: (response: DocumentFragment) => void) => void;
- csv: {
- (url: string, callback: (error: any, response: any[]) => void);
- parse(string: string): any[];
- parseRows(string: string, accessor: (row: any[], index: number) => any): any;
- format(rows: any[]): string;
- };
-
- time: ID3Time;
- scale: {
- linear(): ID3LinearScale;
- ordinal(): ID3OrdinalScale;
- category10(): ID3OrdinalScale;
- category20(): ID3OrdinalScale;
- category20b(): ID3OrdinalScale;
- category20c(): ID3OrdinalScale;
- };
- interpolate: ID3BaseInterpolate;
- interpolateNumber: ID3BaseInterpolate;
- interpolateRound: ID3BaseInterpolate;
- interpolateString: ID3BaseInterpolate;
- interpolateRgb: ID3BaseInterpolate;
- interpolateHsl: ID3BaseInterpolate;
- interpolateArray: ID3BaseInterpolate;
- interpolateObject: ID3BaseInterpolate;
- interpolateTransform: ID3BaseInterpolate;
- layout: ID3Layout;
- svg: ID3Svg;
- random: ID3Random;
- keys(map: Object): any[];
-}
-
-interface ID3Selection extends ID3Selectors {
- attr: {
- (name: string): string;
- (name: string, value: any): ID3Selection;
- (name: string, valueFunction: (data: any, index: number) => any): ID3Selection;
- };
-
- classed: {
- (name: string): string;
- (name: string, value: any): ID3Selection;
- (name: string, valueFunction: (data: any, index: number) => any): ID3Selection;
- };
-
- style: {
- (name: string): string;
- (name: string, value: any, priority?: string): ID3Selection;
- (name: string, valueFunction: (data: any, index: number) => any, priority?: string): ID3Selection;
- };
-
- property: {
- (name: string): void;
- (name: string, value: any): ID3Selection;
- (name: string, valueFunction: (data: any, index: number) => any): ID3Selection;
- };
-
- text: {
- (): string;
- (value: any): ID3Selection;
- (valueFunction: (data: any, index: number) => any): ID3Selection;
- };
-
- html: {
- (): string;
- (value: any): ID3Selection;
- (valueFunction: (data: any, index: number) => any): ID3Selection;
- };
-
- append: (name: string) => ID3Selection;
- insert: (name: string, before: string) => ID3Selection;
- remove: () => ID3Selection;
-
- data: {
- (values: (data: any, index: number) => any) : any;
- (values: any[], key?: (data: any, index: number) => any): ID3UpdateSelection;
- };
-
- call(callback: (selection: ID3Selection) => void): ID3Selection;
-}
-
-interface ID3EnterSelection {
- append: (name: string) => ID3Selection;
- insert: (name: string, before: string) => ID3Selection;
- select: (selector: string) => ID3Selection;
- empty: () => bool;
- node: () => Node;
-}
-
-interface ID3UpdateSelection extends ID3Selection {
- enter: () => ID3EnterSelection;
- update: () => ID3Selection;
- exit: () => ID3Selection;
-}
-
-interface ID3Time {
- second: ID3Interval;
- minute: ID3Interval;
- hour: ID3Interval;
- day: ID3Interval;
- week: ID3Interval;
- sunday: ID3Interval;
- monday: ID3Interval;
- tuesday: ID3Interval;
- wednesday: ID3Interval;
- thursday: ID3Interval;
- friday: ID3Interval;
- saturday: ID3Interval;
- month: ID3Interval;
- year: ID3Interval;
-
- seconds: ID3Range;
- minutes: ID3Range;
- hours: ID3Range;
- days: ID3Range;
- weeks: ID3Range;
- months: ID3Range;
- years: ID3Range;
-
- sundays: ID3Range;
- mondays: ID3Range;
- tuesdays: ID3Range;
- wednesdays: ID3Range;
- thursdays: ID3Range;
- fridays: ID3Range;
- saturdays: ID3Range;
- format: {
-
- (specifier: string): ID3TimeFormat;
- utc: (specifier: string) => ID3TimeFormat;
- iso: ID3TimeFormat;
- };
-
- scale(): ID3TimeScale;
-}
-
-interface ID3Range {
- (start: Date, end: Date, step?: number): Date[];
-}
-
-interface ID3Interval {
- (date: Date): Date;
- floor: (date: Date) => Date;
- round: (date: Date) => Date;
- ceil: (date: Date) => Date;
- range: ID3Range;
- offset: (date: Date, step: number) => Date;
- utc: ID3Interval;
-}
-
-interface ID3TimeFormat {
- (date: Date): string;
- parse: (string: string) => Date;
-}
-
-interface ID3LinearScale {
- (value: number): number;
- invert(value: number): number;
- domain(numbers: any[]): ID3LinearScale;
- range: {
- (values: any[]): ID3LinearScale;
- (): any[];
- };
- rangeRound: (values: any[]) => ID3LinearScale;
- interpolate: {
- (): ID3Interpolate;
- (factory: ID3Interpolate): ID3LinearScale;
- };
- clamp(clamp: bool): ID3LinearScale;
- nice(): ID3LinearScale;
- ticks(count: number): any[];
- tickFormat(count: number): (n: number) => string;
- copy: ID3LinearScale;
-}
-
-interface ID3OrdinalScale {
- (value: any): any;
- domain(values: any[]): ID3OrdinalScale;
- range: {
- (values: any[]): ID3OrdinalScale;
- (): any[];
- };
- rangePoints(interval: any[], padding?: number): ID3OrdinalScale;
- rangeBands(interval: any[], padding?: number, outerPadding?: number): ID3OrdinalScale;
- rangeRoundBands(interval: any[], padding?: number, outerPadding?: number): ID3OrdinalScale;
- rangeBand(): any[];
- rangeExtent(): any[];
- copy: ID3OrdinalScale;
-}
-
-interface ID3TimeScale {
- (value: Date): number;
- invert(value: number): Date;
- domain(numbers: any[]): ID3TimeScale;
- range: {
- (values: any[]): ID3TimeScale;
- (): any[];
- };
- rangeRound: (values: any[]) => ID3TimeScale;
- interpolate: {
- (): ID3Interpolate;
- (factory: ID3InterpolateFactory): ID3TimeScale;
- };
- clamp(clamp: bool): ID3TimeScale;
- ticks: {
- (count: number): any[];
- (range: ID3Range, count: number): any[];
- };
- tickFormat(count: number): (n: number) => string;
- copy(): ID3TimeScale;
-}
-
-interface ID3InterpolateFactory {
- (a: any, b: any): ID3BaseInterpolate;
-}
-interface ID3BaseInterpolate {
- (a: any, b: any): ID3Interpolate;
-}
-
-interface ID3Interpolate {
- (t: number): number;
-}
-
-interface ID3Layout {
- stack(): ID3StackLayout;
- pie(): ID3PieLayout;
-}
-
-interface ID3StackLayout {
- (layers: any[], index?: number): any[];
- values(accessor?: (d: any) => any): ID3StackLayout;
- offset(offset: string): ID3StackLayout;
-}
-
-interface ID3PieLayout {
- (values: any[], index?: number): ID3ArcDescriptor[];
- value: {
- (): (d: any, index: number) => number;
- (accessor: (d: any, index: number) => number): ID3PieLayout;
- };
- sort: {
- (): (d1: any, d2: any) => number;
- (comparator: (d1: any, d2: any) => number): ID3PieLayout;
- };
- startAngle: {
- (): number;
- (angle: number): ID3SvgArc;
- (angle: () => number): ID3SvgArc;
- };
- endAngle: {
- (): number;
- (angle: number): ID3SvgArc;
- (angle: () => number): ID3SvgArc;
- };
-}
-
-interface ID3ArcDescriptor {
- value: any;
- data: any;
- startAngle: number;
- endAngle: number;
-}
-
-interface ID3SVGSymbol
-{
- type: (string) => ID3SVGSymbol;
- size: (number) => ID3SVGSymbol;
-}
-
-interface ID3Svg {
- symbol: ()=> ID3SVGSymbol;
- axis(): ID3SvgAxis;
- arc(): ID3SvgArc;
-}
-
-interface ID3SvgAxis {
- (selection: ID3Selection): void;
- scale: {
- (): any;
- (scale: any): ID3SvgAxis;
- };
-
- orient: {
- (): string;
- (orientation: string): ID3SvgAxis;
- };
-
- ticks: {
- (count: number): ID3SvgAxis;
- (range: ID3Range, count?: number): ID3SvgAxis;
- };
-
- tickSubdivide(count: number): ID3SvgAxis;
- tickSize(major?: number, minor?: number, end?: number): ID3SvgAxis;
- tickFormat(formatter: (value: any) => string): ID3SvgAxis;
-}
-
-interface ID3SvgArc {
- (options?: ID3SvgArcOptions): string;
- innerRadius: {
- (): number;
- (radius: number): ID3SvgArc;
- (radius: () => number): ID3SvgArc;
- };
- outerRadius: {
- (): number;
- (radius: number): ID3SvgArc;
- (radius: () => number): ID3SvgArc;
- };
- startAngle: {
- (): number;
- (angle: number): ID3SvgArc;
- (angle: () => number): ID3SvgArc;
- };
- endAngle: {
- (): number;
- (angle: number): ID3SvgArc;
- (angle: () => number): ID3SvgArc;
- };
- centroid(options?: ID3SvgArcOptions): number[];
-}
-
-interface ID3SvgArcOptions {
- innerRadius?: number;
- outerRadius?: number;
- startAngle?: number;
- endAngle?: number;
-}
-
-interface ID3Random {
- normal(mean?: number, deviation?: number): () => number;
-}
-
-declare var d3: ID3Base;
+interface ID3Selectors {
+ select: {
+ (selector: string): ID3Selection;
+ (element: Element): ID3Selection;
+ };
+ selectAll: {
+ (selector: string): ID3Selection;
+ (elements: Element[]): ID3Selection;
+ };
+}
+
+interface ID3behavior
+{
+ drag: () => any;
+ zoom: () => any;
+}
+
+interface ID3event
+{
+ dx: number;
+ dy: number;
+ clientX: number;
+ clientY: number;
+ translate:number[];
+ scale: number;
+ sourceEvent: ID3event;
+}
+
+interface ID3Base extends ID3Selectors {
+ // behavior
+ behavior: ID3behavior;
+ event: ID3event;
+ // Array Helpers
+ ascending: (a: number, b: number) => number;
+ descending: (a: number, b: number) => number;
+ min: (arr: any[], map?: (v: any) => any ) => any;
+ max: (arr: any[], map?: (v: any) => any ) => any;
+ extent: (arr: any[], map?: (v: any) => any ) => any[];
+ quantile: (arr: number[], p: number) => number;
+ bisectLeft: (arr: any[], x: any, low?: number, high?: number) => number;
+ bisect: (arr: any[], x: any, low?: number, high?: number) => number;
+ bisectRight: (arr: any[], x: any, low?: number, high?: number) => number;
+ first: (arr: any[], comparator: (a: any, b: any) => any ) => any;
+ last: (arr: any[], comparator: (a: any, b: any) => any) => any;
+ range:(start: number, stop?: number, step?: number) => number[];
+
+ // Loading resources
+ xhr: {
+ (url: string, callback: (xhr: XMLHttpRequest) => void): void;
+ (url: string, mime: string, callback: (xhr: XMLHttpRequest) => void): void;
+ };
+ text: {
+ (url: string, callback: (response: string) => void): void;
+ (url: string, mime: string, callback: (response: string) => void): void;
+ };
+ json: (url: string, callback: (response: any) => void) => void;
+ xml: {
+ (url: string, callback: (response: Document) => void): void;
+ (url: string, mime: string, callback: (response: Document) => void): void;
+ };
+ html: (url: string, callback: (response: DocumentFragment) => void) => void;
+ csv: {
+ (url: string, callback: (error: any, response: any[]) => void);
+ parse(string: string): any[];
+ parseRows(string: string, accessor: (row: any[], index: number) => any): any;
+ format(rows: any[]): string;
+ };
+ tsv: {
+ (url: string, callback: (error: any, response: any[]) => void );
+ parse(string: string): any[];
+ parseRows(string: string, accessor: (row: any[], index: number) => any): any;
+ format(rows: any[]): string;
+ };
+
+ time: ID3Time;
+ scale: {
+ linear(): ID3LinearScale;
+ ordinal(): ID3OrdinalScale;
+ quantize(): ID3QuantizeScale;
+ category10(): ID3OrdinalScale;
+ category20(): ID3OrdinalScale;
+ category20b(): ID3OrdinalScale;
+ category20c(): ID3OrdinalScale;
+ };
+ interpolate: ID3BaseInterpolate;
+ interpolateNumber: ID3BaseInterpolate;
+ interpolateRound: ID3BaseInterpolate;
+ interpolateString: ID3BaseInterpolate;
+ interpolateRgb: ID3BaseInterpolate;
+ interpolateHsl: ID3BaseInterpolate;
+ interpolateArray: ID3BaseInterpolate;
+ interpolateObject: ID3BaseInterpolate;
+ interpolateTransform: ID3BaseInterpolate;
+ layout: ID3Layout;
+ svg: ID3Svg;
+ random: ID3Random;
+ keys(map: Object): any[];
+
+ format(specifier: string): (value: number) => string;
+
+ nest(): ID3Nest;
+}
+
+interface ID3Selection extends ID3Selectors {
+ attr: {
+ (name: string): string;
+ (name: string, value: any): ID3Selection;
+ (name: string, valueFunction: (data: any, index: number) => any): ID3Selection;
+ };
+
+ classed: {
+ (name: string): string;
+ (name: string, value: any): ID3Selection;
+ (name: string, valueFunction: (data: any, index: number) => any): ID3Selection;
+ };
+
+ style: {
+ (name: string): string;
+ (name: string, value: any, priority?: string): ID3Selection;
+ (name: string, valueFunction: (data: any, index: number) => any, priority?: string): ID3Selection;
+ };
+
+ property: {
+ (name: string): void;
+ (name: string, value: any): ID3Selection;
+ (name: string, valueFunction: (data: any, index: number) => any): ID3Selection;
+ };
+
+ text: {
+ (): string;
+ (value: any): ID3Selection;
+ (valueFunction: (data: any, index: number) => any): ID3Selection;
+ };
+
+ html: {
+ (): string;
+ (value: any): ID3Selection;
+ (valueFunction: (data: any, index: number) => any): ID3Selection;
+ };
+
+ append: (name: string) => ID3Selection;
+ insert: (name: string, before: string) => ID3Selection;
+ remove: () => ID3Selection;
+
+ data: {
+ (values: (data: any, index: number) => any): ID3UpdateSelection;
+ (values: any[], key?: (data: any, index: number) => any): ID3UpdateSelection;
+ };
+
+ datum: {
+ (values: (data: any, index: number) => any): ID3UpdateSelection;
+ (values: any): ID3UpdateSelection;
+ };
+
+ filter: {
+ (filter: (data: any, index: number) => bool): ID3UpdateSelection;
+ (filter: string): ID3UpdateSelection;
+ };
+
+ call(callback: (selection: ID3Selection) => void ): ID3Selection;
+ each(eachFunction: (data: any, index: number) => any): ID3Selection;
+ on: {
+ (type: string): (data: any, index: number) => any;
+ (type: string, listener: (data: any, index: number) => any, capture?: bool): ID3Selection;
+ };
+
+ transition: () => ID3Transition;
+}
+
+interface ID3EnterSelection {
+ append: (name: string) => ID3Selection;
+ insert: (name: string, before: string) => ID3Selection;
+ select: (selector: string) => ID3Selection;
+ empty: () => bool;
+ node: () => Node;
+}
+
+interface ID3UpdateSelection extends ID3Selection {
+ enter: () => ID3EnterSelection;
+ update: () => ID3Selection;
+ exit: () => ID3Selection;
+}
+
+interface ID3Transition {
+ duration: {
+ (duration: number): ID3Transition;
+ (duration: (data: any, index: number) => any): ID3Transition;
+ };
+ delay: {
+ (delay: number): ID3Transition;
+ (delay: (data: any, index: number) => any): ID3Transition;
+ };
+ attr: {
+ (name: string): string;
+ (name: string, value: any): ID3Transition;
+ (name: string, valueFunction: (data: any, index: number) => any): ID3Transition;
+ };
+ call(callback: (selection: ID3Selection) => void ): ID3Transition;
+
+ select: (selector: string) => ID3Transition;
+ selectAll: (selector: string) => ID3Transition;
+}
+
+interface ID3Nest {
+ key(keyFunction: (data: any, index: number) => any): ID3Nest;
+ rollup(rollupFunction: (data: any, index: number) => any): ID3Nest;
+ map(values: any[]): ID3Nest;
+}
+
+interface ID3Time {
+ second: ID3Interval;
+ minute: ID3Interval;
+ hour: ID3Interval;
+ day: ID3Interval;
+ week: ID3Interval;
+ sunday: ID3Interval;
+ monday: ID3Interval;
+ tuesday: ID3Interval;
+ wednesday: ID3Interval;
+ thursday: ID3Interval;
+ friday: ID3Interval;
+ saturday: ID3Interval;
+ month: ID3Interval;
+ year: ID3Interval;
+
+ seconds: ID3Range;
+ minutes: ID3Range;
+ hours: ID3Range;
+ days: ID3Range;
+ weeks: ID3Range;
+ months: ID3Range;
+ years: ID3Range;
+
+ sundays: ID3Range;
+ mondays: ID3Range;
+ tuesdays: ID3Range;
+ wednesdays: ID3Range;
+ thursdays: ID3Range;
+ fridays: ID3Range;
+ saturdays: ID3Range;
+ format: {
+
+ (specifier: string): ID3TimeFormat;
+ utc: (specifier: string) => ID3TimeFormat;
+ iso: ID3TimeFormat;
+ };
+
+ scale(): ID3TimeScale;
+}
+
+interface ID3Range {
+ (start: Date, end: Date, step?: number): Date[];
+}
+
+interface ID3Interval {
+ (date: Date): Date;
+ floor: (date: Date) => Date;
+ round: (date: Date) => Date;
+ ceil: (date: Date) => Date;
+ range: ID3Range;
+ offset: (date: Date, step: number) => Date;
+ utc: ID3Interval;
+}
+
+interface ID3TimeFormat {
+ (date: Date): string;
+ parse: (string: string) => Date;
+}
+
+interface ID3LinearScale {
+ (value: number): number;
+ invert(value: number): number;
+ domain(numbers: any[]): ID3LinearScale;
+ range: {
+ (values: any[]): ID3LinearScale;
+ (): any[];
+ };
+ rangeRound: (values: any[]) => ID3LinearScale;
+ interpolate: {
+ (): ID3Interpolate;
+ (factory: ID3Interpolate): ID3LinearScale;
+ };
+ clamp(clamp: bool): ID3LinearScale;
+ nice(): ID3LinearScale;
+ ticks(count: number): any[];
+ tickFormat(count: number): (n: number) => string;
+ copy: ID3LinearScale;
+}
+
+interface ID3OrdinalScale {
+ (value: any): any;
+ domain: {
+ (values: any[]): ID3OrdinalScale;
+ (): any[];
+ };
+ range: {
+ (values: any[]): ID3OrdinalScale;
+ (): any[];
+ };
+ rangePoints(interval: any[], padding?: number): ID3OrdinalScale;
+ rangeBands(interval: any[], padding?: number, outerPadding?: number): ID3OrdinalScale;
+ rangeRoundBands(interval: any[], padding?: number, outerPadding?: number): ID3OrdinalScale;
+ rangeBand(): number;
+ rangeExtent(): any[];
+ copy: ID3OrdinalScale;
+}
+
+interface ID3QuantizeScale {
+ (value: any): any;
+ domain: {
+ (values: number[]): ID3QuantizeScale;
+ (): any[];
+ };
+ range: {
+ (values: any[]): ID3QuantizeScale;
+ (): any[];
+ };
+ copy: ID3QuantizeScale;
+}
+
+interface ID3TimeScale {
+ (value: Date): number;
+ invert(value: number): Date;
+ domain(numbers: any[]): ID3TimeScale;
+ range: {
+ (values: any[]): ID3TimeScale;
+ (): any[];
+ };
+ rangeRound: (values: any[]) => ID3TimeScale;
+ interpolate: {
+ (): ID3Interpolate;
+ (factory: ID3InterpolateFactory): ID3TimeScale;
+ };
+ clamp(clamp: bool): ID3TimeScale;
+ ticks: {
+ (count: number): any[];
+ (range: ID3Range, count: number): any[];
+ };
+ tickFormat(count: number): (n: number) => string;
+ copy(): ID3TimeScale;
+}
+
+interface ID3InterpolateFactory {
+ (a: any, b: any): ID3BaseInterpolate;
+}
+interface ID3BaseInterpolate {
+ (a: any, b: any): ID3Interpolate;
+}
+
+interface ID3Interpolate {
+ (t: number): number;
+}
+
+interface ID3Layout {
+ stack(): ID3StackLayout;
+ pie(): ID3PieLayout;
+}
+
+interface ID3StackLayout {
+ (layers: any[], index?: number): any[];
+ values(accessor?: (d: any) => any): ID3StackLayout;
+ offset(offset: string): ID3StackLayout;
+}
+
+interface ID3PieLayout {
+ (values: any[], index?: number): ID3ArcDescriptor[];
+ value: {
+ (): (d: any, index: number) => number;
+ (accessor: (d: any, index: number) => number): ID3PieLayout;
+ };
+ sort: {
+ (): (d1: any, d2: any) => number;
+ (comparator: (d1: any, d2: any) => number): ID3PieLayout;
+ };
+ startAngle: {
+ (): number;
+ (angle: number): ID3SvgArc;
+ (angle: () => number): ID3SvgArc;
+ };
+ endAngle: {
+ (): number;
+ (angle: number): ID3SvgArc;
+ (angle: () => number): ID3SvgArc;
+ };
+}
+
+interface ID3ArcDescriptor {
+ value: any;
+ data: any;
+ startAngle: number;
+ endAngle: number;
+}
+
+interface ID3SVGSymbol
+{
+ type: (string) => ID3SVGSymbol;
+ size: (number) => ID3SVGSymbol;
+}
+
+interface ID3Svg {
+ /**
+ * Create a new symbol generator
+ */
+ symbol: () => ID3SVGSymbol;
+ /**
+ * Create a new axis generator
+ */
+ axis(): ID3SvgAxis;
+ /**
+ * Create a new arc generator
+ */
+ arc(): ID3SvgArc;
+ /**
+ * Create a new line generator
+ */
+ line(): ID3SvgLine;
+ /**
+ * Create a new area generator
+ */
+ area(): ID3SvgArea;
+}
+
+interface ID3SvgAxis {
+ (selection: ID3Selection): void;
+ scale: {
+ (): any;
+ (scale: any): ID3SvgAxis;
+ };
+
+ orient: {
+ (): string;
+ (orientation: string): ID3SvgAxis;
+ };
+
+ ticks: {
+ (count: number): ID3SvgAxis;
+ (range: ID3Range, count?: number): ID3SvgAxis;
+ };
+
+ tickSubdivide(count: number): ID3SvgAxis;
+ tickSize(major?: number, minor?: number, end?: number): ID3SvgAxis;
+ tickFormat(formatter: (value: any) => string): ID3SvgAxis;
+}
+
+interface ID3SvgArc {
+ (options?: ID3SvgArcOptions): string;
+ innerRadius: {
+ (): number;
+ (radius: number): ID3SvgArc;
+ (radius: () => number): ID3SvgArc;
+ };
+ outerRadius: {
+ (): number;
+ (radius: number): ID3SvgArc;
+ (radius: () => number): ID3SvgArc;
+ };
+ startAngle: {
+ (): number;
+ (angle: number): ID3SvgArc;
+ (angle: () => number): ID3SvgArc;
+ };
+ endAngle: {
+ (): number;
+ (angle: number): ID3SvgArc;
+ (angle: () => number): ID3SvgArc;
+ };
+ centroid(options?: ID3SvgArcOptions): number[];
+}
+
+interface ID3SvgArcOptions {
+ innerRadius?: number;
+ outerRadius?: number;
+ startAngle?: number;
+ endAngle?: number;
+}
+
+interface ID3SvgLine {
+ /**
+ * Returns the path data string
+ *
+ * @param data Array of data elements
+ * @param index Optional index
+ */
+ (data: any[], index?: number): string;
+ /**
+ * Get or set the x-coordinate accessor.
+ */
+ x: {
+ /**
+ * Get the x-coordinate accessor.
+ */
+ (): (data: any) => any;
+ /**
+ * Set the x-coordinate accessor.
+ *
+ * @param accessor The new accessor function
+ */
+ (accessor: (data: any) => any): ID3SvgLine;
+ };
+ /**
+ * Get or set the y-coordinate accessor.
+ */
+ y: {
+ /**
+ * Get the y-coordinate accessor.
+ */
+ (): (data: any) => any;
+ /**
+ * Set the y-coordinate accessor.
+ *
+ * @param accessor The new accessor function
+ */
+ (accessor: (data: any) => any): ID3SvgLine;
+ };
+ /**
+ * Get or set the interpolation mode.
+ */
+ interpolate: {
+ /**
+ * Get the interpolation accessor.
+ */
+ (): string;
+ /**
+ * Set the interpolation accessor.
+ *
+ * @param interpolate The interpolation mode
+ */
+ (interpolate: string): ID3SvgLine;
+ };
+ /**
+ * Get or set the cardinal spline tension.
+ */
+ tension: {
+ /**
+ * Get the cardinal spline accessor.
+ */
+ (): number;
+ /**
+ * Set the cardinal spline accessor.
+ *
+ * @param tension The Cardinal spline interpolation tension
+ */
+ (tension: number): ID3SvgLine;
+ };
+ /**
+ * Control whether the line is defined at a given point.
+ */
+ defined: {
+ /**
+ * Get the accessor function that controls where the line is defined.
+ */
+ (): (data: any) => any;
+ /**
+ * Set the accessor function that controls where the area is defined.
+ *
+ * @param defined The new accessor function
+ */
+ (defined: (data: any) => any): ID3SvgLine;
+ };
+}
+
+interface ID3SvgArea {
+ /**
+ * Generate a piecewise linear area, as in an area chart.
+ */
+ (data: any[], index?: number): string;
+ /**
+ * Get or set the x-coordinate accessor.
+ */
+ x: {
+ /**
+ * Get the x-coordinate accessor.
+ */
+ (): (data: any) => any;
+ /**
+ * Set the x-coordinate accessor.
+ *
+ * @param accessor The new accessor function
+ */
+ (accessor: (data: any) => any): ID3SvgArea;
+ };
+ /**
+ * Get or set the x0-coordinate (baseline) accessor.
+ */
+ x0: {
+ /**
+ * Get the x0-coordinate (baseline) accessor.
+ */
+ (): (data: any) => any;
+ /**
+ * Set the x0-coordinate (baseline) accessor.
+ *
+ * @param accessor The new accessor function
+ */
+ (accessor: (data: any) => any): ID3SvgArea;
+ };
+ /**
+ * Get or set the x1-coordinate (topline) accessor.
+ */
+ x1: {
+ /**
+ * Get the x1-coordinate (topline) accessor.
+ */
+ (): (data: any) => any;
+ /**
+ * Set the x1-coordinate (topline) accessor.
+ *
+ * @param accessor The new accessor function
+ */
+ (accessor: (data: any) => any): ID3SvgArea;
+ };
+ /**
+ * Get or set the y-coordinate accessor.
+ */
+ y: {
+ /**
+ * Get the y-coordinate accessor.
+ */
+ (): (data: any) => any;
+ /**
+ * Set the y-coordinate accessor.
+ *
+ * @param accessor The new accessor function
+ */
+ (accessor: (data: any) => any): ID3SvgArea;
+ };
+ /**
+ * Get or set the y0-coordinate (baseline) accessor.
+ */
+ y0: {
+ /**
+ * Get the y0-coordinate (baseline) accessor.
+ */
+ (): (data: any) => any;
+ /**
+ * Set the y0-coordinate (baseline) accessor.
+ *
+ * @param accessor The new accessor function
+ */
+ (accessor: (data: any) => any): ID3SvgArea;
+ };
+ /**
+ * Get or set the y1-coordinate (topline) accessor.
+ */
+ y1: {
+ /**
+ * Get the y1-coordinate (topline) accessor.
+ */
+ (): (data: any) => any;
+ /**
+ * Set the y1-coordinate (topline) accessor.
+ *
+ * @param accessor The new accessor function
+ */
+ (accessor: (data: any) => any): ID3SvgArea;
+ };
+ /**
+ * Get or set the interpolation mode.
+ */
+ interpolate: {
+ /**
+ * Get the interpolation accessor.
+ */
+ (): string;
+ /**
+ * Set the interpolation accessor.
+ *
+ * @param interpolate The interpolation mode
+ */
+ (interpolate: string): ID3SvgArea;
+ };
+ /**
+ * Get or set the cardinal spline tension.
+ */
+ tension: {
+ /**
+ * Get the cardinal spline accessor.
+ */
+ (): number;
+ /**
+ * Set the cardinal spline accessor.
+ *
+ * @param tension The Cardinal spline interpolation tension
+ */
+ (tension: number): ID3SvgArea;
+ };
+ /**
+ * Control whether the area is defined at a given point.
+ */
+ defined: {
+ /**
+ * Get the accessor function that controls where the area is defined.
+ */
+ (): (data: any) => any;
+ /**
+ * Set the accessor function that controls where the area is defined.
+ *
+ * @param defined The new accessor function
+ */
+ (defined: (data: any) => any): ID3SvgArea;
+ };
+}
+
+interface ID3Random {
+ /**
+ * Returns a function for generating random numbers with a normal distribution
+ *
+ * @param mean The expected value of the generated pseudorandom numbers
+ * @param deviation The given standard deviation
+ */
+ normal(mean?: number, deviation?: number): () => number;
+ /**
+ * Returns a function for generating random numbers with a log-normal distribution
+ *
+ * @param mean The expected value of the generated pseudorandom numbers
+ * @param deviation The given standard deviation
+ */
+ logNormal(mean?: number, deviation?: number): () => number;
+ /**
+ * Returns a function for generating random numbers with an Irwin-Hall distribution
+ *
+ * @param count The number of independent variables
+ */
+ irwinHall(count: number): () => number;
+}
+
+declare var d3: ID3Base;
diff --git a/express/express-tests.ts b/express/express-tests.ts
index 9b54b1701..53dfc1143 100644
--- a/express/express-tests.ts
+++ b/express/express-tests.ts
@@ -1,10 +1,1250 @@
///
-declare var _, $;
+import express = module('express');
+var app = express();
-import Express = module('express');
-var express: Express;
-var app: Express.ServerApplication;
+//////////////////////////
+
+var hash: any;
+
+// config
+
+app.set('view engine', 'ejs');
+app.set('views', __dirname + '/views');
+
+// middleware
+
+app.use(express.bodyParser());
+app.use(express.cookieParser('shhhh, very secret'));
+app.use(express.session());
+
+// Session-persisted message middleware
+
+app.use(function (req, res, next) {
+ var err = req.session.error
+ , msg = req.session.success;
+ delete req.session.error;
+ delete req.session.success;
+ res.locals.message = '';
+ if (err) res.locals.message = '
' + err + '
';
+ if (msg) res.locals.message = '' + msg + '
';
+ next();
+});
+
+// dummy database
+
+var users = {
+ tj: { name: 'tj' }
+};
+
+// when you create a user, generate a salt
+// and hash the password ('foobar' is the pass here)
+
+hash('foobar', function (err, salt, hash) {
+ if (err) throw err;
+ // store the salt & hash in the "db"
+ users.tj.salt = salt;
+ users.tj.hash = hash;
+});
+
+
+// Authenticate using our plain-object database of doom!
+
+function authenticate(name, pass, fn) {
+ if (!module.parent) console.log('authenticating %s:%s', name, pass);
+ var user = users[name];
+ // query the db for the given username
+ if (!user) return fn(new Error('cannot find user'));
+ // apply the same algorithm to the POSTed password, applying
+ // the hash against the pass / salt, if there is a match we
+ // found the user
+ hash(pass, user.salt, function (err, hash) {
+ if (err) return fn(err);
+ if (hash == user.hash) return fn(null, user);
+ fn(new Error('invalid password'));
+ })
+}
+
+function restrict(req: ExpressServerRequest, res: ExpressServerResponse, next?: Function) {
+ if (req.session.user) {
+ next();
+ } else {
+ req.session.error = 'Access denied!';
+ res.redirect('/login');
+ }
+}
+
+app.get('/', function (req, res) {
+ res.redirect('login');
+});
+
+app.get('/restricted', restrict, function (req, res) {
+ res.send('Wahoo! restricted area, click to logout');
+});
+
+app.get('/logout', function (req, res) {
+ // destroy the user's session to log them out
+ // will be re-created next request
+ req.session.destroy(function () {
+ res.redirect('/');
+ });
+});
+
+app.get('/login', function (req, res) {
+ res.render('login');
+});
+
+app.post('/login', function (req, res) {
+ authenticate(req.body.username, req.body.password, function (err, user) {
+ if (user) {
+ // Regenerate session when signing in
+ // to prevent fixation
+ req.session.regenerate(function () {
+ // Store the user's primary key
+ // in the session store to be retrieved,
+ // or in this case the entire user object
+ req.session.user = user;
+ req.session.success = 'Authenticated as ' + user.name
+ + ' click to logout. '
+ + ' You may now access /restricted.';
+ res.redirect('back');
+ });
+ } else {
+ req.session.error = 'Authentication failed, please check your '
+ + ' username and password.'
+ + ' (use "tj" and "foobar")';
+ res.redirect('login');
+ }
+ });
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express started on port 3000');
+}
+
+//////////////
+
+app.set('views', __dirname);
+app.set('view engine', 'jade');
+
+var pets = [];
+
+var n = 1000;
+while (n--) {
+ pets.push({ name: 'Tobi', age: 2, species: 'ferret' });
+ pets.push({ name: 'Loki', age: 1, species: 'ferret' });
+ pets.push({ name: 'Jane', age: 6, species: 'ferret' });
+}
+
+app.use(express.logger('dev'));
+
+app.get('/', function (req, res) {
+ res.render('pets', { pets: pets });
+});
+
+app.listen(3000);
+console.log('Express listening on port 3000');
+
+/////////////
+
+app.get('/', function (req, res) {
+ res.format({
+ html: function () {
+ res.send('' + users.map(function (user) {
+ return '- ' + user.name + '
';
+ }).join('') + '
');
+ },
+
+ text: function () {
+ res.send(users.map(function (user) {
+ return ' - ' + user.name + '\n';
+ }).join(''));
+ },
+
+ json: function () {
+ res.json(users);
+ }
+ })
+});
+
+// or you could write a tiny middleware like
+// this to abstract make things a bit more declarative:
+
+function format(mod) {
+ var obj = require(mod);
+ return function (req, res) {
+ res.format(obj);
+ }
+}
+
+app.get('/users', format('./users'));
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('listening on port 3000');
+}
+
+/////////////////////////
+
+// add favicon() before logger() so
+// GET /favicon.ico requests are not
+// logged, because this middleware
+// reponds to /favicon.ico and does not
+// call next()
+app.use(express.favicon());
+
+// custom log format
+if ('test' != process.env.NODE_ENV)
+ app.use(express.logger(':method :url'));
+
+// parses request cookies, populating
+// req.cookies and req.signedCookies
+// when the secret is passed, used
+// for signing the cookies.
+app.use(express.cookieParser('my secret here'));
+
+// parses json, x-www-form-urlencoded, and multipart/form-data
+app.use(express.bodyParser());
+
+app.get('/', function (req, res) {
+ if (req.cookies.remember) {
+ res.send('Remembered :). Click to forget!.');
+ } else {
+ res.send('');
+ }
+});
+
+app.get('/forget', function (req, res) {
+ res.clearCookie('remember');
+ res.redirect('back');
+});
+
+app.post('/', function (req, res) {
+ var minute = 60000;
+ if (req.body.remember) res.cookie('remember', 1, { maxAge: minute });
+ res.redirect('back');
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express started on port 3000');
+}
+
+///////////////////
+
+// ignore GET /favicon.ico
+app.use(express.favicon());
+
+// pass a secret to cookieParser() for signed cookies
+app.use(express.cookieParser('manny is cool'));
+
+// add req.session cookie support
+app.use(express.cookieSession());
+
+// do something with the session
+app.use(count);
+
+// custom middleware
+function count(req, res) {
+ req.session.count = req.session.count || 0;
+ var n = req.session.count++;
+ res.send('viewed ' + n + ' times\n');
+}
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express server listening on port 3000');
+}
+
+///////////////
+
+var api = app;
+
+app.use(express.static(__dirname + '/public'));
+
+// api middleware
+
+api.use(express.logger('dev'));
+api.use(express.bodyParser());
+
+/**
+ * CORS support.
+ */
+
+api.all('*', function (req, res, next) {
+ if (!req.get('Origin')) return next();
+ // use "*" here to accept any origin
+ res.set('Access-Control-Allow-Origin', 'http://localhost:3000');
+ res.set('Access-Control-Allow-Methods', 'GET, POST');
+ res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type');
+ // res.set('Access-Control-Allow-Max-Age', 3600);
+ if ('OPTIONS' == req.method) return res.send(200);
+ next();
+});
+
+/**
+ * POST a user.
+ */
+
+api.post('/user', function (req, res) {
+ console.log(req.body);
+ res.send(201);
+});
+
+app.listen(3000);
+api.listen(3001);
+
+console.log('app listening on 3000');
+console.log('api listening on 3001');
+
+////////////////////
+
+app.get('/', function (req, res) {
+ res.send('');
+});
+
+// /files/* is accessed via req.params[0]
+// but here we name it :file
+app.get('/files/:file(*)', function (req, res, next?) {
+ var file = req.params.file
+ , path = __dirname + '/files/' + file;
+
+ res.download(path);
+});
+
+// error handling middleware. Because it's
+// below our routes, you will be able to
+// "intercept" errors, otherwise Connect
+// will respond with 500 "Internal Server Error".
+app.use(function (err, req, res, next) {
+ // special-case 404s,
+ // remember you could
+ // render a 404 template here
+ if (404 == err.status) {
+ res.statusCode = 404;
+ res.send('Cant find that file, sorry!');
+ } else {
+ next(err);
+ }
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express started on port 3000');
+}
+
+///////////////////
+
+// Register ejs as .html. If we did
+// not call this, we would need to
+// name our views foo.ejs instead
+// of foo.html. The __express method
+// is simply a function that engines
+// use to hook into the Express view
+// system by default, so if we want
+// to change "foo.ejs" to "foo.html"
+// we simply pass _any_ function, in this
+// case `ejs.__express`.
+
+app.engine('.html', require('ejs').__express);
+
+// Optional since express defaults to CWD/views
+
+app.set('views', __dirname + '/views');
+
+// Without this you would need to
+// supply the extension to res.render()
+// ex: res.render('users.html').
+app.set('view engine', 'html');
+
+app.get('/', function (req, res) {
+ res.render('users', {
+ users: users,
+ title: "EJS example",
+ header: "Some users"
+ });
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express app started on port 3000');
+}
+
+////////////////////
+
+var test: any;
+
+if (!test) app.use(express.logger('dev'));
+app.use(app.router);
+
+// the error handler is strategically
+// placed *below* the app.router; if it
+// were above it would not receive errors
+// from app.get() etc
+app.use(error);
+
+// error handling middleware have an arity of 4
+// instead of the typical (req, res, next),
+// otherwise they behave exactly like regular
+// middleware, you may have several of them,
+// in different orders etc.
+
+function error(err, req, res, next) {
+ // log it
+ if (!test) console.error(err.stack);
+
+ // respond with 500 "Internal Server Error".
+ res.send(500);
+}
+
+app.get('/', function (req, res) {
+ // Caught and passed down to the errorHandler middleware
+ throw new Error('something broke!');
+});
+
+app.get('/next', function (req, res, next) {
+ // We can also pass exceptions to next()
+ process.nextTick(function () {
+ next(new Error('oh no!'));
+ });
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express started on port 3000');
+}
+
+/////////////////////
+
+var silent: any;
+
+// general config
+app.set('views', __dirname + '/views');
+app.set('view engine', 'jade');
+
+// our custom "verbose errors" setting
+// which we can use in the templates
+// via settings['verbose errors']
+app.enable('verbose errors');
+
+// disable them in production
+// use $ NODE_ENV=production node examples/error-pages
+if ('production' == app.settings.env) {
+ app.disable('verbose errors');
+}
+
+app.use(express.favicon());
+
+silent || app.use(express.logger('dev'));
+
+// "app.router" positions our routes
+// above the middleware defined below,
+// this means that Express will attempt
+// to match & call routes _before_ continuing
+// on, at which point we assume it's a 404 because
+// no route has handled the request.
+
+app.use(app.router);
+
+// Since this is the last non-error-handling
+// middleware use()d, we assume 404, as nothing else
+// responded.
+
+// $ curl http://localhost:3000/notfound
+// $ curl http://localhost:3000/notfound -H "Accept: application/json"
+// $ curl http://localhost:3000/notfound -H "Accept: text/plain"
+
+app.use(function (req, res, next) {
+ res.status(404);
+
+ // respond with html page
+ if (req.accepts('html')) {
+ res.render('404', { url: req.url });
+ return;
+ }
+
+ // respond with json
+ if (req.accepts('json')) {
+ res.send({ error: 'Not found' });
+ return;
+ }
+
+ // default to plain-text. send()
+ res.type('txt').send('Not found');
+});
+
+// error-handling middleware, take the same form
+// as regular middleware, however they require an
+// arity of 4, aka the signature (err, req, res, next).
+// when connect has an error, it will invoke ONLY error-handling
+// middleware.
+
+// If we were to next() here any remaining non-error-handling
+// middleware would then be executed, or if we next(err) to
+// continue passing the error, only error-handling middleware
+// would remain being executed, however here
+// we simply respond with an error page.
+
+app.use(function (err, req, res, next) {
+ // we may use properties of the error object
+ // here and next(err) appropriately, or if
+ // we possibly recovered from the error, simply next().
+ res.status(err.status || 500);
+ res.render('500', { error: err });
+});
+
+// Routes
+
+app.get('/', function (req, res) {
+ res.render('index.jade');
+});
+
+app.get('/404', function (req, res, next) {
+ // trigger a 404 since no other middleware
+ // will match /404 after this one, and we're not
+ // responding here
+ next();
+});
+
+app.get('/403', function (req, res, next) {
+ // trigger a 403 error
+ var err = new Error('not allowed!');
+ err.status = 403;
+ next(err);
+});
+
+app.get('/500', function (req, res, next) {
+ // trigger a generic (500) error
+ next(new Error('keyboard cat!'));
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ //silent || Â console.log('Express started on port 3000');
+}
+
+///////////////
+
+var fs: any;
+var md: any;
+
+app.set('view engine', 'jade');
+app.set('views', __dirname + '/views');
+
+function User(name) {
+ this.private = 'heyyyy';
+ this.secret = 'something';
+ this.name = name;
+ this.id = 123;
+}
+
+// You'll probably want to do
+// something like this so you
+// dont expose "secret" data.
+
+User.prototype.toJSON = function () {
+ return {
+ id: this.id,
+ name: this.name
+ }
+};
+
+app.use(express.logger('dev'));
+
+// earlier on expose an object
+// that we can tack properties on.
+// all res.locals props are exposed
+// to the templates, so "expose" will
+// be present.
+
+app.use(function (req, res, next) {
+ res.locals.expose = {};
+ // you could alias this as req or res.expose
+ // to make it shorter and less annoying
+ next();
+});
+
+// pretend we loaded a user
+
+app.use(function (req, res, next) {
+ req.user = new User('Tobi');
+ next();
+});
+
+app.get('/', function (req, res) {
+ res.redirect('/user');
+});
+
+app.get('/user', function (req, res) {
+ // we only want to expose the user
+ // to the client for this route:
+ res.locals.expose.user = req.user;
+ res.render('page');
+});
+
+app.listen(3000);
+console.log('app listening on port 3000');
+
+///////////////////////
+
+app.get('/', function (req, res) {
+ res.send('Hello World');
+});
+
+app.listen(3000);
+console.log('Express started on port 3000');
+
+////////////////////
+
+// register .md as an engine in express view system
+
+app.engine('md', function (path, options, fn) {
+ fs.readFile(path, 'utf8', function (err, str) {
+ if (err) return fn(err);
+ try {
+ var html = md(str);
+ html = html.replace(/\{([^}]+)\}/g, function (_, name) {
+ return options[name] || '';
+ })
+ fn(null, html);
+ } catch (err) {
+ fn(err);
+ }
+ });
+})
+
+app.set('views', __dirname + '/views');
+
+// make it the default so we dont need .md
+app.set('view engine', 'md');
+
+app.get('/', function (req, res) {
+ res.render('index', { title: 'Markdown Example' });
+})
+
+app.get('/fail', function (req, res) {
+ res.render('missing', { title: 'Markdown Example' });
+})
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express started on port 3000');
+}
+
+///////////////////////
+
+var mformat: any;
+
+// bodyParser in connect 2.x uses node-formidable to parse
+// the multipart form data.
+app.use(express.bodyParser())
+
+app.get('/', function (req, res) {
+ res.send('');
+});
+
+app.post('/', function (req, res, next) {
+ // the uploaded file can be found as `req.files.image` and the
+ // title field as `req.body.title`
+ res.send(mformat('\nuploaded %s (%d Kb) to %s as %s'
+ , req.files.image.name
+ , req.files.image.size / 1024 | 0
+ , req.files.image.path
+ , req.body.title));
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express started on port 3000');
+}
+
+//////////////////
+
+
+// first:
+// $ npm install redis online
+// $ redis-server
+
+/**
+ * Module dependencies.
+ */
+
+var online: any;
+var redis: any;
+var db: any;
+
+// online
+
+online = online(db);
+
+// activity tracking, in this case using
+// the UA string, you would use req.user.id etc
+
+app.use(function (req, res, next) {
+ // fire-and-forget
+ online.add(req.headers['user-agent']);
+ next();
+});
+
+/**
+ * List helper.
+ */
+
+function list(ids) {
+ return '' + ids.map(function (id) {
+ return '- ' + id + '
';
+ }).join('') + '
';
+}
+
+/**
+ * GET users online.
+ */
+
+app.get('/', function (req, res, next) {
+ online.last(5, function (err, ids) {
+ if (err) return next(err);
+ res.send('Users online: ' + ids.length + '
' + list(ids));
+ });
+});
+
+app.listen(3000);
+console.log('listening on port 3000');
+
+///////////////////
+
+// Convert :to and :from to integers
+
+app.param(['to', 'from'], function (req, res, next, num, name) {
+ req.params[name] = num = parseInt(num, 10);
+ if (isNaN(num)) {
+ next(new Error('failed to parseInt ' + num));
+ } else {
+ next();
+ }
+});
+
+// Load user by id
+
+app.param('user', function (req, res, next, id) {
+ if (req.user = users[id]) {
+ next();
+ } else {
+ next(new Error('failed to find user'));
+ }
+});
+
+/**
+ * GET index.
+ */
+
+app.get('/', function (req, res) {
+ res.send('Visit /user/0 or /users/0-2');
+});
+
+/**
+ * GET :user.
+ */
+
+app.get('/user/:user', function (req, res, next) {
+ res.send('user ' + req.user.name);
+});
+
+/**
+ * GET users :from - :to.
+ */
+
+app.get('/users/:from-:to', function (req, res, next) {
+ var from = req.params.from
+ , to = req.params.to
+ , names = users.map(function (user) { return user.name; });
+ res.send('users ' + names.slice(from, to).join(', '));
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express started on port 3000');
+}
+
+//////////////////
+
+// Ad-hoc example resource method
+
+app.resource = function (path, obj) {
+ this.get(path, obj.index);
+ this.get(path + '/:a..:b.:format?', function (req, res) {
+ var a = parseInt(req.params.a, 10)
+ , b = parseInt(req.params.b, 10)
+ , format = req.params.format;
+ obj.range(req, res, a, b, format);
+ });
+ this.get(path + '/:id', obj.show);
+ this.del(path + '/:id', obj.destroy);
+};
+
+// Fake controller.
+
+var FUser = {
+ index: function (req, res) {
+ res.send(users);
+ },
+ show: function (req, res) {
+ res.send(users[req.params.id] || { error: 'Cannot find user' });
+ },
+ destroy: function (req, res) {
+ var id = req.params.id;
+ var destroyed = id in users;
+ delete users[id];
+ res.send(destroyed ? 'destroyed' : 'Cannot find user');
+ },
+ range: function (req, res, a, b, format) {
+ var range = users.slice(a, b + 1);
+ switch (format) {
+ case 'json':
+ res.send(range);
+ break;
+ case 'html':
+ default:
+ var html = '' + range.map(function (user) {
+ return '- ' + user.name + '
';
+ }).join('\n') + '
';
+ res.send(html);
+ break;
+ }
+ }
+};
+
+// curl http://localhost:3000/users -- responds with all users
+// curl http://localhost:3000/users/1 -- responds with user 1
+// curl http://localhost:3000/users/4 -- responds with error
+// curl http://localhost:3000/users/1..3 -- responds with several users
+// curl -X DELETE http://localhost:3000/users/1 -- deletes the user
+
+app.resource('/users', FUser);
+
+app.get('/', function (req, res) {
+ res.send([
+ 'Examples:
'
+ , '- GET /users
'
+ , '- GET /users/1
'
+ , '- GET /users/3
'
+ , '- GET /users/1..3
'
+ , '- GET /users/1..3.json
'
+ , '- DELETE /users/4
'
+ , '
'
+ ].join('\n'));
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express started on port 3000');
+}
+
+/////////////////////
+
+
+var verbose: any;
+
+app.map = function (a, route) {
+ route = route || '';
+ for (var key in a) {
+ switch (typeof a[key]) {
+ // { '/path': { ... }}
+ case 'object':
+ app.map(a[key], route + key);
+ break;
+ // get: function(){ ... }
+ case 'function':
+ if (verbose) console.log('%s %s', key, route);
+ app[key](route, a[key]);
+ break;
+ }
+ }
+};
+
+var users2 = {
+ list: function (req, res) {
+ res.send('user list');
+ },
+
+ get: function (req, res) {
+ res.send('user ' + req.params.uid);
+ },
+
+ del: function (req, res) {
+ res.send('delete users');
+ }
+};
+
+var pets2 = {
+ list: function (req, res) {
+ res.send('user ' + req.params.uid + '\'s pets');
+ },
+
+ del: function (req, res) {
+ res.send('delete ' + req.params.uid + '\'s pet ' + req.params.pid);
+ }
+};
+
+app.map({
+ '/users': {
+ get: users2.list,
+ del: users2.del,
+ '/:uid': {
+ get: users.get ,
+ '/pets': {
+ get: pets2.list,
+ '/:pid': {
+ del: pets2.del
+ }
+ }
+ }
+ }
+});
+
+app.listen(3000);
+
+///////////////////////////
+
+// Example requests:
+// curl http://localhost:3000/user/0
+// curl http://localhost:3000/user/0/edit
+// curl http://localhost:3000/user/1
+// curl http://localhost:3000/user/1/edit (unauthorized since this is not you)
+// curl -X DELETE http://localhost:3000/user/0 (unauthorized since you are not an admin)
+
+function loadUser(req, res, next) {
+ // You would fetch your user from the db
+ var user = users[req.params.id];
+ if (user) {
+ req.user = user;
+ next();
+ } else {
+ next(new Error('Failed to load user ' + req.params.id));
+ }
+}
+
+function andRestrictToSelf(req, res, next) {
+ // If our authenticated user is the user we are viewing
+ // then everything is fine :)
+ if (req.authenticatedUser.id == req.user.id) {
+ next();
+ } else {
+ // You may want to implement specific exceptions
+ // such as UnauthorizedError or similar so that you
+ // can handle these can be special-cased in an error handler
+ // (view ./examples/pages for this)
+ next(new Error('Unauthorized'));
+ }
+}
+
+function andRestrictTo(role) {
+ return function (req, res, next) {
+ if (req.authenticatedUser.role == role) {
+ next();
+ } else {
+ next(new Error('Unauthorized'));
+ }
+ }
+}
+
+// Middleware for faux authentication
+// you would of course implement something real,
+// but this illustrates how an authenticated user
+// may interact with middleware
+
+app.use(function (req, res, next) {
+ req.authenticatedUser = users[0];
+ next();
+});
+
+app.get('/', function (req, res) {
+ res.redirect('/user/0');
+});
+
+app.get('/user/:id', loadUser, function (req, res) {
+ res.send('Viewing user ' + req.user.name);
+});
+
+app.get('/user/:id/edit', loadUser, andRestrictToSelf, function (req, res) {
+ res.send('Editing user ' + req.user.name);
+});
+
+app.del('/user/:id', loadUser, andRestrictTo('admin'), function (req, res) {
+ res.send('Deleted user ' + req.user.name);
+});
+
+app.listen(3000);
+console.log('Express app started on port 3000');
+
+/////////////////////////
+
+app.set('view engine', 'jade');
+app.set('views', __dirname);
+
+// populate search
+
+db.sadd('ferret', 'tobi');
+db.sadd('ferret', 'loki');
+db.sadd('ferret', 'jane');
+db.sadd('cat', 'manny');
+db.sadd('cat', 'luna');
+
+/**
+ * GET the search page.
+ */
+
+app.get('/', function (req, res) {
+ res.render('search');
+});
+
+/**
+ * GET search for :query.
+ */
+
+app.get('/search/:query?', function (req, res) {
+ var query = req.params.query;
+ db.smembers(query, function (err, vals) {
+ if (err) return res.send(500);
+ res.send(vals);
+ });
+});
+
+/**
+ * GET client javascript. Here we use sendfile()
+ * because serving __dirname with the static() middleware
+ * would also mean serving our server "index.js" and the "search.jade"
+ * template.
+ */
+
+app.get('/client.js', function (req, res) {
+ res.sendfile(__dirname + '/client.js');
+});
+
+app.listen(3000);
+console.log('app listening on port 3000');
+
+///////////////////
+
+app.use(express.logger('dev'));
+
+// Required by session() middleware
+// pass the secret for signed cookies
+// (required by session())
+app.use(express.cookieParser('keyboard cat'));
+
+// Populates req.session
+app.use(express.session());
+
+app.get('/', function (req, res) {
+ var body = '';
+ if (req.session.views) {
+ ++req.session.views;
+ } else {
+ req.session.views = 1;
+ body += 'First time visiting? view this page in several browsers :)
';
+ }
+ res.send(body + 'viewed ' + req.session.views + ' times.
');
+});
+
+app.listen(3000);
+console.log('Express app started on port 3000');
+
+////////////////////////
+
+// log requests
+app.use(express.logger('dev'));
+
+// express on its own has no notion
+// of a "file". The express.static()
+// middleware checks for a file matching
+// the `req.path` within the directory
+// that you pass it. In this case "GET /js/app.js"
+// will look for "./public/js/app.js".
+
+app.use(express.static(__dirname + '/public'));
+
+// if you wanted to "prefix" you may use
+// the mounting feature of Connect, for example
+// "GET /static/js/app.js" instead of "GET /js/app.js".
+// The mount-path "/static" is simply removed before
+// passing control to the express.static() middleware,
+// thus it serves the file correctly by ignoring "/static"
+app.use('/static', express.static(__dirname + '/public'));
+
+// if for some reason you want to serve files from
+// several directories, you can use express.static()
+// multiple times! Here we're passing "./public/css",
+// this will allow "GET /style.css" instead of "GET /css/style.css":
+app.use(express.static(__dirname + '/public/css'));
+
+// this examples does not have any routes, however
+// you may `app.use(app.router)` before or after these
+// static() middleware. If placed before them your routes
+// will be matched BEFORE file serving takes place. If placed
+// after as shown here then file serving is performed BEFORE
+// any routes are hit:
+app.use(app.router);
+
+app.listen(3000);
+console.log('listening on port 3000');
+console.log('try:');
+console.log(' GET /hello.txt');
+console.log(' GET /js/app.js');
+console.log(' GET /css/style.css');
+
+//////////////////
+
+/*
+edit /etc/vhosts:
+
+127.0.0.1 foo.example.com
+127.0.0.1 bar.example.com
+127.0.0.1 example.com
+*/
+
+// Main app
+
+var main = express();
+
+main.use(express.logger('dev'));
+
+main.get('/', function (req, res) {
+ res.send('Hello from main app!')
+});
+
+main.get('/:sub', function (req, res) {
+ res.send('requsted ' + req.params.sub);
+});
+
+// Redirect app
+
+var redirect = express();
+
+redirect.all('*', function (req, res) {
+ console.log(req.subdomains);
+ res.redirect('http://example.com:3000/' + req.subdomains[0]);
+});
+
+app.use(express.vhost('*.example.com', redirect))
+app.use(express.vhost('example.com', main));
+
+app.listen(3000);
+console.log('Express app started on port 3000');
+
+////////////////////
+
+// create an error with .status. we
+// can then use the property in our
+// custom error handler (Connect repects this prop as well)
+
+function merror(status, msg) {
+ var err = new Error(msg);
+ err.status = status;
+ return err;
+}
+
+// if we wanted to supply more than JSON, we could
+// use something similar to the content-negotiation
+// example.
+
+// here we validate the API key,
+// by mounting this middleware to /api
+// meaning only paths prefixed with "/api"
+// will cause this middleware to be invoked
+
+app.use('/api', function (req, res, next) {
+ var key = req.query['api-key'];
+
+ // key isnt present
+ if (!key) return next(merror(400, 'api key required'));
+
+ // key is invalid
+ if (!~apiKeys.indexOf(key)) return next(merror(401, 'invalid api key'));
+
+ // all good, store req.key for route access
+ req.key = key;
+ next();
+});
+
+// position our routes above the error handling middleware,
+// and below our API middleware, since we want the API validation
+// to take place BEFORE our routes
+app.use(app.router);
+
+// middleware with an arity of 4 are considered
+// error handling middleware. When you next(err)
+// it will be passed through the defined middleware
+// in order, but ONLY those with an arity of 4, ignoring
+// regular middleware.
+app.use(function (err, req, res, next) {
+ // whatever you want here, feel free to populate
+ // properties on `err` to treat it differently in here.
+ res.send(err.status || 500, { error: err.message });
+});
+
+// our custom JSON 404 middleware. Since it's placed last
+// it will be the last middleware called, if all others
+// invoke next() and do not respond.
+app.use(function (req, res) {
+ res.send(404, { error: "Lame, can't find that" });
+});
+
+// map of valid api keys, typically mapped to
+// account info with some sort of database like redis.
+// api keys do _not_ serve as authentication, merely to
+// track API usage or help prevent malicious behavior etc.
+
+var apiKeys = ['foo', 'bar', 'baz'];
+
+// these two objects will serve as our faux database
+
+var repos = [
+ { name: 'express', url: 'http://github.com/visionmedia/express' }
+ , { name: 'stylus', url: 'http://github.com/learnboost/stylus' }
+ , { name: 'cluster', url: 'http://github.com/learnboost/cluster' }
+];
+
+var userRepos = {
+ tobi: [repos[0], repos[1]]
+ , loki: [repos[1]]
+ , jane: [repos[2]]
+};
+
+// we now can assume the api key is valid,
+// and simply expose the data
+
+app.get('/api/users', function (req, res, next) {
+ res.send(users);
+});
+
+app.get('/api/repos', function (req, res, next) {
+ res.send(repos);
+});
+
+app.get('/api/user/:name/repos', function (req, res, next) {
+ var name = req.params.name
+ , user = userRepos[name];
+
+ if (user) res.send(user);
+ else next();
+});
+
+if (!module.parent) {
+ app.listen(3000);
+ console.log('Express server listening on port 3000');
+}
+
+//////
function test_general() {
@@ -97,7 +1337,7 @@ function test_general() {
}
function test_request() {
- var req: Express.ServerRequest;
+ var req: ExpressServerRequest;
req.params.name;
req.params[0];
req.query.q;
@@ -130,7 +1370,7 @@ function test_request() {
}
function test_response() {
- var res: Express.ServerResponse;
+ var res: ExpressServerResponse;
res.status(404).sendfile('path/to/404.png');
res.set('Content-Type', 'text/plain');
res.set({
diff --git a/express/express.d.ts b/express/express.d.ts
index c8fe6bec3..8e19ab004 100644
--- a/express/express.d.ts
+++ b/express/express.d.ts
@@ -1,218 +1,1954 @@
-// Type definitions for Express 3.0
+// Type definitions for Express 3.1
// Project: http://expressjs.com
// Definitions by: Boris Yankov
-// Definitions: https://github.com/borisyankov/DefinitelyTyped
+// DefinitelyTyped: https://github.com/borisyankov/DefinitelyTyped
-/*
-USAGE
+/* =================== USAGE ===================
-///
-import express = module('express')
-var app = express()
-...
+ import express = module('express');
+ var app = express();
-MIDDLEWARE
+ =============================================== */
-express exports lots of middleware, like .static, .session, etc, but use connect so you don't have to escape
-var connect = require('connect')
-connect.session({})
+///
-*/
+interface Route {
+ path: string;
-///
+ method: string;
-// do not reference this. use module('express') instead
-declare module _express {
+ callbacks: Function[];
- import http = module("http");
+ regexp: any;
- export interface Handler {
- (req: ServerRequest, res: ServerResponse, next?: Function): void;
- }
+ /**
+ * Check if this route matches `path`, if so
+ * populate `.params`.
+ */
+ match(path: string): bool;
+}
+declare var Route: {
+ /**
+ * Initialize `Route` with the given HTTP `method`, `path`,
+ * and an array of `callbacks` and `options`.
+ *
+ * Options:
+ *
+ * - `sensitive` enable case-sensitive routes
+ * - `strict` enable strict matching for trailing slashes
+ *
+ * @param method
+ * @param path
+ * @param callbacks
+ * @param options
+ */
+ new (method: string, path: string, callbacks: Function[], options: any): Route;
+}
- export interface Errback { (err: Error): void; }
+interface Handler {
+ (req: ExpressServerRequest, res: ExpressServerResponse, next?: Function): void;
+}
- export interface CookieOptions {
- maxAge?: number;
- signed?: bool;
- expires?: Date;
- httpOnly?: bool;
- path?: string;
- domain?: string;
- secure?: bool;
- }
+interface CookieOptions {
+ maxAge?: number;
+ signed?: bool;
+ expires?: Date;
+ httpOnly?: bool;
+ path?: string;
+ domain?: string;
+ secure?: bool;
+}
- export interface ExpressSettings {
- env?: string;
- views?: string;
- }
+interface Errback { (err: Error): void; }
- export interface ServerApplication {
- settings: ExpressSettings;
- locals: any;
- routes: any;
+interface ExpressSession {
+ /**
+ * Update reset `.cookie.maxAge` to prevent
+ * the cookie from expiring when the
+ * session is still active.
+ *
+ * @return {Session} for chaining
+ * @api public
+ */
+ touch(): ExpressSession;
- (): ServerApplication;
+ /**
+ * Reset `.maxAge` to `.originalMaxAge`.
+ */
+ resetMaxAge(): ExpressSession;
- router: Handler;
+ /**
+ * Save the session data with optional callback `fn(err)`.
+ */
+ save(fn: Function): ExpressSession;
- use(route: string, callback: Function): ServerApplication;
- use(route: string, server: ServerApplication): ServerApplication;
- use(callback: Function): ServerApplication;
- use(server: ServerApplication): ServerApplication;
+ /**
+ * Re-loads the session data _without_ altering
+ * the maxAge properties. Invokes the callback `fn(err)`,
+ * after which time if no exception has occurred the
+ * `req.session` property will be a new `Session` object,
+ * although representing the same session.
+ */
+ reload(fn: Function): ExpressSession;
- engine(ext: string, callback: Function): ServerApplication;
+ /**
+ * Destroy `this` session.
+ */
+ destroy(fn: Function): ExpressSession;
- param(param: Function): ServerApplication;
- param(name: string, callback: Function): ServerApplication;
- param(name: string, expressParam: any): ServerApplication;
- param(name: any[], callback: Function): ServerApplication;
+ /**
+ * Regenerate this request's session.
+ */
+ regenerate(fn: Function): ExpressSession;
- set(name: string): ServerApplication;
- set(name: string, val: any): ServerApplication;
+ user: any;
- enabled(name: string): bool;
- disabled(name: string): bool;
+ error: string;
- enable(name: string): ServerApplication;
- disable(name: string): ServerApplication;
+ success: string;
- configure(env: string, callback: () => void ): ServerApplication;
- configure(...params: any[]): ServerApplication; // covering this case: (...env: string[], callback: () => void)
- configure(callback: () => void ): ServerApplication;
+ views: any;
+}
+declare var ExpressSession: {
+ /**
+ * Create a new `Session` with the given request and `data`.
+ */
+ new (req: ExpressServerRequest, data: any): ExpressSession;
+}
- all(path: string, ...callbacks: Function[]): void;
+interface ExpressServerRequest {
- render(view: string, callback: (err: Error, html) => void ): void;
- render(view: string, optionss: any, callback: (err: Error, html) => void ): void;
+ session: ExpressSession;
- listen(port: number, hostname: string, backlog: number, callback: Function): void;
- listen(port: number, callback: Function): void;
- listen(path: string, callback?: Function): void;
- listen(handle: any, listeningListener?: Function): void;
+ /**
+ * Return request header.
+ *
+ * The `Referrer` header field is special-cased,
+ * both `Referrer` and `Referer` are interchangeable.
+ *
+ * Examples:
+ *
+ * req.get('Content-Type');
+ * // => "text/plain"
+ *
+ * req.get('content-type');
+ * // => "text/plain"
+ *
+ * req.get('Something');
+ * // => undefined
+ *
+ * Aliased as `req.header()`.
+ *
+ * @param name
+ */
+ get (name: string): string;
- get(name: string): any;
- get(path: RegExp, handler: Handler): void;
- get(path: string, ...callbacks: Handler[]): void;
+ header(name: string): string;
- post(path: RegExp, handler: Handler ): void;
- post(path: string, ...callbacks: Handler[]): void;
+ /**
+ * Check if the given `type(s)` is acceptable, returning
+ * the best match when true, otherwise `undefined`, in which
+ * case you should respond with 406 "Not Acceptable".
+ *
+ * The `type` value may be a single mime type string
+ * such as "application/json", the extension name
+ * such as "json", a comma-delimted list such as "json, html, text/plain",
+ * or an array `["json", "html", "text/plain"]`. When a list
+ * or array is given the _best_ match, if any is returned.
+ *
+ * Examples:
+ *
+ * // Accept: text/html
+ * req.accepts('html');
+ * // => "html"
+ *
+ * // Accept: text/*, application/json
+ * req.accepts('html');
+ * // => "html"
+ * req.accepts('text/html');
+ * // => "text/html"
+ * req.accepts('json, text');
+ * // => "json"
+ * req.accepts('application/json');
+ * // => "application/json"
+ *
+ * // Accept: text/*, application/json
+ * req.accepts('image/png');
+ * req.accepts('png');
+ * // => undefined
+ *
+ * // Accept: text/*;q=.5, application/json
+ * req.accepts(['html', 'json']);
+ * req.accepts('html, json');
+ * // => "json"
+ */
+ accepts(type: string): string;
- put(path: RegExp, handler: Handler ): void;
- put(path: string, ...callbacks: Handler[]): void;
+ accepts(type: string[]): string;
- del(path: RegExp, handler: Handler ): void;
- del(path: string, ...callbacks: Handler[]): void;
- }
+ /**
+ * Check if the given `charset` is acceptable,
+ * otherwise you should respond with 406 "Not Acceptable".
+ *
+ * @param charset
+ */
+ acceptsCharset(charset: string): bool;
- export interface ServerRequest extends http.ServerRequest {
+ /**
+ * Check if the given `lang` is acceptable,
+ * otherwise you should respond with 406 "Not Acceptable".
+ *
+ * @param lang
+ */
+ acceptsLanguage(lang: string): bool;
- accepted: any[];
- acceptedLanguages: string[];
- acceptedCharsets: string[];
+ /**
+ * Parse Range header field,
+ * capping to the given `size`.
+ *
+ * Unspecified ranges such as "0-" require
+ * knowledge of your resource length. In
+ * the case of a byte range this is of course
+ * the total number of bytes. If the Range
+ * header field is not given `null` is returned,
+ * `-1` when unsatisfiable, `-2` when syntactically invalid.
+ *
+ * NOTE: remember that ranges are inclusive, so
+ * for example "Range: users=0-3" should respond
+ * with 4 users when available, not 3.
+ *
+ * @param size
+ */
+ range(size: number): Array;
- params: any;
- query: any;
- body: any;
- files: any;
+ /**
+ * Return an array of Accepted media types
+ * ordered from highest quality to lowest.
+ *
+ * Examples:
+ *
+ * [ { value: 'application/json',
+ * quality: 1,
+ * type: 'application',
+ * subtype: 'json' },
+ * { value: 'text/html',
+ * quality: 0.5,
+ * type: 'text',
+ * subtype: 'html' } ]
+ */
+ accepted: Array;
- route: any;
- cookies: any;
- signedCookies: any;
+ /**
+ * Return an array of Accepted languages
+ * ordered from highest quality to lowest.
+ *
+ * Examples:
+ *
+ * Accept-Language: en;q=.5, en-us
+ * ['en-us', 'en']
+ */
+ acceptedLanguages: Array;
- get(field: string): string;
- header(field: string): string;
+ /**
+ * Return an array of Accepted charsets
+ * ordered from highest quality to lowest.
+ *
+ * Examples:
+ *
+ * Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8
+ * ['unicode-1-1', 'iso-8859-5']
+ */
+ acceptedCharsets: Array;
- accepts(types: string): any;
- accepts(types: string[]): any;
- acceptsCharset(charset: string): bool;
- acceptsLanguage(lang: string): bool;
+ /**
+ * Return the value of param `name` when present or `defaultValue`.
+ *
+ * - Checks route placeholders, ex: _/user/:id_
+ * - Checks body params, ex: id=12, {"id":12}
+ * - Checks query string params, ex: ?id=12
+ *
+ * To utilize request bodies, `req.body`
+ * should be an object. This can be done by using
+ * the `connect.bodyParser()` middleware.
+ *
+ * @param name
+ * @param defaultValue
+ */
+ param(name: string, defaultValue?: any): string;
- range(size: number): number[];
+ /**
+ * Check if the incoming request contains the "Content-Type"
+ * header field, and it contains the give mime `type`.
+ *
+ * Examples:
+ *
+ * // With Content-Type: text/html; charset=utf-8
+ * req.is('html');
+ * req.is('text/html');
+ * req.is('text/*');
+ * // => true
+ *
+ * // When Content-Type is application/json
+ * req.is('json');
+ * req.is('application/json');
+ * req.is('application/*');
+ * // => true
+ *
+ * req.is('html');
+ * // => false
+ *
+ * @param type
+ */
+ is(type: string): bool;
- param(name: string, defaultValue?: any): string;
- is(type: string): bool;
+ /**
+ * Return the protocol string "http" or "https"
+ * when requested with TLS. When the "trust proxy"
+ * setting is enabled the "X-Forwarded-Proto" header
+ * field will be trusted. If you're running behind
+ * a reverse proxy that supplies https for you this
+ * may be enabled.
+ */
+ protocol: string;
- protocol: string;
- secure: bool;
- ip: string;
- ips: string[];
- auth: any;
- subdomains: string[];
- path: string;
- host: string;
- fresh: bool;
- stale: bool;
- xhr: bool;
- }
+ /**
+ * Short-hand for:
+ *
+ * req.protocol == 'https'
+ */
+ secure: bool;
- export interface ServerResponse extends http.ServerResponse {
+ /**
+ * Return the remote address, or when
+ * "trust proxy" is `true` return
+ * the upstream addr.
+ */
+ ip: string;
- charset: string;
- locals: any;
+ /**
+ * When "trust proxy" is `true`, parse
+ * the "X-Forwarded-For" ip address list.
+ *
+ * For example if the value were "client, proxy1, proxy2"
+ * you would receive the array `["client", "proxy1", "proxy2"]`
+ * where "proxy2" is the furthest down-stream.
+ */
+ ips: string[];
- status(code: number): ServerResponse;
- links(links: any): ServerResponse;
+ /**
+ * Return basic auth credentials.
+ *
+ * Examples:
+ *
+ * // http://tobi:hello@example.com
+ * req.auth
+ * // => { username: 'tobi', password: 'hello' }
+ */
+ auth: any;
- send(status: number): ServerResponse;
- send(bodyOrStatus: any): ServerResponse;
- send(status: number, body: any): ServerResponse;
- json(status: number): ServerResponse;
- json(bodyOrStatus: any): ServerResponse;
- json(status: number, body: any): ServerResponse;
- jsonp(status: number): ServerResponse;
- jsonp(bodyOrStatus: any): ServerResponse;
- jsonp(status: number, body: any): ServerResponse;
+ /**
+ * Return subdomains as an array.
+ *
+ * Subdomains are the dot-separated parts of the host before the main domain of
+ * the app. By default, the domain of the app is assumed to be the last two
+ * parts of the host. This can be changed by setting "subdomain offset".
+ *
+ * For example, if the domain is "tobi.ferrets.example.com":
+ * If "subdomain offset" is not set, req.subdomains is `["ferrets", "tobi"]`.
+ * If "subdomain offset" is 3, req.subdomains is `["tobi"]`.
+ */
+ subdomains: string[];
- sendfile(path: string): void;
- sendfile(path: string, options: any): void;
- sendfile(path: string, fn: Errback): void;
- sendfile(path: string, options: any, fn: Errback): void;
- download(path: string): void;
- download(path: string, filename: string): void;
- download(path: string, fn: Errback): void;
- download(path: string, filename: string, fn: Errback): void;
+ /**
+ * Short-hand for `url.parse(req.url).pathname`.
+ */
+ path: string;
- type(type: string): ServerResponse;
- contentType(type: string): ServerResponse;
+ /**
+ * Parse the "Host" header field hostname.
+ */
+ host: string;
- format(object: any): ServerResponse;
- attachment(filename?: string): ServerResponse;
+ /**
+ * Check if the request is fresh, aka
+ * Last-Modified and/or the ETag
+ * still match.
+ */
+ fresh: bool;
- set(field: any): void;
- set(field: string, value: string): void;
- header(field: any): void;
- header(field: string, value: string): void;
+ /**
+ * Check if the request is stale, aka
+ * "Last-Modified" and / or the "ETag" for the
+ * resource has changed.
+ */
+ stale: bool;
- get(field: string): string;
+ /**
+ * Check if the request was an _XMLHttpRequest_.
+ */
+ xhr: bool;
- clearCookie(name: string, options?: any): ServerResponse;
- cookie(name: string, value: any, options?: CookieOptions): ServerResponse;
+ //body: { username: string; password: string; remember: bool; title: string; };
+ body: any;
- redirect(url: string): void;
- redirect(status: number, url: string): void;
- redirect(url: string, status: number): void;
+ //cookies: { string; remember: bool; };
+ cookies: any;
- render(view: string, options: any): void;
- render(view: string, callback: (err: Error, html: any) => void ): void;
- render(view: string, options: any, callback: (err: Error, html: any) => void ): void;
- }
+ method: string;
+
+ params: any;
+
+ user: any;
+
+ files: any;
+
+ /**
+ * Clear cookie `name`.
+ *
+ * @param name
+ * @param options
+ */
+ clearCookie(name: string, options?: any): ExpressServerResponse;
+
+ query: any;
+
+ route: any;
+
+ signedCookies: any;
+
+ originalUrl: string;
+}
+
+interface ExpressServerResponse {
+ /**
+ * Set status `code`.
+ *
+ * @param code
+ */
+ status(code: number): ExpressServerResponse;
+
+ /**
+ * Set Link header field with the given `links`.
+ *
+ * Examples:
+ *
+ * res.links({
+ * next: 'http://api.example.com/users?page=2',
+ * last: 'http://api.example.com/users?page=5'
+ * });
+ *
+ * @param links
+ */
+ links(links: any): ExpressServerResponse;
+
+ /**
+ * Send a response.
+ *
+ * Examples:
+ *
+ * res.send(new Buffer('wahoo'));
+ * res.send({ some: 'json' });
+ * res.send('some html
');
+ * res.send(404, 'Sorry, cant find that');
+ * res.send(404);
+ */
+ send(status: number): ExpressServerResponse;
+
+ send(bodyOrStatus: any): ExpressServerResponse;
+
+ send(status: number, body: any): ExpressServerResponse;
+
+
+ /**
+ * Send JSON response.
+ *
+ * Examples:
+ *
+ * res.json(null);
+ * res.json({ user: 'tj' });
+ * res.json(500, 'oh noes!');
+ * res.json(404, 'I dont have that');
+ */
+ json(status: number): ExpressServerResponse;
+
+ json(bodyOrStatus: any): ExpressServerResponse;
+
+ json(status: number, body: any): ExpressServerResponse;
+
+ /**
+ * Send JSON response with JSONP callback support.
+ *
+ * Examples:
+ *
+ * res.jsonp(null);
+ * res.jsonp({ user: 'tj' });
+ * res.jsonp(500, 'oh noes!');
+ * res.jsonp(404, 'I dont have that');
+ */
+ jsonp(status: number): ExpressServerResponse;
+
+ jsonp(bodyOrStatus: any): ExpressServerResponse;
+
+ jsonp(status: number, body: any): ExpressServerResponse;
+
+ /**
+ * Transfer the file at the given `path`.
+ *
+ * Automatically sets the _Content-Type_ response header field.
+ * The callback `fn(err)` is invoked when the transfer is complete
+ * or when an error occurs. Be sure to check `res.sentHeader`
+ * if you wish to attempt responding, as the header and some data
+ * may have already been transferred.
+ *
+ * Options:
+ *
+ * - `maxAge` defaulting to 0
+ * - `root` root directory for relative filenames
+ *
+ * Examples:
+ *
+ * The following example illustrates how `res.sendfile()` may
+ * be used as an alternative for the `static()` middleware for
+ * dynamic situations. The code backing `res.sendfile()` is actually
+ * the same code, so HTTP cache support etc is identical.
+ *
+ * app.get('/user/:uid/photos/:file', function(req, res){
+ * var uid = req.params.uid
+ * , file = req.params.file;
+ *
+ * req.user.mayViewFilesFrom(uid, function(yes){
+ * if (yes) {
+ * res.sendfile('/uploads/' + uid + '/' + file);
+ * } else {
+ * res.send(403, 'Sorry! you cant see that.');
+ * }
+ * });
+ * });
+ */
+ sendfile(path: string): void;
+
+ sendfile(path: string, options: any): void;
+
+ sendfile(path: string, fn: Errback): void;
+
+ sendfile(path: string, options: any, fn: Errback): void;
+
+ /**
+ * Transfer the file at the given `path` as an attachment.
+ *
+ * Optionally providing an alternate attachment `filename`,
+ * and optional callback `fn(err)`. The callback is invoked
+ * when the data transfer is complete, or when an error has
+ * ocurred. Be sure to check `res.headerSent` if you plan to respond.
+ *
+ * This method uses `res.sendfile()`.
+ */
+ download(path: string): void;
+
+ download(path: string, filename: string): void;
+
+ download(path: string, fn: Errback): void;
+
+ download(path: string, filename: string, fn: Errback): void;
+
+ /**
+ * Set _Content-Type_ response header with `type` through `mime.lookup()`
+ * when it does not contain "/", or set the Content-Type to `type` otherwise.
+ *
+ * Examples:
+ *
+ * res.type('.html');
+ * res.type('html');
+ * res.type('json');
+ * res.type('application/json');
+ * res.type('png');
+ *
+ * @param type
+ */
+ contentType(type: string): ExpressServerResponse;
+
+ /**
+ * Set _Content-Type_ response header with `type` through `mime.lookup()`
+ * when it does not contain "/", or set the Content-Type to `type` otherwise.
+ *
+ * Examples:
+ *
+ * res.type('.html');
+ * res.type('html');
+ * res.type('json');
+ * res.type('application/json');
+ * res.type('png');
+ *
+ * @param type
+ */
+ type(type: string): ExpressServerResponse;
+
+ /**
+ * Respond to the Acceptable formats using an `obj`
+ * of mime-type callbacks.
+ *
+ * This method uses `req.accepted`, an array of
+ * acceptable types ordered by their quality values.
+ * When "Accept" is not present the _first_ callback
+ * is invoked, otherwise the first match is used. When
+ * no match is performed the server responds with
+ * 406 "Not Acceptable".
+ *
+ * Content-Type is set for you, however if you choose
+ * you may alter this within the callback using `res.type()`
+ * or `res.set('Content-Type', ...)`.
+ *
+ * res.format({
+ * 'text/plain': function(){
+ * res.send('hey');
+ * },
+ *
+ * 'text/html': function(){
+ * res.send('hey
');
+ * },
+ *
+ * 'appliation/json': function(){
+ * res.send({ message: 'hey' });
+ * }
+ * });
+ *
+ * In addition to canonicalized MIME types you may
+ * also use extnames mapped to these types:
+ *
+ * res.format({
+ * text: function(){
+ * res.send('hey');
+ * },
+ *
+ * html: function(){
+ * res.send('hey
');
+ * },
+ *
+ * json: function(){
+ * res.send({ message: 'hey' });
+ * }
+ * });
+ *
+ * By default Express passes an `Error`
+ * with a `.status` of 406 to `next(err)`
+ * if a match is not made. If you provide
+ * a `.default` callback it will be invoked
+ * instead.
+ *
+ * @param obj
+ */
+ format(obj: any): ExpressServerResponse;
+
+ /**
+ * Set _Content-Disposition_ header to _attachment_ with optional `filename`.
+ *
+ * @param filename
+ */
+ attachment(filename?: string): ExpressServerResponse;
+
+ /**
+ * Set header `field` to `val`, or pass
+ * an object of header fields.
+ *
+ * Examples:
+ *
+ * res.set('Foo', ['bar', 'baz']);
+ * res.set('Accept', 'application/json');
+ * res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' });
+ *
+ * Aliased as `res.header()`.
+ */
+ set (field: any): void;
+
+ set (field: string, value?: string): void;
+
+ header(field: any): void;
+
+ header(field: string, value?: string): void;
+
+ /**
+ * Get value for header `field`.
+ *
+ * @param field
+ */
+ get (field: string): string;
+
+ /**
+ * Clear cookie `name`.
+ *
+ * @param name
+ * @param options
+ */
+ clearCookie(name: string, options?: any): ExpressServerResponse;
+
+ /**
+ * Set cookie `name` to `val`, with the given `options`.
+ *
+ * Options:
+ *
+ * - `maxAge` max-age in milliseconds, converted to `expires`
+ * - `signed` sign the cookie
+ * - `path` defaults to "/"
+ *
+ * Examples:
+ *
+ * // "Remember Me" for 15 minutes
+ * res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });
+ *
+ * // save as above
+ * res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
+ */
+ cookie(name: string, val: string, options: CookieOptions);
+
+ cookie(name: string, val: any, options: CookieOptions);
+
+ cookie(name: string, val: any);
+
+ /**
+ * Set the location header to `url`.
+ *
+ * The given `url` can also be the name of a mapped url, for
+ * example by default express supports "back" which redirects
+ * to the _Referrer_ or _Referer_ headers or "/".
+ *
+ * Examples:
+ *
+ * res.location('/foo/bar').;
+ * res.location('http://example.com');
+ * res.location('../login'); // /blog/post/1 -> /blog/login
+ *
+ * Mounting:
+ *
+ * When an application is mounted and `res.location()`
+ * is given a path that does _not_ lead with "/" it becomes
+ * relative to the mount-point. For example if the application
+ * is mounted at "/blog", the following would become "/blog/login".
+ *
+ * res.location('login');
+ *
+ * While the leading slash would result in a location of "/login":
+ *
+ * res.location('/login');
+ *
+ * @param url
+ */
+ location(url: string);
+
+ /**
+ * Redirect to the given `url` with optional response `status`
+ * defaulting to 302.
+ *
+ * The resulting `url` is determined by `res.location()`, so
+ * it will play nicely with mounted apps, relative paths,
+ * `"back"` etc.
+ *
+ * Examples:
+ *
+ * res.redirect('/foo/bar');
+ * res.redirect('http://example.com');
+ * res.redirect(301, 'http://example.com');
+ * res.redirect('http://example.com', 301);
+ * res.redirect('../login'); // /blog/post/1 -> /blog/login
+ */
+ redirect(url: string): void;
+
+ redirect(status: number, url: string): void;
+
+ redirect(url: string, status: number): void;
+
+ /**
+ * Render `view` with the given `options` and optional callback `fn`.
+ * When a callback function is given a response will _not_ be made
+ * automatically, otherwise a response of _200_ and _text/html_ is given.
+ *
+ * Options:
+ *
+ * - `cache` boolean hinting to the engine it should cache
+ * - `filename` filename of the view being rendered
+ */
+ render(view: string): void;
+
+ render(view: string, options: any): void;
+
+ render(view: string, callback: (err: Error, html: any) => void ): void;
+
+ render(view: string, options: any, callback: (err: Error, html: any) => void ): void;
+
+ locals: any;
+
+ charset: string;
+}
+
+interface ExpressApplication {
+ /**
+ * Initialize the server.
+ *
+ * - setup default configuration
+ * - setup default middleware
+ * - setup route reflection methods
+ */
+ init();
+
+ /**
+ * Initialize application configuration.
+ */
+ defaultConfiguration();
+
+ /**
+ * Proxy `connect#use()` to apply settings to
+ * mounted applications.
+ **/
+ use(route: string, callback?: Function): ExpressApplication;
+
+ use(route: string, server: ExpressApplication): ExpressApplication;
+
+ use(callback: Function): ExpressApplication;
+
+ use(server: ExpressApplication): ExpressApplication;
+
+ /**
+ * Register the given template engine callback `fn`
+ * as `ext`.
+ *
+ * By default will `require()` the engine based on the
+ * file extension. For example if you try to render
+ * a "foo.jade" file Express will invoke the following internally:
+ *
+ * app.engine('jade', require('jade').__express);
+ *
+ * For engines that do not provide `.__express` out of the box,
+ * or if you wish to "map" a different extension to the template engine
+ * you may use this method. For example mapping the EJS template engine to
+ * ".html" files:
+ *
+ * app.engine('html', require('ejs').renderFile);
+ *
+ * In this case EJS provides a `.renderFile()` method with
+ * the same signature that Express expects: `(path, options, callback)`,
+ * though note that it aliases this method as `ejs.__express` internally
+ * so if you're using ".ejs" extensions you dont need to do anything.
+ *
+ * Some template engines do not follow this convention, the
+ * [Consolidate.js](https://github.com/visionmedia/consolidate.js)
+ * library was created to map all of node's popular template
+ * engines to follow this convention, thus allowing them to
+ * work seamlessly within Express.
+ */
+ engine(ext: string, fn: Function): ExpressApplication;
+
+ /**
+ * Map the given param placeholder `name`(s) to the given callback(s).
+ *
+ * Parameter mapping is used to provide pre-conditions to routes
+ * which use normalized placeholders. For example a _:user_id_ parameter
+ * could automatically load a user's information from the database without
+ * any additional code,
+ *
+ * The callback uses the samesignature as middleware, the only differencing
+ * being that the value of the placeholder is passed, in this case the _id_
+ * of the user. Once the `next()` function is invoked, just like middleware
+ * it will continue on to execute the route, or subsequent parameter functions.
+ *
+ * app.param('user_id', function(req, res, next, id){
+ * User.find(id, function(err, user){
+ * if (err) {
+ * next(err);
+ * } else if (user) {
+ * req.user = user;
+ * next();
+ * } else {
+ * next(new Error('failed to load user'));
+ * }
+ * });
+ * });
+ *
+ * @param name
+ * @param fn
+ */
+ param(name: string, fn: Function): ExpressApplication;
+
+ param(name: Array, fn: Function): ExpressApplication;
+
+ /**
+ * Assign `setting` to `val`, or return `setting`'s value.
+ *
+ * app.set('foo', 'bar');
+ * app.get('foo');
+ * // => "bar"
+ *
+ * Mounted servers inherit their parent server's settings.
+ *
+ * @param setting
+ * @param val
+ */
+ set (setting: string, val: string): ExpressApplication;
+
+ /**
+ * Return the app's absolute pathname
+ * based on the parent(s) that have
+ * mounted it.
+ *
+ * For example if the application was
+ * mounted as "/admin", which itself
+ * was mounted as "/blog" then the
+ * return value would be "/blog/admin".
+ */
+ path(): string;
+
+ /**
+ * Check if `setting` is enabled (truthy).
+ *
+ * app.enabled('foo')
+ * // => false
+ *
+ * app.enable('foo')
+ * app.enabled('foo')
+ * // => true
+ */
+ enabled(setting: string): bool;
+
+ /**
+ * Check if `setting` is disabled.
+ *
+ * app.disabled('foo')
+ * // => true
+ *
+ * app.enable('foo')
+ * app.disabled('foo')
+ * // => false
+ *
+ * @param setting
+ */
+ disabled(setting: string): bool;
+
+ /**
+ * Enable `setting`.
+ *
+ * @param setting
+ */
+ enable(setting: string): ExpressApplication;
+
+ /**
+ * Disable `setting`.
+ *
+ * @param setting
+ */
+ disable(setting: string): ExpressApplication;
+
+ /**
+ * Configure callback for zero or more envs,
+ * when no `env` is specified that callback will
+ * be invoked for all environments. Any combination
+ * can be used multiple times, in any order desired.
+ *
+ * Examples:
+ *
+ * app.configure(function(){
+ * // executed for all envs
+ * });
+ *
+ * app.configure('stage', function(){
+ * // executed staging env
+ * });
+ *
+ * app.configure('stage', 'production', function(){
+ * // executed for stage and production
+ * });
+ *
+ * Note:
+ *
+ * These callbacks are invoked immediately, and
+ * are effectively sugar for the following:
+ *
+ * var env = process.env.NODE_ENV || 'development';
+ *
+ * switch (env) {
+ * case 'development':
+ * ...
+ * break;
+ * case 'stage':
+ * ...
+ * break;
+ * case 'production':
+ * ...
+ * break;
+ * }
+ *
+ * @param env
+ * @param fn
+ */
+ configure(env: string, fn: Function): ExpressApplication;
+
+ configure(env0: string, env1: string, fn: Function): ExpressApplication;
+
+ configure(env0: string, env1: string, env2: string, fn: Function): ExpressApplication;
+
+ configure(env0: string, env1: string, env2: string, env3: string, fn: Function): ExpressApplication;
+
+ configure(env0: string, env1: string, env2: string, env3: string, env4: string, fn: Function): ExpressApplication;
+
+ configure(fn: Function): ExpressApplication;
+
+ /**
+ * Special-cased "all" method, applying the given route `path`,
+ * middleware, and callback to _every_ HTTP method.
+ *
+ * @param path
+ * @param fn
+ */
+ all(path: string, fn?: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): ExpressApplication;
+
+ all(path: string, ...callbacks: Function[]): void;
+
+ /**
+ * Render the given view `name` name with `options`
+ * and a callback accepting an error and the
+ * rendered template string.
+ *
+ * Example:
+ *
+ * app.render('email', { name: 'Tobi' }, function(err, html){
+ * // ...
+ * })
+ *
+ * @param name
+ * @param options or fn
+ * @param fn
+ */
+ render(name: string, options: string, fn: Function);
+
+ render(name: string, fn: Function);
+
+ get (name: string): any;
+
+ get (name: string, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ get (name: RegExp): any;
+
+ get (name: RegExp, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ get (name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ post(name: string): any;
+
+ post(name: string, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ post(name: RegExp): any;
+
+ post(name: RegExp, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ post(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ put(name: string): any;
+
+ put(name: string, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ put(name: RegExp): any;
+
+ put(name: RegExp, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ put(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ del(name: string): any;
+
+ del(name: string, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: string,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ del(name: RegExp): any;
+
+ del(name: RegExp, handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any): any;
+
+ del(name: RegExp,
+ handler: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler2: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler3: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler4: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ handler5: (req: ExpressServerRequest, res: ExpressServerResponse, next: Function) => any,
+ ...handlers: any[]): any;
+
+ /**
+ * Listen for connections.
+ *
+ * A node `http.Server` is returned, with this
+ * application (which is a `Function`) as its
+ * callback. If you wish to create both an HTTP
+ * and HTTPS server you may do so with the "http"
+ * and "https" modules as shown here:
+ *
+ * var http = require('http')
+ * , https = require('https')
+ * , express = require('express')
+ * , app = express();
+ *
+ * http.createServer(app).listen(80);
+ * https.createServer({ ... }, app).listen(443);
+ */
+ listen(port: number, hostname: string, backlog: number, callback: Function): void;
+
+ listen(port: number, callback: Function): void;
+
+ listen(path: string, callback?: Function): void;
+
+ listen(handle: any, listeningListener?: Function): void;
+
+ render(view: string, callback: (err: Error, html) => void ): void;
+
+ render(view: string, optionss: any, callback: (err: Error, html) => void ): void;
+
+ route: Route;
+
+ router: string;
+
+ settings: any;
+
+ resource: any;
+
+ map: any;
+
+ locals: any;
+}
+
+interface Express extends ExpressApplication {
+ /**
+ * Framework version.
+ */
+ version: string;
+
+ /**
+ * Expose mime.
+ */
+ mime: string;
+
+ (): ExpressApplication;
+
+ /**
+ * Create an express application.
+ */
+ createApplication(): ExpressApplication;
+
+ createServer(): ExpressApplication;
+
+ application: any;
+
+ request: ExpressServerRequest;
+
+ response: ExpressServerResponse;
}
declare module "express" {
- export function (): _express.ServerApplication;
- export function createServer(): ServerApplication;
- export function static(path: string): any;
- export var listen;
+ export function (): Express;
- // Connect middleware
+ /**
+ * Body parser:
+ *
+ * Parse request bodies, supports _application/json_,
+ * _application/x-www-form-urlencoded_, and _multipart/form-data_.
+ *
+ * This is equivalent to:
+ *
+ * app.use(connect.json());
+ * app.use(connect.urlencoded());
+ * app.use(connect.multipart());
+ *
+ * Examples:
+ *
+ * connect()
+ * .use(connect.bodyParser())
+ * .use(function(req, res) {
+ * res.end('viewing user ' + req.body.user.name);
+ * });
+ *
+ * $ curl -d 'user[name]=tj' http://local/
+ * $ curl -d '{"user":{"name":"tj"}}' -H "Content-Type: application/json" http://local/
+ *
+ * View [json](json.html), [urlencoded](urlencoded.html), and [multipart](multipart.html) for more info.
+ *
+ * @param options
+ */
export function bodyParser(options?: any): Handler;
- export function errorHandler(opts?: any): Handler;
- export function methodOverride(): Handler;
- export interface ServerApplication extends _express.ServerApplication {}
- export interface ServerRequest extends _express.ServerRequest {}
- export interface ServerResponse extends _express.ServerResponse {}
- export interface Handler extends _express.Handler {}
-}
+ /**
+ * Error handler:
+ *
+ * Development error handler, providing stack traces
+ * and error message responses for requests accepting text, html,
+ * or json.
+ *
+ * Text:
+ *
+ * By default, and when _text/plain_ is accepted a simple stack trace
+ * or error message will be returned.
+ *
+ * JSON:
+ *
+ * When _application/json_ is accepted, connect will respond with
+ * an object in the form of `{ "error": error }`.
+ *
+ * HTML:
+ *
+ * When accepted connect will output a nice html stack trace.
+ */
+ export function errorHandler(opts?: any): Handler;
+
+ /**
+ * Method Override:
+ *
+ * Provides faux HTTP method support.
+ *
+ * Pass an optional `key` to use when checking for
+ * a method override, othewise defaults to _\_method_.
+ * The original method is available via `req.originalMethod`.
+ *
+ * @param key
+ */
+ export function methodOverride(key?: string): Handler;
+
+ /**
+ * Cookie parser:
+ *
+ * Parse _Cookie_ header and populate `req.cookies`
+ * with an object keyed by the cookie names. Optionally
+ * you may enabled signed cookie support by passing
+ * a `secret` string, which assigns `req.secret` so
+ * it may be used by other middleware.
+ *
+ * Examples:
+ *
+ * connect()
+ * .use(connect.cookieParser('optional secret string'))
+ * .use(function(req, res, next){
+ * res.end(JSON.stringify(req.cookies));
+ * })
+ *
+ * @param secret
+ */
+ export function cookieParser(secret?: string): Handler;
+
+ /**
+ * Session:
+ *
+ * Setup session store with the given `options`.
+ *
+ * Session data is _not_ saved in the cookie itself, however
+ * cookies are used, so we must use the [cookieParser()](cookieParser.html)
+ * middleware _before_ `session()`.
+ *
+ * Examples:
+ *
+ * connect()
+ * .use(connect.cookieParser())
+ * .use(connect.session({ secret: 'keyboard cat', key: 'sid', cookie: { secure: true }}))
+ *
+ * Options:
+ *
+ * - `key` cookie name defaulting to `connect.sid`
+ * - `store` session store instance
+ * - `secret` session cookie is signed with this secret to prevent tampering
+ * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`
+ * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto")
+ *
+ * Cookie option:
+ *
+ * By default `cookie.maxAge` is `null`, meaning no "expires" parameter is set
+ * so the cookie becomes a browser-session cookie. When the user closes the
+ * browser the cookie (and session) will be removed.
+ *
+ * ## req.session
+ *
+ * To store or access session data, simply use the request property `req.session`,
+ * which is (generally) serialized as JSON by the store, so nested objects
+ * are typically fine. For example below is a user-specific view counter:
+ *
+ * connect()
+ * .use(connect.favicon())
+ * .use(connect.cookieParser())
+ * .use(connect.session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
+ * .use(function(req, res, next){
+ * var sess = req.session;
+ * if (sess.views) {
+ * res.setHeader('Content-Type', 'text/html');
+ * res.write('views: ' + sess.views + '
');
+ * res.write('expires in: ' + (sess.cookie.maxAge / 1000) + 's
');
+ * res.end();
+ * sess.views++;
+ * } else {
+ * sess.views = 1;
+ * res.end('welcome to the session demo. refresh!');
+ * }
+ * }
+ * )).listen(3000);
+ *
+ * ## Session#regenerate()
+ *
+ * To regenerate the session simply invoke the method, once complete
+ * a new SID and `Session` instance will be initialized at `req.session`.
+ *
+ * req.session.regenerate(function(err){
+ * // will have a new session here
+ * });
+ *
+ * ## Session#destroy()
+ *
+ * Destroys the session, removing `req.session`, will be re-generated next request.
+ *
+ * req.session.destroy(function(err){
+ * // cannot access session here
+ * });
+ *
+ * ## Session#reload()
+ *
+ * Reloads the session data.
+ *
+ * req.session.reload(function(err){
+ * // session updated
+ * });
+ *
+ * ## Session#save()
+ *
+ * Save the session.
+ *
+ * req.session.save(function(err){
+ * // session saved
+ * });
+ *
+ * ## Session#touch()
+ *
+ * Updates the `.maxAge` property. Typically this is
+ * not necessary to call, as the session middleware does this for you.
+ *
+ * ## Session#cookie
+ *
+ * Each session has a unique cookie object accompany it. This allows
+ * you to alter the session cookie per visitor. For example we can
+ * set `req.session.cookie.expires` to `false` to enable the cookie
+ * to remain for only the duration of the user-agent.
+ *
+ * ## Session#maxAge
+ *
+ * Alternatively `req.session.cookie.maxAge` will return the time
+ * remaining in milliseconds, which we may also re-assign a new value
+ * to adjust the `.expires` property appropriately. The following
+ * are essentially equivalent
+ *
+ * var hour = 3600000;
+ * req.session.cookie.expires = new Date(Date.now() + hour);
+ * req.session.cookie.maxAge = hour;
+ *
+ * For example when `maxAge` is set to `60000` (one minute), and 30 seconds
+ * has elapsed it will return `30000` until the current request has completed,
+ * at which time `req.session.touch()` is called to reset `req.session.maxAge`
+ * to its original value.
+ *
+ * req.session.cookie.maxAge;
+ * // => 30000
+ *
+ * Session Store Implementation:
+ *
+ * Every session store _must_ implement the following methods
+ *
+ * - `.get(sid, callback)`
+ * - `.set(sid, session, callback)`
+ * - `.destroy(sid, callback)`
+ *
+ * Recommended methods include, but are not limited to:
+ *
+ * - `.length(callback)`
+ * - `.clear(callback)`
+ *
+ * For an example implementation view the [connect-redis](http://github.com/visionmedia/connect-redis) repo.
+ *
+ * @param options
+ */
+ export function session(options?: any): Handler;
+
+ /**
+ * Hash the given `sess` object omitting changes
+ * to `.cookie`.
+ *
+ * @param sess
+ */
+ export function hash(sess: string): string;
+
+ /**
+ * Static:
+ *
+ * Static file server with the given `root` path.
+ *
+ * Examples:
+ *
+ * var oneDay = 86400000;
+ *
+ * connect()
+ * .use(connect.static(__dirname + '/public'))
+ *
+ * connect()
+ * .use(connect.static(__dirname + '/public', { maxAge: oneDay }))
+ *
+ * Options:
+ *
+ * - `maxAge` Browser cache maxAge in milliseconds. defaults to 0
+ * - `hidden` Allow transfer of hidden files. defaults to false
+ * - `redirect` Redirect to trailing "/" when the pathname is a dir. defaults to true
+ *
+ * @param root
+ * @param options
+ */
+ export function static (root: string, options?: any): Handler;
+
+ /**
+ * Basic Auth:
+ *
+ * Enfore basic authentication by providing a `callback(user, pass)`,
+ * which must return `true` in order to gain access. Alternatively an async
+ * method is provided as well, invoking `callback(user, pass, callback)`. Populates
+ * `req.user`. The final alternative is simply passing username / password
+ * strings.
+ *
+ * Simple username and password
+ *
+ * connect(connect.basicAuth('username', 'password'));
+ *
+ * Callback verification
+ *
+ * connect()
+ * .use(connect.basicAuth(function(user, pass){
+ * return 'tj' == user & 'wahoo' == pass;
+ * }))
+ *
+ * Async callback verification, accepting `fn(err, user)`.
+ *
+ * connect()
+ * .use(connect.basicAuth(function(user, pass, fn){
+ * User.authenticate({ user: user, pass: pass }, fn);
+ * }))
+ *
+ * @param callback or username
+ * @param realm
+ */
+ export function basicAuth(callback: Function, realm: string);
+
+ export function basicAuth(callback: string, realm: string);
+
+ export function basicAuth(callback: Function);
+
+ /**
+ * Compress:
+ *
+ * Compress response data with gzip/deflate.
+ *
+ * Filter:
+ *
+ * A `filter` callback function may be passed to
+ * replace the default logic of:
+ *
+ * exports.filter = function(req, res){
+ * return /json|text|javascript/.test(res.getHeader('Content-Type'));
+ * };
+ *
+ * Options:
+ *
+ * All remaining options are passed to the gzip/deflate
+ * creation functions. Consult node's docs for additional details.
+ *
+ * - `chunkSize` (default: 16*1024)
+ * - `windowBits`
+ * - `level`: 0-9 where 0 is no compression, and 9 is slow but best compression
+ * - `memLevel`: 1-9 low is slower but uses less memory, high is fast but uses more
+ * - `strategy`: compression strategy
+ *
+ * @param options
+ */
+ export function compress(options?: any): Handler;
+
+ /**
+ * Cookie Session:
+ *
+ * Cookie session middleware.
+ *
+ * var app = connect();
+ * app.use(connect.cookieParser());
+ * app.use(connect.cookieSession({ secret: 'tobo!', cookie: { maxAge: 60 * 60 * 1000 }}));
+ *
+ * Options:
+ *
+ * - `key` cookie name defaulting to `connect.sess`
+ * - `secret` prevents cookie tampering
+ * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`
+ * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto")
+ *
+ * Clearing sessions:
+ *
+ * To clear the session simply set its value to `null`,
+ * `cookieSession()` will then respond with a 1970 Set-Cookie.
+ *
+ * req.session = null;
+ *
+ * @param options
+ */
+ export function cookieSession(options?: any): Handler;
+
+ /**
+ * Anti CSRF:
+ *
+ * CRSF protection middleware.
+ *
+ * By default this middleware generates a token named "_csrf"
+ * which should be added to requests which mutate
+ * state, within a hidden form field, query-string etc. This
+ * token is validated against the visitor's `req.session._csrf`
+ * property.
+ *
+ * The default `value` function checks `req.body` generated
+ * by the `bodyParser()` middleware, `req.query` generated
+ * by `query()`, and the "X-CSRF-Token" header field.
+ *
+ * This middleware requires session support, thus should be added
+ * somewhere _below_ `session()` and `cookieParser()`.
+ *
+ * Options:
+ *
+ * - `value` a function accepting the request, returning the token
+ *
+ * @param options
+ */
+ export function csrf(options: any);
+
+ /**
+ * Directory:
+ *
+ * Serve directory listings with the given `root` path.
+ *
+ * Options:
+ *
+ * - `hidden` display hidden (dot) files. Defaults to false.
+ * - `icons` display icons. Defaults to false.
+ * - `filter` Apply this filter function to files. Defaults to false.
+ *
+ * @param root
+ * @param options
+ */
+ export function directory(root: string, options?: any): Handler;
+
+ /**
+ * Favicon:
+ *
+ * By default serves the connect favicon, or the favicon
+ * located by the given `path`.
+ *
+ * Options:
+ *
+ * - `maxAge` cache-control max-age directive, defaulting to 1 day
+ *
+ * Examples:
+ *
+ * Serve default favicon:
+ *
+ * connect()
+ * .use(connect.favicon())
+ *
+ * Serve favicon before logging for brevity:
+ *
+ * connect()
+ * .use(connect.favicon())
+ * .use(connect.logger('dev'))
+ *
+ * Serve custom favicon:
+ *
+ * connect()
+ * .use(connect.favicon('public/favicon.ico))
+ *
+ * @param path
+ * @param options
+ */
+ export function favicon(path?: string, options?: any);
+
+ /**
+ * JSON:
+ *
+ * Parse JSON request bodies, providing the
+ * parsed object as `req.body`.
+ *
+ * Options:
+ *
+ * - `strict` when `false` anything `JSON.parse()` accepts will be parsed
+ * - `reviver` used as the second "reviver" argument for JSON.parse
+ * - `limit` byte limit disabled by default
+ *
+ * @param options
+ */
+ export function json(options?: any): Handler;
+
+ /**
+ * Limit:
+ *
+ * Limit request bodies to the given size in `bytes`.
+ *
+ * A string representation of the bytesize may also be passed,
+ * for example "5mb", "200kb", "1gb", etc.
+ *
+ * connect()
+ * .use(connect.limit('5.5mb'))
+ * .use(handleImageUpload)
+ */
+ export function limit(bytes: number): Handler;
+
+ export function limit(bytes: string): Handler;
+
+ /**
+ * Logger:
+ *
+ * Log requests with the given `options` or a `format` string.
+ *
+ * Options:
+ *
+ * - `format` Format string, see below for tokens
+ * - `stream` Output stream, defaults to _stdout_
+ * - `buffer` Buffer duration, defaults to 1000ms when _true_
+ * - `immediate` Write log line on request instead of response (for response times)
+ *
+ * Tokens:
+ *
+ * - `:req[header]` ex: `:req[Accept]`
+ * - `:res[header]` ex: `:res[Content-Length]`
+ * - `:http-version`
+ * - `:response-time`
+ * - `:remote-addr`
+ * - `:date`
+ * - `:method`
+ * - `:url`
+ * - `:referrer`
+ * - `:user-agent`
+ * - `:status`
+ *
+ * Formats:
+ *
+ * Pre-defined formats that ship with connect:
+ *
+ * - `default` ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'
+ * - `short` ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'
+ * - `tiny` ':method :url :status :res[content-length] - :response-time ms'
+ * - `dev` concise output colored by response status for development use
+ *
+ * Examples:
+ *
+ * connect.logger() // default
+ * connect.logger('short')
+ * connect.logger('tiny')
+ * connect.logger({ immediate: true, format: 'dev' })
+ * connect.logger(':method :url - :referrer')
+ * connect.logger(':req[content-type] -> :res[content-type]')
+ * connect.logger(function(tokens, req, res){ return 'some format string' })
+ *
+ * Defining Tokens:
+ *
+ * To define a token, simply invoke `connect.logger.token()` with the
+ * name and a callback function. The value returned is then available
+ * as ":type" in this case.
+ *
+ * connect.logger.token('type', function(req, res){ return req.headers['content-type']; })
+ *
+ * Defining Formats:
+ *
+ * All default formats are defined this way, however it's public API as well:
+ *
+ * connect.logger.format('name', 'string or function')
+ */
+ export function logger(options: string): Handler;
+
+ export function logger(options: Function): Handler;
+
+ export function logger(options?: any): Handler;
+
+ /**
+ * Compile `fmt` into a function.
+ *
+ * @param fmt
+ */
+ export function compile(fmt: string): Handler;
+
+ /**
+ * Define a token function with the given `name`,
+ * and callback `fn(req, res)`.
+ *
+ * @param name
+ * @param fn
+ */
+ export function token(name: string, fn: Function): any;
+
+ /**
+ * Define a `fmt` with the given `name`.
+ */
+ export function format(name: string, str: string): any;
+
+ export function format(name: string, str: Function): any;
+
+ /**
+ * Query:
+ *
+ * Automatically parse the query-string when available,
+ * populating the `req.query` object.
+ *
+ * Examples:
+ *
+ * connect()
+ * .use(connect.query())
+ * .use(function(req, res){
+ * res.end(JSON.stringify(req.query));
+ * });
+ *
+ * The `options` passed are provided to qs.parse function.
+ */
+ export function query(options: any): Handler;
+
+ /**
+ * Reponse time:
+ *
+ * Adds the `X-Response-Time` header displaying the response
+ * duration in milliseconds.
+ */
+ export function responseTime(): Handler;
+
+ /**
+ * Static cache:
+ *
+ * Enables a memory cache layer on top of
+ * the `static()` middleware, serving popular
+ * static files.
+ *
+ * By default a maximum of 128 objects are
+ * held in cache, with a max of 256k each,
+ * totalling ~32mb.
+ *
+ * A Least-Recently-Used (LRU) cache algo
+ * is implemented through the `Cache` object,
+ * simply rotating cache objects as they are
+ * hit. This means that increasingly popular
+ * objects maintain their positions while
+ * others get shoved out of the stack and
+ * garbage collected.
+ *
+ * Benchmarks:
+ *
+ * static(): 2700 rps
+ * node-static: 5300 rps
+ * static() + staticCache(): 7500 rps
+ *
+ * Options:
+ *
+ * - `maxObjects` max cache objects [128]
+ * - `maxLength` max cache object length 256kb
+ */
+ export function staticCache(options: any): Handler;
+
+ /**
+ * Timeout:
+ *
+ * Times out the request in `ms`, defaulting to `5000`. The
+ * method `req.clearTimeout()` is added to revert this behaviour
+ * programmatically within your application's middleware, routes, etc.
+ *
+ * The timeout error is passed to `next()` so that you may customize
+ * the response behaviour. This error has the `.timeout` property as
+ * well as `.status == 408`.
+ */
+ export function timeout(ms: number): Handler;
+
+ /**
+ * Vhost:
+ *
+ * Setup vhost for the given `hostname` and `server`.
+ *
+ * connect()
+ * .use(connect.vhost('foo.com', fooApp))
+ * .use(connect.vhost('bar.com', barApp))
+ * .use(connect.vhost('*.com', mainApp))
+ *
+ * The `server` may be a Connect server or
+ * a regular Node `http.Server`.
+ *
+ * @param hostname
+ * @param server
+ */
+ export function vhost(hostname: string, server: any): Handler;
+
+ export function urlencoded(): any;
+
+ export function multipart(): any;
+}
\ No newline at end of file
diff --git a/jquery.bbq/jquery.bbq-tests.ts b/jquery.bbq/jquery.bbq-tests.ts
new file mode 100644
index 000000000..1543ae63c
--- /dev/null
+++ b/jquery.bbq/jquery.bbq-tests.ts
@@ -0,0 +1,1282 @@
+///
+///
+
+
+// ************** Tests to jquery JQueryParam interface
+var myObject = {
+ a: {
+ one: 1,
+ two: 2,
+ three: 3
+ },
+ b: [1,2,3]
+};
+var recursiveEncoded = $.param(myObject);
+var recursiveDecoded = decodeURIComponent($.param(myObject));
+var shallowEncoded = $.param(myObject, true);
+var shallowDecoded = decodeURIComponent(shallowEncoded);
+
+var params = { width:1680, height:1050 };
+var str = jQuery.param(params);
+$("#results").text(str);
+
+// <=1.3.2:
+$.param({ a: [2,3,4] }) // "a=2&a=3&a=4"
+// >=1.4:
+$.param({ a: [2,3,4] }) // "a[]=2&a[]=3&a[]=4"
+
+// <=1.3.2:
+$.param({ a: { b:1,c:2 }, d: [3,4,{ e:5 }] }) // "a=[object+Object]&d=3&d=4&d=[object+Object]"
+// >=1.4:
+$.param({ a: { b:1,c:2 }, d: [3,4,{ e:5 }] }) // "a[b]=1&a[c]=2&d[]=3&d[]=4&d[2][e]=5"
+// *************************************************************
+
+// Not sure why this isn't set by default in qunit.js..
+QUnit.jsDump.HTML = false;
+
+$(function(){ // START CLOSURE
+
+
+var old_jquery = $.fn.jquery < '1.4',
+ is_chrome = /chrome/i.test( navigator.userAgent ),
+ params_init = 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=1',
+ init_url,
+ ajaxcrawlable_init = $.param.fragment.ajaxCrawlable(),
+ aps = Array.prototype.slice;
+
+if ( $.param.querystring() !== params_init || $.param.fragment() !== params_init ) {
+ init_url = window.location.href;
+ init_url = $.param.querystring( init_url, params_init, 2 );
+ init_url = $.param.fragment( init_url, params_init, 2 );
+ window.location.href = init_url;
+}
+
+$('#jq_version').html( $.fn.jquery );
+
+function notice( txt? ) {
+ if ( txt ) {
+ $('#notice').html( txt );
+ } else {
+ $('#notice').hide();
+ }
+};
+
+function run_many_tests(...args: any[]) {
+ var tests = aps.call( arguments ),
+ delay = typeof tests[0] === 'number' && tests.shift(),
+ func_each = $.isFunction( tests[0] ) && tests.shift(),
+ func_done = $.isFunction( tests[0] ) && tests.shift(),
+ result;
+
+ function set_result( i, test ) {
+ result = $.isArray( test )
+ ? func_each.apply( this, test )
+ : $.isFunction( test )
+ ? test( result )
+ : '';
+ };
+
+ if ( delay ) {
+ stop();
+
+ (function loopy(){
+ //test && test.func && test.func( result );
+ if ( tests.length ) {
+ set_result( 0, tests.shift() );
+ setTimeout( loopy, delay );
+ } else {
+ func_done && func_done();
+ start();
+ }
+ })();
+
+ } else {
+ $.each( tests, set_result );
+ func_done && func_done();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+QUnit.module( 'jQuery.param' );
+
+var params_obj = { a:['4','5','6'], b:{x:['7'], y:'8', z:['9','0','true','false','undefined','']}, c:'1' },
+ params_obj_coerce = { a:[4,5,6] },//, b:{x:[7], y:8, z:[9,0,true,false,undefined,'']}, c:1 },
+ params_str = params_init,
+ params_str_old = 'a=4&a=5&a=6&b=[object+Object]&c=1',
+
+ // If a params fragment starts with ! and BBQ is not in ajaxCrawlable mode,
+ // things can get very ugly, very quickly.
+ params_obj_bang = { "!a":['4'], a:['5','6'], b:{x:['7'], y:'8', z:['9','0','true','false','undefined','']}, c:'1' },
+ params_obj_bang_coerce = { "!a":[4], a:[5,6] };//, b:{x:[7], y:8, z:[9,0,true,false,undefined,'']}, c:1 };
+
+test( 'jQuery.param.sorted', function() {
+ var tests = [
+ {
+ obj: {z:1,b:2,ab:3,bc:4,ba:5,aa:6,a1:7,x:8},
+ traditional: false,
+ expected: 'a1=7&aa=6&ab=3&b=2&ba=5&bc=4&x=8&z=1'
+ },
+ {
+ obj: {z:1,b:[6,5,4],x:2,a:[3,2,1]},
+ traditional: false,
+ expected: 'a[]=3&a[]=2&a[]=1&b[]=6&b[]=5&b[]=4&x=2&z=1',
+ expected_old: 'a=3&a=2&a=1&b=6&b=5&b=4&x=2&z=1'
+ },
+ {
+ obj: {z:1,b:[6,5,4],x:2,a:[3,2,1]},
+ traditional: true,
+ expected: 'a=3&a=2&a=1&b=6&b=5&b=4&x=2&z=1'
+ },
+ {
+ obj: {a:[[4,[5,6]],[[7,8],9]]},
+ traditional: false,
+ expected: 'a[0][]=4&a[0][1][]=5&a[0][1][]=6&a[1][0][]=7&a[1][0][]=8&a[1][]=9',
+ expected_old: 'a=4,5,6&a=7,8,9' // obviously not great, but that's the way jQuery used to roll
+ }
+ ];
+
+ if ( $.fn.jquery != '1.4.1' ) {
+ // this explodes in jQuery 1.4.1
+ tests.push({
+ obj: {z:1,'b[]':[6,5,4],x:2,'a[]':[3,2,1]},
+ obj_alt: {z:1,b:[6,5,4],x:2,a:[3,2,1]},
+ traditional: false,
+ expected: 'a[]=3&a[]=2&a[]=1&b[]=6&b[]=5&b[]=4&x=2&z=1'
+ });
+ }
+
+ expect( tests.length * 2 + 6 );
+
+ $.each( tests, function(i,test){
+ var unsorted = $.param( test.obj, test.traditional ),
+ sorted = $.param.sorted( test.obj, test.traditional );
+
+ equal( decodeURIComponent( sorted ), old_jquery && test.expected_old || test.expected, 'params should be sorted' );
+ deepEqual( $.deparam( unsorted, true ), $.deparam( sorted, true ), 'sorted params should deparam the same as unsorted params' )
+ });
+
+ equal( $.param.fragment( 'foo', '#b=2&a=1' ), 'foo#a=1&b=2', 'params should be sorted' );
+ equal( $.param.fragment( 'foo', '#b=2&a=1', 1 ), 'foo#a=1&b=2', 'params should be sorted' );
+ equal( $.param.fragment( 'foo', '#b=2&a=1', 2 ), 'foo#b=2&a=1', 'params should NOT be sorted' );
+ equal( $.param.fragment( 'foo#c=3&a=4', '#b=2&a=1' ), 'foo#a=1&b=2&c=3', 'params should be sorted' );
+ equal( $.param.fragment( 'foo#c=3&a=4', '#b=2&a=1', 1 ), 'foo#a=4&b=2&c=3', 'params should be sorted' );
+ equal( $.param.fragment( 'foo#c=3&a=4', '#b=2&a=1', 2 ), 'foo#b=2&a=1', 'params should NOT be sorted' );
+
+});
+
+test( 'jQuery.param.querystring', function() {
+ expect( 11 );
+
+ equal( $.param.querystring( 'http://example.com/' ), '', 'properly identifying params' );
+ equal( $.param.querystring( 'http://example.com/?foo' ),'foo', 'properly identifying params' );
+ equal( $.param.querystring( 'http://example.com/?foo#bar' ),'foo', 'properly identifying params' );
+ equal( $.param.querystring( 'http://example.com/?foo#bar?baz' ),'foo', 'properly identifying params' );
+ equal( $.param.querystring( 'http://example.com/#foo' ),'', 'properly identifying params' );
+ equal( $.param.querystring( 'http://example.com/#foo?bar' ),'', 'properly identifying params' );
+
+ equal( $.param.querystring(), params_str, 'params string from window.location' );
+ equal( $.param.querystring( '?' + params_str ), params_str, 'params string from url' );
+ equal( $.param.querystring( 'foo.html?' + params_str ), params_str, 'params string from url' );
+ equal( $.param.querystring( 'http://a:b@example.com:1234/foo.html?' + params_str ), params_str, 'params string from url' );
+ equal( $.param.querystring( 'http://a:b@example.com:1234/foo.html?' + params_str + '#bippity-boppity-boo' ), params_str, 'params string from url' );
+});
+
+test( 'jQuery.param.querystring - build URL', function() {
+ expect( 10 );
+
+ function fake_encode( params_str ) {
+ return '?' + $.map( params_str.split('&'), encodeURIComponent ).join('&').replace( /%3D/g, '=' ).replace( /%2B/g, '+' );
+ }
+
+ var pre = 'http://a:b@example.com:1234/foo.html',
+ post = '#get-on-the-floor',
+ current_url = pre + post;
+
+ run_many_tests(
+
+ // execute this for each array item
+ function(){
+ current_url = $.param.querystring.apply( this, [ current_url ].concat( aps.call( arguments ) ) );
+ },
+
+ // tests:
+
+ [ { a:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '?a=2' + post, '$.param.querystring( url, Object )' );
+ },
+
+ [ { b:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '?a=2&b=2' + post, '$.param.querystring( url, Object )' );
+ },
+
+ [ { c:true, d:false, e:'undefined', f:'' } ],
+
+ function(result){
+ equal( current_url, pre + '?a=2&b=2&c=true&d=false&e=undefined&f=' + post, '$.param.querystring( url, Object )' );
+ },
+
+ [ { a:[4,5,6]}],//, b:{x:[7], y:8, z:[9,0,'true','false','undefined','']} }, 2 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.param.querystring( url, Object, 2 )' );
+ },
+
+ [ { a:'1', c:'2' }, 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.param.querystring( url, Object, 1 )' );
+ },
+
+ [ 'foo=1' ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.param.querystring( url, String )' );
+ },
+
+ [ 'foo=2&bar=3', 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&bar=3&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&bar=3&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.param.querystring( url, String, 1 )' );
+ },
+
+ [ 'http://example.com/test.html?/path/to/file.php#the-cow-goes-moo', 2 ],
+
+ function(result){
+ equal( current_url, pre + '?/path/to/file.php' + post, '$.param.querystring( url, String, 2 )' );
+ },
+
+ [ '?another-example', 2 ],
+
+ function(result){
+ equal( current_url, pre + '?another-example' + post, '$.param.querystring( url, String, 2 )' );
+ },
+
+ [ 'i_am_out_of_witty_strings', 2 ],
+
+ function(result){
+ equal( current_url, pre + '?i_am_out_of_witty_strings' + post, '$.param.querystring( url, String, 2 )' );
+ }
+
+ );
+
+});
+
+test( 'jQuery.param.fragment', function() {
+ expect( 29 );
+
+ equal( $.param.fragment( 'http://example.com/' ), '', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo' ),'', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#bar' ),'bar', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#bar?baz' ),'bar?baz', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#foo' ),'foo', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#foo?bar' ),'foo?bar', 'properly identifying params' );
+
+ equal( $.param.fragment( 'http://example.com/' ), '', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo' ),'', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#!bar' ),'!bar', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#!bar?baz' ),'!bar?baz', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#!foo' ),'!foo', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#!foo?bar' ),'!foo?bar', 'properly identifying params' );
+
+ equal( $.param.fragment(), params_str, 'params string from window.location' );
+ equal( $.param.fragment( '#' + params_str ), params_str, 'params string from url' );
+ equal( $.param.fragment( 'foo.html#' + params_str ), params_str, 'params string from url' );
+ equal( $.param.fragment( 'http://a:b@example.com:1234/foo.html#' + params_str ), params_str, 'params string from url' );
+ equal( $.param.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#' + params_str ), params_str, 'params string from url' );
+
+ $.param.fragment.ajaxCrawlable( true );
+
+ equal( $.param.fragment( 'http://example.com/' ), '', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo' ),'', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#bar' ),'bar', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#bar?baz' ),'bar?baz', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#foo' ),'foo', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#foo?bar' ),'foo?bar', 'properly identifying params' );
+
+ equal( $.param.fragment( 'http://example.com/' ), '', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo' ),'', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#!bar' ),'bar', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/?foo#!bar?baz' ),'bar?baz', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#!foo' ),'foo', 'properly identifying params' );
+ equal( $.param.fragment( 'http://example.com/#!foo?bar' ),'foo?bar', 'properly identifying params' );
+
+ $.param.fragment.ajaxCrawlable( false );
+
+});
+
+test( 'jQuery.param.fragment - build URL', function() {
+ expect( 40 );
+
+ function fake_encode( params_str ) {
+ return '#' + $.map( params_str.split('&'), encodeURIComponent ).join('&').replace( /%3D/g, '=' ).replace( /%2B/g, '+' );
+ }
+
+ var pre = 'http://a:b@example.com:1234/foo.html?and-dance-with-me',
+ current_url = pre;
+
+ run_many_tests(
+
+ // execute this for each array item
+ function(){
+ current_url = $.param.fragment.apply( this, [ current_url ].concat( aps.call( arguments ) ) );
+ },
+
+ // tests:
+
+ [ { a:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '#a=2', '$.param.fragment( url, Object )' );
+ },
+
+ [ { b:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '#a=2&b=2', '$.param.fragment( url, Object )' );
+ },
+
+ [ { c:true, d:false, e:'undefined', f:'' } ],
+
+ function(result){
+ equal( current_url, pre + '#a=2&b=2&c=true&d=false&e=undefined&f=', '$.param.fragment( url, Object )' );
+ },
+
+ [ { a:[4,5,6]}],//, b:{x:[7], y:8, z:[9,0,'true','false','undefined','']} }, 2 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=';
+
+ equal( current_url, pre + fake_encode( params ), '$.param.fragment( url, Object, 2 )' );
+ },
+
+ [ { a:'1', c:'2' }, 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2';
+
+ equal( current_url, pre + fake_encode( params ), '$.param.fragment( url, Object, 1 )' );
+ },
+
+ [ 'foo=1' ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ), '$.param.fragment( url, String )' );
+ },
+
+ [ 'foo=2&bar=3', 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&bar=3&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&bar=3&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ), '$.param.fragment( url, String, 1 )' );
+ },
+
+ [ 'http://example.com/test.html?the-cow-goes-moo#/path/to/file.php', 2 ],
+
+ function(result){
+ equal( current_url, pre + '#/path/to/file.php', '$.param.fragment( url, String, 2 )' );
+ },
+
+ [ '#another-example', 2 ],
+
+ function(result){
+ equal( current_url, pre + '#another-example', '$.param.fragment( url, String, 2 )' );
+ },
+
+ [ 'i_am_out_of_witty_strings', 2 ],
+
+ function(result){
+ equal( current_url, pre + '#i_am_out_of_witty_strings', '$.param.fragment( url, String, 2 )' );
+ }
+
+ );
+
+ $.param.fragment.ajaxCrawlable( true );
+
+ equal( $.param.fragment( 'foo', {} ) , 'foo#!', '$.param.fragment( url, Object )' );
+ equal( $.param.fragment( 'foo', { b:2, a:1 } ) , 'foo#!a=1&b=2', '$.param.fragment( url, Object )' );
+ equal( $.param.fragment( 'foo#', { b:2, a:1 } ) , 'foo#!a=1&b=2', '$.param.fragment( url, Object )' );
+ equal( $.param.fragment( 'foo#!', { b:2, a:1 } ) , 'foo#!a=1&b=2', '$.param.fragment( url, Object )' );
+ equal( $.param.fragment( 'foo#c=3&a=4', { b:2, a:1 } ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, Object )' );
+ equal( $.param.fragment( 'foo#!c=3&a=4', { b:2, a:1 } ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, Object )' );
+
+ equal( $.param.fragment( 'foo', '' ) , 'foo#!', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo', 'b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#', 'b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!', 'b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#c=3&a=4', 'b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!c=3&a=4', 'b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, String )' );
+
+ equal( $.param.fragment( 'foo', '#' ) , 'foo#!', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo', '#b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#', '#b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!', '#b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#c=3&a=4', '#b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!c=3&a=4', '#b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, String )' );
+
+ equal( $.param.fragment( 'foo', '#!' ) , 'foo#!', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo', '#!b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#', '#!b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!', '#!b=2&a=1' ) , 'foo#!a=1&b=2', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#c=3&a=4', '#!b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!c=3&a=4', '#!b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.param.fragment( url, String )' );
+
+ $.param.fragment.ajaxCrawlable( false );
+
+ // If a params fragment starts with ! and BBQ is not in ajaxCrawlable mode,
+ // things can get very ugly, very quickly.
+ equal( $.param.fragment( 'foo', '#!' ) , 'foo#!=', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo', '#!b=2&a=1' ) , 'foo#!b=2&a=1', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#', '#!b=2&a=1' ) , 'foo#!b=2&a=1', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!', '#!b=2&a=1' ) , 'foo#!=&!b=2&a=1', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#c=3&a=4', '#!b=2&a=1' ) , 'foo#!b=2&a=1&c=3', '$.param.fragment( url, String )' );
+ equal( $.param.fragment( 'foo#!c=3&a=4', '#!b=2&a=1' ) , 'foo#!b=2&!c=3&a=1', '$.param.fragment( url, String )' );
+
+});
+
+test( 'jQuery.param.fragment.ajaxCrawlable', function() {
+ expect( 5 );
+
+ equal( ajaxcrawlable_init, false, 'ajaxCrawlable is disabled by default' );
+ equal( $.param.fragment.ajaxCrawlable( true ), true, 'enabling ajaxCrawlable should return true' );
+ equal( $.param.fragment.ajaxCrawlable(), true, 'ajaxCrawlable is now enabled' );
+ equal( $.param.fragment.ajaxCrawlable( false ), false, 'disabling ajaxCrawlable should return false' );
+ equal( $.param.fragment.ajaxCrawlable(), false, 'ajaxCrawlable is now disabled' );
+});
+
+test( 'jQuery.param.fragment.noEscape', function() {
+ expect( 2 );
+
+ equal( $.param.fragment( '#', { foo: '/a,b@c$d+e&f=g h!' } ), '#foo=/a,b%40c%24d%2Be%26f%3Dg+h!', '/, should be unescaped, everything else but space (+) should be urlencoded' );
+
+ $.param.fragment.ajaxCrawlable( true );
+
+ equal( $.param.fragment( '#', { foo: '/a,b@c$d+e&f=g h!' } ), '#!foo=/a,b%40c%24d%2Be%26f%3Dg+h!', '/, should be unescaped, everything else but ! and space (+) should be urlencoded' );
+
+ $.param.fragment.ajaxCrawlable( false );
+});
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+QUnit.module( 'jQuery.deparam' );
+
+test( 'jQuery.deparam - 1.4-style params', function() {
+ expect( 2 );
+ deepEqual( $.deparam( params_str ), params_obj, '$.deparam( String )' );
+ deepEqual( $.deparam( params_str, true ), params_obj_coerce, '$.deparam( String, true )' );
+});
+
+test( 'jQuery.deparam - pre-1.4-style params', function() {
+ var params_str = 'a=1&a=2&a=3&b=4&c=5&c=6&c=true&c=false&c=undefined&c=&d=7',
+ params_obj = { a:['1','2','3'], b:'4', c:['5','6','true','false','undefined',''], d:'7' },
+ params_obj_coerce = { a:[1,2,3], b:4, c:[5,6,true,false,undefined,''], d:7 };
+
+ expect( 2 );
+ deepEqual( $.deparam( params_str ), params_obj, '$.deparam( String )' );
+ deepEqual( $.deparam( params_str, true ), params_obj_coerce, '$.deparam( String, true )' );
+});
+
+test( 'jQuery.deparam.querystring', function() {
+ expect( 12 );
+
+ deepEqual( $.deparam.querystring(), params_obj, 'params obj from window.location' );
+ deepEqual( $.deparam.querystring( /*true*/ ), params_obj_coerce, 'params obj from window.location, coerced' );
+ deepEqual( $.deparam.querystring( params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.querystring( params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.querystring( '?' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.querystring( '?' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.querystring( 'foo.html?' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.querystring( 'foo.html?' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.querystring( 'http://a:b@example.com:1234/foo.html?' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.querystring( 'http://a:b@example.com:1234/foo.html?' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.querystring( 'http://a:b@example.com:1234/foo.html?' + params_str + '#bippity-boppity-boo' ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.querystring( 'http://a:b@example.com:1234/foo.html?' + params_str + '#bippity-boppity-boo', true ), params_obj_coerce, 'params obj from string, coerced' );
+});
+
+test( 'jQuery.deparam.fragment', function() {
+ expect( 36 );
+
+ deepEqual( $.deparam.fragment(), params_obj, 'params obj from window.location' );
+ deepEqual( $.deparam.fragment( /*true*/ ), params_obj_coerce, 'params obj from window.location, coerced' );
+ deepEqual( $.deparam.fragment( params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+
+ deepEqual( $.deparam.fragment( '#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( '#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'foo.html#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'foo.html#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+
+ // If a params fragment starts with ! and BBQ is not in ajaxCrawlable mode,
+ // things can get very ugly, very quickly.
+ deepEqual( $.deparam.fragment( '#!' + params_str ), params_obj_bang, 'params obj from string' );
+ deepEqual( $.deparam.fragment( '#!' + params_str, true ), params_obj_bang_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'foo.html#!' + params_str ), params_obj_bang, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'foo.html#!' + params_str, true ), params_obj_bang_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#!' + params_str ), params_obj_bang, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#!' + params_str, true ), params_obj_bang_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#!' + params_str ), params_obj_bang, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#!' + params_str, true ), params_obj_bang_coerce, 'params obj from string, coerced' );
+
+ $.param.fragment.ajaxCrawlable( true );
+
+ deepEqual( $.deparam.fragment( '#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( '#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'foo.html#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'foo.html#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+
+ deepEqual( $.deparam.fragment( '#!' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( '#!' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'foo.html#!' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'foo.html#!' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#!' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html#!' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#!' + params_str ), params_obj, 'params obj from string' );
+ deepEqual( $.deparam.fragment( 'http://a:b@example.com:1234/foo.html?bippity-boppity-boo#!' + params_str, true ), params_obj_coerce, 'params obj from string, coerced' );
+
+ $.param.fragment.ajaxCrawlable( false );
+});
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+QUnit.module( 'jQuery.fn' );
+
+$.elemUrlAttr({ span: 'arbitrary_attr' });
+var test_elems = 'a form link span'.split(' ');
+
+function init_url_attr( container, url ) {
+ var container = $('').hide().appendTo('body');
+ $.each( test_elems, function(i,v){
+ $('<' + v + '/>')
+ .attr( $.elemUrlAttr()[ v ], url )
+ .appendTo( container );
+ });
+ return container;
+};
+
+function test_url_attr( container ) {
+ var url;
+
+ $.each( test_elems, function(i,v){
+ var val = container.children( v ).attr( $.elemUrlAttr()[ v ] );
+ if ( !url ) {
+ url = val;
+ } else if ( val !== url ) {
+ url = -1;
+ }
+ });
+
+ return url;
+};
+
+test( 'jQuery.fn.querystring', function() {
+ expect( 60 );
+
+ function fake_encode( params_str ) {
+ return '?' + $.map( params_str.split('&'), encodeURIComponent ).join('&').replace( /%3D/g, '=' ).replace( /%2B/g, '+' );
+ }
+
+ var pre = 'http://a:b@example.com:1234/foo.html',
+ post = '#get-on-the-floor',
+ current_url = pre + post;
+
+ run_many_tests(
+
+ // execute this for each array item
+ function(){
+ var container,
+ elems;
+
+ container = init_url_attr( container, current_url );
+ elems = container.children('span');
+ equal( elems.length, 1, 'select the correct elements' );
+ equal( elems.querystring.apply( elems, [ 'arbitrary_attr' ].concat( aps.call( arguments ) ) ), elems, 'pass query string' );
+
+ container = init_url_attr( container, current_url );
+ elems = container.children('a, link');
+ equal( elems.length, 2, 'select the correct elements' );
+ equal( elems.querystring.apply( elems, [ 'href' ].concat( aps.call( arguments ) ) ), elems, 'pass query string' );
+
+ container = init_url_attr( container, current_url );
+ elems = container.children();
+ equal( elems.querystring.apply( elems, aps.call( arguments ) ), elems, 'pass query string' );
+
+ current_url = test_url_attr( container );
+ },
+
+ // tests:
+
+ [ { a:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '?a=2' + post, '$.fn.querystring( url, Object )' );
+ },
+
+ [ { b:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '?a=2&b=2' + post, '$.fn.querystring( url, Object )' );
+ },
+
+ [ { c:true, d:false, e:'undefined', f:'' } ],
+
+ function(result){
+ equal( current_url, pre + '?a=2&b=2&c=true&d=false&e=undefined&f=' + post, '$.fn.querystring( url, Object )' );
+ },
+
+ [ { a:[4,5,6]}],//, b:{x:[7], y:8, z:[9,0,'true','false','undefined','']} }, 2 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.fn.querystring( url, Object, 2 )' );
+ },
+
+ [ { a:'1', c:'2' }, 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.fn.querystring( url, Object, 1 )' );
+ },
+
+ [ 'foo=1' ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.fn.querystring( url, String )' );
+ },
+
+ [ 'foo=2&bar=3', 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&bar=3&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&bar=3&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ) + post, '$.fn.querystring( url, String, 1 )' );
+ },
+
+ [ 'http://example.com/test.html?/path/to/file.php#the-cow-goes-moo', 2 ],
+
+ function(result){
+ equal( current_url, pre + '?/path/to/file.php' + post, '$.fn.querystring( url, String, 2 )' );
+ },
+
+ [ '?another-example', 2 ],
+
+ function(result){
+ equal( current_url, pre + '?another-example' + post, '$.fn.querystring( url, String, 2 )' );
+ },
+
+ [ 'i_am_out_of_witty_strings', 2 ],
+
+ function(result){
+ equal( current_url, pre + '?i_am_out_of_witty_strings' + post, '$.fn.querystring( url, String, 2 )' );
+ }
+
+ );
+
+});
+
+test( 'jQuery.fn.fragment', function() {
+ expect( 240 );
+
+ function fake_encode( params_str ) {
+ return '#' + $.map( params_str.split('&'), encodeURIComponent ).join('&').replace( /%3D/g, '=' ).replace( /%2B/g, '+' );
+ }
+
+ var pre = 'http://a:b@example.com:1234/foo.html?and-dance-with-me',
+ current_url = pre;
+
+ run_many_tests(
+
+ // execute this for each array item
+ function( params, merge_mode ){
+ current_url = test_fn_fragment( current_url, params, merge_mode );
+ },
+
+ // tests:
+
+ [ { a:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '#a=2', '$.fn.fragment( url, Object )' );
+ },
+
+ [ { b:'2' } ],
+
+ function(result){
+ equal( current_url, pre + '#a=2&b=2', '$.fn.fragment( url, Object )' );
+ },
+
+ [ { c:true, d:false, e:'undefined', f:'' } ],
+
+ function(result){
+ equal( current_url, pre + '#a=2&b=2&c=true&d=false&e=undefined&f=', '$.fn.fragment( url, Object )' );
+ },
+
+ [ { a:[4,5,6]}],//, b:{x:[7], y:8, z:[9,0,'true','false','undefined','']} }, 2 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=';
+
+ equal( current_url, pre + fake_encode( params ), '$.fn.fragment( url, Object, 2 )' );
+ },
+
+ [ { a:'1', c:'2' }, 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2';
+
+ equal( current_url, pre + fake_encode( params ), '$.fn.fragment( url, Object, 1 )' );
+ },
+
+ [ 'foo=1' ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ), '$.fn.fragment( url, String )' );
+ },
+
+ [ 'foo=2&bar=3', 1 ],
+
+ function(result){
+ var params = old_jquery
+ ? 'a=4&a=5&a=6&b=[object+Object]&bar=3&c=2&foo=1'
+ : 'a[]=4&a[]=5&a[]=6&b[x][]=7&b[y]=8&b[z][]=9&b[z][]=0&b[z][]=true&b[z][]=false&b[z][]=undefined&b[z][]=&bar=3&c=2&foo=1';
+
+ equal( current_url, pre + fake_encode( params ), '$.fn.fragment( url, String, 1 )' );
+ },
+
+ [ 'http://example.com/test.html?the-cow-goes-moo#/path/to/file.php', 2 ],
+
+ function(result){
+ equal( current_url, pre + '#/path/to/file.php', '$.fn.fragment( url, String, 2 )' );
+ },
+
+ [ '#another-example', 2 ],
+
+ function(result){
+ equal( current_url, pre + '#another-example', '$.fn.fragment( url, String, 2 )' );
+ },
+
+ [ 'i_am_out_of_witty_strings', 2 ],
+
+ function(result){
+ equal( current_url, pre + '#i_am_out_of_witty_strings', '$.fn.fragment( url, String, 2 )' );
+ }
+
+ );
+
+ $.param.fragment.ajaxCrawlable( true );
+
+ function test_fn_fragment( url, params, merge_mode? ) {
+ var container,
+ elems;
+
+ container = init_url_attr( container, url );
+ elems = container.children('span');
+ equal( elems.length, 1, 'select the correct elements' );
+ equal( elems.fragment( 'arbitrary_attr', params, merge_mode ), elems, 'pass fragment' );
+
+ container = init_url_attr( container, url );
+ elems = container.children('a, link');
+ equal( elems.length, 2, 'select the correct elements' );
+ equal( elems.fragment( params, merge_mode ), elems, 'pass fragment' );
+
+ container = init_url_attr( container, url );
+ elems = container.children();
+ equal( elems.fragment( params, merge_mode ), elems, 'pass fragment' );
+
+ return test_url_attr( container );
+ };
+
+ equal( test_fn_fragment( 'foo', {} ) , 'foo#!', '$.fn.fragment( url, Object )' );
+ equal( test_fn_fragment( 'foo', { b:2, a:1 } ) , 'foo#!a=1&b=2', '$.fn.fragment( url, Object )' );
+ equal( test_fn_fragment( 'foo#', { b:2, a:1 } ) , 'foo#!a=1&b=2', '$.fn.fragment( url, Object )' );
+ equal( test_fn_fragment( 'foo#!', { b:2, a:1 } ) , 'foo#!a=1&b=2', '$.fn.fragment( url, Object )' );
+ equal( test_fn_fragment( 'foo#c=3&a=4', { b:2, a:1 } ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, Object )' );
+ equal( test_fn_fragment( 'foo#!c=3&a=4', { b:2, a:1 } ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, Object )' );
+
+ equal( test_fn_fragment( 'foo', '' ) , 'foo#!', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo', 'b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#', 'b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!', 'b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#c=3&a=4', 'b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!c=3&a=4', 'b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, String )' );
+
+ equal( test_fn_fragment( 'foo', '#' ) , 'foo#!', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo', '#b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#', '#b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!', '#b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#c=3&a=4', '#b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!c=3&a=4', '#b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, String )' );
+
+ equal( test_fn_fragment( 'foo', '#!' ) , 'foo#!', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo', '#!b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#', '#!b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!', '#!b=2&a=1' ) , 'foo#!a=1&b=2', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#c=3&a=4', '#!b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!c=3&a=4', '#!b=2&a=1' ) , 'foo#!a=1&b=2&c=3', '$.fn.fragment( url, String )' );
+
+ $.param.fragment.ajaxCrawlable( false );
+
+ // If a params fragment starts with ! and BBQ is not in ajaxCrawlable mode,
+ // things can get very ugly, very quickly.
+ equal( test_fn_fragment( 'foo', '#!' ) , 'foo#!=', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo', '#!b=2&a=1' ) , 'foo#!b=2&a=1', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#', '#!b=2&a=1' ) , 'foo#!b=2&a=1', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!', '#!b=2&a=1' ) , 'foo#!=&!b=2&a=1', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#c=3&a=4', '#!b=2&a=1' ) , 'foo#!b=2&a=1&c=3', '$.fn.fragment( url, String )' );
+ equal( test_fn_fragment( 'foo#!c=3&a=4', '#!b=2&a=1' ) , 'foo#!b=2&!c=3&a=1', '$.fn.fragment( url, String )' );
+
+});
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+QUnit.module( 'jQuery.bbq' );
+
+test( 'jQuery.bbq.pushState(), jQuery.bbq.getState(), jQuery.bbq.removeState(), window.onhashchange', function() {
+ expect( old_jquery ? 95 : 167 );
+
+ var a, b, c, d, e, f, x, y, hash, hash_actual, obj, event, msg = 'Testing window.onhashchange and history';
+
+ $.bbq.pushState();
+ equal( window.location.hash.replace( /^#/, ''), '', 'window.location hash should be empty' );
+
+ $.bbq.pushState({ a:'1', b:'1' });
+ deepEqual( $.deparam.fragment(), { a:'1', b:'1' }, 'hash should be set properly' );
+
+ $(window).bind( 'hashchange', function(evt) {
+ var hash_str = $.param.fragment(),
+ param_obj = $.bbq.getState(),
+ param_val = $.bbq.getState( 'param_name' );
+
+ event = evt;
+ hash = $.param.fragment();
+ hash_actual = location.hash;
+ obj = { str: $.bbq.getState(), coerce: $.bbq.getState( true ) };
+ a = { str: $.bbq.getState( 'a' ), coerce: $.bbq.getState( 'a', true ) };
+ b = { str: $.bbq.getState( 'b' ), coerce: $.bbq.getState( 'b', true ) };
+ c = { str: $.bbq.getState( 'c' ), coerce: $.bbq.getState( 'c', true ) };
+ d = { str: $.bbq.getState( 'd' ), coerce: $.bbq.getState( 'd', true ) };
+ e = { str: $.bbq.getState( 'e' ), coerce: $.bbq.getState( 'e', true ) };
+ f = { str: $.bbq.getState( 'f' ), coerce: $.bbq.getState( 'f', true ) };
+
+ }).trigger( 'hashchange' );
+
+ deepEqual( obj.str, { a:'1', b:'1' }, 'hashchange triggered manually: $.bbq.getState()' );
+ deepEqual( obj.coerce, { a:1, b:1 }, 'hashchange triggered manually: $.bbq.getState( true )' );
+ equal( a.str, '1', 'hashchange triggered manually: $.bbq.getState( "a" )' );
+ equal( a.coerce, 1, 'hashchange triggered manually: $.bbq.getState( "a", true )' );
+
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:'1', b:'1' }, 'hashchange triggered manually: event.getState()' );
+ deepEqual( event.getState(true), { a:1, b:1 }, 'hashchange triggered manually: event.getState( true )' );
+ equal( event.getState('a'), '1', 'hashchange triggered manually: event.getState( "a" )' );
+ equal( event.getState('a',true), 1, 'hashchange triggered manually: event.getState( "a", true )' );
+ }
+
+ run_many_tests(
+ // run asynchronously
+ 250,
+
+ // execute this for each array item
+ function(){
+ notice( msg += '.' );
+ $.bbq.pushState.apply( this, aps.call( arguments ) );
+ },
+
+ // execute this at the end
+ function(){
+ notice();
+ },
+
+ // tests:
+
+ [ { a:'2' } ],
+
+ function(result){
+ equal( hash_actual, '#' + hash, 'hash should begin with #!' );
+ deepEqual( obj.str, { a:'2', b:'1' }, '$.bbq.getState()' );
+ deepEqual( obj.coerce, { a:2, b:1 }, '$.bbq.getState( true )' );
+ equal( a.str, '2', '$.bbq.getState( "a" )' );
+ equal( a.coerce, 2, '$.bbq.getState( "a", true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:'2', b:'1' }, 'event.getState()' );
+ deepEqual( event.getState(true), { a:2, b:1 }, 'event.getState( true )' );
+ equal( event.getState('a'), '2', 'event.getState( "a" )' );
+ equal( event.getState('a',true), 2, 'event.getState( "a", true )' );
+ }
+ },
+
+ [ { b:'2' } ],
+
+ function(result){
+ equal( hash_actual, '#' + hash, 'hash should begin with #!' );
+ deepEqual( obj.str, { a:'2', b:'2' }, '$.bbq.getState()' );
+ deepEqual( obj.coerce, { a:2, b:2 }, '$.bbq.getState( true )' );
+ equal( b.str, '2', '$.bbq.getState( "b" )' );
+ equal( b.coerce, 2, '$.bbq.getState( "b", true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:'2', b:'2' }, 'event.getState()' );
+ deepEqual( event.getState(true), { a:2, b:2 }, 'event.getState( true )' );
+ equal( event.getState('b'), '2', 'event.getState( "b" )' );
+ equal( event.getState('b',true), 2, 'event.getState( "b", true )' );
+ }
+ },
+
+ [ { c:true, d:false, e:'undefined', f:'' } ],
+
+ function(result){
+ equal( hash_actual, '#' + hash, 'hash should begin with #!' );
+ deepEqual( obj.str, { a:'2', b:'2', c:'true', d:'false', e:'undefined', f:'' }, '$.bbq.getState()' );
+ deepEqual( obj.coerce, { a:2, b:2, c:true, d:false, e:undefined, f:'' }, '$.bbq.getState( true )' );
+ equal( c.str, 'true', '$.bbq.getState( "c" )' );
+ equal( c.coerce, true, '$.bbq.getState( "c", true )' );
+ equal( d.str, 'false', '$.bbq.getState( "d" )' );
+ equal( d.coerce, false, '$.bbq.getState( "d", true )' );
+ equal( e.str, 'undefined', '$.bbq.getState( "e" )' );
+ equal( e.coerce, undefined, '$.bbq.getState( "e", true )' );
+ equal( f.str, '', '$.bbq.getState( "f" )' );
+ equal( f.coerce, '', '$.bbq.getState( "f", true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:'2', b:'2', c:'true', d:'false', e:'undefined', f:'' }, 'event.getState()' );
+ deepEqual( event.getState(true), { a:2, b:2, c:true, d:false, e:undefined, f:'' }, 'event.getState( true )' );
+ equal( event.getState('c'), 'true', 'event.getState( "c" )' );
+ equal( event.getState('c',true), true, 'event.getState( "c", true )' );
+ equal( event.getState('d'), 'false', 'event.getState( "d" )' );
+ equal( event.getState('d',true), false, 'event.getState( "d", true )' );
+ equal( event.getState('e'), 'undefined', 'event.getState( "e" )' );
+ equal( event.getState('e',true), undefined, 'event.getState( "e", true )' );
+ equal( event.getState('f'), '', 'event.getState( "f" )' );
+ equal( event.getState('f',true), '', 'event.getState( "f", true )' );
+ }
+ },
+
+ function(result){
+ $.param.fragment.ajaxCrawlable( true );
+ },
+
+ function(result){
+ $.bbq.removeState( 'c' );
+ },
+
+ function(result){
+ equal( hash_actual, '#!' + hash, 'hash should begin with #!' );
+ deepEqual( obj.str, { a:'2', b:'2', d:'false', e:'undefined', f:'' }, '$.bbq.getState()' );
+ deepEqual( obj.coerce, { a:2, b:2, d:false, e:undefined, f:'' }, '$.bbq.getState( true )' );
+ equal( a.str, '2', '$.bbq.getState( "a" )' );
+ equal( a.coerce, 2, '$.bbq.getState( "a", true )' );
+ equal( b.str, '2', '$.bbq.getState( "b" )' );
+ equal( b.coerce, 2, '$.bbq.getState( "b", true )' );
+ equal( c.str, undefined, '$.bbq.getState( "c" )' );
+ equal( c.coerce, undefined, '$.bbq.getState( "c", true )' );
+ equal( d.str, 'false', '$.bbq.getState( "d" )' );
+ equal( d.coerce, false, '$.bbq.getState( "d", true )' );
+ equal( e.str, 'undefined', '$.bbq.getState( "e" )' );
+ equal( e.coerce, undefined, '$.bbq.getState( "e", true )' );
+ equal( f.str, '', '$.bbq.getState( "f" )' );
+ equal( f.coerce, '', '$.bbq.getState( "f", true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:'2', b:'2', d:'false', e:'undefined', f:'' }, 'event.getState()' );
+ deepEqual( event.getState(true), { a:2, b:2, d:false, e:undefined, f:'' }, 'event.getState( true )' );
+ equal( event.getState('a'), '2', 'event.getState( "a" )' );
+ equal( event.getState('a',true), 2, 'event.getState( "a", true )' );
+ equal( event.getState('b'), '2', 'event.getState( "b" )' );
+ equal( event.getState('b',true), 2, 'event.getState( "b", true )' );
+ equal( event.getState('c'), undefined, 'event.getState( "c" )' );
+ equal( event.getState('c',true), undefined, 'event.getState( "c", true )' );
+ equal( event.getState('d'), 'false', 'event.getState( "d" )' );
+ equal( event.getState('d',true), false, 'event.getState( "d", true )' );
+ equal( event.getState('e'), 'undefined', 'event.getState( "e" )' );
+ equal( event.getState('e',true), undefined, 'event.getState( "e", true )' );
+ equal( event.getState('f'), '', 'event.getState( "f" )' );
+ equal( event.getState('f',true), '', 'event.getState( "f", true )' );
+ }
+ },
+
+ function(result){
+ $.bbq.removeState( [ 'd', 'e', 'f', 'nonexistent' ] );
+ },
+
+ function(result){
+ equal( hash_actual, '#!' + hash, 'hash should begin with #!' );
+ deepEqual( obj.str, { a:'2', b:'2' }, '$.bbq.getState()' );
+ deepEqual( obj.coerce, { a:2, b:2 }, '$.bbq.getState( true )' );
+ equal( a.str, '2', '$.bbq.getState( "a" )' );
+ equal( a.coerce, 2, '$.bbq.getState( "a", true )' );
+ equal( b.str, '2', '$.bbq.getState( "b" )' );
+ equal( b.coerce, 2, '$.bbq.getState( "b", true )' );
+ equal( c.str, undefined, '$.bbq.getState( "c" )' );
+ equal( c.coerce, undefined, '$.bbq.getState( "c", true )' );
+ equal( d.str, undefined, '$.bbq.getState( "d" )' );
+ equal( d.coerce, undefined, '$.bbq.getState( "d", true )' );
+ equal( e.str, undefined, '$.bbq.getState( "e" )' );
+ equal( e.coerce, undefined, '$.bbq.getState( "e", true )' );
+ equal( f.str, undefined, '$.bbq.getState( "f" )' );
+ equal( f.coerce, undefined, '$.bbq.getState( "f", true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:'2', b:'2' }, 'event.getState()' );
+ deepEqual( event.getState(true), { a:2, b:2 }, 'event.getState( true )' );
+ equal( event.getState('a'), '2', 'event.getState( "a" )' );
+ equal( event.getState('a',true), 2, 'event.getState( "a", true )' );
+ equal( event.getState('b'), '2', 'event.getState( "b" )' );
+ equal( event.getState('b',true), 2, 'event.getState( "b", true )' );
+ equal( event.getState('c'), undefined, 'event.getState( "c" )' );
+ equal( event.getState('c',true), undefined, 'event.getState( "c", true )' );
+ equal( event.getState('d'), undefined, 'event.getState( "d" )' );
+ equal( event.getState('d',true), undefined, 'event.getState( "d", true )' );
+ equal( event.getState('e'), undefined, 'event.getState( "e" )' );
+ equal( event.getState('e',true), undefined, 'event.getState( "e", true )' );
+ equal( event.getState('f'), undefined, 'event.getState( "f" )' );
+ equal( event.getState('f',true), undefined, 'event.getState( "f", true )' );
+ }
+ },
+
+ function(result){
+ $.bbq.removeState();
+ },
+
+ function(result){
+ equal( hash_actual, '#!', 'hash should just be #!' );
+ deepEqual( obj.str, {}, '$.bbq.getState()' );
+ deepEqual( obj.coerce, {}, '$.bbq.getState( true )' );
+ equal( a.str, undefined, '$.bbq.getState( "a" )' );
+ equal( a.coerce, undefined, '$.bbq.getState( "a", true )' );
+ equal( b.str, undefined, '$.bbq.getState( "b" )' );
+ equal( b.coerce, undefined, '$.bbq.getState( "b", true )' );
+ equal( c.str, undefined, '$.bbq.getState( "c" )' );
+ equal( c.coerce, undefined, '$.bbq.getState( "c", true )' );
+ equal( d.str, undefined, '$.bbq.getState( "d" )' );
+ equal( d.coerce, undefined, '$.bbq.getState( "d", true )' );
+ equal( e.str, undefined, '$.bbq.getState( "e" )' );
+ equal( e.coerce, undefined, '$.bbq.getState( "e", true )' );
+ equal( f.str, undefined, '$.bbq.getState( "f" )' );
+ equal( f.coerce, undefined, '$.bbq.getState( "f", true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), {}, 'event.getState()' );
+ deepEqual( event.getState(true), {}, 'event.getState( true )' );
+ equal( event.getState('a'), undefined, 'event.getState( "a" )' );
+ equal( event.getState('a',true), undefined, 'event.getState( "a", true )' );
+ equal( event.getState('b'), undefined, 'event.getState( "b" )' );
+ equal( event.getState('b',true), undefined, 'event.getState( "b", true )' );
+ equal( event.getState('c'), undefined, 'event.getState( "c" )' );
+ equal( event.getState('c',true), undefined, 'event.getState( "c", true )' );
+ equal( event.getState('d'), undefined, 'event.getState( "d" )' );
+ equal( event.getState('d',true), undefined, 'event.getState( "d", true )' );
+ equal( event.getState('e'), undefined, 'event.getState( "e" )' );
+ equal( event.getState('e',true), undefined, 'event.getState( "e", true )' );
+ equal( event.getState('f'), undefined, 'event.getState( "f" )' );
+ equal( event.getState('f',true), undefined, 'event.getState( "f", true )' );
+ }
+ },
+
+ [ { a:'2', b:'2', c:true, d:false, e:'undefined', f:'' } ],
+
+ [ { a:[4,5,6]}],//, b:{x:[7], y:8, z:[9,0,'true','false','undefined','']} }, 2 ],
+
+ function(result){
+ var b_str = old_jquery
+ ? '[object Object]'
+ : {x:['7'], y:'8', z:['9','0','true','false','undefined','']},
+ b_coerce = old_jquery
+ ? '[object Object]'
+ : {x:[7], y:8};//z:[9,0,true,false,undefined,'']};
+
+ equal( hash_actual, '#!' + hash, 'hash should begin with #!' );
+ deepEqual( obj.str, { a:['4','5','6'], b:b_str }, '$.bbq.getState()' );
+ deepEqual( obj.coerce, { a:[4,5,6], b:b_coerce }, '$.bbq.getState( true )' );
+ deepEqual( a.str, ['4','5','6'], '$.bbq.getState( "a" )' );
+ deepEqual( a.coerce, [4,5,6], '$.bbq.getState( "a", true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:['4','5','6'], b:b_str }, 'event.getState()' );
+ deepEqual( event.getState(true), { a:[4,5,6], b:b_coerce }, 'event.getState( true )' );
+ deepEqual( event.getState('a'), ['4','5','6'], 'event.getState( "a" )' );
+ deepEqual( event.getState('a',true), [4,5,6], 'event.getState( "a", true )' );
+ }
+ },
+
+ [ { a:'1', c:'2' }, 1 ],
+
+ function(result){
+ var b_str = old_jquery
+ ? '[object Object]'
+ : {x:['7'], y:'8', z:['9','0','true','false','undefined','']},
+ b_coerce = old_jquery
+ ? '[object Object]'
+ : {x:[7], y:8};//, z:[9,0,true,false,undefined,'']};
+
+ equal( hash_actual, '#!' + hash, 'hash should begin with #!' );
+ deepEqual( obj.str, { a:['4','5','6'], b:b_str, c:'2' }, '$.bbq.getState()' );
+ deepEqual( obj.coerce, { a:[4,5,6], b:b_coerce, c:2 }, '$.bbq.getState( true )' );
+ if ( !old_jquery ) {
+ deepEqual( event.getState(), { a:['4','5','6'], b:b_str, c:'2' }, 'event.getState()' );
+ deepEqual( event.getState(true), { a:[4,5,6], b:b_coerce, c:2 }, 'event.getState( true )' );
+ }
+ },
+
+ [ '#/path/to/file.php', 2 ],
+
+ function(result){
+ equal( hash_actual, '#!' + hash, 'hash should begin with #!' );
+ equal( hash, '/path/to/file.php', '$.param.fragment()' );
+ if ( !old_jquery ) {
+ equal( event.fragment, '/path/to/file.php', 'event.fragment' );
+ }
+ },
+
+ [],
+
+ function(result){
+ equal( hash_actual, '#!', 'hash should just be #!' );
+ equal( hash, '', '$.param.fragment()' );
+ if ( !old_jquery ) {
+ equal( event.fragment, '', 'event.fragment' );
+ }
+ },
+
+ function(result){
+ $(window).bind( 'hashchange', function(evt){
+ x = $.param.fragment();
+ });
+ },
+
+ [ '#omg_ponies', 2 ],
+
+ function(result){
+ equal( hash, 'omg_ponies', 'event handler 1: $.param.fragment()' );
+ equal( x, 'omg_ponies', 'event handler 2: $.param.fragment()' );
+
+ hash = x = '';
+ equal( hash + x, '', 'vars reset' );
+
+ $(window).triggerHandler( 'hashchange' );
+ equal( hash, 'omg_ponies', 'event handler 1: $.param.fragment()' );
+ equal( x, 'omg_ponies', 'event handler 2: $.param.fragment()' );
+
+ hash = x = '';
+ equal( hash + x, '', 'vars reset' );
+
+ $(window).unbind( 'hashchange' );
+ },
+
+ [ '#almost_done?not_search', 2 ],
+
+ function(result){
+ equal( hash, '', 'event handler 1: $.param.fragment()' );
+ equal( x, '', 'event handler 2: $.param.fragment()' );
+
+ var events:any;// = $.data( window, 'events' );
+ ok( !events || !events.hashchange, 'hashchange event unbound' );
+ },
+
+ [ '#' ],
+
+ function(result){
+ x = [];
+ $(window).bind( 'hashchange', function(evt){
+ x.push( $.param.fragment() );
+ });
+ },
+
+ function(result){
+ !is_chrome && window.history.go( -1 );
+ },
+
+ function(result){
+ !is_chrome && window.history.go( -1 );
+ },
+
+ function(result){
+ !is_chrome && window.history.go( -1 );
+ },
+
+ function(result){
+ !is_chrome && window.history.go( -1 );
+ },
+
+ function(result){
+ if ( is_chrome ) {
+ // Read about this issue here: http://benalman.com/news/2009/09/chrome-browser-history-buggine/
+ ok( true, 'history is sporadically broken in chrome, this is a known bug, so this test is skipped in chrome' );
+ } else {
+ deepEqual( x, ['almost_done?not_search', 'omg_ponies', '', '/path/to/file.php'], 'back button and window.bbq.go(-1) should work' );
+ }
+
+ $(window).unbind( 'hashchange' );
+ var events: any;// = $.data( window, 'events' );
+ ok( !events || !events.hashchange, 'hashchange event unbound' );
+ },
+
+ function(result){
+ $.param.fragment.ajaxCrawlable( false );
+ },
+
+ [ '#all_done' ]
+
+ );
+
+});
+
+
+}); // END CLOSURE
\ No newline at end of file
diff --git a/jquery.bbq/jquery.bbq.d.ts b/jquery.bbq/jquery.bbq.d.ts
index b34ea0eb3..5e94efea9 100644
--- a/jquery.bbq/jquery.bbq.d.ts
+++ b/jquery.bbq/jquery.bbq.d.ts
@@ -1,42 +1,160 @@
// Type definitions for jquery.bbq 1.2
// Project: http://benalman.com/projects/jquery-bbq-plugin/
-// Definitions by: https://github.com/sunetos
+// Definitions by: Adam R. Smith
// Definitions: https://github.com/borisyankov/DefinitelyTyped
-interface JQueryBBQ {
- pushState(params?: any, merge_mode?: number): void;
- getState(key?: string, coerce?: bool): any;
- removeState(...key: any[]): void;
+///
+
+module JQueryBbq {
+
+ interface JQuery {
+ /**
+ * Adds a 'state' into the browser history at the current position, setting
+ * location.hash and triggering any bound callbacks
+ * (provided the new state is different than the previous state).
+ *
+ * @name params A serialized params string or a hash string beginning with # to merge into location.hash.
+ * @name merge_mode Merge behavior defaults to 0 if merge_mode is not specified (unless a hash string beginning with # is specified, in which case merge behavior defaults to 2)
+ */
+ pushState(params?: string, merge_mode?: number): void;
+
+ pushState(params?: any, merge_mode?: number): void;
+
+ /**
+ * Retrieves the current 'state' from the browser history, parsing
+ * location.hash for a specific key or returning an object containing the
+ * entire state, optionally coercing numbers, booleans, null and undefined
+ * values.
+ *
+ * @name key An optional state key for which to return a value.
+ * @name coerce If true, coerces any numbers or true, false, null, and undefined to their actual value. Defaults to false
+ */
+ getState(key?: string, coerce?: bool): any;
+
+ getState(coerce?: bool): any;
+
+ /**
+ * Remove one or more keys from the current browser history 'state', creating
+ * a new state, setting location.hash and triggering any bound
+ * callbacks (provided the new state is different than
+ * the previous state).
+ *
+ * @name key One or more key values to remove from the current state.
+ */
+ removeState(...key: any[]): void;
+ }
+
+ interface ParamFragment {
+ (url?: string): string;
+
+ (url: string, params: any, merge_mode?: number): string;
+
+ /**
+ * Specify characters that will be left unescaped when fragments are created
+ * or merged using , or when the fragment is modified
+ * using . This option only applies to serialized data
+ * object fragments, and not set-as-string fragments. Does not affect the
+ * query string. Defaults to ",/" (comma, forward slash).
+ *
+ * @name chars The characters to not escape in the fragment. If unspecified, defaults to empty string (escape all characters).
+ */
+ noEscape: (chars?: string) => void;
+
+ /**
+ * TODO: DESCRIBE
+ *
+ * @name state TODO: DESCRIBE
+ */
+ ajaxCrawlable(state?: bool): bool;
+ }
+
+ interface JQueryDeparam {
+ /**
+ * Deserialize a params string into an object, optionally coercing numbers,
+ * booleans, null and undefined values; this method is the counterpart to the
+ * internal jQuery.param method.
+ *
+ * @name params A params string to be parsed.
+ * @name coerce If true, coerces any numbers or true, false, null, and undefined to their actual value. Defaults to false if omitted.
+ */
+ (params: string, coerce?: bool): any;
+
+
+ /**
+ * Parse the query string from a URL or the current window.location.href,
+ * deserializing it into an object, optionally coercing numbers, booleans,
+ * null and undefined values.
+ *
+ * @name url An optional params string or URL containing query string params to be parsed. If url is omitted, the current window.location.href is used.
+ * @name coerce If true, coerces any numbers or true, false, null, and undefined to their actual value. Defaults to false if omitted.
+ */
+ querystring(url?: string, coerce?: bool): any;
+
+ /**
+ * Parse the fragment (hash) from a URL or the current window.location.href,
+ * deserializing it into an object, optionally coercing numbers, booleans,
+ * null and undefined values.
+ *
+ * @name url An optional params string or URL containing fragment (hash) params to be parsed. If url is omitted, the current window.location.href is used.
+ * @name coerce If true, coerces any numbers or true, false, null, and undefined to their actual value. Defaults to false if omitted.
+ */
+ fragment(url?: string, coerce?: bool): any;
+ }
+
+ interface EventObject extends JQueryEventObject {
+ fragment: string;
+
+ getState( key?: string, coerce? :bool );
+ }
}
interface JQueryParam {
- (obj: any): string;
- (obj: any, traditional: bool): string;
+ /**
+ * Parse the query string from a URL or the current window.location.href,
+ * deserializing it into an object, optionally coercing numbers, booleans,
+ * null and undefined values.
+ *
+ * @name url An optional params string or URL containing query string params to be parsed. If url is omitted, the current window.location.href is used.
+ * @name coerce (Boolean) If true, coerces any numbers or true, false, null, and undefined to their actual value. Defaults to false if omitted.
+ * @name merge_mode An object representing the deserialized params string.
+ */
+ querystring(url?: string, coerce?: bool, merge_mode?: number): string;
- querystring(url?: string): string;
- querystring(url: string, params: any, merge_mode?: number): string;
- fragment: {
- noEscape: (chars?: string) => void;
- (url?: string): string;
- (url: string, params: any, merge_mode?: number): string;
- };
-}
+ querystring(url?: string, coerce?: any, merge_mode?: number): string;
-interface JQueryDeparam {
- (params: string, coerce?: bool): any;
- querystring(url?: string, coerce?: bool): any;
- fragment(url?: string, coerce?: bool): any;
+ fragment: JQueryBbq.ParamFragment;
+
+ /**
+ * Returns a params string equivalent to that returned by the internal
+ * jQuery.param method, but sorted, which makes it suitable for use as a
+ * cache key.
+ *
+ * @name obj An object to be serialized.
+ * @name traditional Params deep/shallow serialization mode. See the documentation at http://api.jquery.com/jQuery.param/ for more detail.
+ */
+ sorted(obj: any, traditional?: bool): string;
}
interface JQueryStatic {
- bbq: JQueryBBQ;
- param: JQueryParam;
- deparam: JQueryDeparam;
+ bbq: JQueryBbq.JQuery;
- elemUrlAttr(tag_attr: any): any;
+ deparam: JQueryBbq.JQueryDeparam;
+
+ /**
+ * Get the internal "Default URL attribute per tag" list, or augment the list
+ * with additional tag-attribute pairs, in case the defaults are insufficient.
+ *
+ * @name tag_attr An object containing a list of tag names and their associated default attribute names in the format { tag: 'attr', ... } to be merged into the internal tag-attribute list.
+ */
+ elemUrlAttr(tag_attr?: any): any;
}
interface JQuery {
- querystring(attr?: any, params?: any, merge_mode?: number): JQuery;
- fragment(attr?: any, params?: any, merge_mode?: number): JQuery;
+ querystring(attr?: any, params?: any, merge_mode?: number): JQuery;
+
+ fragment(attr?: any, params?: any, merge_mode?: number): JQuery;
+
+ hashchange(eventData?: any, handler?: (eventObject: JQueryBbq.EventObject) => any): JQuery;
+
+ hashchange(handler: (eventObject: JQueryBbq.EventObject) => any): JQuery;
}
diff --git a/jquery/jquery.d.ts b/jquery/jquery.d.ts
index 36b46164b..cdae1d8ec 100644
--- a/jquery/jquery.d.ts
+++ b/jquery/jquery.d.ts
@@ -185,6 +185,11 @@ interface JQuerySupport {
tbody?: bool;
}
+interface JQueryParam {
+ (obj: any): string;
+ (obj: any, traditional: bool): string;
+}
+
/*
Static members of jQuery (those on $ and jQuery themselves)
*/
@@ -208,8 +213,7 @@ interface JQueryStatic {
getJSON(url: string, data?: any, success?: any): JQueryXHR;
getScript(url: string, success?: any): JQueryXHR;
- param(obj: any): string;
- param(obj: any, traditional: bool): string;
+ param: JQueryParam;
post(url: string, data?: any, success?: any, dataType?: any): JQueryXHR;
@@ -296,6 +300,9 @@ interface JQueryStatic {
contains(container: Element, contained: Element): bool;
each(collection: any, callback: (indexInArray: any, valueOfElement: any) => any): any;
+ each(collection: JQuery, callback: (indexInArray: number, valueOfElement: HTMLElement) => any): any;
+ each(collection: string[], callback: (indexInArray: number, valueOfElement: string) => any): any;
+ each(collection: number[], callback: (indexInArray: number, valueOfElement: number) => any): any;
extend(target: any, ...objs: any[]): Object;
extend(deep: bool, target: any, ...objs: any[]): Object;
@@ -375,7 +382,7 @@ interface JQuery {
html(htmlString: string): JQuery;
html(htmlContent: (index: number, oldhtml: string) => string): JQuery;
- prop(propertyName: string): any;
+ prop(propertyName: string): string;
prop(propertyName: string, value: any): JQuery;
prop(map: any): JQuery;
prop(propertyName: string, func: (index: any, oldPropertyValue: any) => any): JQuery;
@@ -400,11 +407,11 @@ interface JQuery {
/***
CSS
****/
- css(propertyName: string): any;
- css(propertyNames: string[]): any;
- css(properties: any): any;
- css(propertyName: string, value: any): any;
- css(propertyName: any, value: any): any;
+ css(propertyName: string): string;
+ css(propertyNames: string[]): string;
+ css(properties: any): JQuery;
+ css(propertyName: string, value: any): JQuery;
+ css(propertyName: any, value: any): JQuery;
height(): number;
height(value: number): JQuery;
diff --git a/qunit/qunit.d.ts b/qunit/qunit.d.ts
index f068a857c..b8ba3bb4a 100644
--- a/qunit/qunit.d.ts
+++ b/qunit/qunit.d.ts
@@ -5,44 +5,127 @@
interface DoneCallbackObject {
+ /**
+ * The number of failed assertions
+ */
failed: number;
+
+ /**
+ * The number of passed assertions
+ */
passed: number;
+
+ /**
+ * The total number of assertions
+ */
total: number;
+
+ /**
+ * The time in milliseconds it took tests to run from start to finish.
+ */
runtime: number;
}
interface LogCallbackObject {
+ /**
+ * The boolean result of an assertion, true means passed, false means failed.
+ */
result: bool;
+
+ /**
+ * One side of a comparision assertion. Can be undefined when ok() is used.
+ */
actual: Object;
+
+ /**
+ * One side of a comparision assertion. Can be undefined when ok() is used.
+ */
expected: Object;
+
+ /**
+ * A string description provided by the assertion.
+ */
message: string;
+
+ /**
+ * The associated stacktrace, either from an exception or pointing to the source
+ * of the assertion. Depends on browser support for providing stacktraces, so can be
+ * undefined.
+ */
+ source: string;
}
interface ModuleStartCallbackObject {
+ /**
+ * Name of the next module to run
+ */
name: string;
}
interface ModuleDoneCallbackObject {
+ /**
+ * Name of this module
+ */
name: string;
+
+ /**
+ * The number of failed assertions
+ */
failed: number;
+
+ /**
+ * The number of passed assertions
+ */
passed: number;
+
+ /**
+ * The total number of assertions
+ */
total: number;
}
interface TestDoneCallbackObject {
+ /**
+ * TName of the next test to run
+ */
name: string;
+
+ /**
+ * Name of the current module
+ */
module: string;
+
+ /**
+ * The number of failed assertions
+ */
failed: number;
+
+ /**
+ * The number of passed assertions
+ */
passed: number;
+
+ /**
+ * The total number of assertions
+ */
total: number;
+
+ /**
+ * The total runtime, including setup and teardown
+ */
+ duration: number;
}
interface TestStartCallbackObject {
+ /**
+ * Name of the next test to run
+ */
name: string;
+
+ /**
+ * Name of the current module
+ */
module: string;
- failed: number;
- passed: number;
- total: number;
}
interface Config {
@@ -56,7 +139,14 @@ interface Config {
}
interface LifecycleObject {
+ /**
+ * Runs before each test
+ */
setup?: () => any;
+
+ /**
+ * Runs after each test
+ */
teardown?: () => any;
}
@@ -66,92 +156,554 @@ interface QUnitAssert {
current_testEnvironment: any;
jsDump: any;
+ /**
+ * A deep recursive comparison assertion, working on primitive types, arrays, objects,
+ * regular expressions, dates and functions.
+ *
+ * The deepEqual() assertion can be used just like equal() when comparing the value of
+ * objects, such that { key: value } is equal to { key: value }. For non-scalar values,
+ * identity will be disregarded by deepEqual.
+ *
+ * @param actual Object or Expression being tested
+ * @param expected Known comparison value
+ * @param message A short description of the assertion
+ */
deepEqual(actual: any, expected: any, message?: string);
+
+ /**
+ * A non-strict comparison assertion, roughly equivalent to JUnit assertEquals.
+ *
+ * The equal assertion uses the simple comparison operator (==) to compare the actual
+ * and expected arguments. When they are equal, the assertion passes; otherwise, it fails.
+ * When it fails, both actual and expected values are displayed in the test result,
+ * in addition to a given message.
+ *
+ * @param actual Expression being tested
+ * @param expected Known comparison value
+ * @param message A short description of the assertion
+ */
equal(actual: any, expected: any, message?: string);
+
+ /**
+ * An inverted deep recursive comparison assertion, working on primitive types,
+ * arrays, objects, regular expressions, dates and functions.
+ *
+ * The notDeepEqual() assertion can be used just like equal() when comparing the
+ * value of objects, such that { key: value } is equal to { key: value }. For non-scalar
+ * values, identity will be disregarded by notDeepEqual.
+ *
+ * @param actual Object or Expression being tested
+ * @param expected Known comparison value
+ * @param message A short description of the assertion
+ */
notDeepEqual(actual: any, expected: any, message?: string);
+
+ /**
+ * A non-strict comparison assertion, checking for inequality.
+ *
+ * The notEqual assertion uses the simple inverted comparison operator (!=) to compare
+ * the actual and expected arguments. When they aren't equal, the assertion passes;
+ * otherwise, it fails. When it fails, both actual and expected values are displayed
+ * in the test result, in addition to a given message.
+ *
+ * @param actual Expression being tested
+ * @param expected Known comparison value
+ * @param message A short description of the assertion
+ */
notEqual(actual: any, expected: any, message?: string);
+
notPropEqual(actual: any, expected: any, message?: string);
+
propEqual(actual: any, expected: any, message?: string);
+
+ /**
+ * A non-strict comparison assertion, checking for inequality.
+ *
+ * The notStrictEqual assertion uses the strict inverted comparison operator (!==)
+ * to compare the actual and expected arguments. When they aren't equal, the assertion
+ * passes; otherwise, it fails. When it fails, both actual and expected values are
+ * displayed in the test result, in addition to a given message.
+ *
+ * @param actual Expression being tested
+ * @param expected Known comparison value
+ * @param message A short description of the assertion
+ */
notStrictEqual(actual: any, expected: any, message?: string);
+
+ /**
+ * A boolean assertion, equivalent to CommonJS’s assert.ok() and JUnit’s assertTrue().
+ * Passes if the first argument is truthy.
+ *
+ * The most basic assertion in QUnit, ok() requires just one argument. If the argument
+ * evaluates to true, the assertion passes; otherwise, it fails. If a second message
+ * argument is provided, it will be displayed in place of the result.
+ *
+ * @param state Expression being tested
+ * @param message A short description of the assertion
+ */
ok(state: any, message?: string);
+
+ /**
+ * A strict type and value comparison assertion.
+ *
+ * The strictEqual() assertion provides the most rigid comparison of type and value with
+ * the strict equality operator (===)
+ *
+ * @param actual Expression being tested
+ * @param expected Known comparison value
+ * @param message A short description of the assertion
+ */
strictEqual(actual: any, expected: any, message?: string);
+
+ /**
+ * Assertion to test if a callback throws an exception when run.
+ *
+ * When testing code that is expected to throw an exception based on a specific set of
+ * circumstances, use throws() to catch the error object for testing and comparison.
+ *
+ * @param block Function to execute
+ * @param expected Error Object to compare
+ * @param message A short description of the assertion
+ */
throws(block: () => any, expected: any, message?: string);
+
+ /**
+ * @param block Function to execute
+ * @param message A short description of the assertion
+ */
throws(block: () => any, message?: string);
}
interface QUnitStatic extends QUnitAssert{
/* ASYNC CONTROL */
+
+ /**
+ * Start running tests again after the testrunner was stopped. See stop().
+ *
+ * When your async test has multiple exit points, call start() for the corresponding number of stop() increments.
+ *
+ * @param decrement Optional argument to merge multiple start() calls into one. Use with multiple corrsponding stop() calls.
+ */
start(decrement?: number);
+
+ /**
+ * Stop the testrunner to wait for async tests to run. Call start() to continue.
+ *
+ * When your async test has multiple exit points, call stop() with the increment argument, corresponding to the number of start() calls you need.
+ *
+ * On Blackberry 5.0, window.stop is a native read-only function. If you deal with that browser, use QUnit.stop() instead, which will work anywhere.
+ *
+ * @param decrement Optional argument to merge multiple stop() calls into one. Use with multiple corrsponding start() calls.
+ */
stop(increment? : number);
/* CALLBACKS */
+
+ /**
+ * Register a callback to fire whenever the test suite begins.
+ *
+ * QUnit.begin() is called once before running any tests. (a better would've been QUnit.start,
+ * but thats already in use elsewhere and can't be changed.)
+ *
+ * @param callback Callback to execute
+ */
begin(callback: () => any);
+
+ /**
+ * Register a callback to fire whenever the test suite ends.
+ *
+ * @param callback Callback to execute.
+ */
done(callback: (details: DoneCallbackObject) => any);
+
+ /**
+ * Register a callback to fire whenever an assertion completes.
+ *
+ * This is one of several callbacks QUnit provides. Its intended for integration scenarios like
+ * PhantomJS or Jenkins. The properties of the details argument are listed below as options.
+ *
+ * @param callback Callback to execute.
+ */
log(callback: (details: LogCallbackObject) => any);
+
+ /**
+ * Register a callback to fire whenever a module ends.
+ *
+ * @param callback Callback to execute.
+ */
moduleDone(callback: (details: ModuleDoneCallbackObject) => any);
+
+ /**
+ * Register a callback to fire whenever a module begins.
+ *
+ * @param callback Callback to execute.
+ */
moduleStart(callback: (details: ModuleStartCallbackObject) => any);
+
+ /**
+ * Register a callback to fire whenever a test ends.
+ *
+ * @param callback Callback to execute.
+ */
testDone(callback: (details: TestDoneCallbackObject) => any);
+
+ /**
+ * Register a callback to fire whenever a test begins.
+ *
+ * @param callback Callback to execute.
+ */
testStart(callback: (details: TestStartCallbackObject) => any);
/* CONFIGURATION */
+
+ /**
+ * QUnit has a bunch of internal configuration defaults, some of which are
+ * useful to override. Check the description for each option for details.
+ */
config: Config;
/* TEST */
+
+ /**
+ * Add an asynchronous test to run. The test must include a call to start().
+ *
+ * For testing asynchronous code, asyncTest will automatically stop the test runner
+ * and wait for your code to call start() to continue.
+ *
+ * @param name Title of unit being tested
+ * @param expected Number of assertions in this test
+ * @param test Function to close over assertions
+ */
asyncTest(name: string, expected: number, test: () => any);
+
+ /**
+ * Add an asynchronous test to run. The test must include a call to start().
+ *
+ * For testing asynchronous code, asyncTest will automatically stop the test runner
+ * and wait for your code to call start() to continue.
+ *
+ * @param name Title of unit being tested
+ * @param test Function to close over assertions
+ */
asyncTest(name: string, test: () => any);
+
+ /**
+ * Specify how many assertions are expected to run within a test.
+ *
+ * To ensure that an explicit number of assertions are run within any test, use
+ * expect( number ) to register an expected count. If the number of assertions
+ * run does not match the expected count, the test will fail.
+ *
+ * @param amount Number of assertions in this test.
+ */
expect(amount: number);
+
+ /**
+ * Group related tests under a single label.
+ *
+ * All tests that occur after a call to module() will be grouped into that module.
+ * The test names will all be preceded by the module name in the test results.
+ * You can then use that module name to select tests to run.
+ *
+ * @param name Label for this group of tests
+ * @param lifecycle Callbacks to run before and after each test
+ */
module(name: string, lifecycle?: LifecycleObject);
+
+ /**
+ * Add a test to run.
+ *
+ * When testing the most common, synchronous code, use test().
+ * The assert argument to the callback contains all of QUnit's assertion methods.
+ * If you are avoiding using any of QUnit's globals, you can use the assert
+ * argument instead.
+ *
+ * @param title Title of unit being tested
+ * @param expected Number of assertions in this test
+ * @param test Function to close over assertions
+ */
test(title: string, expected: number, test: (assert: QUnitAssert) => any);
+
+ /**
+ * @param title Title of unit being tested
+ * @param test Function to close over assertions
+ */
test(title: string, test: (assert: QUnitAssert) => any);
- // https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L1568
+ /**
+ * https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L1568
+ */
equiv(a: any, b: any);
// https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L661
raises: any;
- // https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L897
+ /**
+ * https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L897
+ */
push(result, actual, expected, message): any;
- // https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L839
+ /**
+ * https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L839
+ */
reset(): any;
}
/* ASSERT */
+
+/**
+* A deep recursive comparison assertion, working on primitive types, arrays, objects,
+* regular expressions, dates and functions.
+*
+* The deepEqual() assertion can be used just like equal() when comparing the value of
+* objects, such that { key: value } is equal to { key: value }. For non-scalar values,
+* identity will be disregarded by deepEqual.
+*
+* @param actual Object or Expression being tested
+* @param expected Known comparison value
+* @param message A short description of the assertion
+*/
declare function deepEqual(actual: any, expected: any, message?: string);
+
+/**
+* A non-strict comparison assertion, roughly equivalent to JUnit assertEquals.
+*
+* The equal assertion uses the simple comparison operator (==) to compare the actual
+* and expected arguments. When they are equal, the assertion passes; otherwise, it fails.
+* When it fails, both actual and expected values are displayed in the test result,
+* in addition to a given message.
+*
+* @param actual Expression being tested
+* @param expected Known comparison value
+* @param message A short description of the assertion
+*/
declare function equal(actual: any, expected: any, message?: string);
+
+/**
+* An inverted deep recursive comparison assertion, working on primitive types,
+* arrays, objects, regular expressions, dates and functions.
+*
+* The notDeepEqual() assertion can be used just like equal() when comparing the
+* value of objects, such that { key: value } is equal to { key: value }. For non-scalar
+* values, identity will be disregarded by notDeepEqual.
+*
+* @param actual Object or Expression being tested
+* @param expected Known comparison value
+* @param message A short description of the assertion
+*/
declare function notDeepEqual(actual: any, expected: any, message?: string);
+
+/**
+* A non-strict comparison assertion, checking for inequality.
+*
+* The notEqual assertion uses the simple inverted comparison operator (!=) to compare
+* the actual and expected arguments. When they aren't equal, the assertion passes;
+* otherwise, it fails. When it fails, both actual and expected values are displayed
+* in the test result, in addition to a given message.
+*
+* @param actual Expression being tested
+* @param expected Known comparison value
+* @param message A short description of the assertion
+*/
declare function notEqual(actual: any, expected: any, message?: string);
+
+/**
+* A non-strict comparison assertion, checking for inequality.
+*
+* The notStrictEqual assertion uses the strict inverted comparison operator (!==)
+* to compare the actual and expected arguments. When they aren't equal, the assertion
+* passes; otherwise, it fails. When it fails, both actual and expected values are
+* displayed in the test result, in addition to a given message.
+*
+* @param actual Expression being tested
+* @param expected Known comparison value
+* @param message A short description of the assertion
+*/
declare function notStrictEqual(actual: any, expected: any, message?: string);
+
+/**
+* A boolean assertion, equivalent to CommonJS’s assert.ok() and JUnit’s assertTrue().
+* Passes if the first argument is truthy.
+*
+* The most basic assertion in QUnit, ok() requires just one argument. If the argument
+* evaluates to true, the assertion passes; otherwise, it fails. If a second message
+* argument is provided, it will be displayed in place of the result.
+*
+* @param state Expression being tested
+* @param message A short description of the assertion
+*/
declare function ok(state: any, message?: string);
+
+/**
+* A strict type and value comparison assertion.
+*
+* The strictEqual() assertion provides the most rigid comparison of type and value with
+* the strict equality operator (===)
+*
+* @param actual Expression being tested
+* @param expected Known comparison value
+* @param message A short description of the assertion
+*/
declare function strictEqual(actual: any, expected: any, message?: string);
+
+/**
+* Assertion to test if a callback throws an exception when run.
+*
+* When testing code that is expected to throw an exception based on a specific set of
+* circumstances, use throws() to catch the error object for testing and comparison.
+*
+* @param block Function to execute
+* @param expected Error Object to compare
+* @param message A short description of the assertion
+*/
declare function throws(block: () => any, expected: any, message?: string);
+
+/**
+* @param block Function to execute
+* @param message A short description of the assertion
+*/
declare function throws(block: () => any, message?: string);
/* ASYNC CONTROL */
+
+/**
+* Start running tests again after the testrunner was stopped. See stop().
+*
+* When your async test has multiple exit points, call start() for the corresponding number of stop() increments.
+*
+* @param decrement Optional argument to merge multiple start() calls into one. Use with multiple corrsponding stop() calls.
+*/
declare function start(decrement?: number);
+
+/**
+* Stop the testrunner to wait for async tests to run. Call start() to continue.
+*
+* When your async test has multiple exit points, call stop() with the increment argument, corresponding to the number of start() calls you need.
+*
+* On Blackberry 5.0, window.stop is a native read-only function. If you deal with that browser, use QUnit.stop() instead, which will work anywhere.
+*
+* @param decrement Optional argument to merge multiple stop() calls into one. Use with multiple corrsponding start() calls.
+*/
declare function stop(increment? : number);
/* CALLBACKS */
+
+/**
+* Register a callback to fire whenever the test suite begins.
+*
+* QUnit.begin() is called once before running any tests. (a better would've been QUnit.start,
+* but thats already in use elsewhere and can't be changed.)
+*
+* @param callback Callback to execute
+*/
declare function begin(callback: () => any);
+
+/**
+* Register a callback to fire whenever the test suite ends.
+*
+* @param callback Callback to execute.
+*/
declare function done(callback: (details: DoneCallbackObject) => any);
+
+/**
+* Register a callback to fire whenever an assertion completes.
+*
+* This is one of several callbacks QUnit provides. Its intended for integration scenarios like
+* PhantomJS or Jenkins. The properties of the details argument are listed below as options.
+*
+* @param callback Callback to execute.
+*/
declare function log(callback: (details: LogCallbackObject) => any);
+
+/**
+* Register a callback to fire whenever a module ends.
+*
+* @param callback Callback to execute.
+*/
declare function moduleDone(callback: (details: ModuleDoneCallbackObject) => any);
+
+/**
+* Register a callback to fire whenever a module begins.
+*
+* @param callback Callback to execute.
+*/
declare function moduleStart(callback: (name: string) => any);
+
+/**
+* Register a callback to fire whenever a test ends.
+*
+* @param callback Callback to execute.
+*/
declare function testDone(callback: (details: TestDoneCallbackObject) => any);
+
+/**
+* Register a callback to fire whenever a test begins.
+*
+* @param callback Callback to execute.
+*/
declare function testStart(callback: (details: TestStartCallbackObject) => any);
/* TEST */
+
+/**
+* Add an asynchronous test to run. The test must include a call to start().
+*
+* For testing asynchronous code, asyncTest will automatically stop the test runner
+* and wait for your code to call start() to continue.
+*
+* @param name Title of unit being tested
+* @param expected Number of assertions in this test
+* @param test Function to close over assertions
+*/
declare function asyncTest(name: string, expected?: any, test?: () => any);
+
+/**
+* Add an asynchronous test to run. The test must include a call to start().
+*
+* For testing asynchronous code, asyncTest will automatically stop the test runner
+* and wait for your code to call start() to continue.
+*
+* @param name Title of unit being tested
+* @param test Function to close over assertions
+*/
+declare function asyncTest(name: string, test: () => any);
+
+/**
+* Specify how many assertions are expected to run within a test.
+*
+* To ensure that an explicit number of assertions are run within any test, use
+* expect( number ) to register an expected count. If the number of assertions
+* run does not match the expected count, the test will fail.
+*
+* @param amount Number of assertions in this test.
+*/
declare function expect(amount: number);
// ** conflict with TypeScript module keyword. Must be used on QUnit namespace
//declare var module: (name: string, lifecycle?: LifecycleObject) => any;
+/**
+* Add a test to run.
+*
+* When testing the most common, synchronous code, use test().
+* The assert argument to the callback contains all of QUnit's assertion methods.
+* If you are avoiding using any of QUnit's globals, you can use the assert
+* argument instead.
+*
+* @param title Title of unit being tested
+* @param expected Number of assertions in this test
+* @param test Function to close over assertions
+*/
declare function test(title: string, expected: number, test: (assert?: QUnitAssert) => any);
+
+/**
+* @param title Title of unit being tested
+* @param test Function to close over assertions
+*/
declare function test(title: string, test: (assert?: QUnitAssert) => any);
declare function notPropEqual(actual: any, expected: any, message?: string);
+
declare function propEqual(actual: any, expected: any, message?: string);
// https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L1568
diff --git a/requirejs/require.d.ts b/requirejs/require.d.ts
index 1d6934041..e9351aa46 100644
--- a/requirejs/require.d.ts
+++ b/requirejs/require.d.ts
@@ -202,5 +202,5 @@ interface RequireDefine {
}
// Ambient declarations for 'require' and 'define'
-var require: Require;
-var define: RequireDefine;
+declare var require: Require;
+declare var define: RequireDefine;
diff --git a/restify/restify-test.ts b/restify/restify-test.ts
new file mode 100644
index 000000000..964a428b5
--- /dev/null
+++ b/restify/restify-test.ts
@@ -0,0 +1,218 @@
+///
+
+import restify = module("restify");
+
+var server = restify.createServer({
+ formatters: {
+ 'application/foo': function formatFoo(req, res, body) {
+ if (body instanceof Error)
+ return body.stack;
+
+ if (body)
+ return body.toString('base64');
+
+ return body;
+ }
+ }
+});
+
+server = restify.createServer({
+ certificate: "test",
+ key: "test",
+ formatters: {},
+ log: {},
+ name: "test",
+ spdy: {},
+ version: "",
+ responseTimeHeader: "",
+ responseTimeFormatter : (durationInMilliseconds: number) => {}
+});
+
+server.on('someEvent', ()=>{});
+
+
+server.use((req, res, next)=>{});
+server.use([(req, res, next)=>{}]);
+server.use((req, res, next)=>{}, (req, res, next)=>{});
+
+function send(req, res, next) {
+ req.header('key', 'val');
+ req.header('key') === 'val';
+
+ req.accepts('test') === true;
+ req.is('test') === true;
+
+ req.getLogger('test');
+
+ var log = req.log;
+ log.debug({params: req.params}, 'Hello there %s', 'foo');
+
+ req.contentLength === 50;
+ req.contentType === 'test';
+ req.href === 'test';
+ req.id === 'test';
+ req.path === 'test';
+ req.query === 'test';
+ req.secure === true;
+ req.time === 50;
+ req.params;
+
+ res.header('test');
+ res.header('test', {});
+ res.header('test', new Date());
+
+ res.cache();
+ res.cache('testst', {});
+
+ res.status(344);
+
+ res.send({hello: 'world'});
+ res.send(201, {hello: 'world'});
+ res.send(new restify.BadRequestError('meh'));
+
+ res.json(201, {hello: 'world'});
+ res.json({hello: 'world'});
+
+ res.code === 50;
+ res.contentLength === 50;
+ res.charSet === 'test';
+ res.contentType === 'test';
+ res.headers;
+ res.id === 'test';
+
+ res.send('hello ' + req.params.name);
+ return next();
+}
+
+
+server.post('/hello', send);
+server.put( '/hello', send);
+server.del( '/hello', send);
+server.get( '/hello', send);
+server.head('/hello', send);
+
+server.post(/(.*)/, send);
+server.put( /(.*)/, send);
+server.del( /(.*)/, send);
+server.get( /(.*)/, send);
+server.head(/(.*)/, send);
+
+new restify.ConflictError("test");
+new restify.InvalidArguementError("message");
+new restify.RestError("message");
+new restify.BadDigestError("message");
+new restify.BadMethodError("message");
+new restify.BadRequestError('test');
+new restify.InternalError("message");
+new restify.InvalidContentError("message");
+new restify.InvalidCredentialsError("message");
+new restify.InvalidHeaderError("message");
+new restify.InvalidVersionError("message");
+new restify.MissingParameterError("message");
+new restify.NotAuthorizedError("message");
+new restify.RequestExpiredError("jjmessage");
+new restify.RequestThrottledError("message");
+new restify.ResourceNotFoundError("message");
+new restify.WrongAcceptError("message");
+
+server.name = "";
+server.version = "";
+server.log = {};
+server.acceptable = ["test"];
+server.url = "";
+
+server.address().port;
+server.address().family;
+server.address().address;
+
+server.listen("somePath", send);
+server.close();
+
+server.use(restify.acceptParser(server.acceptable));
+server.use(restify.authorizationParser());
+server.use(restify.dateParser());
+server.use(restify.queryParser());
+server.use(restify.jsonp());
+server.use(restify.gzipResponse());
+server.use(restify.bodyParser());
+server.use(restify.throttle({
+ burst: 100,
+ rate: 50,
+ ip: true,
+ overrides: {
+ '192.168.1.1': {
+ rate: 0,
+ burst: 0
+ }
+ }
+}));
+
+server.on('after', restify.auditLogger({
+ log: ()=>{}
+}));
+
+restify.defaultResponseHeaders = function(data) {
+ this.header('Server', 'helloworld');
+};
+
+restify.defaultResponseHeaders = false;
+
+//RESTIFY Client Tests
+
+var client = restify.createJsonClient({
+ url: 'https://api.us-west-1.joyentcloud.com',
+ version: '*'
+});
+
+client = restify.createStringClient({
+ accept: "test",
+ connectTimeout: 30,
+ dtrace: {},
+ gzip: {},
+ headers: {},
+ log: {},
+ retry: {},
+ signRequest: ()=>{},
+ url: "",
+ userAgent: "",
+ version: ""
+});
+
+client.get("test", send);
+client.head('test', send);
+client.post('path', {}, send);
+client.put('path', {}, send);
+client.del('path', send);
+
+client.post('/foo', { hello: 'world' }, function(err, req, res, obj) {
+ console.log('%d -> %j', res.statusCode, res.headers);
+ console.log('%j', obj);
+});
+
+client.get('/foo/bar', function(err, req, res, data) {
+ console.log('%s', data);
+});
+
+var client2 = restify.createClient({
+ url: 'http://127.0.0.1'
+});
+
+client2.get('/str/mcavage', function(err, req) {
+
+ req.on('result', function(err, res) {
+
+ res.body = '';
+ res.setEncoding('utf8');
+ res.on('data', function(chunk) {
+ res.body += chunk;
+ });
+
+ res.on('end', function() {
+ console.log(res.body);
+ });
+ });
+});
+
+
+client.basicAuth('test', 'password');
+client2.basicAuth('test', 'password');
diff --git a/restify/restify.d.ts b/restify/restify.d.ts
new file mode 100644
index 000000000..9d5edd93d
--- /dev/null
+++ b/restify/restify.d.ts
@@ -0,0 +1,152 @@
+interface addressInterface {
+ port: number;
+ family: string;
+ address: string;
+}
+
+interface Request {
+ header: (key: string, defaultValue?: string) => any;
+ accepts: (type: string) => bool;
+ is: (type: string) => bool;
+ getLogger: (component: string) => any;
+ contentLength: number;
+ contentType: string;
+ href: string;
+ log: Object;
+ id: string;
+ path: string;
+ query: string;
+ secure: bool;
+ time: number;
+ params: any;
+}
+
+interface Response {
+ header: (key: string, value ?: any) => any;
+ cache: (type?: any, options?: Object) => any;
+ status: (code: number) => any;
+ send: (status?: any, body?: any) => any;
+ json: (status?: any, body?: any) => any;
+ code: number;
+ contentLength: number;
+ charSet: string;
+ contentType: string;
+ headers: Object;
+ statusCode: number;
+ id: string;
+}
+
+interface Server {
+ use: (... handler: any[]) => any;
+ post: (route: any, routeCallBack: (req: Request, res: Response, next: Function) => any) => any;
+ put: (route: any, routeCallBack: (req: Request, res: Response, next: Function) => any) => any;
+ del: (route: any, routeCallBack: (req: Request, res: Response, next: Function) => any) => any;
+ get: (route: any, routeCallBack: (req: Request, res: Response, next: Function ) => any) => any;
+ head: (route: any, routeCallBack: (req: Request, res: Response, next: Function) => any) => any;
+ on: (event: string, callback: Function) => any;
+ name: string;
+ version: string;
+ log: Object;
+ acceptable: string[];
+ url: string;
+ address: () => addressInterface;
+ listen: (... args: any[]) => any;
+ close: (... args: any[]) => any;
+ pre: (routeCallBack: (req: Request, res: Response, next: Function) => any) => any;
+
+}
+
+interface ServerOptions {
+ certificate ?: string;
+ key ?: string;
+ formatters ?: Object;
+ log ?: Object;
+ name ?: string;
+ spdy ?: Object;
+ version ?: string;
+ responseTimeHeader ?: string;
+ responseTimeFormatter ?: (durationInMilliseconds: number) => any;
+}
+
+interface ClientOptions {
+ accept?: string;
+ connectTimeout?: number;
+ dtrace?: Object;
+ gzip?: Object;
+ headers?: Object;
+ log?: Object;
+ retry?: Object;
+ signRequest?: Function;
+ url?: string;
+ userAgent?: string;
+ version?: string;
+}
+
+interface Client {
+ get: (path: string, callback?: (err: any, req: Request, res: Response, obj: any) => any) => any;
+ head: (path: string, callback?: (err: any, req: Request, res: Response) => any) => any;
+ post: (path: string, object: any, callback?: (err: any, req: Request, res: Response, obj: any) => any) => any;
+ put: (path: string, object: any, callback?: (err: any, req: Request, res: Response, obj: any) => any) => any;
+ del: (path: string, callback?: (err: any, req: Request, res: Response) => any) => any;
+ basicAuth: (username: string, password: string) => any;
+}
+
+interface HttpClient extends Client {
+ get: (path?: any, callback?: Function) => any;
+ head: (path?:any, callback?: Function) => any;
+ post: (opts?: any, callback?: Function) => any;
+ put: (opts?: any, callback?: Function) => any;
+ del: (opts?: any, callback?: Function) => any;
+}
+
+interface ThrottleOptions {
+ burst?: number;
+ rate?: number;
+ ip?: bool;
+ xff?: bool;
+ username?: bool;
+ tokensTable?: Object;
+ maxKeys?: number;
+ overrides?: Object;
+}
+
+declare module "restify" {
+ export function createServer(options?: ServerOptions): Server;
+
+ export function createJsonClient(options?: ClientOptions): Client;
+ export function createStringClient(options?: ClientOptions): Client;
+ export function createClient(options?: ClientOptions): HttpClient;
+
+ export class ConflictError { constructor(message?: any); };
+ export class InvalidArguementError { constructor(message?: any); };
+ export class RestError { constructor(message?: any); };
+ export class BadDigestError { constructor(message: any); };
+ export class BadMethodError { constructor(message: any); };
+ export class BadRequestError { constructor(message: any); };
+ export class InternalError { constructor(message: any); };
+ export class InvalidContentError { constructor(message: any); };
+ export class InvalidCredentialsError { constructor(message: any); };
+ export class InvalidHeaderError { constructor(message: any); };
+ export class InvalidVersionError { constructor(message: any); };
+ export class MissingParameterError { constructor(message: any); };
+ export class NotAuthorizedError { constructor(message: any); };
+ export class RequestExpiredError { constructor(message: any); };
+ export class RequestThrottledError { constructor(message: any); };
+ export class ResourceNotFoundError { constructor(message: any); };
+ export class WrongAcceptError { constructor(message: any); };
+
+ export function acceptParser(parser: any);
+ export function authorizationParser();
+ export function dateParser(skew?: number);
+ export function queryParser(options?: Object);
+ export function urlEncodedBodyParser(options?: Object);
+ export function jsonp(options?: Object);
+ export function gzipResponse(options?: Object);
+ export function bodyParser(options?: Object);
+ export function requestLogger(options?: Object);
+ export function serveStatic(options?: Object);
+ export function throttle(options?: ThrottleOptions);
+ export function conditionalRequest(options?: Object);
+ export function auditLogger(options?: Object);
+ export var defaultResponseHeaders : any;
+}
diff --git a/videojs/videojs-tests.ts b/videojs/videojs-tests.ts
index 37f8d5fda..7995339ac 100644
--- a/videojs/videojs-tests.ts
+++ b/videojs/videojs-tests.ts
@@ -1,7 +1,6 @@
// Tests for Video.js API
///
-<<<<<<< HEAD
_V_("example_video_1").ready(function(){
var myPlayer:VideoJSPlayer = this;
@@ -72,7 +71,4 @@ _V_("example_video_1").ready(function(){
myPlayer.addEvent("volumechange", myFunc);
myPlayer.removeEvent("volumechange", myFunc);
-});
-=======
-var myPlayer:VideoJSPlayer = _V_("example_video_1");
->>>>>>> f8b142ba4c1a906b03601cd1f0d53484250f11b3
+});
\ No newline at end of file
diff --git a/videojs/videojs.d.ts b/videojs/videojs.d.ts
index 17834c22e..49fb1c09a 100644
--- a/videojs/videojs.d.ts
+++ b/videojs/videojs.d.ts
@@ -26,10 +26,7 @@ interface VideoJSPlayer {
src(newSource: VideoJSSource): VideoJSPlayer;
src(newSource: VideoJSSource[]): VideoJSPlayer;
currentTime(seconds: number): VideoJSPlayer;
-<<<<<<< HEAD
currentTime(): number;
-=======
->>>>>>> f8b142ba4c1a906b03601cd1f0d53484250f11b3
duration(): number;
buffered(): TimeRanges;
bufferedPercent(): number;