parent
62fe14dfeb
commit
fe86d8d906
@ -0,0 +1,26 @@
|
|||||||
|
# Lab
|
||||||
|
|
||||||
|
|
||||||
|
###HANGMAN w/DOM
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Last weekend you had a ton of fun with hangman in the console. This weekend your assignment is to make your hangman solution playable in the browser. Feel free to use your existing solution, if you are not comfortable with your solution you may also use our solution to the problem. **PRO TIP** You may have to adapt the existing solutions to work with the DOM.
|
||||||
|
|
||||||
|
|
||||||
|
###User Stories
|
||||||
|
|
||||||
|
* As a user I would like to be able to push a start button and have a game start and render in the browser.
|
||||||
|
* As a user I would like to be able to see what letters I've played
|
||||||
|
* As a user I would like to be able to see how many guesses I have left
|
||||||
|
* As a user I would like to be able to see the current status of the word, with hidden letters represented by underscores and guessed letters represented by their value.
|
||||||
|
* As a user I would like to be able to use an input box on the page to guess my letters
|
||||||
|
|
||||||
|
|
||||||
|
###Bonuses
|
||||||
|
|
||||||
|
* As a user I would like to see a visual representation of hangman similar to the picture above.
|
||||||
|
* As a user I would like my letter inputs to be dictated by keypresses, so if I push the `K` key on my keyboard it will guess `k`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>DOM Hangman</title>
|
||||||
|
<script src="js/letter.js"></script>
|
||||||
|
<script src="js/word.js"></script>
|
||||||
|
<script src="js/game.js"></script>
|
||||||
|
<script src="js/main.js"></script>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>POKEMON HANGMAN</h1>
|
||||||
|
<div id="startButton">Start</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div id="gameArea">
|
||||||
|
|
||||||
|
<div id="guessesLeft">
|
||||||
|
<h2>Guesses Left</h2>
|
||||||
|
<h1 id="guesses"></h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="currentWord">
|
||||||
|
<h2>Current Word</h2>
|
||||||
|
<h1 id="gameWord"></h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="guessedLetters">
|
||||||
|
<h2>Guessed Letters</h2>
|
||||||
|
<h1 id="letters"></h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="screenMessage"></div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
console.log("loaded bro");
|
||||||
|
|
||||||
|
var game = {
|
||||||
|
guesses: null,
|
||||||
|
guessedLetters: [],
|
||||||
|
words: [],
|
||||||
|
currentWord: null,
|
||||||
|
startGame: function (wordsArray) {
|
||||||
|
this.guesses = 10;
|
||||||
|
this.guessedLetters = [];
|
||||||
|
this.words = wordsArray;
|
||||||
|
var randomWord = this.words[Math.floor(Math.random() * this.words.length)];
|
||||||
|
this.currentWord = new Word();
|
||||||
|
this.currentWord.getLetters(randomWord);
|
||||||
|
},
|
||||||
|
guess: function (letter) {
|
||||||
|
if ( this.guessedLetters.indexOf(letter) === -1 ) {
|
||||||
|
var found = this.currentWord.try(letter);
|
||||||
|
if (!found) {
|
||||||
|
this.guesses--;
|
||||||
|
}
|
||||||
|
this.guessedLetters.push(letter);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isOver: function () {
|
||||||
|
return (this.guesses === 0) || (this.currentWord.isFound());
|
||||||
|
},
|
||||||
|
overMessage: function () {
|
||||||
|
if ( this.guesses === 0 ) {
|
||||||
|
return "You Lose"
|
||||||
|
}
|
||||||
|
else if ( this.currentWord.isFound() ) {
|
||||||
|
return "You Win"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render: function () {
|
||||||
|
return this.currentWord.render();
|
||||||
|
},
|
||||||
|
getGuesses: function() {
|
||||||
|
return this.guesses;
|
||||||
|
},
|
||||||
|
getGuessedLetters: function() {
|
||||||
|
return this.guessedLetters.join(" ");
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
var Letter = function(letter) {
|
||||||
|
|
||||||
|
this.value = letter;
|
||||||
|
|
||||||
|
this.hidden = true;
|
||||||
|
|
||||||
|
this.hide = function() {
|
||||||
|
this.hidden = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.show = function() {
|
||||||
|
this.hidden = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.render = function() {
|
||||||
|
return this.hidden ? " _ " : this.value;
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
var wordBank = ["bulbasaur", "ivysaur", "venusaur", "charmander", "charmeleon", "charizard", "squirtle", "wartortle", "blastoise",
|
||||||
|
"caterpie", "metapod", "butterfree", "weedle", "kakuna", "beedrill", "pidgey", "pidgeotto", "pidgeot", "rattata",
|
||||||
|
"raticate", "spearow", "fearow", "ekans", "arbok", "pikachu", "raichu", "sandshrew", "sandslash", "nidoran", "nidorina",
|
||||||
|
"nidoqueen", "nidoran", "nidorino", "nidoking", "clefairy", "clefable", "vulpix", "ninetales", "jigglypuff", "wigglytuff",
|
||||||
|
"zubat", "golbat", "oddish", "gloom", "vileplume", "paras", "parasect", "venonat", "venomoth", "diglett", "dugtrio",
|
||||||
|
"meowth", "persian", "psyduck", "golduck", "mankey", "primeape", "growlithe", "arcanine", "poliwag", "poliwhirl",
|
||||||
|
"poliwrath", "abra", "kadabra", "alakazam", "machop", "machoke", "machamp", "bellsprout", "weepinbell", "victreebel",
|
||||||
|
"tentacool", "tentacruel", "geodude", "graveler", "golem", "ponyta", "rapidash", "slowpoke", "slowbro", "magnemite",
|
||||||
|
"magneton", "farfetchd", "doduo", "dodrio", "seel", "dewgong", "grimer", "muk", "shellder", "cloyster", "gastly",
|
||||||
|
"haunter", "gengar", "onix", "drowzee", "hypno", "krabby", "kingler", "voltorb", "electrode", "exeggcute", "exeggutor",
|
||||||
|
"cubone", "marowak", "hitmonlee", "hitmonchan", "lickitung", "koffing", "weezing", "rhyhorn", "rhydon", "chansey",
|
||||||
|
"tangela", "kangaskhan", "horsea", "seadra", "goldeen", "seaking", "staryu", "starmie", "mr.mime", "scyther", "jynx",
|
||||||
|
"electabuzz", "magmar", "pinsir", "tauros", "magikarp", "gyarados", "lapras", "ditto", "eevee", "vaporeon", "jolteon",
|
||||||
|
"flareon", "porygon", "omanyte", "omastar", "kabuto", "kabutops", "aerodactyl", "snorlax", "articuno", "zapdos", "moltres",
|
||||||
|
"dratini", "dragonair", "dragonite", "mewtwo", "mew"]; // an array of suite pokemon
|
||||||
|
|
||||||
|
window.onload = function() {
|
||||||
|
startButton = document.getElementById("startButton"); // startButton
|
||||||
|
guesses = document.getElementById("guesses"); // element containing what displays the number of guesses
|
||||||
|
gameWord = document.getElementById("gameWord"); // element containing the game render
|
||||||
|
guessedLetters = document.getElementById("letters"); // element containing the users guessed letters
|
||||||
|
screenMessage = document.getElementById("screenMessage"); // element containing the winning or losing message
|
||||||
|
startButton.addEventListener("click", startGame); // click event listener on startButton to start the game
|
||||||
|
document.body.addEventListener("keypress", guessLetter);
|
||||||
|
};
|
||||||
|
|
||||||
|
function startGame() { // function that is executed by clicking the start button
|
||||||
|
game.startGame(wordBank); // calls startGame on the game object passing in the array of words
|
||||||
|
updateUi(); // calls updateUi
|
||||||
|
screenMessage.style.display = "none"; // hide the winning message
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateUi() { // function that updates the dom with the current status of the game
|
||||||
|
guesses.innerHTML = game.getGuesses(); // set the element to show the ammount of guesses remaining
|
||||||
|
gameWord.innerHTML = game.render(); // set the element to show the current rendering of the game
|
||||||
|
guessedLetters.innerHTML = game.getGuessedLetters(); // set the element to show which letters have been guessed
|
||||||
|
};
|
||||||
|
|
||||||
|
function guessLetter(event) {
|
||||||
|
if(!game.isOver()) {
|
||||||
|
// game.guess(String.fromCharCode(event.charCode)); lines 41-43 can all be done in this one line
|
||||||
|
var charCode = event.charCode; // gets the character code of the key that was pressed
|
||||||
|
var charString = String.fromCharCode(charCode); // convert the character code into a letter string
|
||||||
|
game.guess(charString); // use the letter string to guess a letter in the game
|
||||||
|
updateUi(); // calls updateUi to update the ui after you made the guess
|
||||||
|
checkForWin();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function checkForWin() {
|
||||||
|
if(game.isOver()) { // check to see if guess are 0 or if the word is found
|
||||||
|
screenMessage.innerHTML = game.overMessage(); // set the message depending on win or lose
|
||||||
|
screenMessage.style.display = "inline"; // display the winning message
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
var Word = function() {
|
||||||
|
|
||||||
|
this.letters = [];
|
||||||
|
|
||||||
|
this.getLetters = function(word) {
|
||||||
|
for(var i = 0; i < word.length; i++) {
|
||||||
|
this.letters.push(new Letter(word[i]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isFound = function() {
|
||||||
|
return this.letters.every(function(currentLetter) {
|
||||||
|
return !currentLetter.hidden;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.try = function(letter) {
|
||||||
|
var found = false;
|
||||||
|
for(var i = 0; i < this.letters.length; i++) {
|
||||||
|
if(this.letters[i].value === letter) {
|
||||||
|
this.letters[i].show();
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.render = function() {
|
||||||
|
return this.letters.map(function(letter) {
|
||||||
|
return letter.render();
|
||||||
|
}).join("");
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
header h1 {
|
||||||
|
font-size: 75px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#startButton {
|
||||||
|
position: relative;
|
||||||
|
border: 3px solid blue;
|
||||||
|
height: 50px;
|
||||||
|
width: 200px;
|
||||||
|
text-align: center;
|
||||||
|
top: -40px;
|
||||||
|
left: calc(50% - 100px);
|
||||||
|
font-size: 40px;
|
||||||
|
z-index: 99999;
|
||||||
|
}
|
||||||
|
|
||||||
|
#startButton:hover {
|
||||||
|
border: 3px solid red;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
#gameArea {
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid black;
|
||||||
|
height: 700px;
|
||||||
|
width: 1000px;
|
||||||
|
left: calc(50% - 500px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#guessesLeft, #guessedLetters {
|
||||||
|
position: relative;
|
||||||
|
width: 800px;
|
||||||
|
height: 100px;
|
||||||
|
border: 1px solid black;
|
||||||
|
left: calc(50% - 400px);
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#currentWord {
|
||||||
|
position: relative;
|
||||||
|
width: 800px;
|
||||||
|
height: 400px;
|
||||||
|
border: 1px solid black;
|
||||||
|
left: calc(50% - 400px);
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#gameWord {
|
||||||
|
font-size: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#screenMessage {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(0,0,0,0.9);
|
||||||
|
z-index: 9999;
|
||||||
|
font-size: 100px;
|
||||||
|
color: yellow;
|
||||||
|
line-height: 1000px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
require 'jasmine'
|
||||||
|
load 'jasmine/tasks/jasmine.rake'
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Document</title>
|
||||||
|
<script type="text/javascript" src="src/letter2.js"></script>
|
||||||
|
<script type="text/javascript" src="src/word2.js"></script>
|
||||||
|
<script type="text/javascript" src="src/game2.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
console.log("loaded bro");
|
||||||
|
|
||||||
|
var game = {
|
||||||
|
guesses: null,
|
||||||
|
guessedLetters: [],
|
||||||
|
words: [],
|
||||||
|
currentWord: new Word(),
|
||||||
|
startGame: function (wordsArray) {
|
||||||
|
this.guesses = 10;
|
||||||
|
this.guessedLetters = [];
|
||||||
|
for( var i = 0; i < wordsArray.length; i++ ) {
|
||||||
|
this.words.push(wordsArray[i]);
|
||||||
|
};
|
||||||
|
var randomWord = this.words[Math.floor(Math.random() * this.words.length)];
|
||||||
|
this.currentWord.getLetters(randomWord);
|
||||||
|
},
|
||||||
|
guess: function (letter) {
|
||||||
|
if ( this.guessedLetters.indexOf(letter) === -1 ) {
|
||||||
|
var found = this.currentWord.try(letter);
|
||||||
|
if (!found) {
|
||||||
|
this.guesses--;
|
||||||
|
}
|
||||||
|
this.guessedLetters.push(letter);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isOver: function () {
|
||||||
|
return (this.guesses === 0) || (this.currentWord.isFound());
|
||||||
|
},
|
||||||
|
overMessage: function () {
|
||||||
|
if ( this.guesses === 0 ) {
|
||||||
|
return "You Lose"
|
||||||
|
}
|
||||||
|
else if ( this.currentWord.isFound() ) {
|
||||||
|
return "You Win"
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
render: function () {
|
||||||
|
return [
|
||||||
|
this.currentWord.render(),
|
||||||
|
"Guesses: " + this.guesses,
|
||||||
|
this.overMessage()
|
||||||
|
].join("\n");
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
console.log("loaded bro");
|
||||||
|
|
||||||
|
var Letter = function(letter) {
|
||||||
|
this.value = letter;
|
||||||
|
this.hidden = true;
|
||||||
|
this.hide = function () {
|
||||||
|
this.hidden = true;
|
||||||
|
};
|
||||||
|
this.show = function () {
|
||||||
|
this.hidden = false;
|
||||||
|
};
|
||||||
|
this.render = function () {
|
||||||
|
return this.hidden ? ' _ ' : this.value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
console.log("loaded bro");
|
||||||
|
|
||||||
|
var Word = function () {
|
||||||
|
this.letters = [];
|
||||||
|
this.getLetters = function (newWord) {
|
||||||
|
var chars = newWord.split('');
|
||||||
|
for( var i = 0; i < chars.length; i++ ){
|
||||||
|
this.letters.push(new Letter(chars[i]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.isFound = function () {
|
||||||
|
return this.letters.every(function(currentLetter) {
|
||||||
|
return !currentLetter.hidden;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
this.try = function (letter) {
|
||||||
|
for ( var i = 0; i < this.letters.length; i++ ) {
|
||||||
|
if ( this.letters[i].value === letter ) {
|
||||||
|
this.letters[i].show();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
this.render = function () {
|
||||||
|
return this.letters.map( function(letter) {
|
||||||
|
return letter.render();
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
// ajax request to this app's /json route
|
// ajax request to this app's /json/instructors route
|
||||||
// gets data and loads it into callback
|
// gets data and loads it into callback
|
||||||
// you can do whatever you want with the data
|
// you can do whatever you want with the data
|
||||||
// inside the callback
|
// inside the callback
|
||||||
|
|
||||||
$.ajax('/json').done(function(result) {
|
$.ajax('/json/instructors').done(function(result) {
|
||||||
console.log(result);
|
console.log(result);
|
||||||
});
|
});
|
||||||
|
|||||||
464
unit_02/w06d02/homework/maps_multiple_models_solution/node_modules/body-parser/HISTORY.md
generated
vendored
464
unit_02/w06d02/homework/maps_multiple_models_solution/node_modules/body-parser/HISTORY.md
generated
vendored
@ -0,0 +1,464 @@
|
|||||||
|
1.15.2 / 2016-06-19
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: bytes@2.4.0
|
||||||
|
* deps: content-type@~1.0.2
|
||||||
|
- perf: enable strict mode
|
||||||
|
* deps: http-errors@~1.5.0
|
||||||
|
- Use `setprototypeof` module to replace `__proto__` setting
|
||||||
|
- deps: statuses@'>= 1.3.0 < 2'
|
||||||
|
- perf: enable strict mode
|
||||||
|
* deps: qs@6.2.0
|
||||||
|
* deps: raw-body@~2.1.7
|
||||||
|
- deps: bytes@2.4.0
|
||||||
|
- perf: remove double-cleanup on happy path
|
||||||
|
* deps: type-is@~1.6.13
|
||||||
|
- deps: mime-types@~2.1.11
|
||||||
|
|
||||||
|
1.15.1 / 2016-05-05
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: bytes@2.3.0
|
||||||
|
- Drop partial bytes on all parsed units
|
||||||
|
- Fix parsing byte string that looks like hex
|
||||||
|
* deps: raw-body@~2.1.6
|
||||||
|
- deps: bytes@2.3.0
|
||||||
|
* deps: type-is@~1.6.12
|
||||||
|
- deps: mime-types@~2.1.10
|
||||||
|
|
||||||
|
1.15.0 / 2016-02-10
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: http-errors@~1.4.0
|
||||||
|
- Add `HttpError` export, for `err instanceof createError.HttpError`
|
||||||
|
- deps: inherits@2.0.1
|
||||||
|
- deps: statuses@'>= 1.2.1 < 2'
|
||||||
|
* deps: qs@6.1.0
|
||||||
|
* deps: type-is@~1.6.11
|
||||||
|
- deps: mime-types@~2.1.9
|
||||||
|
|
||||||
|
1.14.2 / 2015-12-16
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: bytes@2.2.0
|
||||||
|
* deps: iconv-lite@0.4.13
|
||||||
|
* deps: qs@5.2.0
|
||||||
|
* deps: raw-body@~2.1.5
|
||||||
|
- deps: bytes@2.2.0
|
||||||
|
- deps: iconv-lite@0.4.13
|
||||||
|
* deps: type-is@~1.6.10
|
||||||
|
- deps: mime-types@~2.1.8
|
||||||
|
|
||||||
|
1.14.1 / 2015-09-27
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix issue where invalid charset results in 400 when `verify` used
|
||||||
|
* deps: iconv-lite@0.4.12
|
||||||
|
- Fix CESU-8 decoding in Node.js 4.x
|
||||||
|
* deps: raw-body@~2.1.4
|
||||||
|
- Fix masking critical errors from `iconv-lite`
|
||||||
|
- deps: iconv-lite@0.4.12
|
||||||
|
* deps: type-is@~1.6.9
|
||||||
|
- deps: mime-types@~2.1.7
|
||||||
|
|
||||||
|
1.14.0 / 2015-09-16
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Fix JSON strict parse error to match syntax errors
|
||||||
|
* Provide static `require` analysis in `urlencoded` parser
|
||||||
|
* deps: depd@~1.1.0
|
||||||
|
- Support web browser loading
|
||||||
|
* deps: qs@5.1.0
|
||||||
|
* deps: raw-body@~2.1.3
|
||||||
|
- Fix sync callback when attaching data listener causes sync read
|
||||||
|
* deps: type-is@~1.6.8
|
||||||
|
- Fix type error when given invalid type to match against
|
||||||
|
- deps: mime-types@~2.1.6
|
||||||
|
|
||||||
|
1.13.3 / 2015-07-31
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: type-is@~1.6.6
|
||||||
|
- deps: mime-types@~2.1.4
|
||||||
|
|
||||||
|
1.13.2 / 2015-07-05
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: iconv-lite@0.4.11
|
||||||
|
* deps: qs@4.0.0
|
||||||
|
- Fix dropping parameters like `hasOwnProperty`
|
||||||
|
- Fix user-visible incompatibilities from 3.1.0
|
||||||
|
- Fix various parsing edge cases
|
||||||
|
* deps: raw-body@~2.1.2
|
||||||
|
- Fix error stack traces to skip `makeError`
|
||||||
|
- deps: iconv-lite@0.4.11
|
||||||
|
* deps: type-is@~1.6.4
|
||||||
|
- deps: mime-types@~2.1.2
|
||||||
|
- perf: enable strict mode
|
||||||
|
- perf: remove argument reassignment
|
||||||
|
|
||||||
|
1.13.1 / 2015-06-16
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: qs@2.4.2
|
||||||
|
- Downgraded from 3.1.0 because of user-visible incompatibilities
|
||||||
|
|
||||||
|
1.13.0 / 2015-06-14
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Add `statusCode` property on `Error`s, in addition to `status`
|
||||||
|
* Change `type` default to `application/json` for JSON parser
|
||||||
|
* Change `type` default to `application/x-www-form-urlencoded` for urlencoded parser
|
||||||
|
* Provide static `require` analysis
|
||||||
|
* Use the `http-errors` module to generate errors
|
||||||
|
* deps: bytes@2.1.0
|
||||||
|
- Slight optimizations
|
||||||
|
* deps: iconv-lite@0.4.10
|
||||||
|
- The encoding UTF-16 without BOM now defaults to UTF-16LE when detection fails
|
||||||
|
- Leading BOM is now removed when decoding
|
||||||
|
* deps: on-finished@~2.3.0
|
||||||
|
- Add defined behavior for HTTP `CONNECT` requests
|
||||||
|
- Add defined behavior for HTTP `Upgrade` requests
|
||||||
|
- deps: ee-first@1.1.1
|
||||||
|
* deps: qs@3.1.0
|
||||||
|
- Fix dropping parameters like `hasOwnProperty`
|
||||||
|
- Fix various parsing edge cases
|
||||||
|
- Parsed object now has `null` prototype
|
||||||
|
* deps: raw-body@~2.1.1
|
||||||
|
- Use `unpipe` module for unpiping requests
|
||||||
|
- deps: iconv-lite@0.4.10
|
||||||
|
* deps: type-is@~1.6.3
|
||||||
|
- deps: mime-types@~2.1.1
|
||||||
|
- perf: reduce try block size
|
||||||
|
- perf: remove bitwise operations
|
||||||
|
* perf: enable strict mode
|
||||||
|
* perf: remove argument reassignment
|
||||||
|
* perf: remove delete call
|
||||||
|
|
||||||
|
1.12.4 / 2015-05-10
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: debug@~2.2.0
|
||||||
|
* deps: qs@2.4.2
|
||||||
|
- Fix allowing parameters like `constructor`
|
||||||
|
* deps: on-finished@~2.2.1
|
||||||
|
* deps: raw-body@~2.0.1
|
||||||
|
- Fix a false-positive when unpiping in Node.js 0.8
|
||||||
|
- deps: bytes@2.0.1
|
||||||
|
* deps: type-is@~1.6.2
|
||||||
|
- deps: mime-types@~2.0.11
|
||||||
|
|
||||||
|
1.12.3 / 2015-04-15
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Slight efficiency improvement when not debugging
|
||||||
|
* deps: depd@~1.0.1
|
||||||
|
* deps: iconv-lite@0.4.8
|
||||||
|
- Add encoding alias UNICODE-1-1-UTF-7
|
||||||
|
* deps: raw-body@1.3.4
|
||||||
|
- Fix hanging callback if request aborts during read
|
||||||
|
- deps: iconv-lite@0.4.8
|
||||||
|
|
||||||
|
1.12.2 / 2015-03-16
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: qs@2.4.1
|
||||||
|
- Fix error when parameter `hasOwnProperty` is present
|
||||||
|
|
||||||
|
1.12.1 / 2015-03-15
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: debug@~2.1.3
|
||||||
|
- Fix high intensity foreground color for bold
|
||||||
|
- deps: ms@0.7.0
|
||||||
|
* deps: type-is@~1.6.1
|
||||||
|
- deps: mime-types@~2.0.10
|
||||||
|
|
||||||
|
1.12.0 / 2015-02-13
|
||||||
|
===================
|
||||||
|
|
||||||
|
* add `debug` messages
|
||||||
|
* accept a function for the `type` option
|
||||||
|
* use `content-type` to parse `Content-Type` headers
|
||||||
|
* deps: iconv-lite@0.4.7
|
||||||
|
- Gracefully support enumerables on `Object.prototype`
|
||||||
|
* deps: raw-body@1.3.3
|
||||||
|
- deps: iconv-lite@0.4.7
|
||||||
|
* deps: type-is@~1.6.0
|
||||||
|
- fix argument reassignment
|
||||||
|
- fix false-positives in `hasBody` `Transfer-Encoding` check
|
||||||
|
- support wildcard for both type and subtype (`*/*`)
|
||||||
|
- deps: mime-types@~2.0.9
|
||||||
|
|
||||||
|
1.11.0 / 2015-01-30
|
||||||
|
===================
|
||||||
|
|
||||||
|
* make internal `extended: true` depth limit infinity
|
||||||
|
* deps: type-is@~1.5.6
|
||||||
|
- deps: mime-types@~2.0.8
|
||||||
|
|
||||||
|
1.10.2 / 2015-01-20
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: iconv-lite@0.4.6
|
||||||
|
- Fix rare aliases of single-byte encodings
|
||||||
|
* deps: raw-body@1.3.2
|
||||||
|
- deps: iconv-lite@0.4.6
|
||||||
|
|
||||||
|
1.10.1 / 2015-01-01
|
||||||
|
===================
|
||||||
|
|
||||||
|
* deps: on-finished@~2.2.0
|
||||||
|
* deps: type-is@~1.5.5
|
||||||
|
- deps: mime-types@~2.0.7
|
||||||
|
|
||||||
|
1.10.0 / 2014-12-02
|
||||||
|
===================
|
||||||
|
|
||||||
|
* make internal `extended: true` array limit dynamic
|
||||||
|
|
||||||
|
1.9.3 / 2014-11-21
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: iconv-lite@0.4.5
|
||||||
|
- Fix Windows-31J and X-SJIS encoding support
|
||||||
|
* deps: qs@2.3.3
|
||||||
|
- Fix `arrayLimit` behavior
|
||||||
|
* deps: raw-body@1.3.1
|
||||||
|
- deps: iconv-lite@0.4.5
|
||||||
|
* deps: type-is@~1.5.3
|
||||||
|
- deps: mime-types@~2.0.3
|
||||||
|
|
||||||
|
1.9.2 / 2014-10-27
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: qs@2.3.2
|
||||||
|
- Fix parsing of mixed objects and values
|
||||||
|
|
||||||
|
1.9.1 / 2014-10-22
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: on-finished@~2.1.1
|
||||||
|
- Fix handling of pipelined requests
|
||||||
|
* deps: qs@2.3.0
|
||||||
|
- Fix parsing of mixed implicit and explicit arrays
|
||||||
|
* deps: type-is@~1.5.2
|
||||||
|
- deps: mime-types@~2.0.2
|
||||||
|
|
||||||
|
1.9.0 / 2014-09-24
|
||||||
|
==================
|
||||||
|
|
||||||
|
* include the charset in "unsupported charset" error message
|
||||||
|
* include the encoding in "unsupported content encoding" error message
|
||||||
|
* deps: depd@~1.0.0
|
||||||
|
|
||||||
|
1.8.4 / 2014-09-23
|
||||||
|
==================
|
||||||
|
|
||||||
|
* fix content encoding to be case-insensitive
|
||||||
|
|
||||||
|
1.8.3 / 2014-09-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: qs@2.2.4
|
||||||
|
- Fix issue with object keys starting with numbers truncated
|
||||||
|
|
||||||
|
1.8.2 / 2014-09-15
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: depd@0.4.5
|
||||||
|
|
||||||
|
1.8.1 / 2014-09-07
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: media-typer@0.3.0
|
||||||
|
* deps: type-is@~1.5.1
|
||||||
|
|
||||||
|
1.8.0 / 2014-09-05
|
||||||
|
==================
|
||||||
|
|
||||||
|
* make empty-body-handling consistent between chunked requests
|
||||||
|
- empty `json` produces `{}`
|
||||||
|
- empty `raw` produces `new Buffer(0)`
|
||||||
|
- empty `text` produces `''`
|
||||||
|
- empty `urlencoded` produces `{}`
|
||||||
|
* deps: qs@2.2.3
|
||||||
|
- Fix issue where first empty value in array is discarded
|
||||||
|
* deps: type-is@~1.5.0
|
||||||
|
- fix `hasbody` to be true for `content-length: 0`
|
||||||
|
|
||||||
|
1.7.0 / 2014-09-01
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add `parameterLimit` option to `urlencoded` parser
|
||||||
|
* change `urlencoded` extended array limit to 100
|
||||||
|
* respond with 413 when over `parameterLimit` in `urlencoded`
|
||||||
|
|
||||||
|
1.6.7 / 2014-08-29
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: qs@2.2.2
|
||||||
|
- Remove unnecessary cloning
|
||||||
|
|
||||||
|
1.6.6 / 2014-08-27
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: qs@2.2.0
|
||||||
|
- Array parsing fix
|
||||||
|
- Performance improvements
|
||||||
|
|
||||||
|
1.6.5 / 2014-08-16
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: on-finished@2.1.0
|
||||||
|
|
||||||
|
1.6.4 / 2014-08-14
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: qs@1.2.2
|
||||||
|
|
||||||
|
1.6.3 / 2014-08-10
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: qs@1.2.1
|
||||||
|
|
||||||
|
1.6.2 / 2014-08-07
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: qs@1.2.0
|
||||||
|
- Fix parsing array of objects
|
||||||
|
|
||||||
|
1.6.1 / 2014-08-06
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: qs@1.1.0
|
||||||
|
- Accept urlencoded square brackets
|
||||||
|
- Accept empty values in implicit array notation
|
||||||
|
|
||||||
|
1.6.0 / 2014-08-05
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: qs@1.0.2
|
||||||
|
- Complete rewrite
|
||||||
|
- Limits array length to 20
|
||||||
|
- Limits object depth to 5
|
||||||
|
- Limits parameters to 1,000
|
||||||
|
|
||||||
|
1.5.2 / 2014-07-27
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: depd@0.4.4
|
||||||
|
- Work-around v8 generating empty stack traces
|
||||||
|
|
||||||
|
1.5.1 / 2014-07-26
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: depd@0.4.3
|
||||||
|
- Fix exception when global `Error.stackTraceLimit` is too low
|
||||||
|
|
||||||
|
1.5.0 / 2014-07-20
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: depd@0.4.2
|
||||||
|
- Add `TRACE_DEPRECATION` environment variable
|
||||||
|
- Remove non-standard grey color from color output
|
||||||
|
- Support `--no-deprecation` argument
|
||||||
|
- Support `--trace-deprecation` argument
|
||||||
|
* deps: iconv-lite@0.4.4
|
||||||
|
- Added encoding UTF-7
|
||||||
|
* deps: raw-body@1.3.0
|
||||||
|
- deps: iconv-lite@0.4.4
|
||||||
|
- Added encoding UTF-7
|
||||||
|
- Fix `Cannot switch to old mode now` error on Node.js 0.10+
|
||||||
|
* deps: type-is@~1.3.2
|
||||||
|
|
||||||
|
1.4.3 / 2014-06-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: type-is@1.3.1
|
||||||
|
- fix global variable leak
|
||||||
|
|
||||||
|
1.4.2 / 2014-06-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: type-is@1.3.0
|
||||||
|
- improve type parsing
|
||||||
|
|
||||||
|
1.4.1 / 2014-06-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* fix urlencoded extended deprecation message
|
||||||
|
|
||||||
|
1.4.0 / 2014-06-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add `text` parser
|
||||||
|
* add `raw` parser
|
||||||
|
* check accepted charset in content-type (accepts utf-8)
|
||||||
|
* check accepted encoding in content-encoding (accepts identity)
|
||||||
|
* deprecate `bodyParser()` middleware; use `.json()` and `.urlencoded()` as needed
|
||||||
|
* deprecate `urlencoded()` without provided `extended` option
|
||||||
|
* lazy-load urlencoded parsers
|
||||||
|
* parsers split into files for reduced mem usage
|
||||||
|
* support gzip and deflate bodies
|
||||||
|
- set `inflate: false` to turn off
|
||||||
|
* deps: raw-body@1.2.2
|
||||||
|
- Support all encodings from `iconv-lite`
|
||||||
|
|
||||||
|
1.3.1 / 2014-06-11
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: type-is@1.2.1
|
||||||
|
- Switch dependency from mime to mime-types@1.0.0
|
||||||
|
|
||||||
|
1.3.0 / 2014-05-31
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add `extended` option to urlencoded parser
|
||||||
|
|
||||||
|
1.2.2 / 2014-05-27
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: raw-body@1.1.6
|
||||||
|
- assert stream encoding on node.js 0.8
|
||||||
|
- assert stream encoding on node.js < 0.10.6
|
||||||
|
- deps: bytes@1
|
||||||
|
|
||||||
|
1.2.1 / 2014-05-26
|
||||||
|
==================
|
||||||
|
|
||||||
|
* invoke `next(err)` after request fully read
|
||||||
|
- prevents hung responses and socket hang ups
|
||||||
|
|
||||||
|
1.2.0 / 2014-05-11
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add `verify` option
|
||||||
|
* deps: type-is@1.2.0
|
||||||
|
- support suffix matching
|
||||||
|
|
||||||
|
1.1.2 / 2014-05-11
|
||||||
|
==================
|
||||||
|
|
||||||
|
* improve json parser speed
|
||||||
|
|
||||||
|
1.1.1 / 2014-05-11
|
||||||
|
==================
|
||||||
|
|
||||||
|
* fix repeated limit parsing with every request
|
||||||
|
|
||||||
|
1.1.0 / 2014-05-10
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add `type` option
|
||||||
|
* deps: pin for safety and consistency
|
||||||
|
|
||||||
|
1.0.2 / 2014-04-14
|
||||||
|
==================
|
||||||
|
|
||||||
|
* use `type-is` module
|
||||||
|
|
||||||
|
1.0.1 / 2014-03-20
|
||||||
|
==================
|
||||||
|
|
||||||
|
* lower default limits to 100kb
|
||||||
23
unit_02/w06d02/homework/maps_multiple_models_solution/node_modules/body-parser/LICENSE
generated
vendored
23
unit_02/w06d02/homework/maps_multiple_models_solution/node_modules/body-parser/LICENSE
generated
vendored
@ -0,0 +1,23 @@
|
|||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
|
||||||
|
Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
'Software'), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
409
unit_02/w06d02/homework/maps_multiple_models_solution/node_modules/body-parser/README.md
generated
vendored
409
unit_02/w06d02/homework/maps_multiple_models_solution/node_modules/body-parser/README.md
generated
vendored
@ -0,0 +1,409 @@
|
|||||||
|
# body-parser
|
||||||
|
|
||||||
|
[![NPM Version][npm-image]][npm-url]
|
||||||
|
[![NPM Downloads][downloads-image]][downloads-url]
|
||||||
|
[![Build Status][travis-image]][travis-url]
|
||||||
|
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||||
|
[![Gratipay][gratipay-image]][gratipay-url]
|
||||||
|
|
||||||
|
Node.js body parsing middleware.
|
||||||
|
|
||||||
|
Parse incoming request bodies in a middleware before your handlers, availabe
|
||||||
|
under the `req.body` property.
|
||||||
|
|
||||||
|
[Learn about the anatomy of an HTTP transaction in Node.js](https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/).
|
||||||
|
|
||||||
|
_This does not handle multipart bodies_, due to their complex and typically
|
||||||
|
large nature. For multipart bodies, you may be interested in the following
|
||||||
|
modules:
|
||||||
|
|
||||||
|
* [busboy](https://www.npmjs.org/package/busboy#readme) and
|
||||||
|
[connect-busboy](https://www.npmjs.org/package/connect-busboy#readme)
|
||||||
|
* [multiparty](https://www.npmjs.org/package/multiparty#readme) and
|
||||||
|
[connect-multiparty](https://www.npmjs.org/package/connect-multiparty#readme)
|
||||||
|
* [formidable](https://www.npmjs.org/package/formidable#readme)
|
||||||
|
* [multer](https://www.npmjs.org/package/multer#readme)
|
||||||
|
|
||||||
|
This module provides the following parsers:
|
||||||
|
|
||||||
|
* [JSON body parser](#bodyparserjsonoptions)
|
||||||
|
* [Raw body parser](#bodyparserrawoptions)
|
||||||
|
* [Text body parser](#bodyparsertextoptions)
|
||||||
|
* [URL-encoded form body parser](#bodyparserurlencodedoptions)
|
||||||
|
|
||||||
|
Other body parsers you might be interested in:
|
||||||
|
|
||||||
|
- [body](https://www.npmjs.org/package/body#readme)
|
||||||
|
- [co-body](https://www.npmjs.org/package/co-body#readme)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install body-parser
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
```js
|
||||||
|
var bodyParser = require('body-parser')
|
||||||
|
```
|
||||||
|
|
||||||
|
The `bodyParser` object exposes various factories to create middlewares. All
|
||||||
|
middlewares will populate the `req.body` property with the parsed body, or an
|
||||||
|
empty object (`{}`) if there was no body to parse (or an error was returned).
|
||||||
|
|
||||||
|
The various errors returned by this module are described in the
|
||||||
|
[errors section](#errors).
|
||||||
|
|
||||||
|
### bodyParser.json(options)
|
||||||
|
|
||||||
|
Returns middleware that only parses `json`. This parser accepts any Unicode
|
||||||
|
encoding of the body and supports automatic inflation of `gzip` and `deflate`
|
||||||
|
encodings.
|
||||||
|
|
||||||
|
A new `body` object containing the parsed data is populated on the `request`
|
||||||
|
object after the middleware (i.e. `req.body`).
|
||||||
|
|
||||||
|
#### Options
|
||||||
|
|
||||||
|
The `json` function takes an option `options` object that may contain any of
|
||||||
|
the following keys:
|
||||||
|
|
||||||
|
##### inflate
|
||||||
|
|
||||||
|
When set to `true`, then deflated (compressed) bodies will be inflated; when
|
||||||
|
`false`, deflated bodies are rejected. Defaults to `true`.
|
||||||
|
|
||||||
|
##### limit
|
||||||
|
|
||||||
|
Controls the maximum request body size. If this is a number, then the value
|
||||||
|
specifies the number of bytes; if it is a string, the value is passed to the
|
||||||
|
[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults
|
||||||
|
to `'100kb'`.
|
||||||
|
|
||||||
|
##### reviver
|
||||||
|
|
||||||
|
The `reviver` option is passed directly to `JSON.parse` as the second
|
||||||
|
argument. You can find more information on this argument
|
||||||
|
[in the MDN documentation about JSON.parse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Example.3A_Using_the_reviver_parameter).
|
||||||
|
|
||||||
|
##### strict
|
||||||
|
|
||||||
|
When set to `true`, will only accept arrays and objects; when `false` will
|
||||||
|
accept anything `JSON.parse` accepts. Defaults to `true`.
|
||||||
|
|
||||||
|
##### type
|
||||||
|
|
||||||
|
The `type` option is used to determine what media type the middleware will
|
||||||
|
parse. This option can be a function or a string. If a string, `type` option
|
||||||
|
is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)
|
||||||
|
library and this can be an extension name (like `json`), a mime type (like
|
||||||
|
`application/json`), or a mime type with a wildcard (like `*/*` or `*/json`).
|
||||||
|
If a function, the `type` option is called as `fn(req)` and the request is
|
||||||
|
parsed if it returns a truthy value. Defaults to `application/json`.
|
||||||
|
|
||||||
|
##### verify
|
||||||
|
|
||||||
|
The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,
|
||||||
|
where `buf` is a `Buffer` of the raw request body and `encoding` is the
|
||||||
|
encoding of the request. The parsing can be aborted by throwing an error.
|
||||||
|
|
||||||
|
### bodyParser.raw(options)
|
||||||
|
|
||||||
|
Returns middleware that parses all bodies as a `Buffer`. This parser
|
||||||
|
supports automatic inflation of `gzip` and `deflate` encodings.
|
||||||
|
|
||||||
|
A new `body` object containing the parsed data is populated on the `request`
|
||||||
|
object after the middleware (i.e. `req.body`). This will be a `Buffer` object
|
||||||
|
of the body.
|
||||||
|
|
||||||
|
#### Options
|
||||||
|
|
||||||
|
The `raw` function takes an option `options` object that may contain any of
|
||||||
|
the following keys:
|
||||||
|
|
||||||
|
##### inflate
|
||||||
|
|
||||||
|
When set to `true`, then deflated (compressed) bodies will be inflated; when
|
||||||
|
`false`, deflated bodies are rejected. Defaults to `true`.
|
||||||
|
|
||||||
|
##### limit
|
||||||
|
|
||||||
|
Controls the maximum request body size. If this is a number, then the value
|
||||||
|
specifies the number of bytes; if it is a string, the value is passed to the
|
||||||
|
[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults
|
||||||
|
to `'100kb'`.
|
||||||
|
|
||||||
|
##### type
|
||||||
|
|
||||||
|
The `type` option is used to determine what media type the middleware will
|
||||||
|
parse. This option can be a function or a string. If a string, `type` option
|
||||||
|
is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)
|
||||||
|
library and this can be an extension name (like `bin`), a mime type (like
|
||||||
|
`application/octet-stream`), or a mime type with a wildcard (like `*/*` or
|
||||||
|
`application/*`). If a function, the `type` option is called as `fn(req)`
|
||||||
|
and the request is parsed if it returns a truthy value. Defaults to
|
||||||
|
`application/octet-stream`.
|
||||||
|
|
||||||
|
##### verify
|
||||||
|
|
||||||
|
The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,
|
||||||
|
where `buf` is a `Buffer` of the raw request body and `encoding` is the
|
||||||
|
encoding of the request. The parsing can be aborted by throwing an error.
|
||||||
|
|
||||||
|
### bodyParser.text(options)
|
||||||
|
|
||||||
|
Returns middleware that parses all bodies as a string. This parser supports
|
||||||
|
automatic inflation of `gzip` and `deflate` encodings.
|
||||||
|
|
||||||
|
A new `body` string containing the parsed data is populated on the `request`
|
||||||
|
object after the middleware (i.e. `req.body`). This will be a string of the
|
||||||
|
body.
|
||||||
|
|
||||||
|
#### Options
|
||||||
|
|
||||||
|
The `text` function takes an option `options` object that may contain any of
|
||||||
|
the following keys:
|
||||||
|
|
||||||
|
##### defaultCharset
|
||||||
|
|
||||||
|
Specify the default character set for the text content if the charset is not
|
||||||
|
specified in the `Content-Type` header of the request. Defaults to `utf-8`.
|
||||||
|
|
||||||
|
##### inflate
|
||||||
|
|
||||||
|
When set to `true`, then deflated (compressed) bodies will be inflated; when
|
||||||
|
`false`, deflated bodies are rejected. Defaults to `true`.
|
||||||
|
|
||||||
|
##### limit
|
||||||
|
|
||||||
|
Controls the maximum request body size. If this is a number, then the value
|
||||||
|
specifies the number of bytes; if it is a string, the value is passed to the
|
||||||
|
[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults
|
||||||
|
to `'100kb'`.
|
||||||
|
|
||||||
|
##### type
|
||||||
|
|
||||||
|
The `type` option is used to determine what media type the middleware will
|
||||||
|
parse. This option can be a function or a string. If a string, `type` option
|
||||||
|
is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)
|
||||||
|
library and this can be an extension name (like `txt`), a mime type (like
|
||||||
|
`text/plain`), or a mime type with a wildcard (like `*/*` or `text/*`).
|
||||||
|
If a function, the `type` option is called as `fn(req)` and the request is
|
||||||
|
parsed if it returns a truthy value. Defaults to `text/plain`.
|
||||||
|
|
||||||
|
##### verify
|
||||||
|
|
||||||
|
The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,
|
||||||
|
where `buf` is a `Buffer` of the raw request body and `encoding` is the
|
||||||
|
encoding of the request. The parsing can be aborted by throwing an error.
|
||||||
|
|
||||||
|
### bodyParser.urlencoded(options)
|
||||||
|
|
||||||
|
Returns middleware that only parses `urlencoded` bodies. This parser accepts
|
||||||
|
only UTF-8 encoding of the body and supports automatic inflation of `gzip`
|
||||||
|
and `deflate` encodings.
|
||||||
|
|
||||||
|
A new `body` object containing the parsed data is populated on the `request`
|
||||||
|
object after the middleware (i.e. `req.body`). This object will contain
|
||||||
|
key-value pairs, where the value can be a string or array (when `extended` is
|
||||||
|
`false`), or any type (when `extended` is `true`).
|
||||||
|
|
||||||
|
#### Options
|
||||||
|
|
||||||
|
The `urlencoded` function takes an option `options` object that may contain
|
||||||
|
any of the following keys:
|
||||||
|
|
||||||
|
##### extended
|
||||||
|
|
||||||
|
The `extended` option allows to choose between parsing the URL-encoded data
|
||||||
|
with the `querystring` library (when `false`) or the `qs` library (when
|
||||||
|
`true`). The "extended" syntax allows for rich objects and arrays to be
|
||||||
|
encoded into the URL-encoded format, allowing for a JSON-like experience
|
||||||
|
with URL-encoded. For more information, please
|
||||||
|
[see the qs library](https://www.npmjs.org/package/qs#readme).
|
||||||
|
|
||||||
|
Defaults to `true`, but using the default has been deprecated. Please
|
||||||
|
research into the difference between `qs` and `querystring` and choose the
|
||||||
|
appropriate setting.
|
||||||
|
|
||||||
|
##### inflate
|
||||||
|
|
||||||
|
When set to `true`, then deflated (compressed) bodies will be inflated; when
|
||||||
|
`false`, deflated bodies are rejected. Defaults to `true`.
|
||||||
|
|
||||||
|
##### limit
|
||||||
|
|
||||||
|
Controls the maximum request body size. If this is a number, then the value
|
||||||
|
specifies the number of bytes; if it is a string, the value is passed to the
|
||||||
|
[bytes](https://www.npmjs.com/package/bytes) library for parsing. Defaults
|
||||||
|
to `'100kb'`.
|
||||||
|
|
||||||
|
##### parameterLimit
|
||||||
|
|
||||||
|
The `parameterLimit` option controls the maximum number of parameters that
|
||||||
|
are allowed in the URL-encoded data. If a request contains more parameters
|
||||||
|
than this value, a 413 will be returned to the client. Defaults to `1000`.
|
||||||
|
|
||||||
|
##### type
|
||||||
|
|
||||||
|
The `type` option is used to determine what media type the middleware will
|
||||||
|
parse. This option can be a function or a string. If a string, `type` option
|
||||||
|
is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme)
|
||||||
|
library and this can be an extension name (like `urlencoded`), a mime type (like
|
||||||
|
`application/x-www-form-urlencoded`), or a mime type with a wildcard (like
|
||||||
|
`*/x-www-form-urlencoded`). If a function, the `type` option is called as
|
||||||
|
`fn(req)` and the request is parsed if it returns a truthy value. Defaults
|
||||||
|
to `application/x-www-form-urlencoded`.
|
||||||
|
|
||||||
|
##### verify
|
||||||
|
|
||||||
|
The `verify` option, if supplied, is called as `verify(req, res, buf, encoding)`,
|
||||||
|
where `buf` is a `Buffer` of the raw request body and `encoding` is the
|
||||||
|
encoding of the request. The parsing can be aborted by throwing an error.
|
||||||
|
|
||||||
|
## Errors
|
||||||
|
|
||||||
|
The middlewares provided by this module create errors depending on the error
|
||||||
|
condition during parsing. The errors will typically have a `status` property
|
||||||
|
that contains the suggested HTTP response code and a `body` property containing
|
||||||
|
the read body, if available.
|
||||||
|
|
||||||
|
The following are the common errors emitted, though any error can come through
|
||||||
|
for various reasons.
|
||||||
|
|
||||||
|
### content encoding unsupported
|
||||||
|
|
||||||
|
This error will occur when the request had a `Content-Encoding` header that
|
||||||
|
contained an encoding but the "inflation" option was set to `false`. The
|
||||||
|
`status` property is set to `415`.
|
||||||
|
|
||||||
|
### request aborted
|
||||||
|
|
||||||
|
This error will occur when the request is aborted by the client before reading
|
||||||
|
the body has finished. The `received` property will be set to the number of
|
||||||
|
bytes received before the request was aborted and the `expected` property is
|
||||||
|
set to the number of expected bytes. The `status` property is set to `400`.
|
||||||
|
|
||||||
|
### request entity too large
|
||||||
|
|
||||||
|
This error will occur when the request body's size is larger than the "limit"
|
||||||
|
option. The `limit` property will be set to the byte limit and the `length`
|
||||||
|
property will be set to the request body's length. The `status` property is
|
||||||
|
set to `413`.
|
||||||
|
|
||||||
|
### request size did not match content length
|
||||||
|
|
||||||
|
This error will occur when the request's length did not match the length from
|
||||||
|
the `Content-Length` header. This typically occurs when the request is malformed,
|
||||||
|
typically when the `Content-Length` header was calculated based on characters
|
||||||
|
instead of bytes. The `status` property is set to `400`.
|
||||||
|
|
||||||
|
### stream encoding should not be set
|
||||||
|
|
||||||
|
This error will occur when something called the `req.setEncoding` method prior
|
||||||
|
to this middleware. This module operates directly on bytes only and you cannot
|
||||||
|
call `req.setEncoding` when using this module. The `status` property is set to
|
||||||
|
`500`.
|
||||||
|
|
||||||
|
### unsupported charset "BOGUS"
|
||||||
|
|
||||||
|
This error will occur when the request had a charset parameter in the
|
||||||
|
`Content-Type` header, but the `iconv-lite` module does not support it OR the
|
||||||
|
parser does not support it. The charset is contained in the message as well
|
||||||
|
as in the `charset` property. The `status` property is set to `415`.
|
||||||
|
|
||||||
|
### unsupported content encoding "bogus"
|
||||||
|
|
||||||
|
This error will occur when the request had a `Content-Encoding` header that
|
||||||
|
contained an unsupported encoding. The encoding is contained in the message
|
||||||
|
as well as in the `encoding` property. The `status` property is set to `415`.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Express/Connect top-level generic
|
||||||
|
|
||||||
|
This example demonstrates adding a generic JSON and URL-encoded parser as a
|
||||||
|
top-level middleware, which will parse the bodies of all incoming requests.
|
||||||
|
This is the simplest setup.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var express = require('express')
|
||||||
|
var bodyParser = require('body-parser')
|
||||||
|
|
||||||
|
var app = express()
|
||||||
|
|
||||||
|
// parse application/x-www-form-urlencoded
|
||||||
|
app.use(bodyParser.urlencoded({ extended: false }))
|
||||||
|
|
||||||
|
// parse application/json
|
||||||
|
app.use(bodyParser.json())
|
||||||
|
|
||||||
|
app.use(function (req, res) {
|
||||||
|
res.setHeader('Content-Type', 'text/plain')
|
||||||
|
res.write('you posted:\n')
|
||||||
|
res.end(JSON.stringify(req.body, null, 2))
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Express route-specific
|
||||||
|
|
||||||
|
This example demonstrates adding body parsers specifically to the routes that
|
||||||
|
need them. In general, this is the most recommended way to use body-parser with
|
||||||
|
Express.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var express = require('express')
|
||||||
|
var bodyParser = require('body-parser')
|
||||||
|
|
||||||
|
var app = express()
|
||||||
|
|
||||||
|
// create application/json parser
|
||||||
|
var jsonParser = bodyParser.json()
|
||||||
|
|
||||||
|
// create application/x-www-form-urlencoded parser
|
||||||
|
var urlencodedParser = bodyParser.urlencoded({ extended: false })
|
||||||
|
|
||||||
|
// POST /login gets urlencoded bodies
|
||||||
|
app.post('/login', urlencodedParser, function (req, res) {
|
||||||
|
if (!req.body) return res.sendStatus(400)
|
||||||
|
res.send('welcome, ' + req.body.username)
|
||||||
|
})
|
||||||
|
|
||||||
|
// POST /api/users gets JSON bodies
|
||||||
|
app.post('/api/users', jsonParser, function (req, res) {
|
||||||
|
if (!req.body) return res.sendStatus(400)
|
||||||
|
// create user in req.body
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Change accepted type for parsers
|
||||||
|
|
||||||
|
All the parsers accept a `type` option which allows you to change the
|
||||||
|
`Content-Type` that the middleware will parse.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// parse various different custom JSON types as JSON
|
||||||
|
app.use(bodyParser.json({ type: 'application/*+json' }))
|
||||||
|
|
||||||
|
// parse some custom thing into a Buffer
|
||||||
|
app.use(bodyParser.raw({ type: 'application/vnd.custom-type' }))
|
||||||
|
|
||||||
|
// parse an HTML body into a string
|
||||||
|
app.use(bodyParser.text({ type: 'text/html' }))
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
||||||
|
|
||||||
|
[npm-image]: https://img.shields.io/npm/v/body-parser.svg
|
||||||
|
[npm-url]: https://npmjs.org/package/body-parser
|
||||||
|
[travis-image]: https://img.shields.io/travis/expressjs/body-parser/master.svg
|
||||||
|
[travis-url]: https://travis-ci.org/expressjs/body-parser
|
||||||
|
[coveralls-image]: https://img.shields.io/coveralls/expressjs/body-parser/master.svg
|
||||||
|
[coveralls-url]: https://coveralls.io/r/expressjs/body-parser?branch=master
|
||||||
|
[downloads-image]: https://img.shields.io/npm/dm/body-parser.svg
|
||||||
|
[downloads-url]: https://npmjs.org/package/body-parser
|
||||||
|
[gratipay-image]: https://img.shields.io/gratipay/dougwilson.svg
|
||||||
|
[gratipay-url]: https://www.gratipay.com/dougwilson/
|
||||||
157
unit_02/w06d02/homework/maps_multiple_models_solution/node_modules/body-parser/index.js
generated
vendored
157
unit_02/w06d02/homework/maps_multiple_models_solution/node_modules/body-parser/index.js
generated
vendored
@ -0,0 +1,157 @@
|
|||||||
|
/*!
|
||||||
|
* body-parser
|
||||||
|
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var deprecate = require('depd')('body-parser')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache of loaded parsers.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var parsers = Object.create(null)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef Parsers
|
||||||
|
* @type {function}
|
||||||
|
* @property {function} json
|
||||||
|
* @property {function} raw
|
||||||
|
* @property {function} text
|
||||||
|
* @property {function} urlencoded
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
* @type {Parsers}
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = module.exports = deprecate.function(bodyParser,
|
||||||
|
'bodyParser: use individual json/urlencoded middlewares')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON parser.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Object.defineProperty(exports, 'json', {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true,
|
||||||
|
get: createParserGetter('json')
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raw parser.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Object.defineProperty(exports, 'raw', {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true,
|
||||||
|
get: createParserGetter('raw')
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text parser.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Object.defineProperty(exports, 'text', {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true,
|
||||||
|
get: createParserGetter('text')
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL-encoded parser.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Object.defineProperty(exports, 'urlencoded', {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true,
|
||||||
|
get: createParserGetter('urlencoded')
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a middleware to parse json and urlencoded bodies.
|
||||||
|
*
|
||||||
|
* @param {object} [options]
|
||||||
|
* @return {function}
|
||||||
|
* @deprecated
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function bodyParser (options) {
|
||||||
|
var opts = {}
|
||||||
|
|
||||||
|
// exclude type option
|
||||||
|
if (options) {
|
||||||
|
for (var prop in options) {
|
||||||
|
if (prop !== 'type') {
|
||||||
|
opts[prop] = options[prop]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _urlencoded = exports.urlencoded(opts)
|
||||||
|
var _json = exports.json(opts)
|
||||||
|
|
||||||
|
return function bodyParser (req, res, next) {
|
||||||
|
_json(req, res, function (err) {
|
||||||
|
if (err) return next(err)
|
||||||
|
_urlencoded(req, res, next)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a getter for loading a parser.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function createParserGetter (name) {
|
||||||
|
return function get () {
|
||||||
|
return loadParser(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a parser module.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function loadParser (parserName) {
|
||||||
|
var parser = parsers[parserName]
|
||||||
|
|
||||||
|
if (parser !== undefined) {
|
||||||
|
return parser
|
||||||
|
}
|
||||||
|
|
||||||
|
// this uses a switch for static require analysis
|
||||||
|
switch (parserName) {
|
||||||
|
case 'json':
|
||||||
|
parser = require('./lib/types/json')
|
||||||
|
break
|
||||||
|
case 'raw':
|
||||||
|
parser = require('./lib/types/raw')
|
||||||
|
break
|
||||||
|
case 'text':
|
||||||
|
parser = require('./lib/types/text')
|
||||||
|
break
|
||||||
|
case 'urlencoded':
|
||||||
|
parser = require('./lib/types/urlencoded')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// store to prevent invoking require()
|
||||||
|
return (parsers[parserName] = parser)
|
||||||
|
}
|
||||||
188
unit_02/w06d02/homework/maps_multiple_models_solution/node_modules/body-parser/lib/read.js
generated
vendored
188
unit_02/w06d02/homework/maps_multiple_models_solution/node_modules/body-parser/lib/read.js
generated
vendored
@ -0,0 +1,188 @@
|
|||||||
|
/*!
|
||||||
|
* body-parser
|
||||||
|
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var createError = require('http-errors')
|
||||||
|
var getBody = require('raw-body')
|
||||||
|
var iconv = require('iconv-lite')
|
||||||
|
var onFinished = require('on-finished')
|
||||||
|
var zlib = require('zlib')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = read
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a request into a buffer and parse.
|
||||||
|
*
|
||||||
|
* @param {object} req
|
||||||
|
* @param {object} res
|
||||||
|
* @param {function} next
|
||||||
|
* @param {function} parse
|
||||||
|
* @param {function} debug
|
||||||
|
* @param {object} [options]
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function read (req, res, next, parse, debug, options) {
|
||||||
|
var length
|
||||||
|
var opts = options || {}
|
||||||
|
var stream
|
||||||
|
|
||||||
|
// flag as parsed
|
||||||
|
req._body = true
|
||||||
|
|
||||||
|
// read options
|
||||||
|
var encoding = opts.encoding !== null
|
||||||
|
? opts.encoding || 'utf-8'
|
||||||
|
: null
|
||||||
|
var verify = opts.verify
|
||||||
|
|
||||||
|
try {
|
||||||
|
// get the content stream
|
||||||
|
stream = contentstream(req, debug, opts.inflate)
|
||||||
|
length = stream.length
|
||||||
|
stream.length = undefined
|
||||||
|
} catch (err) {
|
||||||
|
return next(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// set raw-body options
|
||||||
|
opts.length = length
|
||||||
|
opts.encoding = verify
|
||||||
|
? null
|
||||||
|
: encoding
|
||||||
|
|
||||||
|
// assert charset is supported
|
||||||
|
if (opts.encoding === null && encoding !== null && !iconv.encodingExists(encoding)) {
|
||||||
|
return next(createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', {
|
||||||
|
charset: encoding.toLowerCase()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// read body
|
||||||
|
debug('read body')
|
||||||
|
getBody(stream, opts, function (err, body) {
|
||||||
|
if (err) {
|
||||||
|
// default to 400
|
||||||
|
setErrorStatus(err, 400)
|
||||||
|
|
||||||
|
// echo back charset
|
||||||
|
if (err.type === 'encoding.unsupported') {
|
||||||
|
err = createError(415, 'unsupported charset "' + encoding.toUpperCase() + '"', {
|
||||||
|
charset: encoding.toLowerCase()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// read off entire request
|
||||||
|
stream.resume()
|
||||||
|
onFinished(req, function onfinished () {
|
||||||
|
next(err)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify
|
||||||
|
if (verify) {
|
||||||
|
try {
|
||||||
|
debug('verify body')
|
||||||
|
verify(req, res, body, encoding)
|
||||||
|
} catch (err) {
|
||||||
|
// default to 403
|
||||||
|
setErrorStatus(err, 403)
|
||||||
|
next(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse
|
||||||
|
var str
|
||||||
|
try {
|
||||||
|
debug('parse body')
|
||||||
|
str = typeof body !== 'string' && encoding !== null
|
||||||
|
? iconv.decode(body, encoding)
|
||||||
|
: body
|
||||||
|
req.body = parse(str)
|
||||||
|
} catch (err) {
|
||||||
|
err.body = str === undefined
|
||||||
|
? body
|
||||||
|
: str
|
||||||
|
|
||||||
|
// default to 400
|
||||||
|
setErrorStatus(err, 400)
|
||||||
|
|
||||||
|
next(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the content stream of the request.
|
||||||
|
*
|
||||||
|
* @param {object} req
|
||||||
|
* @param {function} debug
|
||||||
|
* @param {boolean} [inflate=true]
|
||||||
|
* @return {object}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function contentstream (req, debug, inflate) {
|
||||||
|
var encoding = (req.headers['content-encoding'] || 'identity').toLowerCase()
|
||||||
|
var length = req.headers['content-length']
|
||||||
|
var stream
|
||||||
|
|
||||||
|
debug('content-encoding "%s"', encoding)
|
||||||
|
|
||||||
|
if (inflate === false && encoding !== 'identity') {
|
||||||
|
throw createError(415, 'content encoding unsupported')
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (encoding) {
|
||||||
|
case 'deflate':
|
||||||
|
stream = zlib.createInflate()
|
||||||
|
debug('inflate body')
|
||||||
|
req.pipe(stream)
|
||||||
|
break
|
||||||
|
case 'gzip':
|
||||||
|
stream = zlib.createGunzip()
|
||||||
|
debug('gunzip body')
|
||||||
|
req.pipe(stream)
|
||||||
|
break
|
||||||
|
case 'identity':
|
||||||
|
stream = req
|
||||||
|
stream.length = length
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw createError(415, 'unsupported content encoding "' + encoding + '"', {
|
||||||
|
encoding: encoding
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a status on an error object, if ones does not exist
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function setErrorStatus (error, status) {
|
||||||
|
if (!error.status && !error.statusCode) {
|
||||||
|
error.status = status
|
||||||
|
error.statusCode = status
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,175 @@
|
|||||||
|
/*!
|
||||||
|
* body-parser
|
||||||
|
* Copyright(c) 2014 Jonathan Ong
|
||||||
|
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var bytes = require('bytes')
|
||||||
|
var contentType = require('content-type')
|
||||||
|
var createError = require('http-errors')
|
||||||
|
var debug = require('debug')('body-parser:json')
|
||||||
|
var read = require('../read')
|
||||||
|
var typeis = require('type-is')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = json
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RegExp to match the first non-space in a string.
|
||||||
|
*
|
||||||
|
* Allowed whitespace is defined in RFC 7159:
|
||||||
|
*
|
||||||
|
* ws = *(
|
||||||
|
* %x20 / ; Space
|
||||||
|
* %x09 / ; Horizontal tab
|
||||||
|
* %x0A / ; Line feed or New line
|
||||||
|
* %x0D ) ; Carriage return
|
||||||
|
*/
|
||||||
|
|
||||||
|
var FIRST_CHAR_REGEXP = /^[\x20\x09\x0a\x0d]*(.)/ // eslint-disable-line no-control-regex
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a middleware to parse JSON bodies.
|
||||||
|
*
|
||||||
|
* @param {object} [options]
|
||||||
|
* @return {function}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function json (options) {
|
||||||
|
var opts = options || {}
|
||||||
|
|
||||||
|
var limit = typeof opts.limit !== 'number'
|
||||||
|
? bytes.parse(opts.limit || '100kb')
|
||||||
|
: opts.limit
|
||||||
|
var inflate = opts.inflate !== false
|
||||||
|
var reviver = opts.reviver
|
||||||
|
var strict = opts.strict !== false
|
||||||
|
var type = opts.type || 'application/json'
|
||||||
|
var verify = opts.verify || false
|
||||||
|
|
||||||
|
if (verify !== false && typeof verify !== 'function') {
|
||||||
|
throw new TypeError('option verify must be function')
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the appropriate type checking function
|
||||||
|
var shouldParse = typeof type !== 'function'
|
||||||
|
? typeChecker(type)
|
||||||
|
: type
|
||||||
|
|
||||||
|
function parse (body) {
|
||||||
|
if (body.length === 0) {
|
||||||
|
// special-case empty json body, as it's a common client-side mistake
|
||||||
|
// TODO: maybe make this configurable or part of "strict" option
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strict) {
|
||||||
|
var first = firstchar(body)
|
||||||
|
|
||||||
|
if (first !== '{' && first !== '[') {
|
||||||
|
debug('strict violation')
|
||||||
|
throw new SyntaxError('Unexpected token ' + first)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug('parse json')
|
||||||
|
return JSON.parse(body, reviver)
|
||||||
|
}
|
||||||
|
|
||||||
|
return function jsonParser (req, res, next) {
|
||||||
|
if (req._body) {
|
||||||
|
debug('body already parsed')
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.body = req.body || {}
|
||||||
|
|
||||||
|
// skip requests without bodies
|
||||||
|
if (!typeis.hasBody(req)) {
|
||||||
|
debug('skip empty body')
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
debug('content-type %j', req.headers['content-type'])
|
||||||
|
|
||||||
|
// determine if request should be parsed
|
||||||
|
if (!shouldParse(req)) {
|
||||||
|
debug('skip parsing')
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert charset per RFC 7159 sec 8.1
|
||||||
|
var charset = getCharset(req) || 'utf-8'
|
||||||
|
if (charset.substr(0, 4) !== 'utf-') {
|
||||||
|
debug('invalid charset')
|
||||||
|
next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', {
|
||||||
|
charset: charset
|
||||||
|
}))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// read
|
||||||
|
read(req, res, next, parse, debug, {
|
||||||
|
encoding: charset,
|
||||||
|
inflate: inflate,
|
||||||
|
limit: limit,
|
||||||
|
verify: verify
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the first non-whitespace character in a string.
|
||||||
|
*
|
||||||
|
* @param {string} str
|
||||||
|
* @return {function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function firstchar (str) {
|
||||||
|
var match = FIRST_CHAR_REGEXP.exec(str)
|
||||||
|
return match ? match[1] : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the charset of a request.
|
||||||
|
*
|
||||||
|
* @param {object} req
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getCharset (req) {
|
||||||
|
try {
|
||||||
|
return contentType.parse(req).parameters.charset.toLowerCase()
|
||||||
|
} catch (e) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the simple type checker.
|
||||||
|
*
|
||||||
|
* @param {string} type
|
||||||
|
* @return {function}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function typeChecker (type) {
|
||||||
|
return function checkType (req) {
|
||||||
|
return Boolean(typeis(req, type))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,101 @@
|
|||||||
|
/*!
|
||||||
|
* body-parser
|
||||||
|
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var bytes = require('bytes')
|
||||||
|
var debug = require('debug')('body-parser:raw')
|
||||||
|
var read = require('../read')
|
||||||
|
var typeis = require('type-is')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = raw
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a middleware to parse raw bodies.
|
||||||
|
*
|
||||||
|
* @param {object} [options]
|
||||||
|
* @return {function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function raw (options) {
|
||||||
|
var opts = options || {}
|
||||||
|
|
||||||
|
var inflate = opts.inflate !== false
|
||||||
|
var limit = typeof opts.limit !== 'number'
|
||||||
|
? bytes.parse(opts.limit || '100kb')
|
||||||
|
: opts.limit
|
||||||
|
var type = opts.type || 'application/octet-stream'
|
||||||
|
var verify = opts.verify || false
|
||||||
|
|
||||||
|
if (verify !== false && typeof verify !== 'function') {
|
||||||
|
throw new TypeError('option verify must be function')
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the appropriate type checking function
|
||||||
|
var shouldParse = typeof type !== 'function'
|
||||||
|
? typeChecker(type)
|
||||||
|
: type
|
||||||
|
|
||||||
|
function parse (buf) {
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
return function rawParser (req, res, next) {
|
||||||
|
if (req._body) {
|
||||||
|
debug('body already parsed')
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.body = req.body || {}
|
||||||
|
|
||||||
|
// skip requests without bodies
|
||||||
|
if (!typeis.hasBody(req)) {
|
||||||
|
debug('skip empty body')
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
debug('content-type %j', req.headers['content-type'])
|
||||||
|
|
||||||
|
// determine if request should be parsed
|
||||||
|
if (!shouldParse(req)) {
|
||||||
|
debug('skip parsing')
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// read
|
||||||
|
read(req, res, next, parse, debug, {
|
||||||
|
encoding: null,
|
||||||
|
inflate: inflate,
|
||||||
|
limit: limit,
|
||||||
|
verify: verify
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the simple type checker.
|
||||||
|
*
|
||||||
|
* @param {string} type
|
||||||
|
* @return {function}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function typeChecker (type) {
|
||||||
|
return function checkType (req) {
|
||||||
|
return Boolean(typeis(req, type))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,121 @@
|
|||||||
|
/*!
|
||||||
|
* body-parser
|
||||||
|
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var bytes = require('bytes')
|
||||||
|
var contentType = require('content-type')
|
||||||
|
var debug = require('debug')('body-parser:text')
|
||||||
|
var read = require('../read')
|
||||||
|
var typeis = require('type-is')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = text
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a middleware to parse text bodies.
|
||||||
|
*
|
||||||
|
* @param {object} [options]
|
||||||
|
* @return {function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function text (options) {
|
||||||
|
var opts = options || {}
|
||||||
|
|
||||||
|
var defaultCharset = opts.defaultCharset || 'utf-8'
|
||||||
|
var inflate = opts.inflate !== false
|
||||||
|
var limit = typeof opts.limit !== 'number'
|
||||||
|
? bytes.parse(opts.limit || '100kb')
|
||||||
|
: opts.limit
|
||||||
|
var type = opts.type || 'text/plain'
|
||||||
|
var verify = opts.verify || false
|
||||||
|
|
||||||
|
if (verify !== false && typeof verify !== 'function') {
|
||||||
|
throw new TypeError('option verify must be function')
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the appropriate type checking function
|
||||||
|
var shouldParse = typeof type !== 'function'
|
||||||
|
? typeChecker(type)
|
||||||
|
: type
|
||||||
|
|
||||||
|
function parse (buf) {
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
return function textParser (req, res, next) {
|
||||||
|
if (req._body) {
|
||||||
|
debug('body already parsed')
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.body = req.body || {}
|
||||||
|
|
||||||
|
// skip requests without bodies
|
||||||
|
if (!typeis.hasBody(req)) {
|
||||||
|
debug('skip empty body')
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
debug('content-type %j', req.headers['content-type'])
|
||||||
|
|
||||||
|
// determine if request should be parsed
|
||||||
|
if (!shouldParse(req)) {
|
||||||
|
debug('skip parsing')
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// get charset
|
||||||
|
var charset = getCharset(req) || defaultCharset
|
||||||
|
|
||||||
|
// read
|
||||||
|
read(req, res, next, parse, debug, {
|
||||||
|
encoding: charset,
|
||||||
|
inflate: inflate,
|
||||||
|
limit: limit,
|
||||||
|
verify: verify
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the charset of a request.
|
||||||
|
*
|
||||||
|
* @param {object} req
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getCharset (req) {
|
||||||
|
try {
|
||||||
|
return contentType.parse(req).parameters.charset.toLowerCase()
|
||||||
|
} catch (e) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the simple type checker.
|
||||||
|
*
|
||||||
|
* @param {string} type
|
||||||
|
* @return {function}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function typeChecker (type) {
|
||||||
|
return function checkType (req) {
|
||||||
|
return Boolean(typeis(req, type))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,279 @@
|
|||||||
|
/*!
|
||||||
|
* body-parser
|
||||||
|
* Copyright(c) 2014 Jonathan Ong
|
||||||
|
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var bytes = require('bytes')
|
||||||
|
var contentType = require('content-type')
|
||||||
|
var createError = require('http-errors')
|
||||||
|
var debug = require('debug')('body-parser:urlencoded')
|
||||||
|
var deprecate = require('depd')('body-parser')
|
||||||
|
var read = require('../read')
|
||||||
|
var typeis = require('type-is')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = urlencoded
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache of parser modules.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var parsers = Object.create(null)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a middleware to parse urlencoded bodies.
|
||||||
|
*
|
||||||
|
* @param {object} [options]
|
||||||
|
* @return {function}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function urlencoded (options) {
|
||||||
|
var opts = options || {}
|
||||||
|
|
||||||
|
// notice because option default will flip in next major
|
||||||
|
if (opts.extended === undefined) {
|
||||||
|
deprecate('undefined extended: provide extended option')
|
||||||
|
}
|
||||||
|
|
||||||
|
var extended = opts.extended !== false
|
||||||
|
var inflate = opts.inflate !== false
|
||||||
|
var limit = typeof opts.limit !== 'number'
|
||||||
|
? bytes.parse(opts.limit || '100kb')
|
||||||
|
: opts.limit
|
||||||
|
var type = opts.type || 'application/x-www-form-urlencoded'
|
||||||
|
var verify = opts.verify || false
|
||||||
|
|
||||||
|
if (verify !== false && typeof verify !== 'function') {
|
||||||
|
throw new TypeError('option verify must be function')
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the appropriate query parser
|
||||||
|
var queryparse = extended
|
||||||
|
? extendedparser(opts)
|
||||||
|
: simpleparser(opts)
|
||||||
|
|
||||||
|
// create the appropriate type checking function
|
||||||
|
var shouldParse = typeof type !== 'function'
|
||||||
|
? typeChecker(type)
|
||||||
|
: type
|
||||||
|
|
||||||
|
function parse (body) {
|
||||||
|
return body.length
|
||||||
|
? queryparse(body)
|
||||||
|
: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function urlencodedParser (req, res, next) {
|
||||||
|
if (req._body) {
|
||||||
|
debug('body already parsed')
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.body = req.body || {}
|
||||||
|
|
||||||
|
// skip requests without bodies
|
||||||
|
if (!typeis.hasBody(req)) {
|
||||||
|
debug('skip empty body')
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
debug('content-type %j', req.headers['content-type'])
|
||||||
|
|
||||||
|
// determine if request should be parsed
|
||||||
|
if (!shouldParse(req)) {
|
||||||
|
debug('skip parsing')
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert charset
|
||||||
|
var charset = getCharset(req) || 'utf-8'
|
||||||
|
if (charset !== 'utf-8') {
|
||||||
|
debug('invalid charset')
|
||||||
|
next(createError(415, 'unsupported charset "' + charset.toUpperCase() + '"', {
|
||||||
|
charset: charset
|
||||||
|
}))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// read
|
||||||
|
read(req, res, next, parse, debug, {
|
||||||
|
debug: debug,
|
||||||
|
encoding: charset,
|
||||||
|
inflate: inflate,
|
||||||
|
limit: limit,
|
||||||
|
verify: verify
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the extended query parser.
|
||||||
|
*
|
||||||
|
* @param {object} options
|
||||||
|
*/
|
||||||
|
|
||||||
|
function extendedparser (options) {
|
||||||
|
var parameterLimit = options.parameterLimit !== undefined
|
||||||
|
? options.parameterLimit
|
||||||
|
: 1000
|
||||||
|
var parse = parser('qs')
|
||||||
|
|
||||||
|
if (isNaN(parameterLimit) || parameterLimit < 1) {
|
||||||
|
throw new TypeError('option parameterLimit must be a positive number')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFinite(parameterLimit)) {
|
||||||
|
parameterLimit = parameterLimit | 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return function queryparse (body) {
|
||||||
|
var paramCount = parameterCount(body, parameterLimit)
|
||||||
|
|
||||||
|
if (paramCount === undefined) {
|
||||||
|
debug('too many parameters')
|
||||||
|
throw createError(413, 'too many parameters')
|
||||||
|
}
|
||||||
|
|
||||||
|
var arrayLimit = Math.max(100, paramCount)
|
||||||
|
|
||||||
|
debug('parse extended urlencoding')
|
||||||
|
return parse(body, {
|
||||||
|
allowPrototypes: true,
|
||||||
|
arrayLimit: arrayLimit,
|
||||||
|
depth: Infinity,
|
||||||
|
parameterLimit: parameterLimit
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the charset of a request.
|
||||||
|
*
|
||||||
|
* @param {object} req
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getCharset (req) {
|
||||||
|
try {
|
||||||
|
return contentType.parse(req).parameters.charset.toLowerCase()
|
||||||
|
} catch (e) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count the number of parameters, stopping once limit reached
|
||||||
|
*
|
||||||
|
* @param {string} body
|
||||||
|
* @param {number} limit
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function parameterCount (body, limit) {
|
||||||
|
var count = 0
|
||||||
|
var index = 0
|
||||||
|
|
||||||
|
while ((index = body.indexOf('&', index)) !== -1) {
|
||||||
|
count++
|
||||||
|
index++
|
||||||
|
|
||||||
|
if (count === limit) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get parser for module name dynamically.
|
||||||
|
*
|
||||||
|
* @param {string} name
|
||||||
|
* @return {function}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function parser (name) {
|
||||||
|
var mod = parsers[name]
|
||||||
|
|
||||||
|
if (mod !== undefined) {
|
||||||
|
return mod.parse
|
||||||
|
}
|
||||||
|
|
||||||
|
// this uses a switch for static require analysis
|
||||||
|
switch (name) {
|
||||||
|
case 'qs':
|
||||||
|
mod = require('qs')
|
||||||
|
break
|
||||||
|
case 'querystring':
|
||||||
|
mod = require('querystring')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// store to prevent invoking require()
|
||||||
|
parsers[name] = mod
|
||||||
|
|
||||||
|
return mod.parse
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the simple query parser.
|
||||||
|
*
|
||||||
|
* @param {object} options
|
||||||
|
*/
|
||||||
|
|
||||||
|
function simpleparser (options) {
|
||||||
|
var parameterLimit = options.parameterLimit !== undefined
|
||||||
|
? options.parameterLimit
|
||||||
|
: 1000
|
||||||
|
var parse = parser('querystring')
|
||||||
|
|
||||||
|
if (isNaN(parameterLimit) || parameterLimit < 1) {
|
||||||
|
throw new TypeError('option parameterLimit must be a positive number')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFinite(parameterLimit)) {
|
||||||
|
parameterLimit = parameterLimit | 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return function queryparse (body) {
|
||||||
|
var paramCount = parameterCount(body, parameterLimit)
|
||||||
|
|
||||||
|
if (paramCount === undefined) {
|
||||||
|
debug('too many parameters')
|
||||||
|
throw createError(413, 'too many parameters')
|
||||||
|
}
|
||||||
|
|
||||||
|
debug('parse urlencoding')
|
||||||
|
return parse(body, undefined, undefined, {maxKeys: parameterLimit})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the simple type checker.
|
||||||
|
*
|
||||||
|
* @param {string} type
|
||||||
|
* @return {function}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function typeChecker (type) {
|
||||||
|
return function checkType (req) {
|
||||||
|
return Boolean(typeis(req, type))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
2.4.0 / 2016-06-01
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add option "unitSeparator"
|
||||||
|
|
||||||
|
2.3.0 / 2016-02-15
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Drop partial bytes on all parsed units
|
||||||
|
* Fix non-finite numbers to `.format` to return `null`
|
||||||
|
* Fix parsing byte string that looks like hex
|
||||||
|
* perf: hoist regular expressions
|
||||||
|
|
||||||
|
2.2.0 / 2015-11-13
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add option "decimalPlaces"
|
||||||
|
* add option "fixedDecimals"
|
||||||
|
|
||||||
|
2.1.0 / 2015-05-21
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add `.format` export
|
||||||
|
* add `.parse` export
|
||||||
|
|
||||||
|
2.0.2 / 2015-05-20
|
||||||
|
==================
|
||||||
|
|
||||||
|
* remove map recreation
|
||||||
|
* remove unnecessary object construction
|
||||||
|
|
||||||
|
2.0.1 / 2015-05-07
|
||||||
|
==================
|
||||||
|
|
||||||
|
* fix browserify require
|
||||||
|
* remove node.extend dependency
|
||||||
|
|
||||||
|
2.0.0 / 2015-04-12
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add option "case"
|
||||||
|
* add option "thousandsSeparator"
|
||||||
|
* return "null" on invalid parse input
|
||||||
|
* support proper round-trip: bytes(bytes(num)) === num
|
||||||
|
* units no longer case sensitive when parsing
|
||||||
|
|
||||||
|
1.0.0 / 2014-05-05
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add negative support. fixes #6
|
||||||
|
|
||||||
|
0.3.0 / 2014-03-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* added terabyte support
|
||||||
|
|
||||||
|
0.2.1 / 2013-04-01
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add .component
|
||||||
|
|
||||||
|
0.2.0 / 2012-10-28
|
||||||
|
==================
|
||||||
|
|
||||||
|
* bytes(200).should.eql('200b')
|
||||||
|
|
||||||
|
0.1.0 / 2012-07-04
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add bytes to string conversion [yields]
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2012-2014 TJ Holowaychuk <tj@vision-media.ca>
|
||||||
|
Copyright (c) 2015 Jed Watson <jed.watson@me.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
'Software'), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
# Bytes utility
|
||||||
|
|
||||||
|
[![NPM Version][npm-image]][npm-url]
|
||||||
|
[![NPM Downloads][downloads-image]][downloads-url]
|
||||||
|
[![Build Status][travis-image]][travis-url]
|
||||||
|
|
||||||
|
Utility to parse a string bytes (ex: `1TB`) to bytes (`1099511627776`) and vice-versa.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
var bytes = require('bytes');
|
||||||
|
```
|
||||||
|
|
||||||
|
#### bytes.format(number value, [options]): string|null
|
||||||
|
|
||||||
|
Format the given value in bytes into a string. If the value is negative, it is kept as such. If it is a float, it is
|
||||||
|
rounded.
|
||||||
|
|
||||||
|
**Arguments**
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|---------|--------|--------------------|
|
||||||
|
| value | `number` | Value in bytes |
|
||||||
|
| options | `Object` | Conversion options |
|
||||||
|
|
||||||
|
**Options**
|
||||||
|
|
||||||
|
| Property | Type | Description |
|
||||||
|
|-------------------|--------|-----------------------------------------------------------------------------------------|
|
||||||
|
| decimalPlaces | `number`|`null` | Maximum number of decimal places to include in output. Default value to `2`. |
|
||||||
|
| fixedDecimals | `boolean`|`null` | Whether to always display the maximum number of decimal places. Default value to `false` |
|
||||||
|
| thousandsSeparator | `string`|`null` | Example of values: `' '`, `','` and `.`... Default value to `' '`. |
|
||||||
|
| unitSeparator | `string`|`null` | Separator to use between number and unit. Default value to `''`. |
|
||||||
|
|
||||||
|
**Returns**
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|---------|-------------|-------------------------|
|
||||||
|
| results | `string`|`null` | Return null upon error. String value otherwise. |
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
```js
|
||||||
|
bytes(1024);
|
||||||
|
// output: '1kB'
|
||||||
|
|
||||||
|
bytes(1000);
|
||||||
|
// output: '1000B'
|
||||||
|
|
||||||
|
bytes(1000, {thousandsSeparator: ' '});
|
||||||
|
// output: '1 000B'
|
||||||
|
|
||||||
|
bytes(1024 * 1.7, {decimalPlaces: 0});
|
||||||
|
// output: '2kB'
|
||||||
|
|
||||||
|
bytes(1024, {unitSeparator: ' '});
|
||||||
|
// output: '1 kB'
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
#### bytes.parse(string value): number|null
|
||||||
|
|
||||||
|
Parse the string value into an integer in bytes. If no unit is given, it is assumed the value is in bytes.
|
||||||
|
|
||||||
|
Supported units and abbreviations are as follows and are case-insensitive:
|
||||||
|
|
||||||
|
* "b" for bytes
|
||||||
|
* "kb" for kilobytes
|
||||||
|
* "mb" for megabytes
|
||||||
|
* "gb" for gigabytes
|
||||||
|
* "tb" for terabytes
|
||||||
|
|
||||||
|
The units are in powers of two, not ten. This means 1kb = 1024b according to this parser.
|
||||||
|
|
||||||
|
**Arguments**
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|---------------|--------|--------------------|
|
||||||
|
| value | `string` | String to parse. |
|
||||||
|
|
||||||
|
**Returns**
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|---------|-------------|-------------------------|
|
||||||
|
| results | `number`|`null` | Return null upon error. Value in bytes otherwise. |
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
```js
|
||||||
|
bytes('1kB');
|
||||||
|
// output: 1024
|
||||||
|
|
||||||
|
bytes('1024');
|
||||||
|
// output: 1024
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install bytes --save
|
||||||
|
component install visionmedia/bytes.js
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[](https://github.com/visionmedia/bytes.js/blob/master/LICENSE)
|
||||||
|
|
||||||
|
[downloads-image]: https://img.shields.io/npm/dm/bytes.svg
|
||||||
|
[downloads-url]: https://npmjs.org/package/bytes
|
||||||
|
[npm-image]: https://img.shields.io/npm/v/bytes.svg
|
||||||
|
[npm-url]: https://npmjs.org/package/bytes
|
||||||
|
[travis-image]: https://img.shields.io/travis/visionmedia/bytes.js/master.svg
|
||||||
|
[travis-url]: https://travis-ci.org/visionmedia/bytes.js
|
||||||
@ -0,0 +1,157 @@
|
|||||||
|
/*!
|
||||||
|
* bytes
|
||||||
|
* Copyright(c) 2012-2014 TJ Holowaychuk
|
||||||
|
* Copyright(c) 2015 Jed Watson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = bytes;
|
||||||
|
module.exports.format = format;
|
||||||
|
module.exports.parse = parse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module variables.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var formatThousandsRegExp = /\B(?=(\d{3})+(?!\d))/g;
|
||||||
|
|
||||||
|
var formatDecimalsRegExp = /(?:\.0*|(\.[^0]+)0+)$/;
|
||||||
|
|
||||||
|
var map = {
|
||||||
|
b: 1,
|
||||||
|
kb: 1 << 10,
|
||||||
|
mb: 1 << 20,
|
||||||
|
gb: 1 << 30,
|
||||||
|
tb: ((1 << 30) * 1024)
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: use is-finite module?
|
||||||
|
var numberIsFinite = Number.isFinite || function (v) { return typeof v === 'number' && isFinite(v); };
|
||||||
|
|
||||||
|
var parseRegExp = /^((-|\+)?(\d+(?:\.\d+)?)) *(kb|mb|gb|tb)$/i;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the given value in bytes into a string or parse to string to an integer in bytes.
|
||||||
|
*
|
||||||
|
* @param {string|number} value
|
||||||
|
* @param {{
|
||||||
|
* case: [string],
|
||||||
|
* decimalPlaces: [number]
|
||||||
|
* fixedDecimals: [boolean]
|
||||||
|
* thousandsSeparator: [string]
|
||||||
|
* unitSeparator: [string]
|
||||||
|
* }} [options] bytes options.
|
||||||
|
*
|
||||||
|
* @returns {string|number|null}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function bytes(value, options) {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return parse(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
return format(value, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format the given value in bytes into a string.
|
||||||
|
*
|
||||||
|
* If the value is negative, it is kept as such. If it is a float,
|
||||||
|
* it is rounded.
|
||||||
|
*
|
||||||
|
* @param {number} value
|
||||||
|
* @param {object} [options]
|
||||||
|
* @param {number} [options.decimalPlaces=2]
|
||||||
|
* @param {number} [options.fixedDecimals=false]
|
||||||
|
* @param {string} [options.thousandsSeparator=]
|
||||||
|
* @param {string} [options.unitSeparator=]
|
||||||
|
*
|
||||||
|
* @returns {string|null}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function format(value, options) {
|
||||||
|
if (!numberIsFinite(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mag = Math.abs(value);
|
||||||
|
var thousandsSeparator = (options && options.thousandsSeparator) || '';
|
||||||
|
var unitSeparator = (options && options.unitSeparator) || '';
|
||||||
|
var decimalPlaces = (options && options.decimalPlaces !== undefined) ? options.decimalPlaces : 2;
|
||||||
|
var fixedDecimals = Boolean(options && options.fixedDecimals);
|
||||||
|
var unit = 'B';
|
||||||
|
|
||||||
|
if (mag >= map.tb) {
|
||||||
|
unit = 'TB';
|
||||||
|
} else if (mag >= map.gb) {
|
||||||
|
unit = 'GB';
|
||||||
|
} else if (mag >= map.mb) {
|
||||||
|
unit = 'MB';
|
||||||
|
} else if (mag >= map.kb) {
|
||||||
|
unit = 'kB';
|
||||||
|
}
|
||||||
|
|
||||||
|
var val = value / map[unit.toLowerCase()];
|
||||||
|
var str = val.toFixed(decimalPlaces);
|
||||||
|
|
||||||
|
if (!fixedDecimals) {
|
||||||
|
str = str.replace(formatDecimalsRegExp, '$1');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thousandsSeparator) {
|
||||||
|
str = str.replace(formatThousandsRegExp, thousandsSeparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str + unitSeparator + unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the string value into an integer in bytes.
|
||||||
|
*
|
||||||
|
* If no unit is given, it is assumed the value is in bytes.
|
||||||
|
*
|
||||||
|
* @param {number|string} val
|
||||||
|
*
|
||||||
|
* @returns {number|null}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function parse(val) {
|
||||||
|
if (typeof val === 'number' && !isNaN(val)) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof val !== 'string') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if the string passed is valid
|
||||||
|
var results = parseRegExp.exec(val);
|
||||||
|
var floatValue;
|
||||||
|
var unit = 'b';
|
||||||
|
|
||||||
|
if (!results) {
|
||||||
|
// Nothing could be extracted from the given string
|
||||||
|
floatValue = parseInt(val, 10);
|
||||||
|
unit = 'b'
|
||||||
|
} else {
|
||||||
|
// Retrieve the value and the unit
|
||||||
|
floatValue = parseFloat(results[1]);
|
||||||
|
unit = results[4].toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.floor(map[unit] * floatValue);
|
||||||
|
}
|
||||||
@ -0,0 +1,85 @@
|
|||||||
|
{
|
||||||
|
"name": "bytes",
|
||||||
|
"description": "Utility to parse a string bytes to bytes and vice-versa",
|
||||||
|
"version": "2.4.0",
|
||||||
|
"author": {
|
||||||
|
"name": "TJ Holowaychuk",
|
||||||
|
"email": "tj@vision-media.ca",
|
||||||
|
"url": "http://tjholowaychuk.com"
|
||||||
|
},
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Jed Watson",
|
||||||
|
"email": "jed.watson@me.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Théo FIDRY",
|
||||||
|
"email": "theo.fidry@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"byte",
|
||||||
|
"bytes",
|
||||||
|
"utility",
|
||||||
|
"parse",
|
||||||
|
"parser",
|
||||||
|
"convert",
|
||||||
|
"converter"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/visionmedia/bytes.js.git"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"scripts": {
|
||||||
|
"bytes/index.js": "index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"mocha": "1.21.5"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"History.md",
|
||||||
|
"LICENSE",
|
||||||
|
"Readme.md",
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"test": "mocha --check-leaks --reporter spec"
|
||||||
|
},
|
||||||
|
"gitHead": "2a598442bdfa796df8d01a96cc54495cda550e70",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/visionmedia/bytes.js/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/visionmedia/bytes.js",
|
||||||
|
"_id": "bytes@2.4.0",
|
||||||
|
"_shasum": "7d97196f9d5baf7f6935e25985549edd2a6c2339",
|
||||||
|
"_from": "bytes@2.4.0",
|
||||||
|
"_npmVersion": "1.4.28",
|
||||||
|
"_npmUser": {
|
||||||
|
"name": "dougwilson",
|
||||||
|
"email": "doug@somethingdoug.com"
|
||||||
|
},
|
||||||
|
"maintainers": [
|
||||||
|
{
|
||||||
|
"name": "dougwilson",
|
||||||
|
"email": "doug@somethingdoug.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tjholowaychuk",
|
||||||
|
"email": "tj@vision-media.ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dist": {
|
||||||
|
"shasum": "7d97196f9d5baf7f6935e25985549edd2a6c2339",
|
||||||
|
"tarball": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz"
|
||||||
|
},
|
||||||
|
"_npmOperationalInternal": {
|
||||||
|
"host": "packages-16-east.internal.npmjs.com",
|
||||||
|
"tmp": "tmp/bytes-2.4.0.tgz_1464812473023_0.6271433881483972"
|
||||||
|
},
|
||||||
|
"directories": {},
|
||||||
|
"_resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz",
|
||||||
|
"readme": "ERROR: No README data found!"
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
1.0.2 / 2016-05-09
|
||||||
|
==================
|
||||||
|
|
||||||
|
* perf: enable strict mode
|
||||||
|
|
||||||
|
1.0.1 / 2015-02-13
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Improve missing `Content-Type` header error message
|
||||||
|
|
||||||
|
1.0.0 / 2015-02-01
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Initial implementation, derived from `media-typer@0.3.0`
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Douglas Christopher Wilson
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
'Software'), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
# content-type
|
||||||
|
|
||||||
|
[![NPM Version][npm-image]][npm-url]
|
||||||
|
[![NPM Downloads][downloads-image]][downloads-url]
|
||||||
|
[![Node.js Version][node-version-image]][node-version-url]
|
||||||
|
[![Build Status][travis-image]][travis-url]
|
||||||
|
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||||
|
|
||||||
|
Create and parse HTTP Content-Type header according to RFC 7231
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install content-type
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
```js
|
||||||
|
var contentType = require('content-type')
|
||||||
|
```
|
||||||
|
|
||||||
|
### contentType.parse(string)
|
||||||
|
|
||||||
|
```js
|
||||||
|
var obj = contentType.parse('image/svg+xml; charset=utf-8')
|
||||||
|
```
|
||||||
|
|
||||||
|
Parse a content type string. This will return an object with the following
|
||||||
|
properties (examples are shown for the string `'image/svg+xml; charset=utf-8'`):
|
||||||
|
|
||||||
|
- `type`: The media type (the type and subtype, always lower case).
|
||||||
|
Example: `'image/svg+xml'`
|
||||||
|
|
||||||
|
- `parameters`: An object of the parameters in the media type (name of parameter
|
||||||
|
always lower case). Example: `{charset: 'utf-8'}`
|
||||||
|
|
||||||
|
Throws a `TypeError` if the string is missing or invalid.
|
||||||
|
|
||||||
|
### contentType.parse(req)
|
||||||
|
|
||||||
|
```js
|
||||||
|
var obj = contentType.parse(req)
|
||||||
|
```
|
||||||
|
|
||||||
|
Parse the `content-type` header from the given `req`. Short-cut for
|
||||||
|
`contentType.parse(req.headers['content-type'])`.
|
||||||
|
|
||||||
|
Throws a `TypeError` if the `Content-Type` header is missing or invalid.
|
||||||
|
|
||||||
|
### contentType.parse(res)
|
||||||
|
|
||||||
|
```js
|
||||||
|
var obj = contentType.parse(res)
|
||||||
|
```
|
||||||
|
|
||||||
|
Parse the `content-type` header set on the given `res`. Short-cut for
|
||||||
|
`contentType.parse(res.getHeader('content-type'))`.
|
||||||
|
|
||||||
|
Throws a `TypeError` if the `Content-Type` header is missing or invalid.
|
||||||
|
|
||||||
|
### contentType.format(obj)
|
||||||
|
|
||||||
|
```js
|
||||||
|
var str = contentType.format({type: 'image/svg+xml'})
|
||||||
|
```
|
||||||
|
|
||||||
|
Format an object into a content type string. This will return a string of the
|
||||||
|
content type for the given object with the following properties (examples are
|
||||||
|
shown that produce the string `'image/svg+xml; charset=utf-8'`):
|
||||||
|
|
||||||
|
- `type`: The media type (will be lower-cased). Example: `'image/svg+xml'`
|
||||||
|
|
||||||
|
- `parameters`: An object of the parameters in the media type (name of the
|
||||||
|
parameter will be lower-cased). Example: `{charset: 'utf-8'}`
|
||||||
|
|
||||||
|
Throws a `TypeError` if the object contains an invalid type or parameter names.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
||||||
|
|
||||||
|
[npm-image]: https://img.shields.io/npm/v/content-type.svg
|
||||||
|
[npm-url]: https://npmjs.org/package/content-type
|
||||||
|
[node-version-image]: https://img.shields.io/node/v/content-type.svg
|
||||||
|
[node-version-url]: http://nodejs.org/download/
|
||||||
|
[travis-image]: https://img.shields.io/travis/jshttp/content-type/master.svg
|
||||||
|
[travis-url]: https://travis-ci.org/jshttp/content-type
|
||||||
|
[coveralls-image]: https://img.shields.io/coveralls/jshttp/content-type/master.svg
|
||||||
|
[coveralls-url]: https://coveralls.io/r/jshttp/content-type
|
||||||
|
[downloads-image]: https://img.shields.io/npm/dm/content-type.svg
|
||||||
|
[downloads-url]: https://npmjs.org/package/content-type
|
||||||
@ -0,0 +1,216 @@
|
|||||||
|
/*!
|
||||||
|
* content-type
|
||||||
|
* Copyright(c) 2015 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RegExp to match *( ";" parameter ) in RFC 7231 sec 3.1.1.1
|
||||||
|
*
|
||||||
|
* parameter = token "=" ( token / quoted-string )
|
||||||
|
* token = 1*tchar
|
||||||
|
* tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
|
||||||
|
* / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
|
||||||
|
* / DIGIT / ALPHA
|
||||||
|
* ; any VCHAR, except delimiters
|
||||||
|
* quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
|
||||||
|
* qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text
|
||||||
|
* obs-text = %x80-FF
|
||||||
|
* quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
||||||
|
*/
|
||||||
|
var paramRegExp = /; *([!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+) */g
|
||||||
|
var textRegExp = /^[\u000b\u0020-\u007e\u0080-\u00ff]+$/
|
||||||
|
var tokenRegExp = /^[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+$/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RegExp to match quoted-pair in RFC 7230 sec 3.2.6
|
||||||
|
*
|
||||||
|
* quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
||||||
|
* obs-text = %x80-FF
|
||||||
|
*/
|
||||||
|
var qescRegExp = /\\([\u000b\u0020-\u00ff])/g
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RegExp to match chars that must be quoted-pair in RFC 7230 sec 3.2.6
|
||||||
|
*/
|
||||||
|
var quoteRegExp = /([\\"])/g
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RegExp to match type in RFC 6838
|
||||||
|
*
|
||||||
|
* media-type = type "/" subtype
|
||||||
|
* type = token
|
||||||
|
* subtype = token
|
||||||
|
*/
|
||||||
|
var typeRegExp = /^[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+\/[!#$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+$/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.format = format
|
||||||
|
exports.parse = parse
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format object to media type.
|
||||||
|
*
|
||||||
|
* @param {object} obj
|
||||||
|
* @return {string}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function format(obj) {
|
||||||
|
if (!obj || typeof obj !== 'object') {
|
||||||
|
throw new TypeError('argument obj is required')
|
||||||
|
}
|
||||||
|
|
||||||
|
var parameters = obj.parameters
|
||||||
|
var type = obj.type
|
||||||
|
|
||||||
|
if (!type || !typeRegExp.test(type)) {
|
||||||
|
throw new TypeError('invalid type')
|
||||||
|
}
|
||||||
|
|
||||||
|
var string = type
|
||||||
|
|
||||||
|
// append parameters
|
||||||
|
if (parameters && typeof parameters === 'object') {
|
||||||
|
var param
|
||||||
|
var params = Object.keys(parameters).sort()
|
||||||
|
|
||||||
|
for (var i = 0; i < params.length; i++) {
|
||||||
|
param = params[i]
|
||||||
|
|
||||||
|
if (!tokenRegExp.test(param)) {
|
||||||
|
throw new TypeError('invalid parameter name')
|
||||||
|
}
|
||||||
|
|
||||||
|
string += '; ' + param + '=' + qstring(parameters[param])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse media type to object.
|
||||||
|
*
|
||||||
|
* @param {string|object} string
|
||||||
|
* @return {Object}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function parse(string) {
|
||||||
|
if (!string) {
|
||||||
|
throw new TypeError('argument string is required')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof string === 'object') {
|
||||||
|
// support req/res-like objects as argument
|
||||||
|
string = getcontenttype(string)
|
||||||
|
|
||||||
|
if (typeof string !== 'string') {
|
||||||
|
throw new TypeError('content-type header is missing from object');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof string !== 'string') {
|
||||||
|
throw new TypeError('argument string is required to be a string')
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = string.indexOf(';')
|
||||||
|
var type = index !== -1
|
||||||
|
? string.substr(0, index).trim()
|
||||||
|
: string.trim()
|
||||||
|
|
||||||
|
if (!typeRegExp.test(type)) {
|
||||||
|
throw new TypeError('invalid media type')
|
||||||
|
}
|
||||||
|
|
||||||
|
var key
|
||||||
|
var match
|
||||||
|
var obj = new ContentType(type.toLowerCase())
|
||||||
|
var value
|
||||||
|
|
||||||
|
paramRegExp.lastIndex = index
|
||||||
|
|
||||||
|
while (match = paramRegExp.exec(string)) {
|
||||||
|
if (match.index !== index) {
|
||||||
|
throw new TypeError('invalid parameter format')
|
||||||
|
}
|
||||||
|
|
||||||
|
index += match[0].length
|
||||||
|
key = match[1].toLowerCase()
|
||||||
|
value = match[2]
|
||||||
|
|
||||||
|
if (value[0] === '"') {
|
||||||
|
// remove quotes and escapes
|
||||||
|
value = value
|
||||||
|
.substr(1, value.length - 2)
|
||||||
|
.replace(qescRegExp, '$1')
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.parameters[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index !== -1 && index !== string.length) {
|
||||||
|
throw new TypeError('invalid parameter format')
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get content-type from req/res objects.
|
||||||
|
*
|
||||||
|
* @param {object}
|
||||||
|
* @return {Object}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getcontenttype(obj) {
|
||||||
|
if (typeof obj.getHeader === 'function') {
|
||||||
|
// res-like
|
||||||
|
return obj.getHeader('content-type')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof obj.headers === 'object') {
|
||||||
|
// req-like
|
||||||
|
return obj.headers && obj.headers['content-type']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quote a string if necessary.
|
||||||
|
*
|
||||||
|
* @param {string} val
|
||||||
|
* @return {string}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function qstring(val) {
|
||||||
|
var str = String(val)
|
||||||
|
|
||||||
|
// no need to quote tokens
|
||||||
|
if (tokenRegExp.test(str)) {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str.length > 0 && !textRegExp.test(str)) {
|
||||||
|
throw new TypeError('invalid parameter value')
|
||||||
|
}
|
||||||
|
|
||||||
|
return '"' + str.replace(quoteRegExp, '\\$1') + '"'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to represent a content type.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function ContentType(type) {
|
||||||
|
this.parameters = Object.create(null)
|
||||||
|
this.type = type
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
"name": "content-type",
|
||||||
|
"description": "Create and parse HTTP Content-Type header",
|
||||||
|
"version": "1.0.2",
|
||||||
|
"author": {
|
||||||
|
"name": "Douglas Christopher Wilson",
|
||||||
|
"email": "doug@somethingdoug.com"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"content-type",
|
||||||
|
"http",
|
||||||
|
"req",
|
||||||
|
"res",
|
||||||
|
"rfc7231"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/jshttp/content-type.git"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"istanbul": "0.4.3",
|
||||||
|
"mocha": "~1.21.5"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"LICENSE",
|
||||||
|
"HISTORY.md",
|
||||||
|
"README.md",
|
||||||
|
"index.js"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "mocha --reporter spec --check-leaks --bail test/",
|
||||||
|
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/",
|
||||||
|
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/"
|
||||||
|
},
|
||||||
|
"gitHead": "8118763adfbbac80cf1254191889330aec8b8be7",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/jshttp/content-type/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/jshttp/content-type#readme",
|
||||||
|
"_id": "content-type@1.0.2",
|
||||||
|
"_shasum": "b7d113aee7a8dd27bd21133c4dc2529df1721eed",
|
||||||
|
"_from": "content-type@>=1.0.2 <1.1.0",
|
||||||
|
"_npmVersion": "2.15.1",
|
||||||
|
"_nodeVersion": "4.4.3",
|
||||||
|
"_npmUser": {
|
||||||
|
"name": "dougwilson",
|
||||||
|
"email": "doug@somethingdoug.com"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"shasum": "b7d113aee7a8dd27bd21133c4dc2529df1721eed",
|
||||||
|
"tarball": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz"
|
||||||
|
},
|
||||||
|
"maintainers": [
|
||||||
|
{
|
||||||
|
"name": "dougwilson",
|
||||||
|
"email": "doug@somethingdoug.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_npmOperationalInternal": {
|
||||||
|
"host": "packages-12-west.internal.npmjs.com",
|
||||||
|
"tmp": "tmp/content-type-1.0.2.tgz_1462852785748_0.5491233412176371"
|
||||||
|
},
|
||||||
|
"directories": {},
|
||||||
|
"_resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz",
|
||||||
|
"readme": "ERROR: No README data found!"
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"laxbreak": true
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
support
|
||||||
|
test
|
||||||
|
examples
|
||||||
|
example
|
||||||
|
*.sock
|
||||||
|
dist
|
||||||
@ -0,0 +1,195 @@
|
|||||||
|
|
||||||
|
2.2.0 / 2015-05-09
|
||||||
|
==================
|
||||||
|
|
||||||
|
* package: update "ms" to v0.7.1 (#202, @dougwilson)
|
||||||
|
* README: add logging to file example (#193, @DanielOchoa)
|
||||||
|
* README: fixed a typo (#191, @amir-s)
|
||||||
|
* browser: expose `storage` (#190, @stephenmathieson)
|
||||||
|
* Makefile: add a `distclean` target (#189, @stephenmathieson)
|
||||||
|
|
||||||
|
2.1.3 / 2015-03-13
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Updated stdout/stderr example (#186)
|
||||||
|
* Updated example/stdout.js to match debug current behaviour
|
||||||
|
* Renamed example/stderr.js to stdout.js
|
||||||
|
* Update Readme.md (#184)
|
||||||
|
* replace high intensity foreground color for bold (#182, #183)
|
||||||
|
|
||||||
|
2.1.2 / 2015-03-01
|
||||||
|
==================
|
||||||
|
|
||||||
|
* dist: recompile
|
||||||
|
* update "ms" to v0.7.0
|
||||||
|
* package: update "browserify" to v9.0.3
|
||||||
|
* component: fix "ms.js" repo location
|
||||||
|
* changed bower package name
|
||||||
|
* updated documentation about using debug in a browser
|
||||||
|
* fix: security error on safari (#167, #168, @yields)
|
||||||
|
|
||||||
|
2.1.1 / 2014-12-29
|
||||||
|
==================
|
||||||
|
|
||||||
|
* browser: use `typeof` to check for `console` existence
|
||||||
|
* browser: check for `console.log` truthiness (fix IE 8/9)
|
||||||
|
* browser: add support for Chrome apps
|
||||||
|
* Readme: added Windows usage remarks
|
||||||
|
* Add `bower.json` to properly support bower install
|
||||||
|
|
||||||
|
2.1.0 / 2014-10-15
|
||||||
|
==================
|
||||||
|
|
||||||
|
* node: implement `DEBUG_FD` env variable support
|
||||||
|
* package: update "browserify" to v6.1.0
|
||||||
|
* package: add "license" field to package.json (#135, @panuhorsmalahti)
|
||||||
|
|
||||||
|
2.0.0 / 2014-09-01
|
||||||
|
==================
|
||||||
|
|
||||||
|
* package: update "browserify" to v5.11.0
|
||||||
|
* node: use stderr rather than stdout for logging (#29, @stephenmathieson)
|
||||||
|
|
||||||
|
1.0.4 / 2014-07-15
|
||||||
|
==================
|
||||||
|
|
||||||
|
* dist: recompile
|
||||||
|
* example: remove `console.info()` log usage
|
||||||
|
* example: add "Content-Type" UTF-8 header to browser example
|
||||||
|
* browser: place %c marker after the space character
|
||||||
|
* browser: reset the "content" color via `color: inherit`
|
||||||
|
* browser: add colors support for Firefox >= v31
|
||||||
|
* debug: prefer an instance `log()` function over the global one (#119)
|
||||||
|
* Readme: update documentation about styled console logs for FF v31 (#116, @wryk)
|
||||||
|
|
||||||
|
1.0.3 / 2014-07-09
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add support for multiple wildcards in namespaces (#122, @seegno)
|
||||||
|
* browser: fix lint
|
||||||
|
|
||||||
|
1.0.2 / 2014-06-10
|
||||||
|
==================
|
||||||
|
|
||||||
|
* browser: update color palette (#113, @gscottolson)
|
||||||
|
* common: make console logging function configurable (#108, @timoxley)
|
||||||
|
* node: fix %o colors on old node <= 0.8.x
|
||||||
|
* Makefile: find node path using shell/which (#109, @timoxley)
|
||||||
|
|
||||||
|
1.0.1 / 2014-06-06
|
||||||
|
==================
|
||||||
|
|
||||||
|
* browser: use `removeItem()` to clear localStorage
|
||||||
|
* browser, node: don't set DEBUG if namespaces is undefined (#107, @leedm777)
|
||||||
|
* package: add "contributors" section
|
||||||
|
* node: fix comment typo
|
||||||
|
* README: list authors
|
||||||
|
|
||||||
|
1.0.0 / 2014-06-04
|
||||||
|
==================
|
||||||
|
|
||||||
|
* make ms diff be global, not be scope
|
||||||
|
* debug: ignore empty strings in enable()
|
||||||
|
* node: make DEBUG_COLORS able to disable coloring
|
||||||
|
* *: export the `colors` array
|
||||||
|
* npmignore: don't publish the `dist` dir
|
||||||
|
* Makefile: refactor to use browserify
|
||||||
|
* package: add "browserify" as a dev dependency
|
||||||
|
* Readme: add Web Inspector Colors section
|
||||||
|
* node: reset terminal color for the debug content
|
||||||
|
* node: map "%o" to `util.inspect()`
|
||||||
|
* browser: map "%j" to `JSON.stringify()`
|
||||||
|
* debug: add custom "formatters"
|
||||||
|
* debug: use "ms" module for humanizing the diff
|
||||||
|
* Readme: add "bash" syntax highlighting
|
||||||
|
* browser: add Firebug color support
|
||||||
|
* browser: add colors for WebKit browsers
|
||||||
|
* node: apply log to `console`
|
||||||
|
* rewrite: abstract common logic for Node & browsers
|
||||||
|
* add .jshintrc file
|
||||||
|
|
||||||
|
0.8.1 / 2014-04-14
|
||||||
|
==================
|
||||||
|
|
||||||
|
* package: re-add the "component" section
|
||||||
|
|
||||||
|
0.8.0 / 2014-03-30
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add `enable()` method for nodejs. Closes #27
|
||||||
|
* change from stderr to stdout
|
||||||
|
* remove unnecessary index.js file
|
||||||
|
|
||||||
|
0.7.4 / 2013-11-13
|
||||||
|
==================
|
||||||
|
|
||||||
|
* remove "browserify" key from package.json (fixes something in browserify)
|
||||||
|
|
||||||
|
0.7.3 / 2013-10-30
|
||||||
|
==================
|
||||||
|
|
||||||
|
* fix: catch localStorage security error when cookies are blocked (Chrome)
|
||||||
|
* add debug(err) support. Closes #46
|
||||||
|
* add .browser prop to package.json. Closes #42
|
||||||
|
|
||||||
|
0.7.2 / 2013-02-06
|
||||||
|
==================
|
||||||
|
|
||||||
|
* fix package.json
|
||||||
|
* fix: Mobile Safari (private mode) is broken with debug
|
||||||
|
* fix: Use unicode to send escape character to shell instead of octal to work with strict mode javascript
|
||||||
|
|
||||||
|
0.7.1 / 2013-02-05
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add repository URL to package.json
|
||||||
|
* add DEBUG_COLORED to force colored output
|
||||||
|
* add browserify support
|
||||||
|
* fix component. Closes #24
|
||||||
|
|
||||||
|
0.7.0 / 2012-05-04
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Added .component to package.json
|
||||||
|
* Added debug.component.js build
|
||||||
|
|
||||||
|
0.6.0 / 2012-03-16
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Added support for "-" prefix in DEBUG [Vinay Pulim]
|
||||||
|
* Added `.enabled` flag to the node version [TooTallNate]
|
||||||
|
|
||||||
|
0.5.0 / 2012-02-02
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Added: humanize diffs. Closes #8
|
||||||
|
* Added `debug.disable()` to the CS variant
|
||||||
|
* Removed padding. Closes #10
|
||||||
|
* Fixed: persist client-side variant again. Closes #9
|
||||||
|
|
||||||
|
0.4.0 / 2012-02-01
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Added browser variant support for older browsers [TooTallNate]
|
||||||
|
* Added `debug.enable('project:*')` to browser variant [TooTallNate]
|
||||||
|
* Added padding to diff (moved it to the right)
|
||||||
|
|
||||||
|
0.3.0 / 2012-01-26
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Added millisecond diff when isatty, otherwise UTC string
|
||||||
|
|
||||||
|
0.2.0 / 2012-01-22
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Added wildcard support
|
||||||
|
|
||||||
|
0.1.0 / 2011-12-02
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Added: remove colors unless stderr isatty [TooTallNate]
|
||||||
|
|
||||||
|
0.0.1 / 2010-01-03
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Initial release
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
# get Makefile directory name: http://stackoverflow.com/a/5982798/376773
|
||||||
|
THIS_MAKEFILE_PATH:=$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
|
||||||
|
THIS_DIR:=$(shell cd $(dir $(THIS_MAKEFILE_PATH));pwd)
|
||||||
|
|
||||||
|
# BIN directory
|
||||||
|
BIN := $(THIS_DIR)/node_modules/.bin
|
||||||
|
|
||||||
|
# applications
|
||||||
|
NODE ?= $(shell which node)
|
||||||
|
NPM ?= $(NODE) $(shell which npm)
|
||||||
|
BROWSERIFY ?= $(NODE) $(BIN)/browserify
|
||||||
|
|
||||||
|
all: dist/debug.js
|
||||||
|
|
||||||
|
install: node_modules
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -rf dist
|
||||||
|
|
||||||
|
dist:
|
||||||
|
@mkdir -p $@
|
||||||
|
|
||||||
|
dist/debug.js: node_modules browser.js debug.js dist
|
||||||
|
@$(BROWSERIFY) \
|
||||||
|
--standalone debug \
|
||||||
|
. > $@
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
@rm -rf node_modules
|
||||||
|
|
||||||
|
node_modules: package.json
|
||||||
|
@NODE_ENV= $(NPM) install
|
||||||
|
@touch node_modules
|
||||||
|
|
||||||
|
.PHONY: all install clean distclean
|
||||||
@ -0,0 +1,188 @@
|
|||||||
|
# debug
|
||||||
|
|
||||||
|
tiny node.js debugging utility modelled after node core's debugging technique.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ npm install debug
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility.
|
||||||
|
|
||||||
|
Example _app.js_:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var debug = require('debug')('http')
|
||||||
|
, http = require('http')
|
||||||
|
, name = 'My App';
|
||||||
|
|
||||||
|
// fake app
|
||||||
|
|
||||||
|
debug('booting %s', name);
|
||||||
|
|
||||||
|
http.createServer(function(req, res){
|
||||||
|
debug(req.method + ' ' + req.url);
|
||||||
|
res.end('hello\n');
|
||||||
|
}).listen(3000, function(){
|
||||||
|
debug('listening');
|
||||||
|
});
|
||||||
|
|
||||||
|
// fake worker of some kind
|
||||||
|
|
||||||
|
require('./worker');
|
||||||
|
```
|
||||||
|
|
||||||
|
Example _worker.js_:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var debug = require('debug')('worker');
|
||||||
|
|
||||||
|
setInterval(function(){
|
||||||
|
debug('doing some work');
|
||||||
|
}, 1000);
|
||||||
|
```
|
||||||
|
|
||||||
|
The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
#### Windows note
|
||||||
|
|
||||||
|
On Windows the environment variable is set using the `set` command.
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
set DEBUG=*,-not_this
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, run the program to be debugged as usual.
|
||||||
|
|
||||||
|
## Millisecond diff
|
||||||
|
|
||||||
|
When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser".
|
||||||
|
|
||||||
|
## Wildcards
|
||||||
|
|
||||||
|
The `*` character may be used as a wildcard. Suppose for example your library has debuggers named "connect:bodyParser", "connect:compress", "connect:session", instead of listing all three with `DEBUG=connect:bodyParser,connect:compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.
|
||||||
|
|
||||||
|
You can also exclude specific debuggers by prefixing them with a "-" character. For example, `DEBUG=*,-connect:*` would include all debuggers except those starting with "connect:".
|
||||||
|
|
||||||
|
## Browser support
|
||||||
|
|
||||||
|
Debug works in the browser as well, currently persisted by `localStorage`. Consider the situation shown below where you have `worker:a` and `worker:b`, and wish to debug both. Somewhere in the code on your page, include:
|
||||||
|
|
||||||
|
```js
|
||||||
|
window.myDebug = require("debug");
|
||||||
|
```
|
||||||
|
|
||||||
|
("debug" is a global object in the browser so we give this object a different name.) When your page is open in the browser, type the following in the console:
|
||||||
|
|
||||||
|
```js
|
||||||
|
myDebug.enable("worker:*")
|
||||||
|
```
|
||||||
|
|
||||||
|
Refresh the page. Debug output will continue to be sent to the console until it is disabled by typing `myDebug.disable()` in the console.
|
||||||
|
|
||||||
|
```js
|
||||||
|
a = debug('worker:a');
|
||||||
|
b = debug('worker:b');
|
||||||
|
|
||||||
|
setInterval(function(){
|
||||||
|
a('doing some work');
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
setInterval(function(){
|
||||||
|
b('doing some work');
|
||||||
|
}, 1200);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Web Inspector Colors
|
||||||
|
|
||||||
|
Colors are also enabled on "Web Inspectors" that understand the `%c` formatting
|
||||||
|
option. These are WebKit web inspectors, Firefox ([since version
|
||||||
|
31](https://hacks.mozilla.org/2014/05/editable-box-model-multiple-selection-sublime-text-keys-much-more-firefox-developer-tools-episode-31/))
|
||||||
|
and the Firebug plugin for Firefox (any version).
|
||||||
|
|
||||||
|
Colored output looks something like:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### stderr vs stdout
|
||||||
|
|
||||||
|
You can set an alternative logging method per-namespace by overriding the `log` method on a per-namespace or globally:
|
||||||
|
|
||||||
|
Example _stdout.js_:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var debug = require('debug');
|
||||||
|
var error = debug('app:error');
|
||||||
|
|
||||||
|
// by default stderr is used
|
||||||
|
error('goes to stderr!');
|
||||||
|
|
||||||
|
var log = debug('app:log');
|
||||||
|
// set this namespace to log via console.log
|
||||||
|
log.log = console.log.bind(console); // don't forget to bind to console!
|
||||||
|
log('goes to stdout');
|
||||||
|
error('still goes to stderr!');
|
||||||
|
|
||||||
|
// set all output to go via console.info
|
||||||
|
// overrides all per-namespace log settings
|
||||||
|
debug.log = console.info.bind(console);
|
||||||
|
error('now goes to stdout via console.info');
|
||||||
|
log('still goes to stdout, but via console.info now');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Save debug output to a file
|
||||||
|
|
||||||
|
You can save all debug statements to a file by piping them.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ DEBUG_FD=3 node your-app.js 3> whatever.log
|
||||||
|
```
|
||||||
|
|
||||||
|
## Authors
|
||||||
|
|
||||||
|
- TJ Holowaychuk
|
||||||
|
- Nathan Rajlich
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2014 TJ Holowaychuk <tj@vision-media.ca>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
'Software'), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "visionmedia-debug",
|
||||||
|
"main": "dist/debug.js",
|
||||||
|
"version": "2.2.0",
|
||||||
|
"homepage": "https://github.com/visionmedia/debug",
|
||||||
|
"authors": [
|
||||||
|
"TJ Holowaychuk <tj@vision-media.ca>"
|
||||||
|
],
|
||||||
|
"description": "visionmedia-debug",
|
||||||
|
"moduleType": [
|
||||||
|
"amd",
|
||||||
|
"es6",
|
||||||
|
"globals",
|
||||||
|
"node"
|
||||||
|
],
|
||||||
|
"keywords": [
|
||||||
|
"visionmedia",
|
||||||
|
"debug"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"ignore": [
|
||||||
|
"**/.*",
|
||||||
|
"node_modules",
|
||||||
|
"bower_components",
|
||||||
|
"test",
|
||||||
|
"tests"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,168 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* This is the web browser implementation of `debug()`.
|
||||||
|
*
|
||||||
|
* Expose `debug()` as the module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = module.exports = require('./debug');
|
||||||
|
exports.log = log;
|
||||||
|
exports.formatArgs = formatArgs;
|
||||||
|
exports.save = save;
|
||||||
|
exports.load = load;
|
||||||
|
exports.useColors = useColors;
|
||||||
|
exports.storage = 'undefined' != typeof chrome
|
||||||
|
&& 'undefined' != typeof chrome.storage
|
||||||
|
? chrome.storage.local
|
||||||
|
: localstorage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.colors = [
|
||||||
|
'lightseagreen',
|
||||||
|
'forestgreen',
|
||||||
|
'goldenrod',
|
||||||
|
'dodgerblue',
|
||||||
|
'darkorchid',
|
||||||
|
'crimson'
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Currently only WebKit-based Web Inspectors, Firefox >= v31,
|
||||||
|
* and the Firebug extension (any Firefox version) are known
|
||||||
|
* to support "%c" CSS customizations.
|
||||||
|
*
|
||||||
|
* TODO: add a `localStorage` variable to explicitly enable/disable colors
|
||||||
|
*/
|
||||||
|
|
||||||
|
function useColors() {
|
||||||
|
// is webkit? http://stackoverflow.com/a/16459606/376773
|
||||||
|
return ('WebkitAppearance' in document.documentElement.style) ||
|
||||||
|
// is firebug? http://stackoverflow.com/a/398120/376773
|
||||||
|
(window.console && (console.firebug || (console.exception && console.table))) ||
|
||||||
|
// is firefox >= v31?
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
|
||||||
|
(navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.formatters.j = function(v) {
|
||||||
|
return JSON.stringify(v);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colorize log arguments if enabled.
|
||||||
|
*
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function formatArgs() {
|
||||||
|
var args = arguments;
|
||||||
|
var useColors = this.useColors;
|
||||||
|
|
||||||
|
args[0] = (useColors ? '%c' : '')
|
||||||
|
+ this.namespace
|
||||||
|
+ (useColors ? ' %c' : ' ')
|
||||||
|
+ args[0]
|
||||||
|
+ (useColors ? '%c ' : ' ')
|
||||||
|
+ '+' + exports.humanize(this.diff);
|
||||||
|
|
||||||
|
if (!useColors) return args;
|
||||||
|
|
||||||
|
var c = 'color: ' + this.color;
|
||||||
|
args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1));
|
||||||
|
|
||||||
|
// the final "%c" is somewhat tricky, because there could be other
|
||||||
|
// arguments passed either before or after the %c, so we need to
|
||||||
|
// figure out the correct index to insert the CSS into
|
||||||
|
var index = 0;
|
||||||
|
var lastC = 0;
|
||||||
|
args[0].replace(/%[a-z%]/g, function(match) {
|
||||||
|
if ('%%' === match) return;
|
||||||
|
index++;
|
||||||
|
if ('%c' === match) {
|
||||||
|
// we only are interested in the *last* %c
|
||||||
|
// (the user may have provided their own)
|
||||||
|
lastC = index;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
args.splice(lastC, 0, c);
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes `console.log()` when available.
|
||||||
|
* No-op when `console.log` is not a "function".
|
||||||
|
*
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function log() {
|
||||||
|
// this hackery is required for IE8/9, where
|
||||||
|
// the `console.log` function doesn't have 'apply'
|
||||||
|
return 'object' === typeof console
|
||||||
|
&& console.log
|
||||||
|
&& Function.prototype.apply.call(console.log, console, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save `namespaces`.
|
||||||
|
*
|
||||||
|
* @param {String} namespaces
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function save(namespaces) {
|
||||||
|
try {
|
||||||
|
if (null == namespaces) {
|
||||||
|
exports.storage.removeItem('debug');
|
||||||
|
} else {
|
||||||
|
exports.storage.debug = namespaces;
|
||||||
|
}
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load `namespaces`.
|
||||||
|
*
|
||||||
|
* @return {String} returns the previously persisted debug modes
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function load() {
|
||||||
|
var r;
|
||||||
|
try {
|
||||||
|
r = exports.storage.debug;
|
||||||
|
} catch(e) {}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable namespaces listed in `localStorage.debug` initially.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.enable(load());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Localstorage attempts to return the localstorage.
|
||||||
|
*
|
||||||
|
* This is necessary because safari throws
|
||||||
|
* when a user disables cookies/localstorage
|
||||||
|
* and you attempt to access it.
|
||||||
|
*
|
||||||
|
* @return {LocalStorage}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function localstorage(){
|
||||||
|
try {
|
||||||
|
return window.localStorage;
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "debug",
|
||||||
|
"repo": "visionmedia/debug",
|
||||||
|
"description": "small debugging utility",
|
||||||
|
"version": "2.2.0",
|
||||||
|
"keywords": [
|
||||||
|
"debug",
|
||||||
|
"log",
|
||||||
|
"debugger"
|
||||||
|
],
|
||||||
|
"main": "browser.js",
|
||||||
|
"scripts": [
|
||||||
|
"browser.js",
|
||||||
|
"debug.js"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"rauchg/ms.js": "0.7.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,197 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* This is the common logic for both the Node.js and web browser
|
||||||
|
* implementations of `debug()`.
|
||||||
|
*
|
||||||
|
* Expose `debug()` as the module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = module.exports = debug;
|
||||||
|
exports.coerce = coerce;
|
||||||
|
exports.disable = disable;
|
||||||
|
exports.enable = enable;
|
||||||
|
exports.enabled = enabled;
|
||||||
|
exports.humanize = require('ms');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The currently active debug mode names, and names to skip.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.names = [];
|
||||||
|
exports.skips = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of special "%n" handling functions, for the debug "format" argument.
|
||||||
|
*
|
||||||
|
* Valid key names are a single, lowercased letter, i.e. "n".
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.formatters = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Previously assigned color.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var prevColor = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Previous log timestamp.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var prevTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select a color.
|
||||||
|
*
|
||||||
|
* @return {Number}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function selectColor() {
|
||||||
|
return exports.colors[prevColor++ % exports.colors.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a debugger with the given `namespace`.
|
||||||
|
*
|
||||||
|
* @param {String} namespace
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function debug(namespace) {
|
||||||
|
|
||||||
|
// define the `disabled` version
|
||||||
|
function disabled() {
|
||||||
|
}
|
||||||
|
disabled.enabled = false;
|
||||||
|
|
||||||
|
// define the `enabled` version
|
||||||
|
function enabled() {
|
||||||
|
|
||||||
|
var self = enabled;
|
||||||
|
|
||||||
|
// set `diff` timestamp
|
||||||
|
var curr = +new Date();
|
||||||
|
var ms = curr - (prevTime || curr);
|
||||||
|
self.diff = ms;
|
||||||
|
self.prev = prevTime;
|
||||||
|
self.curr = curr;
|
||||||
|
prevTime = curr;
|
||||||
|
|
||||||
|
// add the `color` if not set
|
||||||
|
if (null == self.useColors) self.useColors = exports.useColors();
|
||||||
|
if (null == self.color && self.useColors) self.color = selectColor();
|
||||||
|
|
||||||
|
var args = Array.prototype.slice.call(arguments);
|
||||||
|
|
||||||
|
args[0] = exports.coerce(args[0]);
|
||||||
|
|
||||||
|
if ('string' !== typeof args[0]) {
|
||||||
|
// anything else let's inspect with %o
|
||||||
|
args = ['%o'].concat(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply any `formatters` transformations
|
||||||
|
var index = 0;
|
||||||
|
args[0] = args[0].replace(/%([a-z%])/g, function(match, format) {
|
||||||
|
// if we encounter an escaped % then don't increase the array index
|
||||||
|
if (match === '%%') return match;
|
||||||
|
index++;
|
||||||
|
var formatter = exports.formatters[format];
|
||||||
|
if ('function' === typeof formatter) {
|
||||||
|
var val = args[index];
|
||||||
|
match = formatter.call(self, val);
|
||||||
|
|
||||||
|
// now we need to remove `args[index]` since it's inlined in the `format`
|
||||||
|
args.splice(index, 1);
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
});
|
||||||
|
|
||||||
|
if ('function' === typeof exports.formatArgs) {
|
||||||
|
args = exports.formatArgs.apply(self, args);
|
||||||
|
}
|
||||||
|
var logFn = enabled.log || exports.log || console.log.bind(console);
|
||||||
|
logFn.apply(self, args);
|
||||||
|
}
|
||||||
|
enabled.enabled = true;
|
||||||
|
|
||||||
|
var fn = exports.enabled(namespace) ? enabled : disabled;
|
||||||
|
|
||||||
|
fn.namespace = namespace;
|
||||||
|
|
||||||
|
return fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables a debug mode by namespaces. This can include modes
|
||||||
|
* separated by a colon and wildcards.
|
||||||
|
*
|
||||||
|
* @param {String} namespaces
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function enable(namespaces) {
|
||||||
|
exports.save(namespaces);
|
||||||
|
|
||||||
|
var split = (namespaces || '').split(/[\s,]+/);
|
||||||
|
var len = split.length;
|
||||||
|
|
||||||
|
for (var i = 0; i < len; i++) {
|
||||||
|
if (!split[i]) continue; // ignore empty strings
|
||||||
|
namespaces = split[i].replace(/\*/g, '.*?');
|
||||||
|
if (namespaces[0] === '-') {
|
||||||
|
exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
|
||||||
|
} else {
|
||||||
|
exports.names.push(new RegExp('^' + namespaces + '$'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable debug output.
|
||||||
|
*
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function disable() {
|
||||||
|
exports.enable('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given mode name is enabled, false otherwise.
|
||||||
|
*
|
||||||
|
* @param {String} name
|
||||||
|
* @return {Boolean}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function enabled(name) {
|
||||||
|
var i, len;
|
||||||
|
for (i = 0, len = exports.skips.length; i < len; i++) {
|
||||||
|
if (exports.skips[i].test(name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0, len = exports.names.length; i < len; i++) {
|
||||||
|
if (exports.names[i].test(name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coerce `val`.
|
||||||
|
*
|
||||||
|
* @param {Mixed} val
|
||||||
|
* @return {Mixed}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function coerce(val) {
|
||||||
|
if (val instanceof Error) return val.stack || val.message;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
@ -0,0 +1,209 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var tty = require('tty');
|
||||||
|
var util = require('util');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the Node.js implementation of `debug()`.
|
||||||
|
*
|
||||||
|
* Expose `debug()` as the module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = module.exports = require('./debug');
|
||||||
|
exports.log = log;
|
||||||
|
exports.formatArgs = formatArgs;
|
||||||
|
exports.save = save;
|
||||||
|
exports.load = load;
|
||||||
|
exports.useColors = useColors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.colors = [6, 2, 3, 4, 5, 1];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The file descriptor to write the `debug()` calls to.
|
||||||
|
* Set the `DEBUG_FD` env variable to override with another value. i.e.:
|
||||||
|
*
|
||||||
|
* $ DEBUG_FD=3 node script.js 3>debug.log
|
||||||
|
*/
|
||||||
|
|
||||||
|
var fd = parseInt(process.env.DEBUG_FD, 10) || 2;
|
||||||
|
var stream = 1 === fd ? process.stdout :
|
||||||
|
2 === fd ? process.stderr :
|
||||||
|
createWritableStdioStream(fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is stdout a TTY? Colored output is enabled when `true`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function useColors() {
|
||||||
|
var debugColors = (process.env.DEBUG_COLORS || '').trim().toLowerCase();
|
||||||
|
if (0 === debugColors.length) {
|
||||||
|
return tty.isatty(fd);
|
||||||
|
} else {
|
||||||
|
return '0' !== debugColors
|
||||||
|
&& 'no' !== debugColors
|
||||||
|
&& 'false' !== debugColors
|
||||||
|
&& 'disabled' !== debugColors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map %o to `util.inspect()`, since Node doesn't do that out of the box.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var inspect = (4 === util.inspect.length ?
|
||||||
|
// node <= 0.8.x
|
||||||
|
function (v, colors) {
|
||||||
|
return util.inspect(v, void 0, void 0, colors);
|
||||||
|
} :
|
||||||
|
// node > 0.8.x
|
||||||
|
function (v, colors) {
|
||||||
|
return util.inspect(v, { colors: colors });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
exports.formatters.o = function(v) {
|
||||||
|
return inspect(v, this.useColors)
|
||||||
|
.replace(/\s*\n\s*/g, ' ');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds ANSI color escape codes if enabled.
|
||||||
|
*
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function formatArgs() {
|
||||||
|
var args = arguments;
|
||||||
|
var useColors = this.useColors;
|
||||||
|
var name = this.namespace;
|
||||||
|
|
||||||
|
if (useColors) {
|
||||||
|
var c = this.color;
|
||||||
|
|
||||||
|
args[0] = ' \u001b[3' + c + ';1m' + name + ' '
|
||||||
|
+ '\u001b[0m'
|
||||||
|
+ args[0] + '\u001b[3' + c + 'm'
|
||||||
|
+ ' +' + exports.humanize(this.diff) + '\u001b[0m';
|
||||||
|
} else {
|
||||||
|
args[0] = new Date().toUTCString()
|
||||||
|
+ ' ' + name + ' ' + args[0];
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes `console.error()` with the specified arguments.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function log() {
|
||||||
|
return stream.write(util.format.apply(this, arguments) + '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save `namespaces`.
|
||||||
|
*
|
||||||
|
* @param {String} namespaces
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function save(namespaces) {
|
||||||
|
if (null == namespaces) {
|
||||||
|
// If you set a process.env field to null or undefined, it gets cast to the
|
||||||
|
// string 'null' or 'undefined'. Just delete instead.
|
||||||
|
delete process.env.DEBUG;
|
||||||
|
} else {
|
||||||
|
process.env.DEBUG = namespaces;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load `namespaces`.
|
||||||
|
*
|
||||||
|
* @return {String} returns the previously persisted debug modes
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function load() {
|
||||||
|
return process.env.DEBUG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copied from `node/src/node.js`.
|
||||||
|
*
|
||||||
|
* XXX: It's lame that node doesn't expose this API out-of-the-box. It also
|
||||||
|
* relies on the undocumented `tty_wrap.guessHandleType()` which is also lame.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function createWritableStdioStream (fd) {
|
||||||
|
var stream;
|
||||||
|
var tty_wrap = process.binding('tty_wrap');
|
||||||
|
|
||||||
|
// Note stream._type is used for test-module-load-list.js
|
||||||
|
|
||||||
|
switch (tty_wrap.guessHandleType(fd)) {
|
||||||
|
case 'TTY':
|
||||||
|
stream = new tty.WriteStream(fd);
|
||||||
|
stream._type = 'tty';
|
||||||
|
|
||||||
|
// Hack to have stream not keep the event loop alive.
|
||||||
|
// See https://github.com/joyent/node/issues/1726
|
||||||
|
if (stream._handle && stream._handle.unref) {
|
||||||
|
stream._handle.unref();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'FILE':
|
||||||
|
var fs = require('fs');
|
||||||
|
stream = new fs.SyncWriteStream(fd, { autoClose: false });
|
||||||
|
stream._type = 'fs';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'PIPE':
|
||||||
|
case 'TCP':
|
||||||
|
var net = require('net');
|
||||||
|
stream = new net.Socket({
|
||||||
|
fd: fd,
|
||||||
|
readable: false,
|
||||||
|
writable: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// FIXME Should probably have an option in net.Socket to create a
|
||||||
|
// stream from an existing fd which is writable only. But for now
|
||||||
|
// we'll just add this hack and set the `readable` member to false.
|
||||||
|
// Test: ./node test/fixtures/echo.js < /etc/passwd
|
||||||
|
stream.readable = false;
|
||||||
|
stream.read = null;
|
||||||
|
stream._type = 'pipe';
|
||||||
|
|
||||||
|
// FIXME Hack to have stream not keep the event loop alive.
|
||||||
|
// See https://github.com/joyent/node/issues/1726
|
||||||
|
if (stream._handle && stream._handle.unref) {
|
||||||
|
stream._handle.unref();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Probably an error on in uv_guess_handle()
|
||||||
|
throw new Error('Implement me. Unknown stream file type!');
|
||||||
|
}
|
||||||
|
|
||||||
|
// For supporting legacy API we put the FD here.
|
||||||
|
stream.fd = fd;
|
||||||
|
|
||||||
|
stream._isStdio = true;
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable namespaces listed in `process.env.DEBUG` initially.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.enable(load());
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
node_modules
|
||||||
|
test
|
||||||
|
History.md
|
||||||
|
Makefile
|
||||||
|
component.json
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
|
||||||
|
0.7.1 / 2015-04-20
|
||||||
|
==================
|
||||||
|
|
||||||
|
* prevent extraordinary long inputs (@evilpacket)
|
||||||
|
* Fixed broken readme link
|
||||||
|
|
||||||
|
0.7.0 / 2014-11-24
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add time abbreviations, updated tests and readme for the new units
|
||||||
|
* fix example in the readme.
|
||||||
|
* add LICENSE file
|
||||||
|
|
||||||
|
0.6.2 / 2013-12-05
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Adding repository section to package.json to suppress warning from NPM.
|
||||||
|
|
||||||
|
0.6.1 / 2013-05-10
|
||||||
|
==================
|
||||||
|
|
||||||
|
* fix singularization [visionmedia]
|
||||||
|
|
||||||
|
0.6.0 / 2013-03-15
|
||||||
|
==================
|
||||||
|
|
||||||
|
* fix minutes
|
||||||
|
|
||||||
|
0.5.1 / 2013-02-24
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add component namespace
|
||||||
|
|
||||||
|
0.5.0 / 2012-11-09
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add short formatting as default and .long option
|
||||||
|
* add .license property to component.json
|
||||||
|
* add version to component.json
|
||||||
|
|
||||||
|
0.4.0 / 2012-10-22
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add rounding to fix crazy decimals
|
||||||
|
|
||||||
|
0.3.0 / 2012-09-07
|
||||||
|
==================
|
||||||
|
|
||||||
|
* fix `ms(<String>)` [visionmedia]
|
||||||
|
|
||||||
|
0.2.0 / 2012-09-03
|
||||||
|
==================
|
||||||
|
|
||||||
|
* add component.json [visionmedia]
|
||||||
|
* add days support [visionmedia]
|
||||||
|
* add hours support [visionmedia]
|
||||||
|
* add minutes support [visionmedia]
|
||||||
|
* add seconds support [visionmedia]
|
||||||
|
* add ms string support [visionmedia]
|
||||||
|
* refactor tests to facilitate ms(number) [visionmedia]
|
||||||
|
|
||||||
|
0.1.0 / 2012-03-07
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Initial release
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Guillermo Rauch <rauchg@gmail.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
# ms.js: miliseconds conversion utility
|
||||||
|
|
||||||
|
```js
|
||||||
|
ms('2 days') // 172800000
|
||||||
|
ms('1d') // 86400000
|
||||||
|
ms('10h') // 36000000
|
||||||
|
ms('2.5 hrs') // 9000000
|
||||||
|
ms('2h') // 7200000
|
||||||
|
ms('1m') // 60000
|
||||||
|
ms('5s') // 5000
|
||||||
|
ms('100') // 100
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
ms(60000) // "1m"
|
||||||
|
ms(2 * 60000) // "2m"
|
||||||
|
ms(ms('10 hours')) // "10h"
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
ms(60000, { long: true }) // "1 minute"
|
||||||
|
ms(2 * 60000, { long: true }) // "2 minutes"
|
||||||
|
ms(ms('10 hours'), { long: true }) // "10 hours"
|
||||||
|
```
|
||||||
|
|
||||||
|
- Node/Browser compatible. Published as [`ms`](https://www.npmjs.org/package/ms) in [NPM](http://nodejs.org/download).
|
||||||
|
- If a number is supplied to `ms`, a string with a unit is returned.
|
||||||
|
- If a string that contains the number is supplied, it returns it as
|
||||||
|
a number (e.g: it returns `100` for `'100'`).
|
||||||
|
- If you pass a string with a number and a valid unit, the number of
|
||||||
|
equivalent ms is returned.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
@ -0,0 +1,125 @@
|
|||||||
|
/**
|
||||||
|
* Helpers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var s = 1000;
|
||||||
|
var m = s * 60;
|
||||||
|
var h = m * 60;
|
||||||
|
var d = h * 24;
|
||||||
|
var y = d * 365.25;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse or format the given `val`.
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
*
|
||||||
|
* - `long` verbose formatting [false]
|
||||||
|
*
|
||||||
|
* @param {String|Number} val
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {String|Number}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function(val, options){
|
||||||
|
options = options || {};
|
||||||
|
if ('string' == typeof val) return parse(val);
|
||||||
|
return options.long
|
||||||
|
? long(val)
|
||||||
|
: short(val);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the given `str` and return milliseconds.
|
||||||
|
*
|
||||||
|
* @param {String} str
|
||||||
|
* @return {Number}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function parse(str) {
|
||||||
|
str = '' + str;
|
||||||
|
if (str.length > 10000) return;
|
||||||
|
var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str);
|
||||||
|
if (!match) return;
|
||||||
|
var n = parseFloat(match[1]);
|
||||||
|
var type = (match[2] || 'ms').toLowerCase();
|
||||||
|
switch (type) {
|
||||||
|
case 'years':
|
||||||
|
case 'year':
|
||||||
|
case 'yrs':
|
||||||
|
case 'yr':
|
||||||
|
case 'y':
|
||||||
|
return n * y;
|
||||||
|
case 'days':
|
||||||
|
case 'day':
|
||||||
|
case 'd':
|
||||||
|
return n * d;
|
||||||
|
case 'hours':
|
||||||
|
case 'hour':
|
||||||
|
case 'hrs':
|
||||||
|
case 'hr':
|
||||||
|
case 'h':
|
||||||
|
return n * h;
|
||||||
|
case 'minutes':
|
||||||
|
case 'minute':
|
||||||
|
case 'mins':
|
||||||
|
case 'min':
|
||||||
|
case 'm':
|
||||||
|
return n * m;
|
||||||
|
case 'seconds':
|
||||||
|
case 'second':
|
||||||
|
case 'secs':
|
||||||
|
case 'sec':
|
||||||
|
case 's':
|
||||||
|
return n * s;
|
||||||
|
case 'milliseconds':
|
||||||
|
case 'millisecond':
|
||||||
|
case 'msecs':
|
||||||
|
case 'msec':
|
||||||
|
case 'ms':
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Short format for `ms`.
|
||||||
|
*
|
||||||
|
* @param {Number} ms
|
||||||
|
* @return {String}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function short(ms) {
|
||||||
|
if (ms >= d) return Math.round(ms / d) + 'd';
|
||||||
|
if (ms >= h) return Math.round(ms / h) + 'h';
|
||||||
|
if (ms >= m) return Math.round(ms / m) + 'm';
|
||||||
|
if (ms >= s) return Math.round(ms / s) + 's';
|
||||||
|
return ms + 'ms';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Long format for `ms`.
|
||||||
|
*
|
||||||
|
* @param {Number} ms
|
||||||
|
* @return {String}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function long(ms) {
|
||||||
|
return plural(ms, d, 'day')
|
||||||
|
|| plural(ms, h, 'hour')
|
||||||
|
|| plural(ms, m, 'minute')
|
||||||
|
|| plural(ms, s, 'second')
|
||||||
|
|| ms + ' ms';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pluralization helper.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function plural(ms, n, name) {
|
||||||
|
if (ms < n) return;
|
||||||
|
if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name;
|
||||||
|
return Math.ceil(ms / n) + ' ' + name + 's';
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"name": "ms",
|
||||||
|
"version": "0.7.1",
|
||||||
|
"description": "Tiny ms conversion utility",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/guille/ms.js.git"
|
||||||
|
},
|
||||||
|
"main": "./index",
|
||||||
|
"devDependencies": {
|
||||||
|
"mocha": "*",
|
||||||
|
"expect.js": "*",
|
||||||
|
"serve": "*"
|
||||||
|
},
|
||||||
|
"component": {
|
||||||
|
"scripts": {
|
||||||
|
"ms/index.js": "index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gitHead": "713dcf26d9e6fd9dbc95affe7eff9783b7f1b909",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/guille/ms.js/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/guille/ms.js",
|
||||||
|
"_id": "ms@0.7.1",
|
||||||
|
"scripts": {},
|
||||||
|
"_shasum": "9cd13c03adbff25b65effde7ce864ee952017098",
|
||||||
|
"_from": "ms@0.7.1",
|
||||||
|
"_npmVersion": "2.7.5",
|
||||||
|
"_nodeVersion": "0.12.2",
|
||||||
|
"_npmUser": {
|
||||||
|
"name": "rauchg",
|
||||||
|
"email": "rauchg@gmail.com"
|
||||||
|
},
|
||||||
|
"maintainers": [
|
||||||
|
{
|
||||||
|
"name": "rauchg",
|
||||||
|
"email": "rauchg@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dist": {
|
||||||
|
"shasum": "9cd13c03adbff25b65effde7ce864ee952017098",
|
||||||
|
"tarball": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz"
|
||||||
|
},
|
||||||
|
"directories": {},
|
||||||
|
"_resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
|
||||||
|
"readme": "ERROR: No README data found!"
|
||||||
|
}
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"name": "debug",
|
||||||
|
"version": "2.2.0",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/visionmedia/debug.git"
|
||||||
|
},
|
||||||
|
"description": "small debugging utility",
|
||||||
|
"keywords": [
|
||||||
|
"debug",
|
||||||
|
"log",
|
||||||
|
"debugger"
|
||||||
|
],
|
||||||
|
"author": {
|
||||||
|
"name": "TJ Holowaychuk",
|
||||||
|
"email": "tj@vision-media.ca"
|
||||||
|
},
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Nathan Rajlich",
|
||||||
|
"email": "nathan@tootallnate.net",
|
||||||
|
"url": "http://n8.io"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "0.7.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"browserify": "9.0.3",
|
||||||
|
"mocha": "*"
|
||||||
|
},
|
||||||
|
"main": "./node.js",
|
||||||
|
"browser": "./browser.js",
|
||||||
|
"component": {
|
||||||
|
"scripts": {
|
||||||
|
"debug/index.js": "browser.js",
|
||||||
|
"debug/debug.js": "debug.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gitHead": "b38458422b5aa8aa6d286b10dfe427e8a67e2b35",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/visionmedia/debug/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/visionmedia/debug",
|
||||||
|
"_id": "debug@2.2.0",
|
||||||
|
"scripts": {},
|
||||||
|
"_shasum": "f87057e995b1a1f6ae6a4960664137bc56f039da",
|
||||||
|
"_from": "debug@>=2.2.0 <2.3.0",
|
||||||
|
"_npmVersion": "2.7.4",
|
||||||
|
"_nodeVersion": "0.12.2",
|
||||||
|
"_npmUser": {
|
||||||
|
"name": "tootallnate",
|
||||||
|
"email": "nathan@tootallnate.net"
|
||||||
|
},
|
||||||
|
"maintainers": [
|
||||||
|
{
|
||||||
|
"name": "tjholowaychuk",
|
||||||
|
"email": "tj@vision-media.ca"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tootallnate",
|
||||||
|
"email": "nathan@tootallnate.net"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dist": {
|
||||||
|
"shasum": "f87057e995b1a1f6ae6a4960664137bc56f039da",
|
||||||
|
"tarball": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz"
|
||||||
|
},
|
||||||
|
"directories": {},
|
||||||
|
"_resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
|
||||||
|
"readme": "ERROR: No README data found!"
|
||||||
|
}
|
||||||
@ -0,0 +1,84 @@
|
|||||||
|
1.1.0 / 2015-09-14
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Enable strict mode in more places
|
||||||
|
* Support io.js 3.x
|
||||||
|
* Support io.js 2.x
|
||||||
|
* Support web browser loading
|
||||||
|
- Requires bundler like Browserify or webpack
|
||||||
|
|
||||||
|
1.0.1 / 2015-04-07
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix `TypeError`s when under `'use strict'` code
|
||||||
|
* Fix useless type name on auto-generated messages
|
||||||
|
* Support io.js 1.x
|
||||||
|
* Support Node.js 0.12
|
||||||
|
|
||||||
|
1.0.0 / 2014-09-17
|
||||||
|
==================
|
||||||
|
|
||||||
|
* No changes
|
||||||
|
|
||||||
|
0.4.5 / 2014-09-09
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Improve call speed to functions using the function wrapper
|
||||||
|
* Support Node.js 0.6
|
||||||
|
|
||||||
|
0.4.4 / 2014-07-27
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Work-around v8 generating empty stack traces
|
||||||
|
|
||||||
|
0.4.3 / 2014-07-26
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix exception when global `Error.stackTraceLimit` is too low
|
||||||
|
|
||||||
|
0.4.2 / 2014-07-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Correct call site for wrapped functions and properties
|
||||||
|
|
||||||
|
0.4.1 / 2014-07-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Improve automatic message generation for function properties
|
||||||
|
|
||||||
|
0.4.0 / 2014-07-19
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `TRACE_DEPRECATION` environment variable
|
||||||
|
* Remove non-standard grey color from color output
|
||||||
|
* Support `--no-deprecation` argument
|
||||||
|
* Support `--trace-deprecation` argument
|
||||||
|
* Support `deprecate.property(fn, prop, message)`
|
||||||
|
|
||||||
|
0.3.0 / 2014-06-16
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `NO_DEPRECATION` environment variable
|
||||||
|
|
||||||
|
0.2.0 / 2014-06-15
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `deprecate.property(obj, prop, message)`
|
||||||
|
* Remove `supports-color` dependency for node.js 0.8
|
||||||
|
|
||||||
|
0.1.0 / 2014-06-15
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `deprecate.function(fn, message)`
|
||||||
|
* Add `process.on('deprecation', fn)` emitter
|
||||||
|
* Automatically generate message when omitted from `deprecate()`
|
||||||
|
|
||||||
|
0.0.1 / 2014-06-15
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix warning for dynamic calls at singe call site
|
||||||
|
|
||||||
|
0.0.0 / 2014-06-15
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Initial implementation
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2014-2015 Douglas Christopher Wilson
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
'Software'), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
@ -0,0 +1,281 @@
|
|||||||
|
# depd
|
||||||
|
|
||||||
|
[![NPM Version][npm-version-image]][npm-url]
|
||||||
|
[![NPM Downloads][npm-downloads-image]][npm-url]
|
||||||
|
[![Node.js Version][node-image]][node-url]
|
||||||
|
[![Linux Build][travis-image]][travis-url]
|
||||||
|
[![Windows Build][appveyor-image]][appveyor-url]
|
||||||
|
[![Coverage Status][coveralls-image]][coveralls-url]
|
||||||
|
[![Gratipay][gratipay-image]][gratipay-url]
|
||||||
|
|
||||||
|
Deprecate all the things
|
||||||
|
|
||||||
|
> With great modules comes great responsibility; mark things deprecated!
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
This module is installed directly using `npm`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ npm install depd
|
||||||
|
```
|
||||||
|
|
||||||
|
This module can also be bundled with systems like
|
||||||
|
[Browserify](http://browserify.org/) or [webpack](https://webpack.github.io/),
|
||||||
|
though by default this module will alter it's API to no longer display or
|
||||||
|
track deprecations.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
```js
|
||||||
|
var deprecate = require('depd')('my-module')
|
||||||
|
```
|
||||||
|
|
||||||
|
This library allows you to display deprecation messages to your users.
|
||||||
|
This library goes above and beyond with deprecation warnings by
|
||||||
|
introspection of the call stack (but only the bits that it is interested
|
||||||
|
in).
|
||||||
|
|
||||||
|
Instead of just warning on the first invocation of a deprecated
|
||||||
|
function and never again, this module will warn on the first invocation
|
||||||
|
of a deprecated function per unique call site, making it ideal to alert
|
||||||
|
users of all deprecated uses across the code base, rather than just
|
||||||
|
whatever happens to execute first.
|
||||||
|
|
||||||
|
The deprecation warnings from this module also include the file and line
|
||||||
|
information for the call into the module that the deprecated function was
|
||||||
|
in.
|
||||||
|
|
||||||
|
**NOTE** this library has a similar interface to the `debug` module, and
|
||||||
|
this module uses the calling file to get the boundary for the call stacks,
|
||||||
|
so you should always create a new `deprecate` object in each file and not
|
||||||
|
within some central file.
|
||||||
|
|
||||||
|
### depd(namespace)
|
||||||
|
|
||||||
|
Create a new deprecate function that uses the given namespace name in the
|
||||||
|
messages and will display the call site prior to the stack entering the
|
||||||
|
file this function was called from. It is highly suggested you use the
|
||||||
|
name of your module as the namespace.
|
||||||
|
|
||||||
|
### deprecate(message)
|
||||||
|
|
||||||
|
Call this function from deprecated code to display a deprecation message.
|
||||||
|
This message will appear once per unique caller site. Caller site is the
|
||||||
|
first call site in the stack in a different file from the caller of this
|
||||||
|
function.
|
||||||
|
|
||||||
|
If the message is omitted, a message is generated for you based on the site
|
||||||
|
of the `deprecate()` call and will display the name of the function called,
|
||||||
|
similar to the name displayed in a stack trace.
|
||||||
|
|
||||||
|
### deprecate.function(fn, message)
|
||||||
|
|
||||||
|
Call this function to wrap a given function in a deprecation message on any
|
||||||
|
call to the function. An optional message can be supplied to provide a custom
|
||||||
|
message.
|
||||||
|
|
||||||
|
### deprecate.property(obj, prop, message)
|
||||||
|
|
||||||
|
Call this function to wrap a given property on object in a deprecation message
|
||||||
|
on any accessing or setting of the property. An optional message can be supplied
|
||||||
|
to provide a custom message.
|
||||||
|
|
||||||
|
The method must be called on the object where the property belongs (not
|
||||||
|
inherited from the prototype).
|
||||||
|
|
||||||
|
If the property is a data descriptor, it will be converted to an accessor
|
||||||
|
descriptor in order to display the deprecation message.
|
||||||
|
|
||||||
|
### process.on('deprecation', fn)
|
||||||
|
|
||||||
|
This module will allow easy capturing of deprecation errors by emitting the
|
||||||
|
errors as the type "deprecation" on the global `process`. If there are no
|
||||||
|
listeners for this type, the errors are written to STDERR as normal, but if
|
||||||
|
there are any listeners, nothing will be written to STDERR and instead only
|
||||||
|
emitted. From there, you can write the errors in a different format or to a
|
||||||
|
logging source.
|
||||||
|
|
||||||
|
The error represents the deprecation and is emitted only once with the same
|
||||||
|
rules as writing to STDERR. The error has the following properties:
|
||||||
|
|
||||||
|
- `message` - This is the message given by the library
|
||||||
|
- `name` - This is always `'DeprecationError'`
|
||||||
|
- `namespace` - This is the namespace the deprecation came from
|
||||||
|
- `stack` - This is the stack of the call to the deprecated thing
|
||||||
|
|
||||||
|
Example `error.stack` output:
|
||||||
|
|
||||||
|
```
|
||||||
|
DeprecationError: my-cool-module deprecated oldfunction
|
||||||
|
at Object.<anonymous> ([eval]-wrapper:6:22)
|
||||||
|
at Module._compile (module.js:456:26)
|
||||||
|
at evalScript (node.js:532:25)
|
||||||
|
at startup (node.js:80:7)
|
||||||
|
at node.js:902:3
|
||||||
|
```
|
||||||
|
|
||||||
|
### process.env.NO_DEPRECATION
|
||||||
|
|
||||||
|
As a user of modules that are deprecated, the environment variable `NO_DEPRECATION`
|
||||||
|
is provided as a quick solution to silencing deprecation warnings from being
|
||||||
|
output. The format of this is similar to that of `DEBUG`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ NO_DEPRECATION=my-module,othermod node app.js
|
||||||
|
```
|
||||||
|
|
||||||
|
This will suppress deprecations from being output for "my-module" and "othermod".
|
||||||
|
The value is a list of comma-separated namespaces. To suppress every warning
|
||||||
|
across all namespaces, use the value `*` for a namespace.
|
||||||
|
|
||||||
|
Providing the argument `--no-deprecation` to the `node` executable will suppress
|
||||||
|
all deprecations (only available in Node.js 0.8 or higher).
|
||||||
|
|
||||||
|
**NOTE** This will not suppress the deperecations given to any "deprecation"
|
||||||
|
event listeners, just the output to STDERR.
|
||||||
|
|
||||||
|
### process.env.TRACE_DEPRECATION
|
||||||
|
|
||||||
|
As a user of modules that are deprecated, the environment variable `TRACE_DEPRECATION`
|
||||||
|
is provided as a solution to getting more detailed location information in deprecation
|
||||||
|
warnings by including the entire stack trace. The format of this is the same as
|
||||||
|
`NO_DEPRECATION`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ TRACE_DEPRECATION=my-module,othermod node app.js
|
||||||
|
```
|
||||||
|
|
||||||
|
This will include stack traces for deprecations being output for "my-module" and
|
||||||
|
"othermod". The value is a list of comma-separated namespaces. To trace every
|
||||||
|
warning across all namespaces, use the value `*` for a namespace.
|
||||||
|
|
||||||
|
Providing the argument `--trace-deprecation` to the `node` executable will trace
|
||||||
|
all deprecations (only available in Node.js 0.8 or higher).
|
||||||
|
|
||||||
|
**NOTE** This will not trace the deperecations silenced by `NO_DEPRECATION`.
|
||||||
|
|
||||||
|
## Display
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
When a user calls a function in your library that you mark deprecated, they
|
||||||
|
will see the following written to STDERR (in the given colors, similar colors
|
||||||
|
and layout to the `debug` module):
|
||||||
|
|
||||||
|
```
|
||||||
|
bright cyan bright yellow
|
||||||
|
| | reset cyan
|
||||||
|
| | | |
|
||||||
|
▼ ▼ ▼ ▼
|
||||||
|
my-cool-module deprecated oldfunction [eval]-wrapper:6:22
|
||||||
|
▲ ▲ ▲ ▲
|
||||||
|
| | | |
|
||||||
|
namespace | | location of mycoolmod.oldfunction() call
|
||||||
|
| deprecation message
|
||||||
|
the word "deprecated"
|
||||||
|
```
|
||||||
|
|
||||||
|
If the user redirects their STDERR to a file or somewhere that does not support
|
||||||
|
colors, they see (similar layout to the `debug` module):
|
||||||
|
|
||||||
|
```
|
||||||
|
Sun, 15 Jun 2014 05:21:37 GMT my-cool-module deprecated oldfunction at [eval]-wrapper:6:22
|
||||||
|
▲ ▲ ▲ ▲ ▲
|
||||||
|
| | | | |
|
||||||
|
timestamp of message namespace | | location of mycoolmod.oldfunction() call
|
||||||
|
| deprecation message
|
||||||
|
the word "deprecated"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Deprecating all calls to a function
|
||||||
|
|
||||||
|
This will display a deprecated message about "oldfunction" being deprecated
|
||||||
|
from "my-module" on STDERR.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var deprecate = require('depd')('my-cool-module')
|
||||||
|
|
||||||
|
// message automatically derived from function name
|
||||||
|
// Object.oldfunction
|
||||||
|
exports.oldfunction = deprecate.function(function oldfunction() {
|
||||||
|
// all calls to function are deprecated
|
||||||
|
})
|
||||||
|
|
||||||
|
// specific message
|
||||||
|
exports.oldfunction = deprecate.function(function () {
|
||||||
|
// all calls to function are deprecated
|
||||||
|
}, 'oldfunction')
|
||||||
|
```
|
||||||
|
|
||||||
|
### Conditionally deprecating a function call
|
||||||
|
|
||||||
|
This will display a deprecated message about "weirdfunction" being deprecated
|
||||||
|
from "my-module" on STDERR when called with less than 2 arguments.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var deprecate = require('depd')('my-cool-module')
|
||||||
|
|
||||||
|
exports.weirdfunction = function () {
|
||||||
|
if (arguments.length < 2) {
|
||||||
|
// calls with 0 or 1 args are deprecated
|
||||||
|
deprecate('weirdfunction args < 2')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
When calling `deprecate` as a function, the warning is counted per call site
|
||||||
|
within your own module, so you can display different deprecations depending
|
||||||
|
on different situations and the users will still get all the warnings:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var deprecate = require('depd')('my-cool-module')
|
||||||
|
|
||||||
|
exports.weirdfunction = function () {
|
||||||
|
if (arguments.length < 2) {
|
||||||
|
// calls with 0 or 1 args are deprecated
|
||||||
|
deprecate('weirdfunction args < 2')
|
||||||
|
} else if (typeof arguments[0] !== 'string') {
|
||||||
|
// calls with non-string first argument are deprecated
|
||||||
|
deprecate('weirdfunction non-string first arg')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deprecating property access
|
||||||
|
|
||||||
|
This will display a deprecated message about "oldprop" being deprecated
|
||||||
|
from "my-module" on STDERR when accessed. A deprecation will be displayed
|
||||||
|
when setting the value and when getting the value.
|
||||||
|
|
||||||
|
```js
|
||||||
|
var deprecate = require('depd')('my-cool-module')
|
||||||
|
|
||||||
|
exports.oldprop = 'something'
|
||||||
|
|
||||||
|
// message automatically derives from property name
|
||||||
|
deprecate.property(exports, 'oldprop')
|
||||||
|
|
||||||
|
// explicit message
|
||||||
|
deprecate.property(exports, 'oldprop', 'oldprop >= 0.10')
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
||||||
|
|
||||||
|
[npm-version-image]: https://img.shields.io/npm/v/depd.svg
|
||||||
|
[npm-downloads-image]: https://img.shields.io/npm/dm/depd.svg
|
||||||
|
[npm-url]: https://npmjs.org/package/depd
|
||||||
|
[travis-image]: https://img.shields.io/travis/dougwilson/nodejs-depd/master.svg?label=linux
|
||||||
|
[travis-url]: https://travis-ci.org/dougwilson/nodejs-depd
|
||||||
|
[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/nodejs-depd/master.svg?label=windows
|
||||||
|
[appveyor-url]: https://ci.appveyor.com/project/dougwilson/nodejs-depd
|
||||||
|
[coveralls-image]: https://img.shields.io/coveralls/dougwilson/nodejs-depd/master.svg
|
||||||
|
[coveralls-url]: https://coveralls.io/r/dougwilson/nodejs-depd?branch=master
|
||||||
|
[node-image]: https://img.shields.io/node/v/depd.svg
|
||||||
|
[node-url]: http://nodejs.org/download/
|
||||||
|
[gratipay-image]: https://img.shields.io/gratipay/dougwilson.svg
|
||||||
|
[gratipay-url]: https://www.gratipay.com/dougwilson/
|
||||||
@ -0,0 +1,521 @@
|
|||||||
|
/*!
|
||||||
|
* depd
|
||||||
|
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var callSiteToString = require('./lib/compat').callSiteToString
|
||||||
|
var eventListenerCount = require('./lib/compat').eventListenerCount
|
||||||
|
var relative = require('path').relative
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = depd
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path to base files on.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var basePath = process.cwd()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if namespace is contained in the string.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function containsNamespace(str, namespace) {
|
||||||
|
var val = str.split(/[ ,]+/)
|
||||||
|
|
||||||
|
namespace = String(namespace).toLowerCase()
|
||||||
|
|
||||||
|
for (var i = 0 ; i < val.length; i++) {
|
||||||
|
if (!(str = val[i])) continue;
|
||||||
|
|
||||||
|
// namespace contained
|
||||||
|
if (str === '*' || str.toLowerCase() === namespace) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a data descriptor to accessor descriptor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function convertDataDescriptorToAccessor(obj, prop, message) {
|
||||||
|
var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
|
||||||
|
var value = descriptor.value
|
||||||
|
|
||||||
|
descriptor.get = function getter() { return value }
|
||||||
|
|
||||||
|
if (descriptor.writable) {
|
||||||
|
descriptor.set = function setter(val) { return value = val }
|
||||||
|
}
|
||||||
|
|
||||||
|
delete descriptor.value
|
||||||
|
delete descriptor.writable
|
||||||
|
|
||||||
|
Object.defineProperty(obj, prop, descriptor)
|
||||||
|
|
||||||
|
return descriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create arguments string to keep arity.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function createArgumentsString(arity) {
|
||||||
|
var str = ''
|
||||||
|
|
||||||
|
for (var i = 0; i < arity; i++) {
|
||||||
|
str += ', arg' + i
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.substr(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create stack string from stack.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function createStackString(stack) {
|
||||||
|
var str = this.name + ': ' + this.namespace
|
||||||
|
|
||||||
|
if (this.message) {
|
||||||
|
str += ' deprecated ' + this.message
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < stack.length; i++) {
|
||||||
|
str += '\n at ' + callSiteToString(stack[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create deprecate for namespace in caller.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function depd(namespace) {
|
||||||
|
if (!namespace) {
|
||||||
|
throw new TypeError('argument namespace is required')
|
||||||
|
}
|
||||||
|
|
||||||
|
var stack = getStack()
|
||||||
|
var site = callSiteLocation(stack[1])
|
||||||
|
var file = site[0]
|
||||||
|
|
||||||
|
function deprecate(message) {
|
||||||
|
// call to self as log
|
||||||
|
log.call(deprecate, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
deprecate._file = file
|
||||||
|
deprecate._ignored = isignored(namespace)
|
||||||
|
deprecate._namespace = namespace
|
||||||
|
deprecate._traced = istraced(namespace)
|
||||||
|
deprecate._warned = Object.create(null)
|
||||||
|
|
||||||
|
deprecate.function = wrapfunction
|
||||||
|
deprecate.property = wrapproperty
|
||||||
|
|
||||||
|
return deprecate
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if namespace is ignored.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isignored(namespace) {
|
||||||
|
/* istanbul ignore next: tested in a child processs */
|
||||||
|
if (process.noDeprecation) {
|
||||||
|
// --no-deprecation support
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var str = process.env.NO_DEPRECATION || ''
|
||||||
|
|
||||||
|
// namespace ignored
|
||||||
|
return containsNamespace(str, namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if namespace is traced.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function istraced(namespace) {
|
||||||
|
/* istanbul ignore next: tested in a child processs */
|
||||||
|
if (process.traceDeprecation) {
|
||||||
|
// --trace-deprecation support
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var str = process.env.TRACE_DEPRECATION || ''
|
||||||
|
|
||||||
|
// namespace traced
|
||||||
|
return containsNamespace(str, namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display deprecation message.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function log(message, site) {
|
||||||
|
var haslisteners = eventListenerCount(process, 'deprecation') !== 0
|
||||||
|
|
||||||
|
// abort early if no destination
|
||||||
|
if (!haslisteners && this._ignored) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var caller
|
||||||
|
var callFile
|
||||||
|
var callSite
|
||||||
|
var i = 0
|
||||||
|
var seen = false
|
||||||
|
var stack = getStack()
|
||||||
|
var file = this._file
|
||||||
|
|
||||||
|
if (site) {
|
||||||
|
// provided site
|
||||||
|
callSite = callSiteLocation(stack[1])
|
||||||
|
callSite.name = site.name
|
||||||
|
file = callSite[0]
|
||||||
|
} else {
|
||||||
|
// get call site
|
||||||
|
i = 2
|
||||||
|
site = callSiteLocation(stack[i])
|
||||||
|
callSite = site
|
||||||
|
}
|
||||||
|
|
||||||
|
// get caller of deprecated thing in relation to file
|
||||||
|
for (; i < stack.length; i++) {
|
||||||
|
caller = callSiteLocation(stack[i])
|
||||||
|
callFile = caller[0]
|
||||||
|
|
||||||
|
if (callFile === file) {
|
||||||
|
seen = true
|
||||||
|
} else if (callFile === this._file) {
|
||||||
|
file = this._file
|
||||||
|
} else if (seen) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var key = caller
|
||||||
|
? site.join(':') + '__' + caller.join(':')
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
if (key !== undefined && key in this._warned) {
|
||||||
|
// already warned
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this._warned[key] = true
|
||||||
|
|
||||||
|
// generate automatic message from call site
|
||||||
|
if (!message) {
|
||||||
|
message = callSite === site || !callSite.name
|
||||||
|
? defaultMessage(site)
|
||||||
|
: defaultMessage(callSite)
|
||||||
|
}
|
||||||
|
|
||||||
|
// emit deprecation if listeners exist
|
||||||
|
if (haslisteners) {
|
||||||
|
var err = DeprecationError(this._namespace, message, stack.slice(i))
|
||||||
|
process.emit('deprecation', err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// format and write message
|
||||||
|
var format = process.stderr.isTTY
|
||||||
|
? formatColor
|
||||||
|
: formatPlain
|
||||||
|
var msg = format.call(this, message, caller, stack.slice(i))
|
||||||
|
process.stderr.write(msg + '\n', 'utf8')
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get call site location as array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function callSiteLocation(callSite) {
|
||||||
|
var file = callSite.getFileName() || '<anonymous>'
|
||||||
|
var line = callSite.getLineNumber()
|
||||||
|
var colm = callSite.getColumnNumber()
|
||||||
|
|
||||||
|
if (callSite.isEval()) {
|
||||||
|
file = callSite.getEvalOrigin() + ', ' + file
|
||||||
|
}
|
||||||
|
|
||||||
|
var site = [file, line, colm]
|
||||||
|
|
||||||
|
site.callSite = callSite
|
||||||
|
site.name = callSite.getFunctionName()
|
||||||
|
|
||||||
|
return site
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a default message from the site.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function defaultMessage(site) {
|
||||||
|
var callSite = site.callSite
|
||||||
|
var funcName = site.name
|
||||||
|
|
||||||
|
// make useful anonymous name
|
||||||
|
if (!funcName) {
|
||||||
|
funcName = '<anonymous@' + formatLocation(site) + '>'
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = callSite.getThis()
|
||||||
|
var typeName = context && callSite.getTypeName()
|
||||||
|
|
||||||
|
// ignore useless type name
|
||||||
|
if (typeName === 'Object') {
|
||||||
|
typeName = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
// make useful type name
|
||||||
|
if (typeName === 'Function') {
|
||||||
|
typeName = context.name || typeName
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeName && callSite.getMethodName()
|
||||||
|
? typeName + '.' + funcName
|
||||||
|
: funcName
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format deprecation message without color.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function formatPlain(msg, caller, stack) {
|
||||||
|
var timestamp = new Date().toUTCString()
|
||||||
|
|
||||||
|
var formatted = timestamp
|
||||||
|
+ ' ' + this._namespace
|
||||||
|
+ ' deprecated ' + msg
|
||||||
|
|
||||||
|
// add stack trace
|
||||||
|
if (this._traced) {
|
||||||
|
for (var i = 0; i < stack.length; i++) {
|
||||||
|
formatted += '\n at ' + callSiteToString(stack[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatted
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caller) {
|
||||||
|
formatted += ' at ' + formatLocation(caller)
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatted
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format deprecation message with color.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function formatColor(msg, caller, stack) {
|
||||||
|
var formatted = '\x1b[36;1m' + this._namespace + '\x1b[22;39m' // bold cyan
|
||||||
|
+ ' \x1b[33;1mdeprecated\x1b[22;39m' // bold yellow
|
||||||
|
+ ' \x1b[0m' + msg + '\x1b[39m' // reset
|
||||||
|
|
||||||
|
// add stack trace
|
||||||
|
if (this._traced) {
|
||||||
|
for (var i = 0; i < stack.length; i++) {
|
||||||
|
formatted += '\n \x1b[36mat ' + callSiteToString(stack[i]) + '\x1b[39m' // cyan
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatted
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caller) {
|
||||||
|
formatted += ' \x1b[36m' + formatLocation(caller) + '\x1b[39m' // cyan
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatted
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format call site location.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function formatLocation(callSite) {
|
||||||
|
return relative(basePath, callSite[0])
|
||||||
|
+ ':' + callSite[1]
|
||||||
|
+ ':' + callSite[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the stack as array of call sites.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getStack() {
|
||||||
|
var limit = Error.stackTraceLimit
|
||||||
|
var obj = {}
|
||||||
|
var prep = Error.prepareStackTrace
|
||||||
|
|
||||||
|
Error.prepareStackTrace = prepareObjectStackTrace
|
||||||
|
Error.stackTraceLimit = Math.max(10, limit)
|
||||||
|
|
||||||
|
// capture the stack
|
||||||
|
Error.captureStackTrace(obj)
|
||||||
|
|
||||||
|
// slice this function off the top
|
||||||
|
var stack = obj.stack.slice(1)
|
||||||
|
|
||||||
|
Error.prepareStackTrace = prep
|
||||||
|
Error.stackTraceLimit = limit
|
||||||
|
|
||||||
|
return stack
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capture call site stack from v8.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function prepareObjectStackTrace(obj, stack) {
|
||||||
|
return stack
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a wrapped function in a deprecation message.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function wrapfunction(fn, message) {
|
||||||
|
if (typeof fn !== 'function') {
|
||||||
|
throw new TypeError('argument fn must be a function')
|
||||||
|
}
|
||||||
|
|
||||||
|
var args = createArgumentsString(fn.length)
|
||||||
|
var deprecate = this
|
||||||
|
var stack = getStack()
|
||||||
|
var site = callSiteLocation(stack[1])
|
||||||
|
|
||||||
|
site.name = fn.name
|
||||||
|
|
||||||
|
var deprecatedfn = eval('(function (' + args + ') {\n'
|
||||||
|
+ '"use strict"\n'
|
||||||
|
+ 'log.call(deprecate, message, site)\n'
|
||||||
|
+ 'return fn.apply(this, arguments)\n'
|
||||||
|
+ '})')
|
||||||
|
|
||||||
|
return deprecatedfn
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap property in a deprecation message.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function wrapproperty(obj, prop, message) {
|
||||||
|
if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) {
|
||||||
|
throw new TypeError('argument obj must be object')
|
||||||
|
}
|
||||||
|
|
||||||
|
var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
|
||||||
|
|
||||||
|
if (!descriptor) {
|
||||||
|
throw new TypeError('must call property on owner object')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!descriptor.configurable) {
|
||||||
|
throw new TypeError('property must be configurable')
|
||||||
|
}
|
||||||
|
|
||||||
|
var deprecate = this
|
||||||
|
var stack = getStack()
|
||||||
|
var site = callSiteLocation(stack[1])
|
||||||
|
|
||||||
|
// set site name
|
||||||
|
site.name = prop
|
||||||
|
|
||||||
|
// convert data descriptor
|
||||||
|
if ('value' in descriptor) {
|
||||||
|
descriptor = convertDataDescriptorToAccessor(obj, prop, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
var get = descriptor.get
|
||||||
|
var set = descriptor.set
|
||||||
|
|
||||||
|
// wrap getter
|
||||||
|
if (typeof get === 'function') {
|
||||||
|
descriptor.get = function getter() {
|
||||||
|
log.call(deprecate, message, site)
|
||||||
|
return get.apply(this, arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrap setter
|
||||||
|
if (typeof set === 'function') {
|
||||||
|
descriptor.set = function setter() {
|
||||||
|
log.call(deprecate, message, site)
|
||||||
|
return set.apply(this, arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(obj, prop, descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create DeprecationError for deprecation
|
||||||
|
*/
|
||||||
|
|
||||||
|
function DeprecationError(namespace, message, stack) {
|
||||||
|
var error = new Error()
|
||||||
|
var stackString
|
||||||
|
|
||||||
|
Object.defineProperty(error, 'constructor', {
|
||||||
|
value: DeprecationError
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.defineProperty(error, 'message', {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: false,
|
||||||
|
value: message,
|
||||||
|
writable: true
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.defineProperty(error, 'name', {
|
||||||
|
enumerable: false,
|
||||||
|
configurable: true,
|
||||||
|
value: 'DeprecationError',
|
||||||
|
writable: true
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.defineProperty(error, 'namespace', {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: false,
|
||||||
|
value: namespace,
|
||||||
|
writable: true
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.defineProperty(error, 'stack', {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: false,
|
||||||
|
get: function () {
|
||||||
|
if (stackString !== undefined) {
|
||||||
|
return stackString
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare stack trace
|
||||||
|
return stackString = createStackString.call(this, stack)
|
||||||
|
},
|
||||||
|
set: function setter(val) {
|
||||||
|
stackString = val
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return error
|
||||||
|
}
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
/*!
|
||||||
|
* depd
|
||||||
|
* Copyright(c) 2015 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = depd
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create deprecate for namespace in caller.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function depd(namespace) {
|
||||||
|
if (!namespace) {
|
||||||
|
throw new TypeError('argument namespace is required')
|
||||||
|
}
|
||||||
|
|
||||||
|
function deprecate(message) {
|
||||||
|
// no-op in browser
|
||||||
|
}
|
||||||
|
|
||||||
|
deprecate._file = undefined
|
||||||
|
deprecate._ignored = true
|
||||||
|
deprecate._namespace = namespace
|
||||||
|
deprecate._traced = false
|
||||||
|
deprecate._warned = Object.create(null)
|
||||||
|
|
||||||
|
deprecate.function = wrapfunction
|
||||||
|
deprecate.property = wrapproperty
|
||||||
|
|
||||||
|
return deprecate
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a wrapped function in a deprecation message.
|
||||||
|
*
|
||||||
|
* This is a no-op version of the wrapper, which does nothing but call
|
||||||
|
* validation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function wrapfunction(fn, message) {
|
||||||
|
if (typeof fn !== 'function') {
|
||||||
|
throw new TypeError('argument fn must be a function')
|
||||||
|
}
|
||||||
|
|
||||||
|
return fn
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap property in a deprecation message.
|
||||||
|
*
|
||||||
|
* This is a no-op version of the wrapper, which does nothing but call
|
||||||
|
* validation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function wrapproperty(obj, prop, message) {
|
||||||
|
if (!obj || (typeof obj !== 'object' && typeof obj !== 'function')) {
|
||||||
|
throw new TypeError('argument obj must be object')
|
||||||
|
}
|
||||||
|
|
||||||
|
var descriptor = Object.getOwnPropertyDescriptor(obj, prop)
|
||||||
|
|
||||||
|
if (!descriptor) {
|
||||||
|
throw new TypeError('must call property on owner object')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!descriptor.configurable) {
|
||||||
|
throw new TypeError('property must be configurable')
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
/*!
|
||||||
|
* depd
|
||||||
|
* Copyright(c) 2014 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = bufferConcat
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatenate an array of Buffers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function bufferConcat(bufs) {
|
||||||
|
var length = 0
|
||||||
|
|
||||||
|
for (var i = 0, len = bufs.length; i < len; i++) {
|
||||||
|
length += bufs[i].length
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf = new Buffer(length)
|
||||||
|
var pos = 0
|
||||||
|
|
||||||
|
for (var i = 0, len = bufs.length; i < len; i++) {
|
||||||
|
bufs[i].copy(buf, pos)
|
||||||
|
pos += bufs[i].length
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf
|
||||||
|
}
|
||||||
@ -0,0 +1,103 @@
|
|||||||
|
/*!
|
||||||
|
* depd
|
||||||
|
* Copyright(c) 2014 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = callSiteToString
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a CallSite file location to a string.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function callSiteFileLocation(callSite) {
|
||||||
|
var fileName
|
||||||
|
var fileLocation = ''
|
||||||
|
|
||||||
|
if (callSite.isNative()) {
|
||||||
|
fileLocation = 'native'
|
||||||
|
} else if (callSite.isEval()) {
|
||||||
|
fileName = callSite.getScriptNameOrSourceURL()
|
||||||
|
if (!fileName) {
|
||||||
|
fileLocation = callSite.getEvalOrigin()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fileName = callSite.getFileName()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileName) {
|
||||||
|
fileLocation += fileName
|
||||||
|
|
||||||
|
var lineNumber = callSite.getLineNumber()
|
||||||
|
if (lineNumber != null) {
|
||||||
|
fileLocation += ':' + lineNumber
|
||||||
|
|
||||||
|
var columnNumber = callSite.getColumnNumber()
|
||||||
|
if (columnNumber) {
|
||||||
|
fileLocation += ':' + columnNumber
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileLocation || 'unknown source'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a CallSite to a string.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function callSiteToString(callSite) {
|
||||||
|
var addSuffix = true
|
||||||
|
var fileLocation = callSiteFileLocation(callSite)
|
||||||
|
var functionName = callSite.getFunctionName()
|
||||||
|
var isConstructor = callSite.isConstructor()
|
||||||
|
var isMethodCall = !(callSite.isToplevel() || isConstructor)
|
||||||
|
var line = ''
|
||||||
|
|
||||||
|
if (isMethodCall) {
|
||||||
|
var methodName = callSite.getMethodName()
|
||||||
|
var typeName = getConstructorName(callSite)
|
||||||
|
|
||||||
|
if (functionName) {
|
||||||
|
if (typeName && functionName.indexOf(typeName) !== 0) {
|
||||||
|
line += typeName + '.'
|
||||||
|
}
|
||||||
|
|
||||||
|
line += functionName
|
||||||
|
|
||||||
|
if (methodName && functionName.lastIndexOf('.' + methodName) !== functionName.length - methodName.length - 1) {
|
||||||
|
line += ' [as ' + methodName + ']'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
line += typeName + '.' + (methodName || '<anonymous>')
|
||||||
|
}
|
||||||
|
} else if (isConstructor) {
|
||||||
|
line += 'new ' + (functionName || '<anonymous>')
|
||||||
|
} else if (functionName) {
|
||||||
|
line += functionName
|
||||||
|
} else {
|
||||||
|
addSuffix = false
|
||||||
|
line += fileLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addSuffix) {
|
||||||
|
line += ' (' + fileLocation + ')'
|
||||||
|
}
|
||||||
|
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get constructor name of reviver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getConstructorName(obj) {
|
||||||
|
var receiver = obj.receiver
|
||||||
|
return (receiver.constructor && receiver.constructor.name) || null
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
/*!
|
||||||
|
* depd
|
||||||
|
* Copyright(c) 2015 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = eventListenerCount
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the count of listeners on an event emitter of a specific type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function eventListenerCount(emitter, type) {
|
||||||
|
return emitter.listeners(type).length
|
||||||
|
}
|
||||||
@ -0,0 +1,84 @@
|
|||||||
|
/*!
|
||||||
|
* depd
|
||||||
|
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Buffer = require('buffer')
|
||||||
|
var EventEmitter = require('events').EventEmitter
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
lazyProperty(module.exports, 'bufferConcat', function bufferConcat() {
|
||||||
|
return Buffer.concat || require('./buffer-concat')
|
||||||
|
})
|
||||||
|
|
||||||
|
lazyProperty(module.exports, 'callSiteToString', function callSiteToString() {
|
||||||
|
var limit = Error.stackTraceLimit
|
||||||
|
var obj = {}
|
||||||
|
var prep = Error.prepareStackTrace
|
||||||
|
|
||||||
|
function prepareObjectStackTrace(obj, stack) {
|
||||||
|
return stack
|
||||||
|
}
|
||||||
|
|
||||||
|
Error.prepareStackTrace = prepareObjectStackTrace
|
||||||
|
Error.stackTraceLimit = 2
|
||||||
|
|
||||||
|
// capture the stack
|
||||||
|
Error.captureStackTrace(obj)
|
||||||
|
|
||||||
|
// slice the stack
|
||||||
|
var stack = obj.stack.slice()
|
||||||
|
|
||||||
|
Error.prepareStackTrace = prep
|
||||||
|
Error.stackTraceLimit = limit
|
||||||
|
|
||||||
|
return stack[0].toString ? toString : require('./callsite-tostring')
|
||||||
|
})
|
||||||
|
|
||||||
|
lazyProperty(module.exports, 'eventListenerCount', function eventListenerCount() {
|
||||||
|
return EventEmitter.listenerCount || require('./event-listener-count')
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a lazy property.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function lazyProperty(obj, prop, getter) {
|
||||||
|
function get() {
|
||||||
|
var val = getter()
|
||||||
|
|
||||||
|
Object.defineProperty(obj, prop, {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true,
|
||||||
|
value: val
|
||||||
|
})
|
||||||
|
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(obj, prop, {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true,
|
||||||
|
get: get
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call toString() on the obj
|
||||||
|
*/
|
||||||
|
|
||||||
|
function toString(obj) {
|
||||||
|
return obj.toString()
|
||||||
|
}
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"name": "depd",
|
||||||
|
"description": "Deprecate all the things",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"author": {
|
||||||
|
"name": "Douglas Christopher Wilson",
|
||||||
|
"email": "doug@somethingdoug.com"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"deprecate",
|
||||||
|
"deprecated"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/dougwilson/nodejs-depd.git"
|
||||||
|
},
|
||||||
|
"browser": "lib/browser/index.js",
|
||||||
|
"devDependencies": {
|
||||||
|
"benchmark": "1.0.0",
|
||||||
|
"beautify-benchmark": "0.2.4",
|
||||||
|
"istanbul": "0.3.5",
|
||||||
|
"mocha": "~1.21.5"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib/",
|
||||||
|
"History.md",
|
||||||
|
"LICENSE",
|
||||||
|
"index.js",
|
||||||
|
"Readme.md"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"bench": "node benchmark/index.js",
|
||||||
|
"test": "mocha --reporter spec --bail test/",
|
||||||
|
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --no-exit test/",
|
||||||
|
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot test/"
|
||||||
|
},
|
||||||
|
"gitHead": "78c659de20283e3a6bee92bda455e6daff01686a",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/dougwilson/nodejs-depd/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/dougwilson/nodejs-depd",
|
||||||
|
"_id": "depd@1.1.0",
|
||||||
|
"_shasum": "e1bd82c6aab6ced965b97b88b17ed3e528ca18c3",
|
||||||
|
"_from": "depd@>=1.1.0 <1.2.0",
|
||||||
|
"_npmVersion": "1.4.28",
|
||||||
|
"_npmUser": {
|
||||||
|
"name": "dougwilson",
|
||||||
|
"email": "doug@somethingdoug.com"
|
||||||
|
},
|
||||||
|
"maintainers": [
|
||||||
|
{
|
||||||
|
"name": "dougwilson",
|
||||||
|
"email": "doug@somethingdoug.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dist": {
|
||||||
|
"shasum": "e1bd82c6aab6ced965b97b88b17ed3e528ca18c3",
|
||||||
|
"tarball": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz"
|
||||||
|
},
|
||||||
|
"directories": {},
|
||||||
|
"_resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz",
|
||||||
|
"readme": "ERROR: No README data found!"
|
||||||
|
}
|
||||||
@ -0,0 +1,95 @@
|
|||||||
|
2016-05-18 / 1.5.0
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Support new code `421 Misdirected Request`
|
||||||
|
* Use `setprototypeof` module to replace `__proto__` setting
|
||||||
|
* deps: statuses@'>= 1.3.0 < 2'
|
||||||
|
- Add `421 Misdirected Request`
|
||||||
|
- perf: enable strict mode
|
||||||
|
* perf: enable strict mode
|
||||||
|
|
||||||
|
2016-01-28 / 1.4.0
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `HttpError` export, for `err instanceof createError.HttpError`
|
||||||
|
* deps: inherits@2.0.1
|
||||||
|
* deps: statuses@'>= 1.2.1 < 2'
|
||||||
|
- Fix message for status 451
|
||||||
|
- Remove incorrect nginx status code
|
||||||
|
|
||||||
|
2015-02-02 / 1.3.1
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix regression where status can be overwritten in `createError` `props`
|
||||||
|
|
||||||
|
2015-02-01 / 1.3.0
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Construct errors using defined constructors from `createError`
|
||||||
|
* Fix error names that are not identifiers
|
||||||
|
- `createError["I'mateapot"]` is now `createError.ImATeapot`
|
||||||
|
* Set a meaningful `name` property on constructed errors
|
||||||
|
|
||||||
|
2014-12-09 / 1.2.8
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix stack trace from exported function
|
||||||
|
* Remove `arguments.callee` usage
|
||||||
|
|
||||||
|
2014-10-14 / 1.2.7
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Remove duplicate line
|
||||||
|
|
||||||
|
2014-10-02 / 1.2.6
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix `expose` to be `true` for `ClientError` constructor
|
||||||
|
|
||||||
|
2014-09-28 / 1.2.5
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: statuses@1
|
||||||
|
|
||||||
|
2014-09-21 / 1.2.4
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix dependency version to work with old `npm`s
|
||||||
|
|
||||||
|
2014-09-21 / 1.2.3
|
||||||
|
==================
|
||||||
|
|
||||||
|
* deps: statuses@~1.1.0
|
||||||
|
|
||||||
|
2014-09-21 / 1.2.2
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix publish error
|
||||||
|
|
||||||
|
2014-09-21 / 1.2.1
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Support Node.js 0.6
|
||||||
|
* Use `inherits` instead of `util`
|
||||||
|
|
||||||
|
2014-09-09 / 1.2.0
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix the way inheriting functions
|
||||||
|
* Support `expose` being provided in properties argument
|
||||||
|
|
||||||
|
2014-09-08 / 1.1.0
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Default status to 500
|
||||||
|
* Support provided `error` to extend
|
||||||
|
|
||||||
|
2014-09-08 / 1.0.1
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix accepting string message
|
||||||
|
|
||||||
|
2014-09-08 / 1.0.0
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Initial release
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Jonathan Ong me@jongleberry.com
|
||||||
|
Copyright (c) 2016 Douglas Christopher Wilson doug@somethingdoug.com
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
@ -0,0 +1,112 @@
|
|||||||
|
# http-errors
|
||||||
|
|
||||||
|
[![NPM Version][npm-image]][npm-url]
|
||||||
|
[![NPM Downloads][downloads-image]][downloads-url]
|
||||||
|
[![Node.js Version][node-version-image]][node-version-url]
|
||||||
|
[![Build Status][travis-image]][travis-url]
|
||||||
|
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||||
|
|
||||||
|
Create HTTP errors for Express, Koa, Connect, etc. with ease.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```js
|
||||||
|
var createError = require('http-errors');
|
||||||
|
|
||||||
|
app.use(function (req, res, next) {
|
||||||
|
if (!req.user) return next(createError(401, 'Please login to view this page.'));
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
This is the current API, currently extracted from Koa and subject to change.
|
||||||
|
|
||||||
|
All errors inherit from JavaScript `Error` and the exported `createError.HttpError`.
|
||||||
|
|
||||||
|
### Error Properties
|
||||||
|
|
||||||
|
- `expose` - can be used to signal if `message` should be sent to the client, defaulting to `false` when `status` >= 500
|
||||||
|
- `message`
|
||||||
|
- `status` and `statusCode` - the status code of the error, defaulting to `500`
|
||||||
|
|
||||||
|
### createError([status], [message], [properties])
|
||||||
|
|
||||||
|
```js
|
||||||
|
var err = createError(404, 'This video does not exist!');
|
||||||
|
```
|
||||||
|
|
||||||
|
- `status: 500` - the status code as a number
|
||||||
|
- `message` - the message of the error, defaulting to node's text for that status code.
|
||||||
|
- `properties` - custom properties to attach to the object
|
||||||
|
|
||||||
|
### new createError\[code || name\](\[msg]\))
|
||||||
|
|
||||||
|
```js
|
||||||
|
var err = new createError.NotFound();
|
||||||
|
```
|
||||||
|
|
||||||
|
- `code` - the status code as a number
|
||||||
|
- `name` - the name of the error as a "bumpy case", i.e. `NotFound` or `InternalServerError`.
|
||||||
|
|
||||||
|
#### List of all constructors
|
||||||
|
|
||||||
|
|Status Code|Constructor Name |
|
||||||
|
|-----------|-----------------------------|
|
||||||
|
|400 |BadRequest |
|
||||||
|
|401 |Unauthorized |
|
||||||
|
|402 |PaymentRequired |
|
||||||
|
|403 |Forbidden |
|
||||||
|
|404 |NotFound |
|
||||||
|
|405 |MethodNotAllowed |
|
||||||
|
|406 |NotAcceptable |
|
||||||
|
|407 |ProxyAuthenticationRequired |
|
||||||
|
|408 |RequestTimeout |
|
||||||
|
|409 |Conflict |
|
||||||
|
|410 |Gone |
|
||||||
|
|411 |LengthRequired |
|
||||||
|
|412 |PreconditionFailed |
|
||||||
|
|413 |PayloadTooLarge |
|
||||||
|
|414 |URITooLong |
|
||||||
|
|415 |UnsupportedMediaType |
|
||||||
|
|416 |RangeNotSatisfiable |
|
||||||
|
|417 |ExpectationFailed |
|
||||||
|
|418 |ImATeapot |
|
||||||
|
|421 |MisdirectedRequest |
|
||||||
|
|422 |UnprocessableEntity |
|
||||||
|
|423 |Locked |
|
||||||
|
|424 |FailedDependency |
|
||||||
|
|425 |UnorderedCollection |
|
||||||
|
|426 |UpgradeRequired |
|
||||||
|
|428 |PreconditionRequired |
|
||||||
|
|429 |TooManyRequests |
|
||||||
|
|431 |RequestHeaderFieldsTooLarge |
|
||||||
|
|451 |UnavailableForLegalReasons |
|
||||||
|
|500 |InternalServerError |
|
||||||
|
|501 |NotImplemented |
|
||||||
|
|502 |BadGateway |
|
||||||
|
|503 |ServiceUnavailable |
|
||||||
|
|504 |GatewayTimeout |
|
||||||
|
|505 |HTTPVersionNotSupported |
|
||||||
|
|506 |VariantAlsoNegotiates |
|
||||||
|
|507 |InsufficientStorage |
|
||||||
|
|508 |LoopDetected |
|
||||||
|
|509 |BandwidthLimitExceeded |
|
||||||
|
|510 |NotExtended |
|
||||||
|
|511 |NetworkAuthenticationRequired|
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
||||||
|
|
||||||
|
[npm-image]: https://img.shields.io/npm/v/http-errors.svg?style=flat
|
||||||
|
[npm-url]: https://npmjs.org/package/http-errors
|
||||||
|
[node-version-image]: https://img.shields.io/node/v/http-errors.svg?style=flat
|
||||||
|
[node-version-url]: https://nodejs.org/en/download/
|
||||||
|
[travis-image]: https://img.shields.io/travis/jshttp/http-errors.svg?style=flat
|
||||||
|
[travis-url]: https://travis-ci.org/jshttp/http-errors
|
||||||
|
[coveralls-image]: https://img.shields.io/coveralls/jshttp/http-errors.svg?style=flat
|
||||||
|
[coveralls-url]: https://coveralls.io/r/jshttp/http-errors
|
||||||
|
[downloads-image]: https://img.shields.io/npm/dm/http-errors.svg?style=flat
|
||||||
|
[downloads-url]: https://npmjs.org/package/http-errors
|
||||||
@ -0,0 +1,223 @@
|
|||||||
|
/*!
|
||||||
|
* http-errors
|
||||||
|
* Copyright(c) 2014 Jonathan Ong
|
||||||
|
* Copyright(c) 2016 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var setPrototypeOf = require('setprototypeof')
|
||||||
|
var statuses = require('statuses')
|
||||||
|
var inherits = require('inherits')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = createError
|
||||||
|
module.exports.HttpError = createHttpErrorConstructor()
|
||||||
|
|
||||||
|
// Populate exports for all constructors
|
||||||
|
populateConstructorExports(module.exports, statuses.codes, module.exports.HttpError)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new HTTP Error.
|
||||||
|
*
|
||||||
|
* @returns {Error}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function createError () {
|
||||||
|
// so much arity going on ~_~
|
||||||
|
var err
|
||||||
|
var msg
|
||||||
|
var status = 500
|
||||||
|
var props = {}
|
||||||
|
for (var i = 0; i < arguments.length; i++) {
|
||||||
|
var arg = arguments[i]
|
||||||
|
if (arg instanceof Error) {
|
||||||
|
err = arg
|
||||||
|
status = err.status || err.statusCode || status
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch (typeof arg) {
|
||||||
|
case 'string':
|
||||||
|
msg = arg
|
||||||
|
break
|
||||||
|
case 'number':
|
||||||
|
status = arg
|
||||||
|
break
|
||||||
|
case 'object':
|
||||||
|
props = arg
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof status !== 'number' || !statuses[status]) {
|
||||||
|
status = 500
|
||||||
|
}
|
||||||
|
|
||||||
|
// constructor
|
||||||
|
var HttpError = createError[status]
|
||||||
|
|
||||||
|
if (!err) {
|
||||||
|
// create error
|
||||||
|
err = HttpError
|
||||||
|
? new HttpError(msg)
|
||||||
|
: new Error(msg || statuses[status])
|
||||||
|
Error.captureStackTrace(err, createError)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HttpError || !(err instanceof HttpError)) {
|
||||||
|
// add properties to generic error
|
||||||
|
err.expose = status < 500
|
||||||
|
err.status = err.statusCode = status
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var key in props) {
|
||||||
|
if (key !== 'status' && key !== 'statusCode') {
|
||||||
|
err[key] = props[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create HTTP error abstract base class.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function createHttpErrorConstructor () {
|
||||||
|
function HttpError () {
|
||||||
|
throw new TypeError('cannot construct abstract class')
|
||||||
|
}
|
||||||
|
|
||||||
|
inherits(HttpError, Error)
|
||||||
|
|
||||||
|
return HttpError
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a constructor for a client error.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function createClientErrorConstructor (HttpError, name, code) {
|
||||||
|
var className = name.match(/Error$/) ? name : name + 'Error'
|
||||||
|
|
||||||
|
function ClientError (message) {
|
||||||
|
// create the error object
|
||||||
|
var err = new Error(message != null ? message : statuses[code])
|
||||||
|
|
||||||
|
// capture a stack trace to the construction point
|
||||||
|
Error.captureStackTrace(err, ClientError)
|
||||||
|
|
||||||
|
// adjust the [[Prototype]]
|
||||||
|
setPrototypeOf(err, ClientError.prototype)
|
||||||
|
|
||||||
|
// redefine the error name
|
||||||
|
Object.defineProperty(err, 'name', {
|
||||||
|
enumerable: false,
|
||||||
|
configurable: true,
|
||||||
|
value: className,
|
||||||
|
writable: true
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
inherits(ClientError, HttpError)
|
||||||
|
|
||||||
|
ClientError.prototype.status = code
|
||||||
|
ClientError.prototype.statusCode = code
|
||||||
|
ClientError.prototype.expose = true
|
||||||
|
|
||||||
|
return ClientError
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a constructor for a server error.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function createServerErrorConstructor (HttpError, name, code) {
|
||||||
|
var className = name.match(/Error$/) ? name : name + 'Error'
|
||||||
|
|
||||||
|
function ServerError (message) {
|
||||||
|
// create the error object
|
||||||
|
var err = new Error(message != null ? message : statuses[code])
|
||||||
|
|
||||||
|
// capture a stack trace to the construction point
|
||||||
|
Error.captureStackTrace(err, ServerError)
|
||||||
|
|
||||||
|
// adjust the [[Prototype]]
|
||||||
|
setPrototypeOf(err, ServerError.prototype)
|
||||||
|
|
||||||
|
// redefine the error name
|
||||||
|
Object.defineProperty(err, 'name', {
|
||||||
|
enumerable: false,
|
||||||
|
configurable: true,
|
||||||
|
value: className,
|
||||||
|
writable: true
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
inherits(ServerError, HttpError)
|
||||||
|
|
||||||
|
ServerError.prototype.status = code
|
||||||
|
ServerError.prototype.statusCode = code
|
||||||
|
ServerError.prototype.expose = false
|
||||||
|
|
||||||
|
return ServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate the exports object with constructors for every error class.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function populateConstructorExports (exports, codes, HttpError) {
|
||||||
|
codes.forEach(function forEachCode (code) {
|
||||||
|
var CodeError
|
||||||
|
var name = toIdentifier(statuses[code])
|
||||||
|
|
||||||
|
switch (String(code).charAt(0)) {
|
||||||
|
case '4':
|
||||||
|
CodeError = createClientErrorConstructor(HttpError, name, code)
|
||||||
|
break
|
||||||
|
case '5':
|
||||||
|
CodeError = createServerErrorConstructor(HttpError, name, code)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CodeError) {
|
||||||
|
// export the constructor
|
||||||
|
exports[code] = CodeError
|
||||||
|
exports[name] = CodeError
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// backwards-compatibility
|
||||||
|
exports["I'mateapot"] = exports.ImATeapot
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a string of words to a JavaScript identifier.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function toIdentifier (str) {
|
||||||
|
return str.split(' ').map(function (token) {
|
||||||
|
return token.slice(0, 1).toUpperCase() + token.slice(1)
|
||||||
|
}).join('').replace(/[^ _0-9a-z]/gi, '')
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
The ISC License
|
||||||
|
|
||||||
|
Copyright (c) Isaac Z. Schlueter
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
Browser-friendly inheritance fully compatible with standard node.js
|
||||||
|
[inherits](http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor).
|
||||||
|
|
||||||
|
This package exports standard `inherits` from node.js `util` module in
|
||||||
|
node environment, but also provides alternative browser-friendly
|
||||||
|
implementation through [browser
|
||||||
|
field](https://gist.github.com/shtylman/4339901). Alternative
|
||||||
|
implementation is a literal copy of standard one located in standalone
|
||||||
|
module to avoid requiring of `util`. It also has a shim for old
|
||||||
|
browsers with no `Object.create` support.
|
||||||
|
|
||||||
|
While keeping you sure you are using standard `inherits`
|
||||||
|
implementation in node.js environment, it allows bundlers such as
|
||||||
|
[browserify](https://github.com/substack/node-browserify) to not
|
||||||
|
include full `util` package to your client code if all you need is
|
||||||
|
just `inherits` function. It worth, because browser shim for `util`
|
||||||
|
package is large and `inherits` is often the single function you need
|
||||||
|
from it.
|
||||||
|
|
||||||
|
It's recommended to use this package instead of
|
||||||
|
`require('util').inherits` for any code that has chances to be used
|
||||||
|
not only in node.js but in browser too.
|
||||||
|
|
||||||
|
## usage
|
||||||
|
|
||||||
|
```js
|
||||||
|
var inherits = require('inherits');
|
||||||
|
// then use exactly as the standard one
|
||||||
|
```
|
||||||
|
|
||||||
|
## note on version ~1.0
|
||||||
|
|
||||||
|
Version ~1.0 had completely different motivation and is not compatible
|
||||||
|
neither with 2.0 nor with standard node.js `inherits`.
|
||||||
|
|
||||||
|
If you are using version ~1.0 and planning to switch to ~2.0, be
|
||||||
|
careful:
|
||||||
|
|
||||||
|
* new version uses `super_` instead of `super` for referencing
|
||||||
|
superclass
|
||||||
|
* new version overwrites current prototype while old one preserves any
|
||||||
|
existing fields on it
|
||||||
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('util').inherits
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
if (typeof Object.create === 'function') {
|
||||||
|
// implementation from standard node.js 'util' module
|
||||||
|
module.exports = function inherits(ctor, superCtor) {
|
||||||
|
ctor.super_ = superCtor
|
||||||
|
ctor.prototype = Object.create(superCtor.prototype, {
|
||||||
|
constructor: {
|
||||||
|
value: ctor,
|
||||||
|
enumerable: false,
|
||||||
|
writable: true,
|
||||||
|
configurable: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// old school shim for old browsers
|
||||||
|
module.exports = function inherits(ctor, superCtor) {
|
||||||
|
ctor.super_ = superCtor
|
||||||
|
var TempCtor = function () {}
|
||||||
|
TempCtor.prototype = superCtor.prototype
|
||||||
|
ctor.prototype = new TempCtor()
|
||||||
|
ctor.prototype.constructor = ctor
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"name": "inherits",
|
||||||
|
"description": "Browser-friendly inheritance fully compatible with standard node.js inherits()",
|
||||||
|
"version": "2.0.1",
|
||||||
|
"keywords": [
|
||||||
|
"inheritance",
|
||||||
|
"class",
|
||||||
|
"klass",
|
||||||
|
"oop",
|
||||||
|
"object-oriented",
|
||||||
|
"inherits",
|
||||||
|
"browser",
|
||||||
|
"browserify"
|
||||||
|
],
|
||||||
|
"main": "./inherits.js",
|
||||||
|
"browser": "./inherits_browser.js",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/isaacs/inherits.git"
|
||||||
|
},
|
||||||
|
"license": "ISC",
|
||||||
|
"scripts": {
|
||||||
|
"test": "node test"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/isaacs/inherits/issues"
|
||||||
|
},
|
||||||
|
"_id": "inherits@2.0.1",
|
||||||
|
"dist": {
|
||||||
|
"shasum": "b17d08d326b4423e568eff719f91b0b1cbdf69f1",
|
||||||
|
"tarball": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
|
||||||
|
},
|
||||||
|
"_from": "inherits@2.0.1",
|
||||||
|
"_npmVersion": "1.3.8",
|
||||||
|
"_npmUser": {
|
||||||
|
"name": "isaacs",
|
||||||
|
"email": "i@izs.me"
|
||||||
|
},
|
||||||
|
"maintainers": [
|
||||||
|
{
|
||||||
|
"name": "isaacs",
|
||||||
|
"email": "i@izs.me"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directories": {},
|
||||||
|
"_shasum": "b17d08d326b4423e568eff719f91b0b1cbdf69f1",
|
||||||
|
"_resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
|
||||||
|
"readme": "ERROR: No README data found!",
|
||||||
|
"homepage": "https://github.com/isaacs/inherits#readme"
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
var inherits = require('./inherits.js')
|
||||||
|
var assert = require('assert')
|
||||||
|
|
||||||
|
function test(c) {
|
||||||
|
assert(c.constructor === Child)
|
||||||
|
assert(c.constructor.super_ === Parent)
|
||||||
|
assert(Object.getPrototypeOf(c) === Child.prototype)
|
||||||
|
assert(Object.getPrototypeOf(Object.getPrototypeOf(c)) === Parent.prototype)
|
||||||
|
assert(c instanceof Child)
|
||||||
|
assert(c instanceof Parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Child() {
|
||||||
|
Parent.call(this)
|
||||||
|
test(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Parent() {}
|
||||||
|
|
||||||
|
inherits(Child, Parent)
|
||||||
|
|
||||||
|
var c = new Child
|
||||||
|
test(c)
|
||||||
|
|
||||||
|
console.log('ok')
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
Copyright (c) 2015, Wes Todd
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
# Polyfill for `Object.setPrototypeOf`
|
||||||
|
|
||||||
|
A simple cross platform implementation to set the prototype of an instianted object. Supports all modern browsers and at least back to IE8.
|
||||||
|
|
||||||
|
## Usage:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm install --save setprototypeof
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var setPrototypeOf = require('setprototypeof');
|
||||||
|
|
||||||
|
var obj = {};
|
||||||
|
setPrototypeOf(obj, {
|
||||||
|
foo: function() {
|
||||||
|
return 'bar';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
obj.foo(); // bar
|
||||||
|
```
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
module.exports = Object.setPrototypeOf || ({__proto__:[]} instanceof Array ? setProtoOf : mixinProperties);
|
||||||
|
|
||||||
|
function setProtoOf(obj, proto) {
|
||||||
|
obj.__proto__ = proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mixinProperties(obj, proto) {
|
||||||
|
for (var prop in proto) {
|
||||||
|
obj[prop] = proto[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"name": "setprototypeof",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"description": "A small polyfill for Object.setprototypeof",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/wesleytodd/setprototypeof.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"polyfill",
|
||||||
|
"object",
|
||||||
|
"setprototypeof"
|
||||||
|
],
|
||||||
|
"author": {
|
||||||
|
"name": "Wes Todd"
|
||||||
|
},
|
||||||
|
"license": "ISC",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/wesleytodd/setprototypeof/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/wesleytodd/setprototypeof",
|
||||||
|
"gitHead": "1e3d0cde6b7f4a9fba10cd28e62b200c9d8f899f",
|
||||||
|
"_id": "setprototypeof@1.0.1",
|
||||||
|
"_shasum": "52009b27888c4dc48f591949c0a8275834c1ca7e",
|
||||||
|
"_from": "setprototypeof@1.0.1",
|
||||||
|
"_npmVersion": "3.3.6",
|
||||||
|
"_nodeVersion": "5.0.0",
|
||||||
|
"_npmUser": {
|
||||||
|
"name": "wesleytodd",
|
||||||
|
"email": "wes@wesleytodd.com"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"shasum": "52009b27888c4dc48f591949c0a8275834c1ca7e",
|
||||||
|
"tarball": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.1.tgz"
|
||||||
|
},
|
||||||
|
"maintainers": [
|
||||||
|
{
|
||||||
|
"name": "wesleytodd",
|
||||||
|
"email": "wes@wesleytodd.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_npmOperationalInternal": {
|
||||||
|
"host": "packages-5-east.internal.npmjs.com",
|
||||||
|
"tmp": "tmp/setprototypeof-1.0.1.tgz_1454803015119_0.7522649802267551"
|
||||||
|
},
|
||||||
|
"directories": {},
|
||||||
|
"_resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.1.tgz",
|
||||||
|
"readme": "ERROR: No README data found!"
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
1.3.0 / 2016-05-17
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `421 Misdirected Request`
|
||||||
|
* perf: enable strict mode
|
||||||
|
|
||||||
|
1.2.1 / 2015-02-01
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Fix message for status 451
|
||||||
|
- `451 Unavailable For Legal Reasons`
|
||||||
|
|
||||||
|
1.2.0 / 2014-09-28
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `208 Already Repored`
|
||||||
|
* Add `226 IM Used`
|
||||||
|
* Add `306 (Unused)`
|
||||||
|
* Add `415 Unable For Legal Reasons`
|
||||||
|
* Add `508 Loop Detected`
|
||||||
|
|
||||||
|
1.1.1 / 2014-09-24
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add missing 308 to `codes.json`
|
||||||
|
|
||||||
|
1.1.0 / 2014-09-21
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `codes.json` for universal support
|
||||||
|
|
||||||
|
1.0.4 / 2014-08-20
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Package cleanup
|
||||||
|
|
||||||
|
1.0.3 / 2014-06-08
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add 308 to `.redirect` category
|
||||||
|
|
||||||
|
1.0.2 / 2014-03-13
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Add `.retry` category
|
||||||
|
|
||||||
|
1.0.1 / 2014-03-12
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Initial release
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Jonathan Ong me@jongleberry.com
|
||||||
|
Copyright (c) 2016 Douglas Christopher Wilson doug@somethingdoug.com
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
# Statuses
|
||||||
|
|
||||||
|
[![NPM Version][npm-image]][npm-url]
|
||||||
|
[![NPM Downloads][downloads-image]][downloads-url]
|
||||||
|
[![Node.js Version][node-version-image]][node-version-url]
|
||||||
|
[![Build Status][travis-image]][travis-url]
|
||||||
|
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||||
|
|
||||||
|
HTTP status utility for node.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
```js
|
||||||
|
var status = require('statuses')
|
||||||
|
```
|
||||||
|
|
||||||
|
### var code = status(Integer || String)
|
||||||
|
|
||||||
|
If `Integer` or `String` is a valid HTTP code or status message, then the appropriate `code` will be returned. Otherwise, an error will be thrown.
|
||||||
|
|
||||||
|
```js
|
||||||
|
status(403) // => 403
|
||||||
|
status('403') // => 403
|
||||||
|
status('forbidden') // => 403
|
||||||
|
status('Forbidden') // => 403
|
||||||
|
status(306) // throws, as it's not supported by node.js
|
||||||
|
```
|
||||||
|
|
||||||
|
### status.codes
|
||||||
|
|
||||||
|
Returns an array of all the status codes as `Integer`s.
|
||||||
|
|
||||||
|
### var msg = status[code]
|
||||||
|
|
||||||
|
Map of `code` to `status message`. `undefined` for invalid `code`s.
|
||||||
|
|
||||||
|
```js
|
||||||
|
status[404] // => 'Not Found'
|
||||||
|
```
|
||||||
|
|
||||||
|
### var code = status[msg]
|
||||||
|
|
||||||
|
Map of `status message` to `code`. `msg` can either be title-cased or lower-cased. `undefined` for invalid `status message`s.
|
||||||
|
|
||||||
|
```js
|
||||||
|
status['not found'] // => 404
|
||||||
|
status['Not Found'] // => 404
|
||||||
|
```
|
||||||
|
|
||||||
|
### status.redirect[code]
|
||||||
|
|
||||||
|
Returns `true` if a status code is a valid redirect status.
|
||||||
|
|
||||||
|
```js
|
||||||
|
status.redirect[200] // => undefined
|
||||||
|
status.redirect[301] // => true
|
||||||
|
```
|
||||||
|
|
||||||
|
### status.empty[code]
|
||||||
|
|
||||||
|
Returns `true` if a status code expects an empty body.
|
||||||
|
|
||||||
|
```js
|
||||||
|
status.empty[200] // => undefined
|
||||||
|
status.empty[204] // => true
|
||||||
|
status.empty[304] // => true
|
||||||
|
```
|
||||||
|
|
||||||
|
### status.retry[code]
|
||||||
|
|
||||||
|
Returns `true` if you should retry the rest.
|
||||||
|
|
||||||
|
```js
|
||||||
|
status.retry[501] // => undefined
|
||||||
|
status.retry[503] // => true
|
||||||
|
```
|
||||||
|
|
||||||
|
### statuses/codes.json
|
||||||
|
|
||||||
|
```js
|
||||||
|
var codes = require('statuses/codes.json')
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a JSON file of the status codes
|
||||||
|
taken from `require('http').STATUS_CODES`.
|
||||||
|
This is saved so that codes are consistent even in older node.js versions.
|
||||||
|
For example, `308` will be added in v0.12.
|
||||||
|
|
||||||
|
## Adding Status Codes
|
||||||
|
|
||||||
|
The status codes are primarily sourced from http://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv.
|
||||||
|
Additionally, custom codes are added from http://en.wikipedia.org/wiki/List_of_HTTP_status_codes.
|
||||||
|
These are added manually in the `lib/*.json` files.
|
||||||
|
If you would like to add a status code, add it to the appropriate JSON file.
|
||||||
|
|
||||||
|
To rebuild `codes.json`, run the following:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# update src/iana.json
|
||||||
|
npm run fetch
|
||||||
|
# build codes.json
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
[npm-image]: https://img.shields.io/npm/v/statuses.svg
|
||||||
|
[npm-url]: https://npmjs.org/package/statuses
|
||||||
|
[node-version-image]: https://img.shields.io/badge/node.js-%3E%3D_0.6-brightgreen.svg
|
||||||
|
[node-version-url]: https://nodejs.org/en/download
|
||||||
|
[travis-image]: https://img.shields.io/travis/jshttp/statuses.svg
|
||||||
|
[travis-url]: https://travis-ci.org/jshttp/statuses
|
||||||
|
[coveralls-image]: https://img.shields.io/coveralls/jshttp/statuses.svg
|
||||||
|
[coveralls-url]: https://coveralls.io/r/jshttp/statuses?branch=master
|
||||||
|
[downloads-image]: https://img.shields.io/npm/dm/statuses.svg
|
||||||
|
[downloads-url]: https://npmjs.org/package/statuses
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"100": "Continue",
|
||||||
|
"101": "Switching Protocols",
|
||||||
|
"102": "Processing",
|
||||||
|
"200": "OK",
|
||||||
|
"201": "Created",
|
||||||
|
"202": "Accepted",
|
||||||
|
"203": "Non-Authoritative Information",
|
||||||
|
"204": "No Content",
|
||||||
|
"205": "Reset Content",
|
||||||
|
"206": "Partial Content",
|
||||||
|
"207": "Multi-Status",
|
||||||
|
"208": "Already Reported",
|
||||||
|
"226": "IM Used",
|
||||||
|
"300": "Multiple Choices",
|
||||||
|
"301": "Moved Permanently",
|
||||||
|
"302": "Found",
|
||||||
|
"303": "See Other",
|
||||||
|
"304": "Not Modified",
|
||||||
|
"305": "Use Proxy",
|
||||||
|
"306": "(Unused)",
|
||||||
|
"307": "Temporary Redirect",
|
||||||
|
"308": "Permanent Redirect",
|
||||||
|
"400": "Bad Request",
|
||||||
|
"401": "Unauthorized",
|
||||||
|
"402": "Payment Required",
|
||||||
|
"403": "Forbidden",
|
||||||
|
"404": "Not Found",
|
||||||
|
"405": "Method Not Allowed",
|
||||||
|
"406": "Not Acceptable",
|
||||||
|
"407": "Proxy Authentication Required",
|
||||||
|
"408": "Request Timeout",
|
||||||
|
"409": "Conflict",
|
||||||
|
"410": "Gone",
|
||||||
|
"411": "Length Required",
|
||||||
|
"412": "Precondition Failed",
|
||||||
|
"413": "Payload Too Large",
|
||||||
|
"414": "URI Too Long",
|
||||||
|
"415": "Unsupported Media Type",
|
||||||
|
"416": "Range Not Satisfiable",
|
||||||
|
"417": "Expectation Failed",
|
||||||
|
"418": "I'm a teapot",
|
||||||
|
"421": "Misdirected Request",
|
||||||
|
"422": "Unprocessable Entity",
|
||||||
|
"423": "Locked",
|
||||||
|
"424": "Failed Dependency",
|
||||||
|
"425": "Unordered Collection",
|
||||||
|
"426": "Upgrade Required",
|
||||||
|
"428": "Precondition Required",
|
||||||
|
"429": "Too Many Requests",
|
||||||
|
"431": "Request Header Fields Too Large",
|
||||||
|
"451": "Unavailable For Legal Reasons",
|
||||||
|
"500": "Internal Server Error",
|
||||||
|
"501": "Not Implemented",
|
||||||
|
"502": "Bad Gateway",
|
||||||
|
"503": "Service Unavailable",
|
||||||
|
"504": "Gateway Timeout",
|
||||||
|
"505": "HTTP Version Not Supported",
|
||||||
|
"506": "Variant Also Negotiates",
|
||||||
|
"507": "Insufficient Storage",
|
||||||
|
"508": "Loop Detected",
|
||||||
|
"509": "Bandwidth Limit Exceeded",
|
||||||
|
"510": "Not Extended",
|
||||||
|
"511": "Network Authentication Required"
|
||||||
|
}
|
||||||
@ -0,0 +1,110 @@
|
|||||||
|
/*!
|
||||||
|
* statuses
|
||||||
|
* Copyright(c) 2014 Jonathan Ong
|
||||||
|
* Copyright(c) 2016 Douglas Christopher Wilson
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var codes = require('./codes.json')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module exports.
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = status
|
||||||
|
|
||||||
|
// array of status codes
|
||||||
|
status.codes = populateStatusesMap(status, codes)
|
||||||
|
|
||||||
|
// status codes for redirects
|
||||||
|
status.redirect = {
|
||||||
|
300: true,
|
||||||
|
301: true,
|
||||||
|
302: true,
|
||||||
|
303: true,
|
||||||
|
305: true,
|
||||||
|
307: true,
|
||||||
|
308: true
|
||||||
|
}
|
||||||
|
|
||||||
|
// status codes for empty bodies
|
||||||
|
status.empty = {
|
||||||
|
204: true,
|
||||||
|
205: true,
|
||||||
|
304: true
|
||||||
|
}
|
||||||
|
|
||||||
|
// status codes for when you should retry the request
|
||||||
|
status.retry = {
|
||||||
|
502: true,
|
||||||
|
503: true,
|
||||||
|
504: true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate the statuses map for given codes.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function populateStatusesMap (statuses, codes) {
|
||||||
|
var arr = []
|
||||||
|
|
||||||
|
Object.keys(codes).forEach(function forEachCode (code) {
|
||||||
|
var message = codes[code]
|
||||||
|
var status = Number(code)
|
||||||
|
|
||||||
|
// Populate properties
|
||||||
|
statuses[status] = message
|
||||||
|
statuses[message] = status
|
||||||
|
statuses[message.toLowerCase()] = status
|
||||||
|
|
||||||
|
// Add to array
|
||||||
|
arr.push(status)
|
||||||
|
})
|
||||||
|
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the status code.
|
||||||
|
*
|
||||||
|
* Given a number, this will throw if it is not a known status
|
||||||
|
* code, otherwise the code will be returned. Given a string,
|
||||||
|
* the string will be parsed for a number and return the code
|
||||||
|
* if valid, otherwise will lookup the code assuming this is
|
||||||
|
* the status message.
|
||||||
|
*
|
||||||
|
* @param {string|number} code
|
||||||
|
* @returns {string}
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function status (code) {
|
||||||
|
if (typeof code === 'number') {
|
||||||
|
if (!status[code]) throw new Error('invalid status code: ' + code)
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof code !== 'string') {
|
||||||
|
throw new TypeError('code must be a number or string')
|
||||||
|
}
|
||||||
|
|
||||||
|
// '403'
|
||||||
|
var n = parseInt(code, 10)
|
||||||
|
if (!isNaN(n)) {
|
||||||
|
if (!status[n]) throw new Error('invalid status code: ' + n)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
n = status[code.toLowerCase()]
|
||||||
|
if (!n) throw new Error('invalid status message: "' + code + '"')
|
||||||
|
return n
|
||||||
|
}
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
{
|
||||||
|
"name": "statuses",
|
||||||
|
"description": "HTTP status utility",
|
||||||
|
"version": "1.3.0",
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Douglas Christopher Wilson",
|
||||||
|
"email": "doug@somethingdoug.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jonathan Ong",
|
||||||
|
"email": "me@jongleberry.com",
|
||||||
|
"url": "http://jongleberry.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/jshttp/statuses.git"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"http",
|
||||||
|
"status",
|
||||||
|
"code"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"HISTORY.md",
|
||||||
|
"index.js",
|
||||||
|
"codes.json",
|
||||||
|
"LICENSE"
|
||||||
|
],
|
||||||
|
"devDependencies": {
|
||||||
|
"csv-parse": "1.0.1",
|
||||||
|
"eslint": "2.10.2",
|
||||||
|
"eslint-config-standard": "5.3.1",
|
||||||
|
"eslint-plugin-promise": "1.1.0",
|
||||||
|
"eslint-plugin-standard": "1.3.2",
|
||||||
|
"istanbul": "0.4.3",
|
||||||
|
"mocha": "1.21.5",
|
||||||
|
"stream-to-array": "2.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "node scripts/build.js",
|
||||||
|
"fetch": "node scripts/fetch.js",
|
||||||
|
"lint": "eslint **/*.js",
|
||||||
|
"test": "mocha --reporter spec --check-leaks --bail test/",
|
||||||
|
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/",
|
||||||
|
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
|
||||||
|
"update": "npm run fetch && npm run build"
|
||||||
|
},
|
||||||
|
"gitHead": "b3e31e8c32dd8107e898b44b8c0b2dfff3cba495",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/jshttp/statuses/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/jshttp/statuses",
|
||||||
|
"_id": "statuses@1.3.0",
|
||||||
|
"_shasum": "8e55758cb20e7682c1f4fce8dcab30bf01d1e07a",
|
||||||
|
"_from": "statuses@>=1.3.0 <2.0.0",
|
||||||
|
"_npmVersion": "1.4.28",
|
||||||
|
"_npmUser": {
|
||||||
|
"name": "dougwilson",
|
||||||
|
"email": "doug@somethingdoug.com"
|
||||||
|
},
|
||||||
|
"maintainers": [
|
||||||
|
{
|
||||||
|
"name": "defunctzombie",
|
||||||
|
"email": "shtylman@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dougwilson",
|
||||||
|
"email": "doug@somethingdoug.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "fishrock123",
|
||||||
|
"email": "fishrock123@rocketmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "jongleberry",
|
||||||
|
"email": "jonathanrichardong@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "mscdex",
|
||||||
|
"email": "mscdex@mscdex.net"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tjholowaychuk",
|
||||||
|
"email": "tj@vision-media.ca"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dist": {
|
||||||
|
"shasum": "8e55758cb20e7682c1f4fce8dcab30bf01d1e07a",
|
||||||
|
"tarball": "https://registry.npmjs.org/statuses/-/statuses-1.3.0.tgz"
|
||||||
|
},
|
||||||
|
"_npmOperationalInternal": {
|
||||||
|
"host": "packages-12-west.internal.npmjs.com",
|
||||||
|
"tmp": "tmp/statuses-1.3.0.tgz_1463517875633_0.19560232176445425"
|
||||||
|
},
|
||||||
|
"directories": {},
|
||||||
|
"_resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.0.tgz",
|
||||||
|
"readme": "ERROR: No README data found!"
|
||||||
|
}
|
||||||
@ -0,0 +1,96 @@
|
|||||||
|
{
|
||||||
|
"name": "http-errors",
|
||||||
|
"description": "Create HTTP error objects",
|
||||||
|
"version": "1.5.0",
|
||||||
|
"author": {
|
||||||
|
"name": "Jonathan Ong",
|
||||||
|
"email": "me@jongleberry.com",
|
||||||
|
"url": "http://jongleberry.com"
|
||||||
|
},
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Alan Plum",
|
||||||
|
"email": "me@pluma.io"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Douglas Christopher Wilson",
|
||||||
|
"email": "doug@somethingdoug.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/jshttp/http-errors.git"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "2.0.1",
|
||||||
|
"setprototypeof": "1.0.1",
|
||||||
|
"statuses": ">= 1.3.0 < 2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"eslint": "2.10.2",
|
||||||
|
"eslint-config-standard": "5.3.1",
|
||||||
|
"eslint-plugin-promise": "1.1.0",
|
||||||
|
"eslint-plugin-standard": "1.3.2",
|
||||||
|
"istanbul": "0.4.3",
|
||||||
|
"mocha": "1.21.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"lint": "eslint **/*.js",
|
||||||
|
"test": "mocha --reporter spec --bail",
|
||||||
|
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot",
|
||||||
|
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter dot"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"http",
|
||||||
|
"error"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"index.js",
|
||||||
|
"HISTORY.md",
|
||||||
|
"LICENSE",
|
||||||
|
"README.md"
|
||||||
|
],
|
||||||
|
"gitHead": "1a826d7ac31dde16931b9c566041697939ebd0e0",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/jshttp/http-errors/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/jshttp/http-errors#readme",
|
||||||
|
"_id": "http-errors@1.5.0",
|
||||||
|
"_shasum": "b1cb3d8260fd8e2386cad3189045943372d48211",
|
||||||
|
"_from": "http-errors@>=1.5.0 <1.6.0",
|
||||||
|
"_npmVersion": "2.15.1",
|
||||||
|
"_nodeVersion": "4.4.3",
|
||||||
|
"_npmUser": {
|
||||||
|
"name": "dougwilson",
|
||||||
|
"email": "doug@somethingdoug.com"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"shasum": "b1cb3d8260fd8e2386cad3189045943372d48211",
|
||||||
|
"tarball": "https://registry.npmjs.org/http-errors/-/http-errors-1.5.0.tgz"
|
||||||
|
},
|
||||||
|
"maintainers": [
|
||||||
|
{
|
||||||
|
"name": "dougwilson",
|
||||||
|
"email": "doug@somethingdoug.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "egeste",
|
||||||
|
"email": "npm@egeste.net"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "jongleberry",
|
||||||
|
"email": "jonathanrichardong@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_npmOperationalInternal": {
|
||||||
|
"host": "packages-16-east.internal.npmjs.com",
|
||||||
|
"tmp": "tmp/http-errors-1.5.0.tgz_1463621678183_0.44013352948240936"
|
||||||
|
},
|
||||||
|
"directories": {},
|
||||||
|
"_resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.5.0.tgz",
|
||||||
|
"readme": "ERROR: No README data found!"
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
*~
|
||||||
|
*sublime-*
|
||||||
|
generation
|
||||||
|
test
|
||||||
|
wiki
|
||||||
|
coverage
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
sudo: false
|
||||||
|
env:
|
||||||
|
- CXX=g++-4.8
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- "0.8"
|
||||||
|
- "0.10"
|
||||||
|
- "0.11"
|
||||||
|
- "0.12"
|
||||||
|
- "iojs"
|
||||||
|
- "4.0"
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
packages:
|
||||||
|
- gcc-4.8
|
||||||
|
- g++-4.8
|
||||||
|
before_install:
|
||||||
|
- "test $TRAVIS_NODE_VERSION != '0.8' || npm install -g npm@1.2.8000"
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
|
||||||
|
# 0.4.13 / 2015-10-01
|
||||||
|
|
||||||
|
* Fix silly mistake in deprecation notice.
|
||||||
|
|
||||||
|
|
||||||
|
# 0.4.12 / 2015-09-26
|
||||||
|
|
||||||
|
* Node v4 support:
|
||||||
|
* Added CESU-8 decoding (#106)
|
||||||
|
* Added deprecation notice for `extendNodeEncodings`
|
||||||
|
* Added Travis tests for Node v4 and io.js latest (#105 by @Mithgol)
|
||||||
|
|
||||||
|
|
||||||
|
# 0.4.11 / 2015-07-03
|
||||||
|
|
||||||
|
* Added CESU-8 encoding.
|
||||||
|
|
||||||
|
|
||||||
|
# 0.4.10 / 2015-05-26
|
||||||
|
|
||||||
|
* Changed UTF-16 endianness heuristic to take into account any ASCII chars, not
|
||||||
|
just spaces. This should minimize the importance of "default" endianness.
|
||||||
|
|
||||||
|
|
||||||
|
# 0.4.9 / 2015-05-24
|
||||||
|
|
||||||
|
* Streamlined BOM handling: strip BOM by default, add BOM when encoding if
|
||||||
|
addBOM: true. Added docs to Readme.
|
||||||
|
* UTF16 now uses UTF16-LE by default.
|
||||||
|
* Fixed minor issue with big5 encoding.
|
||||||
|
* Added io.js testing on Travis; updated node-iconv version to test against.
|
||||||
|
Now we just skip testing SBCS encodings that node-iconv doesn't support.
|
||||||
|
* (internal refactoring) Updated codec interface to use classes.
|
||||||
|
* Use strict mode in all files.
|
||||||
|
|
||||||
|
|
||||||
|
# 0.4.8 / 2015-04-14
|
||||||
|
|
||||||
|
* added alias UNICODE-1-1-UTF-7 for UTF-7 encoding (#94)
|
||||||
|
|
||||||
|
|
||||||
|
# 0.4.7 / 2015-02-05
|
||||||
|
|
||||||
|
* stop official support of Node.js v0.8. Should still work, but no guarantees.
|
||||||
|
reason: Packages needed for testing are hard to get on Travis CI.
|
||||||
|
* work in environment where Object.prototype is monkey patched with enumerable
|
||||||
|
props (#89).
|
||||||
|
|
||||||
|
|
||||||
|
# 0.4.6 / 2015-01-12
|
||||||
|
|
||||||
|
* fix rare aliases of single-byte encodings (thanks @mscdex)
|
||||||
|
* double the timeout for dbcs tests to make them less flaky on travis
|
||||||
|
|
||||||
|
|
||||||
|
# 0.4.5 / 2014-11-20
|
||||||
|
|
||||||
|
* fix windows-31j and x-sjis encoding support (@nleush)
|
||||||
|
* minor fix: undefined variable reference when internal error happens
|
||||||
|
|
||||||
|
|
||||||
|
# 0.4.4 / 2014-07-16
|
||||||
|
|
||||||
|
* added encodings UTF-7 (RFC2152) and UTF-7-IMAP (RFC3501 Section 5.1.3)
|
||||||
|
* fixed streaming base64 encoding
|
||||||
|
|
||||||
|
|
||||||
|
# 0.4.3 / 2014-06-14
|
||||||
|
|
||||||
|
* added encodings UTF-16BE and UTF-16 with BOM
|
||||||
|
|
||||||
|
|
||||||
|
# 0.4.2 / 2014-06-12
|
||||||
|
|
||||||
|
* don't throw exception if `extendNodeEncodings()` is called more than once
|
||||||
|
|
||||||
|
|
||||||
|
# 0.4.1 / 2014-06-11
|
||||||
|
|
||||||
|
* codepage 808 added
|
||||||
|
|
||||||
|
|
||||||
|
# 0.4.0 / 2014-06-10
|
||||||
|
|
||||||
|
* code is rewritten from scratch
|
||||||
|
* all widespread encodings are supported
|
||||||
|
* streaming interface added
|
||||||
|
* browserify compatibility added
|
||||||
|
* (optional) extend core primitive encodings to make usage even simpler
|
||||||
|
* moved from vows to mocha as the testing framework
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
Copyright (c) 2011 Alexander Shtuchkin
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
@ -0,0 +1,554 @@
|
|||||||
|
"use strict"
|
||||||
|
|
||||||
|
// Multibyte codec. In this scheme, a character is represented by 1 or more bytes.
|
||||||
|
// Our codec supports UTF-16 surrogates, extensions for GB18030 and unicode sequences.
|
||||||
|
// To save memory and loading time, we read table files only when requested.
|
||||||
|
|
||||||
|
exports._dbcs = DBCSCodec;
|
||||||
|
|
||||||
|
var UNASSIGNED = -1,
|
||||||
|
GB18030_CODE = -2,
|
||||||
|
SEQ_START = -10,
|
||||||
|
NODE_START = -1000,
|
||||||
|
UNASSIGNED_NODE = new Array(0x100),
|
||||||
|
DEF_CHAR = -1;
|
||||||
|
|
||||||
|
for (var i = 0; i < 0x100; i++)
|
||||||
|
UNASSIGNED_NODE[i] = UNASSIGNED;
|
||||||
|
|
||||||
|
|
||||||
|
// Class DBCSCodec reads and initializes mapping tables.
|
||||||
|
function DBCSCodec(codecOptions, iconv) {
|
||||||
|
this.encodingName = codecOptions.encodingName;
|
||||||
|
if (!codecOptions)
|
||||||
|
throw new Error("DBCS codec is called without the data.")
|
||||||
|
if (!codecOptions.table)
|
||||||
|
throw new Error("Encoding '" + this.encodingName + "' has no data.");
|
||||||
|
|
||||||
|
// Load tables.
|
||||||
|
var mappingTable = codecOptions.table();
|
||||||
|
|
||||||
|
|
||||||
|
// Decode tables: MBCS -> Unicode.
|
||||||
|
|
||||||
|
// decodeTables is a trie, encoded as an array of arrays of integers. Internal arrays are trie nodes and all have len = 256.
|
||||||
|
// Trie root is decodeTables[0].
|
||||||
|
// Values: >= 0 -> unicode character code. can be > 0xFFFF
|
||||||
|
// == UNASSIGNED -> unknown/unassigned sequence.
|
||||||
|
// == GB18030_CODE -> this is the end of a GB18030 4-byte sequence.
|
||||||
|
// <= NODE_START -> index of the next node in our trie to process next byte.
|
||||||
|
// <= SEQ_START -> index of the start of a character code sequence, in decodeTableSeq.
|
||||||
|
this.decodeTables = [];
|
||||||
|
this.decodeTables[0] = UNASSIGNED_NODE.slice(0); // Create root node.
|
||||||
|
|
||||||
|
// Sometimes a MBCS char corresponds to a sequence of unicode chars. We store them as arrays of integers here.
|
||||||
|
this.decodeTableSeq = [];
|
||||||
|
|
||||||
|
// Actual mapping tables consist of chunks. Use them to fill up decode tables.
|
||||||
|
for (var i = 0; i < mappingTable.length; i++)
|
||||||
|
this._addDecodeChunk(mappingTable[i]);
|
||||||
|
|
||||||
|
this.defaultCharUnicode = iconv.defaultCharUnicode;
|
||||||
|
|
||||||
|
|
||||||
|
// Encode tables: Unicode -> DBCS.
|
||||||
|
|
||||||
|
// `encodeTable` is array mapping from unicode char to encoded char. All its values are integers for performance.
|
||||||
|
// Because it can be sparse, it is represented as array of buckets by 256 chars each. Bucket can be null.
|
||||||
|
// Values: >= 0 -> it is a normal char. Write the value (if <=256 then 1 byte, if <=65536 then 2 bytes, etc.).
|
||||||
|
// == UNASSIGNED -> no conversion found. Output a default char.
|
||||||
|
// <= SEQ_START -> it's an index in encodeTableSeq, see below. The character starts a sequence.
|
||||||
|
this.encodeTable = [];
|
||||||
|
|
||||||
|
// `encodeTableSeq` is used when a sequence of unicode characters is encoded as a single code. We use a tree of
|
||||||
|
// objects where keys correspond to characters in sequence and leafs are the encoded dbcs values. A special DEF_CHAR key
|
||||||
|
// means end of sequence (needed when one sequence is a strict subsequence of another).
|
||||||
|
// Objects are kept separately from encodeTable to increase performance.
|
||||||
|
this.encodeTableSeq = [];
|
||||||
|
|
||||||
|
// Some chars can be decoded, but need not be encoded.
|
||||||
|
var skipEncodeChars = {};
|
||||||
|
if (codecOptions.encodeSkipVals)
|
||||||
|
for (var i = 0; i < codecOptions.encodeSkipVals.length; i++) {
|
||||||
|
var val = codecOptions.encodeSkipVals[i];
|
||||||
|
if (typeof val === 'number')
|
||||||
|
skipEncodeChars[val] = true;
|
||||||
|
else
|
||||||
|
for (var j = val.from; j <= val.to; j++)
|
||||||
|
skipEncodeChars[j] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use decode trie to recursively fill out encode tables.
|
||||||
|
this._fillEncodeTable(0, 0, skipEncodeChars);
|
||||||
|
|
||||||
|
// Add more encoding pairs when needed.
|
||||||
|
if (codecOptions.encodeAdd) {
|
||||||
|
for (var uChar in codecOptions.encodeAdd)
|
||||||
|
if (Object.prototype.hasOwnProperty.call(codecOptions.encodeAdd, uChar))
|
||||||
|
this._setEncodeChar(uChar.charCodeAt(0), codecOptions.encodeAdd[uChar]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.defCharSB = this.encodeTable[0][iconv.defaultCharSingleByte.charCodeAt(0)];
|
||||||
|
if (this.defCharSB === UNASSIGNED) this.defCharSB = this.encodeTable[0]['?'];
|
||||||
|
if (this.defCharSB === UNASSIGNED) this.defCharSB = "?".charCodeAt(0);
|
||||||
|
|
||||||
|
|
||||||
|
// Load & create GB18030 tables when needed.
|
||||||
|
if (typeof codecOptions.gb18030 === 'function') {
|
||||||
|
this.gb18030 = codecOptions.gb18030(); // Load GB18030 ranges.
|
||||||
|
|
||||||
|
// Add GB18030 decode tables.
|
||||||
|
var thirdByteNodeIdx = this.decodeTables.length;
|
||||||
|
var thirdByteNode = this.decodeTables[thirdByteNodeIdx] = UNASSIGNED_NODE.slice(0);
|
||||||
|
|
||||||
|
var fourthByteNodeIdx = this.decodeTables.length;
|
||||||
|
var fourthByteNode = this.decodeTables[fourthByteNodeIdx] = UNASSIGNED_NODE.slice(0);
|
||||||
|
|
||||||
|
for (var i = 0x81; i <= 0xFE; i++) {
|
||||||
|
var secondByteNodeIdx = NODE_START - this.decodeTables[0][i];
|
||||||
|
var secondByteNode = this.decodeTables[secondByteNodeIdx];
|
||||||
|
for (var j = 0x30; j <= 0x39; j++)
|
||||||
|
secondByteNode[j] = NODE_START - thirdByteNodeIdx;
|
||||||
|
}
|
||||||
|
for (var i = 0x81; i <= 0xFE; i++)
|
||||||
|
thirdByteNode[i] = NODE_START - fourthByteNodeIdx;
|
||||||
|
for (var i = 0x30; i <= 0x39; i++)
|
||||||
|
fourthByteNode[i] = GB18030_CODE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DBCSCodec.prototype.encoder = DBCSEncoder;
|
||||||
|
DBCSCodec.prototype.decoder = DBCSDecoder;
|
||||||
|
|
||||||
|
// Decoder helpers
|
||||||
|
DBCSCodec.prototype._getDecodeTrieNode = function(addr) {
|
||||||
|
var bytes = [];
|
||||||
|
for (; addr > 0; addr >>= 8)
|
||||||
|
bytes.push(addr & 0xFF);
|
||||||
|
if (bytes.length == 0)
|
||||||
|
bytes.push(0);
|
||||||
|
|
||||||
|
var node = this.decodeTables[0];
|
||||||
|
for (var i = bytes.length-1; i > 0; i--) { // Traverse nodes deeper into the trie.
|
||||||
|
var val = node[bytes[i]];
|
||||||
|
|
||||||
|
if (val == UNASSIGNED) { // Create new node.
|
||||||
|
node[bytes[i]] = NODE_START - this.decodeTables.length;
|
||||||
|
this.decodeTables.push(node = UNASSIGNED_NODE.slice(0));
|
||||||
|
}
|
||||||
|
else if (val <= NODE_START) { // Existing node.
|
||||||
|
node = this.decodeTables[NODE_START - val];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new Error("Overwrite byte in " + this.encodingName + ", addr: " + addr.toString(16));
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DBCSCodec.prototype._addDecodeChunk = function(chunk) {
|
||||||
|
// First element of chunk is the hex mbcs code where we start.
|
||||||
|
var curAddr = parseInt(chunk[0], 16);
|
||||||
|
|
||||||
|
// Choose the decoding node where we'll write our chars.
|
||||||
|
var writeTable = this._getDecodeTrieNode(curAddr);
|
||||||
|
curAddr = curAddr & 0xFF;
|
||||||
|
|
||||||
|
// Write all other elements of the chunk to the table.
|
||||||
|
for (var k = 1; k < chunk.length; k++) {
|
||||||
|
var part = chunk[k];
|
||||||
|
if (typeof part === "string") { // String, write as-is.
|
||||||
|
for (var l = 0; l < part.length;) {
|
||||||
|
var code = part.charCodeAt(l++);
|
||||||
|
if (0xD800 <= code && code < 0xDC00) { // Decode surrogate
|
||||||
|
var codeTrail = part.charCodeAt(l++);
|
||||||
|
if (0xDC00 <= codeTrail && codeTrail < 0xE000)
|
||||||
|
writeTable[curAddr++] = 0x10000 + (code - 0xD800) * 0x400 + (codeTrail - 0xDC00);
|
||||||
|
else
|
||||||
|
throw new Error("Incorrect surrogate pair in " + this.encodingName + " at chunk " + chunk[0]);
|
||||||
|
}
|
||||||
|
else if (0x0FF0 < code && code <= 0x0FFF) { // Character sequence (our own encoding used)
|
||||||
|
var len = 0xFFF - code + 2;
|
||||||
|
var seq = [];
|
||||||
|
for (var m = 0; m < len; m++)
|
||||||
|
seq.push(part.charCodeAt(l++)); // Simple variation: don't support surrogates or subsequences in seq.
|
||||||
|
|
||||||
|
writeTable[curAddr++] = SEQ_START - this.decodeTableSeq.length;
|
||||||
|
this.decodeTableSeq.push(seq);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
writeTable[curAddr++] = code; // Basic char
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (typeof part === "number") { // Integer, meaning increasing sequence starting with prev character.
|
||||||
|
var charCode = writeTable[curAddr - 1] + 1;
|
||||||
|
for (var l = 0; l < part; l++)
|
||||||
|
writeTable[curAddr++] = charCode++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new Error("Incorrect type '" + typeof part + "' given in " + this.encodingName + " at chunk " + chunk[0]);
|
||||||
|
}
|
||||||
|
if (curAddr > 0xFF)
|
||||||
|
throw new Error("Incorrect chunk in " + this.encodingName + " at addr " + chunk[0] + ": too long" + curAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encoder helpers
|
||||||
|
DBCSCodec.prototype._getEncodeBucket = function(uCode) {
|
||||||
|
var high = uCode >> 8; // This could be > 0xFF because of astral characters.
|
||||||
|
if (this.encodeTable[high] === undefined)
|
||||||
|
this.encodeTable[high] = UNASSIGNED_NODE.slice(0); // Create bucket on demand.
|
||||||
|
return this.encodeTable[high];
|
||||||
|
}
|
||||||
|
|
||||||
|
DBCSCodec.prototype._setEncodeChar = function(uCode, dbcsCode) {
|
||||||
|
var bucket = this._getEncodeBucket(uCode);
|
||||||
|
var low = uCode & 0xFF;
|
||||||
|
if (bucket[low] <= SEQ_START)
|
||||||
|
this.encodeTableSeq[SEQ_START-bucket[low]][DEF_CHAR] = dbcsCode; // There's already a sequence, set a single-char subsequence of it.
|
||||||
|
else if (bucket[low] == UNASSIGNED)
|
||||||
|
bucket[low] = dbcsCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBCSCodec.prototype._setEncodeSequence = function(seq, dbcsCode) {
|
||||||
|
|
||||||
|
// Get the root of character tree according to first character of the sequence.
|
||||||
|
var uCode = seq[0];
|
||||||
|
var bucket = this._getEncodeBucket(uCode);
|
||||||
|
var low = uCode & 0xFF;
|
||||||
|
|
||||||
|
var node;
|
||||||
|
if (bucket[low] <= SEQ_START) {
|
||||||
|
// There's already a sequence with - use it.
|
||||||
|
node = this.encodeTableSeq[SEQ_START-bucket[low]];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// There was no sequence object - allocate a new one.
|
||||||
|
node = {};
|
||||||
|
if (bucket[low] !== UNASSIGNED) node[DEF_CHAR] = bucket[low]; // If a char was set before - make it a single-char subsequence.
|
||||||
|
bucket[low] = SEQ_START - this.encodeTableSeq.length;
|
||||||
|
this.encodeTableSeq.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traverse the character tree, allocating new nodes as needed.
|
||||||
|
for (var j = 1; j < seq.length-1; j++) {
|
||||||
|
var oldVal = node[uCode];
|
||||||
|
if (typeof oldVal === 'object')
|
||||||
|
node = oldVal;
|
||||||
|
else {
|
||||||
|
node = node[uCode] = {}
|
||||||
|
if (oldVal !== undefined)
|
||||||
|
node[DEF_CHAR] = oldVal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the leaf to given dbcsCode.
|
||||||
|
uCode = seq[seq.length-1];
|
||||||
|
node[uCode] = dbcsCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBCSCodec.prototype._fillEncodeTable = function(nodeIdx, prefix, skipEncodeChars) {
|
||||||
|
var node = this.decodeTables[nodeIdx];
|
||||||
|
for (var i = 0; i < 0x100; i++) {
|
||||||
|
var uCode = node[i];
|
||||||
|
var mbCode = prefix + i;
|
||||||
|
if (skipEncodeChars[mbCode])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (uCode >= 0)
|
||||||
|
this._setEncodeChar(uCode, mbCode);
|
||||||
|
else if (uCode <= NODE_START)
|
||||||
|
this._fillEncodeTable(NODE_START - uCode, mbCode << 8, skipEncodeChars);
|
||||||
|
else if (uCode <= SEQ_START)
|
||||||
|
this._setEncodeSequence(this.decodeTableSeq[SEQ_START - uCode], mbCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// == Encoder ==================================================================
|
||||||
|
|
||||||
|
function DBCSEncoder(options, codec) {
|
||||||
|
// Encoder state
|
||||||
|
this.leadSurrogate = -1;
|
||||||
|
this.seqObj = undefined;
|
||||||
|
|
||||||
|
// Static data
|
||||||
|
this.encodeTable = codec.encodeTable;
|
||||||
|
this.encodeTableSeq = codec.encodeTableSeq;
|
||||||
|
this.defaultCharSingleByte = codec.defCharSB;
|
||||||
|
this.gb18030 = codec.gb18030;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBCSEncoder.prototype.write = function(str) {
|
||||||
|
var newBuf = new Buffer(str.length * (this.gb18030 ? 4 : 3)),
|
||||||
|
leadSurrogate = this.leadSurrogate,
|
||||||
|
seqObj = this.seqObj, nextChar = -1,
|
||||||
|
i = 0, j = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// 0. Get next character.
|
||||||
|
if (nextChar === -1) {
|
||||||
|
if (i == str.length) break;
|
||||||
|
var uCode = str.charCodeAt(i++);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var uCode = nextChar;
|
||||||
|
nextChar = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Handle surrogates.
|
||||||
|
if (0xD800 <= uCode && uCode < 0xE000) { // Char is one of surrogates.
|
||||||
|
if (uCode < 0xDC00) { // We've got lead surrogate.
|
||||||
|
if (leadSurrogate === -1) {
|
||||||
|
leadSurrogate = uCode;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
leadSurrogate = uCode;
|
||||||
|
// Double lead surrogate found.
|
||||||
|
uCode = UNASSIGNED;
|
||||||
|
}
|
||||||
|
} else { // We've got trail surrogate.
|
||||||
|
if (leadSurrogate !== -1) {
|
||||||
|
uCode = 0x10000 + (leadSurrogate - 0xD800) * 0x400 + (uCode - 0xDC00);
|
||||||
|
leadSurrogate = -1;
|
||||||
|
} else {
|
||||||
|
// Incomplete surrogate pair - only trail surrogate found.
|
||||||
|
uCode = UNASSIGNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (leadSurrogate !== -1) {
|
||||||
|
// Incomplete surrogate pair - only lead surrogate found.
|
||||||
|
nextChar = uCode; uCode = UNASSIGNED; // Write an error, then current char.
|
||||||
|
leadSurrogate = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Convert uCode character.
|
||||||
|
var dbcsCode = UNASSIGNED;
|
||||||
|
if (seqObj !== undefined && uCode != UNASSIGNED) { // We are in the middle of the sequence
|
||||||
|
var resCode = seqObj[uCode];
|
||||||
|
if (typeof resCode === 'object') { // Sequence continues.
|
||||||
|
seqObj = resCode;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
} else if (typeof resCode == 'number') { // Sequence finished. Write it.
|
||||||
|
dbcsCode = resCode;
|
||||||
|
|
||||||
|
} else if (resCode == undefined) { // Current character is not part of the sequence.
|
||||||
|
|
||||||
|
// Try default character for this sequence
|
||||||
|
resCode = seqObj[DEF_CHAR];
|
||||||
|
if (resCode !== undefined) {
|
||||||
|
dbcsCode = resCode; // Found. Write it.
|
||||||
|
nextChar = uCode; // Current character will be written too in the next iteration.
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// TODO: What if we have no default? (resCode == undefined)
|
||||||
|
// Then, we should write first char of the sequence as-is and try the rest recursively.
|
||||||
|
// Didn't do it for now because no encoding has this situation yet.
|
||||||
|
// Currently, just skip the sequence and write current char.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seqObj = undefined;
|
||||||
|
}
|
||||||
|
else if (uCode >= 0) { // Regular character
|
||||||
|
var subtable = this.encodeTable[uCode >> 8];
|
||||||
|
if (subtable !== undefined)
|
||||||
|
dbcsCode = subtable[uCode & 0xFF];
|
||||||
|
|
||||||
|
if (dbcsCode <= SEQ_START) { // Sequence start
|
||||||
|
seqObj = this.encodeTableSeq[SEQ_START-dbcsCode];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dbcsCode == UNASSIGNED && this.gb18030) {
|
||||||
|
// Use GB18030 algorithm to find character(s) to write.
|
||||||
|
var idx = findIdx(this.gb18030.uChars, uCode);
|
||||||
|
if (idx != -1) {
|
||||||
|
var dbcsCode = this.gb18030.gbChars[idx] + (uCode - this.gb18030.uChars[idx]);
|
||||||
|
newBuf[j++] = 0x81 + Math.floor(dbcsCode / 12600); dbcsCode = dbcsCode % 12600;
|
||||||
|
newBuf[j++] = 0x30 + Math.floor(dbcsCode / 1260); dbcsCode = dbcsCode % 1260;
|
||||||
|
newBuf[j++] = 0x81 + Math.floor(dbcsCode / 10); dbcsCode = dbcsCode % 10;
|
||||||
|
newBuf[j++] = 0x30 + dbcsCode;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Write dbcsCode character.
|
||||||
|
if (dbcsCode === UNASSIGNED)
|
||||||
|
dbcsCode = this.defaultCharSingleByte;
|
||||||
|
|
||||||
|
if (dbcsCode < 0x100) {
|
||||||
|
newBuf[j++] = dbcsCode;
|
||||||
|
}
|
||||||
|
else if (dbcsCode < 0x10000) {
|
||||||
|
newBuf[j++] = dbcsCode >> 8; // high byte
|
||||||
|
newBuf[j++] = dbcsCode & 0xFF; // low byte
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newBuf[j++] = dbcsCode >> 16;
|
||||||
|
newBuf[j++] = (dbcsCode >> 8) & 0xFF;
|
||||||
|
newBuf[j++] = dbcsCode & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.seqObj = seqObj;
|
||||||
|
this.leadSurrogate = leadSurrogate;
|
||||||
|
return newBuf.slice(0, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
DBCSEncoder.prototype.end = function() {
|
||||||
|
if (this.leadSurrogate === -1 && this.seqObj === undefined)
|
||||||
|
return; // All clean. Most often case.
|
||||||
|
|
||||||
|
var newBuf = new Buffer(10), j = 0;
|
||||||
|
|
||||||
|
if (this.seqObj) { // We're in the sequence.
|
||||||
|
var dbcsCode = this.seqObj[DEF_CHAR];
|
||||||
|
if (dbcsCode !== undefined) { // Write beginning of the sequence.
|
||||||
|
if (dbcsCode < 0x100) {
|
||||||
|
newBuf[j++] = dbcsCode;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newBuf[j++] = dbcsCode >> 8; // high byte
|
||||||
|
newBuf[j++] = dbcsCode & 0xFF; // low byte
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// See todo above.
|
||||||
|
}
|
||||||
|
this.seqObj = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.leadSurrogate !== -1) {
|
||||||
|
// Incomplete surrogate pair - only lead surrogate found.
|
||||||
|
newBuf[j++] = this.defaultCharSingleByte;
|
||||||
|
this.leadSurrogate = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newBuf.slice(0, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export for testing
|
||||||
|
DBCSEncoder.prototype.findIdx = findIdx;
|
||||||
|
|
||||||
|
|
||||||
|
// == Decoder ==================================================================
|
||||||
|
|
||||||
|
function DBCSDecoder(options, codec) {
|
||||||
|
// Decoder state
|
||||||
|
this.nodeIdx = 0;
|
||||||
|
this.prevBuf = new Buffer(0);
|
||||||
|
|
||||||
|
// Static data
|
||||||
|
this.decodeTables = codec.decodeTables;
|
||||||
|
this.decodeTableSeq = codec.decodeTableSeq;
|
||||||
|
this.defaultCharUnicode = codec.defaultCharUnicode;
|
||||||
|
this.gb18030 = codec.gb18030;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBCSDecoder.prototype.write = function(buf) {
|
||||||
|
var newBuf = new Buffer(buf.length*2),
|
||||||
|
nodeIdx = this.nodeIdx,
|
||||||
|
prevBuf = this.prevBuf, prevBufOffset = this.prevBuf.length,
|
||||||
|
seqStart = -this.prevBuf.length, // idx of the start of current parsed sequence.
|
||||||
|
uCode;
|
||||||
|
|
||||||
|
if (prevBufOffset > 0) // Make prev buf overlap a little to make it easier to slice later.
|
||||||
|
prevBuf = Buffer.concat([prevBuf, buf.slice(0, 10)]);
|
||||||
|
|
||||||
|
for (var i = 0, j = 0; i < buf.length; i++) {
|
||||||
|
var curByte = (i >= 0) ? buf[i] : prevBuf[i + prevBufOffset];
|
||||||
|
|
||||||
|
// Lookup in current trie node.
|
||||||
|
var uCode = this.decodeTables[nodeIdx][curByte];
|
||||||
|
|
||||||
|
if (uCode >= 0) {
|
||||||
|
// Normal character, just use it.
|
||||||
|
}
|
||||||
|
else if (uCode === UNASSIGNED) { // Unknown char.
|
||||||
|
// TODO: Callback with seq.
|
||||||
|
//var curSeq = (seqStart >= 0) ? buf.slice(seqStart, i+1) : prevBuf.slice(seqStart + prevBufOffset, i+1 + prevBufOffset);
|
||||||
|
i = seqStart; // Try to parse again, after skipping first byte of the sequence ('i' will be incremented by 'for' cycle).
|
||||||
|
uCode = this.defaultCharUnicode.charCodeAt(0);
|
||||||
|
}
|
||||||
|
else if (uCode === GB18030_CODE) {
|
||||||
|
var curSeq = (seqStart >= 0) ? buf.slice(seqStart, i+1) : prevBuf.slice(seqStart + prevBufOffset, i+1 + prevBufOffset);
|
||||||
|
var ptr = (curSeq[0]-0x81)*12600 + (curSeq[1]-0x30)*1260 + (curSeq[2]-0x81)*10 + (curSeq[3]-0x30);
|
||||||
|
var idx = findIdx(this.gb18030.gbChars, ptr);
|
||||||
|
uCode = this.gb18030.uChars[idx] + ptr - this.gb18030.gbChars[idx];
|
||||||
|
}
|
||||||
|
else if (uCode <= NODE_START) { // Go to next trie node.
|
||||||
|
nodeIdx = NODE_START - uCode;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (uCode <= SEQ_START) { // Output a sequence of chars.
|
||||||
|
var seq = this.decodeTableSeq[SEQ_START - uCode];
|
||||||
|
for (var k = 0; k < seq.length - 1; k++) {
|
||||||
|
uCode = seq[k];
|
||||||
|
newBuf[j++] = uCode & 0xFF;
|
||||||
|
newBuf[j++] = uCode >> 8;
|
||||||
|
}
|
||||||
|
uCode = seq[seq.length-1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new Error("iconv-lite internal error: invalid decoding table value " + uCode + " at " + nodeIdx + "/" + curByte);
|
||||||
|
|
||||||
|
// Write the character to buffer, handling higher planes using surrogate pair.
|
||||||
|
if (uCode > 0xFFFF) {
|
||||||
|
uCode -= 0x10000;
|
||||||
|
var uCodeLead = 0xD800 + Math.floor(uCode / 0x400);
|
||||||
|
newBuf[j++] = uCodeLead & 0xFF;
|
||||||
|
newBuf[j++] = uCodeLead >> 8;
|
||||||
|
|
||||||
|
uCode = 0xDC00 + uCode % 0x400;
|
||||||
|
}
|
||||||
|
newBuf[j++] = uCode & 0xFF;
|
||||||
|
newBuf[j++] = uCode >> 8;
|
||||||
|
|
||||||
|
// Reset trie node.
|
||||||
|
nodeIdx = 0; seqStart = i+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.nodeIdx = nodeIdx;
|
||||||
|
this.prevBuf = (seqStart >= 0) ? buf.slice(seqStart) : prevBuf.slice(seqStart + prevBufOffset);
|
||||||
|
return newBuf.slice(0, j).toString('ucs2');
|
||||||
|
}
|
||||||
|
|
||||||
|
DBCSDecoder.prototype.end = function() {
|
||||||
|
var ret = '';
|
||||||
|
|
||||||
|
// Try to parse all remaining chars.
|
||||||
|
while (this.prevBuf.length > 0) {
|
||||||
|
// Skip 1 character in the buffer.
|
||||||
|
ret += this.defaultCharUnicode;
|
||||||
|
var buf = this.prevBuf.slice(1);
|
||||||
|
|
||||||
|
// Parse remaining as usual.
|
||||||
|
this.prevBuf = new Buffer(0);
|
||||||
|
this.nodeIdx = 0;
|
||||||
|
if (buf.length > 0)
|
||||||
|
ret += this.write(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.nodeIdx = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binary search for GB18030. Returns largest i such that table[i] <= val.
|
||||||
|
function findIdx(table, val) {
|
||||||
|
if (table[0] > val)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
var l = 0, r = table.length;
|
||||||
|
while (l < r-1) { // always table[l] <= val < table[r]
|
||||||
|
var mid = l + Math.floor((r-l+1)/2);
|
||||||
|
if (table[mid] <= val)
|
||||||
|
l = mid;
|
||||||
|
else
|
||||||
|
r = mid;
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
@ -0,0 +1,170 @@
|
|||||||
|
"use strict"
|
||||||
|
|
||||||
|
// Description of supported double byte encodings and aliases.
|
||||||
|
// Tables are not require()-d until they are needed to speed up library load.
|
||||||
|
// require()-s are direct to support Browserify.
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
|
||||||
|
// == Japanese/ShiftJIS ====================================================
|
||||||
|
// All japanese encodings are based on JIS X set of standards:
|
||||||
|
// JIS X 0201 - Single-byte encoding of ASCII + ¥ + Kana chars at 0xA1-0xDF.
|
||||||
|
// JIS X 0208 - Main set of 6879 characters, placed in 94x94 plane, to be encoded by 2 bytes.
|
||||||
|
// Has several variations in 1978, 1983, 1990 and 1997.
|
||||||
|
// JIS X 0212 - Supplementary plane of 6067 chars in 94x94 plane. 1990. Effectively dead.
|
||||||
|
// JIS X 0213 - Extension and modern replacement of 0208 and 0212. Total chars: 11233.
|
||||||
|
// 2 planes, first is superset of 0208, second - revised 0212.
|
||||||
|
// Introduced in 2000, revised 2004. Some characters are in Unicode Plane 2 (0x2xxxx)
|
||||||
|
|
||||||
|
// Byte encodings are:
|
||||||
|
// * Shift_JIS: Compatible with 0201, uses not defined chars in top half as lead bytes for double-byte
|
||||||
|
// encoding of 0208. Lead byte ranges: 0x81-0x9F, 0xE0-0xEF; Trail byte ranges: 0x40-0x7E, 0x80-0x9E, 0x9F-0xFC.
|
||||||
|
// Windows CP932 is a superset of Shift_JIS. Some companies added more chars, notably KDDI.
|
||||||
|
// * EUC-JP: Up to 3 bytes per character. Used mostly on *nixes.
|
||||||
|
// 0x00-0x7F - lower part of 0201
|
||||||
|
// 0x8E, 0xA1-0xDF - upper part of 0201
|
||||||
|
// (0xA1-0xFE)x2 - 0208 plane (94x94).
|
||||||
|
// 0x8F, (0xA1-0xFE)x2 - 0212 plane (94x94).
|
||||||
|
// * JIS X 208: 7-bit, direct encoding of 0208. Byte ranges: 0x21-0x7E (94 values). Uncommon.
|
||||||
|
// Used as-is in ISO2022 family.
|
||||||
|
// * ISO2022-JP: Stateful encoding, with escape sequences to switch between ASCII,
|
||||||
|
// 0201-1976 Roman, 0208-1978, 0208-1983.
|
||||||
|
// * ISO2022-JP-1: Adds esc seq for 0212-1990.
|
||||||
|
// * ISO2022-JP-2: Adds esc seq for GB2313-1980, KSX1001-1992, ISO8859-1, ISO8859-7.
|
||||||
|
// * ISO2022-JP-3: Adds esc seq for 0201-1976 Kana set, 0213-2000 Planes 1, 2.
|
||||||
|
// * ISO2022-JP-2004: Adds 0213-2004 Plane 1.
|
||||||
|
//
|
||||||
|
// After JIS X 0213 appeared, Shift_JIS-2004, EUC-JISX0213 and ISO2022-JP-2004 followed, with just changing the planes.
|
||||||
|
//
|
||||||
|
// Overall, it seems that it's a mess :( http://www8.plala.or.jp/tkubota1/unicode-symbols-map2.html
|
||||||
|
|
||||||
|
|
||||||
|
'shiftjis': {
|
||||||
|
type: '_dbcs',
|
||||||
|
table: function() { return require('./tables/shiftjis.json') },
|
||||||
|
encodeAdd: {'\u00a5': 0x5C, '\u203E': 0x7E},
|
||||||
|
encodeSkipVals: [{from: 0xED40, to: 0xF940}],
|
||||||
|
},
|
||||||
|
'csshiftjis': 'shiftjis',
|
||||||
|
'mskanji': 'shiftjis',
|
||||||
|
'sjis': 'shiftjis',
|
||||||
|
'windows31j': 'shiftjis',
|
||||||
|
'xsjis': 'shiftjis',
|
||||||
|
'windows932': 'shiftjis',
|
||||||
|
'932': 'shiftjis',
|
||||||
|
'cp932': 'shiftjis',
|
||||||
|
|
||||||
|
'eucjp': {
|
||||||
|
type: '_dbcs',
|
||||||
|
table: function() { return require('./tables/eucjp.json') },
|
||||||
|
encodeAdd: {'\u00a5': 0x5C, '\u203E': 0x7E},
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: KDDI extension to Shift_JIS
|
||||||
|
// TODO: IBM CCSID 942 = CP932, but F0-F9 custom chars and other char changes.
|
||||||
|
// TODO: IBM CCSID 943 = Shift_JIS = CP932 with original Shift_JIS lower 128 chars.
|
||||||
|
|
||||||
|
// == Chinese/GBK ==========================================================
|
||||||
|
// http://en.wikipedia.org/wiki/GBK
|
||||||
|
|
||||||
|
// Oldest GB2312 (1981, ~7600 chars) is a subset of CP936
|
||||||
|
'gb2312': 'cp936',
|
||||||
|
'gb231280': 'cp936',
|
||||||
|
'gb23121980': 'cp936',
|
||||||
|
'csgb2312': 'cp936',
|
||||||
|
'csiso58gb231280': 'cp936',
|
||||||
|
'euccn': 'cp936',
|
||||||
|
'isoir58': 'gbk',
|
||||||
|
|
||||||
|
// Microsoft's CP936 is a subset and approximation of GBK.
|
||||||
|
// TODO: Euro = 0x80 in cp936, but not in GBK (where it's valid but undefined)
|
||||||
|
'windows936': 'cp936',
|
||||||
|
'936': 'cp936',
|
||||||
|
'cp936': {
|
||||||
|
type: '_dbcs',
|
||||||
|
table: function() { return require('./tables/cp936.json') },
|
||||||
|
},
|
||||||
|
|
||||||
|
// GBK (~22000 chars) is an extension of CP936 that added user-mapped chars and some other.
|
||||||
|
'gbk': {
|
||||||
|
type: '_dbcs',
|
||||||
|
table: function() { return require('./tables/cp936.json').concat(require('./tables/gbk-added.json')) },
|
||||||
|
},
|
||||||
|
'xgbk': 'gbk',
|
||||||
|
|
||||||
|
// GB18030 is an algorithmic extension of GBK.
|
||||||
|
'gb18030': {
|
||||||
|
type: '_dbcs',
|
||||||
|
table: function() { return require('./tables/cp936.json').concat(require('./tables/gbk-added.json')) },
|
||||||
|
gb18030: function() { return require('./tables/gb18030-ranges.json') },
|
||||||
|
},
|
||||||
|
|
||||||
|
'chinese': 'gb18030',
|
||||||
|
|
||||||
|
// TODO: Support GB18030 (~27000 chars + whole unicode mapping, cp54936)
|
||||||
|
// http://icu-project.org/docs/papers/gb18030.html
|
||||||
|
// http://source.icu-project.org/repos/icu/data/trunk/charset/data/xml/gb-18030-2000.xml
|
||||||
|
// http://www.khngai.com/chinese/charmap/tblgbk.php?page=0
|
||||||
|
|
||||||
|
// == Korean ===============================================================
|
||||||
|
// EUC-KR, KS_C_5601 and KS X 1001 are exactly the same.
|
||||||
|
'windows949': 'cp949',
|
||||||
|
'949': 'cp949',
|
||||||
|
'cp949': {
|
||||||
|
type: '_dbcs',
|
||||||
|
table: function() { return require('./tables/cp949.json') },
|
||||||
|
},
|
||||||
|
|
||||||
|
'cseuckr': 'cp949',
|
||||||
|
'csksc56011987': 'cp949',
|
||||||
|
'euckr': 'cp949',
|
||||||
|
'isoir149': 'cp949',
|
||||||
|
'korean': 'cp949',
|
||||||
|
'ksc56011987': 'cp949',
|
||||||
|
'ksc56011989': 'cp949',
|
||||||
|
'ksc5601': 'cp949',
|
||||||
|
|
||||||
|
|
||||||
|
// == Big5/Taiwan/Hong Kong ================================================
|
||||||
|
// There are lots of tables for Big5 and cp950. Please see the following links for history:
|
||||||
|
// http://moztw.org/docs/big5/ http://www.haible.de/bruno/charsets/conversion-tables/Big5.html
|
||||||
|
// Variations, in roughly number of defined chars:
|
||||||
|
// * Windows CP 950: Microsoft variant of Big5. Canonical: http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP950.TXT
|
||||||
|
// * Windows CP 951: Microsoft variant of Big5-HKSCS-2001. Seems to be never public. http://me.abelcheung.org/articles/research/what-is-cp951/
|
||||||
|
// * Big5-2003 (Taiwan standard) almost superset of cp950.
|
||||||
|
// * Unicode-at-on (UAO) / Mozilla 1.8. Falling out of use on the Web. Not supported by other browsers.
|
||||||
|
// * Big5-HKSCS (-2001, -2004, -2008). Hong Kong standard.
|
||||||
|
// many unicode code points moved from PUA to Supplementary plane (U+2XXXX) over the years.
|
||||||
|
// Plus, it has 4 combining sequences.
|
||||||
|
// Seems that Mozilla refused to support it for 10 yrs. https://bugzilla.mozilla.org/show_bug.cgi?id=162431 https://bugzilla.mozilla.org/show_bug.cgi?id=310299
|
||||||
|
// because big5-hkscs is the only encoding to include astral characters in non-algorithmic way.
|
||||||
|
// Implementations are not consistent within browsers; sometimes labeled as just big5.
|
||||||
|
// MS Internet Explorer switches from big5 to big5-hkscs when a patch applied.
|
||||||
|
// Great discussion & recap of what's going on https://bugzilla.mozilla.org/show_bug.cgi?id=912470#c31
|
||||||
|
// In the encoder, it might make sense to support encoding old PUA mappings to Big5 bytes seq-s.
|
||||||
|
// Official spec: http://www.ogcio.gov.hk/en/business/tech_promotion/ccli/terms/doc/2003cmp_2008.txt
|
||||||
|
// http://www.ogcio.gov.hk/tc/business/tech_promotion/ccli/terms/doc/hkscs-2008-big5-iso.txt
|
||||||
|
//
|
||||||
|
// Current understanding of how to deal with Big5(-HKSCS) is in the Encoding Standard, http://encoding.spec.whatwg.org/#big5-encoder
|
||||||
|
// Unicode mapping (http://www.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/OTHER/BIG5.TXT) is said to be wrong.
|
||||||
|
|
||||||
|
'windows950': 'cp950',
|
||||||
|
'950': 'cp950',
|
||||||
|
'cp950': {
|
||||||
|
type: '_dbcs',
|
||||||
|
table: function() { return require('./tables/cp950.json') },
|
||||||
|
},
|
||||||
|
|
||||||
|
// Big5 has many variations and is an extension of cp950. We use Encoding Standard's as a consensus.
|
||||||
|
'big5': 'big5hkscs',
|
||||||
|
'big5hkscs': {
|
||||||
|
type: '_dbcs',
|
||||||
|
table: function() { return require('./tables/cp950.json').concat(require('./tables/big5-added.json')) },
|
||||||
|
encodeSkipVals: [0xa2cc],
|
||||||
|
},
|
||||||
|
|
||||||
|
'cnbig5': 'big5hkscs',
|
||||||
|
'csbig5': 'big5hkscs',
|
||||||
|
'xxbig5': 'big5hkscs',
|
||||||
|
|
||||||
|
};
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
"use strict"
|
||||||
|
|
||||||
|
// Update this array if you add/rename/remove files in this directory.
|
||||||
|
// We support Browserify by skipping automatic module discovery and requiring modules directly.
|
||||||
|
var modules = [
|
||||||
|
require("./internal"),
|
||||||
|
require("./utf16"),
|
||||||
|
require("./utf7"),
|
||||||
|
require("./sbcs-codec"),
|
||||||
|
require("./sbcs-data"),
|
||||||
|
require("./sbcs-data-generated"),
|
||||||
|
require("./dbcs-codec"),
|
||||||
|
require("./dbcs-data"),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Put all encoding/alias/codec definitions to single object and export it.
|
||||||
|
for (var i = 0; i < modules.length; i++) {
|
||||||
|
var module = modules[i];
|
||||||
|
for (var enc in module)
|
||||||
|
if (Object.prototype.hasOwnProperty.call(module, enc))
|
||||||
|
exports[enc] = module[enc];
|
||||||
|
}
|
||||||
@ -0,0 +1,187 @@
|
|||||||
|
"use strict"
|
||||||
|
|
||||||
|
// Export Node.js internal encodings.
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// Encodings
|
||||||
|
utf8: { type: "_internal", bomAware: true},
|
||||||
|
cesu8: { type: "_internal", bomAware: true},
|
||||||
|
unicode11utf8: "utf8",
|
||||||
|
|
||||||
|
ucs2: { type: "_internal", bomAware: true},
|
||||||
|
utf16le: "ucs2",
|
||||||
|
|
||||||
|
binary: { type: "_internal" },
|
||||||
|
base64: { type: "_internal" },
|
||||||
|
hex: { type: "_internal" },
|
||||||
|
|
||||||
|
// Codec.
|
||||||
|
_internal: InternalCodec,
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function InternalCodec(codecOptions, iconv) {
|
||||||
|
this.enc = codecOptions.encodingName;
|
||||||
|
this.bomAware = codecOptions.bomAware;
|
||||||
|
|
||||||
|
if (this.enc === "base64")
|
||||||
|
this.encoder = InternalEncoderBase64;
|
||||||
|
else if (this.enc === "cesu8") {
|
||||||
|
this.enc = "utf8"; // Use utf8 for decoding.
|
||||||
|
this.encoder = InternalEncoderCesu8;
|
||||||
|
|
||||||
|
// Add decoder for versions of Node not supporting CESU-8
|
||||||
|
if (new Buffer("eda080", 'hex').toString().length == 3) {
|
||||||
|
this.decoder = InternalDecoderCesu8;
|
||||||
|
this.defaultCharUnicode = iconv.defaultCharUnicode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalCodec.prototype.encoder = InternalEncoder;
|
||||||
|
InternalCodec.prototype.decoder = InternalDecoder;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// We use node.js internal decoder. Its signature is the same as ours.
|
||||||
|
var StringDecoder = require('string_decoder').StringDecoder;
|
||||||
|
|
||||||
|
if (!StringDecoder.prototype.end) // Node v0.8 doesn't have this method.
|
||||||
|
StringDecoder.prototype.end = function() {};
|
||||||
|
|
||||||
|
|
||||||
|
function InternalDecoder(options, codec) {
|
||||||
|
StringDecoder.call(this, codec.enc);
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalDecoder.prototype = StringDecoder.prototype;
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Encoder is mostly trivial
|
||||||
|
|
||||||
|
function InternalEncoder(options, codec) {
|
||||||
|
this.enc = codec.enc;
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalEncoder.prototype.write = function(str) {
|
||||||
|
return new Buffer(str, this.enc);
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalEncoder.prototype.end = function() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Except base64 encoder, which must keep its state.
|
||||||
|
|
||||||
|
function InternalEncoderBase64(options, codec) {
|
||||||
|
this.prevStr = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalEncoderBase64.prototype.write = function(str) {
|
||||||
|
str = this.prevStr + str;
|
||||||
|
var completeQuads = str.length - (str.length % 4);
|
||||||
|
this.prevStr = str.slice(completeQuads);
|
||||||
|
str = str.slice(0, completeQuads);
|
||||||
|
|
||||||
|
return new Buffer(str, "base64");
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalEncoderBase64.prototype.end = function() {
|
||||||
|
return new Buffer(this.prevStr, "base64");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// CESU-8 encoder is also special.
|
||||||
|
|
||||||
|
function InternalEncoderCesu8(options, codec) {
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalEncoderCesu8.prototype.write = function(str) {
|
||||||
|
var buf = new Buffer(str.length * 3), bufIdx = 0;
|
||||||
|
for (var i = 0; i < str.length; i++) {
|
||||||
|
var charCode = str.charCodeAt(i);
|
||||||
|
// Naive implementation, but it works because CESU-8 is especially easy
|
||||||
|
// to convert from UTF-16 (which all JS strings are encoded in).
|
||||||
|
if (charCode < 0x80)
|
||||||
|
buf[bufIdx++] = charCode;
|
||||||
|
else if (charCode < 0x800) {
|
||||||
|
buf[bufIdx++] = 0xC0 + (charCode >>> 6);
|
||||||
|
buf[bufIdx++] = 0x80 + (charCode & 0x3f);
|
||||||
|
}
|
||||||
|
else { // charCode will always be < 0x10000 in javascript.
|
||||||
|
buf[bufIdx++] = 0xE0 + (charCode >>> 12);
|
||||||
|
buf[bufIdx++] = 0x80 + ((charCode >>> 6) & 0x3f);
|
||||||
|
buf[bufIdx++] = 0x80 + (charCode & 0x3f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.slice(0, bufIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalEncoderCesu8.prototype.end = function() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// CESU-8 decoder is not implemented in Node v4.0+
|
||||||
|
|
||||||
|
function InternalDecoderCesu8(options, codec) {
|
||||||
|
this.acc = 0;
|
||||||
|
this.contBytes = 0;
|
||||||
|
this.accBytes = 0;
|
||||||
|
this.defaultCharUnicode = codec.defaultCharUnicode;
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalDecoderCesu8.prototype.write = function(buf) {
|
||||||
|
var acc = this.acc, contBytes = this.contBytes, accBytes = this.accBytes,
|
||||||
|
res = '';
|
||||||
|
for (var i = 0; i < buf.length; i++) {
|
||||||
|
var curByte = buf[i];
|
||||||
|
if ((curByte & 0xC0) !== 0x80) { // Leading byte
|
||||||
|
if (contBytes > 0) { // Previous code is invalid
|
||||||
|
res += this.defaultCharUnicode;
|
||||||
|
contBytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curByte < 0x80) { // Single-byte code
|
||||||
|
res += String.fromCharCode(curByte);
|
||||||
|
} else if (curByte < 0xE0) { // Two-byte code
|
||||||
|
acc = curByte & 0x1F;
|
||||||
|
contBytes = 1; accBytes = 1;
|
||||||
|
} else if (curByte < 0xF0) { // Three-byte code
|
||||||
|
acc = curByte & 0x0F;
|
||||||
|
contBytes = 2; accBytes = 1;
|
||||||
|
} else { // Four or more are not supported for CESU-8.
|
||||||
|
res += this.defaultCharUnicode;
|
||||||
|
}
|
||||||
|
} else { // Continuation byte
|
||||||
|
if (contBytes > 0) { // We're waiting for it.
|
||||||
|
acc = (acc << 6) | (curByte & 0x3f);
|
||||||
|
contBytes--; accBytes++;
|
||||||
|
if (contBytes === 0) {
|
||||||
|
// Check for overlong encoding, but support Modified UTF-8 (encoding NULL as C0 80)
|
||||||
|
if (accBytes === 2 && acc < 0x80 && acc > 0)
|
||||||
|
res += this.defaultCharUnicode;
|
||||||
|
else if (accBytes === 3 && acc < 0x800)
|
||||||
|
res += this.defaultCharUnicode;
|
||||||
|
else
|
||||||
|
// Actually add character.
|
||||||
|
res += String.fromCharCode(acc);
|
||||||
|
}
|
||||||
|
} else { // Unexpected continuation byte
|
||||||
|
res += this.defaultCharUnicode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.acc = acc; this.contBytes = contBytes; this.accBytes = accBytes;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalDecoderCesu8.prototype.end = function() {
|
||||||
|
var res = 0;
|
||||||
|
if (this.contBytes > 0)
|
||||||
|
res += this.defaultCharUnicode;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
"use strict"
|
||||||
|
|
||||||
|
// Single-byte codec. Needs a 'chars' string parameter that contains 256 or 128 chars that
|
||||||
|
// correspond to encoded bytes (if 128 - then lower half is ASCII).
|
||||||
|
|
||||||
|
exports._sbcs = SBCSCodec;
|
||||||
|
function SBCSCodec(codecOptions, iconv) {
|
||||||
|
if (!codecOptions)
|
||||||
|
throw new Error("SBCS codec is called without the data.")
|
||||||
|
|
||||||
|
// Prepare char buffer for decoding.
|
||||||
|
if (!codecOptions.chars || (codecOptions.chars.length !== 128 && codecOptions.chars.length !== 256))
|
||||||
|
throw new Error("Encoding '"+codecOptions.type+"' has incorrect 'chars' (must be of len 128 or 256)");
|
||||||
|
|
||||||
|
if (codecOptions.chars.length === 128) {
|
||||||
|
var asciiString = "";
|
||||||
|
for (var i = 0; i < 128; i++)
|
||||||
|
asciiString += String.fromCharCode(i);
|
||||||
|
codecOptions.chars = asciiString + codecOptions.chars;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.decodeBuf = new Buffer(codecOptions.chars, 'ucs2');
|
||||||
|
|
||||||
|
// Encoding buffer.
|
||||||
|
var encodeBuf = new Buffer(65536);
|
||||||
|
encodeBuf.fill(iconv.defaultCharSingleByte.charCodeAt(0));
|
||||||
|
|
||||||
|
for (var i = 0; i < codecOptions.chars.length; i++)
|
||||||
|
encodeBuf[codecOptions.chars.charCodeAt(i)] = i;
|
||||||
|
|
||||||
|
this.encodeBuf = encodeBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
SBCSCodec.prototype.encoder = SBCSEncoder;
|
||||||
|
SBCSCodec.prototype.decoder = SBCSDecoder;
|
||||||
|
|
||||||
|
|
||||||
|
function SBCSEncoder(options, codec) {
|
||||||
|
this.encodeBuf = codec.encodeBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
SBCSEncoder.prototype.write = function(str) {
|
||||||
|
var buf = new Buffer(str.length);
|
||||||
|
for (var i = 0; i < str.length; i++)
|
||||||
|
buf[i] = this.encodeBuf[str.charCodeAt(i)];
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
SBCSEncoder.prototype.end = function() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function SBCSDecoder(options, codec) {
|
||||||
|
this.decodeBuf = codec.decodeBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
SBCSDecoder.prototype.write = function(buf) {
|
||||||
|
// Strings are immutable in JS -> we use ucs2 buffer to speed up computations.
|
||||||
|
var decodeBuf = this.decodeBuf;
|
||||||
|
var newBuf = new Buffer(buf.length*2);
|
||||||
|
var idx1 = 0, idx2 = 0;
|
||||||
|
for (var i = 0; i < buf.length; i++) {
|
||||||
|
idx1 = buf[i]*2; idx2 = i*2;
|
||||||
|
newBuf[idx2] = decodeBuf[idx1];
|
||||||
|
newBuf[idx2+1] = decodeBuf[idx1+1];
|
||||||
|
}
|
||||||
|
return newBuf.toString('ucs2');
|
||||||
|
}
|
||||||
|
|
||||||
|
SBCSDecoder.prototype.end = function() {
|
||||||
|
}
|
||||||
@ -0,0 +1,169 @@
|
|||||||
|
"use strict"
|
||||||
|
|
||||||
|
// Manually added data to be used by sbcs codec in addition to generated one.
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// Not supported by iconv, not sure why.
|
||||||
|
"10029": "maccenteuro",
|
||||||
|
"maccenteuro": {
|
||||||
|
"type": "_sbcs",
|
||||||
|
"chars": "ÄĀāÉĄÖÜáąČäčĆć鏟ĎíďĒēĖóėôöõúĚěü†°Ę£§•¶ß®©™ę¨≠ģĮįĪ≤≥īĶ∂∑łĻļĽľĹĺŅņѬ√ńŇ∆«»… ňŐÕőŌ–—“”‘’÷◊ōŔŕŘ‹›řŖŗŠ‚„šŚśÁŤťÍŽžŪÓÔūŮÚůŰűŲųÝýķŻŁżĢˇ"
|
||||||
|
},
|
||||||
|
|
||||||
|
"808": "cp808",
|
||||||
|
"ibm808": "cp808",
|
||||||
|
"cp808": {
|
||||||
|
"type": "_sbcs",
|
||||||
|
"chars": "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёЄєЇїЎў°∙·√№€■ "
|
||||||
|
},
|
||||||
|
|
||||||
|
// Aliases of generated encodings.
|
||||||
|
"ascii8bit": "ascii",
|
||||||
|
"usascii": "ascii",
|
||||||
|
"ansix34": "ascii",
|
||||||
|
"ansix341968": "ascii",
|
||||||
|
"ansix341986": "ascii",
|
||||||
|
"csascii": "ascii",
|
||||||
|
"cp367": "ascii",
|
||||||
|
"ibm367": "ascii",
|
||||||
|
"isoir6": "ascii",
|
||||||
|
"iso646us": "ascii",
|
||||||
|
"iso646irv": "ascii",
|
||||||
|
"us": "ascii",
|
||||||
|
|
||||||
|
"latin1": "iso88591",
|
||||||
|
"latin2": "iso88592",
|
||||||
|
"latin3": "iso88593",
|
||||||
|
"latin4": "iso88594",
|
||||||
|
"latin5": "iso88599",
|
||||||
|
"latin6": "iso885910",
|
||||||
|
"latin7": "iso885913",
|
||||||
|
"latin8": "iso885914",
|
||||||
|
"latin9": "iso885915",
|
||||||
|
"latin10": "iso885916",
|
||||||
|
|
||||||
|
"csisolatin1": "iso88591",
|
||||||
|
"csisolatin2": "iso88592",
|
||||||
|
"csisolatin3": "iso88593",
|
||||||
|
"csisolatin4": "iso88594",
|
||||||
|
"csisolatincyrillic": "iso88595",
|
||||||
|
"csisolatinarabic": "iso88596",
|
||||||
|
"csisolatingreek" : "iso88597",
|
||||||
|
"csisolatinhebrew": "iso88598",
|
||||||
|
"csisolatin5": "iso88599",
|
||||||
|
"csisolatin6": "iso885910",
|
||||||
|
|
||||||
|
"l1": "iso88591",
|
||||||
|
"l2": "iso88592",
|
||||||
|
"l3": "iso88593",
|
||||||
|
"l4": "iso88594",
|
||||||
|
"l5": "iso88599",
|
||||||
|
"l6": "iso885910",
|
||||||
|
"l7": "iso885913",
|
||||||
|
"l8": "iso885914",
|
||||||
|
"l9": "iso885915",
|
||||||
|
"l10": "iso885916",
|
||||||
|
|
||||||
|
"isoir14": "iso646jp",
|
||||||
|
"isoir57": "iso646cn",
|
||||||
|
"isoir100": "iso88591",
|
||||||
|
"isoir101": "iso88592",
|
||||||
|
"isoir109": "iso88593",
|
||||||
|
"isoir110": "iso88594",
|
||||||
|
"isoir144": "iso88595",
|
||||||
|
"isoir127": "iso88596",
|
||||||
|
"isoir126": "iso88597",
|
||||||
|
"isoir138": "iso88598",
|
||||||
|
"isoir148": "iso88599",
|
||||||
|
"isoir157": "iso885910",
|
||||||
|
"isoir166": "tis620",
|
||||||
|
"isoir179": "iso885913",
|
||||||
|
"isoir199": "iso885914",
|
||||||
|
"isoir203": "iso885915",
|
||||||
|
"isoir226": "iso885916",
|
||||||
|
|
||||||
|
"cp819": "iso88591",
|
||||||
|
"ibm819": "iso88591",
|
||||||
|
|
||||||
|
"cyrillic": "iso88595",
|
||||||
|
|
||||||
|
"arabic": "iso88596",
|
||||||
|
"arabic8": "iso88596",
|
||||||
|
"ecma114": "iso88596",
|
||||||
|
"asmo708": "iso88596",
|
||||||
|
|
||||||
|
"greek" : "iso88597",
|
||||||
|
"greek8" : "iso88597",
|
||||||
|
"ecma118" : "iso88597",
|
||||||
|
"elot928" : "iso88597",
|
||||||
|
|
||||||
|
"hebrew": "iso88598",
|
||||||
|
"hebrew8": "iso88598",
|
||||||
|
|
||||||
|
"turkish": "iso88599",
|
||||||
|
"turkish8": "iso88599",
|
||||||
|
|
||||||
|
"thai": "iso885911",
|
||||||
|
"thai8": "iso885911",
|
||||||
|
|
||||||
|
"celtic": "iso885914",
|
||||||
|
"celtic8": "iso885914",
|
||||||
|
"isoceltic": "iso885914",
|
||||||
|
|
||||||
|
"tis6200": "tis620",
|
||||||
|
"tis62025291": "tis620",
|
||||||
|
"tis62025330": "tis620",
|
||||||
|
|
||||||
|
"10000": "macroman",
|
||||||
|
"10006": "macgreek",
|
||||||
|
"10007": "maccyrillic",
|
||||||
|
"10079": "maciceland",
|
||||||
|
"10081": "macturkish",
|
||||||
|
|
||||||
|
"cspc8codepage437": "cp437",
|
||||||
|
"cspc775baltic": "cp775",
|
||||||
|
"cspc850multilingual": "cp850",
|
||||||
|
"cspcp852": "cp852",
|
||||||
|
"cspc862latinhebrew": "cp862",
|
||||||
|
"cpgr": "cp869",
|
||||||
|
|
||||||
|
"msee": "cp1250",
|
||||||
|
"mscyrl": "cp1251",
|
||||||
|
"msansi": "cp1252",
|
||||||
|
"msgreek": "cp1253",
|
||||||
|
"msturk": "cp1254",
|
||||||
|
"mshebr": "cp1255",
|
||||||
|
"msarab": "cp1256",
|
||||||
|
"winbaltrim": "cp1257",
|
||||||
|
|
||||||
|
"cp20866": "koi8r",
|
||||||
|
"20866": "koi8r",
|
||||||
|
"ibm878": "koi8r",
|
||||||
|
"cskoi8r": "koi8r",
|
||||||
|
|
||||||
|
"cp21866": "koi8u",
|
||||||
|
"21866": "koi8u",
|
||||||
|
"ibm1168": "koi8u",
|
||||||
|
|
||||||
|
"strk10482002": "rk1048",
|
||||||
|
|
||||||
|
"tcvn5712": "tcvn",
|
||||||
|
"tcvn57121": "tcvn",
|
||||||
|
|
||||||
|
"gb198880": "iso646cn",
|
||||||
|
"cn": "iso646cn",
|
||||||
|
|
||||||
|
"csiso14jisc6220ro": "iso646jp",
|
||||||
|
"jisc62201969ro": "iso646jp",
|
||||||
|
"jp": "iso646jp",
|
||||||
|
|
||||||
|
"cshproman8": "hproman8",
|
||||||
|
"r8": "hproman8",
|
||||||
|
"roman8": "hproman8",
|
||||||
|
"xroman8": "hproman8",
|
||||||
|
"ibm1051": "hproman8",
|
||||||
|
|
||||||
|
"mac": "macintosh",
|
||||||
|
"csmacintosh": "macintosh",
|
||||||
|
};
|
||||||
|
|
||||||
@ -0,0 +1 @@
|
|||||||
|
{"uChars":[128,165,169,178,184,216,226,235,238,244,248,251,253,258,276,284,300,325,329,334,364,463,465,467,469,471,473,475,477,506,594,610,712,716,730,930,938,962,970,1026,1104,1106,8209,8215,8218,8222,8231,8241,8244,8246,8252,8365,8452,8454,8458,8471,8482,8556,8570,8596,8602,8713,8720,8722,8726,8731,8737,8740,8742,8748,8751,8760,8766,8777,8781,8787,8802,8808,8816,8854,8858,8870,8896,8979,9322,9372,9548,9588,9616,9622,9634,9652,9662,9672,9676,9680,9702,9735,9738,9793,9795,11906,11909,11913,11917,11928,11944,11947,11951,11956,11960,11964,11979,12284,12292,12312,12319,12330,12351,12436,12447,12535,12543,12586,12842,12850,12964,13200,13215,13218,13253,13263,13267,13270,13384,13428,13727,13839,13851,14617,14703,14801,14816,14964,15183,15471,15585,16471,16736,17208,17325,17330,17374,17623,17997,18018,18212,18218,18301,18318,18760,18811,18814,18820,18823,18844,18848,18872,19576,19620,19738,19887,40870,59244,59336,59367,59413,59417,59423,59431,59437,59443,59452,59460,59478,59493,63789,63866,63894,63976,63986,64016,64018,64021,64025,64034,64037,64042,65074,65093,65107,65112,65127,65132,65375,65510,65536],"gbChars":[0,36,38,45,50,81,89,95,96,100,103,104,105,109,126,133,148,172,175,179,208,306,307,308,309,310,311,312,313,341,428,443,544,545,558,741,742,749,750,805,819,820,7922,7924,7925,7927,7934,7943,7944,7945,7950,8062,8148,8149,8152,8164,8174,8236,8240,8262,8264,8374,8380,8381,8384,8388,8390,8392,8393,8394,8396,8401,8406,8416,8419,8424,8437,8439,8445,8482,8485,8496,8521,8603,8936,8946,9046,9050,9063,9066,9076,9092,9100,9108,9111,9113,9131,9162,9164,9218,9219,11329,11331,11334,11336,11346,11361,11363,11366,11370,11372,11375,11389,11682,11686,11687,11692,11694,11714,11716,11723,11725,11730,11736,11982,11989,12102,12336,12348,12350,12384,12393,12395,12397,12510,12553,12851,12962,12973,13738,13823,13919,13933,14080,14298,14585,14698,15583,15847,16318,16434,16438,16481,16729,17102,17122,17315,17320,17402,17418,17859,17909,17911,17915,17916,17936,17939,17961,18664,18703,18814,18962,19043,33469,33470,33471,33484,33485,33490,33497,33501,33505,33513,33520,33536,33550,37845,37921,37948,38029,38038,38064,38065,38066,38069,38075,38076,38078,39108,39109,39113,39114,39115,39116,39265,39394,189000]}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue