신동해

Add list.ejs, Update server.js

Showing 132 changed files with 19387 additions and 6 deletions
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + exec "$basedir/node" "$basedir/../ejs/bin/cli.js" "$@"
10 +else
11 + exec node "$basedir/../ejs/bin/cli.js" "$@"
12 +fi
1 +@ECHO off
2 +GOTO start
3 +:find_dp0
4 +SET dp0=%~dp0
5 +EXIT /b
6 +:start
7 +SETLOCAL
8 +CALL :find_dp0
9 +
10 +IF EXIST "%dp0%\node.exe" (
11 + SET "_prog=%dp0%\node.exe"
12 +) ELSE (
13 + SET "_prog=node"
14 + SET PATHEXT=%PATHEXT:;.JS;=;%
15 +)
16 +
17 +endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\ejs\bin\cli.js" %*
1 +#!/usr/bin/env pwsh
2 +$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
3 +
4 +$exe=""
5 +if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
6 + # Fix case when both the Windows and Linux builds of Node
7 + # are installed in the same directory
8 + $exe=".exe"
9 +}
10 +$ret=0
11 +if (Test-Path "$basedir/node$exe") {
12 + # Support pipeline input
13 + if ($MyInvocation.ExpectingInput) {
14 + $input | & "$basedir/node$exe" "$basedir/../ejs/bin/cli.js" $args
15 + } else {
16 + & "$basedir/node$exe" "$basedir/../ejs/bin/cli.js" $args
17 + }
18 + $ret=$LASTEXITCODE
19 +} else {
20 + # Support pipeline input
21 + if ($MyInvocation.ExpectingInput) {
22 + $input | & "node$exe" "$basedir/../ejs/bin/cli.js" $args
23 + } else {
24 + & "node$exe" "$basedir/../ejs/bin/cli.js" $args
25 + }
26 + $ret=$LASTEXITCODE
27 +}
28 +exit $ret
1 +#!/bin/sh
2 +basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3 +
4 +case `uname` in
5 + *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
6 +esac
7 +
8 +if [ -x "$basedir/node" ]; then
9 + exec "$basedir/node" "$basedir/../jake/bin/cli.js" "$@"
10 +else
11 + exec node "$basedir/../jake/bin/cli.js" "$@"
12 +fi
1 +@ECHO off
2 +GOTO start
3 +:find_dp0
4 +SET dp0=%~dp0
5 +EXIT /b
6 +:start
7 +SETLOCAL
8 +CALL :find_dp0
9 +
10 +IF EXIST "%dp0%\node.exe" (
11 + SET "_prog=%dp0%\node.exe"
12 +) ELSE (
13 + SET "_prog=node"
14 + SET PATHEXT=%PATHEXT:;.JS;=;%
15 +)
16 +
17 +endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\jake\bin\cli.js" %*
1 +#!/usr/bin/env pwsh
2 +$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
3 +
4 +$exe=""
5 +if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
6 + # Fix case when both the Windows and Linux builds of Node
7 + # are installed in the same directory
8 + $exe=".exe"
9 +}
10 +$ret=0
11 +if (Test-Path "$basedir/node$exe") {
12 + # Support pipeline input
13 + if ($MyInvocation.ExpectingInput) {
14 + $input | & "$basedir/node$exe" "$basedir/../jake/bin/cli.js" $args
15 + } else {
16 + & "$basedir/node$exe" "$basedir/../jake/bin/cli.js" $args
17 + }
18 + $ret=$LASTEXITCODE
19 +} else {
20 + # Support pipeline input
21 + if ($MyInvocation.ExpectingInput) {
22 + $input | & "node$exe" "$basedir/../jake/bin/cli.js" $args
23 + } else {
24 + & "node$exe" "$basedir/../jake/bin/cli.js" $args
25 + }
26 + $ret=$LASTEXITCODE
27 +}
28 +exit $ret
...@@ -16,11 +16,32 @@ ...@@ -16,11 +16,32 @@
16 "node": ">= 0.6" 16 "node": ">= 0.6"
17 } 17 }
18 }, 18 },
19 + "node_modules/ansi-styles": {
20 + "version": "3.2.1",
21 + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
22 + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
23 + "dependencies": {
24 + "color-convert": "^1.9.0"
25 + },
26 + "engines": {
27 + "node": ">=4"
28 + }
29 + },
19 "node_modules/array-flatten": { 30 "node_modules/array-flatten": {
20 "version": "1.1.1", 31 "version": "1.1.1",
21 "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 32 "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
22 "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 33 "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
23 }, 34 },
35 + "node_modules/async": {
36 + "version": "0.9.2",
37 + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
38 + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0="
39 + },
40 + "node_modules/balanced-match": {
41 + "version": "1.0.2",
42 + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
43 + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
44 + },
24 "node_modules/bl": { 45 "node_modules/bl": {
25 "version": "2.2.1", 46 "version": "2.2.1",
26 "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", 47 "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
...@@ -50,6 +71,15 @@ ...@@ -50,6 +71,15 @@
50 "node": ">= 0.8" 71 "node": ">= 0.8"
51 } 72 }
52 }, 73 },
74 + "node_modules/brace-expansion": {
75 + "version": "1.1.11",
76 + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
77 + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
78 + "dependencies": {
79 + "balanced-match": "^1.0.0",
80 + "concat-map": "0.0.1"
81 + }
82 + },
53 "node_modules/bson": { 83 "node_modules/bson": {
54 "version": "1.1.6", 84 "version": "1.1.6",
55 "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", 85 "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz",
...@@ -66,6 +96,37 @@ ...@@ -66,6 +96,37 @@
66 "node": ">= 0.8" 96 "node": ">= 0.8"
67 } 97 }
68 }, 98 },
99 + "node_modules/chalk": {
100 + "version": "2.4.2",
101 + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
102 + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
103 + "dependencies": {
104 + "ansi-styles": "^3.2.1",
105 + "escape-string-regexp": "^1.0.5",
106 + "supports-color": "^5.3.0"
107 + },
108 + "engines": {
109 + "node": ">=4"
110 + }
111 + },
112 + "node_modules/color-convert": {
113 + "version": "1.9.3",
114 + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
115 + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
116 + "dependencies": {
117 + "color-name": "1.1.3"
118 + }
119 + },
120 + "node_modules/color-name": {
121 + "version": "1.1.3",
122 + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
123 + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
124 + },
125 + "node_modules/concat-map": {
126 + "version": "0.0.1",
127 + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
128 + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
129 + },
69 "node_modules/content-disposition": { 130 "node_modules/content-disposition": {
70 "version": "0.5.3", 131 "version": "0.5.3",
71 "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", 132 "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
...@@ -137,6 +198,20 @@ ...@@ -137,6 +198,20 @@
137 "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 198 "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
138 "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 199 "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
139 }, 200 },
201 + "node_modules/ejs": {
202 + "version": "3.1.6",
203 + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz",
204 + "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==",
205 + "dependencies": {
206 + "jake": "^10.6.1"
207 + },
208 + "bin": {
209 + "ejs": "bin/cli.js"
210 + },
211 + "engines": {
212 + "node": ">=0.10.0"
213 + }
214 + },
140 "node_modules/encodeurl": { 215 "node_modules/encodeurl": {
141 "version": "1.0.2", 216 "version": "1.0.2",
142 "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 217 "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
...@@ -150,6 +225,14 @@ ...@@ -150,6 +225,14 @@
150 "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 225 "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
151 "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 226 "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
152 }, 227 },
228 + "node_modules/escape-string-regexp": {
229 + "version": "1.0.5",
230 + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
231 + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
232 + "engines": {
233 + "node": ">=0.8.0"
234 + }
235 + },
153 "node_modules/etag": { 236 "node_modules/etag": {
154 "version": "1.8.1", 237 "version": "1.8.1",
155 "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 238 "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
...@@ -198,6 +281,14 @@ ...@@ -198,6 +281,14 @@
198 "node": ">= 0.10.0" 281 "node": ">= 0.10.0"
199 } 282 }
200 }, 283 },
284 + "node_modules/filelist": {
285 + "version": "1.0.2",
286 + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz",
287 + "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==",
288 + "dependencies": {
289 + "minimatch": "^3.0.4"
290 + }
291 + },
201 "node_modules/finalhandler": { 292 "node_modules/finalhandler": {
202 "version": "1.1.2", 293 "version": "1.1.2",
203 "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", 294 "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
...@@ -231,6 +322,14 @@ ...@@ -231,6 +322,14 @@
231 "node": ">= 0.6" 322 "node": ">= 0.6"
232 } 323 }
233 }, 324 },
325 + "node_modules/has-flag": {
326 + "version": "3.0.0",
327 + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
328 + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
329 + "engines": {
330 + "node": ">=4"
331 + }
332 + },
234 "node_modules/http-errors": { 333 "node_modules/http-errors": {
235 "version": "1.7.2", 334 "version": "1.7.2",
236 "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", 335 "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
...@@ -275,6 +374,23 @@ ...@@ -275,6 +374,23 @@
275 "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 374 "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
276 "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 375 "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
277 }, 376 },
377 + "node_modules/jake": {
378 + "version": "10.8.2",
379 + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz",
380 + "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==",
381 + "dependencies": {
382 + "async": "0.9.x",
383 + "chalk": "^2.4.2",
384 + "filelist": "^1.0.1",
385 + "minimatch": "^3.0.4"
386 + },
387 + "bin": {
388 + "jake": "bin/cli.js"
389 + },
390 + "engines": {
391 + "node": "*"
392 + }
393 + },
278 "node_modules/media-typer": { 394 "node_modules/media-typer": {
279 "version": "0.3.0", 395 "version": "0.3.0",
280 "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 396 "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
...@@ -332,6 +448,17 @@ ...@@ -332,6 +448,17 @@
332 "node": ">= 0.6" 448 "node": ">= 0.6"
333 } 449 }
334 }, 450 },
451 + "node_modules/minimatch": {
452 + "version": "3.0.4",
453 + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
454 + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
455 + "dependencies": {
456 + "brace-expansion": "^1.1.7"
457 + },
458 + "engines": {
459 + "node": "*"
460 + }
461 + },
335 "node_modules/mongodb": { 462 "node_modules/mongodb": {
336 "version": "3.6.4", 463 "version": "3.6.4",
337 "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.4.tgz", 464 "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.4.tgz",
...@@ -587,6 +714,17 @@ ...@@ -587,6 +714,17 @@
587 "safe-buffer": "~5.1.0" 714 "safe-buffer": "~5.1.0"
588 } 715 }
589 }, 716 },
717 + "node_modules/supports-color": {
718 + "version": "5.5.0",
719 + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
720 + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
721 + "dependencies": {
722 + "has-flag": "^3.0.0"
723 + },
724 + "engines": {
725 + "node": ">=4"
726 + }
727 + },
590 "node_modules/toidentifier": { 728 "node_modules/toidentifier": {
591 "version": "1.0.0", 729 "version": "1.0.0",
592 "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 730 "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
......
1 +'use strict';
2 +const colorConvert = require('color-convert');
3 +
4 +const wrapAnsi16 = (fn, offset) => function () {
5 + const code = fn.apply(colorConvert, arguments);
6 + return `\u001B[${code + offset}m`;
7 +};
8 +
9 +const wrapAnsi256 = (fn, offset) => function () {
10 + const code = fn.apply(colorConvert, arguments);
11 + return `\u001B[${38 + offset};5;${code}m`;
12 +};
13 +
14 +const wrapAnsi16m = (fn, offset) => function () {
15 + const rgb = fn.apply(colorConvert, arguments);
16 + return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`;
17 +};
18 +
19 +function assembleStyles() {
20 + const codes = new Map();
21 + const styles = {
22 + modifier: {
23 + reset: [0, 0],
24 + // 21 isn't widely supported and 22 does the same thing
25 + bold: [1, 22],
26 + dim: [2, 22],
27 + italic: [3, 23],
28 + underline: [4, 24],
29 + inverse: [7, 27],
30 + hidden: [8, 28],
31 + strikethrough: [9, 29]
32 + },
33 + color: {
34 + black: [30, 39],
35 + red: [31, 39],
36 + green: [32, 39],
37 + yellow: [33, 39],
38 + blue: [34, 39],
39 + magenta: [35, 39],
40 + cyan: [36, 39],
41 + white: [37, 39],
42 + gray: [90, 39],
43 +
44 + // Bright color
45 + redBright: [91, 39],
46 + greenBright: [92, 39],
47 + yellowBright: [93, 39],
48 + blueBright: [94, 39],
49 + magentaBright: [95, 39],
50 + cyanBright: [96, 39],
51 + whiteBright: [97, 39]
52 + },
53 + bgColor: {
54 + bgBlack: [40, 49],
55 + bgRed: [41, 49],
56 + bgGreen: [42, 49],
57 + bgYellow: [43, 49],
58 + bgBlue: [44, 49],
59 + bgMagenta: [45, 49],
60 + bgCyan: [46, 49],
61 + bgWhite: [47, 49],
62 +
63 + // Bright color
64 + bgBlackBright: [100, 49],
65 + bgRedBright: [101, 49],
66 + bgGreenBright: [102, 49],
67 + bgYellowBright: [103, 49],
68 + bgBlueBright: [104, 49],
69 + bgMagentaBright: [105, 49],
70 + bgCyanBright: [106, 49],
71 + bgWhiteBright: [107, 49]
72 + }
73 + };
74 +
75 + // Fix humans
76 + styles.color.grey = styles.color.gray;
77 +
78 + for (const groupName of Object.keys(styles)) {
79 + const group = styles[groupName];
80 +
81 + for (const styleName of Object.keys(group)) {
82 + const style = group[styleName];
83 +
84 + styles[styleName] = {
85 + open: `\u001B[${style[0]}m`,
86 + close: `\u001B[${style[1]}m`
87 + };
88 +
89 + group[styleName] = styles[styleName];
90 +
91 + codes.set(style[0], style[1]);
92 + }
93 +
94 + Object.defineProperty(styles, groupName, {
95 + value: group,
96 + enumerable: false
97 + });
98 +
99 + Object.defineProperty(styles, 'codes', {
100 + value: codes,
101 + enumerable: false
102 + });
103 + }
104 +
105 + const ansi2ansi = n => n;
106 + const rgb2rgb = (r, g, b) => [r, g, b];
107 +
108 + styles.color.close = '\u001B[39m';
109 + styles.bgColor.close = '\u001B[49m';
110 +
111 + styles.color.ansi = {
112 + ansi: wrapAnsi16(ansi2ansi, 0)
113 + };
114 + styles.color.ansi256 = {
115 + ansi256: wrapAnsi256(ansi2ansi, 0)
116 + };
117 + styles.color.ansi16m = {
118 + rgb: wrapAnsi16m(rgb2rgb, 0)
119 + };
120 +
121 + styles.bgColor.ansi = {
122 + ansi: wrapAnsi16(ansi2ansi, 10)
123 + };
124 + styles.bgColor.ansi256 = {
125 + ansi256: wrapAnsi256(ansi2ansi, 10)
126 + };
127 + styles.bgColor.ansi16m = {
128 + rgb: wrapAnsi16m(rgb2rgb, 10)
129 + };
130 +
131 + for (let key of Object.keys(colorConvert)) {
132 + if (typeof colorConvert[key] !== 'object') {
133 + continue;
134 + }
135 +
136 + const suite = colorConvert[key];
137 +
138 + if (key === 'ansi16') {
139 + key = 'ansi';
140 + }
141 +
142 + if ('ansi16' in suite) {
143 + styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0);
144 + styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10);
145 + }
146 +
147 + if ('ansi256' in suite) {
148 + styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0);
149 + styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10);
150 + }
151 +
152 + if ('rgb' in suite) {
153 + styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0);
154 + styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10);
155 + }
156 + }
157 +
158 + return styles;
159 +}
160 +
161 +// Make the export immutable
162 +Object.defineProperty(module, 'exports', {
163 + enumerable: true,
164 + get: assembleStyles
165 +});
1 +MIT License
2 +
3 +Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
4 +
5 +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:
6 +
7 +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 +
9 +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.
1 +{
2 + "name": "ansi-styles",
3 + "version": "3.2.1",
4 + "description": "ANSI escape codes for styling strings in the terminal",
5 + "license": "MIT",
6 + "repository": "chalk/ansi-styles",
7 + "author": {
8 + "name": "Sindre Sorhus",
9 + "email": "sindresorhus@gmail.com",
10 + "url": "sindresorhus.com"
11 + },
12 + "engines": {
13 + "node": ">=4"
14 + },
15 + "scripts": {
16 + "test": "xo && ava",
17 + "screenshot": "svg-term --command='node screenshot' --out=screenshot.svg --padding=3 --width=55 --height=3 --at=1000 --no-cursor"
18 + },
19 + "files": [
20 + "index.js"
21 + ],
22 + "keywords": [
23 + "ansi",
24 + "styles",
25 + "color",
26 + "colour",
27 + "colors",
28 + "terminal",
29 + "console",
30 + "cli",
31 + "string",
32 + "tty",
33 + "escape",
34 + "formatting",
35 + "rgb",
36 + "256",
37 + "shell",
38 + "xterm",
39 + "log",
40 + "logging",
41 + "command-line",
42 + "text"
43 + ],
44 + "dependencies": {
45 + "color-convert": "^1.9.0"
46 + },
47 + "devDependencies": {
48 + "ava": "*",
49 + "babel-polyfill": "^6.23.0",
50 + "svg-term-cli": "^2.1.1",
51 + "xo": "*"
52 + },
53 + "ava": {
54 + "require": "babel-polyfill"
55 + }
56 +}
1 +# ansi-styles [![Build Status](https://travis-ci.org/chalk/ansi-styles.svg?branch=master)](https://travis-ci.org/chalk/ansi-styles)
2 +
3 +> [ANSI escape codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors_and_Styles) for styling strings in the terminal
4 +
5 +You probably want the higher-level [chalk](https://github.com/chalk/chalk) module for styling your strings.
6 +
7 +<img src="https://cdn.rawgit.com/chalk/ansi-styles/8261697c95bf34b6c7767e2cbe9941a851d59385/screenshot.svg" width="900">
8 +
9 +
10 +## Install
11 +
12 +```
13 +$ npm install ansi-styles
14 +```
15 +
16 +
17 +## Usage
18 +
19 +```js
20 +const style = require('ansi-styles');
21 +
22 +console.log(`${style.green.open}Hello world!${style.green.close}`);
23 +
24 +
25 +// Color conversion between 16/256/truecolor
26 +// NOTE: If conversion goes to 16 colors or 256 colors, the original color
27 +// may be degraded to fit that color palette. This means terminals
28 +// that do not support 16 million colors will best-match the
29 +// original color.
30 +console.log(style.bgColor.ansi.hsl(120, 80, 72) + 'Hello world!' + style.bgColor.close);
31 +console.log(style.color.ansi256.rgb(199, 20, 250) + 'Hello world!' + style.color.close);
32 +console.log(style.color.ansi16m.hex('#ABCDEF') + 'Hello world!' + style.color.close);
33 +```
34 +
35 +## API
36 +
37 +Each style has an `open` and `close` property.
38 +
39 +
40 +## Styles
41 +
42 +### Modifiers
43 +
44 +- `reset`
45 +- `bold`
46 +- `dim`
47 +- `italic` *(Not widely supported)*
48 +- `underline`
49 +- `inverse`
50 +- `hidden`
51 +- `strikethrough` *(Not widely supported)*
52 +
53 +### Colors
54 +
55 +- `black`
56 +- `red`
57 +- `green`
58 +- `yellow`
59 +- `blue`
60 +- `magenta`
61 +- `cyan`
62 +- `white`
63 +- `gray` ("bright black")
64 +- `redBright`
65 +- `greenBright`
66 +- `yellowBright`
67 +- `blueBright`
68 +- `magentaBright`
69 +- `cyanBright`
70 +- `whiteBright`
71 +
72 +### Background colors
73 +
74 +- `bgBlack`
75 +- `bgRed`
76 +- `bgGreen`
77 +- `bgYellow`
78 +- `bgBlue`
79 +- `bgMagenta`
80 +- `bgCyan`
81 +- `bgWhite`
82 +- `bgBlackBright`
83 +- `bgRedBright`
84 +- `bgGreenBright`
85 +- `bgYellowBright`
86 +- `bgBlueBright`
87 +- `bgMagentaBright`
88 +- `bgCyanBright`
89 +- `bgWhiteBright`
90 +
91 +
92 +## Advanced usage
93 +
94 +By default, you get a map of styles, but the styles are also available as groups. They are non-enumerable so they don't show up unless you access them explicitly. This makes it easier to expose only a subset in a higher-level module.
95 +
96 +- `style.modifier`
97 +- `style.color`
98 +- `style.bgColor`
99 +
100 +###### Example
101 +
102 +```js
103 +console.log(style.color.green.open);
104 +```
105 +
106 +Raw escape codes (i.e. without the CSI escape prefix `\u001B[` and render mode postfix `m`) are available under `style.codes`, which returns a `Map` with the open codes as keys and close codes as values.
107 +
108 +###### Example
109 +
110 +```js
111 +console.log(style.codes.get(36));
112 +//=> 39
113 +```
114 +
115 +
116 +## [256 / 16 million (TrueColor) support](https://gist.github.com/XVilka/8346728)
117 +
118 +`ansi-styles` uses the [`color-convert`](https://github.com/Qix-/color-convert) package to allow for converting between various colors and ANSI escapes, with support for 256 and 16 million colors.
119 +
120 +To use these, call the associated conversion function with the intended output, for example:
121 +
122 +```js
123 +style.color.ansi.rgb(100, 200, 15); // RGB to 16 color ansi foreground code
124 +style.bgColor.ansi.rgb(100, 200, 15); // RGB to 16 color ansi background code
125 +
126 +style.color.ansi256.hsl(120, 100, 60); // HSL to 256 color ansi foreground code
127 +style.bgColor.ansi256.hsl(120, 100, 60); // HSL to 256 color ansi foreground code
128 +
129 +style.color.ansi16m.hex('#C0FFEE'); // Hex (RGB) to 16 million color foreground code
130 +style.bgColor.ansi16m.hex('#C0FFEE'); // Hex (RGB) to 16 million color background code
131 +```
132 +
133 +
134 +## Related
135 +
136 +- [ansi-escapes](https://github.com/sindresorhus/ansi-escapes) - ANSI escape codes for manipulating the terminal
137 +
138 +
139 +## Maintainers
140 +
141 +- [Sindre Sorhus](https://github.com/sindresorhus)
142 +- [Josh Junon](https://github.com/qix-)
143 +
144 +
145 +## License
146 +
147 +MIT
1 +language: node_js
2 +node_js:
3 + - "0.10"
4 + - "0.12"
5 + - "iojs"
1 +Copyright (c) 2010-2014 Caolan McMahon
2 +
3 +Permission is hereby granted, free of charge, to any person obtaining a copy
4 +of this software and associated documentation files (the "Software"), to deal
5 +in the Software without restriction, including without limitation the rights
6 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 +copies of the Software, and to permit persons to whom the Software is
8 +furnished to do so, subject to the following conditions:
9 +
10 +The above copyright notice and this permission notice shall be included in
11 +all copies or substantial portions of the Software.
12 +
13 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 +THE SOFTWARE.
1 +# Async.js
2 +
3 +[![Build Status via Travis CI](https://travis-ci.org/caolan/async.svg?branch=master)](https://travis-ci.org/caolan/async)
4 +
5 +
6 +Async is a utility module which provides straight-forward, powerful functions
7 +for working with asynchronous JavaScript. Although originally designed for
8 +use with [Node.js](http://nodejs.org) and installable via `npm install async`,
9 +it can also be used directly in the browser.
10 +
11 +Async is also installable via:
12 +
13 +- [bower](http://bower.io/): `bower install async`
14 +- [component](https://github.com/component/component): `component install
15 + caolan/async`
16 +- [jam](http://jamjs.org/): `jam install async`
17 +- [spm](http://spmjs.io/): `spm install async`
18 +
19 +Async provides around 20 functions that include the usual 'functional'
20 +suspects (`map`, `reduce`, `filter`, `each`…) as well as some common patterns
21 +for asynchronous control flow (`parallel`, `series`, `waterfall`…). All these
22 +functions assume you follow the Node.js convention of providing a single
23 +callback as the last argument of your `async` function.
24 +
25 +
26 +## Quick Examples
27 +
28 +```javascript
29 +async.map(['file1','file2','file3'], fs.stat, function(err, results){
30 + // results is now an array of stats for each file
31 +});
32 +
33 +async.filter(['file1','file2','file3'], fs.exists, function(results){
34 + // results now equals an array of the existing files
35 +});
36 +
37 +async.parallel([
38 + function(){ ... },
39 + function(){ ... }
40 +], callback);
41 +
42 +async.series([
43 + function(){ ... },
44 + function(){ ... }
45 +]);
46 +```
47 +
48 +There are many more functions available so take a look at the docs below for a
49 +full list. This module aims to be comprehensive, so if you feel anything is
50 +missing please create a GitHub issue for it.
51 +
52 +## Common Pitfalls
53 +
54 +### Binding a context to an iterator
55 +
56 +This section is really about `bind`, not about `async`. If you are wondering how to
57 +make `async` execute your iterators in a given context, or are confused as to why
58 +a method of another library isn't working as an iterator, study this example:
59 +
60 +```js
61 +// Here is a simple object with an (unnecessarily roundabout) squaring method
62 +var AsyncSquaringLibrary = {
63 + squareExponent: 2,
64 + square: function(number, callback){
65 + var result = Math.pow(number, this.squareExponent);
66 + setTimeout(function(){
67 + callback(null, result);
68 + }, 200);
69 + }
70 +};
71 +
72 +async.map([1, 2, 3], AsyncSquaringLibrary.square, function(err, result){
73 + // result is [NaN, NaN, NaN]
74 + // This fails because the `this.squareExponent` expression in the square
75 + // function is not evaluated in the context of AsyncSquaringLibrary, and is
76 + // therefore undefined.
77 +});
78 +
79 +async.map([1, 2, 3], AsyncSquaringLibrary.square.bind(AsyncSquaringLibrary), function(err, result){
80 + // result is [1, 4, 9]
81 + // With the help of bind we can attach a context to the iterator before
82 + // passing it to async. Now the square function will be executed in its
83 + // 'home' AsyncSquaringLibrary context and the value of `this.squareExponent`
84 + // will be as expected.
85 +});
86 +```
87 +
88 +## Download
89 +
90 +The source is available for download from
91 +[GitHub](http://github.com/caolan/async).
92 +Alternatively, you can install using Node Package Manager (`npm`):
93 +
94 + npm install async
95 +
96 +__Development:__ [async.js](https://github.com/caolan/async/raw/master/lib/async.js) - 29.6kb Uncompressed
97 +
98 +## In the Browser
99 +
100 +So far it's been tested in IE6, IE7, IE8, FF3.6 and Chrome 5.
101 +
102 +Usage:
103 +
104 +```html
105 +<script type="text/javascript" src="async.js"></script>
106 +<script type="text/javascript">
107 +
108 + async.map(data, asyncProcess, function(err, results){
109 + alert(results);
110 + });
111 +
112 +</script>
113 +```
114 +
115 +## Documentation
116 +
117 +### Collections
118 +
119 +* [`each`](#each)
120 +* [`eachSeries`](#eachSeries)
121 +* [`eachLimit`](#eachLimit)
122 +* [`map`](#map)
123 +* [`mapSeries`](#mapSeries)
124 +* [`mapLimit`](#mapLimit)
125 +* [`filter`](#filter)
126 +* [`filterSeries`](#filterSeries)
127 +* [`reject`](#reject)
128 +* [`rejectSeries`](#rejectSeries)
129 +* [`reduce`](#reduce)
130 +* [`reduceRight`](#reduceRight)
131 +* [`detect`](#detect)
132 +* [`detectSeries`](#detectSeries)
133 +* [`sortBy`](#sortBy)
134 +* [`some`](#some)
135 +* [`every`](#every)
136 +* [`concat`](#concat)
137 +* [`concatSeries`](#concatSeries)
138 +
139 +### Control Flow
140 +
141 +* [`series`](#seriestasks-callback)
142 +* [`parallel`](#parallel)
143 +* [`parallelLimit`](#parallellimittasks-limit-callback)
144 +* [`whilst`](#whilst)
145 +* [`doWhilst`](#doWhilst)
146 +* [`until`](#until)
147 +* [`doUntil`](#doUntil)
148 +* [`forever`](#forever)
149 +* [`waterfall`](#waterfall)
150 +* [`compose`](#compose)
151 +* [`seq`](#seq)
152 +* [`applyEach`](#applyEach)
153 +* [`applyEachSeries`](#applyEachSeries)
154 +* [`queue`](#queue)
155 +* [`priorityQueue`](#priorityQueue)
156 +* [`cargo`](#cargo)
157 +* [`auto`](#auto)
158 +* [`retry`](#retry)
159 +* [`iterator`](#iterator)
160 +* [`apply`](#apply)
161 +* [`nextTick`](#nextTick)
162 +* [`times`](#times)
163 +* [`timesSeries`](#timesSeries)
164 +
165 +### Utils
166 +
167 +* [`memoize`](#memoize)
168 +* [`unmemoize`](#unmemoize)
169 +* [`log`](#log)
170 +* [`dir`](#dir)
171 +* [`noConflict`](#noConflict)
172 +
173 +
174 +## Collections
175 +
176 +<a name="forEach" />
177 +<a name="each" />
178 +### each(arr, iterator, callback)
179 +
180 +Applies the function `iterator` to each item in `arr`, in parallel.
181 +The `iterator` is called with an item from the list, and a callback for when it
182 +has finished. If the `iterator` passes an error to its `callback`, the main
183 +`callback` (for the `each` function) is immediately called with the error.
184 +
185 +Note, that since this function applies `iterator` to each item in parallel,
186 +there is no guarantee that the iterator functions will complete in order.
187 +
188 +__Arguments__
189 +
190 +* `arr` - An array to iterate over.
191 +* `iterator(item, callback)` - A function to apply to each item in `arr`.
192 + The iterator is passed a `callback(err)` which must be called once it has
193 + completed. If no error has occurred, the `callback` should be run without
194 + arguments or with an explicit `null` argument.
195 +* `callback(err)` - A callback which is called when all `iterator` functions
196 + have finished, or an error occurs.
197 +
198 +__Examples__
199 +
200 +
201 +```js
202 +// assuming openFiles is an array of file names and saveFile is a function
203 +// to save the modified contents of that file:
204 +
205 +async.each(openFiles, saveFile, function(err){
206 + // if any of the saves produced an error, err would equal that error
207 +});
208 +```
209 +
210 +```js
211 +// assuming openFiles is an array of file names
212 +
213 +async.each(openFiles, function(file, callback) {
214 +
215 + // Perform operation on file here.
216 + console.log('Processing file ' + file);
217 +
218 + if( file.length > 32 ) {
219 + console.log('This file name is too long');
220 + callback('File name too long');
221 + } else {
222 + // Do work to process file here
223 + console.log('File processed');
224 + callback();
225 + }
226 +}, function(err){
227 + // if any of the file processing produced an error, err would equal that error
228 + if( err ) {
229 + // One of the iterations produced an error.
230 + // All processing will now stop.
231 + console.log('A file failed to process');
232 + } else {
233 + console.log('All files have been processed successfully');
234 + }
235 +});
236 +```
237 +
238 +---------------------------------------
239 +
240 +<a name="forEachSeries" />
241 +<a name="eachSeries" />
242 +### eachSeries(arr, iterator, callback)
243 +
244 +The same as [`each`](#each), only `iterator` is applied to each item in `arr` in
245 +series. The next `iterator` is only called once the current one has completed.
246 +This means the `iterator` functions will complete in order.
247 +
248 +
249 +---------------------------------------
250 +
251 +<a name="forEachLimit" />
252 +<a name="eachLimit" />
253 +### eachLimit(arr, limit, iterator, callback)
254 +
255 +The same as [`each`](#each), only no more than `limit` `iterator`s will be simultaneously
256 +running at any time.
257 +
258 +Note that the items in `arr` are not processed in batches, so there is no guarantee that
259 +the first `limit` `iterator` functions will complete before any others are started.
260 +
261 +__Arguments__
262 +
263 +* `arr` - An array to iterate over.
264 +* `limit` - The maximum number of `iterator`s to run at any time.
265 +* `iterator(item, callback)` - A function to apply to each item in `arr`.
266 + The iterator is passed a `callback(err)` which must be called once it has
267 + completed. If no error has occurred, the callback should be run without
268 + arguments or with an explicit `null` argument.
269 +* `callback(err)` - A callback which is called when all `iterator` functions
270 + have finished, or an error occurs.
271 +
272 +__Example__
273 +
274 +```js
275 +// Assume documents is an array of JSON objects and requestApi is a
276 +// function that interacts with a rate-limited REST api.
277 +
278 +async.eachLimit(documents, 20, requestApi, function(err){
279 + // if any of the saves produced an error, err would equal that error
280 +});
281 +```
282 +
283 +---------------------------------------
284 +
285 +<a name="map" />
286 +### map(arr, iterator, callback)
287 +
288 +Produces a new array of values by mapping each value in `arr` through
289 +the `iterator` function. The `iterator` is called with an item from `arr` and a
290 +callback for when it has finished processing. Each of these callback takes 2 arguments:
291 +an `error`, and the transformed item from `arr`. If `iterator` passes an error to his
292 +callback, the main `callback` (for the `map` function) is immediately called with the error.
293 +
294 +Note, that since this function applies the `iterator` to each item in parallel,
295 +there is no guarantee that the `iterator` functions will complete in order.
296 +However, the results array will be in the same order as the original `arr`.
297 +
298 +__Arguments__
299 +
300 +* `arr` - An array to iterate over.
301 +* `iterator(item, callback)` - A function to apply to each item in `arr`.
302 + The iterator is passed a `callback(err, transformed)` which must be called once
303 + it has completed with an error (which can be `null`) and a transformed item.
304 +* `callback(err, results)` - A callback which is called when all `iterator`
305 + functions have finished, or an error occurs. Results is an array of the
306 + transformed items from the `arr`.
307 +
308 +__Example__
309 +
310 +```js
311 +async.map(['file1','file2','file3'], fs.stat, function(err, results){
312 + // results is now an array of stats for each file
313 +});
314 +```
315 +
316 +---------------------------------------
317 +
318 +<a name="mapSeries" />
319 +### mapSeries(arr, iterator, callback)
320 +
321 +The same as [`map`](#map), only the `iterator` is applied to each item in `arr` in
322 +series. The next `iterator` is only called once the current one has completed.
323 +The results array will be in the same order as the original.
324 +
325 +
326 +---------------------------------------
327 +
328 +<a name="mapLimit" />
329 +### mapLimit(arr, limit, iterator, callback)
330 +
331 +The same as [`map`](#map), only no more than `limit` `iterator`s will be simultaneously
332 +running at any time.
333 +
334 +Note that the items are not processed in batches, so there is no guarantee that
335 +the first `limit` `iterator` functions will complete before any others are started.
336 +
337 +__Arguments__
338 +
339 +* `arr` - An array to iterate over.
340 +* `limit` - The maximum number of `iterator`s to run at any time.
341 +* `iterator(item, callback)` - A function to apply to each item in `arr`.
342 + The iterator is passed a `callback(err, transformed)` which must be called once
343 + it has completed with an error (which can be `null`) and a transformed item.
344 +* `callback(err, results)` - A callback which is called when all `iterator`
345 + calls have finished, or an error occurs. The result is an array of the
346 + transformed items from the original `arr`.
347 +
348 +__Example__
349 +
350 +```js
351 +async.mapLimit(['file1','file2','file3'], 1, fs.stat, function(err, results){
352 + // results is now an array of stats for each file
353 +});
354 +```
355 +
356 +---------------------------------------
357 +
358 +<a name="select" />
359 +<a name="filter" />
360 +### filter(arr, iterator, callback)
361 +
362 +__Alias:__ `select`
363 +
364 +Returns a new array of all the values in `arr` which pass an async truth test.
365 +_The callback for each `iterator` call only accepts a single argument of `true` or
366 +`false`; it does not accept an error argument first!_ This is in-line with the
367 +way node libraries work with truth tests like `fs.exists`. This operation is
368 +performed in parallel, but the results array will be in the same order as the
369 +original.
370 +
371 +__Arguments__
372 +
373 +* `arr` - An array to iterate over.
374 +* `iterator(item, callback)` - A truth test to apply to each item in `arr`.
375 + The `iterator` is passed a `callback(truthValue)`, which must be called with a
376 + boolean argument once it has completed.
377 +* `callback(results)` - A callback which is called after all the `iterator`
378 + functions have finished.
379 +
380 +__Example__
381 +
382 +```js
383 +async.filter(['file1','file2','file3'], fs.exists, function(results){
384 + // results now equals an array of the existing files
385 +});
386 +```
387 +
388 +---------------------------------------
389 +
390 +<a name="selectSeries" />
391 +<a name="filterSeries" />
392 +### filterSeries(arr, iterator, callback)
393 +
394 +__Alias:__ `selectSeries`
395 +
396 +The same as [`filter`](#filter) only the `iterator` is applied to each item in `arr` in
397 +series. The next `iterator` is only called once the current one has completed.
398 +The results array will be in the same order as the original.
399 +
400 +---------------------------------------
401 +
402 +<a name="reject" />
403 +### reject(arr, iterator, callback)
404 +
405 +The opposite of [`filter`](#filter). Removes values that pass an `async` truth test.
406 +
407 +---------------------------------------
408 +
409 +<a name="rejectSeries" />
410 +### rejectSeries(arr, iterator, callback)
411 +
412 +The same as [`reject`](#reject), only the `iterator` is applied to each item in `arr`
413 +in series.
414 +
415 +
416 +---------------------------------------
417 +
418 +<a name="reduce" />
419 +### reduce(arr, memo, iterator, callback)
420 +
421 +__Aliases:__ `inject`, `foldl`
422 +
423 +Reduces `arr` into a single value using an async `iterator` to return
424 +each successive step. `memo` is the initial state of the reduction.
425 +This function only operates in series.
426 +
427 +For performance reasons, it may make sense to split a call to this function into
428 +a parallel map, and then use the normal `Array.prototype.reduce` on the results.
429 +This function is for situations where each step in the reduction needs to be async;
430 +if you can get the data before reducing it, then it's probably a good idea to do so.
431 +
432 +__Arguments__
433 +
434 +* `arr` - An array to iterate over.
435 +* `memo` - The initial state of the reduction.
436 +* `iterator(memo, item, callback)` - A function applied to each item in the
437 + array to produce the next step in the reduction. The `iterator` is passed a
438 + `callback(err, reduction)` which accepts an optional error as its first
439 + argument, and the state of the reduction as the second. If an error is
440 + passed to the callback, the reduction is stopped and the main `callback` is
441 + immediately called with the error.
442 +* `callback(err, result)` - A callback which is called after all the `iterator`
443 + functions have finished. Result is the reduced value.
444 +
445 +__Example__
446 +
447 +```js
448 +async.reduce([1,2,3], 0, function(memo, item, callback){
449 + // pointless async:
450 + process.nextTick(function(){
451 + callback(null, memo + item)
452 + });
453 +}, function(err, result){
454 + // result is now equal to the last value of memo, which is 6
455 +});
456 +```
457 +
458 +---------------------------------------
459 +
460 +<a name="reduceRight" />
461 +### reduceRight(arr, memo, iterator, callback)
462 +
463 +__Alias:__ `foldr`
464 +
465 +Same as [`reduce`](#reduce), only operates on `arr` in reverse order.
466 +
467 +
468 +---------------------------------------
469 +
470 +<a name="detect" />
471 +### detect(arr, iterator, callback)
472 +
473 +Returns the first value in `arr` that passes an async truth test. The
474 +`iterator` is applied in parallel, meaning the first iterator to return `true` will
475 +fire the detect `callback` with that result. That means the result might not be
476 +the first item in the original `arr` (in terms of order) that passes the test.
477 +
478 +If order within the original `arr` is important, then look at [`detectSeries`](#detectSeries).
479 +
480 +__Arguments__
481 +
482 +* `arr` - An array to iterate over.
483 +* `iterator(item, callback)` - A truth test to apply to each item in `arr`.
484 + The iterator is passed a `callback(truthValue)` which must be called with a
485 + boolean argument once it has completed.
486 +* `callback(result)` - A callback which is called as soon as any iterator returns
487 + `true`, or after all the `iterator` functions have finished. Result will be
488 + the first item in the array that passes the truth test (iterator) or the
489 + value `undefined` if none passed.
490 +
491 +__Example__
492 +
493 +```js
494 +async.detect(['file1','file2','file3'], fs.exists, function(result){
495 + // result now equals the first file in the list that exists
496 +});
497 +```
498 +
499 +---------------------------------------
500 +
501 +<a name="detectSeries" />
502 +### detectSeries(arr, iterator, callback)
503 +
504 +The same as [`detect`](#detect), only the `iterator` is applied to each item in `arr`
505 +in series. This means the result is always the first in the original `arr` (in
506 +terms of array order) that passes the truth test.
507 +
508 +
509 +---------------------------------------
510 +
511 +<a name="sortBy" />
512 +### sortBy(arr, iterator, callback)
513 +
514 +Sorts a list by the results of running each `arr` value through an async `iterator`.
515 +
516 +__Arguments__
517 +
518 +* `arr` - An array to iterate over.
519 +* `iterator(item, callback)` - A function to apply to each item in `arr`.
520 + The iterator is passed a `callback(err, sortValue)` which must be called once it
521 + has completed with an error (which can be `null`) and a value to use as the sort
522 + criteria.
523 +* `callback(err, results)` - A callback which is called after all the `iterator`
524 + functions have finished, or an error occurs. Results is the items from
525 + the original `arr` sorted by the values returned by the `iterator` calls.
526 +
527 +__Example__
528 +
529 +```js
530 +async.sortBy(['file1','file2','file3'], function(file, callback){
531 + fs.stat(file, function(err, stats){
532 + callback(err, stats.mtime);
533 + });
534 +}, function(err, results){
535 + // results is now the original array of files sorted by
536 + // modified date
537 +});
538 +```
539 +
540 +__Sort Order__
541 +
542 +By modifying the callback parameter the sorting order can be influenced:
543 +
544 +```js
545 +//ascending order
546 +async.sortBy([1,9,3,5], function(x, callback){
547 + callback(null, x);
548 +}, function(err,result){
549 + //result callback
550 +} );
551 +
552 +//descending order
553 +async.sortBy([1,9,3,5], function(x, callback){
554 + callback(null, x*-1); //<- x*-1 instead of x, turns the order around
555 +}, function(err,result){
556 + //result callback
557 +} );
558 +```
559 +
560 +---------------------------------------
561 +
562 +<a name="some" />
563 +### some(arr, iterator, callback)
564 +
565 +__Alias:__ `any`
566 +
567 +Returns `true` if at least one element in the `arr` satisfies an async test.
568 +_The callback for each iterator call only accepts a single argument of `true` or
569 +`false`; it does not accept an error argument first!_ This is in-line with the
570 +way node libraries work with truth tests like `fs.exists`. Once any iterator
571 +call returns `true`, the main `callback` is immediately called.
572 +
573 +__Arguments__
574 +
575 +* `arr` - An array to iterate over.
576 +* `iterator(item, callback)` - A truth test to apply to each item in the array
577 + in parallel. The iterator is passed a callback(truthValue) which must be
578 + called with a boolean argument once it has completed.
579 +* `callback(result)` - A callback which is called as soon as any iterator returns
580 + `true`, or after all the iterator functions have finished. Result will be
581 + either `true` or `false` depending on the values of the async tests.
582 +
583 +__Example__
584 +
585 +```js
586 +async.some(['file1','file2','file3'], fs.exists, function(result){
587 + // if result is true then at least one of the files exists
588 +});
589 +```
590 +
591 +---------------------------------------
592 +
593 +<a name="every" />
594 +### every(arr, iterator, callback)
595 +
596 +__Alias:__ `all`
597 +
598 +Returns `true` if every element in `arr` satisfies an async test.
599 +_The callback for each `iterator` call only accepts a single argument of `true` or
600 +`false`; it does not accept an error argument first!_ This is in-line with the
601 +way node libraries work with truth tests like `fs.exists`.
602 +
603 +__Arguments__
604 +
605 +* `arr` - An array to iterate over.
606 +* `iterator(item, callback)` - A truth test to apply to each item in the array
607 + in parallel. The iterator is passed a callback(truthValue) which must be
608 + called with a boolean argument once it has completed.
609 +* `callback(result)` - A callback which is called after all the `iterator`
610 + functions have finished. Result will be either `true` or `false` depending on
611 + the values of the async tests.
612 +
613 +__Example__
614 +
615 +```js
616 +async.every(['file1','file2','file3'], fs.exists, function(result){
617 + // if result is true then every file exists
618 +});
619 +```
620 +
621 +---------------------------------------
622 +
623 +<a name="concat" />
624 +### concat(arr, iterator, callback)
625 +
626 +Applies `iterator` to each item in `arr`, concatenating the results. Returns the
627 +concatenated list. The `iterator`s are called in parallel, and the results are
628 +concatenated as they return. There is no guarantee that the results array will
629 +be returned in the original order of `arr` passed to the `iterator` function.
630 +
631 +__Arguments__
632 +
633 +* `arr` - An array to iterate over.
634 +* `iterator(item, callback)` - A function to apply to each item in `arr`.
635 + The iterator is passed a `callback(err, results)` which must be called once it
636 + has completed with an error (which can be `null`) and an array of results.
637 +* `callback(err, results)` - A callback which is called after all the `iterator`
638 + functions have finished, or an error occurs. Results is an array containing
639 + the concatenated results of the `iterator` function.
640 +
641 +__Example__
642 +
643 +```js
644 +async.concat(['dir1','dir2','dir3'], fs.readdir, function(err, files){
645 + // files is now a list of filenames that exist in the 3 directories
646 +});
647 +```
648 +
649 +---------------------------------------
650 +
651 +<a name="concatSeries" />
652 +### concatSeries(arr, iterator, callback)
653 +
654 +Same as [`concat`](#concat), but executes in series instead of parallel.
655 +
656 +
657 +## Control Flow
658 +
659 +<a name="series" />
660 +### series(tasks, [callback])
661 +
662 +Run the functions in the `tasks` array in series, each one running once the previous
663 +function has completed. If any functions in the series pass an error to its
664 +callback, no more functions are run, and `callback` is immediately called with the value of the error.
665 +Otherwise, `callback` receives an array of results when `tasks` have completed.
666 +
667 +It is also possible to use an object instead of an array. Each property will be
668 +run as a function, and the results will be passed to the final `callback` as an object
669 +instead of an array. This can be a more readable way of handling results from
670 +[`series`](#series).
671 +
672 +**Note** that while many implementations preserve the order of object properties, the
673 +[ECMAScript Language Specifcation](http://www.ecma-international.org/ecma-262/5.1/#sec-8.6)
674 +explicitly states that
675 +
676 +> The mechanics and order of enumerating the properties is not specified.
677 +
678 +So if you rely on the order in which your series of functions are executed, and want
679 +this to work on all platforms, consider using an array.
680 +
681 +__Arguments__
682 +
683 +* `tasks` - An array or object containing functions to run, each function is passed
684 + a `callback(err, result)` it must call on completion with an error `err` (which can
685 + be `null`) and an optional `result` value.
686 +* `callback(err, results)` - An optional callback to run once all the functions
687 + have completed. This function gets a results array (or object) containing all
688 + the result arguments passed to the `task` callbacks.
689 +
690 +__Example__
691 +
692 +```js
693 +async.series([
694 + function(callback){
695 + // do some stuff ...
696 + callback(null, 'one');
697 + },
698 + function(callback){
699 + // do some more stuff ...
700 + callback(null, 'two');
701 + }
702 +],
703 +// optional callback
704 +function(err, results){
705 + // results is now equal to ['one', 'two']
706 +});
707 +
708 +
709 +// an example using an object instead of an array
710 +async.series({
711 + one: function(callback){
712 + setTimeout(function(){
713 + callback(null, 1);
714 + }, 200);
715 + },
716 + two: function(callback){
717 + setTimeout(function(){
718 + callback(null, 2);
719 + }, 100);
720 + }
721 +},
722 +function(err, results) {
723 + // results is now equal to: {one: 1, two: 2}
724 +});
725 +```
726 +
727 +---------------------------------------
728 +
729 +<a name="parallel" />
730 +### parallel(tasks, [callback])
731 +
732 +Run the `tasks` array of functions in parallel, without waiting until the previous
733 +function has completed. If any of the functions pass an error to its
734 +callback, the main `callback` is immediately called with the value of the error.
735 +Once the `tasks` have completed, the results are passed to the final `callback` as an
736 +array.
737 +
738 +It is also possible to use an object instead of an array. Each property will be
739 +run as a function and the results will be passed to the final `callback` as an object
740 +instead of an array. This can be a more readable way of handling results from
741 +[`parallel`](#parallel).
742 +
743 +
744 +__Arguments__
745 +
746 +* `tasks` - An array or object containing functions to run. Each function is passed
747 + a `callback(err, result)` which it must call on completion with an error `err`
748 + (which can be `null`) and an optional `result` value.
749 +* `callback(err, results)` - An optional callback to run once all the functions
750 + have completed. This function gets a results array (or object) containing all
751 + the result arguments passed to the task callbacks.
752 +
753 +__Example__
754 +
755 +```js
756 +async.parallel([
757 + function(callback){
758 + setTimeout(function(){
759 + callback(null, 'one');
760 + }, 200);
761 + },
762 + function(callback){
763 + setTimeout(function(){
764 + callback(null, 'two');
765 + }, 100);
766 + }
767 +],
768 +// optional callback
769 +function(err, results){
770 + // the results array will equal ['one','two'] even though
771 + // the second function had a shorter timeout.
772 +});
773 +
774 +
775 +// an example using an object instead of an array
776 +async.parallel({
777 + one: function(callback){
778 + setTimeout(function(){
779 + callback(null, 1);
780 + }, 200);
781 + },
782 + two: function(callback){
783 + setTimeout(function(){
784 + callback(null, 2);
785 + }, 100);
786 + }
787 +},
788 +function(err, results) {
789 + // results is now equals to: {one: 1, two: 2}
790 +});
791 +```
792 +
793 +---------------------------------------
794 +
795 +<a name="parallelLimit" />
796 +### parallelLimit(tasks, limit, [callback])
797 +
798 +The same as [`parallel`](#parallel), only `tasks` are executed in parallel
799 +with a maximum of `limit` tasks executing at any time.
800 +
801 +Note that the `tasks` are not executed in batches, so there is no guarantee that
802 +the first `limit` tasks will complete before any others are started.
803 +
804 +__Arguments__
805 +
806 +* `tasks` - An array or object containing functions to run, each function is passed
807 + a `callback(err, result)` it must call on completion with an error `err` (which can
808 + be `null`) and an optional `result` value.
809 +* `limit` - The maximum number of `tasks` to run at any time.
810 +* `callback(err, results)` - An optional callback to run once all the functions
811 + have completed. This function gets a results array (or object) containing all
812 + the result arguments passed to the `task` callbacks.
813 +
814 +---------------------------------------
815 +
816 +<a name="whilst" />
817 +### whilst(test, fn, callback)
818 +
819 +Repeatedly call `fn`, while `test` returns `true`. Calls `callback` when stopped,
820 +or an error occurs.
821 +
822 +__Arguments__
823 +
824 +* `test()` - synchronous truth test to perform before each execution of `fn`.
825 +* `fn(callback)` - A function which is called each time `test` passes. The function is
826 + passed a `callback(err)`, which must be called once it has completed with an
827 + optional `err` argument.
828 +* `callback(err)` - A callback which is called after the test fails and repeated
829 + execution of `fn` has stopped.
830 +
831 +__Example__
832 +
833 +```js
834 +var count = 0;
835 +
836 +async.whilst(
837 + function () { return count < 5; },
838 + function (callback) {
839 + count++;
840 + setTimeout(callback, 1000);
841 + },
842 + function (err) {
843 + // 5 seconds have passed
844 + }
845 +);
846 +```
847 +
848 +---------------------------------------
849 +
850 +<a name="doWhilst" />
851 +### doWhilst(fn, test, callback)
852 +
853 +The post-check version of [`whilst`](#whilst). To reflect the difference in
854 +the order of operations, the arguments `test` and `fn` are switched.
855 +
856 +`doWhilst` is to `whilst` as `do while` is to `while` in plain JavaScript.
857 +
858 +---------------------------------------
859 +
860 +<a name="until" />
861 +### until(test, fn, callback)
862 +
863 +Repeatedly call `fn` until `test` returns `true`. Calls `callback` when stopped,
864 +or an error occurs.
865 +
866 +The inverse of [`whilst`](#whilst).
867 +
868 +---------------------------------------
869 +
870 +<a name="doUntil" />
871 +### doUntil(fn, test, callback)
872 +
873 +Like [`doWhilst`](#doWhilst), except the `test` is inverted. Note the argument ordering differs from `until`.
874 +
875 +---------------------------------------
876 +
877 +<a name="forever" />
878 +### forever(fn, errback)
879 +
880 +Calls the asynchronous function `fn` with a callback parameter that allows it to
881 +call itself again, in series, indefinitely.
882 +
883 +If an error is passed to the callback then `errback` is called with the
884 +error, and execution stops, otherwise it will never be called.
885 +
886 +```js
887 +async.forever(
888 + function(next) {
889 + // next is suitable for passing to things that need a callback(err [, whatever]);
890 + // it will result in this function being called again.
891 + },
892 + function(err) {
893 + // if next is called with a value in its first parameter, it will appear
894 + // in here as 'err', and execution will stop.
895 + }
896 +);
897 +```
898 +
899 +---------------------------------------
900 +
901 +<a name="waterfall" />
902 +### waterfall(tasks, [callback])
903 +
904 +Runs the `tasks` array of functions in series, each passing their results to the next in
905 +the array. However, if any of the `tasks` pass an error to their own callback, the
906 +next function is not executed, and the main `callback` is immediately called with
907 +the error.
908 +
909 +__Arguments__
910 +
911 +* `tasks` - An array of functions to run, each function is passed a
912 + `callback(err, result1, result2, ...)` it must call on completion. The first
913 + argument is an error (which can be `null`) and any further arguments will be
914 + passed as arguments in order to the next task.
915 +* `callback(err, [results])` - An optional callback to run once all the functions
916 + have completed. This will be passed the results of the last task's callback.
917 +
918 +
919 +
920 +__Example__
921 +
922 +```js
923 +async.waterfall([
924 + function(callback) {
925 + callback(null, 'one', 'two');
926 + },
927 + function(arg1, arg2, callback) {
928 + // arg1 now equals 'one' and arg2 now equals 'two'
929 + callback(null, 'three');
930 + },
931 + function(arg1, callback) {
932 + // arg1 now equals 'three'
933 + callback(null, 'done');
934 + }
935 +], function (err, result) {
936 + // result now equals 'done'
937 +});
938 +```
939 +
940 +---------------------------------------
941 +<a name="compose" />
942 +### compose(fn1, fn2...)
943 +
944 +Creates a function which is a composition of the passed asynchronous
945 +functions. Each function consumes the return value of the function that
946 +follows. Composing functions `f()`, `g()`, and `h()` would produce the result of
947 +`f(g(h()))`, only this version uses callbacks to obtain the return values.
948 +
949 +Each function is executed with the `this` binding of the composed function.
950 +
951 +__Arguments__
952 +
953 +* `functions...` - the asynchronous functions to compose
954 +
955 +
956 +__Example__
957 +
958 +```js
959 +function add1(n, callback) {
960 + setTimeout(function () {
961 + callback(null, n + 1);
962 + }, 10);
963 +}
964 +
965 +function mul3(n, callback) {
966 + setTimeout(function () {
967 + callback(null, n * 3);
968 + }, 10);
969 +}
970 +
971 +var add1mul3 = async.compose(mul3, add1);
972 +
973 +add1mul3(4, function (err, result) {
974 + // result now equals 15
975 +});
976 +```
977 +
978 +---------------------------------------
979 +<a name="seq" />
980 +### seq(fn1, fn2...)
981 +
982 +Version of the compose function that is more natural to read.
983 +Each function consumes the return value of the previous function.
984 +It is the equivalent of [`compose`](#compose) with the arguments reversed.
985 +
986 +Each function is executed with the `this` binding of the composed function.
987 +
988 +__Arguments__
989 +
990 +* functions... - the asynchronous functions to compose
991 +
992 +
993 +__Example__
994 +
995 +```js
996 +// Requires lodash (or underscore), express3 and dresende's orm2.
997 +// Part of an app, that fetches cats of the logged user.
998 +// This example uses `seq` function to avoid overnesting and error
999 +// handling clutter.
1000 +app.get('/cats', function(request, response) {
1001 + var User = request.models.User;
1002 + async.seq(
1003 + _.bind(User.get, User), // 'User.get' has signature (id, callback(err, data))
1004 + function(user, fn) {
1005 + user.getCats(fn); // 'getCats' has signature (callback(err, data))
1006 + }
1007 + )(req.session.user_id, function (err, cats) {
1008 + if (err) {
1009 + console.error(err);
1010 + response.json({ status: 'error', message: err.message });
1011 + } else {
1012 + response.json({ status: 'ok', message: 'Cats found', data: cats });
1013 + }
1014 + });
1015 +});
1016 +```
1017 +
1018 +---------------------------------------
1019 +<a name="applyEach" />
1020 +### applyEach(fns, args..., callback)
1021 +
1022 +Applies the provided arguments to each function in the array, calling
1023 +`callback` after all functions have completed. If you only provide the first
1024 +argument, then it will return a function which lets you pass in the
1025 +arguments as if it were a single function call.
1026 +
1027 +__Arguments__
1028 +
1029 +* `fns` - the asynchronous functions to all call with the same arguments
1030 +* `args...` - any number of separate arguments to pass to the function
1031 +* `callback` - the final argument should be the callback, called when all
1032 + functions have completed processing
1033 +
1034 +
1035 +__Example__
1036 +
1037 +```js
1038 +async.applyEach([enableSearch, updateSchema], 'bucket', callback);
1039 +
1040 +// partial application example:
1041 +async.each(
1042 + buckets,
1043 + async.applyEach([enableSearch, updateSchema]),
1044 + callback
1045 +);
1046 +```
1047 +
1048 +---------------------------------------
1049 +
1050 +<a name="applyEachSeries" />
1051 +### applyEachSeries(arr, iterator, callback)
1052 +
1053 +The same as [`applyEach`](#applyEach) only the functions are applied in series.
1054 +
1055 +---------------------------------------
1056 +
1057 +<a name="queue" />
1058 +### queue(worker, concurrency)
1059 +
1060 +Creates a `queue` object with the specified `concurrency`. Tasks added to the
1061 +`queue` are processed in parallel (up to the `concurrency` limit). If all
1062 +`worker`s are in progress, the task is queued until one becomes available.
1063 +Once a `worker` completes a `task`, that `task`'s callback is called.
1064 +
1065 +__Arguments__
1066 +
1067 +* `worker(task, callback)` - An asynchronous function for processing a queued
1068 + task, which must call its `callback(err)` argument when finished, with an
1069 + optional `error` as an argument.
1070 +* `concurrency` - An `integer` for determining how many `worker` functions should be
1071 + run in parallel.
1072 +
1073 +__Queue objects__
1074 +
1075 +The `queue` object returned by this function has the following properties and
1076 +methods:
1077 +
1078 +* `length()` - a function returning the number of items waiting to be processed.
1079 +* `started` - a function returning whether or not any items have been pushed and processed by the queue
1080 +* `running()` - a function returning the number of items currently being processed.
1081 +* `idle()` - a function returning false if there are items waiting or being processed, or true if not.
1082 +* `concurrency` - an integer for determining how many `worker` functions should be
1083 + run in parallel. This property can be changed after a `queue` is created to
1084 + alter the concurrency on-the-fly.
1085 +* `push(task, [callback])` - add a new task to the `queue`. Calls `callback` once
1086 + the `worker` has finished processing the task. Instead of a single task, a `tasks` array
1087 + can be submitted. The respective callback is used for every task in the list.
1088 +* `unshift(task, [callback])` - add a new task to the front of the `queue`.
1089 +* `saturated` - a callback that is called when the `queue` length hits the `concurrency` limit,
1090 + and further tasks will be queued.
1091 +* `empty` - a callback that is called when the last item from the `queue` is given to a `worker`.
1092 +* `drain` - a callback that is called when the last item from the `queue` has returned from the `worker`.
1093 +* `paused` - a boolean for determining whether the queue is in a paused state
1094 +* `pause()` - a function that pauses the processing of tasks until `resume()` is called.
1095 +* `resume()` - a function that resumes the processing of queued tasks when the queue is paused.
1096 +* `kill()` - a function that removes the `drain` callback and empties remaining tasks from the queue forcing it to go idle.
1097 +
1098 +__Example__
1099 +
1100 +```js
1101 +// create a queue object with concurrency 2
1102 +
1103 +var q = async.queue(function (task, callback) {
1104 + console.log('hello ' + task.name);
1105 + callback();
1106 +}, 2);
1107 +
1108 +
1109 +// assign a callback
1110 +q.drain = function() {
1111 + console.log('all items have been processed');
1112 +}
1113 +
1114 +// add some items to the queue
1115 +
1116 +q.push({name: 'foo'}, function (err) {
1117 + console.log('finished processing foo');
1118 +});
1119 +q.push({name: 'bar'}, function (err) {
1120 + console.log('finished processing bar');
1121 +});
1122 +
1123 +// add some items to the queue (batch-wise)
1124 +
1125 +q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function (err) {
1126 + console.log('finished processing item');
1127 +});
1128 +
1129 +// add some items to the front of the queue
1130 +
1131 +q.unshift({name: 'bar'}, function (err) {
1132 + console.log('finished processing bar');
1133 +});
1134 +```
1135 +
1136 +
1137 +---------------------------------------
1138 +
1139 +<a name="priorityQueue" />
1140 +### priorityQueue(worker, concurrency)
1141 +
1142 +The same as [`queue`](#queue) only tasks are assigned a priority and completed in ascending priority order. There are two differences between `queue` and `priorityQueue` objects:
1143 +
1144 +* `push(task, priority, [callback])` - `priority` should be a number. If an array of
1145 + `tasks` is given, all tasks will be assigned the same priority.
1146 +* The `unshift` method was removed.
1147 +
1148 +---------------------------------------
1149 +
1150 +<a name="cargo" />
1151 +### cargo(worker, [payload])
1152 +
1153 +Creates a `cargo` object with the specified payload. Tasks added to the
1154 +cargo will be processed altogether (up to the `payload` limit). If the
1155 +`worker` is in progress, the task is queued until it becomes available. Once
1156 +the `worker` has completed some tasks, each callback of those tasks is called.
1157 +Check out [this animation](https://camo.githubusercontent.com/6bbd36f4cf5b35a0f11a96dcd2e97711ffc2fb37/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313637363837312f36383130382f62626330636662302d356632392d313165322d393734662d3333393763363464633835382e676966) for how `cargo` and `queue` work.
1158 +
1159 +While [queue](#queue) passes only one task to one of a group of workers
1160 +at a time, cargo passes an array of tasks to a single worker, repeating
1161 +when the worker is finished.
1162 +
1163 +__Arguments__
1164 +
1165 +* `worker(tasks, callback)` - An asynchronous function for processing an array of
1166 + queued tasks, which must call its `callback(err)` argument when finished, with
1167 + an optional `err` argument.
1168 +* `payload` - An optional `integer` for determining how many tasks should be
1169 + processed per round; if omitted, the default is unlimited.
1170 +
1171 +__Cargo objects__
1172 +
1173 +The `cargo` object returned by this function has the following properties and
1174 +methods:
1175 +
1176 +* `length()` - A function returning the number of items waiting to be processed.
1177 +* `payload` - An `integer` for determining how many tasks should be
1178 + process per round. This property can be changed after a `cargo` is created to
1179 + alter the payload on-the-fly.
1180 +* `push(task, [callback])` - Adds `task` to the `queue`. The callback is called
1181 + once the `worker` has finished processing the task. Instead of a single task, an array of `tasks`
1182 + can be submitted. The respective callback is used for every task in the list.
1183 +* `saturated` - A callback that is called when the `queue.length()` hits the concurrency and further tasks will be queued.
1184 +* `empty` - A callback that is called when the last item from the `queue` is given to a `worker`.
1185 +* `drain` - A callback that is called when the last item from the `queue` has returned from the `worker`.
1186 +
1187 +__Example__
1188 +
1189 +```js
1190 +// create a cargo object with payload 2
1191 +
1192 +var cargo = async.cargo(function (tasks, callback) {
1193 + for(var i=0; i<tasks.length; i++){
1194 + console.log('hello ' + tasks[i].name);
1195 + }
1196 + callback();
1197 +}, 2);
1198 +
1199 +
1200 +// add some items
1201 +
1202 +cargo.push({name: 'foo'}, function (err) {
1203 + console.log('finished processing foo');
1204 +});
1205 +cargo.push({name: 'bar'}, function (err) {
1206 + console.log('finished processing bar');
1207 +});
1208 +cargo.push({name: 'baz'}, function (err) {
1209 + console.log('finished processing baz');
1210 +});
1211 +```
1212 +
1213 +---------------------------------------
1214 +
1215 +<a name="auto" />
1216 +### auto(tasks, [callback])
1217 +
1218 +Determines the best order for running the functions in `tasks`, based on their
1219 +requirements. Each function can optionally depend on other functions being completed
1220 +first, and each function is run as soon as its requirements are satisfied.
1221 +
1222 +If any of the functions pass an error to their callback, it will not
1223 +complete (so any other functions depending on it will not run), and the main
1224 +`callback` is immediately called with the error. Functions also receive an
1225 +object containing the results of functions which have completed so far.
1226 +
1227 +Note, all functions are called with a `results` object as a second argument,
1228 +so it is unsafe to pass functions in the `tasks` object which cannot handle the
1229 +extra argument.
1230 +
1231 +For example, this snippet of code:
1232 +
1233 +```js
1234 +async.auto({
1235 + readData: async.apply(fs.readFile, 'data.txt', 'utf-8')
1236 +}, callback);
1237 +```
1238 +
1239 +will have the effect of calling `readFile` with the results object as the last
1240 +argument, which will fail:
1241 +
1242 +```js
1243 +fs.readFile('data.txt', 'utf-8', cb, {});
1244 +```
1245 +
1246 +Instead, wrap the call to `readFile` in a function which does not forward the
1247 +`results` object:
1248 +
1249 +```js
1250 +async.auto({
1251 + readData: function(cb, results){
1252 + fs.readFile('data.txt', 'utf-8', cb);
1253 + }
1254 +}, callback);
1255 +```
1256 +
1257 +__Arguments__
1258 +
1259 +* `tasks` - An object. Each of its properties is either a function or an array of
1260 + requirements, with the function itself the last item in the array. The object's key
1261 + of a property serves as the name of the task defined by that property,
1262 + i.e. can be used when specifying requirements for other tasks.
1263 + The function receives two arguments: (1) a `callback(err, result)` which must be
1264 + called when finished, passing an `error` (which can be `null`) and the result of
1265 + the function's execution, and (2) a `results` object, containing the results of
1266 + the previously executed functions.
1267 +* `callback(err, results)` - An optional callback which is called when all the
1268 + tasks have been completed. It receives the `err` argument if any `tasks`
1269 + pass an error to their callback. Results are always returned; however, if
1270 + an error occurs, no further `tasks` will be performed, and the results
1271 + object will only contain partial results.
1272 +
1273 +
1274 +__Example__
1275 +
1276 +```js
1277 +async.auto({
1278 + get_data: function(callback){
1279 + console.log('in get_data');
1280 + // async code to get some data
1281 + callback(null, 'data', 'converted to array');
1282 + },
1283 + make_folder: function(callback){
1284 + console.log('in make_folder');
1285 + // async code to create a directory to store a file in
1286 + // this is run at the same time as getting the data
1287 + callback(null, 'folder');
1288 + },
1289 + write_file: ['get_data', 'make_folder', function(callback, results){
1290 + console.log('in write_file', JSON.stringify(results));
1291 + // once there is some data and the directory exists,
1292 + // write the data to a file in the directory
1293 + callback(null, 'filename');
1294 + }],
1295 + email_link: ['write_file', function(callback, results){
1296 + console.log('in email_link', JSON.stringify(results));
1297 + // once the file is written let's email a link to it...
1298 + // results.write_file contains the filename returned by write_file.
1299 + callback(null, {'file':results.write_file, 'email':'user@example.com'});
1300 + }]
1301 +}, function(err, results) {
1302 + console.log('err = ', err);
1303 + console.log('results = ', results);
1304 +});
1305 +```
1306 +
1307 +This is a fairly trivial example, but to do this using the basic parallel and
1308 +series functions would look like this:
1309 +
1310 +```js
1311 +async.parallel([
1312 + function(callback){
1313 + console.log('in get_data');
1314 + // async code to get some data
1315 + callback(null, 'data', 'converted to array');
1316 + },
1317 + function(callback){
1318 + console.log('in make_folder');
1319 + // async code to create a directory to store a file in
1320 + // this is run at the same time as getting the data
1321 + callback(null, 'folder');
1322 + }
1323 +],
1324 +function(err, results){
1325 + async.series([
1326 + function(callback){
1327 + console.log('in write_file', JSON.stringify(results));
1328 + // once there is some data and the directory exists,
1329 + // write the data to a file in the directory
1330 + results.push('filename');
1331 + callback(null);
1332 + },
1333 + function(callback){
1334 + console.log('in email_link', JSON.stringify(results));
1335 + // once the file is written let's email a link to it...
1336 + callback(null, {'file':results.pop(), 'email':'user@example.com'});
1337 + }
1338 + ]);
1339 +});
1340 +```
1341 +
1342 +For a complicated series of `async` tasks, using the [`auto`](#auto) function makes adding
1343 +new tasks much easier (and the code more readable).
1344 +
1345 +
1346 +---------------------------------------
1347 +
1348 +<a name="retry" />
1349 +### retry([times = 5], task, [callback])
1350 +
1351 +Attempts to get a successful response from `task` no more than `times` times before
1352 +returning an error. If the task is successful, the `callback` will be passed the result
1353 +of the successful task. If all attempts fail, the callback will be passed the error and
1354 +result (if any) of the final attempt.
1355 +
1356 +__Arguments__
1357 +
1358 +* `times` - An integer indicating how many times to attempt the `task` before giving up. Defaults to 5.
1359 +* `task(callback, results)` - A function which receives two arguments: (1) a `callback(err, result)`
1360 + which must be called when finished, passing `err` (which can be `null`) and the `result` of
1361 + the function's execution, and (2) a `results` object, containing the results of
1362 + the previously executed functions (if nested inside another control flow).
1363 +* `callback(err, results)` - An optional callback which is called when the
1364 + task has succeeded, or after the final failed attempt. It receives the `err` and `result` arguments of the last attempt at completing the `task`.
1365 +
1366 +The [`retry`](#retry) function can be used as a stand-alone control flow by passing a
1367 +callback, as shown below:
1368 +
1369 +```js
1370 +async.retry(3, apiMethod, function(err, result) {
1371 + // do something with the result
1372 +});
1373 +```
1374 +
1375 +It can also be embeded within other control flow functions to retry individual methods
1376 +that are not as reliable, like this:
1377 +
1378 +```js
1379 +async.auto({
1380 + users: api.getUsers.bind(api),
1381 + payments: async.retry(3, api.getPayments.bind(api))
1382 +}, function(err, results) {
1383 + // do something with the results
1384 +});
1385 +```
1386 +
1387 +
1388 +---------------------------------------
1389 +
1390 +<a name="iterator" />
1391 +### iterator(tasks)
1392 +
1393 +Creates an iterator function which calls the next function in the `tasks` array,
1394 +returning a continuation to call the next one after that. It's also possible to
1395 +“peek” at the next iterator with `iterator.next()`.
1396 +
1397 +This function is used internally by the `async` module, but can be useful when
1398 +you want to manually control the flow of functions in series.
1399 +
1400 +__Arguments__
1401 +
1402 +* `tasks` - An array of functions to run.
1403 +
1404 +__Example__
1405 +
1406 +```js
1407 +var iterator = async.iterator([
1408 + function(){ sys.p('one'); },
1409 + function(){ sys.p('two'); },
1410 + function(){ sys.p('three'); }
1411 +]);
1412 +
1413 +node> var iterator2 = iterator();
1414 +'one'
1415 +node> var iterator3 = iterator2();
1416 +'two'
1417 +node> iterator3();
1418 +'three'
1419 +node> var nextfn = iterator2.next();
1420 +node> nextfn();
1421 +'three'
1422 +```
1423 +
1424 +---------------------------------------
1425 +
1426 +<a name="apply" />
1427 +### apply(function, arguments..)
1428 +
1429 +Creates a continuation function with some arguments already applied.
1430 +
1431 +Useful as a shorthand when combined with other control flow functions. Any arguments
1432 +passed to the returned function are added to the arguments originally passed
1433 +to apply.
1434 +
1435 +__Arguments__
1436 +
1437 +* `function` - The function you want to eventually apply all arguments to.
1438 +* `arguments...` - Any number of arguments to automatically apply when the
1439 + continuation is called.
1440 +
1441 +__Example__
1442 +
1443 +```js
1444 +// using apply
1445 +
1446 +async.parallel([
1447 + async.apply(fs.writeFile, 'testfile1', 'test1'),
1448 + async.apply(fs.writeFile, 'testfile2', 'test2'),
1449 +]);
1450 +
1451 +
1452 +// the same process without using apply
1453 +
1454 +async.parallel([
1455 + function(callback){
1456 + fs.writeFile('testfile1', 'test1', callback);
1457 + },
1458 + function(callback){
1459 + fs.writeFile('testfile2', 'test2', callback);
1460 + }
1461 +]);
1462 +```
1463 +
1464 +It's possible to pass any number of additional arguments when calling the
1465 +continuation:
1466 +
1467 +```js
1468 +node> var fn = async.apply(sys.puts, 'one');
1469 +node> fn('two', 'three');
1470 +one
1471 +two
1472 +three
1473 +```
1474 +
1475 +---------------------------------------
1476 +
1477 +<a name="nextTick" />
1478 +### nextTick(callback), setImmediate(callback)
1479 +
1480 +Calls `callback` on a later loop around the event loop. In Node.js this just
1481 +calls `process.nextTick`; in the browser it falls back to `setImmediate(callback)`
1482 +if available, otherwise `setTimeout(callback, 0)`, which means other higher priority
1483 +events may precede the execution of `callback`.
1484 +
1485 +This is used internally for browser-compatibility purposes.
1486 +
1487 +__Arguments__
1488 +
1489 +* `callback` - The function to call on a later loop around the event loop.
1490 +
1491 +__Example__
1492 +
1493 +```js
1494 +var call_order = [];
1495 +async.nextTick(function(){
1496 + call_order.push('two');
1497 + // call_order now equals ['one','two']
1498 +});
1499 +call_order.push('one')
1500 +```
1501 +
1502 +<a name="times" />
1503 +### times(n, callback)
1504 +
1505 +Calls the `callback` function `n` times, and accumulates results in the same manner
1506 +you would use with [`map`](#map).
1507 +
1508 +__Arguments__
1509 +
1510 +* `n` - The number of times to run the function.
1511 +* `callback` - The function to call `n` times.
1512 +
1513 +__Example__
1514 +
1515 +```js
1516 +// Pretend this is some complicated async factory
1517 +var createUser = function(id, callback) {
1518 + callback(null, {
1519 + id: 'user' + id
1520 + })
1521 +}
1522 +// generate 5 users
1523 +async.times(5, function(n, next){
1524 + createUser(n, function(err, user) {
1525 + next(err, user)
1526 + })
1527 +}, function(err, users) {
1528 + // we should now have 5 users
1529 +});
1530 +```
1531 +
1532 +<a name="timesSeries" />
1533 +### timesSeries(n, callback)
1534 +
1535 +The same as [`times`](#times), only the iterator is applied to each item in `arr` in
1536 +series. The next `iterator` is only called once the current one has completed.
1537 +The results array will be in the same order as the original.
1538 +
1539 +
1540 +## Utils
1541 +
1542 +<a name="memoize" />
1543 +### memoize(fn, [hasher])
1544 +
1545 +Caches the results of an `async` function. When creating a hash to store function
1546 +results against, the callback is omitted from the hash and an optional hash
1547 +function can be used.
1548 +
1549 +The cache of results is exposed as the `memo` property of the function returned
1550 +by `memoize`.
1551 +
1552 +__Arguments__
1553 +
1554 +* `fn` - The function to proxy and cache results from.
1555 +* `hasher` - Tn optional function for generating a custom hash for storing
1556 + results. It has all the arguments applied to it apart from the callback, and
1557 + must be synchronous.
1558 +
1559 +__Example__
1560 +
1561 +```js
1562 +var slow_fn = function (name, callback) {
1563 + // do something
1564 + callback(null, result);
1565 +};
1566 +var fn = async.memoize(slow_fn);
1567 +
1568 +// fn can now be used as if it were slow_fn
1569 +fn('some name', function () {
1570 + // callback
1571 +});
1572 +```
1573 +
1574 +<a name="unmemoize" />
1575 +### unmemoize(fn)
1576 +
1577 +Undoes a [`memoize`](#memoize)d function, reverting it to the original, unmemoized
1578 +form. Handy for testing.
1579 +
1580 +__Arguments__
1581 +
1582 +* `fn` - the memoized function
1583 +
1584 +<a name="log" />
1585 +### log(function, arguments)
1586 +
1587 +Logs the result of an `async` function to the `console`. Only works in Node.js or
1588 +in browsers that support `console.log` and `console.error` (such as FF and Chrome).
1589 +If multiple arguments are returned from the async function, `console.log` is
1590 +called on each argument in order.
1591 +
1592 +__Arguments__
1593 +
1594 +* `function` - The function you want to eventually apply all arguments to.
1595 +* `arguments...` - Any number of arguments to apply to the function.
1596 +
1597 +__Example__
1598 +
1599 +```js
1600 +var hello = function(name, callback){
1601 + setTimeout(function(){
1602 + callback(null, 'hello ' + name);
1603 + }, 1000);
1604 +};
1605 +```
1606 +```js
1607 +node> async.log(hello, 'world');
1608 +'hello world'
1609 +```
1610 +
1611 +---------------------------------------
1612 +
1613 +<a name="dir" />
1614 +### dir(function, arguments)
1615 +
1616 +Logs the result of an `async` function to the `console` using `console.dir` to
1617 +display the properties of the resulting object. Only works in Node.js or
1618 +in browsers that support `console.dir` and `console.error` (such as FF and Chrome).
1619 +If multiple arguments are returned from the async function, `console.dir` is
1620 +called on each argument in order.
1621 +
1622 +__Arguments__
1623 +
1624 +* `function` - The function you want to eventually apply all arguments to.
1625 +* `arguments...` - Any number of arguments to apply to the function.
1626 +
1627 +__Example__
1628 +
1629 +```js
1630 +var hello = function(name, callback){
1631 + setTimeout(function(){
1632 + callback(null, {hello: name});
1633 + }, 1000);
1634 +};
1635 +```
1636 +```js
1637 +node> async.dir(hello, 'world');
1638 +{hello: 'world'}
1639 +```
1640 +
1641 +---------------------------------------
1642 +
1643 +<a name="noConflict" />
1644 +### noConflict()
1645 +
1646 +Changes the value of `async` back to its original value, returning a reference to the
1647 +`async` object.
1 +{
2 + "name": "async",
3 + "description": "Higher-order functions and common patterns for asynchronous code",
4 + "version": "0.9.2",
5 + "main": "lib/async.js",
6 + "keywords": [
7 + "async",
8 + "callback",
9 + "utility",
10 + "module"
11 + ],
12 + "license": "MIT",
13 + "repository": {
14 + "type": "git",
15 + "url": "https://github.com/caolan/async.git"
16 + },
17 + "devDependencies": {
18 + "nodeunit": ">0.0.0",
19 + "uglify-js": "1.2.x",
20 + "nodelint": ">0.0.0",
21 + "lodash": ">=2.4.1"
22 + },
23 + "moduleType": [
24 + "amd",
25 + "globals",
26 + "node"
27 + ],
28 + "ignore": [
29 + "**/.*",
30 + "node_modules",
31 + "bower_components",
32 + "test",
33 + "tests"
34 + ],
35 + "authors": [
36 + "Caolan McMahon"
37 + ]
38 +}
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "name": "async",
3 + "description": "Higher-order functions and common patterns for asynchronous code",
4 + "version": "0.9.2",
5 + "keywords": [
6 + "async",
7 + "callback",
8 + "utility",
9 + "module"
10 + ],
11 + "license": "MIT",
12 + "repository": "caolan/async",
13 + "scripts": [
14 + "lib/async.js"
15 + ]
16 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*!
2 + * async
3 + * https://github.com/caolan/async
4 + *
5 + * Copyright 2010-2014 Caolan McMahon
6 + * Released under the MIT license
7 + */
8 +/*jshint onevar: false, indent:4 */
9 +/*global setImmediate: false, setTimeout: false, console: false */
10 +(function () {
11 +
12 + var async = {};
13 +
14 + // global on the server, window in the browser
15 + var root, previous_async;
16 +
17 + root = this;
18 + if (root != null) {
19 + previous_async = root.async;
20 + }
21 +
22 + async.noConflict = function () {
23 + root.async = previous_async;
24 + return async;
25 + };
26 +
27 + function only_once(fn) {
28 + var called = false;
29 + return function() {
30 + if (called) throw new Error("Callback was already called.");
31 + called = true;
32 + fn.apply(root, arguments);
33 + }
34 + }
35 +
36 + //// cross-browser compatiblity functions ////
37 +
38 + var _toString = Object.prototype.toString;
39 +
40 + var _isArray = Array.isArray || function (obj) {
41 + return _toString.call(obj) === '[object Array]';
42 + };
43 +
44 + var _each = function (arr, iterator) {
45 + for (var i = 0; i < arr.length; i += 1) {
46 + iterator(arr[i], i, arr);
47 + }
48 + };
49 +
50 + var _map = function (arr, iterator) {
51 + if (arr.map) {
52 + return arr.map(iterator);
53 + }
54 + var results = [];
55 + _each(arr, function (x, i, a) {
56 + results.push(iterator(x, i, a));
57 + });
58 + return results;
59 + };
60 +
61 + var _reduce = function (arr, iterator, memo) {
62 + if (arr.reduce) {
63 + return arr.reduce(iterator, memo);
64 + }
65 + _each(arr, function (x, i, a) {
66 + memo = iterator(memo, x, i, a);
67 + });
68 + return memo;
69 + };
70 +
71 + var _keys = function (obj) {
72 + if (Object.keys) {
73 + return Object.keys(obj);
74 + }
75 + var keys = [];
76 + for (var k in obj) {
77 + if (obj.hasOwnProperty(k)) {
78 + keys.push(k);
79 + }
80 + }
81 + return keys;
82 + };
83 +
84 + //// exported async module functions ////
85 +
86 + //// nextTick implementation with browser-compatible fallback ////
87 + if (typeof process === 'undefined' || !(process.nextTick)) {
88 + if (typeof setImmediate === 'function') {
89 + async.nextTick = function (fn) {
90 + // not a direct alias for IE10 compatibility
91 + setImmediate(fn);
92 + };
93 + async.setImmediate = async.nextTick;
94 + }
95 + else {
96 + async.nextTick = function (fn) {
97 + setTimeout(fn, 0);
98 + };
99 + async.setImmediate = async.nextTick;
100 + }
101 + }
102 + else {
103 + async.nextTick = process.nextTick;
104 + if (typeof setImmediate !== 'undefined') {
105 + async.setImmediate = function (fn) {
106 + // not a direct alias for IE10 compatibility
107 + setImmediate(fn);
108 + };
109 + }
110 + else {
111 + async.setImmediate = async.nextTick;
112 + }
113 + }
114 +
115 + async.each = function (arr, iterator, callback) {
116 + callback = callback || function () {};
117 + if (!arr.length) {
118 + return callback();
119 + }
120 + var completed = 0;
121 + _each(arr, function (x) {
122 + iterator(x, only_once(done) );
123 + });
124 + function done(err) {
125 + if (err) {
126 + callback(err);
127 + callback = function () {};
128 + }
129 + else {
130 + completed += 1;
131 + if (completed >= arr.length) {
132 + callback();
133 + }
134 + }
135 + }
136 + };
137 + async.forEach = async.each;
138 +
139 + async.eachSeries = function (arr, iterator, callback) {
140 + callback = callback || function () {};
141 + if (!arr.length) {
142 + return callback();
143 + }
144 + var completed = 0;
145 + var iterate = function () {
146 + iterator(arr[completed], function (err) {
147 + if (err) {
148 + callback(err);
149 + callback = function () {};
150 + }
151 + else {
152 + completed += 1;
153 + if (completed >= arr.length) {
154 + callback();
155 + }
156 + else {
157 + iterate();
158 + }
159 + }
160 + });
161 + };
162 + iterate();
163 + };
164 + async.forEachSeries = async.eachSeries;
165 +
166 + async.eachLimit = function (arr, limit, iterator, callback) {
167 + var fn = _eachLimit(limit);
168 + fn.apply(null, [arr, iterator, callback]);
169 + };
170 + async.forEachLimit = async.eachLimit;
171 +
172 + var _eachLimit = function (limit) {
173 +
174 + return function (arr, iterator, callback) {
175 + callback = callback || function () {};
176 + if (!arr.length || limit <= 0) {
177 + return callback();
178 + }
179 + var completed = 0;
180 + var started = 0;
181 + var running = 0;
182 +
183 + (function replenish () {
184 + if (completed >= arr.length) {
185 + return callback();
186 + }
187 +
188 + while (running < limit && started < arr.length) {
189 + started += 1;
190 + running += 1;
191 + iterator(arr[started - 1], function (err) {
192 + if (err) {
193 + callback(err);
194 + callback = function () {};
195 + }
196 + else {
197 + completed += 1;
198 + running -= 1;
199 + if (completed >= arr.length) {
200 + callback();
201 + }
202 + else {
203 + replenish();
204 + }
205 + }
206 + });
207 + }
208 + })();
209 + };
210 + };
211 +
212 +
213 + var doParallel = function (fn) {
214 + return function () {
215 + var args = Array.prototype.slice.call(arguments);
216 + return fn.apply(null, [async.each].concat(args));
217 + };
218 + };
219 + var doParallelLimit = function(limit, fn) {
220 + return function () {
221 + var args = Array.prototype.slice.call(arguments);
222 + return fn.apply(null, [_eachLimit(limit)].concat(args));
223 + };
224 + };
225 + var doSeries = function (fn) {
226 + return function () {
227 + var args = Array.prototype.slice.call(arguments);
228 + return fn.apply(null, [async.eachSeries].concat(args));
229 + };
230 + };
231 +
232 +
233 + var _asyncMap = function (eachfn, arr, iterator, callback) {
234 + arr = _map(arr, function (x, i) {
235 + return {index: i, value: x};
236 + });
237 + if (!callback) {
238 + eachfn(arr, function (x, callback) {
239 + iterator(x.value, function (err) {
240 + callback(err);
241 + });
242 + });
243 + } else {
244 + var results = [];
245 + eachfn(arr, function (x, callback) {
246 + iterator(x.value, function (err, v) {
247 + results[x.index] = v;
248 + callback(err);
249 + });
250 + }, function (err) {
251 + callback(err, results);
252 + });
253 + }
254 + };
255 + async.map = doParallel(_asyncMap);
256 + async.mapSeries = doSeries(_asyncMap);
257 + async.mapLimit = function (arr, limit, iterator, callback) {
258 + return _mapLimit(limit)(arr, iterator, callback);
259 + };
260 +
261 + var _mapLimit = function(limit) {
262 + return doParallelLimit(limit, _asyncMap);
263 + };
264 +
265 + // reduce only has a series version, as doing reduce in parallel won't
266 + // work in many situations.
267 + async.reduce = function (arr, memo, iterator, callback) {
268 + async.eachSeries(arr, function (x, callback) {
269 + iterator(memo, x, function (err, v) {
270 + memo = v;
271 + callback(err);
272 + });
273 + }, function (err) {
274 + callback(err, memo);
275 + });
276 + };
277 + // inject alias
278 + async.inject = async.reduce;
279 + // foldl alias
280 + async.foldl = async.reduce;
281 +
282 + async.reduceRight = function (arr, memo, iterator, callback) {
283 + var reversed = _map(arr, function (x) {
284 + return x;
285 + }).reverse();
286 + async.reduce(reversed, memo, iterator, callback);
287 + };
288 + // foldr alias
289 + async.foldr = async.reduceRight;
290 +
291 + var _filter = function (eachfn, arr, iterator, callback) {
292 + var results = [];
293 + arr = _map(arr, function (x, i) {
294 + return {index: i, value: x};
295 + });
296 + eachfn(arr, function (x, callback) {
297 + iterator(x.value, function (v) {
298 + if (v) {
299 + results.push(x);
300 + }
301 + callback();
302 + });
303 + }, function (err) {
304 + callback(_map(results.sort(function (a, b) {
305 + return a.index - b.index;
306 + }), function (x) {
307 + return x.value;
308 + }));
309 + });
310 + };
311 + async.filter = doParallel(_filter);
312 + async.filterSeries = doSeries(_filter);
313 + // select alias
314 + async.select = async.filter;
315 + async.selectSeries = async.filterSeries;
316 +
317 + var _reject = function (eachfn, arr, iterator, callback) {
318 + var results = [];
319 + arr = _map(arr, function (x, i) {
320 + return {index: i, value: x};
321 + });
322 + eachfn(arr, function (x, callback) {
323 + iterator(x.value, function (v) {
324 + if (!v) {
325 + results.push(x);
326 + }
327 + callback();
328 + });
329 + }, function (err) {
330 + callback(_map(results.sort(function (a, b) {
331 + return a.index - b.index;
332 + }), function (x) {
333 + return x.value;
334 + }));
335 + });
336 + };
337 + async.reject = doParallel(_reject);
338 + async.rejectSeries = doSeries(_reject);
339 +
340 + var _detect = function (eachfn, arr, iterator, main_callback) {
341 + eachfn(arr, function (x, callback) {
342 + iterator(x, function (result) {
343 + if (result) {
344 + main_callback(x);
345 + main_callback = function () {};
346 + }
347 + else {
348 + callback();
349 + }
350 + });
351 + }, function (err) {
352 + main_callback();
353 + });
354 + };
355 + async.detect = doParallel(_detect);
356 + async.detectSeries = doSeries(_detect);
357 +
358 + async.some = function (arr, iterator, main_callback) {
359 + async.each(arr, function (x, callback) {
360 + iterator(x, function (v) {
361 + if (v) {
362 + main_callback(true);
363 + main_callback = function () {};
364 + }
365 + callback();
366 + });
367 + }, function (err) {
368 + main_callback(false);
369 + });
370 + };
371 + // any alias
372 + async.any = async.some;
373 +
374 + async.every = function (arr, iterator, main_callback) {
375 + async.each(arr, function (x, callback) {
376 + iterator(x, function (v) {
377 + if (!v) {
378 + main_callback(false);
379 + main_callback = function () {};
380 + }
381 + callback();
382 + });
383 + }, function (err) {
384 + main_callback(true);
385 + });
386 + };
387 + // all alias
388 + async.all = async.every;
389 +
390 + async.sortBy = function (arr, iterator, callback) {
391 + async.map(arr, function (x, callback) {
392 + iterator(x, function (err, criteria) {
393 + if (err) {
394 + callback(err);
395 + }
396 + else {
397 + callback(null, {value: x, criteria: criteria});
398 + }
399 + });
400 + }, function (err, results) {
401 + if (err) {
402 + return callback(err);
403 + }
404 + else {
405 + var fn = function (left, right) {
406 + var a = left.criteria, b = right.criteria;
407 + return a < b ? -1 : a > b ? 1 : 0;
408 + };
409 + callback(null, _map(results.sort(fn), function (x) {
410 + return x.value;
411 + }));
412 + }
413 + });
414 + };
415 +
416 + async.auto = function (tasks, callback) {
417 + callback = callback || function () {};
418 + var keys = _keys(tasks);
419 + var remainingTasks = keys.length
420 + if (!remainingTasks) {
421 + return callback();
422 + }
423 +
424 + var results = {};
425 +
426 + var listeners = [];
427 + var addListener = function (fn) {
428 + listeners.unshift(fn);
429 + };
430 + var removeListener = function (fn) {
431 + for (var i = 0; i < listeners.length; i += 1) {
432 + if (listeners[i] === fn) {
433 + listeners.splice(i, 1);
434 + return;
435 + }
436 + }
437 + };
438 + var taskComplete = function () {
439 + remainingTasks--
440 + _each(listeners.slice(0), function (fn) {
441 + fn();
442 + });
443 + };
444 +
445 + addListener(function () {
446 + if (!remainingTasks) {
447 + var theCallback = callback;
448 + // prevent final callback from calling itself if it errors
449 + callback = function () {};
450 +
451 + theCallback(null, results);
452 + }
453 + });
454 +
455 + _each(keys, function (k) {
456 + var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]];
457 + var taskCallback = function (err) {
458 + var args = Array.prototype.slice.call(arguments, 1);
459 + if (args.length <= 1) {
460 + args = args[0];
461 + }
462 + if (err) {
463 + var safeResults = {};
464 + _each(_keys(results), function(rkey) {
465 + safeResults[rkey] = results[rkey];
466 + });
467 + safeResults[k] = args;
468 + callback(err, safeResults);
469 + // stop subsequent errors hitting callback multiple times
470 + callback = function () {};
471 + }
472 + else {
473 + results[k] = args;
474 + async.setImmediate(taskComplete);
475 + }
476 + };
477 + var requires = task.slice(0, Math.abs(task.length - 1)) || [];
478 + var ready = function () {
479 + return _reduce(requires, function (a, x) {
480 + return (a && results.hasOwnProperty(x));
481 + }, true) && !results.hasOwnProperty(k);
482 + };
483 + if (ready()) {
484 + task[task.length - 1](taskCallback, results);
485 + }
486 + else {
487 + var listener = function () {
488 + if (ready()) {
489 + removeListener(listener);
490 + task[task.length - 1](taskCallback, results);
491 + }
492 + };
493 + addListener(listener);
494 + }
495 + });
496 + };
497 +
498 + async.retry = function(times, task, callback) {
499 + var DEFAULT_TIMES = 5;
500 + var attempts = [];
501 + // Use defaults if times not passed
502 + if (typeof times === 'function') {
503 + callback = task;
504 + task = times;
505 + times = DEFAULT_TIMES;
506 + }
507 + // Make sure times is a number
508 + times = parseInt(times, 10) || DEFAULT_TIMES;
509 + var wrappedTask = function(wrappedCallback, wrappedResults) {
510 + var retryAttempt = function(task, finalAttempt) {
511 + return function(seriesCallback) {
512 + task(function(err, result){
513 + seriesCallback(!err || finalAttempt, {err: err, result: result});
514 + }, wrappedResults);
515 + };
516 + };
517 + while (times) {
518 + attempts.push(retryAttempt(task, !(times-=1)));
519 + }
520 + async.series(attempts, function(done, data){
521 + data = data[data.length - 1];
522 + (wrappedCallback || callback)(data.err, data.result);
523 + });
524 + }
525 + // If a callback is passed, run this as a controll flow
526 + return callback ? wrappedTask() : wrappedTask
527 + };
528 +
529 + async.waterfall = function (tasks, callback) {
530 + callback = callback || function () {};
531 + if (!_isArray(tasks)) {
532 + var err = new Error('First argument to waterfall must be an array of functions');
533 + return callback(err);
534 + }
535 + if (!tasks.length) {
536 + return callback();
537 + }
538 + var wrapIterator = function (iterator) {
539 + return function (err) {
540 + if (err) {
541 + callback.apply(null, arguments);
542 + callback = function () {};
543 + }
544 + else {
545 + var args = Array.prototype.slice.call(arguments, 1);
546 + var next = iterator.next();
547 + if (next) {
548 + args.push(wrapIterator(next));
549 + }
550 + else {
551 + args.push(callback);
552 + }
553 + async.setImmediate(function () {
554 + iterator.apply(null, args);
555 + });
556 + }
557 + };
558 + };
559 + wrapIterator(async.iterator(tasks))();
560 + };
561 +
562 + var _parallel = function(eachfn, tasks, callback) {
563 + callback = callback || function () {};
564 + if (_isArray(tasks)) {
565 + eachfn.map(tasks, function (fn, callback) {
566 + if (fn) {
567 + fn(function (err) {
568 + var args = Array.prototype.slice.call(arguments, 1);
569 + if (args.length <= 1) {
570 + args = args[0];
571 + }
572 + callback.call(null, err, args);
573 + });
574 + }
575 + }, callback);
576 + }
577 + else {
578 + var results = {};
579 + eachfn.each(_keys(tasks), function (k, callback) {
580 + tasks[k](function (err) {
581 + var args = Array.prototype.slice.call(arguments, 1);
582 + if (args.length <= 1) {
583 + args = args[0];
584 + }
585 + results[k] = args;
586 + callback(err);
587 + });
588 + }, function (err) {
589 + callback(err, results);
590 + });
591 + }
592 + };
593 +
594 + async.parallel = function (tasks, callback) {
595 + _parallel({ map: async.map, each: async.each }, tasks, callback);
596 + };
597 +
598 + async.parallelLimit = function(tasks, limit, callback) {
599 + _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback);
600 + };
601 +
602 + async.series = function (tasks, callback) {
603 + callback = callback || function () {};
604 + if (_isArray(tasks)) {
605 + async.mapSeries(tasks, function (fn, callback) {
606 + if (fn) {
607 + fn(function (err) {
608 + var args = Array.prototype.slice.call(arguments, 1);
609 + if (args.length <= 1) {
610 + args = args[0];
611 + }
612 + callback.call(null, err, args);
613 + });
614 + }
615 + }, callback);
616 + }
617 + else {
618 + var results = {};
619 + async.eachSeries(_keys(tasks), function (k, callback) {
620 + tasks[k](function (err) {
621 + var args = Array.prototype.slice.call(arguments, 1);
622 + if (args.length <= 1) {
623 + args = args[0];
624 + }
625 + results[k] = args;
626 + callback(err);
627 + });
628 + }, function (err) {
629 + callback(err, results);
630 + });
631 + }
632 + };
633 +
634 + async.iterator = function (tasks) {
635 + var makeCallback = function (index) {
636 + var fn = function () {
637 + if (tasks.length) {
638 + tasks[index].apply(null, arguments);
639 + }
640 + return fn.next();
641 + };
642 + fn.next = function () {
643 + return (index < tasks.length - 1) ? makeCallback(index + 1): null;
644 + };
645 + return fn;
646 + };
647 + return makeCallback(0);
648 + };
649 +
650 + async.apply = function (fn) {
651 + var args = Array.prototype.slice.call(arguments, 1);
652 + return function () {
653 + return fn.apply(
654 + null, args.concat(Array.prototype.slice.call(arguments))
655 + );
656 + };
657 + };
658 +
659 + var _concat = function (eachfn, arr, fn, callback) {
660 + var r = [];
661 + eachfn(arr, function (x, cb) {
662 + fn(x, function (err, y) {
663 + r = r.concat(y || []);
664 + cb(err);
665 + });
666 + }, function (err) {
667 + callback(err, r);
668 + });
669 + };
670 + async.concat = doParallel(_concat);
671 + async.concatSeries = doSeries(_concat);
672 +
673 + async.whilst = function (test, iterator, callback) {
674 + if (test()) {
675 + iterator(function (err) {
676 + if (err) {
677 + return callback(err);
678 + }
679 + async.whilst(test, iterator, callback);
680 + });
681 + }
682 + else {
683 + callback();
684 + }
685 + };
686 +
687 + async.doWhilst = function (iterator, test, callback) {
688 + iterator(function (err) {
689 + if (err) {
690 + return callback(err);
691 + }
692 + var args = Array.prototype.slice.call(arguments, 1);
693 + if (test.apply(null, args)) {
694 + async.doWhilst(iterator, test, callback);
695 + }
696 + else {
697 + callback();
698 + }
699 + });
700 + };
701 +
702 + async.until = function (test, iterator, callback) {
703 + if (!test()) {
704 + iterator(function (err) {
705 + if (err) {
706 + return callback(err);
707 + }
708 + async.until(test, iterator, callback);
709 + });
710 + }
711 + else {
712 + callback();
713 + }
714 + };
715 +
716 + async.doUntil = function (iterator, test, callback) {
717 + iterator(function (err) {
718 + if (err) {
719 + return callback(err);
720 + }
721 + var args = Array.prototype.slice.call(arguments, 1);
722 + if (!test.apply(null, args)) {
723 + async.doUntil(iterator, test, callback);
724 + }
725 + else {
726 + callback();
727 + }
728 + });
729 + };
730 +
731 + async.queue = function (worker, concurrency) {
732 + if (concurrency === undefined) {
733 + concurrency = 1;
734 + }
735 + function _insert(q, data, pos, callback) {
736 + if (!q.started){
737 + q.started = true;
738 + }
739 + if (!_isArray(data)) {
740 + data = [data];
741 + }
742 + if(data.length == 0) {
743 + // call drain immediately if there are no tasks
744 + return async.setImmediate(function() {
745 + if (q.drain) {
746 + q.drain();
747 + }
748 + });
749 + }
750 + _each(data, function(task) {
751 + var item = {
752 + data: task,
753 + callback: typeof callback === 'function' ? callback : null
754 + };
755 +
756 + if (pos) {
757 + q.tasks.unshift(item);
758 + } else {
759 + q.tasks.push(item);
760 + }
761 +
762 + if (q.saturated && q.tasks.length === q.concurrency) {
763 + q.saturated();
764 + }
765 + async.setImmediate(q.process);
766 + });
767 + }
768 +
769 + var workers = 0;
770 + var q = {
771 + tasks: [],
772 + concurrency: concurrency,
773 + saturated: null,
774 + empty: null,
775 + drain: null,
776 + started: false,
777 + paused: false,
778 + push: function (data, callback) {
779 + _insert(q, data, false, callback);
780 + },
781 + kill: function () {
782 + q.drain = null;
783 + q.tasks = [];
784 + },
785 + unshift: function (data, callback) {
786 + _insert(q, data, true, callback);
787 + },
788 + process: function () {
789 + if (!q.paused && workers < q.concurrency && q.tasks.length) {
790 + var task = q.tasks.shift();
791 + if (q.empty && q.tasks.length === 0) {
792 + q.empty();
793 + }
794 + workers += 1;
795 + var next = function () {
796 + workers -= 1;
797 + if (task.callback) {
798 + task.callback.apply(task, arguments);
799 + }
800 + if (q.drain && q.tasks.length + workers === 0) {
801 + q.drain();
802 + }
803 + q.process();
804 + };
805 + var cb = only_once(next);
806 + worker(task.data, cb);
807 + }
808 + },
809 + length: function () {
810 + return q.tasks.length;
811 + },
812 + running: function () {
813 + return workers;
814 + },
815 + idle: function() {
816 + return q.tasks.length + workers === 0;
817 + },
818 + pause: function () {
819 + if (q.paused === true) { return; }
820 + q.paused = true;
821 + },
822 + resume: function () {
823 + if (q.paused === false) { return; }
824 + q.paused = false;
825 + // Need to call q.process once per concurrent
826 + // worker to preserve full concurrency after pause
827 + for (var w = 1; w <= q.concurrency; w++) {
828 + async.setImmediate(q.process);
829 + }
830 + }
831 + };
832 + return q;
833 + };
834 +
835 + async.priorityQueue = function (worker, concurrency) {
836 +
837 + function _compareTasks(a, b){
838 + return a.priority - b.priority;
839 + };
840 +
841 + function _binarySearch(sequence, item, compare) {
842 + var beg = -1,
843 + end = sequence.length - 1;
844 + while (beg < end) {
845 + var mid = beg + ((end - beg + 1) >>> 1);
846 + if (compare(item, sequence[mid]) >= 0) {
847 + beg = mid;
848 + } else {
849 + end = mid - 1;
850 + }
851 + }
852 + return beg;
853 + }
854 +
855 + function _insert(q, data, priority, callback) {
856 + if (!q.started){
857 + q.started = true;
858 + }
859 + if (!_isArray(data)) {
860 + data = [data];
861 + }
862 + if(data.length == 0) {
863 + // call drain immediately if there are no tasks
864 + return async.setImmediate(function() {
865 + if (q.drain) {
866 + q.drain();
867 + }
868 + });
869 + }
870 + _each(data, function(task) {
871 + var item = {
872 + data: task,
873 + priority: priority,
874 + callback: typeof callback === 'function' ? callback : null
875 + };
876 +
877 + q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item);
878 +
879 + if (q.saturated && q.tasks.length === q.concurrency) {
880 + q.saturated();
881 + }
882 + async.setImmediate(q.process);
883 + });
884 + }
885 +
886 + // Start with a normal queue
887 + var q = async.queue(worker, concurrency);
888 +
889 + // Override push to accept second parameter representing priority
890 + q.push = function (data, priority, callback) {
891 + _insert(q, data, priority, callback);
892 + };
893 +
894 + // Remove unshift function
895 + delete q.unshift;
896 +
897 + return q;
898 + };
899 +
900 + async.cargo = function (worker, payload) {
901 + var working = false,
902 + tasks = [];
903 +
904 + var cargo = {
905 + tasks: tasks,
906 + payload: payload,
907 + saturated: null,
908 + empty: null,
909 + drain: null,
910 + drained: true,
911 + push: function (data, callback) {
912 + if (!_isArray(data)) {
913 + data = [data];
914 + }
915 + _each(data, function(task) {
916 + tasks.push({
917 + data: task,
918 + callback: typeof callback === 'function' ? callback : null
919 + });
920 + cargo.drained = false;
921 + if (cargo.saturated && tasks.length === payload) {
922 + cargo.saturated();
923 + }
924 + });
925 + async.setImmediate(cargo.process);
926 + },
927 + process: function process() {
928 + if (working) return;
929 + if (tasks.length === 0) {
930 + if(cargo.drain && !cargo.drained) cargo.drain();
931 + cargo.drained = true;
932 + return;
933 + }
934 +
935 + var ts = typeof payload === 'number'
936 + ? tasks.splice(0, payload)
937 + : tasks.splice(0, tasks.length);
938 +
939 + var ds = _map(ts, function (task) {
940 + return task.data;
941 + });
942 +
943 + if(cargo.empty) cargo.empty();
944 + working = true;
945 + worker(ds, function () {
946 + working = false;
947 +
948 + var args = arguments;
949 + _each(ts, function (data) {
950 + if (data.callback) {
951 + data.callback.apply(null, args);
952 + }
953 + });
954 +
955 + process();
956 + });
957 + },
958 + length: function () {
959 + return tasks.length;
960 + },
961 + running: function () {
962 + return working;
963 + }
964 + };
965 + return cargo;
966 + };
967 +
968 + var _console_fn = function (name) {
969 + return function (fn) {
970 + var args = Array.prototype.slice.call(arguments, 1);
971 + fn.apply(null, args.concat([function (err) {
972 + var args = Array.prototype.slice.call(arguments, 1);
973 + if (typeof console !== 'undefined') {
974 + if (err) {
975 + if (console.error) {
976 + console.error(err);
977 + }
978 + }
979 + else if (console[name]) {
980 + _each(args, function (x) {
981 + console[name](x);
982 + });
983 + }
984 + }
985 + }]));
986 + };
987 + };
988 + async.log = _console_fn('log');
989 + async.dir = _console_fn('dir');
990 + /*async.info = _console_fn('info');
991 + async.warn = _console_fn('warn');
992 + async.error = _console_fn('error');*/
993 +
994 + async.memoize = function (fn, hasher) {
995 + var memo = {};
996 + var queues = {};
997 + hasher = hasher || function (x) {
998 + return x;
999 + };
1000 + var memoized = function () {
1001 + var args = Array.prototype.slice.call(arguments);
1002 + var callback = args.pop();
1003 + var key = hasher.apply(null, args);
1004 + if (key in memo) {
1005 + async.nextTick(function () {
1006 + callback.apply(null, memo[key]);
1007 + });
1008 + }
1009 + else if (key in queues) {
1010 + queues[key].push(callback);
1011 + }
1012 + else {
1013 + queues[key] = [callback];
1014 + fn.apply(null, args.concat([function () {
1015 + memo[key] = arguments;
1016 + var q = queues[key];
1017 + delete queues[key];
1018 + for (var i = 0, l = q.length; i < l; i++) {
1019 + q[i].apply(null, arguments);
1020 + }
1021 + }]));
1022 + }
1023 + };
1024 + memoized.memo = memo;
1025 + memoized.unmemoized = fn;
1026 + return memoized;
1027 + };
1028 +
1029 + async.unmemoize = function (fn) {
1030 + return function () {
1031 + return (fn.unmemoized || fn).apply(null, arguments);
1032 + };
1033 + };
1034 +
1035 + async.times = function (count, iterator, callback) {
1036 + var counter = [];
1037 + for (var i = 0; i < count; i++) {
1038 + counter.push(i);
1039 + }
1040 + return async.map(counter, iterator, callback);
1041 + };
1042 +
1043 + async.timesSeries = function (count, iterator, callback) {
1044 + var counter = [];
1045 + for (var i = 0; i < count; i++) {
1046 + counter.push(i);
1047 + }
1048 + return async.mapSeries(counter, iterator, callback);
1049 + };
1050 +
1051 + async.seq = function (/* functions... */) {
1052 + var fns = arguments;
1053 + return function () {
1054 + var that = this;
1055 + var args = Array.prototype.slice.call(arguments);
1056 + var callback = args.pop();
1057 + async.reduce(fns, args, function (newargs, fn, cb) {
1058 + fn.apply(that, newargs.concat([function () {
1059 + var err = arguments[0];
1060 + var nextargs = Array.prototype.slice.call(arguments, 1);
1061 + cb(err, nextargs);
1062 + }]))
1063 + },
1064 + function (err, results) {
1065 + callback.apply(that, [err].concat(results));
1066 + });
1067 + };
1068 + };
1069 +
1070 + async.compose = function (/* functions... */) {
1071 + return async.seq.apply(null, Array.prototype.reverse.call(arguments));
1072 + };
1073 +
1074 + var _applyEach = function (eachfn, fns /*args...*/) {
1075 + var go = function () {
1076 + var that = this;
1077 + var args = Array.prototype.slice.call(arguments);
1078 + var callback = args.pop();
1079 + return eachfn(fns, function (fn, cb) {
1080 + fn.apply(that, args.concat([cb]));
1081 + },
1082 + callback);
1083 + };
1084 + if (arguments.length > 2) {
1085 + var args = Array.prototype.slice.call(arguments, 2);
1086 + return go.apply(this, args);
1087 + }
1088 + else {
1089 + return go;
1090 + }
1091 + };
1092 + async.applyEach = doParallel(_applyEach);
1093 + async.applyEachSeries = doSeries(_applyEach);
1094 +
1095 + async.forever = function (fn, callback) {
1096 + function next(err) {
1097 + if (err) {
1098 + if (callback) {
1099 + return callback(err);
1100 + }
1101 + throw err;
1102 + }
1103 + fn(next);
1104 + }
1105 + next();
1106 + };
1107 +
1108 + // Node.js
1109 + if (typeof module !== 'undefined' && module.exports) {
1110 + module.exports = async;
1111 + }
1112 + // AMD / RequireJS
1113 + else if (typeof define !== 'undefined' && define.amd) {
1114 + define([], function () {
1115 + return async;
1116 + });
1117 + }
1118 + // included directly via <script> tag
1119 + else {
1120 + root.async = async;
1121 + }
1122 +
1123 +}());
1 +{
2 + "name": "async",
3 + "description": "Higher-order functions and common patterns for asynchronous code",
4 + "main": "lib/async.js",
5 + "author": "Caolan McMahon",
6 + "version": "0.9.2",
7 + "keywords": [
8 + "async",
9 + "callback",
10 + "utility",
11 + "module"
12 + ],
13 + "repository": {
14 + "type": "git",
15 + "url": "https://github.com/caolan/async.git"
16 + },
17 + "bugs": {
18 + "url": "https://github.com/caolan/async/issues"
19 + },
20 + "license": "MIT",
21 + "devDependencies": {
22 + "nodeunit": ">0.0.0",
23 + "uglify-js": "1.2.x",
24 + "nodelint": ">0.0.0",
25 + "lodash": ">=2.4.1"
26 + },
27 + "jam": {
28 + "main": "lib/async.js",
29 + "include": [
30 + "lib/async.js",
31 + "README.md",
32 + "LICENSE"
33 + ],
34 + "categories": [
35 + "Utilities"
36 + ]
37 + },
38 + "scripts": {
39 + "test": "nodeunit test/test-async.js"
40 + },
41 + "spm": {
42 + "main": "lib/async.js"
43 + },
44 + "volo": {
45 + "main": "lib/async.js",
46 + "ignore": [
47 + "**/.*",
48 + "node_modules",
49 + "bower_components",
50 + "test",
51 + "tests"
52 + ]
53 + }
54 +}
...\ No newline at end of file ...\ No newline at end of file
1 +#!/usr/bin/env node
2 +
3 +// This should probably be its own module but complaints about bower/etc.
4 +// support keep coming up and I'd rather just enable the workflow here for now
5 +// and figure out where this should live later. -- @beaugunderson
6 +
7 +var fs = require('fs');
8 +var _ = require('lodash');
9 +
10 +var packageJson = require('../package.json');
11 +
12 +var IGNORES = ['**/.*', 'node_modules', 'bower_components', 'test', 'tests'];
13 +var INCLUDES = ['lib/async.js', 'README.md', 'LICENSE'];
14 +var REPOSITORY_NAME = 'caolan/async';
15 +
16 +packageJson.jam = {
17 + main: packageJson.main,
18 + include: INCLUDES,
19 + categories: ['Utilities']
20 +};
21 +
22 +packageJson.spm = {
23 + main: packageJson.main
24 +};
25 +
26 +packageJson.volo = {
27 + main: packageJson.main,
28 + ignore: IGNORES
29 +};
30 +
31 +var bowerSpecific = {
32 + moduleType: ['amd', 'globals', 'node'],
33 + ignore: IGNORES,
34 + authors: [packageJson.author]
35 +};
36 +
37 +var bowerInclude = ['name', 'description', 'version', 'main', 'keywords',
38 + 'license', 'homepage', 'repository', 'devDependencies'];
39 +
40 +var componentSpecific = {
41 + repository: REPOSITORY_NAME,
42 + scripts: [packageJson.main]
43 +};
44 +
45 +var componentInclude = ['name', 'description', 'version', 'keywords',
46 + 'license'];
47 +
48 +var bowerJson = _.merge({}, _.pick(packageJson, bowerInclude), bowerSpecific);
49 +var componentJson = _.merge({}, _.pick(packageJson, componentInclude), componentSpecific);
50 +
51 +fs.writeFileSync('./bower.json', JSON.stringify(bowerJson, null, 2));
52 +fs.writeFileSync('./component.json', JSON.stringify(componentJson, null, 2));
53 +fs.writeFileSync('./package.json', JSON.stringify(packageJson, null, 2));
1 +tidelift: "npm/balanced-match"
2 +patreon: juliangruber
1 +(MIT)
2 +
3 +Copyright (c) 2013 Julian Gruber &lt;julian@juliangruber.com&gt;
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy of
6 +this software and associated documentation files (the "Software"), to deal in
7 +the Software without restriction, including without limitation the rights to
8 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 +of the Software, and to permit persons to whom the Software is furnished to do
10 +so, subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in all
13 +copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 +SOFTWARE.
1 +# balanced-match
2 +
3 +Match balanced string pairs, like `{` and `}` or `<b>` and `</b>`. Supports regular expressions as well!
4 +
5 +[![build status](https://secure.travis-ci.org/juliangruber/balanced-match.svg)](http://travis-ci.org/juliangruber/balanced-match)
6 +[![downloads](https://img.shields.io/npm/dm/balanced-match.svg)](https://www.npmjs.org/package/balanced-match)
7 +
8 +[![testling badge](https://ci.testling.com/juliangruber/balanced-match.png)](https://ci.testling.com/juliangruber/balanced-match)
9 +
10 +## Example
11 +
12 +Get the first matching pair of braces:
13 +
14 +```js
15 +var balanced = require('balanced-match');
16 +
17 +console.log(balanced('{', '}', 'pre{in{nested}}post'));
18 +console.log(balanced('{', '}', 'pre{first}between{second}post'));
19 +console.log(balanced(/\s+\{\s+/, /\s+\}\s+/, 'pre { in{nest} } post'));
20 +```
21 +
22 +The matches are:
23 +
24 +```bash
25 +$ node example.js
26 +{ start: 3, end: 14, pre: 'pre', body: 'in{nested}', post: 'post' }
27 +{ start: 3,
28 + end: 9,
29 + pre: 'pre',
30 + body: 'first',
31 + post: 'between{second}post' }
32 +{ start: 3, end: 17, pre: 'pre', body: 'in{nest}', post: 'post' }
33 +```
34 +
35 +## API
36 +
37 +### var m = balanced(a, b, str)
38 +
39 +For the first non-nested matching pair of `a` and `b` in `str`, return an
40 +object with those keys:
41 +
42 +* **start** the index of the first match of `a`
43 +* **end** the index of the matching `b`
44 +* **pre** the preamble, `a` and `b` not included
45 +* **body** the match, `a` and `b` not included
46 +* **post** the postscript, `a` and `b` not included
47 +
48 +If there's no match, `undefined` will be returned.
49 +
50 +If the `str` contains more `a` than `b` / there are unmatched pairs, the first match that was closed will be used. For example, `{{a}` will match `['{', 'a', '']` and `{a}}` will match `['', 'a', '}']`.
51 +
52 +### var r = balanced.range(a, b, str)
53 +
54 +For the first non-nested matching pair of `a` and `b` in `str`, return an
55 +array with indexes: `[ <a index>, <b index> ]`.
56 +
57 +If there's no match, `undefined` will be returned.
58 +
59 +If the `str` contains more `a` than `b` / there are unmatched pairs, the first match that was closed will be used. For example, `{{a}` will match `[ 1, 3 ]` and `{a}}` will match `[0, 2]`.
60 +
61 +## Installation
62 +
63 +With [npm](https://npmjs.org) do:
64 +
65 +```bash
66 +npm install balanced-match
67 +```
68 +
69 +## Security contact information
70 +
71 +To report a security vulnerability, please use the
72 +[Tidelift security contact](https://tidelift.com/security).
73 +Tidelift will coordinate the fix and disclosure.
74 +
75 +## License
76 +
77 +(MIT)
78 +
79 +Copyright (c) 2013 Julian Gruber &lt;julian@juliangruber.com&gt;
80 +
81 +Permission is hereby granted, free of charge, to any person obtaining a copy of
82 +this software and associated documentation files (the "Software"), to deal in
83 +the Software without restriction, including without limitation the rights to
84 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
85 +of the Software, and to permit persons to whom the Software is furnished to do
86 +so, subject to the following conditions:
87 +
88 +The above copyright notice and this permission notice shall be included in all
89 +copies or substantial portions of the Software.
90 +
91 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
92 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
93 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
94 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
95 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
96 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
97 +SOFTWARE.
1 +'use strict';
2 +module.exports = balanced;
3 +function balanced(a, b, str) {
4 + if (a instanceof RegExp) a = maybeMatch(a, str);
5 + if (b instanceof RegExp) b = maybeMatch(b, str);
6 +
7 + var r = range(a, b, str);
8 +
9 + return r && {
10 + start: r[0],
11 + end: r[1],
12 + pre: str.slice(0, r[0]),
13 + body: str.slice(r[0] + a.length, r[1]),
14 + post: str.slice(r[1] + b.length)
15 + };
16 +}
17 +
18 +function maybeMatch(reg, str) {
19 + var m = str.match(reg);
20 + return m ? m[0] : null;
21 +}
22 +
23 +balanced.range = range;
24 +function range(a, b, str) {
25 + var begs, beg, left, right, result;
26 + var ai = str.indexOf(a);
27 + var bi = str.indexOf(b, ai + 1);
28 + var i = ai;
29 +
30 + if (ai >= 0 && bi > 0) {
31 + if(a===b) {
32 + return [ai, bi];
33 + }
34 + begs = [];
35 + left = str.length;
36 +
37 + while (i >= 0 && !result) {
38 + if (i == ai) {
39 + begs.push(i);
40 + ai = str.indexOf(a, i + 1);
41 + } else if (begs.length == 1) {
42 + result = [ begs.pop(), bi ];
43 + } else {
44 + beg = begs.pop();
45 + if (beg < left) {
46 + left = beg;
47 + right = bi;
48 + }
49 +
50 + bi = str.indexOf(b, i + 1);
51 + }
52 +
53 + i = ai < bi && ai >= 0 ? ai : bi;
54 + }
55 +
56 + if (begs.length) {
57 + result = [ left, right ];
58 + }
59 + }
60 +
61 + return result;
62 +}
1 +{
2 + "name": "balanced-match",
3 + "description": "Match balanced character pairs, like \"{\" and \"}\"",
4 + "version": "1.0.2",
5 + "repository": {
6 + "type": "git",
7 + "url": "git://github.com/juliangruber/balanced-match.git"
8 + },
9 + "homepage": "https://github.com/juliangruber/balanced-match",
10 + "main": "index.js",
11 + "scripts": {
12 + "test": "tape test/test.js",
13 + "bench": "matcha test/bench.js"
14 + },
15 + "devDependencies": {
16 + "matcha": "^0.7.0",
17 + "tape": "^4.6.0"
18 + },
19 + "keywords": [
20 + "match",
21 + "regexp",
22 + "test",
23 + "balanced",
24 + "parse"
25 + ],
26 + "author": {
27 + "name": "Julian Gruber",
28 + "email": "mail@juliangruber.com",
29 + "url": "http://juliangruber.com"
30 + },
31 + "license": "MIT",
32 + "testling": {
33 + "files": "test/*.js",
34 + "browsers": [
35 + "ie/8..latest",
36 + "firefox/20..latest",
37 + "firefox/nightly",
38 + "chrome/25..latest",
39 + "chrome/canary",
40 + "opera/12..latest",
41 + "opera/next",
42 + "safari/5.1..latest",
43 + "ipad/6.0..latest",
44 + "iphone/6.0..latest",
45 + "android-browser/4.2..latest"
46 + ]
47 + }
48 +}
1 +MIT License
2 +
3 +Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy
6 +of this software and associated documentation files (the "Software"), to deal
7 +in the Software without restriction, including without limitation the rights
8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 +copies of the Software, and to permit persons to whom the Software is
10 +furnished to do so, subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in all
13 +copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 +SOFTWARE.
1 +# brace-expansion
2 +
3 +[Brace expansion](https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html),
4 +as known from sh/bash, in JavaScript.
5 +
6 +[![build status](https://secure.travis-ci.org/juliangruber/brace-expansion.svg)](http://travis-ci.org/juliangruber/brace-expansion)
7 +[![downloads](https://img.shields.io/npm/dm/brace-expansion.svg)](https://www.npmjs.org/package/brace-expansion)
8 +[![Greenkeeper badge](https://badges.greenkeeper.io/juliangruber/brace-expansion.svg)](https://greenkeeper.io/)
9 +
10 +[![testling badge](https://ci.testling.com/juliangruber/brace-expansion.png)](https://ci.testling.com/juliangruber/brace-expansion)
11 +
12 +## Example
13 +
14 +```js
15 +var expand = require('brace-expansion');
16 +
17 +expand('file-{a,b,c}.jpg')
18 +// => ['file-a.jpg', 'file-b.jpg', 'file-c.jpg']
19 +
20 +expand('-v{,,}')
21 +// => ['-v', '-v', '-v']
22 +
23 +expand('file{0..2}.jpg')
24 +// => ['file0.jpg', 'file1.jpg', 'file2.jpg']
25 +
26 +expand('file-{a..c}.jpg')
27 +// => ['file-a.jpg', 'file-b.jpg', 'file-c.jpg']
28 +
29 +expand('file{2..0}.jpg')
30 +// => ['file2.jpg', 'file1.jpg', 'file0.jpg']
31 +
32 +expand('file{0..4..2}.jpg')
33 +// => ['file0.jpg', 'file2.jpg', 'file4.jpg']
34 +
35 +expand('file-{a..e..2}.jpg')
36 +// => ['file-a.jpg', 'file-c.jpg', 'file-e.jpg']
37 +
38 +expand('file{00..10..5}.jpg')
39 +// => ['file00.jpg', 'file05.jpg', 'file10.jpg']
40 +
41 +expand('{{A..C},{a..c}}')
42 +// => ['A', 'B', 'C', 'a', 'b', 'c']
43 +
44 +expand('ppp{,config,oe{,conf}}')
45 +// => ['ppp', 'pppconfig', 'pppoe', 'pppoeconf']
46 +```
47 +
48 +## API
49 +
50 +```js
51 +var expand = require('brace-expansion');
52 +```
53 +
54 +### var expanded = expand(str)
55 +
56 +Return an array of all possible and valid expansions of `str`. If none are
57 +found, `[str]` is returned.
58 +
59 +Valid expansions are:
60 +
61 +```js
62 +/^(.*,)+(.+)?$/
63 +// {a,b,...}
64 +```
65 +
66 +A comma separated list of options, like `{a,b}` or `{a,{b,c}}` or `{,a,}`.
67 +
68 +```js
69 +/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/
70 +// {x..y[..incr]}
71 +```
72 +
73 +A numeric sequence from `x` to `y` inclusive, with optional increment.
74 +If `x` or `y` start with a leading `0`, all the numbers will be padded
75 +to have equal length. Negative numbers and backwards iteration work too.
76 +
77 +```js
78 +/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/
79 +// {x..y[..incr]}
80 +```
81 +
82 +An alphabetic sequence from `x` to `y` inclusive, with optional increment.
83 +`x` and `y` must be exactly one character, and if given, `incr` must be a
84 +number.
85 +
86 +For compatibility reasons, the string `${` is not eligible for brace expansion.
87 +
88 +## Installation
89 +
90 +With [npm](https://npmjs.org) do:
91 +
92 +```bash
93 +npm install brace-expansion
94 +```
95 +
96 +## Contributors
97 +
98 +- [Julian Gruber](https://github.com/juliangruber)
99 +- [Isaac Z. Schlueter](https://github.com/isaacs)
100 +
101 +## Sponsors
102 +
103 +This module is proudly supported by my [Sponsors](https://github.com/juliangruber/sponsors)!
104 +
105 +Do you want to support modules like this to improve their quality, stability and weigh in on new features? Then please consider donating to my [Patreon](https://www.patreon.com/juliangruber). Not sure how much of my modules you're using? Try [feross/thanks](https://github.com/feross/thanks)!
106 +
107 +## License
108 +
109 +(MIT)
110 +
111 +Copyright (c) 2013 Julian Gruber &lt;julian@juliangruber.com&gt;
112 +
113 +Permission is hereby granted, free of charge, to any person obtaining a copy of
114 +this software and associated documentation files (the "Software"), to deal in
115 +the Software without restriction, including without limitation the rights to
116 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
117 +of the Software, and to permit persons to whom the Software is furnished to do
118 +so, subject to the following conditions:
119 +
120 +The above copyright notice and this permission notice shall be included in all
121 +copies or substantial portions of the Software.
122 +
123 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
124 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
125 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
126 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
127 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
128 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
129 +SOFTWARE.
1 +var concatMap = require('concat-map');
2 +var balanced = require('balanced-match');
3 +
4 +module.exports = expandTop;
5 +
6 +var escSlash = '\0SLASH'+Math.random()+'\0';
7 +var escOpen = '\0OPEN'+Math.random()+'\0';
8 +var escClose = '\0CLOSE'+Math.random()+'\0';
9 +var escComma = '\0COMMA'+Math.random()+'\0';
10 +var escPeriod = '\0PERIOD'+Math.random()+'\0';
11 +
12 +function numeric(str) {
13 + return parseInt(str, 10) == str
14 + ? parseInt(str, 10)
15 + : str.charCodeAt(0);
16 +}
17 +
18 +function escapeBraces(str) {
19 + return str.split('\\\\').join(escSlash)
20 + .split('\\{').join(escOpen)
21 + .split('\\}').join(escClose)
22 + .split('\\,').join(escComma)
23 + .split('\\.').join(escPeriod);
24 +}
25 +
26 +function unescapeBraces(str) {
27 + return str.split(escSlash).join('\\')
28 + .split(escOpen).join('{')
29 + .split(escClose).join('}')
30 + .split(escComma).join(',')
31 + .split(escPeriod).join('.');
32 +}
33 +
34 +
35 +// Basically just str.split(","), but handling cases
36 +// where we have nested braced sections, which should be
37 +// treated as individual members, like {a,{b,c},d}
38 +function parseCommaParts(str) {
39 + if (!str)
40 + return [''];
41 +
42 + var parts = [];
43 + var m = balanced('{', '}', str);
44 +
45 + if (!m)
46 + return str.split(',');
47 +
48 + var pre = m.pre;
49 + var body = m.body;
50 + var post = m.post;
51 + var p = pre.split(',');
52 +
53 + p[p.length-1] += '{' + body + '}';
54 + var postParts = parseCommaParts(post);
55 + if (post.length) {
56 + p[p.length-1] += postParts.shift();
57 + p.push.apply(p, postParts);
58 + }
59 +
60 + parts.push.apply(parts, p);
61 +
62 + return parts;
63 +}
64 +
65 +function expandTop(str) {
66 + if (!str)
67 + return [];
68 +
69 + // I don't know why Bash 4.3 does this, but it does.
70 + // Anything starting with {} will have the first two bytes preserved
71 + // but *only* at the top level, so {},a}b will not expand to anything,
72 + // but a{},b}c will be expanded to [a}c,abc].
73 + // One could argue that this is a bug in Bash, but since the goal of
74 + // this module is to match Bash's rules, we escape a leading {}
75 + if (str.substr(0, 2) === '{}') {
76 + str = '\\{\\}' + str.substr(2);
77 + }
78 +
79 + return expand(escapeBraces(str), true).map(unescapeBraces);
80 +}
81 +
82 +function identity(e) {
83 + return e;
84 +}
85 +
86 +function embrace(str) {
87 + return '{' + str + '}';
88 +}
89 +function isPadded(el) {
90 + return /^-?0\d/.test(el);
91 +}
92 +
93 +function lte(i, y) {
94 + return i <= y;
95 +}
96 +function gte(i, y) {
97 + return i >= y;
98 +}
99 +
100 +function expand(str, isTop) {
101 + var expansions = [];
102 +
103 + var m = balanced('{', '}', str);
104 + if (!m || /\$$/.test(m.pre)) return [str];
105 +
106 + var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
107 + var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
108 + var isSequence = isNumericSequence || isAlphaSequence;
109 + var isOptions = m.body.indexOf(',') >= 0;
110 + if (!isSequence && !isOptions) {
111 + // {a},b}
112 + if (m.post.match(/,.*\}/)) {
113 + str = m.pre + '{' + m.body + escClose + m.post;
114 + return expand(str);
115 + }
116 + return [str];
117 + }
118 +
119 + var n;
120 + if (isSequence) {
121 + n = m.body.split(/\.\./);
122 + } else {
123 + n = parseCommaParts(m.body);
124 + if (n.length === 1) {
125 + // x{{a,b}}y ==> x{a}y x{b}y
126 + n = expand(n[0], false).map(embrace);
127 + if (n.length === 1) {
128 + var post = m.post.length
129 + ? expand(m.post, false)
130 + : [''];
131 + return post.map(function(p) {
132 + return m.pre + n[0] + p;
133 + });
134 + }
135 + }
136 + }
137 +
138 + // at this point, n is the parts, and we know it's not a comma set
139 + // with a single entry.
140 +
141 + // no need to expand pre, since it is guaranteed to be free of brace-sets
142 + var pre = m.pre;
143 + var post = m.post.length
144 + ? expand(m.post, false)
145 + : [''];
146 +
147 + var N;
148 +
149 + if (isSequence) {
150 + var x = numeric(n[0]);
151 + var y = numeric(n[1]);
152 + var width = Math.max(n[0].length, n[1].length)
153 + var incr = n.length == 3
154 + ? Math.abs(numeric(n[2]))
155 + : 1;
156 + var test = lte;
157 + var reverse = y < x;
158 + if (reverse) {
159 + incr *= -1;
160 + test = gte;
161 + }
162 + var pad = n.some(isPadded);
163 +
164 + N = [];
165 +
166 + for (var i = x; test(i, y); i += incr) {
167 + var c;
168 + if (isAlphaSequence) {
169 + c = String.fromCharCode(i);
170 + if (c === '\\')
171 + c = '';
172 + } else {
173 + c = String(i);
174 + if (pad) {
175 + var need = width - c.length;
176 + if (need > 0) {
177 + var z = new Array(need + 1).join('0');
178 + if (i < 0)
179 + c = '-' + z + c.slice(1);
180 + else
181 + c = z + c;
182 + }
183 + }
184 + }
185 + N.push(c);
186 + }
187 + } else {
188 + N = concatMap(n, function(el) { return expand(el, false) });
189 + }
190 +
191 + for (var j = 0; j < N.length; j++) {
192 + for (var k = 0; k < post.length; k++) {
193 + var expansion = pre + N[j] + post[k];
194 + if (!isTop || isSequence || expansion)
195 + expansions.push(expansion);
196 + }
197 + }
198 +
199 + return expansions;
200 +}
201 +
1 +{
2 + "name": "brace-expansion",
3 + "description": "Brace expansion as known from sh/bash",
4 + "version": "1.1.11",
5 + "repository": {
6 + "type": "git",
7 + "url": "git://github.com/juliangruber/brace-expansion.git"
8 + },
9 + "homepage": "https://github.com/juliangruber/brace-expansion",
10 + "main": "index.js",
11 + "scripts": {
12 + "test": "tape test/*.js",
13 + "gentest": "bash test/generate.sh",
14 + "bench": "matcha test/perf/bench.js"
15 + },
16 + "dependencies": {
17 + "balanced-match": "^1.0.0",
18 + "concat-map": "0.0.1"
19 + },
20 + "devDependencies": {
21 + "matcha": "^0.7.0",
22 + "tape": "^4.6.0"
23 + },
24 + "keywords": [],
25 + "author": {
26 + "name": "Julian Gruber",
27 + "email": "mail@juliangruber.com",
28 + "url": "http://juliangruber.com"
29 + },
30 + "license": "MIT",
31 + "testling": {
32 + "files": "test/*.js",
33 + "browsers": [
34 + "ie/8..latest",
35 + "firefox/20..latest",
36 + "firefox/nightly",
37 + "chrome/25..latest",
38 + "chrome/canary",
39 + "opera/12..latest",
40 + "opera/next",
41 + "safari/5.1..latest",
42 + "ipad/6.0..latest",
43 + "iphone/6.0..latest",
44 + "android-browser/4.2..latest"
45 + ]
46 + }
47 +}
1 +'use strict';
2 +const escapeStringRegexp = require('escape-string-regexp');
3 +const ansiStyles = require('ansi-styles');
4 +const stdoutColor = require('supports-color').stdout;
5 +
6 +const template = require('./templates.js');
7 +
8 +const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm');
9 +
10 +// `supportsColor.level` → `ansiStyles.color[name]` mapping
11 +const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m'];
12 +
13 +// `color-convert` models to exclude from the Chalk API due to conflicts and such
14 +const skipModels = new Set(['gray']);
15 +
16 +const styles = Object.create(null);
17 +
18 +function applyOptions(obj, options) {
19 + options = options || {};
20 +
21 + // Detect level if not set manually
22 + const scLevel = stdoutColor ? stdoutColor.level : 0;
23 + obj.level = options.level === undefined ? scLevel : options.level;
24 + obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0;
25 +}
26 +
27 +function Chalk(options) {
28 + // We check for this.template here since calling `chalk.constructor()`
29 + // by itself will have a `this` of a previously constructed chalk object
30 + if (!this || !(this instanceof Chalk) || this.template) {
31 + const chalk = {};
32 + applyOptions(chalk, options);
33 +
34 + chalk.template = function () {
35 + const args = [].slice.call(arguments);
36 + return chalkTag.apply(null, [chalk.template].concat(args));
37 + };
38 +
39 + Object.setPrototypeOf(chalk, Chalk.prototype);
40 + Object.setPrototypeOf(chalk.template, chalk);
41 +
42 + chalk.template.constructor = Chalk;
43 +
44 + return chalk.template;
45 + }
46 +
47 + applyOptions(this, options);
48 +}
49 +
50 +// Use bright blue on Windows as the normal blue color is illegible
51 +if (isSimpleWindowsTerm) {
52 + ansiStyles.blue.open = '\u001B[94m';
53 +}
54 +
55 +for (const key of Object.keys(ansiStyles)) {
56 + ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g');
57 +
58 + styles[key] = {
59 + get() {
60 + const codes = ansiStyles[key];
61 + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key);
62 + }
63 + };
64 +}
65 +
66 +styles.visible = {
67 + get() {
68 + return build.call(this, this._styles || [], true, 'visible');
69 + }
70 +};
71 +
72 +ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g');
73 +for (const model of Object.keys(ansiStyles.color.ansi)) {
74 + if (skipModels.has(model)) {
75 + continue;
76 + }
77 +
78 + styles[model] = {
79 + get() {
80 + const level = this.level;
81 + return function () {
82 + const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments);
83 + const codes = {
84 + open,
85 + close: ansiStyles.color.close,
86 + closeRe: ansiStyles.color.closeRe
87 + };
88 + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model);
89 + };
90 + }
91 + };
92 +}
93 +
94 +ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g');
95 +for (const model of Object.keys(ansiStyles.bgColor.ansi)) {
96 + if (skipModels.has(model)) {
97 + continue;
98 + }
99 +
100 + const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1);
101 + styles[bgModel] = {
102 + get() {
103 + const level = this.level;
104 + return function () {
105 + const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments);
106 + const codes = {
107 + open,
108 + close: ansiStyles.bgColor.close,
109 + closeRe: ansiStyles.bgColor.closeRe
110 + };
111 + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model);
112 + };
113 + }
114 + };
115 +}
116 +
117 +const proto = Object.defineProperties(() => {}, styles);
118 +
119 +function build(_styles, _empty, key) {
120 + const builder = function () {
121 + return applyStyle.apply(builder, arguments);
122 + };
123 +
124 + builder._styles = _styles;
125 + builder._empty = _empty;
126 +
127 + const self = this;
128 +
129 + Object.defineProperty(builder, 'level', {
130 + enumerable: true,
131 + get() {
132 + return self.level;
133 + },
134 + set(level) {
135 + self.level = level;
136 + }
137 + });
138 +
139 + Object.defineProperty(builder, 'enabled', {
140 + enumerable: true,
141 + get() {
142 + return self.enabled;
143 + },
144 + set(enabled) {
145 + self.enabled = enabled;
146 + }
147 + });
148 +
149 + // See below for fix regarding invisible grey/dim combination on Windows
150 + builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey';
151 +
152 + // `__proto__` is used because we must return a function, but there is
153 + // no way to create a function with a different prototype
154 + builder.__proto__ = proto; // eslint-disable-line no-proto
155 +
156 + return builder;
157 +}
158 +
159 +function applyStyle() {
160 + // Support varags, but simply cast to string in case there's only one arg
161 + const args = arguments;
162 + const argsLen = args.length;
163 + let str = String(arguments[0]);
164 +
165 + if (argsLen === 0) {
166 + return '';
167 + }
168 +
169 + if (argsLen > 1) {
170 + // Don't slice `arguments`, it prevents V8 optimizations
171 + for (let a = 1; a < argsLen; a++) {
172 + str += ' ' + args[a];
173 + }
174 + }
175 +
176 + if (!this.enabled || this.level <= 0 || !str) {
177 + return this._empty ? '' : str;
178 + }
179 +
180 + // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe,
181 + // see https://github.com/chalk/chalk/issues/58
182 + // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop.
183 + const originalDim = ansiStyles.dim.open;
184 + if (isSimpleWindowsTerm && this.hasGrey) {
185 + ansiStyles.dim.open = '';
186 + }
187 +
188 + for (const code of this._styles.slice().reverse()) {
189 + // Replace any instances already present with a re-opening code
190 + // otherwise only the part of the string until said closing code
191 + // will be colored, and the rest will simply be 'plain'.
192 + str = code.open + str.replace(code.closeRe, code.open) + code.close;
193 +
194 + // Close the styling before a linebreak and reopen
195 + // after next line to fix a bleed issue on macOS
196 + // https://github.com/chalk/chalk/pull/92
197 + str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`);
198 + }
199 +
200 + // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue
201 + ansiStyles.dim.open = originalDim;
202 +
203 + return str;
204 +}
205 +
206 +function chalkTag(chalk, strings) {
207 + if (!Array.isArray(strings)) {
208 + // If chalk() was called by itself or with a string,
209 + // return the string itself as a string.
210 + return [].slice.call(arguments, 1).join(' ');
211 + }
212 +
213 + const args = [].slice.call(arguments, 2);
214 + const parts = [strings.raw[0]];
215 +
216 + for (let i = 1; i < strings.length; i++) {
217 + parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&'));
218 + parts.push(String(strings.raw[i]));
219 + }
220 +
221 + return template(chalk, parts.join(''));
222 +}
223 +
224 +Object.defineProperties(Chalk.prototype, styles);
225 +
226 +module.exports = Chalk(); // eslint-disable-line new-cap
227 +module.exports.supportsColor = stdoutColor;
228 +module.exports.default = module.exports; // For TypeScript
1 +// @flow strict
2 +
3 +type TemplateStringsArray = $ReadOnlyArray<string>;
4 +
5 +export type Level = $Values<{
6 + None: 0,
7 + Basic: 1,
8 + Ansi256: 2,
9 + TrueColor: 3
10 +}>;
11 +
12 +export type ChalkOptions = {|
13 + enabled?: boolean,
14 + level?: Level
15 +|};
16 +
17 +export type ColorSupport = {|
18 + level: Level,
19 + hasBasic: boolean,
20 + has256: boolean,
21 + has16m: boolean
22 +|};
23 +
24 +export interface Chalk {
25 + (...text: string[]): string,
26 + (text: TemplateStringsArray, ...placeholders: string[]): string,
27 + constructor(options?: ChalkOptions): Chalk,
28 + enabled: boolean,
29 + level: Level,
30 + rgb(r: number, g: number, b: number): Chalk,
31 + hsl(h: number, s: number, l: number): Chalk,
32 + hsv(h: number, s: number, v: number): Chalk,
33 + hwb(h: number, w: number, b: number): Chalk,
34 + bgHex(color: string): Chalk,
35 + bgKeyword(color: string): Chalk,
36 + bgRgb(r: number, g: number, b: number): Chalk,
37 + bgHsl(h: number, s: number, l: number): Chalk,
38 + bgHsv(h: number, s: number, v: number): Chalk,
39 + bgHwb(h: number, w: number, b: number): Chalk,
40 + hex(color: string): Chalk,
41 + keyword(color: string): Chalk,
42 +
43 + +reset: Chalk,
44 + +bold: Chalk,
45 + +dim: Chalk,
46 + +italic: Chalk,
47 + +underline: Chalk,
48 + +inverse: Chalk,
49 + +hidden: Chalk,
50 + +strikethrough: Chalk,
51 +
52 + +visible: Chalk,
53 +
54 + +black: Chalk,
55 + +red: Chalk,
56 + +green: Chalk,
57 + +yellow: Chalk,
58 + +blue: Chalk,
59 + +magenta: Chalk,
60 + +cyan: Chalk,
61 + +white: Chalk,
62 + +gray: Chalk,
63 + +grey: Chalk,
64 + +blackBright: Chalk,
65 + +redBright: Chalk,
66 + +greenBright: Chalk,
67 + +yellowBright: Chalk,
68 + +blueBright: Chalk,
69 + +magentaBright: Chalk,
70 + +cyanBright: Chalk,
71 + +whiteBright: Chalk,
72 +
73 + +bgBlack: Chalk,
74 + +bgRed: Chalk,
75 + +bgGreen: Chalk,
76 + +bgYellow: Chalk,
77 + +bgBlue: Chalk,
78 + +bgMagenta: Chalk,
79 + +bgCyan: Chalk,
80 + +bgWhite: Chalk,
81 + +bgBlackBright: Chalk,
82 + +bgRedBright: Chalk,
83 + +bgGreenBright: Chalk,
84 + +bgYellowBright: Chalk,
85 + +bgBlueBright: Chalk,
86 + +bgMagentaBright: Chalk,
87 + +bgCyanBright: Chalk,
88 + +bgWhiteBrigh: Chalk,
89 +
90 + supportsColor: ColorSupport
91 +};
92 +
93 +declare module.exports: Chalk;
1 +MIT License
2 +
3 +Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
4 +
5 +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:
6 +
7 +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 +
9 +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.
1 +{
2 + "name": "chalk",
3 + "version": "2.4.2",
4 + "description": "Terminal string styling done right",
5 + "license": "MIT",
6 + "repository": "chalk/chalk",
7 + "engines": {
8 + "node": ">=4"
9 + },
10 + "scripts": {
11 + "test": "xo && tsc --project types && flow --max-warnings=0 && nyc ava",
12 + "bench": "matcha benchmark.js",
13 + "coveralls": "nyc report --reporter=text-lcov | coveralls"
14 + },
15 + "files": [
16 + "index.js",
17 + "templates.js",
18 + "types/index.d.ts",
19 + "index.js.flow"
20 + ],
21 + "keywords": [
22 + "color",
23 + "colour",
24 + "colors",
25 + "terminal",
26 + "console",
27 + "cli",
28 + "string",
29 + "str",
30 + "ansi",
31 + "style",
32 + "styles",
33 + "tty",
34 + "formatting",
35 + "rgb",
36 + "256",
37 + "shell",
38 + "xterm",
39 + "log",
40 + "logging",
41 + "command-line",
42 + "text"
43 + ],
44 + "dependencies": {
45 + "ansi-styles": "^3.2.1",
46 + "escape-string-regexp": "^1.0.5",
47 + "supports-color": "^5.3.0"
48 + },
49 + "devDependencies": {
50 + "ava": "*",
51 + "coveralls": "^3.0.0",
52 + "execa": "^0.9.0",
53 + "flow-bin": "^0.68.0",
54 + "import-fresh": "^2.0.0",
55 + "matcha": "^0.7.0",
56 + "nyc": "^11.0.2",
57 + "resolve-from": "^4.0.0",
58 + "typescript": "^2.5.3",
59 + "xo": "*"
60 + },
61 + "types": "types/index.d.ts",
62 + "xo": {
63 + "envs": [
64 + "node",
65 + "mocha"
66 + ],
67 + "ignores": [
68 + "test/_flow.js"
69 + ]
70 + }
71 +}
1 +<h1 align="center">
2 + <br>
3 + <br>
4 + <img width="320" src="media/logo.svg" alt="Chalk">
5 + <br>
6 + <br>
7 + <br>
8 +</h1>
9 +
10 +> Terminal string styling done right
11 +
12 +[![Build Status](https://travis-ci.org/chalk/chalk.svg?branch=master)](https://travis-ci.org/chalk/chalk) [![Coverage Status](https://coveralls.io/repos/github/chalk/chalk/badge.svg?branch=master)](https://coveralls.io/github/chalk/chalk?branch=master) [![](https://img.shields.io/badge/unicorn-approved-ff69b4.svg)](https://www.youtube.com/watch?v=9auOCbH5Ns4) [![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/xojs/xo) [![Mentioned in Awesome Node.js](https://awesome.re/mentioned-badge.svg)](https://github.com/sindresorhus/awesome-nodejs)
13 +
14 +### [See what's new in Chalk 2](https://github.com/chalk/chalk/releases/tag/v2.0.0)
15 +
16 +<img src="https://cdn.rawgit.com/chalk/ansi-styles/8261697c95bf34b6c7767e2cbe9941a851d59385/screenshot.svg" alt="" width="900">
17 +
18 +
19 +## Highlights
20 +
21 +- Expressive API
22 +- Highly performant
23 +- Ability to nest styles
24 +- [256/Truecolor color support](#256-and-truecolor-color-support)
25 +- Auto-detects color support
26 +- Doesn't extend `String.prototype`
27 +- Clean and focused
28 +- Actively maintained
29 +- [Used by ~23,000 packages](https://www.npmjs.com/browse/depended/chalk) as of December 31, 2017
30 +
31 +
32 +## Install
33 +
34 +```console
35 +$ npm install chalk
36 +```
37 +
38 +<a href="https://www.patreon.com/sindresorhus">
39 + <img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" width="160">
40 +</a>
41 +
42 +
43 +## Usage
44 +
45 +```js
46 +const chalk = require('chalk');
47 +
48 +console.log(chalk.blue('Hello world!'));
49 +```
50 +
51 +Chalk comes with an easy to use composable API where you just chain and nest the styles you want.
52 +
53 +```js
54 +const chalk = require('chalk');
55 +const log = console.log;
56 +
57 +// Combine styled and normal strings
58 +log(chalk.blue('Hello') + ' World' + chalk.red('!'));
59 +
60 +// Compose multiple styles using the chainable API
61 +log(chalk.blue.bgRed.bold('Hello world!'));
62 +
63 +// Pass in multiple arguments
64 +log(chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz'));
65 +
66 +// Nest styles
67 +log(chalk.red('Hello', chalk.underline.bgBlue('world') + '!'));
68 +
69 +// Nest styles of the same type even (color, underline, background)
70 +log(chalk.green(
71 + 'I am a green line ' +
72 + chalk.blue.underline.bold('with a blue substring') +
73 + ' that becomes green again!'
74 +));
75 +
76 +// ES2015 template literal
77 +log(`
78 +CPU: ${chalk.red('90%')}
79 +RAM: ${chalk.green('40%')}
80 +DISK: ${chalk.yellow('70%')}
81 +`);
82 +
83 +// ES2015 tagged template literal
84 +log(chalk`
85 +CPU: {red ${cpu.totalPercent}%}
86 +RAM: {green ${ram.used / ram.total * 100}%}
87 +DISK: {rgb(255,131,0) ${disk.used / disk.total * 100}%}
88 +`);
89 +
90 +// Use RGB colors in terminal emulators that support it.
91 +log(chalk.keyword('orange')('Yay for orange colored text!'));
92 +log(chalk.rgb(123, 45, 67).underline('Underlined reddish color'));
93 +log(chalk.hex('#DEADED').bold('Bold gray!'));
94 +```
95 +
96 +Easily define your own themes:
97 +
98 +```js
99 +const chalk = require('chalk');
100 +
101 +const error = chalk.bold.red;
102 +const warning = chalk.keyword('orange');
103 +
104 +console.log(error('Error!'));
105 +console.log(warning('Warning!'));
106 +```
107 +
108 +Take advantage of console.log [string substitution](https://nodejs.org/docs/latest/api/console.html#console_console_log_data_args):
109 +
110 +```js
111 +const name = 'Sindre';
112 +console.log(chalk.green('Hello %s'), name);
113 +//=> 'Hello Sindre'
114 +```
115 +
116 +
117 +## API
118 +
119 +### chalk.`<style>[.<style>...](string, [string...])`
120 +
121 +Example: `chalk.red.bold.underline('Hello', 'world');`
122 +
123 +Chain [styles](#styles) and call the last one as a method with a string argument. Order doesn't matter, and later styles take precedent in case of a conflict. This simply means that `chalk.red.yellow.green` is equivalent to `chalk.green`.
124 +
125 +Multiple arguments will be separated by space.
126 +
127 +### chalk.enabled
128 +
129 +Color support is automatically detected, as is the level (see `chalk.level`). However, if you'd like to simply enable/disable Chalk, you can do so via the `.enabled` property.
130 +
131 +Chalk is enabled by default unless explicitly disabled via the constructor or `chalk.level` is `0`.
132 +
133 +If you need to change this in a reusable module, create a new instance:
134 +
135 +```js
136 +const ctx = new chalk.constructor({enabled: false});
137 +```
138 +
139 +### chalk.level
140 +
141 +Color support is automatically detected, but you can override it by setting the `level` property. You should however only do this in your own code as it applies globally to all Chalk consumers.
142 +
143 +If you need to change this in a reusable module, create a new instance:
144 +
145 +```js
146 +const ctx = new chalk.constructor({level: 0});
147 +```
148 +
149 +Levels are as follows:
150 +
151 +0. All colors disabled
152 +1. Basic color support (16 colors)
153 +2. 256 color support
154 +3. Truecolor support (16 million colors)
155 +
156 +### chalk.supportsColor
157 +
158 +Detect whether the terminal [supports color](https://github.com/chalk/supports-color). Used internally and handled for you, but exposed for convenience.
159 +
160 +Can be overridden by the user with the flags `--color` and `--no-color`. For situations where using `--color` is not possible, add the environment variable `FORCE_COLOR=1` to forcefully enable color or `FORCE_COLOR=0` to forcefully disable. The use of `FORCE_COLOR` overrides all other color support checks.
161 +
162 +Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color=16m` flags, respectively.
163 +
164 +
165 +## Styles
166 +
167 +### Modifiers
168 +
169 +- `reset`
170 +- `bold`
171 +- `dim`
172 +- `italic` *(Not widely supported)*
173 +- `underline`
174 +- `inverse`
175 +- `hidden`
176 +- `strikethrough` *(Not widely supported)*
177 +- `visible` (Text is emitted only if enabled)
178 +
179 +### Colors
180 +
181 +- `black`
182 +- `red`
183 +- `green`
184 +- `yellow`
185 +- `blue` *(On Windows the bright version is used since normal blue is illegible)*
186 +- `magenta`
187 +- `cyan`
188 +- `white`
189 +- `gray` ("bright black")
190 +- `redBright`
191 +- `greenBright`
192 +- `yellowBright`
193 +- `blueBright`
194 +- `magentaBright`
195 +- `cyanBright`
196 +- `whiteBright`
197 +
198 +### Background colors
199 +
200 +- `bgBlack`
201 +- `bgRed`
202 +- `bgGreen`
203 +- `bgYellow`
204 +- `bgBlue`
205 +- `bgMagenta`
206 +- `bgCyan`
207 +- `bgWhite`
208 +- `bgBlackBright`
209 +- `bgRedBright`
210 +- `bgGreenBright`
211 +- `bgYellowBright`
212 +- `bgBlueBright`
213 +- `bgMagentaBright`
214 +- `bgCyanBright`
215 +- `bgWhiteBright`
216 +
217 +
218 +## Tagged template literal
219 +
220 +Chalk can be used as a [tagged template literal](http://exploringjs.com/es6/ch_template-literals.html#_tagged-template-literals).
221 +
222 +```js
223 +const chalk = require('chalk');
224 +
225 +const miles = 18;
226 +const calculateFeet = miles => miles * 5280;
227 +
228 +console.log(chalk`
229 + There are {bold 5280 feet} in a mile.
230 + In {bold ${miles} miles}, there are {green.bold ${calculateFeet(miles)} feet}.
231 +`);
232 +```
233 +
234 +Blocks are delimited by an opening curly brace (`{`), a style, some content, and a closing curly brace (`}`).
235 +
236 +Template styles are chained exactly like normal Chalk styles. The following two statements are equivalent:
237 +
238 +```js
239 +console.log(chalk.bold.rgb(10, 100, 200)('Hello!'));
240 +console.log(chalk`{bold.rgb(10,100,200) Hello!}`);
241 +```
242 +
243 +Note that function styles (`rgb()`, `hsl()`, `keyword()`, etc.) may not contain spaces between parameters.
244 +
245 +All interpolated values (`` chalk`${foo}` ``) are converted to strings via the `.toString()` method. All curly braces (`{` and `}`) in interpolated value strings are escaped.
246 +
247 +
248 +## 256 and Truecolor color support
249 +
250 +Chalk supports 256 colors and [Truecolor](https://gist.github.com/XVilka/8346728) (16 million colors) on supported terminal apps.
251 +
252 +Colors are downsampled from 16 million RGB values to an ANSI color format that is supported by the terminal emulator (or by specifying `{level: n}` as a Chalk option). For example, Chalk configured to run at level 1 (basic color support) will downsample an RGB value of #FF0000 (red) to 31 (ANSI escape for red).
253 +
254 +Examples:
255 +
256 +- `chalk.hex('#DEADED').underline('Hello, world!')`
257 +- `chalk.keyword('orange')('Some orange text')`
258 +- `chalk.rgb(15, 100, 204).inverse('Hello!')`
259 +
260 +Background versions of these models are prefixed with `bg` and the first level of the module capitalized (e.g. `keyword` for foreground colors and `bgKeyword` for background colors).
261 +
262 +- `chalk.bgHex('#DEADED').underline('Hello, world!')`
263 +- `chalk.bgKeyword('orange')('Some orange text')`
264 +- `chalk.bgRgb(15, 100, 204).inverse('Hello!')`
265 +
266 +The following color models can be used:
267 +
268 +- [`rgb`](https://en.wikipedia.org/wiki/RGB_color_model) - Example: `chalk.rgb(255, 136, 0).bold('Orange!')`
269 +- [`hex`](https://en.wikipedia.org/wiki/Web_colors#Hex_triplet) - Example: `chalk.hex('#FF8800').bold('Orange!')`
270 +- [`keyword`](https://www.w3.org/wiki/CSS/Properties/color/keywords) (CSS keywords) - Example: `chalk.keyword('orange').bold('Orange!')`
271 +- [`hsl`](https://en.wikipedia.org/wiki/HSL_and_HSV) - Example: `chalk.hsl(32, 100, 50).bold('Orange!')`
272 +- [`hsv`](https://en.wikipedia.org/wiki/HSL_and_HSV) - Example: `chalk.hsv(32, 100, 100).bold('Orange!')`
273 +- [`hwb`](https://en.wikipedia.org/wiki/HWB_color_model) - Example: `chalk.hwb(32, 0, 50).bold('Orange!')`
274 +- `ansi16`
275 +- `ansi256`
276 +
277 +
278 +## Windows
279 +
280 +If you're on Windows, do yourself a favor and use [`cmder`](http://cmder.net/) instead of `cmd.exe`.
281 +
282 +
283 +## Origin story
284 +
285 +[colors.js](https://github.com/Marak/colors.js) used to be the most popular string styling module, but it has serious deficiencies like extending `String.prototype` which causes all kinds of [problems](https://github.com/yeoman/yo/issues/68) and the package is unmaintained. Although there are other packages, they either do too much or not enough. Chalk is a clean and focused alternative.
286 +
287 +
288 +## Related
289 +
290 +- [chalk-cli](https://github.com/chalk/chalk-cli) - CLI for this module
291 +- [ansi-styles](https://github.com/chalk/ansi-styles) - ANSI escape codes for styling strings in the terminal
292 +- [supports-color](https://github.com/chalk/supports-color) - Detect whether a terminal supports color
293 +- [strip-ansi](https://github.com/chalk/strip-ansi) - Strip ANSI escape codes
294 +- [strip-ansi-stream](https://github.com/chalk/strip-ansi-stream) - Strip ANSI escape codes from a stream
295 +- [has-ansi](https://github.com/chalk/has-ansi) - Check if a string has ANSI escape codes
296 +- [ansi-regex](https://github.com/chalk/ansi-regex) - Regular expression for matching ANSI escape codes
297 +- [wrap-ansi](https://github.com/chalk/wrap-ansi) - Wordwrap a string with ANSI escape codes
298 +- [slice-ansi](https://github.com/chalk/slice-ansi) - Slice a string with ANSI escape codes
299 +- [color-convert](https://github.com/qix-/color-convert) - Converts colors between different models
300 +- [chalk-animation](https://github.com/bokub/chalk-animation) - Animate strings in the terminal
301 +- [gradient-string](https://github.com/bokub/gradient-string) - Apply color gradients to strings
302 +- [chalk-pipe](https://github.com/LitoMore/chalk-pipe) - Create chalk style schemes with simpler style strings
303 +- [terminal-link](https://github.com/sindresorhus/terminal-link) - Create clickable links in the terminal
304 +
305 +
306 +## Maintainers
307 +
308 +- [Sindre Sorhus](https://github.com/sindresorhus)
309 +- [Josh Junon](https://github.com/qix-)
310 +
311 +
312 +## License
313 +
314 +MIT
1 +'use strict';
2 +const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi;
3 +const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g;
4 +const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/;
5 +const ESCAPE_REGEX = /\\(u[a-f\d]{4}|x[a-f\d]{2}|.)|([^\\])/gi;
6 +
7 +const ESCAPES = new Map([
8 + ['n', '\n'],
9 + ['r', '\r'],
10 + ['t', '\t'],
11 + ['b', '\b'],
12 + ['f', '\f'],
13 + ['v', '\v'],
14 + ['0', '\0'],
15 + ['\\', '\\'],
16 + ['e', '\u001B'],
17 + ['a', '\u0007']
18 +]);
19 +
20 +function unescape(c) {
21 + if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) {
22 + return String.fromCharCode(parseInt(c.slice(1), 16));
23 + }
24 +
25 + return ESCAPES.get(c) || c;
26 +}
27 +
28 +function parseArguments(name, args) {
29 + const results = [];
30 + const chunks = args.trim().split(/\s*,\s*/g);
31 + let matches;
32 +
33 + for (const chunk of chunks) {
34 + if (!isNaN(chunk)) {
35 + results.push(Number(chunk));
36 + } else if ((matches = chunk.match(STRING_REGEX))) {
37 + results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, chr) => escape ? unescape(escape) : chr));
38 + } else {
39 + throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`);
40 + }
41 + }
42 +
43 + return results;
44 +}
45 +
46 +function parseStyle(style) {
47 + STYLE_REGEX.lastIndex = 0;
48 +
49 + const results = [];
50 + let matches;
51 +
52 + while ((matches = STYLE_REGEX.exec(style)) !== null) {
53 + const name = matches[1];
54 +
55 + if (matches[2]) {
56 + const args = parseArguments(name, matches[2]);
57 + results.push([name].concat(args));
58 + } else {
59 + results.push([name]);
60 + }
61 + }
62 +
63 + return results;
64 +}
65 +
66 +function buildStyle(chalk, styles) {
67 + const enabled = {};
68 +
69 + for (const layer of styles) {
70 + for (const style of layer.styles) {
71 + enabled[style[0]] = layer.inverse ? null : style.slice(1);
72 + }
73 + }
74 +
75 + let current = chalk;
76 + for (const styleName of Object.keys(enabled)) {
77 + if (Array.isArray(enabled[styleName])) {
78 + if (!(styleName in current)) {
79 + throw new Error(`Unknown Chalk style: ${styleName}`);
80 + }
81 +
82 + if (enabled[styleName].length > 0) {
83 + current = current[styleName].apply(current, enabled[styleName]);
84 + } else {
85 + current = current[styleName];
86 + }
87 + }
88 + }
89 +
90 + return current;
91 +}
92 +
93 +module.exports = (chalk, tmp) => {
94 + const styles = [];
95 + const chunks = [];
96 + let chunk = [];
97 +
98 + // eslint-disable-next-line max-params
99 + tmp.replace(TEMPLATE_REGEX, (m, escapeChar, inverse, style, close, chr) => {
100 + if (escapeChar) {
101 + chunk.push(unescape(escapeChar));
102 + } else if (style) {
103 + const str = chunk.join('');
104 + chunk = [];
105 + chunks.push(styles.length === 0 ? str : buildStyle(chalk, styles)(str));
106 + styles.push({inverse, styles: parseStyle(style)});
107 + } else if (close) {
108 + if (styles.length === 0) {
109 + throw new Error('Found extraneous } in Chalk template literal');
110 + }
111 +
112 + chunks.push(buildStyle(chalk, styles)(chunk.join('')));
113 + chunk = [];
114 + styles.pop();
115 + } else {
116 + chunk.push(chr);
117 + }
118 + });
119 +
120 + chunks.push(chunk.join(''));
121 +
122 + if (styles.length > 0) {
123 + const errMsg = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`;
124 + throw new Error(errMsg);
125 + }
126 +
127 + return chunks.join('');
128 +};
1 +// Type definitions for Chalk
2 +// Definitions by: Thomas Sauer <https://github.com/t-sauer>
3 +
4 +export const enum Level {
5 + None = 0,
6 + Basic = 1,
7 + Ansi256 = 2,
8 + TrueColor = 3
9 +}
10 +
11 +export interface ChalkOptions {
12 + enabled?: boolean;
13 + level?: Level;
14 +}
15 +
16 +export interface ChalkConstructor {
17 + new (options?: ChalkOptions): Chalk;
18 + (options?: ChalkOptions): Chalk;
19 +}
20 +
21 +export interface ColorSupport {
22 + level: Level;
23 + hasBasic: boolean;
24 + has256: boolean;
25 + has16m: boolean;
26 +}
27 +
28 +export interface Chalk {
29 + (...text: string[]): string;
30 + (text: TemplateStringsArray, ...placeholders: string[]): string;
31 + constructor: ChalkConstructor;
32 + enabled: boolean;
33 + level: Level;
34 + rgb(r: number, g: number, b: number): this;
35 + hsl(h: number, s: number, l: number): this;
36 + hsv(h: number, s: number, v: number): this;
37 + hwb(h: number, w: number, b: number): this;
38 + bgHex(color: string): this;
39 + bgKeyword(color: string): this;
40 + bgRgb(r: number, g: number, b: number): this;
41 + bgHsl(h: number, s: number, l: number): this;
42 + bgHsv(h: number, s: number, v: number): this;
43 + bgHwb(h: number, w: number, b: number): this;
44 + hex(color: string): this;
45 + keyword(color: string): this;
46 +
47 + readonly reset: this;
48 + readonly bold: this;
49 + readonly dim: this;
50 + readonly italic: this;
51 + readonly underline: this;
52 + readonly inverse: this;
53 + readonly hidden: this;
54 + readonly strikethrough: this;
55 +
56 + readonly visible: this;
57 +
58 + readonly black: this;
59 + readonly red: this;
60 + readonly green: this;
61 + readonly yellow: this;
62 + readonly blue: this;
63 + readonly magenta: this;
64 + readonly cyan: this;
65 + readonly white: this;
66 + readonly gray: this;
67 + readonly grey: this;
68 + readonly blackBright: this;
69 + readonly redBright: this;
70 + readonly greenBright: this;
71 + readonly yellowBright: this;
72 + readonly blueBright: this;
73 + readonly magentaBright: this;
74 + readonly cyanBright: this;
75 + readonly whiteBright: this;
76 +
77 + readonly bgBlack: this;
78 + readonly bgRed: this;
79 + readonly bgGreen: this;
80 + readonly bgYellow: this;
81 + readonly bgBlue: this;
82 + readonly bgMagenta: this;
83 + readonly bgCyan: this;
84 + readonly bgWhite: this;
85 + readonly bgBlackBright: this;
86 + readonly bgRedBright: this;
87 + readonly bgGreenBright: this;
88 + readonly bgYellowBright: this;
89 + readonly bgBlueBright: this;
90 + readonly bgMagentaBright: this;
91 + readonly bgCyanBright: this;
92 + readonly bgWhiteBright: this;
93 +}
94 +
95 +declare const chalk: Chalk & { supportsColor: ColorSupport };
96 +
97 +export default chalk
1 +# 1.0.0 - 2016-01-07
2 +
3 +- Removed: unused speed test
4 +- Added: Automatic routing between previously unsupported conversions
5 +([#27](https://github.com/Qix-/color-convert/pull/27))
6 +- Removed: `xxx2xxx()` and `xxx2xxxRaw()` functions
7 +([#27](https://github.com/Qix-/color-convert/pull/27))
8 +- Removed: `convert()` class
9 +([#27](https://github.com/Qix-/color-convert/pull/27))
10 +- Changed: all functions to lookup dictionary
11 +([#27](https://github.com/Qix-/color-convert/pull/27))
12 +- Changed: `ansi` to `ansi256`
13 +([#27](https://github.com/Qix-/color-convert/pull/27))
14 +- Fixed: argument grouping for functions requiring only one argument
15 +([#27](https://github.com/Qix-/color-convert/pull/27))
16 +
17 +# 0.6.0 - 2015-07-23
18 +
19 +- Added: methods to handle
20 +[ANSI](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) 16/256 colors:
21 + - rgb2ansi16
22 + - rgb2ansi
23 + - hsl2ansi16
24 + - hsl2ansi
25 + - hsv2ansi16
26 + - hsv2ansi
27 + - hwb2ansi16
28 + - hwb2ansi
29 + - cmyk2ansi16
30 + - cmyk2ansi
31 + - keyword2ansi16
32 + - keyword2ansi
33 + - ansi162rgb
34 + - ansi162hsl
35 + - ansi162hsv
36 + - ansi162hwb
37 + - ansi162cmyk
38 + - ansi162keyword
39 + - ansi2rgb
40 + - ansi2hsl
41 + - ansi2hsv
42 + - ansi2hwb
43 + - ansi2cmyk
44 + - ansi2keyword
45 +([#18](https://github.com/harthur/color-convert/pull/18))
46 +
47 +# 0.5.3 - 2015-06-02
48 +
49 +- Fixed: hsl2hsv does not return `NaN` anymore when using `[0,0,0]`
50 +([#15](https://github.com/harthur/color-convert/issues/15))
51 +
52 +---
53 +
54 +Check out commit logs for older releases
1 +Copyright (c) 2011-2016 Heather Arthur <fayearthur@gmail.com>
2 +
3 +Permission is hereby granted, free of charge, to any person obtaining
4 +a copy of this software and associated documentation files (the
5 +"Software"), to deal in the Software without restriction, including
6 +without limitation the rights to use, copy, modify, merge, publish,
7 +distribute, sublicense, and/or sell copies of the Software, and to
8 +permit persons to whom the Software is furnished to do so, subject to
9 +the following conditions:
10 +
11 +The above copyright notice and this permission notice shall be
12 +included in all copies or substantial portions of the Software.
13 +
14 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 +
1 +# color-convert
2 +
3 +[![Build Status](https://travis-ci.org/Qix-/color-convert.svg?branch=master)](https://travis-ci.org/Qix-/color-convert)
4 +
5 +Color-convert is a color conversion library for JavaScript and node.
6 +It converts all ways between `rgb`, `hsl`, `hsv`, `hwb`, `cmyk`, `ansi`, `ansi16`, `hex` strings, and CSS `keyword`s (will round to closest):
7 +
8 +```js
9 +var convert = require('color-convert');
10 +
11 +convert.rgb.hsl(140, 200, 100); // [96, 48, 59]
12 +convert.keyword.rgb('blue'); // [0, 0, 255]
13 +
14 +var rgbChannels = convert.rgb.channels; // 3
15 +var cmykChannels = convert.cmyk.channels; // 4
16 +var ansiChannels = convert.ansi16.channels; // 1
17 +```
18 +
19 +# Install
20 +
21 +```console
22 +$ npm install color-convert
23 +```
24 +
25 +# API
26 +
27 +Simply get the property of the _from_ and _to_ conversion that you're looking for.
28 +
29 +All functions have a rounded and unrounded variant. By default, return values are rounded. To get the unrounded (raw) results, simply tack on `.raw` to the function.
30 +
31 +All 'from' functions have a hidden property called `.channels` that indicates the number of channels the function expects (not including alpha).
32 +
33 +```js
34 +var convert = require('color-convert');
35 +
36 +// Hex to LAB
37 +convert.hex.lab('DEADBF'); // [ 76, 21, -2 ]
38 +convert.hex.lab.raw('DEADBF'); // [ 75.56213190997677, 20.653827952644754, -2.290532499330533 ]
39 +
40 +// RGB to CMYK
41 +convert.rgb.cmyk(167, 255, 4); // [ 35, 0, 98, 0 ]
42 +convert.rgb.cmyk.raw(167, 255, 4); // [ 34.509803921568626, 0, 98.43137254901961, 0 ]
43 +```
44 +
45 +### Arrays
46 +All functions that accept multiple arguments also support passing an array.
47 +
48 +Note that this does **not** apply to functions that convert from a color that only requires one value (e.g. `keyword`, `ansi256`, `hex`, etc.)
49 +
50 +```js
51 +var convert = require('color-convert');
52 +
53 +convert.rgb.hex(123, 45, 67); // '7B2D43'
54 +convert.rgb.hex([123, 45, 67]); // '7B2D43'
55 +```
56 +
57 +## Routing
58 +
59 +Conversions that don't have an _explicitly_ defined conversion (in [conversions.js](conversions.js)), but can be converted by means of sub-conversions (e.g. XYZ -> **RGB** -> CMYK), are automatically routed together. This allows just about any color model supported by `color-convert` to be converted to any other model, so long as a sub-conversion path exists. This is also true for conversions requiring more than one step in between (e.g. LCH -> **LAB** -> **XYZ** -> **RGB** -> Hex).
60 +
61 +Keep in mind that extensive conversions _may_ result in a loss of precision, and exist only to be complete. For a list of "direct" (single-step) conversions, see [conversions.js](conversions.js).
62 +
63 +# Contribute
64 +
65 +If there is a new model you would like to support, or want to add a direct conversion between two existing models, please send us a pull request.
66 +
67 +# License
68 +Copyright &copy; 2011-2016, Heather Arthur and Josh Junon. Licensed under the [MIT License](LICENSE).
1 +/* MIT license */
2 +var cssKeywords = require('color-name');
3 +
4 +// NOTE: conversions should only return primitive values (i.e. arrays, or
5 +// values that give correct `typeof` results).
6 +// do not use box values types (i.e. Number(), String(), etc.)
7 +
8 +var reverseKeywords = {};
9 +for (var key in cssKeywords) {
10 + if (cssKeywords.hasOwnProperty(key)) {
11 + reverseKeywords[cssKeywords[key]] = key;
12 + }
13 +}
14 +
15 +var convert = module.exports = {
16 + rgb: {channels: 3, labels: 'rgb'},
17 + hsl: {channels: 3, labels: 'hsl'},
18 + hsv: {channels: 3, labels: 'hsv'},
19 + hwb: {channels: 3, labels: 'hwb'},
20 + cmyk: {channels: 4, labels: 'cmyk'},
21 + xyz: {channels: 3, labels: 'xyz'},
22 + lab: {channels: 3, labels: 'lab'},
23 + lch: {channels: 3, labels: 'lch'},
24 + hex: {channels: 1, labels: ['hex']},
25 + keyword: {channels: 1, labels: ['keyword']},
26 + ansi16: {channels: 1, labels: ['ansi16']},
27 + ansi256: {channels: 1, labels: ['ansi256']},
28 + hcg: {channels: 3, labels: ['h', 'c', 'g']},
29 + apple: {channels: 3, labels: ['r16', 'g16', 'b16']},
30 + gray: {channels: 1, labels: ['gray']}
31 +};
32 +
33 +// hide .channels and .labels properties
34 +for (var model in convert) {
35 + if (convert.hasOwnProperty(model)) {
36 + if (!('channels' in convert[model])) {
37 + throw new Error('missing channels property: ' + model);
38 + }
39 +
40 + if (!('labels' in convert[model])) {
41 + throw new Error('missing channel labels property: ' + model);
42 + }
43 +
44 + if (convert[model].labels.length !== convert[model].channels) {
45 + throw new Error('channel and label counts mismatch: ' + model);
46 + }
47 +
48 + var channels = convert[model].channels;
49 + var labels = convert[model].labels;
50 + delete convert[model].channels;
51 + delete convert[model].labels;
52 + Object.defineProperty(convert[model], 'channels', {value: channels});
53 + Object.defineProperty(convert[model], 'labels', {value: labels});
54 + }
55 +}
56 +
57 +convert.rgb.hsl = function (rgb) {
58 + var r = rgb[0] / 255;
59 + var g = rgb[1] / 255;
60 + var b = rgb[2] / 255;
61 + var min = Math.min(r, g, b);
62 + var max = Math.max(r, g, b);
63 + var delta = max - min;
64 + var h;
65 + var s;
66 + var l;
67 +
68 + if (max === min) {
69 + h = 0;
70 + } else if (r === max) {
71 + h = (g - b) / delta;
72 + } else if (g === max) {
73 + h = 2 + (b - r) / delta;
74 + } else if (b === max) {
75 + h = 4 + (r - g) / delta;
76 + }
77 +
78 + h = Math.min(h * 60, 360);
79 +
80 + if (h < 0) {
81 + h += 360;
82 + }
83 +
84 + l = (min + max) / 2;
85 +
86 + if (max === min) {
87 + s = 0;
88 + } else if (l <= 0.5) {
89 + s = delta / (max + min);
90 + } else {
91 + s = delta / (2 - max - min);
92 + }
93 +
94 + return [h, s * 100, l * 100];
95 +};
96 +
97 +convert.rgb.hsv = function (rgb) {
98 + var rdif;
99 + var gdif;
100 + var bdif;
101 + var h;
102 + var s;
103 +
104 + var r = rgb[0] / 255;
105 + var g = rgb[1] / 255;
106 + var b = rgb[2] / 255;
107 + var v = Math.max(r, g, b);
108 + var diff = v - Math.min(r, g, b);
109 + var diffc = function (c) {
110 + return (v - c) / 6 / diff + 1 / 2;
111 + };
112 +
113 + if (diff === 0) {
114 + h = s = 0;
115 + } else {
116 + s = diff / v;
117 + rdif = diffc(r);
118 + gdif = diffc(g);
119 + bdif = diffc(b);
120 +
121 + if (r === v) {
122 + h = bdif - gdif;
123 + } else if (g === v) {
124 + h = (1 / 3) + rdif - bdif;
125 + } else if (b === v) {
126 + h = (2 / 3) + gdif - rdif;
127 + }
128 + if (h < 0) {
129 + h += 1;
130 + } else if (h > 1) {
131 + h -= 1;
132 + }
133 + }
134 +
135 + return [
136 + h * 360,
137 + s * 100,
138 + v * 100
139 + ];
140 +};
141 +
142 +convert.rgb.hwb = function (rgb) {
143 + var r = rgb[0];
144 + var g = rgb[1];
145 + var b = rgb[2];
146 + var h = convert.rgb.hsl(rgb)[0];
147 + var w = 1 / 255 * Math.min(r, Math.min(g, b));
148 +
149 + b = 1 - 1 / 255 * Math.max(r, Math.max(g, b));
150 +
151 + return [h, w * 100, b * 100];
152 +};
153 +
154 +convert.rgb.cmyk = function (rgb) {
155 + var r = rgb[0] / 255;
156 + var g = rgb[1] / 255;
157 + var b = rgb[2] / 255;
158 + var c;
159 + var m;
160 + var y;
161 + var k;
162 +
163 + k = Math.min(1 - r, 1 - g, 1 - b);
164 + c = (1 - r - k) / (1 - k) || 0;
165 + m = (1 - g - k) / (1 - k) || 0;
166 + y = (1 - b - k) / (1 - k) || 0;
167 +
168 + return [c * 100, m * 100, y * 100, k * 100];
169 +};
170 +
171 +/**
172 + * See https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance
173 + * */
174 +function comparativeDistance(x, y) {
175 + return (
176 + Math.pow(x[0] - y[0], 2) +
177 + Math.pow(x[1] - y[1], 2) +
178 + Math.pow(x[2] - y[2], 2)
179 + );
180 +}
181 +
182 +convert.rgb.keyword = function (rgb) {
183 + var reversed = reverseKeywords[rgb];
184 + if (reversed) {
185 + return reversed;
186 + }
187 +
188 + var currentClosestDistance = Infinity;
189 + var currentClosestKeyword;
190 +
191 + for (var keyword in cssKeywords) {
192 + if (cssKeywords.hasOwnProperty(keyword)) {
193 + var value = cssKeywords[keyword];
194 +
195 + // Compute comparative distance
196 + var distance = comparativeDistance(rgb, value);
197 +
198 + // Check if its less, if so set as closest
199 + if (distance < currentClosestDistance) {
200 + currentClosestDistance = distance;
201 + currentClosestKeyword = keyword;
202 + }
203 + }
204 + }
205 +
206 + return currentClosestKeyword;
207 +};
208 +
209 +convert.keyword.rgb = function (keyword) {
210 + return cssKeywords[keyword];
211 +};
212 +
213 +convert.rgb.xyz = function (rgb) {
214 + var r = rgb[0] / 255;
215 + var g = rgb[1] / 255;
216 + var b = rgb[2] / 255;
217 +
218 + // assume sRGB
219 + r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
220 + g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
221 + b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
222 +
223 + var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
224 + var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
225 + var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
226 +
227 + return [x * 100, y * 100, z * 100];
228 +};
229 +
230 +convert.rgb.lab = function (rgb) {
231 + var xyz = convert.rgb.xyz(rgb);
232 + var x = xyz[0];
233 + var y = xyz[1];
234 + var z = xyz[2];
235 + var l;
236 + var a;
237 + var b;
238 +
239 + x /= 95.047;
240 + y /= 100;
241 + z /= 108.883;
242 +
243 + x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);
244 + y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);
245 + z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);
246 +
247 + l = (116 * y) - 16;
248 + a = 500 * (x - y);
249 + b = 200 * (y - z);
250 +
251 + return [l, a, b];
252 +};
253 +
254 +convert.hsl.rgb = function (hsl) {
255 + var h = hsl[0] / 360;
256 + var s = hsl[1] / 100;
257 + var l = hsl[2] / 100;
258 + var t1;
259 + var t2;
260 + var t3;
261 + var rgb;
262 + var val;
263 +
264 + if (s === 0) {
265 + val = l * 255;
266 + return [val, val, val];
267 + }
268 +
269 + if (l < 0.5) {
270 + t2 = l * (1 + s);
271 + } else {
272 + t2 = l + s - l * s;
273 + }
274 +
275 + t1 = 2 * l - t2;
276 +
277 + rgb = [0, 0, 0];
278 + for (var i = 0; i < 3; i++) {
279 + t3 = h + 1 / 3 * -(i - 1);
280 + if (t3 < 0) {
281 + t3++;
282 + }
283 + if (t3 > 1) {
284 + t3--;
285 + }
286 +
287 + if (6 * t3 < 1) {
288 + val = t1 + (t2 - t1) * 6 * t3;
289 + } else if (2 * t3 < 1) {
290 + val = t2;
291 + } else if (3 * t3 < 2) {
292 + val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
293 + } else {
294 + val = t1;
295 + }
296 +
297 + rgb[i] = val * 255;
298 + }
299 +
300 + return rgb;
301 +};
302 +
303 +convert.hsl.hsv = function (hsl) {
304 + var h = hsl[0];
305 + var s = hsl[1] / 100;
306 + var l = hsl[2] / 100;
307 + var smin = s;
308 + var lmin = Math.max(l, 0.01);
309 + var sv;
310 + var v;
311 +
312 + l *= 2;
313 + s *= (l <= 1) ? l : 2 - l;
314 + smin *= lmin <= 1 ? lmin : 2 - lmin;
315 + v = (l + s) / 2;
316 + sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s);
317 +
318 + return [h, sv * 100, v * 100];
319 +};
320 +
321 +convert.hsv.rgb = function (hsv) {
322 + var h = hsv[0] / 60;
323 + var s = hsv[1] / 100;
324 + var v = hsv[2] / 100;
325 + var hi = Math.floor(h) % 6;
326 +
327 + var f = h - Math.floor(h);
328 + var p = 255 * v * (1 - s);
329 + var q = 255 * v * (1 - (s * f));
330 + var t = 255 * v * (1 - (s * (1 - f)));
331 + v *= 255;
332 +
333 + switch (hi) {
334 + case 0:
335 + return [v, t, p];
336 + case 1:
337 + return [q, v, p];
338 + case 2:
339 + return [p, v, t];
340 + case 3:
341 + return [p, q, v];
342 + case 4:
343 + return [t, p, v];
344 + case 5:
345 + return [v, p, q];
346 + }
347 +};
348 +
349 +convert.hsv.hsl = function (hsv) {
350 + var h = hsv[0];
351 + var s = hsv[1] / 100;
352 + var v = hsv[2] / 100;
353 + var vmin = Math.max(v, 0.01);
354 + var lmin;
355 + var sl;
356 + var l;
357 +
358 + l = (2 - s) * v;
359 + lmin = (2 - s) * vmin;
360 + sl = s * vmin;
361 + sl /= (lmin <= 1) ? lmin : 2 - lmin;
362 + sl = sl || 0;
363 + l /= 2;
364 +
365 + return [h, sl * 100, l * 100];
366 +};
367 +
368 +// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
369 +convert.hwb.rgb = function (hwb) {
370 + var h = hwb[0] / 360;
371 + var wh = hwb[1] / 100;
372 + var bl = hwb[2] / 100;
373 + var ratio = wh + bl;
374 + var i;
375 + var v;
376 + var f;
377 + var n;
378 +
379 + // wh + bl cant be > 1
380 + if (ratio > 1) {
381 + wh /= ratio;
382 + bl /= ratio;
383 + }
384 +
385 + i = Math.floor(6 * h);
386 + v = 1 - bl;
387 + f = 6 * h - i;
388 +
389 + if ((i & 0x01) !== 0) {
390 + f = 1 - f;
391 + }
392 +
393 + n = wh + f * (v - wh); // linear interpolation
394 +
395 + var r;
396 + var g;
397 + var b;
398 + switch (i) {
399 + default:
400 + case 6:
401 + case 0: r = v; g = n; b = wh; break;
402 + case 1: r = n; g = v; b = wh; break;
403 + case 2: r = wh; g = v; b = n; break;
404 + case 3: r = wh; g = n; b = v; break;
405 + case 4: r = n; g = wh; b = v; break;
406 + case 5: r = v; g = wh; b = n; break;
407 + }
408 +
409 + return [r * 255, g * 255, b * 255];
410 +};
411 +
412 +convert.cmyk.rgb = function (cmyk) {
413 + var c = cmyk[0] / 100;
414 + var m = cmyk[1] / 100;
415 + var y = cmyk[2] / 100;
416 + var k = cmyk[3] / 100;
417 + var r;
418 + var g;
419 + var b;
420 +
421 + r = 1 - Math.min(1, c * (1 - k) + k);
422 + g = 1 - Math.min(1, m * (1 - k) + k);
423 + b = 1 - Math.min(1, y * (1 - k) + k);
424 +
425 + return [r * 255, g * 255, b * 255];
426 +};
427 +
428 +convert.xyz.rgb = function (xyz) {
429 + var x = xyz[0] / 100;
430 + var y = xyz[1] / 100;
431 + var z = xyz[2] / 100;
432 + var r;
433 + var g;
434 + var b;
435 +
436 + r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
437 + g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
438 + b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
439 +
440 + // assume sRGB
441 + r = r > 0.0031308
442 + ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
443 + : r * 12.92;
444 +
445 + g = g > 0.0031308
446 + ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
447 + : g * 12.92;
448 +
449 + b = b > 0.0031308
450 + ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
451 + : b * 12.92;
452 +
453 + r = Math.min(Math.max(0, r), 1);
454 + g = Math.min(Math.max(0, g), 1);
455 + b = Math.min(Math.max(0, b), 1);
456 +
457 + return [r * 255, g * 255, b * 255];
458 +};
459 +
460 +convert.xyz.lab = function (xyz) {
461 + var x = xyz[0];
462 + var y = xyz[1];
463 + var z = xyz[2];
464 + var l;
465 + var a;
466 + var b;
467 +
468 + x /= 95.047;
469 + y /= 100;
470 + z /= 108.883;
471 +
472 + x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);
473 + y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);
474 + z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);
475 +
476 + l = (116 * y) - 16;
477 + a = 500 * (x - y);
478 + b = 200 * (y - z);
479 +
480 + return [l, a, b];
481 +};
482 +
483 +convert.lab.xyz = function (lab) {
484 + var l = lab[0];
485 + var a = lab[1];
486 + var b = lab[2];
487 + var x;
488 + var y;
489 + var z;
490 +
491 + y = (l + 16) / 116;
492 + x = a / 500 + y;
493 + z = y - b / 200;
494 +
495 + var y2 = Math.pow(y, 3);
496 + var x2 = Math.pow(x, 3);
497 + var z2 = Math.pow(z, 3);
498 + y = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787;
499 + x = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787;
500 + z = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787;
501 +
502 + x *= 95.047;
503 + y *= 100;
504 + z *= 108.883;
505 +
506 + return [x, y, z];
507 +};
508 +
509 +convert.lab.lch = function (lab) {
510 + var l = lab[0];
511 + var a = lab[1];
512 + var b = lab[2];
513 + var hr;
514 + var h;
515 + var c;
516 +
517 + hr = Math.atan2(b, a);
518 + h = hr * 360 / 2 / Math.PI;
519 +
520 + if (h < 0) {
521 + h += 360;
522 + }
523 +
524 + c = Math.sqrt(a * a + b * b);
525 +
526 + return [l, c, h];
527 +};
528 +
529 +convert.lch.lab = function (lch) {
530 + var l = lch[0];
531 + var c = lch[1];
532 + var h = lch[2];
533 + var a;
534 + var b;
535 + var hr;
536 +
537 + hr = h / 360 * 2 * Math.PI;
538 + a = c * Math.cos(hr);
539 + b = c * Math.sin(hr);
540 +
541 + return [l, a, b];
542 +};
543 +
544 +convert.rgb.ansi16 = function (args) {
545 + var r = args[0];
546 + var g = args[1];
547 + var b = args[2];
548 + var value = 1 in arguments ? arguments[1] : convert.rgb.hsv(args)[2]; // hsv -> ansi16 optimization
549 +
550 + value = Math.round(value / 50);
551 +
552 + if (value === 0) {
553 + return 30;
554 + }
555 +
556 + var ansi = 30
557 + + ((Math.round(b / 255) << 2)
558 + | (Math.round(g / 255) << 1)
559 + | Math.round(r / 255));
560 +
561 + if (value === 2) {
562 + ansi += 60;
563 + }
564 +
565 + return ansi;
566 +};
567 +
568 +convert.hsv.ansi16 = function (args) {
569 + // optimization here; we already know the value and don't need to get
570 + // it converted for us.
571 + return convert.rgb.ansi16(convert.hsv.rgb(args), args[2]);
572 +};
573 +
574 +convert.rgb.ansi256 = function (args) {
575 + var r = args[0];
576 + var g = args[1];
577 + var b = args[2];
578 +
579 + // we use the extended greyscale palette here, with the exception of
580 + // black and white. normal palette only has 4 greyscale shades.
581 + if (r === g && g === b) {
582 + if (r < 8) {
583 + return 16;
584 + }
585 +
586 + if (r > 248) {
587 + return 231;
588 + }
589 +
590 + return Math.round(((r - 8) / 247) * 24) + 232;
591 + }
592 +
593 + var ansi = 16
594 + + (36 * Math.round(r / 255 * 5))
595 + + (6 * Math.round(g / 255 * 5))
596 + + Math.round(b / 255 * 5);
597 +
598 + return ansi;
599 +};
600 +
601 +convert.ansi16.rgb = function (args) {
602 + var color = args % 10;
603 +
604 + // handle greyscale
605 + if (color === 0 || color === 7) {
606 + if (args > 50) {
607 + color += 3.5;
608 + }
609 +
610 + color = color / 10.5 * 255;
611 +
612 + return [color, color, color];
613 + }
614 +
615 + var mult = (~~(args > 50) + 1) * 0.5;
616 + var r = ((color & 1) * mult) * 255;
617 + var g = (((color >> 1) & 1) * mult) * 255;
618 + var b = (((color >> 2) & 1) * mult) * 255;
619 +
620 + return [r, g, b];
621 +};
622 +
623 +convert.ansi256.rgb = function (args) {
624 + // handle greyscale
625 + if (args >= 232) {
626 + var c = (args - 232) * 10 + 8;
627 + return [c, c, c];
628 + }
629 +
630 + args -= 16;
631 +
632 + var rem;
633 + var r = Math.floor(args / 36) / 5 * 255;
634 + var g = Math.floor((rem = args % 36) / 6) / 5 * 255;
635 + var b = (rem % 6) / 5 * 255;
636 +
637 + return [r, g, b];
638 +};
639 +
640 +convert.rgb.hex = function (args) {
641 + var integer = ((Math.round(args[0]) & 0xFF) << 16)
642 + + ((Math.round(args[1]) & 0xFF) << 8)
643 + + (Math.round(args[2]) & 0xFF);
644 +
645 + var string = integer.toString(16).toUpperCase();
646 + return '000000'.substring(string.length) + string;
647 +};
648 +
649 +convert.hex.rgb = function (args) {
650 + var match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);
651 + if (!match) {
652 + return [0, 0, 0];
653 + }
654 +
655 + var colorString = match[0];
656 +
657 + if (match[0].length === 3) {
658 + colorString = colorString.split('').map(function (char) {
659 + return char + char;
660 + }).join('');
661 + }
662 +
663 + var integer = parseInt(colorString, 16);
664 + var r = (integer >> 16) & 0xFF;
665 + var g = (integer >> 8) & 0xFF;
666 + var b = integer & 0xFF;
667 +
668 + return [r, g, b];
669 +};
670 +
671 +convert.rgb.hcg = function (rgb) {
672 + var r = rgb[0] / 255;
673 + var g = rgb[1] / 255;
674 + var b = rgb[2] / 255;
675 + var max = Math.max(Math.max(r, g), b);
676 + var min = Math.min(Math.min(r, g), b);
677 + var chroma = (max - min);
678 + var grayscale;
679 + var hue;
680 +
681 + if (chroma < 1) {
682 + grayscale = min / (1 - chroma);
683 + } else {
684 + grayscale = 0;
685 + }
686 +
687 + if (chroma <= 0) {
688 + hue = 0;
689 + } else
690 + if (max === r) {
691 + hue = ((g - b) / chroma) % 6;
692 + } else
693 + if (max === g) {
694 + hue = 2 + (b - r) / chroma;
695 + } else {
696 + hue = 4 + (r - g) / chroma + 4;
697 + }
698 +
699 + hue /= 6;
700 + hue %= 1;
701 +
702 + return [hue * 360, chroma * 100, grayscale * 100];
703 +};
704 +
705 +convert.hsl.hcg = function (hsl) {
706 + var s = hsl[1] / 100;
707 + var l = hsl[2] / 100;
708 + var c = 1;
709 + var f = 0;
710 +
711 + if (l < 0.5) {
712 + c = 2.0 * s * l;
713 + } else {
714 + c = 2.0 * s * (1.0 - l);
715 + }
716 +
717 + if (c < 1.0) {
718 + f = (l - 0.5 * c) / (1.0 - c);
719 + }
720 +
721 + return [hsl[0], c * 100, f * 100];
722 +};
723 +
724 +convert.hsv.hcg = function (hsv) {
725 + var s = hsv[1] / 100;
726 + var v = hsv[2] / 100;
727 +
728 + var c = s * v;
729 + var f = 0;
730 +
731 + if (c < 1.0) {
732 + f = (v - c) / (1 - c);
733 + }
734 +
735 + return [hsv[0], c * 100, f * 100];
736 +};
737 +
738 +convert.hcg.rgb = function (hcg) {
739 + var h = hcg[0] / 360;
740 + var c = hcg[1] / 100;
741 + var g = hcg[2] / 100;
742 +
743 + if (c === 0.0) {
744 + return [g * 255, g * 255, g * 255];
745 + }
746 +
747 + var pure = [0, 0, 0];
748 + var hi = (h % 1) * 6;
749 + var v = hi % 1;
750 + var w = 1 - v;
751 + var mg = 0;
752 +
753 + switch (Math.floor(hi)) {
754 + case 0:
755 + pure[0] = 1; pure[1] = v; pure[2] = 0; break;
756 + case 1:
757 + pure[0] = w; pure[1] = 1; pure[2] = 0; break;
758 + case 2:
759 + pure[0] = 0; pure[1] = 1; pure[2] = v; break;
760 + case 3:
761 + pure[0] = 0; pure[1] = w; pure[2] = 1; break;
762 + case 4:
763 + pure[0] = v; pure[1] = 0; pure[2] = 1; break;
764 + default:
765 + pure[0] = 1; pure[1] = 0; pure[2] = w;
766 + }
767 +
768 + mg = (1.0 - c) * g;
769 +
770 + return [
771 + (c * pure[0] + mg) * 255,
772 + (c * pure[1] + mg) * 255,
773 + (c * pure[2] + mg) * 255
774 + ];
775 +};
776 +
777 +convert.hcg.hsv = function (hcg) {
778 + var c = hcg[1] / 100;
779 + var g = hcg[2] / 100;
780 +
781 + var v = c + g * (1.0 - c);
782 + var f = 0;
783 +
784 + if (v > 0.0) {
785 + f = c / v;
786 + }
787 +
788 + return [hcg[0], f * 100, v * 100];
789 +};
790 +
791 +convert.hcg.hsl = function (hcg) {
792 + var c = hcg[1] / 100;
793 + var g = hcg[2] / 100;
794 +
795 + var l = g * (1.0 - c) + 0.5 * c;
796 + var s = 0;
797 +
798 + if (l > 0.0 && l < 0.5) {
799 + s = c / (2 * l);
800 + } else
801 + if (l >= 0.5 && l < 1.0) {
802 + s = c / (2 * (1 - l));
803 + }
804 +
805 + return [hcg[0], s * 100, l * 100];
806 +};
807 +
808 +convert.hcg.hwb = function (hcg) {
809 + var c = hcg[1] / 100;
810 + var g = hcg[2] / 100;
811 + var v = c + g * (1.0 - c);
812 + return [hcg[0], (v - c) * 100, (1 - v) * 100];
813 +};
814 +
815 +convert.hwb.hcg = function (hwb) {
816 + var w = hwb[1] / 100;
817 + var b = hwb[2] / 100;
818 + var v = 1 - b;
819 + var c = v - w;
820 + var g = 0;
821 +
822 + if (c < 1) {
823 + g = (v - c) / (1 - c);
824 + }
825 +
826 + return [hwb[0], c * 100, g * 100];
827 +};
828 +
829 +convert.apple.rgb = function (apple) {
830 + return [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255];
831 +};
832 +
833 +convert.rgb.apple = function (rgb) {
834 + return [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535];
835 +};
836 +
837 +convert.gray.rgb = function (args) {
838 + return [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255];
839 +};
840 +
841 +convert.gray.hsl = convert.gray.hsv = function (args) {
842 + return [0, 0, args[0]];
843 +};
844 +
845 +convert.gray.hwb = function (gray) {
846 + return [0, 100, gray[0]];
847 +};
848 +
849 +convert.gray.cmyk = function (gray) {
850 + return [0, 0, 0, gray[0]];
851 +};
852 +
853 +convert.gray.lab = function (gray) {
854 + return [gray[0], 0, 0];
855 +};
856 +
857 +convert.gray.hex = function (gray) {
858 + var val = Math.round(gray[0] / 100 * 255) & 0xFF;
859 + var integer = (val << 16) + (val << 8) + val;
860 +
861 + var string = integer.toString(16).toUpperCase();
862 + return '000000'.substring(string.length) + string;
863 +};
864 +
865 +convert.rgb.gray = function (rgb) {
866 + var val = (rgb[0] + rgb[1] + rgb[2]) / 3;
867 + return [val / 255 * 100];
868 +};
1 +var conversions = require('./conversions');
2 +var route = require('./route');
3 +
4 +var convert = {};
5 +
6 +var models = Object.keys(conversions);
7 +
8 +function wrapRaw(fn) {
9 + var wrappedFn = function (args) {
10 + if (args === undefined || args === null) {
11 + return args;
12 + }
13 +
14 + if (arguments.length > 1) {
15 + args = Array.prototype.slice.call(arguments);
16 + }
17 +
18 + return fn(args);
19 + };
20 +
21 + // preserve .conversion property if there is one
22 + if ('conversion' in fn) {
23 + wrappedFn.conversion = fn.conversion;
24 + }
25 +
26 + return wrappedFn;
27 +}
28 +
29 +function wrapRounded(fn) {
30 + var wrappedFn = function (args) {
31 + if (args === undefined || args === null) {
32 + return args;
33 + }
34 +
35 + if (arguments.length > 1) {
36 + args = Array.prototype.slice.call(arguments);
37 + }
38 +
39 + var result = fn(args);
40 +
41 + // we're assuming the result is an array here.
42 + // see notice in conversions.js; don't use box types
43 + // in conversion functions.
44 + if (typeof result === 'object') {
45 + for (var len = result.length, i = 0; i < len; i++) {
46 + result[i] = Math.round(result[i]);
47 + }
48 + }
49 +
50 + return result;
51 + };
52 +
53 + // preserve .conversion property if there is one
54 + if ('conversion' in fn) {
55 + wrappedFn.conversion = fn.conversion;
56 + }
57 +
58 + return wrappedFn;
59 +}
60 +
61 +models.forEach(function (fromModel) {
62 + convert[fromModel] = {};
63 +
64 + Object.defineProperty(convert[fromModel], 'channels', {value: conversions[fromModel].channels});
65 + Object.defineProperty(convert[fromModel], 'labels', {value: conversions[fromModel].labels});
66 +
67 + var routes = route(fromModel);
68 + var routeModels = Object.keys(routes);
69 +
70 + routeModels.forEach(function (toModel) {
71 + var fn = routes[toModel];
72 +
73 + convert[fromModel][toModel] = wrapRounded(fn);
74 + convert[fromModel][toModel].raw = wrapRaw(fn);
75 + });
76 +});
77 +
78 +module.exports = convert;
1 +{
2 + "name": "color-convert",
3 + "description": "Plain color conversion functions",
4 + "version": "1.9.3",
5 + "author": "Heather Arthur <fayearthur@gmail.com>",
6 + "license": "MIT",
7 + "repository": "Qix-/color-convert",
8 + "scripts": {
9 + "pretest": "xo",
10 + "test": "node test/basic.js"
11 + },
12 + "keywords": [
13 + "color",
14 + "colour",
15 + "convert",
16 + "converter",
17 + "conversion",
18 + "rgb",
19 + "hsl",
20 + "hsv",
21 + "hwb",
22 + "cmyk",
23 + "ansi",
24 + "ansi16"
25 + ],
26 + "files": [
27 + "index.js",
28 + "conversions.js",
29 + "css-keywords.js",
30 + "route.js"
31 + ],
32 + "xo": {
33 + "rules": {
34 + "default-case": 0,
35 + "no-inline-comments": 0,
36 + "operator-linebreak": 0
37 + }
38 + },
39 + "devDependencies": {
40 + "chalk": "1.1.1",
41 + "xo": "0.11.2"
42 + },
43 + "dependencies": {
44 + "color-name": "1.1.3"
45 + }
46 +}
1 +var conversions = require('./conversions');
2 +
3 +/*
4 + this function routes a model to all other models.
5 +
6 + all functions that are routed have a property `.conversion` attached
7 + to the returned synthetic function. This property is an array
8 + of strings, each with the steps in between the 'from' and 'to'
9 + color models (inclusive).
10 +
11 + conversions that are not possible simply are not included.
12 +*/
13 +
14 +function buildGraph() {
15 + var graph = {};
16 + // https://jsperf.com/object-keys-vs-for-in-with-closure/3
17 + var models = Object.keys(conversions);
18 +
19 + for (var len = models.length, i = 0; i < len; i++) {
20 + graph[models[i]] = {
21 + // http://jsperf.com/1-vs-infinity
22 + // micro-opt, but this is simple.
23 + distance: -1,
24 + parent: null
25 + };
26 + }
27 +
28 + return graph;
29 +}
30 +
31 +// https://en.wikipedia.org/wiki/Breadth-first_search
32 +function deriveBFS(fromModel) {
33 + var graph = buildGraph();
34 + var queue = [fromModel]; // unshift -> queue -> pop
35 +
36 + graph[fromModel].distance = 0;
37 +
38 + while (queue.length) {
39 + var current = queue.pop();
40 + var adjacents = Object.keys(conversions[current]);
41 +
42 + for (var len = adjacents.length, i = 0; i < len; i++) {
43 + var adjacent = adjacents[i];
44 + var node = graph[adjacent];
45 +
46 + if (node.distance === -1) {
47 + node.distance = graph[current].distance + 1;
48 + node.parent = current;
49 + queue.unshift(adjacent);
50 + }
51 + }
52 + }
53 +
54 + return graph;
55 +}
56 +
57 +function link(from, to) {
58 + return function (args) {
59 + return to(from(args));
60 + };
61 +}
62 +
63 +function wrapConversion(toModel, graph) {
64 + var path = [graph[toModel].parent, toModel];
65 + var fn = conversions[graph[toModel].parent][toModel];
66 +
67 + var cur = graph[toModel].parent;
68 + while (graph[cur].parent) {
69 + path.unshift(graph[cur].parent);
70 + fn = link(conversions[graph[cur].parent][cur], fn);
71 + cur = graph[cur].parent;
72 + }
73 +
74 + fn.conversion = path;
75 + return fn;
76 +}
77 +
78 +module.exports = function (fromModel) {
79 + var graph = deriveBFS(fromModel);
80 + var conversion = {};
81 +
82 + var models = Object.keys(graph);
83 + for (var len = models.length, i = 0; i < len; i++) {
84 + var toModel = models[i];
85 + var node = graph[toModel];
86 +
87 + if (node.parent === null) {
88 + // no possible conversion, or this node is the source model.
89 + continue;
90 + }
91 +
92 + conversion[toModel] = wrapConversion(toModel, graph);
93 + }
94 +
95 + return conversion;
96 +};
97 +
1 +{
2 + "env": {
3 + "browser": true,
4 + "node": true,
5 + "commonjs": true,
6 + "es6": true
7 + },
8 + "extends": "eslint:recommended",
9 + "rules": {
10 + "strict": 2,
11 + "indent": 0,
12 + "linebreak-style": 0,
13 + "quotes": 0,
14 + "semi": 0,
15 + "no-cond-assign": 1,
16 + "no-constant-condition": 1,
17 + "no-duplicate-case": 1,
18 + "no-empty": 1,
19 + "no-ex-assign": 1,
20 + "no-extra-boolean-cast": 1,
21 + "no-extra-semi": 1,
22 + "no-fallthrough": 1,
23 + "no-func-assign": 1,
24 + "no-global-assign": 1,
25 + "no-implicit-globals": 2,
26 + "no-inner-declarations": ["error", "functions"],
27 + "no-irregular-whitespace": 2,
28 + "no-loop-func": 1,
29 + "no-multi-str": 1,
30 + "no-mixed-spaces-and-tabs": 1,
31 + "no-proto": 1,
32 + "no-sequences": 1,
33 + "no-throw-literal": 1,
34 + "no-unmodified-loop-condition": 1,
35 + "no-useless-call": 1,
36 + "no-void": 1,
37 + "no-with": 2,
38 + "wrap-iife": 1,
39 + "no-redeclare": 1,
40 + "no-unused-vars": ["error", { "vars": "all", "args": "none" }],
41 + "no-sparse-arrays": 1
42 + }
43 +}
1 +//this will affect all the git repos
2 +git config --global core.excludesfile ~/.gitignore
3 +
4 +
5 +//update files since .ignore won't if already tracked
6 +git rm --cached <file>
7 +
8 +# Compiled source #
9 +###################
10 +*.com
11 +*.class
12 +*.dll
13 +*.exe
14 +*.o
15 +*.so
16 +
17 +# Packages #
18 +############
19 +# it's better to unpack these files and commit the raw source
20 +# git has its own built in compression methods
21 +*.7z
22 +*.dmg
23 +*.gz
24 +*.iso
25 +*.jar
26 +*.rar
27 +*.tar
28 +*.zip
29 +
30 +# Logs and databases #
31 +######################
32 +*.log
33 +*.sql
34 +*.sqlite
35 +
36 +# OS generated files #
37 +######################
38 +.DS_Store
39 +.DS_Store?
40 +._*
41 +.Spotlight-V100
42 +.Trashes
43 +# Icon?
44 +ehthumbs.db
45 +Thumbs.db
46 +.cache
47 +.project
48 +.settings
49 +.tmproj
50 +*.esproj
51 +nbproject
52 +
53 +# Numerous always-ignore extensions #
54 +#####################################
55 +*.diff
56 +*.err
57 +*.orig
58 +*.rej
59 +*.swn
60 +*.swo
61 +*.swp
62 +*.vi
63 +*~
64 +*.sass-cache
65 +*.grunt
66 +*.tmp
67 +
68 +# Dreamweaver added files #
69 +###########################
70 +_notes
71 +dwsync.xml
72 +
73 +# Komodo #
74 +###########################
75 +*.komodoproject
76 +.komodotools
77 +
78 +# Node #
79 +#####################
80 +node_modules
81 +
82 +# Bower #
83 +#####################
84 +bower_components
85 +
86 +# Folders to ignore #
87 +#####################
88 +.hg
89 +.svn
90 +.CVS
91 +intermediate
92 +publish
93 +.idea
94 +.graphics
95 +_test
96 +_archive
97 +uploads
98 +tmp
99 +
100 +# Vim files to ignore #
101 +#######################
102 +.VimballRecord
103 +.netrwhist
104 +
105 +bundle.*
106 +
107 +_demo
...\ No newline at end of file ...\ No newline at end of file
1 +The MIT License (MIT)
2 +Copyright (c) 2015 Dmitry Ivanov
3 +
4 +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:
5 +
6 +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 +
8 +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.
...\ No newline at end of file ...\ No newline at end of file
1 +A JSON with color names and its values. Based on http://dev.w3.org/csswg/css-color/#named-colors.
2 +
3 +[![NPM](https://nodei.co/npm/color-name.png?mini=true)](https://nodei.co/npm/color-name/)
4 +
5 +
6 +```js
7 +var colors = require('color-name');
8 +colors.red //[255,0,0]
9 +```
10 +
11 +<a href="LICENSE"><img src="https://upload.wikimedia.org/wikipedia/commons/0/0c/MIT_logo.svg" width="120"/></a>
1 +'use strict'
2 +
3 +module.exports = {
4 + "aliceblue": [240, 248, 255],
5 + "antiquewhite": [250, 235, 215],
6 + "aqua": [0, 255, 255],
7 + "aquamarine": [127, 255, 212],
8 + "azure": [240, 255, 255],
9 + "beige": [245, 245, 220],
10 + "bisque": [255, 228, 196],
11 + "black": [0, 0, 0],
12 + "blanchedalmond": [255, 235, 205],
13 + "blue": [0, 0, 255],
14 + "blueviolet": [138, 43, 226],
15 + "brown": [165, 42, 42],
16 + "burlywood": [222, 184, 135],
17 + "cadetblue": [95, 158, 160],
18 + "chartreuse": [127, 255, 0],
19 + "chocolate": [210, 105, 30],
20 + "coral": [255, 127, 80],
21 + "cornflowerblue": [100, 149, 237],
22 + "cornsilk": [255, 248, 220],
23 + "crimson": [220, 20, 60],
24 + "cyan": [0, 255, 255],
25 + "darkblue": [0, 0, 139],
26 + "darkcyan": [0, 139, 139],
27 + "darkgoldenrod": [184, 134, 11],
28 + "darkgray": [169, 169, 169],
29 + "darkgreen": [0, 100, 0],
30 + "darkgrey": [169, 169, 169],
31 + "darkkhaki": [189, 183, 107],
32 + "darkmagenta": [139, 0, 139],
33 + "darkolivegreen": [85, 107, 47],
34 + "darkorange": [255, 140, 0],
35 + "darkorchid": [153, 50, 204],
36 + "darkred": [139, 0, 0],
37 + "darksalmon": [233, 150, 122],
38 + "darkseagreen": [143, 188, 143],
39 + "darkslateblue": [72, 61, 139],
40 + "darkslategray": [47, 79, 79],
41 + "darkslategrey": [47, 79, 79],
42 + "darkturquoise": [0, 206, 209],
43 + "darkviolet": [148, 0, 211],
44 + "deeppink": [255, 20, 147],
45 + "deepskyblue": [0, 191, 255],
46 + "dimgray": [105, 105, 105],
47 + "dimgrey": [105, 105, 105],
48 + "dodgerblue": [30, 144, 255],
49 + "firebrick": [178, 34, 34],
50 + "floralwhite": [255, 250, 240],
51 + "forestgreen": [34, 139, 34],
52 + "fuchsia": [255, 0, 255],
53 + "gainsboro": [220, 220, 220],
54 + "ghostwhite": [248, 248, 255],
55 + "gold": [255, 215, 0],
56 + "goldenrod": [218, 165, 32],
57 + "gray": [128, 128, 128],
58 + "green": [0, 128, 0],
59 + "greenyellow": [173, 255, 47],
60 + "grey": [128, 128, 128],
61 + "honeydew": [240, 255, 240],
62 + "hotpink": [255, 105, 180],
63 + "indianred": [205, 92, 92],
64 + "indigo": [75, 0, 130],
65 + "ivory": [255, 255, 240],
66 + "khaki": [240, 230, 140],
67 + "lavender": [230, 230, 250],
68 + "lavenderblush": [255, 240, 245],
69 + "lawngreen": [124, 252, 0],
70 + "lemonchiffon": [255, 250, 205],
71 + "lightblue": [173, 216, 230],
72 + "lightcoral": [240, 128, 128],
73 + "lightcyan": [224, 255, 255],
74 + "lightgoldenrodyellow": [250, 250, 210],
75 + "lightgray": [211, 211, 211],
76 + "lightgreen": [144, 238, 144],
77 + "lightgrey": [211, 211, 211],
78 + "lightpink": [255, 182, 193],
79 + "lightsalmon": [255, 160, 122],
80 + "lightseagreen": [32, 178, 170],
81 + "lightskyblue": [135, 206, 250],
82 + "lightslategray": [119, 136, 153],
83 + "lightslategrey": [119, 136, 153],
84 + "lightsteelblue": [176, 196, 222],
85 + "lightyellow": [255, 255, 224],
86 + "lime": [0, 255, 0],
87 + "limegreen": [50, 205, 50],
88 + "linen": [250, 240, 230],
89 + "magenta": [255, 0, 255],
90 + "maroon": [128, 0, 0],
91 + "mediumaquamarine": [102, 205, 170],
92 + "mediumblue": [0, 0, 205],
93 + "mediumorchid": [186, 85, 211],
94 + "mediumpurple": [147, 112, 219],
95 + "mediumseagreen": [60, 179, 113],
96 + "mediumslateblue": [123, 104, 238],
97 + "mediumspringgreen": [0, 250, 154],
98 + "mediumturquoise": [72, 209, 204],
99 + "mediumvioletred": [199, 21, 133],
100 + "midnightblue": [25, 25, 112],
101 + "mintcream": [245, 255, 250],
102 + "mistyrose": [255, 228, 225],
103 + "moccasin": [255, 228, 181],
104 + "navajowhite": [255, 222, 173],
105 + "navy": [0, 0, 128],
106 + "oldlace": [253, 245, 230],
107 + "olive": [128, 128, 0],
108 + "olivedrab": [107, 142, 35],
109 + "orange": [255, 165, 0],
110 + "orangered": [255, 69, 0],
111 + "orchid": [218, 112, 214],
112 + "palegoldenrod": [238, 232, 170],
113 + "palegreen": [152, 251, 152],
114 + "paleturquoise": [175, 238, 238],
115 + "palevioletred": [219, 112, 147],
116 + "papayawhip": [255, 239, 213],
117 + "peachpuff": [255, 218, 185],
118 + "peru": [205, 133, 63],
119 + "pink": [255, 192, 203],
120 + "plum": [221, 160, 221],
121 + "powderblue": [176, 224, 230],
122 + "purple": [128, 0, 128],
123 + "rebeccapurple": [102, 51, 153],
124 + "red": [255, 0, 0],
125 + "rosybrown": [188, 143, 143],
126 + "royalblue": [65, 105, 225],
127 + "saddlebrown": [139, 69, 19],
128 + "salmon": [250, 128, 114],
129 + "sandybrown": [244, 164, 96],
130 + "seagreen": [46, 139, 87],
131 + "seashell": [255, 245, 238],
132 + "sienna": [160, 82, 45],
133 + "silver": [192, 192, 192],
134 + "skyblue": [135, 206, 235],
135 + "slateblue": [106, 90, 205],
136 + "slategray": [112, 128, 144],
137 + "slategrey": [112, 128, 144],
138 + "snow": [255, 250, 250],
139 + "springgreen": [0, 255, 127],
140 + "steelblue": [70, 130, 180],
141 + "tan": [210, 180, 140],
142 + "teal": [0, 128, 128],
143 + "thistle": [216, 191, 216],
144 + "tomato": [255, 99, 71],
145 + "turquoise": [64, 224, 208],
146 + "violet": [238, 130, 238],
147 + "wheat": [245, 222, 179],
148 + "white": [255, 255, 255],
149 + "whitesmoke": [245, 245, 245],
150 + "yellow": [255, 255, 0],
151 + "yellowgreen": [154, 205, 50]
152 +};
1 +{
2 + "name": "color-name",
3 + "version": "1.1.3",
4 + "description": "A list of color names and its values",
5 + "main": "index.js",
6 + "scripts": {
7 + "test": "node test.js"
8 + },
9 + "repository": {
10 + "type": "git",
11 + "url": "git@github.com:dfcreative/color-name.git"
12 + },
13 + "keywords": [
14 + "color-name",
15 + "color",
16 + "color-keyword",
17 + "keyword"
18 + ],
19 + "author": "DY <dfcreative@gmail.com>",
20 + "license": "MIT",
21 + "bugs": {
22 + "url": "https://github.com/dfcreative/color-name/issues"
23 + },
24 + "homepage": "https://github.com/dfcreative/color-name"
25 +}
1 +'use strict'
2 +
3 +var names = require('./');
4 +var assert = require('assert');
5 +
6 +assert.deepEqual(names.red, [255,0,0]);
7 +assert.deepEqual(names.aliceblue, [240,248,255]);
1 +language: node_js
2 +node_js:
3 + - 0.4
4 + - 0.6
1 +This software is released under the MIT license:
2 +
3 +Permission is hereby granted, free of charge, to any person obtaining a copy of
4 +this software and associated documentation files (the "Software"), to deal in
5 +the Software without restriction, including without limitation the rights to
6 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 +the Software, and to permit persons to whom the Software is furnished to do so,
8 +subject to the following conditions:
9 +
10 +The above copyright notice and this permission notice shall be included in all
11 +copies or substantial portions of the Software.
12 +
13 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1 +concat-map
2 +==========
3 +
4 +Concatenative mapdashery.
5 +
6 +[![browser support](http://ci.testling.com/substack/node-concat-map.png)](http://ci.testling.com/substack/node-concat-map)
7 +
8 +[![build status](https://secure.travis-ci.org/substack/node-concat-map.png)](http://travis-ci.org/substack/node-concat-map)
9 +
10 +example
11 +=======
12 +
13 +``` js
14 +var concatMap = require('concat-map');
15 +var xs = [ 1, 2, 3, 4, 5, 6 ];
16 +var ys = concatMap(xs, function (x) {
17 + return x % 2 ? [ x - 0.1, x, x + 0.1 ] : [];
18 +});
19 +console.dir(ys);
20 +```
21 +
22 +***
23 +
24 +```
25 +[ 0.9, 1, 1.1, 2.9, 3, 3.1, 4.9, 5, 5.1 ]
26 +```
27 +
28 +methods
29 +=======
30 +
31 +``` js
32 +var concatMap = require('concat-map')
33 +```
34 +
35 +concatMap(xs, fn)
36 +-----------------
37 +
38 +Return an array of concatenated elements by calling `fn(x, i)` for each element
39 +`x` and each index `i` in the array `xs`.
40 +
41 +When `fn(x, i)` returns an array, its result will be concatenated with the
42 +result array. If `fn(x, i)` returns anything else, that value will be pushed
43 +onto the end of the result array.
44 +
45 +install
46 +=======
47 +
48 +With [npm](http://npmjs.org) do:
49 +
50 +```
51 +npm install concat-map
52 +```
53 +
54 +license
55 +=======
56 +
57 +MIT
58 +
59 +notes
60 +=====
61 +
62 +This module was written while sitting high above the ground in a tree.
1 +var concatMap = require('../');
2 +var xs = [ 1, 2, 3, 4, 5, 6 ];
3 +var ys = concatMap(xs, function (x) {
4 + return x % 2 ? [ x - 0.1, x, x + 0.1 ] : [];
5 +});
6 +console.dir(ys);
1 +module.exports = function (xs, fn) {
2 + var res = [];
3 + for (var i = 0; i < xs.length; i++) {
4 + var x = fn(xs[i], i);
5 + if (isArray(x)) res.push.apply(res, x);
6 + else res.push(x);
7 + }
8 + return res;
9 +};
10 +
11 +var isArray = Array.isArray || function (xs) {
12 + return Object.prototype.toString.call(xs) === '[object Array]';
13 +};
1 +{
2 + "name" : "concat-map",
3 + "description" : "concatenative mapdashery",
4 + "version" : "0.0.1",
5 + "repository" : {
6 + "type" : "git",
7 + "url" : "git://github.com/substack/node-concat-map.git"
8 + },
9 + "main" : "index.js",
10 + "keywords" : [
11 + "concat",
12 + "concatMap",
13 + "map",
14 + "functional",
15 + "higher-order"
16 + ],
17 + "directories" : {
18 + "example" : "example",
19 + "test" : "test"
20 + },
21 + "scripts" : {
22 + "test" : "tape test/*.js"
23 + },
24 + "devDependencies" : {
25 + "tape" : "~2.4.0"
26 + },
27 + "license" : "MIT",
28 + "author" : {
29 + "name" : "James Halliday",
30 + "email" : "mail@substack.net",
31 + "url" : "http://substack.net"
32 + },
33 + "testling" : {
34 + "files" : "test/*.js",
35 + "browsers" : {
36 + "ie" : [ 6, 7, 8, 9 ],
37 + "ff" : [ 3.5, 10, 15.0 ],
38 + "chrome" : [ 10, 22 ],
39 + "safari" : [ 5.1 ],
40 + "opera" : [ 12 ]
41 + }
42 + }
43 +}
1 +var concatMap = require('../');
2 +var test = require('tape');
3 +
4 +test('empty or not', function (t) {
5 + var xs = [ 1, 2, 3, 4, 5, 6 ];
6 + var ixes = [];
7 + var ys = concatMap(xs, function (x, ix) {
8 + ixes.push(ix);
9 + return x % 2 ? [ x - 0.1, x, x + 0.1 ] : [];
10 + });
11 + t.same(ys, [ 0.9, 1, 1.1, 2.9, 3, 3.1, 4.9, 5, 5.1 ]);
12 + t.same(ixes, [ 0, 1, 2, 3, 4, 5 ]);
13 + t.end();
14 +});
15 +
16 +test('always something', function (t) {
17 + var xs = [ 'a', 'b', 'c', 'd' ];
18 + var ys = concatMap(xs, function (x) {
19 + return x === 'b' ? [ 'B', 'B', 'B' ] : [ x ];
20 + });
21 + t.same(ys, [ 'a', 'B', 'B', 'B', 'c', 'd' ]);
22 + t.end();
23 +});
24 +
25 +test('scalars', function (t) {
26 + var xs = [ 'a', 'b', 'c', 'd' ];
27 + var ys = concatMap(xs, function (x) {
28 + return x === 'b' ? [ 'B', 'B', 'B' ] : x;
29 + });
30 + t.same(ys, [ 'a', 'B', 'B', 'B', 'c', 'd' ]);
31 + t.end();
32 +});
33 +
34 +test('undefs', function (t) {
35 + var xs = [ 'a', 'b', 'c', 'd' ];
36 + var ys = concatMap(xs, function () {});
37 + t.same(ys, [ undefined, undefined, undefined, undefined ]);
38 + t.end();
39 +});
1 +
2 + Apache License
3 + Version 2.0, January 2004
4 + http://www.apache.org/licenses/
5 +
6 + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 +
8 + 1. Definitions.
9 +
10 + "License" shall mean the terms and conditions for use, reproduction,
11 + and distribution as defined by Sections 1 through 9 of this document.
12 +
13 + "Licensor" shall mean the copyright owner or entity authorized by
14 + the copyright owner that is granting the License.
15 +
16 + "Legal Entity" shall mean the union of the acting entity and all
17 + other entities that control, are controlled by, or are under common
18 + control with that entity. For the purposes of this definition,
19 + "control" means (i) the power, direct or indirect, to cause the
20 + direction or management of such entity, whether by contract or
21 + otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 + outstanding shares, or (iii) beneficial ownership of such entity.
23 +
24 + "You" (or "Your") shall mean an individual or Legal Entity
25 + exercising permissions granted by this License.
26 +
27 + "Source" form shall mean the preferred form for making modifications,
28 + including but not limited to software source code, documentation
29 + source, and configuration files.
30 +
31 + "Object" form shall mean any form resulting from mechanical
32 + transformation or translation of a Source form, including but
33 + not limited to compiled object code, generated documentation,
34 + and conversions to other media types.
35 +
36 + "Work" shall mean the work of authorship, whether in Source or
37 + Object form, made available under the License, as indicated by a
38 + copyright notice that is included in or attached to the work
39 + (an example is provided in the Appendix below).
40 +
41 + "Derivative Works" shall mean any work, whether in Source or Object
42 + form, that is based on (or derived from) the Work and for which the
43 + editorial revisions, annotations, elaborations, or other modifications
44 + represent, as a whole, an original work of authorship. For the purposes
45 + of this License, Derivative Works shall not include works that remain
46 + separable from, or merely link (or bind by name) to the interfaces of,
47 + the Work and Derivative Works thereof.
48 +
49 + "Contribution" shall mean any work of authorship, including
50 + the original version of the Work and any modifications or additions
51 + to that Work or Derivative Works thereof, that is intentionally
52 + submitted to Licensor for inclusion in the Work by the copyright owner
53 + or by an individual or Legal Entity authorized to submit on behalf of
54 + the copyright owner. For the purposes of this definition, "submitted"
55 + means any form of electronic, verbal, or written communication sent
56 + to the Licensor or its representatives, including but not limited to
57 + communication on electronic mailing lists, source code control systems,
58 + and issue tracking systems that are managed by, or on behalf of, the
59 + Licensor for the purpose of discussing and improving the Work, but
60 + excluding communication that is conspicuously marked or otherwise
61 + designated in writing by the copyright owner as "Not a Contribution."
62 +
63 + "Contributor" shall mean Licensor and any individual or Legal Entity
64 + on behalf of whom a Contribution has been received by Licensor and
65 + subsequently incorporated within the Work.
66 +
67 + 2. Grant of Copyright License. Subject to the terms and conditions of
68 + this License, each Contributor hereby grants to You a perpetual,
69 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 + copyright license to reproduce, prepare Derivative Works of,
71 + publicly display, publicly perform, sublicense, and distribute the
72 + Work and such Derivative Works in Source or Object form.
73 +
74 + 3. Grant of Patent License. Subject to the terms and conditions of
75 + this License, each Contributor hereby grants to You a perpetual,
76 + worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 + (except as stated in this section) patent license to make, have made,
78 + use, offer to sell, sell, import, and otherwise transfer the Work,
79 + where such license applies only to those patent claims licensable
80 + by such Contributor that are necessarily infringed by their
81 + Contribution(s) alone or by combination of their Contribution(s)
82 + with the Work to which such Contribution(s) was submitted. If You
83 + institute patent litigation against any entity (including a
84 + cross-claim or counterclaim in a lawsuit) alleging that the Work
85 + or a Contribution incorporated within the Work constitutes direct
86 + or contributory patent infringement, then any patent licenses
87 + granted to You under this License for that Work shall terminate
88 + as of the date such litigation is filed.
89 +
90 + 4. Redistribution. You may reproduce and distribute copies of the
91 + Work or Derivative Works thereof in any medium, with or without
92 + modifications, and in Source or Object form, provided that You
93 + meet the following conditions:
94 +
95 + (a) You must give any other recipients of the Work or
96 + Derivative Works a copy of this License; and
97 +
98 + (b) You must cause any modified files to carry prominent notices
99 + stating that You changed the files; and
100 +
101 + (c) You must retain, in the Source form of any Derivative Works
102 + that You distribute, all copyright, patent, trademark, and
103 + attribution notices from the Source form of the Work,
104 + excluding those notices that do not pertain to any part of
105 + the Derivative Works; and
106 +
107 + (d) If the Work includes a "NOTICE" text file as part of its
108 + distribution, then any Derivative Works that You distribute must
109 + include a readable copy of the attribution notices contained
110 + within such NOTICE file, excluding those notices that do not
111 + pertain to any part of the Derivative Works, in at least one
112 + of the following places: within a NOTICE text file distributed
113 + as part of the Derivative Works; within the Source form or
114 + documentation, if provided along with the Derivative Works; or,
115 + within a display generated by the Derivative Works, if and
116 + wherever such third-party notices normally appear. The contents
117 + of the NOTICE file are for informational purposes only and
118 + do not modify the License. You may add Your own attribution
119 + notices within Derivative Works that You distribute, alongside
120 + or as an addendum to the NOTICE text from the Work, provided
121 + that such additional attribution notices cannot be construed
122 + as modifying the License.
123 +
124 + You may add Your own copyright statement to Your modifications and
125 + may provide additional or different license terms and conditions
126 + for use, reproduction, or distribution of Your modifications, or
127 + for any such Derivative Works as a whole, provided Your use,
128 + reproduction, and distribution of the Work otherwise complies with
129 + the conditions stated in this License.
130 +
131 + 5. Submission of Contributions. Unless You explicitly state otherwise,
132 + any Contribution intentionally submitted for inclusion in the Work
133 + by You to the Licensor shall be under the terms and conditions of
134 + this License, without any additional terms or conditions.
135 + Notwithstanding the above, nothing herein shall supersede or modify
136 + the terms of any separate license agreement you may have executed
137 + with Licensor regarding such Contributions.
138 +
139 + 6. Trademarks. This License does not grant permission to use the trade
140 + names, trademarks, service marks, or product names of the Licensor,
141 + except as required for reasonable and customary use in describing the
142 + origin of the Work and reproducing the content of the NOTICE file.
143 +
144 + 7. Disclaimer of Warranty. Unless required by applicable law or
145 + agreed to in writing, Licensor provides the Work (and each
146 + Contributor provides its Contributions) on an "AS IS" BASIS,
147 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 + implied, including, without limitation, any warranties or conditions
149 + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 + PARTICULAR PURPOSE. You are solely responsible for determining the
151 + appropriateness of using or redistributing the Work and assume any
152 + risks associated with Your exercise of permissions under this License.
153 +
154 + 8. Limitation of Liability. In no event and under no legal theory,
155 + whether in tort (including negligence), contract, or otherwise,
156 + unless required by applicable law (such as deliberate and grossly
157 + negligent acts) or agreed to in writing, shall any Contributor be
158 + liable to You for damages, including any direct, indirect, special,
159 + incidental, or consequential damages of any character arising as a
160 + result of this License or out of the use or inability to use the
161 + Work (including but not limited to damages for loss of goodwill,
162 + work stoppage, computer failure or malfunction, or any and all
163 + other commercial damages or losses), even if such Contributor
164 + has been advised of the possibility of such damages.
165 +
166 + 9. Accepting Warranty or Additional Liability. While redistributing
167 + the Work or Derivative Works thereof, You may choose to offer,
168 + and charge a fee for, acceptance of support, warranty, indemnity,
169 + or other liability obligations and/or rights consistent with this
170 + License. However, in accepting such obligations, You may act only
171 + on Your own behalf and on Your sole responsibility, not on behalf
172 + of any other Contributor, and only if You agree to indemnify,
173 + defend, and hold each Contributor harmless for any liability
174 + incurred by, or claims asserted against, such Contributor by reason
175 + of your accepting any such warranty or additional liability.
176 +
177 + END OF TERMS AND CONDITIONS
178 +
179 + APPENDIX: How to apply the Apache License to your work.
180 +
181 + To apply the Apache License to your work, attach the following
182 + boilerplate notice, with the fields enclosed by brackets "[]"
183 + replaced with your own identifying information. (Don't include
184 + the brackets!) The text should be enclosed in the appropriate
185 + comment syntax for the file format. We also recommend that a
186 + file or class name and description of purpose be included on the
187 + same "printed page" as the copyright notice for easier
188 + identification within third-party archives.
189 +
190 + Copyright [yyyy] [name of copyright owner]
191 +
192 + Licensed under the Apache License, Version 2.0 (the "License");
193 + you may not use this file except in compliance with the License.
194 + You may obtain a copy of the License at
195 +
196 + http://www.apache.org/licenses/LICENSE-2.0
197 +
198 + Unless required by applicable law or agreed to in writing, software
199 + distributed under the License is distributed on an "AS IS" BASIS,
200 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 + See the License for the specific language governing permissions and
202 + limitations under the License.
1 +Embedded JavaScript templates<br/>
2 +[![Build Status](https://img.shields.io/travis/mde/ejs/master.svg?style=flat)](https://travis-ci.org/mde/ejs)
3 +[![Developing Dependencies](https://img.shields.io/david/dev/mde/ejs.svg?style=flat)](https://david-dm.org/mde/ejs?type=dev)
4 +[![Known Vulnerabilities](https://snyk.io/test/npm/ejs/badge.svg?style=flat)](https://snyk.io/test/npm/ejs)
5 +=============================
6 +
7 +## Installation
8 +
9 +```bash
10 +$ npm install ejs
11 +```
12 +
13 +## Features
14 +
15 + * Control flow with `<% %>`
16 + * Escaped output with `<%= %>` (escape function configurable)
17 + * Unescaped raw output with `<%- %>`
18 + * Newline-trim mode ('newline slurping') with `-%>` ending tag
19 + * Whitespace-trim mode (slurp all whitespace) for control flow with `<%_ _%>`
20 + * Custom delimiters (e.g. `[? ?]` instead of `<% %>`)
21 + * Includes
22 + * Client-side support
23 + * Static caching of intermediate JavaScript
24 + * Static caching of templates
25 + * Complies with the [Express](http://expressjs.com) view system
26 +
27 +## Example
28 +
29 +```ejs
30 +<% if (user) { %>
31 + <h2><%= user.name %></h2>
32 +<% } %>
33 +```
34 +
35 +Try EJS online at: https://ionicabizau.github.io/ejs-playground/.
36 +
37 +## Basic usage
38 +
39 +```javascript
40 +let template = ejs.compile(str, options);
41 +template(data);
42 +// => Rendered HTML string
43 +
44 +ejs.render(str, data, options);
45 +// => Rendered HTML string
46 +
47 +ejs.renderFile(filename, data, options, function(err, str){
48 + // str => Rendered HTML string
49 +});
50 +```
51 +
52 +It is also possible to use `ejs.render(dataAndOptions);` where you pass
53 +everything in a single object. In that case, you'll end up with local variables
54 +for all the passed options. However, be aware that your code could break if we
55 +add an option with the same name as one of your data object's properties.
56 +Therefore, we do not recommend using this shortcut.
57 +
58 +### Options
59 +
60 + - `cache` Compiled functions are cached, requires `filename`
61 + - `filename` The name of the file being rendered. Not required if you
62 + are using `renderFile()`. Used by `cache` to key caches, and for includes.
63 + - `root` Set project root for includes with an absolute path (e.g, /file.ejs).
64 + Can be array to try to resolve include from multiple directories.
65 + - `views` An array of paths to use when resolving includes with relative paths.
66 + - `context` Function execution context
67 + - `compileDebug` When `false` no debug instrumentation is compiled
68 + - `client` When `true`, compiles a function that can be rendered
69 + in the browser without needing to load the EJS Runtime
70 + ([ejs.min.js](https://github.com/mde/ejs/releases/latest)).
71 + - `delimiter` Character to use for inner delimiter, by default '%'
72 + - `openDelimiter` Character to use for opening delimiter, by default '<'
73 + - `closeDelimiter` Character to use for closing delimiter, by default '>'
74 + - `debug` Outputs generated function body
75 + - `strict` When set to `true`, generated function is in strict mode
76 + - `_with` Whether or not to use `with() {}` constructs. If `false`
77 + then the locals will be stored in the `locals` object. Set to `false` in strict mode.
78 + - `destructuredLocals` An array of local variables that are always destructured from
79 + the locals object, available even in strict mode.
80 + - `localsName` Name to use for the object storing local variables when not using
81 + `with` Defaults to `locals`
82 + - `rmWhitespace` Remove all safe-to-remove whitespace, including leading
83 + and trailing whitespace. It also enables a safer version of `-%>` line
84 + slurping for all scriptlet tags (it does not strip new lines of tags in
85 + the middle of a line).
86 + - `escape` The escaping function used with `<%=` construct. It is
87 + used in rendering and is `.toString()`ed in the generation of client functions.
88 + (By default escapes XML).
89 + - `outputFunctionName` Set to a string (e.g., 'echo' or 'print') for a function to print
90 + output inside scriptlet tags.
91 + - `async` When `true`, EJS will use an async function for rendering. (Depends
92 + on async/await support in the JS runtime.
93 + - `includer` Custom function to handle EJS includes, receives `(originalPath, parsedPath)`
94 + parameters, where `originalPath` is the path in include as-is and `parsedPath` is the
95 + previously resolved path. Should return an object `{ filename, template }`,
96 + you may return only one of the properties, where `filename` is the final parsed path and `template`
97 + is the included content.
98 +
99 +This project uses [JSDoc](http://usejsdoc.org/). For the full public API
100 +documentation, clone the repository and run `jake doc`. This will run JSDoc
101 +with the proper options and output the documentation to `out/`. If you want
102 +the both the public & private API docs, run `jake devdoc` instead.
103 +
104 +### Tags
105 +
106 + - `<%` 'Scriptlet' tag, for control-flow, no output
107 + - `<%_` 'Whitespace Slurping' Scriptlet tag, strips all whitespace before it
108 + - `<%=` Outputs the value into the template (escaped)
109 + - `<%-` Outputs the unescaped value into the template
110 + - `<%#` Comment tag, no execution, no output
111 + - `<%%` Outputs a literal '<%'
112 + - `%%>` Outputs a literal '%>'
113 + - `%>` Plain ending tag
114 + - `-%>` Trim-mode ('newline slurp') tag, trims following newline
115 + - `_%>` 'Whitespace Slurping' ending tag, removes all whitespace after it
116 +
117 +For the full syntax documentation, please see [docs/syntax.md](https://github.com/mde/ejs/blob/master/docs/syntax.md).
118 +
119 +### Includes
120 +
121 +Includes either have to be an absolute path, or, if not, are assumed as
122 +relative to the template with the `include` call. For example if you are
123 +including `./views/user/show.ejs` from `./views/users.ejs` you would
124 +use `<%- include('user/show') %>`.
125 +
126 +You must specify the `filename` option for the template with the `include`
127 +call unless you are using `renderFile()`.
128 +
129 +You'll likely want to use the raw output tag (`<%-`) with your include to avoid
130 +double-escaping the HTML output.
131 +
132 +```ejs
133 +<ul>
134 + <% users.forEach(function(user){ %>
135 + <%- include('user/show', {user: user}) %>
136 + <% }); %>
137 +</ul>
138 +```
139 +
140 +Includes are inserted at runtime, so you can use variables for the path in the
141 +`include` call (for example `<%- include(somePath) %>`). Variables in your
142 +top-level data object are available to all your includes, but local variables
143 +need to be passed down.
144 +
145 +NOTE: Include preprocessor directives (`<% include user/show %>`) are
146 +not supported in v3.0+.
147 +
148 +## Custom delimiters
149 +
150 +Custom delimiters can be applied on a per-template basis, or globally:
151 +
152 +```javascript
153 +let ejs = require('ejs'),
154 + users = ['geddy', 'neil', 'alex'];
155 +
156 +// Just one template
157 +ejs.render('<p>[?= users.join(" | "); ?]</p>', {users: users}, {delimiter: '?', openDelimiter: '[', closeDelimiter: ']'});
158 +// => '<p>geddy | neil | alex</p>'
159 +
160 +// Or globally
161 +ejs.delimiter = '?';
162 +ejs.openDelimiter = '[';
163 +ejs.closeDelimiter = ']';
164 +ejs.render('<p>[?= users.join(" | "); ?]</p>', {users: users});
165 +// => '<p>geddy | neil | alex</p>'
166 +```
167 +
168 +### Caching
169 +
170 +EJS ships with a basic in-process cache for caching the intermediate JavaScript
171 +functions used to render templates. It's easy to plug in LRU caching using
172 +Node's `lru-cache` library:
173 +
174 +```javascript
175 +let ejs = require('ejs'),
176 + LRU = require('lru-cache');
177 +ejs.cache = LRU(100); // LRU cache with 100-item limit
178 +```
179 +
180 +If you want to clear the EJS cache, call `ejs.clearCache`. If you're using the
181 +LRU cache and need a different limit, simple reset `ejs.cache` to a new instance
182 +of the LRU.
183 +
184 +### Custom file loader
185 +
186 +The default file loader is `fs.readFileSync`, if you want to customize it, you can set ejs.fileLoader.
187 +
188 +```javascript
189 +let ejs = require('ejs');
190 +let myFileLoad = function (filePath) {
191 + return 'myFileLoad: ' + fs.readFileSync(filePath);
192 +};
193 +
194 +ejs.fileLoader = myFileLoad;
195 +```
196 +
197 +With this feature, you can preprocess the template before reading it.
198 +
199 +### Layouts
200 +
201 +EJS does not specifically support blocks, but layouts can be implemented by
202 +including headers and footers, like so:
203 +
204 +
205 +```ejs
206 +<%- include('header') -%>
207 +<h1>
208 + Title
209 +</h1>
210 +<p>
211 + My page
212 +</p>
213 +<%- include('footer') -%>
214 +```
215 +
216 +## Client-side support
217 +
218 +Go to the [Latest Release](https://github.com/mde/ejs/releases/latest), download
219 +`./ejs.js` or `./ejs.min.js`. Alternately, you can compile it yourself by cloning
220 +the repository and running `jake build` (or `$(npm bin)/jake build` if jake is
221 +not installed globally).
222 +
223 +Include one of these files on your page, and `ejs` should be available globally.
224 +
225 +### Example
226 +
227 +```html
228 +<div id="output"></div>
229 +<script src="ejs.min.js"></script>
230 +<script>
231 + let people = ['geddy', 'neil', 'alex'],
232 + html = ejs.render('<%= people.join(", "); %>', {people: people});
233 + // With jQuery:
234 + $('#output').html(html);
235 + // Vanilla JS:
236 + document.getElementById('output').innerHTML = html;
237 +</script>
238 +```
239 +
240 +### Caveats
241 +
242 +Most of EJS will work as expected; however, there are a few things to note:
243 +
244 +1. Obviously, since you do not have access to the filesystem, `ejs.renderFile()` won't work.
245 +2. For the same reason, `include`s do not work unless you use an `include callback`. Here is an example:
246 + ```javascript
247 + let str = "Hello <%= include('file', {person: 'John'}); %>",
248 + fn = ejs.compile(str, {client: true});
249 +
250 + fn(data, null, function(path, d){ // include callback
251 + // path -> 'file'
252 + // d -> {person: 'John'}
253 + // Put your code here
254 + // Return the contents of file as a string
255 + }); // returns rendered string
256 + ```
257 +
258 +See the [examples folder](https://github.com/mde/ejs/tree/master/examples) for more details.
259 +
260 +## CLI
261 +
262 +EJS ships with a full-featured CLI. Options are similar to those used in JavaScript code:
263 +
264 + - `-o / --output-file FILE` Write the rendered output to FILE rather than stdout.
265 + - `-f / --data-file FILE` Must be JSON-formatted. Use parsed input from FILE as data for rendering.
266 + - `-i / --data-input STRING` Must be JSON-formatted and URI-encoded. Use parsed input from STRING as data for rendering.
267 + - `-m / --delimiter CHARACTER` Use CHARACTER with angle brackets for open/close (defaults to %).
268 + - `-p / --open-delimiter CHARACTER` Use CHARACTER instead of left angle bracket to open.
269 + - `-c / --close-delimiter CHARACTER` Use CHARACTER instead of right angle bracket to close.
270 + - `-s / --strict` When set to `true`, generated function is in strict mode
271 + - `-n / --no-with` Use 'locals' object for vars rather than using `with` (implies --strict).
272 + - `-l / --locals-name` Name to use for the object storing local variables when not using `with`.
273 + - `-w / --rm-whitespace` Remove all safe-to-remove whitespace, including leading and trailing whitespace.
274 + - `-d / --debug` Outputs generated function body
275 + - `-h / --help` Display this help message.
276 + - `-V/v / --version` Display the EJS version.
277 +
278 +Here are some examples of usage:
279 +
280 +```shell
281 +$ ejs -p [ -c ] ./template_file.ejs -o ./output.html
282 +$ ejs ./test/fixtures/user.ejs name=Lerxst
283 +$ ejs -n -l _ ./some_template.ejs -f ./data_file.json
284 +```
285 +
286 +### Data input
287 +
288 +There is a variety of ways to pass the CLI data for rendering.
289 +
290 +Stdin:
291 +
292 +```shell
293 +$ ./test/fixtures/user_data.json | ejs ./test/fixtures/user.ejs
294 +$ ejs ./test/fixtures/user.ejs < test/fixtures/user_data.json
295 +```
296 +
297 +A data file:
298 +
299 +```shell
300 +$ ejs ./test/fixtures/user.ejs -f ./user_data.json
301 +```
302 +
303 +A command-line option (must be URI-encoded):
304 +
305 +```shell
306 +./bin/cli.js -i %7B%22name%22%3A%20%22foo%22%7D ./test/fixtures/user.ejs
307 +```
308 +
309 +Or, passing values directly at the end of the invocation:
310 +
311 +```shell
312 +./bin/cli.js -m $ ./test/fixtures/user.ejs name=foo
313 +```
314 +
315 +### Output
316 +
317 +The CLI by default send output to stdout, but you can use the `-o` or `--output-file`
318 +flag to specify a target file to send the output to.
319 +
320 +## IDE Integration with Syntax Highlighting
321 +
322 +VSCode:Javascript EJS by *DigitalBrainstem*
323 +
324 +## Related projects
325 +
326 +There are a number of implementations of EJS:
327 +
328 + * TJ's implementation, the v1 of this library: https://github.com/tj/ejs
329 + * EJS Embedded JavaScript Framework on Google Code: https://code.google.com/p/embeddedjavascript/
330 + * Sam Stephenson's Ruby implementation: https://rubygems.org/gems/ejs
331 + * Erubis, an ERB implementation which also runs JavaScript: http://www.kuwata-lab.com/erubis/users-guide.04.html#lang-javascript
332 + * DigitalBrainstem EJS Language support: https://github.com/Digitalbrainstem/ejs-grammar
333 +
334 +## License
335 +
336 +Licensed under the Apache License, Version 2.0
337 +(<http://www.apache.org/licenses/LICENSE-2.0>)
338 +
339 +- - -
340 +EJS Embedded JavaScript templates copyright 2112
341 +mde@fleegix.org.
1 +#!/usr/bin/env node
2 +/*
3 + * EJS Embedded JavaScript templates
4 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
5 + *
6 + * Licensed under the Apache License, Version 2.0 (the "License");
7 + * you may not use this file except in compliance with the License.
8 + * You may obtain a copy of the License at
9 + *
10 + * http://www.apache.org/licenses/LICENSE-2.0
11 + *
12 + * Unless required by applicable law or agreed to in writing, software
13 + * distributed under the License is distributed on an "AS IS" BASIS,
14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 + * See the License for the specific language governing permissions and
16 + * limitations under the License.
17 + *
18 +*/
19 +
20 +
21 +let program = require('jake').program;
22 +delete global.jake; // NO NOT WANT
23 +program.setTaskNames = function (n) { this.taskNames = n; };
24 +
25 +let ejs = require('../lib/ejs');
26 +let { hyphenToCamel } = require('../lib/utils');
27 +let fs = require('fs');
28 +let args = process.argv.slice(2);
29 +let usage = fs.readFileSync(`${__dirname}/../usage.txt`).toString();
30 +
31 +const CLI_OPTS = [
32 + { full: 'output-file',
33 + abbr: 'o',
34 + expectValue: true,
35 + },
36 + { full: 'data-file',
37 + abbr: 'f',
38 + expectValue: true,
39 + },
40 + { full: 'data-input',
41 + abbr: 'i',
42 + expectValue: true,
43 + },
44 + { full: 'delimiter',
45 + abbr: 'm',
46 + expectValue: true,
47 + passThrough: true,
48 + },
49 + { full: 'open-delimiter',
50 + abbr: 'p',
51 + expectValue: true,
52 + passThrough: true,
53 + },
54 + { full: 'close-delimiter',
55 + abbr: 'c',
56 + expectValue: true,
57 + passThrough: true,
58 + },
59 + { full: 'strict',
60 + abbr: 's',
61 + expectValue: false,
62 + allowValue: false,
63 + passThrough: true,
64 + },
65 + { full: 'no-with',
66 + abbr: 'n',
67 + expectValue: false,
68 + allowValue: false,
69 + },
70 + { full: 'locals-name',
71 + abbr: 'l',
72 + expectValue: true,
73 + passThrough: true,
74 + },
75 + { full: 'rm-whitespace',
76 + abbr: 'w',
77 + expectValue: false,
78 + allowValue: false,
79 + passThrough: true,
80 + },
81 + { full: 'debug',
82 + abbr: 'd',
83 + expectValue: false,
84 + allowValue: false,
85 + passThrough: true,
86 + },
87 + { full: 'help',
88 + abbr: 'h',
89 + passThrough: true,
90 + },
91 + { full: 'version',
92 + abbr: 'V',
93 + passThrough: true,
94 + },
95 + // Alias lowercase v
96 + { full: 'version',
97 + abbr: 'v',
98 + passThrough: true,
99 + },
100 +];
101 +
102 +let preempts = {
103 + version: function () {
104 + program.die(ejs.VERSION);
105 + },
106 + help: function () {
107 + program.die(usage);
108 + }
109 +};
110 +
111 +let stdin = '';
112 +process.stdin.setEncoding('utf8');
113 +process.stdin.on('readable', () => {
114 + let chunk;
115 + while ((chunk = process.stdin.read()) !== null) {
116 + stdin += chunk;
117 + }
118 +});
119 +
120 +function run() {
121 +
122 + program.availableOpts = CLI_OPTS;
123 + program.parseArgs(args);
124 +
125 + let templatePath = program.taskNames[0];
126 + let pVals = program.envVars;
127 + let pOpts = {};
128 +
129 + for (let p in program.opts) {
130 + let name = hyphenToCamel(p);
131 + pOpts[name] = program.opts[p];
132 + }
133 +
134 + let opts = {};
135 + let vals = {};
136 +
137 + // Same-named 'passthrough' opts
138 + CLI_OPTS.forEach((opt) => {
139 + let optName = hyphenToCamel(opt.full);
140 + if (opt.passThrough && typeof pOpts[optName] != 'undefined') {
141 + opts[optName] = pOpts[optName];
142 + }
143 + });
144 +
145 + // Bail out for help/version
146 + for (let p in opts) {
147 + if (preempts[p]) {
148 + return preempts[p]();
149 + }
150 + }
151 +
152 + // Default to having views relative from the current working directory
153 + opts.views = ['.'];
154 +
155 + // Ensure there's a template to render
156 + if (!templatePath) {
157 + throw new Error('Please provide a template path. (Run ejs -h for help)');
158 + }
159 +
160 + if (opts.strict) {
161 + pOpts.noWith = true;
162 + }
163 + if (pOpts.noWith) {
164 + opts._with = false;
165 + }
166 +
167 + // Grab and parse any input data, in order of precedence:
168 + // 1. Stdin
169 + // 2. CLI arg via -i
170 + // 3. Data file via -f
171 + // Any individual vals passed at the end (e.g., foo=bar) will override
172 + // any vals previously set
173 + let input;
174 + let err = new Error('Please do not pass data multiple ways. Pick one of stdin, -f, or -i.');
175 + if (stdin) {
176 + input = stdin;
177 + }
178 + else if (pOpts.dataInput) {
179 + if (input) {
180 + throw err;
181 + }
182 + input = decodeURIComponent(pOpts.dataInput);
183 + }
184 + else if (pOpts.dataFile) {
185 + if (input) {
186 + throw err;
187 + }
188 + input = fs.readFileSync(pOpts.dataFile).toString();
189 + }
190 +
191 + if (input) {
192 + vals = JSON.parse(input);
193 + }
194 +
195 + // Override / set any individual values passed from the command line
196 + for (let p in pVals) {
197 + vals[p] = pVals[p];
198 + }
199 +
200 + let template = fs.readFileSync(templatePath).toString();
201 + let output = ejs.render(template, vals, opts);
202 + if (pOpts.outputFile) {
203 + fs.writeFileSync(pOpts.outputFile, output);
204 + }
205 + else {
206 + process.stdout.write(output);
207 + }
208 + process.exit();
209 +}
210 +
211 +// Defer execution so that stdin can be read if necessary
212 +setImmediate(run);
1 +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.ejs = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
2 +/*
3 + * EJS Embedded JavaScript templates
4 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
5 + *
6 + * Licensed under the Apache License, Version 2.0 (the "License");
7 + * you may not use this file except in compliance with the License.
8 + * You may obtain a copy of the License at
9 + *
10 + * http://www.apache.org/licenses/LICENSE-2.0
11 + *
12 + * Unless required by applicable law or agreed to in writing, software
13 + * distributed under the License is distributed on an "AS IS" BASIS,
14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 + * See the License for the specific language governing permissions and
16 + * limitations under the License.
17 + *
18 +*/
19 +
20 +'use strict';
21 +
22 +/**
23 + * @file Embedded JavaScript templating engine. {@link http://ejs.co}
24 + * @author Matthew Eernisse <mde@fleegix.org>
25 + * @author Tiancheng "Timothy" Gu <timothygu99@gmail.com>
26 + * @project EJS
27 + * @license {@link http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0}
28 + */
29 +
30 +/**
31 + * EJS internal functions.
32 + *
33 + * Technically this "module" lies in the same file as {@link module:ejs}, for
34 + * the sake of organization all the private functions re grouped into this
35 + * module.
36 + *
37 + * @module ejs-internal
38 + * @private
39 + */
40 +
41 +/**
42 + * Embedded JavaScript templating engine.
43 + *
44 + * @module ejs
45 + * @public
46 + */
47 +
48 +var fs = require('fs');
49 +var path = require('path');
50 +var utils = require('./utils');
51 +
52 +var scopeOptionWarned = false;
53 +/** @type {string} */
54 +var _VERSION_STRING = require('../package.json').version;
55 +var _DEFAULT_OPEN_DELIMITER = '<';
56 +var _DEFAULT_CLOSE_DELIMITER = '>';
57 +var _DEFAULT_DELIMITER = '%';
58 +var _DEFAULT_LOCALS_NAME = 'locals';
59 +var _NAME = 'ejs';
60 +var _REGEX_STRING = '(<%%|%%>|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)';
61 +var _OPTS_PASSABLE_WITH_DATA = ['delimiter', 'scope', 'context', 'debug', 'compileDebug',
62 + 'client', '_with', 'rmWhitespace', 'strict', 'filename', 'async'];
63 +// We don't allow 'cache' option to be passed in the data obj for
64 +// the normal `render` call, but this is where Express 2 & 3 put it
65 +// so we make an exception for `renderFile`
66 +var _OPTS_PASSABLE_WITH_DATA_EXPRESS = _OPTS_PASSABLE_WITH_DATA.concat('cache');
67 +var _BOM = /^\uFEFF/;
68 +
69 +/**
70 + * EJS template function cache. This can be a LRU object from lru-cache NPM
71 + * module. By default, it is {@link module:utils.cache}, a simple in-process
72 + * cache that grows continuously.
73 + *
74 + * @type {Cache}
75 + */
76 +
77 +exports.cache = utils.cache;
78 +
79 +/**
80 + * Custom file loader. Useful for template preprocessing or restricting access
81 + * to a certain part of the filesystem.
82 + *
83 + * @type {fileLoader}
84 + */
85 +
86 +exports.fileLoader = fs.readFileSync;
87 +
88 +/**
89 + * Name of the object containing the locals.
90 + *
91 + * This variable is overridden by {@link Options}`.localsName` if it is not
92 + * `undefined`.
93 + *
94 + * @type {String}
95 + * @public
96 + */
97 +
98 +exports.localsName = _DEFAULT_LOCALS_NAME;
99 +
100 +/**
101 + * Promise implementation -- defaults to the native implementation if available
102 + * This is mostly just for testability
103 + *
104 + * @type {PromiseConstructorLike}
105 + * @public
106 + */
107 +
108 +exports.promiseImpl = (new Function('return this;'))().Promise;
109 +
110 +/**
111 + * Get the path to the included file from the parent file path and the
112 + * specified path.
113 + *
114 + * @param {String} name specified path
115 + * @param {String} filename parent file path
116 + * @param {Boolean} [isDir=false] whether the parent file path is a directory
117 + * @return {String}
118 + */
119 +exports.resolveInclude = function(name, filename, isDir) {
120 + var dirname = path.dirname;
121 + var extname = path.extname;
122 + var resolve = path.resolve;
123 + var includePath = resolve(isDir ? filename : dirname(filename), name);
124 + var ext = extname(name);
125 + if (!ext) {
126 + includePath += '.ejs';
127 + }
128 + return includePath;
129 +};
130 +
131 +/**
132 + * Try to resolve file path on multiple directories
133 + *
134 + * @param {String} name specified path
135 + * @param {Array<String>} paths list of possible parent directory paths
136 + * @return {String}
137 + */
138 +function resolvePaths(name, paths) {
139 + var filePath;
140 + if (paths.some(function (v) {
141 + filePath = exports.resolveInclude(name, v, true);
142 + return fs.existsSync(filePath);
143 + })) {
144 + return filePath;
145 + }
146 +}
147 +
148 +/**
149 + * Get the path to the included file by Options
150 + *
151 + * @param {String} path specified path
152 + * @param {Options} options compilation options
153 + * @return {String}
154 + */
155 +function getIncludePath(path, options) {
156 + var includePath;
157 + var filePath;
158 + var views = options.views;
159 + var match = /^[A-Za-z]+:\\|^\//.exec(path);
160 +
161 + // Abs path
162 + if (match && match.length) {
163 + path = path.replace(/^\/*/, '');
164 + if (Array.isArray(options.root)) {
165 + includePath = resolvePaths(path, options.root);
166 + } else {
167 + includePath = exports.resolveInclude(path, options.root || '/', true);
168 + }
169 + }
170 + // Relative paths
171 + else {
172 + // Look relative to a passed filename first
173 + if (options.filename) {
174 + filePath = exports.resolveInclude(path, options.filename);
175 + if (fs.existsSync(filePath)) {
176 + includePath = filePath;
177 + }
178 + }
179 + // Then look in any views directories
180 + if (!includePath && Array.isArray(views)) {
181 + includePath = resolvePaths(path, views);
182 + }
183 + if (!includePath && typeof options.includer !== 'function') {
184 + throw new Error('Could not find the include file "' +
185 + options.escapeFunction(path) + '"');
186 + }
187 + }
188 + return includePath;
189 +}
190 +
191 +/**
192 + * Get the template from a string or a file, either compiled on-the-fly or
193 + * read from cache (if enabled), and cache the template if needed.
194 + *
195 + * If `template` is not set, the file specified in `options.filename` will be
196 + * read.
197 + *
198 + * If `options.cache` is true, this function reads the file from
199 + * `options.filename` so it must be set prior to calling this function.
200 + *
201 + * @memberof module:ejs-internal
202 + * @param {Options} options compilation options
203 + * @param {String} [template] template source
204 + * @return {(TemplateFunction|ClientFunction)}
205 + * Depending on the value of `options.client`, either type might be returned.
206 + * @static
207 + */
208 +
209 +function handleCache(options, template) {
210 + var func;
211 + var filename = options.filename;
212 + var hasTemplate = arguments.length > 1;
213 +
214 + if (options.cache) {
215 + if (!filename) {
216 + throw new Error('cache option requires a filename');
217 + }
218 + func = exports.cache.get(filename);
219 + if (func) {
220 + return func;
221 + }
222 + if (!hasTemplate) {
223 + template = fileLoader(filename).toString().replace(_BOM, '');
224 + }
225 + }
226 + else if (!hasTemplate) {
227 + // istanbul ignore if: should not happen at all
228 + if (!filename) {
229 + throw new Error('Internal EJS error: no file name or template '
230 + + 'provided');
231 + }
232 + template = fileLoader(filename).toString().replace(_BOM, '');
233 + }
234 + func = exports.compile(template, options);
235 + if (options.cache) {
236 + exports.cache.set(filename, func);
237 + }
238 + return func;
239 +}
240 +
241 +/**
242 + * Try calling handleCache with the given options and data and call the
243 + * callback with the result. If an error occurs, call the callback with
244 + * the error. Used by renderFile().
245 + *
246 + * @memberof module:ejs-internal
247 + * @param {Options} options compilation options
248 + * @param {Object} data template data
249 + * @param {RenderFileCallback} cb callback
250 + * @static
251 + */
252 +
253 +function tryHandleCache(options, data, cb) {
254 + var result;
255 + if (!cb) {
256 + if (typeof exports.promiseImpl == 'function') {
257 + return new exports.promiseImpl(function (resolve, reject) {
258 + try {
259 + result = handleCache(options)(data);
260 + resolve(result);
261 + }
262 + catch (err) {
263 + reject(err);
264 + }
265 + });
266 + }
267 + else {
268 + throw new Error('Please provide a callback function');
269 + }
270 + }
271 + else {
272 + try {
273 + result = handleCache(options)(data);
274 + }
275 + catch (err) {
276 + return cb(err);
277 + }
278 +
279 + cb(null, result);
280 + }
281 +}
282 +
283 +/**
284 + * fileLoader is independent
285 + *
286 + * @param {String} filePath ejs file path.
287 + * @return {String} The contents of the specified file.
288 + * @static
289 + */
290 +
291 +function fileLoader(filePath){
292 + return exports.fileLoader(filePath);
293 +}
294 +
295 +/**
296 + * Get the template function.
297 + *
298 + * If `options.cache` is `true`, then the template is cached.
299 + *
300 + * @memberof module:ejs-internal
301 + * @param {String} path path for the specified file
302 + * @param {Options} options compilation options
303 + * @return {(TemplateFunction|ClientFunction)}
304 + * Depending on the value of `options.client`, either type might be returned
305 + * @static
306 + */
307 +
308 +function includeFile(path, options) {
309 + var opts = utils.shallowCopy({}, options);
310 + opts.filename = getIncludePath(path, opts);
311 + if (typeof options.includer === 'function') {
312 + var includerResult = options.includer(path, opts.filename);
313 + if (includerResult) {
314 + if (includerResult.filename) {
315 + opts.filename = includerResult.filename;
316 + }
317 + if (includerResult.template) {
318 + return handleCache(opts, includerResult.template);
319 + }
320 + }
321 + }
322 + return handleCache(opts);
323 +}
324 +
325 +/**
326 + * Re-throw the given `err` in context to the `str` of ejs, `filename`, and
327 + * `lineno`.
328 + *
329 + * @implements {RethrowCallback}
330 + * @memberof module:ejs-internal
331 + * @param {Error} err Error object
332 + * @param {String} str EJS source
333 + * @param {String} flnm file name of the EJS file
334 + * @param {Number} lineno line number of the error
335 + * @param {EscapeCallback} esc
336 + * @static
337 + */
338 +
339 +function rethrow(err, str, flnm, lineno, esc) {
340 + var lines = str.split('\n');
341 + var start = Math.max(lineno - 3, 0);
342 + var end = Math.min(lines.length, lineno + 3);
343 + var filename = esc(flnm);
344 + // Error context
345 + var context = lines.slice(start, end).map(function (line, i){
346 + var curr = i + start + 1;
347 + return (curr == lineno ? ' >> ' : ' ')
348 + + curr
349 + + '| '
350 + + line;
351 + }).join('\n');
352 +
353 + // Alter exception message
354 + err.path = filename;
355 + err.message = (filename || 'ejs') + ':'
356 + + lineno + '\n'
357 + + context + '\n\n'
358 + + err.message;
359 +
360 + throw err;
361 +}
362 +
363 +function stripSemi(str){
364 + return str.replace(/;(\s*$)/, '$1');
365 +}
366 +
367 +/**
368 + * Compile the given `str` of ejs into a template function.
369 + *
370 + * @param {String} template EJS template
371 + *
372 + * @param {Options} [opts] compilation options
373 + *
374 + * @return {(TemplateFunction|ClientFunction)}
375 + * Depending on the value of `opts.client`, either type might be returned.
376 + * Note that the return type of the function also depends on the value of `opts.async`.
377 + * @public
378 + */
379 +
380 +exports.compile = function compile(template, opts) {
381 + var templ;
382 +
383 + // v1 compat
384 + // 'scope' is 'context'
385 + // FIXME: Remove this in a future version
386 + if (opts && opts.scope) {
387 + if (!scopeOptionWarned){
388 + console.warn('`scope` option is deprecated and will be removed in EJS 3');
389 + scopeOptionWarned = true;
390 + }
391 + if (!opts.context) {
392 + opts.context = opts.scope;
393 + }
394 + delete opts.scope;
395 + }
396 + templ = new Template(template, opts);
397 + return templ.compile();
398 +};
399 +
400 +/**
401 + * Render the given `template` of ejs.
402 + *
403 + * If you would like to include options but not data, you need to explicitly
404 + * call this function with `data` being an empty object or `null`.
405 + *
406 + * @param {String} template EJS template
407 + * @param {Object} [data={}] template data
408 + * @param {Options} [opts={}] compilation and rendering options
409 + * @return {(String|Promise<String>)}
410 + * Return value type depends on `opts.async`.
411 + * @public
412 + */
413 +
414 +exports.render = function (template, d, o) {
415 + var data = d || {};
416 + var opts = o || {};
417 +
418 + // No options object -- if there are optiony names
419 + // in the data, copy them to options
420 + if (arguments.length == 2) {
421 + utils.shallowCopyFromList(opts, data, _OPTS_PASSABLE_WITH_DATA);
422 + }
423 +
424 + return handleCache(opts, template)(data);
425 +};
426 +
427 +/**
428 + * Render an EJS file at the given `path` and callback `cb(err, str)`.
429 + *
430 + * If you would like to include options but not data, you need to explicitly
431 + * call this function with `data` being an empty object or `null`.
432 + *
433 + * @param {String} path path to the EJS file
434 + * @param {Object} [data={}] template data
435 + * @param {Options} [opts={}] compilation and rendering options
436 + * @param {RenderFileCallback} cb callback
437 + * @public
438 + */
439 +
440 +exports.renderFile = function () {
441 + var args = Array.prototype.slice.call(arguments);
442 + var filename = args.shift();
443 + var cb;
444 + var opts = {filename: filename};
445 + var data;
446 + var viewOpts;
447 +
448 + // Do we have a callback?
449 + if (typeof arguments[arguments.length - 1] == 'function') {
450 + cb = args.pop();
451 + }
452 + // Do we have data/opts?
453 + if (args.length) {
454 + // Should always have data obj
455 + data = args.shift();
456 + // Normal passed opts (data obj + opts obj)
457 + if (args.length) {
458 + // Use shallowCopy so we don't pollute passed in opts obj with new vals
459 + utils.shallowCopy(opts, args.pop());
460 + }
461 + // Special casing for Express (settings + opts-in-data)
462 + else {
463 + // Express 3 and 4
464 + if (data.settings) {
465 + // Pull a few things from known locations
466 + if (data.settings.views) {
467 + opts.views = data.settings.views;
468 + }
469 + if (data.settings['view cache']) {
470 + opts.cache = true;
471 + }
472 + // Undocumented after Express 2, but still usable, esp. for
473 + // items that are unsafe to be passed along with data, like `root`
474 + viewOpts = data.settings['view options'];
475 + if (viewOpts) {
476 + utils.shallowCopy(opts, viewOpts);
477 + }
478 + }
479 + // Express 2 and lower, values set in app.locals, or people who just
480 + // want to pass options in their data. NOTE: These values will override
481 + // anything previously set in settings or settings['view options']
482 + utils.shallowCopyFromList(opts, data, _OPTS_PASSABLE_WITH_DATA_EXPRESS);
483 + }
484 + opts.filename = filename;
485 + }
486 + else {
487 + data = {};
488 + }
489 +
490 + return tryHandleCache(opts, data, cb);
491 +};
492 +
493 +/**
494 + * Clear intermediate JavaScript cache. Calls {@link Cache#reset}.
495 + * @public
496 + */
497 +
498 +/**
499 + * EJS template class
500 + * @public
501 + */
502 +exports.Template = Template;
503 +
504 +exports.clearCache = function () {
505 + exports.cache.reset();
506 +};
507 +
508 +function Template(text, opts) {
509 + opts = opts || {};
510 + var options = {};
511 + this.templateText = text;
512 + /** @type {string | null} */
513 + this.mode = null;
514 + this.truncate = false;
515 + this.currentLine = 1;
516 + this.source = '';
517 + options.client = opts.client || false;
518 + options.escapeFunction = opts.escape || opts.escapeFunction || utils.escapeXML;
519 + options.compileDebug = opts.compileDebug !== false;
520 + options.debug = !!opts.debug;
521 + options.filename = opts.filename;
522 + options.openDelimiter = opts.openDelimiter || exports.openDelimiter || _DEFAULT_OPEN_DELIMITER;
523 + options.closeDelimiter = opts.closeDelimiter || exports.closeDelimiter || _DEFAULT_CLOSE_DELIMITER;
524 + options.delimiter = opts.delimiter || exports.delimiter || _DEFAULT_DELIMITER;
525 + options.strict = opts.strict || false;
526 + options.context = opts.context;
527 + options.cache = opts.cache || false;
528 + options.rmWhitespace = opts.rmWhitespace;
529 + options.root = opts.root;
530 + options.includer = opts.includer;
531 + options.outputFunctionName = opts.outputFunctionName;
532 + options.localsName = opts.localsName || exports.localsName || _DEFAULT_LOCALS_NAME;
533 + options.views = opts.views;
534 + options.async = opts.async;
535 + options.destructuredLocals = opts.destructuredLocals;
536 + options.legacyInclude = typeof opts.legacyInclude != 'undefined' ? !!opts.legacyInclude : true;
537 +
538 + if (options.strict) {
539 + options._with = false;
540 + }
541 + else {
542 + options._with = typeof opts._with != 'undefined' ? opts._with : true;
543 + }
544 +
545 + this.opts = options;
546 +
547 + this.regex = this.createRegex();
548 +}
549 +
550 +Template.modes = {
551 + EVAL: 'eval',
552 + ESCAPED: 'escaped',
553 + RAW: 'raw',
554 + COMMENT: 'comment',
555 + LITERAL: 'literal'
556 +};
557 +
558 +Template.prototype = {
559 + createRegex: function () {
560 + var str = _REGEX_STRING;
561 + var delim = utils.escapeRegExpChars(this.opts.delimiter);
562 + var open = utils.escapeRegExpChars(this.opts.openDelimiter);
563 + var close = utils.escapeRegExpChars(this.opts.closeDelimiter);
564 + str = str.replace(/%/g, delim)
565 + .replace(/</g, open)
566 + .replace(/>/g, close);
567 + return new RegExp(str);
568 + },
569 +
570 + compile: function () {
571 + /** @type {string} */
572 + var src;
573 + /** @type {ClientFunction} */
574 + var fn;
575 + var opts = this.opts;
576 + var prepended = '';
577 + var appended = '';
578 + /** @type {EscapeCallback} */
579 + var escapeFn = opts.escapeFunction;
580 + /** @type {FunctionConstructor} */
581 + var ctor;
582 + /** @type {string} */
583 + var sanitizedFilename = opts.filename ? JSON.stringify(opts.filename) : 'undefined';
584 +
585 + if (!this.source) {
586 + this.generateSource();
587 + prepended +=
588 + ' var __output = "";\n' +
589 + ' function __append(s) { if (s !== undefined && s !== null) __output += s }\n';
590 + if (opts.outputFunctionName) {
591 + prepended += ' var ' + opts.outputFunctionName + ' = __append;' + '\n';
592 + }
593 + if (opts.destructuredLocals && opts.destructuredLocals.length) {
594 + var destructuring = ' var __locals = (' + opts.localsName + ' || {}),\n';
595 + for (var i = 0; i < opts.destructuredLocals.length; i++) {
596 + var name = opts.destructuredLocals[i];
597 + if (i > 0) {
598 + destructuring += ',\n ';
599 + }
600 + destructuring += name + ' = __locals.' + name;
601 + }
602 + prepended += destructuring + ';\n';
603 + }
604 + if (opts._with !== false) {
605 + prepended += ' with (' + opts.localsName + ' || {}) {' + '\n';
606 + appended += ' }' + '\n';
607 + }
608 + appended += ' return __output;' + '\n';
609 + this.source = prepended + this.source + appended;
610 + }
611 +
612 + if (opts.compileDebug) {
613 + src = 'var __line = 1' + '\n'
614 + + ' , __lines = ' + JSON.stringify(this.templateText) + '\n'
615 + + ' , __filename = ' + sanitizedFilename + ';' + '\n'
616 + + 'try {' + '\n'
617 + + this.source
618 + + '} catch (e) {' + '\n'
619 + + ' rethrow(e, __lines, __filename, __line, escapeFn);' + '\n'
620 + + '}' + '\n';
621 + }
622 + else {
623 + src = this.source;
624 + }
625 +
626 + if (opts.client) {
627 + src = 'escapeFn = escapeFn || ' + escapeFn.toString() + ';' + '\n' + src;
628 + if (opts.compileDebug) {
629 + src = 'rethrow = rethrow || ' + rethrow.toString() + ';' + '\n' + src;
630 + }
631 + }
632 +
633 + if (opts.strict) {
634 + src = '"use strict";\n' + src;
635 + }
636 + if (opts.debug) {
637 + console.log(src);
638 + }
639 + if (opts.compileDebug && opts.filename) {
640 + src = src + '\n'
641 + + '//# sourceURL=' + sanitizedFilename + '\n';
642 + }
643 +
644 + try {
645 + if (opts.async) {
646 + // Have to use generated function for this, since in envs without support,
647 + // it breaks in parsing
648 + try {
649 + ctor = (new Function('return (async function(){}).constructor;'))();
650 + }
651 + catch(e) {
652 + if (e instanceof SyntaxError) {
653 + throw new Error('This environment does not support async/await');
654 + }
655 + else {
656 + throw e;
657 + }
658 + }
659 + }
660 + else {
661 + ctor = Function;
662 + }
663 + fn = new ctor(opts.localsName + ', escapeFn, include, rethrow', src);
664 + }
665 + catch(e) {
666 + // istanbul ignore else
667 + if (e instanceof SyntaxError) {
668 + if (opts.filename) {
669 + e.message += ' in ' + opts.filename;
670 + }
671 + e.message += ' while compiling ejs\n\n';
672 + e.message += 'If the above error is not helpful, you may want to try EJS-Lint:\n';
673 + e.message += 'https://github.com/RyanZim/EJS-Lint';
674 + if (!opts.async) {
675 + e.message += '\n';
676 + e.message += 'Or, if you meant to create an async function, pass `async: true` as an option.';
677 + }
678 + }
679 + throw e;
680 + }
681 +
682 + // Return a callable function which will execute the function
683 + // created by the source-code, with the passed data as locals
684 + // Adds a local `include` function which allows full recursive include
685 + var returnedFn = opts.client ? fn : function anonymous(data) {
686 + var include = function (path, includeData) {
687 + var d = utils.shallowCopy({}, data);
688 + if (includeData) {
689 + d = utils.shallowCopy(d, includeData);
690 + }
691 + return includeFile(path, opts)(d);
692 + };
693 + return fn.apply(opts.context, [data || {}, escapeFn, include, rethrow]);
694 + };
695 + if (opts.filename && typeof Object.defineProperty === 'function') {
696 + var filename = opts.filename;
697 + var basename = path.basename(filename, path.extname(filename));
698 + try {
699 + Object.defineProperty(returnedFn, 'name', {
700 + value: basename,
701 + writable: false,
702 + enumerable: false,
703 + configurable: true
704 + });
705 + } catch (e) {/* ignore */}
706 + }
707 + return returnedFn;
708 + },
709 +
710 + generateSource: function () {
711 + var opts = this.opts;
712 +
713 + if (opts.rmWhitespace) {
714 + // Have to use two separate replace here as `^` and `$` operators don't
715 + // work well with `\r` and empty lines don't work well with the `m` flag.
716 + this.templateText =
717 + this.templateText.replace(/[\r\n]+/g, '\n').replace(/^\s+|\s+$/gm, '');
718 + }
719 +
720 + // Slurp spaces and tabs before <%_ and after _%>
721 + this.templateText =
722 + this.templateText.replace(/[ \t]*<%_/gm, '<%_').replace(/_%>[ \t]*/gm, '_%>');
723 +
724 + var self = this;
725 + var matches = this.parseTemplateText();
726 + var d = this.opts.delimiter;
727 + var o = this.opts.openDelimiter;
728 + var c = this.opts.closeDelimiter;
729 +
730 + if (matches && matches.length) {
731 + matches.forEach(function (line, index) {
732 + var closing;
733 + // If this is an opening tag, check for closing tags
734 + // FIXME: May end up with some false positives here
735 + // Better to store modes as k/v with openDelimiter + delimiter as key
736 + // Then this can simply check against the map
737 + if ( line.indexOf(o + d) === 0 // If it is a tag
738 + && line.indexOf(o + d + d) !== 0) { // and is not escaped
739 + closing = matches[index + 2];
740 + if (!(closing == d + c || closing == '-' + d + c || closing == '_' + d + c)) {
741 + throw new Error('Could not find matching close tag for "' + line + '".');
742 + }
743 + }
744 + self.scanLine(line);
745 + });
746 + }
747 +
748 + },
749 +
750 + parseTemplateText: function () {
751 + var str = this.templateText;
752 + var pat = this.regex;
753 + var result = pat.exec(str);
754 + var arr = [];
755 + var firstPos;
756 +
757 + while (result) {
758 + firstPos = result.index;
759 +
760 + if (firstPos !== 0) {
761 + arr.push(str.substring(0, firstPos));
762 + str = str.slice(firstPos);
763 + }
764 +
765 + arr.push(result[0]);
766 + str = str.slice(result[0].length);
767 + result = pat.exec(str);
768 + }
769 +
770 + if (str) {
771 + arr.push(str);
772 + }
773 +
774 + return arr;
775 + },
776 +
777 + _addOutput: function (line) {
778 + if (this.truncate) {
779 + // Only replace single leading linebreak in the line after
780 + // -%> tag -- this is the single, trailing linebreak
781 + // after the tag that the truncation mode replaces
782 + // Handle Win / Unix / old Mac linebreaks -- do the \r\n
783 + // combo first in the regex-or
784 + line = line.replace(/^(?:\r\n|\r|\n)/, '');
785 + this.truncate = false;
786 + }
787 + if (!line) {
788 + return line;
789 + }
790 +
791 + // Preserve literal slashes
792 + line = line.replace(/\\/g, '\\\\');
793 +
794 + // Convert linebreaks
795 + line = line.replace(/\n/g, '\\n');
796 + line = line.replace(/\r/g, '\\r');
797 +
798 + // Escape double-quotes
799 + // - this will be the delimiter during execution
800 + line = line.replace(/"/g, '\\"');
801 + this.source += ' ; __append("' + line + '")' + '\n';
802 + },
803 +
804 + scanLine: function (line) {
805 + var self = this;
806 + var d = this.opts.delimiter;
807 + var o = this.opts.openDelimiter;
808 + var c = this.opts.closeDelimiter;
809 + var newLineCount = 0;
810 +
811 + newLineCount = (line.split('\n').length - 1);
812 +
813 + switch (line) {
814 + case o + d:
815 + case o + d + '_':
816 + this.mode = Template.modes.EVAL;
817 + break;
818 + case o + d + '=':
819 + this.mode = Template.modes.ESCAPED;
820 + break;
821 + case o + d + '-':
822 + this.mode = Template.modes.RAW;
823 + break;
824 + case o + d + '#':
825 + this.mode = Template.modes.COMMENT;
826 + break;
827 + case o + d + d:
828 + this.mode = Template.modes.LITERAL;
829 + this.source += ' ; __append("' + line.replace(o + d + d, o + d) + '")' + '\n';
830 + break;
831 + case d + d + c:
832 + this.mode = Template.modes.LITERAL;
833 + this.source += ' ; __append("' + line.replace(d + d + c, d + c) + '")' + '\n';
834 + break;
835 + case d + c:
836 + case '-' + d + c:
837 + case '_' + d + c:
838 + if (this.mode == Template.modes.LITERAL) {
839 + this._addOutput(line);
840 + }
841 +
842 + this.mode = null;
843 + this.truncate = line.indexOf('-') === 0 || line.indexOf('_') === 0;
844 + break;
845 + default:
846 + // In script mode, depends on type of tag
847 + if (this.mode) {
848 + // If '//' is found without a line break, add a line break.
849 + switch (this.mode) {
850 + case Template.modes.EVAL:
851 + case Template.modes.ESCAPED:
852 + case Template.modes.RAW:
853 + if (line.lastIndexOf('//') > line.lastIndexOf('\n')) {
854 + line += '\n';
855 + }
856 + }
857 + switch (this.mode) {
858 + // Just executing code
859 + case Template.modes.EVAL:
860 + this.source += ' ; ' + line + '\n';
861 + break;
862 + // Exec, esc, and output
863 + case Template.modes.ESCAPED:
864 + this.source += ' ; __append(escapeFn(' + stripSemi(line) + '))' + '\n';
865 + break;
866 + // Exec and output
867 + case Template.modes.RAW:
868 + this.source += ' ; __append(' + stripSemi(line) + ')' + '\n';
869 + break;
870 + case Template.modes.COMMENT:
871 + // Do nothing
872 + break;
873 + // Literal <%% mode, append as raw output
874 + case Template.modes.LITERAL:
875 + this._addOutput(line);
876 + break;
877 + }
878 + }
879 + // In string mode, just add the output
880 + else {
881 + this._addOutput(line);
882 + }
883 + }
884 +
885 + if (self.opts.compileDebug && newLineCount) {
886 + this.currentLine += newLineCount;
887 + this.source += ' ; __line = ' + this.currentLine + '\n';
888 + }
889 + }
890 +};
891 +
892 +/**
893 + * Escape characters reserved in XML.
894 + *
895 + * This is simply an export of {@link module:utils.escapeXML}.
896 + *
897 + * If `markup` is `undefined` or `null`, the empty string is returned.
898 + *
899 + * @param {String} markup Input string
900 + * @return {String} Escaped string
901 + * @public
902 + * @func
903 + * */
904 +exports.escapeXML = utils.escapeXML;
905 +
906 +/**
907 + * Express.js support.
908 + *
909 + * This is an alias for {@link module:ejs.renderFile}, in order to support
910 + * Express.js out-of-the-box.
911 + *
912 + * @func
913 + */
914 +
915 +exports.__express = exports.renderFile;
916 +
917 +/**
918 + * Version of EJS.
919 + *
920 + * @readonly
921 + * @type {String}
922 + * @public
923 + */
924 +
925 +exports.VERSION = _VERSION_STRING;
926 +
927 +/**
928 + * Name for detection of EJS.
929 + *
930 + * @readonly
931 + * @type {String}
932 + * @public
933 + */
934 +
935 +exports.name = _NAME;
936 +
937 +/* istanbul ignore if */
938 +if (typeof window != 'undefined') {
939 + window.ejs = exports;
940 +}
941 +
942 +},{"../package.json":6,"./utils":2,"fs":3,"path":4}],2:[function(require,module,exports){
943 +/*
944 + * EJS Embedded JavaScript templates
945 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
946 + *
947 + * Licensed under the Apache License, Version 2.0 (the "License");
948 + * you may not use this file except in compliance with the License.
949 + * You may obtain a copy of the License at
950 + *
951 + * http://www.apache.org/licenses/LICENSE-2.0
952 + *
953 + * Unless required by applicable law or agreed to in writing, software
954 + * distributed under the License is distributed on an "AS IS" BASIS,
955 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
956 + * See the License for the specific language governing permissions and
957 + * limitations under the License.
958 + *
959 +*/
960 +
961 +/**
962 + * Private utility functions
963 + * @module utils
964 + * @private
965 + */
966 +
967 +'use strict';
968 +
969 +var regExpChars = /[|\\{}()[\]^$+*?.]/g;
970 +
971 +/**
972 + * Escape characters reserved in regular expressions.
973 + *
974 + * If `string` is `undefined` or `null`, the empty string is returned.
975 + *
976 + * @param {String} string Input string
977 + * @return {String} Escaped string
978 + * @static
979 + * @private
980 + */
981 +exports.escapeRegExpChars = function (string) {
982 + // istanbul ignore if
983 + if (!string) {
984 + return '';
985 + }
986 + return String(string).replace(regExpChars, '\\$&');
987 +};
988 +
989 +var _ENCODE_HTML_RULES = {
990 + '&': '&amp;',
991 + '<': '&lt;',
992 + '>': '&gt;',
993 + '"': '&#34;',
994 + "'": '&#39;'
995 +};
996 +var _MATCH_HTML = /[&<>'"]/g;
997 +
998 +function encode_char(c) {
999 + return _ENCODE_HTML_RULES[c] || c;
1000 +}
1001 +
1002 +/**
1003 + * Stringified version of constants used by {@link module:utils.escapeXML}.
1004 + *
1005 + * It is used in the process of generating {@link ClientFunction}s.
1006 + *
1007 + * @readonly
1008 + * @type {String}
1009 + */
1010 +
1011 +var escapeFuncStr =
1012 + 'var _ENCODE_HTML_RULES = {\n'
1013 ++ ' "&": "&amp;"\n'
1014 ++ ' , "<": "&lt;"\n'
1015 ++ ' , ">": "&gt;"\n'
1016 ++ ' , \'"\': "&#34;"\n'
1017 ++ ' , "\'": "&#39;"\n'
1018 ++ ' }\n'
1019 ++ ' , _MATCH_HTML = /[&<>\'"]/g;\n'
1020 ++ 'function encode_char(c) {\n'
1021 ++ ' return _ENCODE_HTML_RULES[c] || c;\n'
1022 ++ '};\n';
1023 +
1024 +/**
1025 + * Escape characters reserved in XML.
1026 + *
1027 + * If `markup` is `undefined` or `null`, the empty string is returned.
1028 + *
1029 + * @implements {EscapeCallback}
1030 + * @param {String} markup Input string
1031 + * @return {String} Escaped string
1032 + * @static
1033 + * @private
1034 + */
1035 +
1036 +exports.escapeXML = function (markup) {
1037 + return markup == undefined
1038 + ? ''
1039 + : String(markup)
1040 + .replace(_MATCH_HTML, encode_char);
1041 +};
1042 +exports.escapeXML.toString = function () {
1043 + return Function.prototype.toString.call(this) + ';\n' + escapeFuncStr;
1044 +};
1045 +
1046 +/**
1047 + * Naive copy of properties from one object to another.
1048 + * Does not recurse into non-scalar properties
1049 + * Does not check to see if the property has a value before copying
1050 + *
1051 + * @param {Object} to Destination object
1052 + * @param {Object} from Source object
1053 + * @return {Object} Destination object
1054 + * @static
1055 + * @private
1056 + */
1057 +exports.shallowCopy = function (to, from) {
1058 + from = from || {};
1059 + for (var p in from) {
1060 + to[p] = from[p];
1061 + }
1062 + return to;
1063 +};
1064 +
1065 +/**
1066 + * Naive copy of a list of key names, from one object to another.
1067 + * Only copies property if it is actually defined
1068 + * Does not recurse into non-scalar properties
1069 + *
1070 + * @param {Object} to Destination object
1071 + * @param {Object} from Source object
1072 + * @param {Array} list List of properties to copy
1073 + * @return {Object} Destination object
1074 + * @static
1075 + * @private
1076 + */
1077 +exports.shallowCopyFromList = function (to, from, list) {
1078 + for (var i = 0; i < list.length; i++) {
1079 + var p = list[i];
1080 + if (typeof from[p] != 'undefined') {
1081 + to[p] = from[p];
1082 + }
1083 + }
1084 + return to;
1085 +};
1086 +
1087 +/**
1088 + * Simple in-process cache implementation. Does not implement limits of any
1089 + * sort.
1090 + *
1091 + * @implements {Cache}
1092 + * @static
1093 + * @private
1094 + */
1095 +exports.cache = {
1096 + _data: {},
1097 + set: function (key, val) {
1098 + this._data[key] = val;
1099 + },
1100 + get: function (key) {
1101 + return this._data[key];
1102 + },
1103 + remove: function (key) {
1104 + delete this._data[key];
1105 + },
1106 + reset: function () {
1107 + this._data = {};
1108 + }
1109 +};
1110 +
1111 +/**
1112 + * Transforms hyphen case variable into camel case.
1113 + *
1114 + * @param {String} string Hyphen case string
1115 + * @return {String} Camel case string
1116 + * @static
1117 + * @private
1118 + */
1119 +exports.hyphenToCamel = function (str) {
1120 + return str.replace(/-[a-z]/g, function (match) { return match[1].toUpperCase(); });
1121 +};
1122 +
1123 +},{}],3:[function(require,module,exports){
1124 +
1125 +},{}],4:[function(require,module,exports){
1126 +(function (process){
1127 +// .dirname, .basename, and .extname methods are extracted from Node.js v8.11.1,
1128 +// backported and transplited with Babel, with backwards-compat fixes
1129 +
1130 +// Copyright Joyent, Inc. and other Node contributors.
1131 +//
1132 +// Permission is hereby granted, free of charge, to any person obtaining a
1133 +// copy of this software and associated documentation files (the
1134 +// "Software"), to deal in the Software without restriction, including
1135 +// without limitation the rights to use, copy, modify, merge, publish,
1136 +// distribute, sublicense, and/or sell copies of the Software, and to permit
1137 +// persons to whom the Software is furnished to do so, subject to the
1138 +// following conditions:
1139 +//
1140 +// The above copyright notice and this permission notice shall be included
1141 +// in all copies or substantial portions of the Software.
1142 +//
1143 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1144 +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1145 +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
1146 +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
1147 +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
1148 +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
1149 +// USE OR OTHER DEALINGS IN THE SOFTWARE.
1150 +
1151 +// resolves . and .. elements in a path array with directory names there
1152 +// must be no slashes, empty elements, or device names (c:\) in the array
1153 +// (so also no leading and trailing slashes - it does not distinguish
1154 +// relative and absolute paths)
1155 +function normalizeArray(parts, allowAboveRoot) {
1156 + // if the path tries to go above the root, `up` ends up > 0
1157 + var up = 0;
1158 + for (var i = parts.length - 1; i >= 0; i--) {
1159 + var last = parts[i];
1160 + if (last === '.') {
1161 + parts.splice(i, 1);
1162 + } else if (last === '..') {
1163 + parts.splice(i, 1);
1164 + up++;
1165 + } else if (up) {
1166 + parts.splice(i, 1);
1167 + up--;
1168 + }
1169 + }
1170 +
1171 + // if the path is allowed to go above the root, restore leading ..s
1172 + if (allowAboveRoot) {
1173 + for (; up--; up) {
1174 + parts.unshift('..');
1175 + }
1176 + }
1177 +
1178 + return parts;
1179 +}
1180 +
1181 +// path.resolve([from ...], to)
1182 +// posix version
1183 +exports.resolve = function() {
1184 + var resolvedPath = '',
1185 + resolvedAbsolute = false;
1186 +
1187 + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
1188 + var path = (i >= 0) ? arguments[i] : process.cwd();
1189 +
1190 + // Skip empty and invalid entries
1191 + if (typeof path !== 'string') {
1192 + throw new TypeError('Arguments to path.resolve must be strings');
1193 + } else if (!path) {
1194 + continue;
1195 + }
1196 +
1197 + resolvedPath = path + '/' + resolvedPath;
1198 + resolvedAbsolute = path.charAt(0) === '/';
1199 + }
1200 +
1201 + // At this point the path should be resolved to a full absolute path, but
1202 + // handle relative paths to be safe (might happen when process.cwd() fails)
1203 +
1204 + // Normalize the path
1205 + resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
1206 + return !!p;
1207 + }), !resolvedAbsolute).join('/');
1208 +
1209 + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
1210 +};
1211 +
1212 +// path.normalize(path)
1213 +// posix version
1214 +exports.normalize = function(path) {
1215 + var isAbsolute = exports.isAbsolute(path),
1216 + trailingSlash = substr(path, -1) === '/';
1217 +
1218 + // Normalize the path
1219 + path = normalizeArray(filter(path.split('/'), function(p) {
1220 + return !!p;
1221 + }), !isAbsolute).join('/');
1222 +
1223 + if (!path && !isAbsolute) {
1224 + path = '.';
1225 + }
1226 + if (path && trailingSlash) {
1227 + path += '/';
1228 + }
1229 +
1230 + return (isAbsolute ? '/' : '') + path;
1231 +};
1232 +
1233 +// posix version
1234 +exports.isAbsolute = function(path) {
1235 + return path.charAt(0) === '/';
1236 +};
1237 +
1238 +// posix version
1239 +exports.join = function() {
1240 + var paths = Array.prototype.slice.call(arguments, 0);
1241 + return exports.normalize(filter(paths, function(p, index) {
1242 + if (typeof p !== 'string') {
1243 + throw new TypeError('Arguments to path.join must be strings');
1244 + }
1245 + return p;
1246 + }).join('/'));
1247 +};
1248 +
1249 +
1250 +// path.relative(from, to)
1251 +// posix version
1252 +exports.relative = function(from, to) {
1253 + from = exports.resolve(from).substr(1);
1254 + to = exports.resolve(to).substr(1);
1255 +
1256 + function trim(arr) {
1257 + var start = 0;
1258 + for (; start < arr.length; start++) {
1259 + if (arr[start] !== '') break;
1260 + }
1261 +
1262 + var end = arr.length - 1;
1263 + for (; end >= 0; end--) {
1264 + if (arr[end] !== '') break;
1265 + }
1266 +
1267 + if (start > end) return [];
1268 + return arr.slice(start, end - start + 1);
1269 + }
1270 +
1271 + var fromParts = trim(from.split('/'));
1272 + var toParts = trim(to.split('/'));
1273 +
1274 + var length = Math.min(fromParts.length, toParts.length);
1275 + var samePartsLength = length;
1276 + for (var i = 0; i < length; i++) {
1277 + if (fromParts[i] !== toParts[i]) {
1278 + samePartsLength = i;
1279 + break;
1280 + }
1281 + }
1282 +
1283 + var outputParts = [];
1284 + for (var i = samePartsLength; i < fromParts.length; i++) {
1285 + outputParts.push('..');
1286 + }
1287 +
1288 + outputParts = outputParts.concat(toParts.slice(samePartsLength));
1289 +
1290 + return outputParts.join('/');
1291 +};
1292 +
1293 +exports.sep = '/';
1294 +exports.delimiter = ':';
1295 +
1296 +exports.dirname = function (path) {
1297 + if (typeof path !== 'string') path = path + '';
1298 + if (path.length === 0) return '.';
1299 + var code = path.charCodeAt(0);
1300 + var hasRoot = code === 47 /*/*/;
1301 + var end = -1;
1302 + var matchedSlash = true;
1303 + for (var i = path.length - 1; i >= 1; --i) {
1304 + code = path.charCodeAt(i);
1305 + if (code === 47 /*/*/) {
1306 + if (!matchedSlash) {
1307 + end = i;
1308 + break;
1309 + }
1310 + } else {
1311 + // We saw the first non-path separator
1312 + matchedSlash = false;
1313 + }
1314 + }
1315 +
1316 + if (end === -1) return hasRoot ? '/' : '.';
1317 + if (hasRoot && end === 1) {
1318 + // return '//';
1319 + // Backwards-compat fix:
1320 + return '/';
1321 + }
1322 + return path.slice(0, end);
1323 +};
1324 +
1325 +function basename(path) {
1326 + if (typeof path !== 'string') path = path + '';
1327 +
1328 + var start = 0;
1329 + var end = -1;
1330 + var matchedSlash = true;
1331 + var i;
1332 +
1333 + for (i = path.length - 1; i >= 0; --i) {
1334 + if (path.charCodeAt(i) === 47 /*/*/) {
1335 + // If we reached a path separator that was not part of a set of path
1336 + // separators at the end of the string, stop now
1337 + if (!matchedSlash) {
1338 + start = i + 1;
1339 + break;
1340 + }
1341 + } else if (end === -1) {
1342 + // We saw the first non-path separator, mark this as the end of our
1343 + // path component
1344 + matchedSlash = false;
1345 + end = i + 1;
1346 + }
1347 + }
1348 +
1349 + if (end === -1) return '';
1350 + return path.slice(start, end);
1351 +}
1352 +
1353 +// Uses a mixed approach for backwards-compatibility, as ext behavior changed
1354 +// in new Node.js versions, so only basename() above is backported here
1355 +exports.basename = function (path, ext) {
1356 + var f = basename(path);
1357 + if (ext && f.substr(-1 * ext.length) === ext) {
1358 + f = f.substr(0, f.length - ext.length);
1359 + }
1360 + return f;
1361 +};
1362 +
1363 +exports.extname = function (path) {
1364 + if (typeof path !== 'string') path = path + '';
1365 + var startDot = -1;
1366 + var startPart = 0;
1367 + var end = -1;
1368 + var matchedSlash = true;
1369 + // Track the state of characters (if any) we see before our first dot and
1370 + // after any path separator we find
1371 + var preDotState = 0;
1372 + for (var i = path.length - 1; i >= 0; --i) {
1373 + var code = path.charCodeAt(i);
1374 + if (code === 47 /*/*/) {
1375 + // If we reached a path separator that was not part of a set of path
1376 + // separators at the end of the string, stop now
1377 + if (!matchedSlash) {
1378 + startPart = i + 1;
1379 + break;
1380 + }
1381 + continue;
1382 + }
1383 + if (end === -1) {
1384 + // We saw the first non-path separator, mark this as the end of our
1385 + // extension
1386 + matchedSlash = false;
1387 + end = i + 1;
1388 + }
1389 + if (code === 46 /*.*/) {
1390 + // If this is our first dot, mark it as the start of our extension
1391 + if (startDot === -1)
1392 + startDot = i;
1393 + else if (preDotState !== 1)
1394 + preDotState = 1;
1395 + } else if (startDot !== -1) {
1396 + // We saw a non-dot and non-path separator before our dot, so we should
1397 + // have a good chance at having a non-empty extension
1398 + preDotState = -1;
1399 + }
1400 + }
1401 +
1402 + if (startDot === -1 || end === -1 ||
1403 + // We saw a non-dot character immediately before the dot
1404 + preDotState === 0 ||
1405 + // The (right-most) trimmed path component is exactly '..'
1406 + preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
1407 + return '';
1408 + }
1409 + return path.slice(startDot, end);
1410 +};
1411 +
1412 +function filter (xs, f) {
1413 + if (xs.filter) return xs.filter(f);
1414 + var res = [];
1415 + for (var i = 0; i < xs.length; i++) {
1416 + if (f(xs[i], i, xs)) res.push(xs[i]);
1417 + }
1418 + return res;
1419 +}
1420 +
1421 +// String.prototype.substr - negative index don't work in IE8
1422 +var substr = 'ab'.substr(-1) === 'b'
1423 + ? function (str, start, len) { return str.substr(start, len) }
1424 + : function (str, start, len) {
1425 + if (start < 0) start = str.length + start;
1426 + return str.substr(start, len);
1427 + }
1428 +;
1429 +
1430 +}).call(this,require('_process'))
1431 +},{"_process":5}],5:[function(require,module,exports){
1432 +// shim for using process in browser
1433 +var process = module.exports = {};
1434 +
1435 +// cached from whatever global is present so that test runners that stub it
1436 +// don't break things. But we need to wrap it in a try catch in case it is
1437 +// wrapped in strict mode code which doesn't define any globals. It's inside a
1438 +// function because try/catches deoptimize in certain engines.
1439 +
1440 +var cachedSetTimeout;
1441 +var cachedClearTimeout;
1442 +
1443 +function defaultSetTimout() {
1444 + throw new Error('setTimeout has not been defined');
1445 +}
1446 +function defaultClearTimeout () {
1447 + throw new Error('clearTimeout has not been defined');
1448 +}
1449 +(function () {
1450 + try {
1451 + if (typeof setTimeout === 'function') {
1452 + cachedSetTimeout = setTimeout;
1453 + } else {
1454 + cachedSetTimeout = defaultSetTimout;
1455 + }
1456 + } catch (e) {
1457 + cachedSetTimeout = defaultSetTimout;
1458 + }
1459 + try {
1460 + if (typeof clearTimeout === 'function') {
1461 + cachedClearTimeout = clearTimeout;
1462 + } else {
1463 + cachedClearTimeout = defaultClearTimeout;
1464 + }
1465 + } catch (e) {
1466 + cachedClearTimeout = defaultClearTimeout;
1467 + }
1468 +} ())
1469 +function runTimeout(fun) {
1470 + if (cachedSetTimeout === setTimeout) {
1471 + //normal enviroments in sane situations
1472 + return setTimeout(fun, 0);
1473 + }
1474 + // if setTimeout wasn't available but was latter defined
1475 + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
1476 + cachedSetTimeout = setTimeout;
1477 + return setTimeout(fun, 0);
1478 + }
1479 + try {
1480 + // when when somebody has screwed with setTimeout but no I.E. maddness
1481 + return cachedSetTimeout(fun, 0);
1482 + } catch(e){
1483 + try {
1484 + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
1485 + return cachedSetTimeout.call(null, fun, 0);
1486 + } catch(e){
1487 + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
1488 + return cachedSetTimeout.call(this, fun, 0);
1489 + }
1490 + }
1491 +
1492 +
1493 +}
1494 +function runClearTimeout(marker) {
1495 + if (cachedClearTimeout === clearTimeout) {
1496 + //normal enviroments in sane situations
1497 + return clearTimeout(marker);
1498 + }
1499 + // if clearTimeout wasn't available but was latter defined
1500 + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
1501 + cachedClearTimeout = clearTimeout;
1502 + return clearTimeout(marker);
1503 + }
1504 + try {
1505 + // when when somebody has screwed with setTimeout but no I.E. maddness
1506 + return cachedClearTimeout(marker);
1507 + } catch (e){
1508 + try {
1509 + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
1510 + return cachedClearTimeout.call(null, marker);
1511 + } catch (e){
1512 + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
1513 + // Some versions of I.E. have different rules for clearTimeout vs setTimeout
1514 + return cachedClearTimeout.call(this, marker);
1515 + }
1516 + }
1517 +
1518 +
1519 +
1520 +}
1521 +var queue = [];
1522 +var draining = false;
1523 +var currentQueue;
1524 +var queueIndex = -1;
1525 +
1526 +function cleanUpNextTick() {
1527 + if (!draining || !currentQueue) {
1528 + return;
1529 + }
1530 + draining = false;
1531 + if (currentQueue.length) {
1532 + queue = currentQueue.concat(queue);
1533 + } else {
1534 + queueIndex = -1;
1535 + }
1536 + if (queue.length) {
1537 + drainQueue();
1538 + }
1539 +}
1540 +
1541 +function drainQueue() {
1542 + if (draining) {
1543 + return;
1544 + }
1545 + var timeout = runTimeout(cleanUpNextTick);
1546 + draining = true;
1547 +
1548 + var len = queue.length;
1549 + while(len) {
1550 + currentQueue = queue;
1551 + queue = [];
1552 + while (++queueIndex < len) {
1553 + if (currentQueue) {
1554 + currentQueue[queueIndex].run();
1555 + }
1556 + }
1557 + queueIndex = -1;
1558 + len = queue.length;
1559 + }
1560 + currentQueue = null;
1561 + draining = false;
1562 + runClearTimeout(timeout);
1563 +}
1564 +
1565 +process.nextTick = function (fun) {
1566 + var args = new Array(arguments.length - 1);
1567 + if (arguments.length > 1) {
1568 + for (var i = 1; i < arguments.length; i++) {
1569 + args[i - 1] = arguments[i];
1570 + }
1571 + }
1572 + queue.push(new Item(fun, args));
1573 + if (queue.length === 1 && !draining) {
1574 + runTimeout(drainQueue);
1575 + }
1576 +};
1577 +
1578 +// v8 likes predictible objects
1579 +function Item(fun, array) {
1580 + this.fun = fun;
1581 + this.array = array;
1582 +}
1583 +Item.prototype.run = function () {
1584 + this.fun.apply(null, this.array);
1585 +};
1586 +process.title = 'browser';
1587 +process.browser = true;
1588 +process.env = {};
1589 +process.argv = [];
1590 +process.version = ''; // empty string to avoid regexp issues
1591 +process.versions = {};
1592 +
1593 +function noop() {}
1594 +
1595 +process.on = noop;
1596 +process.addListener = noop;
1597 +process.once = noop;
1598 +process.off = noop;
1599 +process.removeListener = noop;
1600 +process.removeAllListeners = noop;
1601 +process.emit = noop;
1602 +process.prependListener = noop;
1603 +process.prependOnceListener = noop;
1604 +
1605 +process.listeners = function (name) { return [] }
1606 +
1607 +process.binding = function (name) {
1608 + throw new Error('process.binding is not supported');
1609 +};
1610 +
1611 +process.cwd = function () { return '/' };
1612 +process.chdir = function (dir) {
1613 + throw new Error('process.chdir is not supported');
1614 +};
1615 +process.umask = function() { return 0; };
1616 +
1617 +},{}],6:[function(require,module,exports){
1618 +module.exports={
1619 + "name": "ejs",
1620 + "description": "Embedded JavaScript templates",
1621 + "keywords": [
1622 + "template",
1623 + "engine",
1624 + "ejs"
1625 + ],
1626 + "version": "3.1.6",
1627 + "author": "Matthew Eernisse <mde@fleegix.org> (http://fleegix.org)",
1628 + "license": "Apache-2.0",
1629 + "bin": {
1630 + "ejs": "./bin/cli.js"
1631 + },
1632 + "main": "./lib/ejs.js",
1633 + "jsdelivr": "ejs.min.js",
1634 + "unpkg": "ejs.min.js",
1635 + "repository": {
1636 + "type": "git",
1637 + "url": "git://github.com/mde/ejs.git"
1638 + },
1639 + "bugs": "https://github.com/mde/ejs/issues",
1640 + "homepage": "https://github.com/mde/ejs",
1641 + "dependencies": {
1642 + "jake": "^10.6.1"
1643 + },
1644 + "devDependencies": {
1645 + "browserify": "^16.5.1",
1646 + "eslint": "^6.8.0",
1647 + "git-directory-deploy": "^1.5.1",
1648 + "jsdoc": "^3.6.4",
1649 + "lru-cache": "^4.0.1",
1650 + "mocha": "^7.1.1",
1651 + "uglify-js": "^3.3.16"
1652 + },
1653 + "engines": {
1654 + "node": ">=0.10.0"
1655 + },
1656 + "scripts": {
1657 + "test": "mocha"
1658 + }
1659 +}
1660 +
1661 +},{}]},{},[1])(1)
1662 +});
1 +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.ejs=f()}})(function(){var define,module,exports;return function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r}()({1:[function(require,module,exports){"use strict";var fs=require("fs");var path=require("path");var utils=require("./utils");var scopeOptionWarned=false;var _VERSION_STRING=require("../package.json").version;var _DEFAULT_OPEN_DELIMITER="<";var _DEFAULT_CLOSE_DELIMITER=">";var _DEFAULT_DELIMITER="%";var _DEFAULT_LOCALS_NAME="locals";var _NAME="ejs";var _REGEX_STRING="(<%%|%%>|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)";var _OPTS_PASSABLE_WITH_DATA=["delimiter","scope","context","debug","compileDebug","client","_with","rmWhitespace","strict","filename","async"];var _OPTS_PASSABLE_WITH_DATA_EXPRESS=_OPTS_PASSABLE_WITH_DATA.concat("cache");var _BOM=/^\uFEFF/;exports.cache=utils.cache;exports.fileLoader=fs.readFileSync;exports.localsName=_DEFAULT_LOCALS_NAME;exports.promiseImpl=new Function("return this;")().Promise;exports.resolveInclude=function(name,filename,isDir){var dirname=path.dirname;var extname=path.extname;var resolve=path.resolve;var includePath=resolve(isDir?filename:dirname(filename),name);var ext=extname(name);if(!ext){includePath+=".ejs"}return includePath};function resolvePaths(name,paths){var filePath;if(paths.some(function(v){filePath=exports.resolveInclude(name,v,true);return fs.existsSync(filePath)})){return filePath}}function getIncludePath(path,options){var includePath;var filePath;var views=options.views;var match=/^[A-Za-z]+:\\|^\//.exec(path);if(match&&match.length){path=path.replace(/^\/*/,"");if(Array.isArray(options.root)){includePath=resolvePaths(path,options.root)}else{includePath=exports.resolveInclude(path,options.root||"/",true)}}else{if(options.filename){filePath=exports.resolveInclude(path,options.filename);if(fs.existsSync(filePath)){includePath=filePath}}if(!includePath&&Array.isArray(views)){includePath=resolvePaths(path,views)}if(!includePath&&typeof options.includer!=="function"){throw new Error('Could not find the include file "'+options.escapeFunction(path)+'"')}}return includePath}function handleCache(options,template){var func;var filename=options.filename;var hasTemplate=arguments.length>1;if(options.cache){if(!filename){throw new Error("cache option requires a filename")}func=exports.cache.get(filename);if(func){return func}if(!hasTemplate){template=fileLoader(filename).toString().replace(_BOM,"")}}else if(!hasTemplate){if(!filename){throw new Error("Internal EJS error: no file name or template "+"provided")}template=fileLoader(filename).toString().replace(_BOM,"")}func=exports.compile(template,options);if(options.cache){exports.cache.set(filename,func)}return func}function tryHandleCache(options,data,cb){var result;if(!cb){if(typeof exports.promiseImpl=="function"){return new exports.promiseImpl(function(resolve,reject){try{result=handleCache(options)(data);resolve(result)}catch(err){reject(err)}})}else{throw new Error("Please provide a callback function")}}else{try{result=handleCache(options)(data)}catch(err){return cb(err)}cb(null,result)}}function fileLoader(filePath){return exports.fileLoader(filePath)}function includeFile(path,options){var opts=utils.shallowCopy({},options);opts.filename=getIncludePath(path,opts);if(typeof options.includer==="function"){var includerResult=options.includer(path,opts.filename);if(includerResult){if(includerResult.filename){opts.filename=includerResult.filename}if(includerResult.template){return handleCache(opts,includerResult.template)}}}return handleCache(opts)}function rethrow(err,str,flnm,lineno,esc){var lines=str.split("\n");var start=Math.max(lineno-3,0);var end=Math.min(lines.length,lineno+3);var filename=esc(flnm);var context=lines.slice(start,end).map(function(line,i){var curr=i+start+1;return(curr==lineno?" >> ":" ")+curr+"| "+line}).join("\n");err.path=filename;err.message=(filename||"ejs")+":"+lineno+"\n"+context+"\n\n"+err.message;throw err}function stripSemi(str){return str.replace(/;(\s*$)/,"$1")}exports.compile=function compile(template,opts){var templ;if(opts&&opts.scope){if(!scopeOptionWarned){console.warn("`scope` option is deprecated and will be removed in EJS 3");scopeOptionWarned=true}if(!opts.context){opts.context=opts.scope}delete opts.scope}templ=new Template(template,opts);return templ.compile()};exports.render=function(template,d,o){var data=d||{};var opts=o||{};if(arguments.length==2){utils.shallowCopyFromList(opts,data,_OPTS_PASSABLE_WITH_DATA)}return handleCache(opts,template)(data)};exports.renderFile=function(){var args=Array.prototype.slice.call(arguments);var filename=args.shift();var cb;var opts={filename:filename};var data;var viewOpts;if(typeof arguments[arguments.length-1]=="function"){cb=args.pop()}if(args.length){data=args.shift();if(args.length){utils.shallowCopy(opts,args.pop())}else{if(data.settings){if(data.settings.views){opts.views=data.settings.views}if(data.settings["view cache"]){opts.cache=true}viewOpts=data.settings["view options"];if(viewOpts){utils.shallowCopy(opts,viewOpts)}}utils.shallowCopyFromList(opts,data,_OPTS_PASSABLE_WITH_DATA_EXPRESS)}opts.filename=filename}else{data={}}return tryHandleCache(opts,data,cb)};exports.Template=Template;exports.clearCache=function(){exports.cache.reset()};function Template(text,opts){opts=opts||{};var options={};this.templateText=text;this.mode=null;this.truncate=false;this.currentLine=1;this.source="";options.client=opts.client||false;options.escapeFunction=opts.escape||opts.escapeFunction||utils.escapeXML;options.compileDebug=opts.compileDebug!==false;options.debug=!!opts.debug;options.filename=opts.filename;options.openDelimiter=opts.openDelimiter||exports.openDelimiter||_DEFAULT_OPEN_DELIMITER;options.closeDelimiter=opts.closeDelimiter||exports.closeDelimiter||_DEFAULT_CLOSE_DELIMITER;options.delimiter=opts.delimiter||exports.delimiter||_DEFAULT_DELIMITER;options.strict=opts.strict||false;options.context=opts.context;options.cache=opts.cache||false;options.rmWhitespace=opts.rmWhitespace;options.root=opts.root;options.includer=opts.includer;options.outputFunctionName=opts.outputFunctionName;options.localsName=opts.localsName||exports.localsName||_DEFAULT_LOCALS_NAME;options.views=opts.views;options.async=opts.async;options.destructuredLocals=opts.destructuredLocals;options.legacyInclude=typeof opts.legacyInclude!="undefined"?!!opts.legacyInclude:true;if(options.strict){options._with=false}else{options._with=typeof opts._with!="undefined"?opts._with:true}this.opts=options;this.regex=this.createRegex()}Template.modes={EVAL:"eval",ESCAPED:"escaped",RAW:"raw",COMMENT:"comment",LITERAL:"literal"};Template.prototype={createRegex:function(){var str=_REGEX_STRING;var delim=utils.escapeRegExpChars(this.opts.delimiter);var open=utils.escapeRegExpChars(this.opts.openDelimiter);var close=utils.escapeRegExpChars(this.opts.closeDelimiter);str=str.replace(/%/g,delim).replace(/</g,open).replace(/>/g,close);return new RegExp(str)},compile:function(){var src;var fn;var opts=this.opts;var prepended="";var appended="";var escapeFn=opts.escapeFunction;var ctor;var sanitizedFilename=opts.filename?JSON.stringify(opts.filename):"undefined";if(!this.source){this.generateSource();prepended+=' var __output = "";\n'+" function __append(s) { if (s !== undefined && s !== null) __output += s }\n";if(opts.outputFunctionName){prepended+=" var "+opts.outputFunctionName+" = __append;"+"\n"}if(opts.destructuredLocals&&opts.destructuredLocals.length){var destructuring=" var __locals = ("+opts.localsName+" || {}),\n";for(var i=0;i<opts.destructuredLocals.length;i++){var name=opts.destructuredLocals[i];if(i>0){destructuring+=",\n "}destructuring+=name+" = __locals."+name}prepended+=destructuring+";\n"}if(opts._with!==false){prepended+=" with ("+opts.localsName+" || {}) {"+"\n";appended+=" }"+"\n"}appended+=" return __output;"+"\n";this.source=prepended+this.source+appended}if(opts.compileDebug){src="var __line = 1"+"\n"+" , __lines = "+JSON.stringify(this.templateText)+"\n"+" , __filename = "+sanitizedFilename+";"+"\n"+"try {"+"\n"+this.source+"} catch (e) {"+"\n"+" rethrow(e, __lines, __filename, __line, escapeFn);"+"\n"+"}"+"\n"}else{src=this.source}if(opts.client){src="escapeFn = escapeFn || "+escapeFn.toString()+";"+"\n"+src;if(opts.compileDebug){src="rethrow = rethrow || "+rethrow.toString()+";"+"\n"+src}}if(opts.strict){src='"use strict";\n'+src}if(opts.debug){console.log(src)}if(opts.compileDebug&&opts.filename){src=src+"\n"+"//# sourceURL="+sanitizedFilename+"\n"}try{if(opts.async){try{ctor=new Function("return (async function(){}).constructor;")()}catch(e){if(e instanceof SyntaxError){throw new Error("This environment does not support async/await")}else{throw e}}}else{ctor=Function}fn=new ctor(opts.localsName+", escapeFn, include, rethrow",src)}catch(e){if(e instanceof SyntaxError){if(opts.filename){e.message+=" in "+opts.filename}e.message+=" while compiling ejs\n\n";e.message+="If the above error is not helpful, you may want to try EJS-Lint:\n";e.message+="https://github.com/RyanZim/EJS-Lint";if(!opts.async){e.message+="\n";e.message+="Or, if you meant to create an async function, pass `async: true` as an option."}}throw e}var returnedFn=opts.client?fn:function anonymous(data){var include=function(path,includeData){var d=utils.shallowCopy({},data);if(includeData){d=utils.shallowCopy(d,includeData)}return includeFile(path,opts)(d)};return fn.apply(opts.context,[data||{},escapeFn,include,rethrow])};if(opts.filename&&typeof Object.defineProperty==="function"){var filename=opts.filename;var basename=path.basename(filename,path.extname(filename));try{Object.defineProperty(returnedFn,"name",{value:basename,writable:false,enumerable:false,configurable:true})}catch(e){}}return returnedFn},generateSource:function(){var opts=this.opts;if(opts.rmWhitespace){this.templateText=this.templateText.replace(/[\r\n]+/g,"\n").replace(/^\s+|\s+$/gm,"")}this.templateText=this.templateText.replace(/[ \t]*<%_/gm,"<%_").replace(/_%>[ \t]*/gm,"_%>");var self=this;var matches=this.parseTemplateText();var d=this.opts.delimiter;var o=this.opts.openDelimiter;var c=this.opts.closeDelimiter;if(matches&&matches.length){matches.forEach(function(line,index){var closing;if(line.indexOf(o+d)===0&&line.indexOf(o+d+d)!==0){closing=matches[index+2];if(!(closing==d+c||closing=="-"+d+c||closing=="_"+d+c)){throw new Error('Could not find matching close tag for "'+line+'".')}}self.scanLine(line)})}},parseTemplateText:function(){var str=this.templateText;var pat=this.regex;var result=pat.exec(str);var arr=[];var firstPos;while(result){firstPos=result.index;if(firstPos!==0){arr.push(str.substring(0,firstPos));str=str.slice(firstPos)}arr.push(result[0]);str=str.slice(result[0].length);result=pat.exec(str)}if(str){arr.push(str)}return arr},_addOutput:function(line){if(this.truncate){line=line.replace(/^(?:\r\n|\r|\n)/,"");this.truncate=false}if(!line){return line}line=line.replace(/\\/g,"\\\\");line=line.replace(/\n/g,"\\n");line=line.replace(/\r/g,"\\r");line=line.replace(/"/g,'\\"');this.source+=' ; __append("'+line+'")'+"\n"},scanLine:function(line){var self=this;var d=this.opts.delimiter;var o=this.opts.openDelimiter;var c=this.opts.closeDelimiter;var newLineCount=0;newLineCount=line.split("\n").length-1;switch(line){case o+d:case o+d+"_":this.mode=Template.modes.EVAL;break;case o+d+"=":this.mode=Template.modes.ESCAPED;break;case o+d+"-":this.mode=Template.modes.RAW;break;case o+d+"#":this.mode=Template.modes.COMMENT;break;case o+d+d:this.mode=Template.modes.LITERAL;this.source+=' ; __append("'+line.replace(o+d+d,o+d)+'")'+"\n";break;case d+d+c:this.mode=Template.modes.LITERAL;this.source+=' ; __append("'+line.replace(d+d+c,d+c)+'")'+"\n";break;case d+c:case"-"+d+c:case"_"+d+c:if(this.mode==Template.modes.LITERAL){this._addOutput(line)}this.mode=null;this.truncate=line.indexOf("-")===0||line.indexOf("_")===0;break;default:if(this.mode){switch(this.mode){case Template.modes.EVAL:case Template.modes.ESCAPED:case Template.modes.RAW:if(line.lastIndexOf("//")>line.lastIndexOf("\n")){line+="\n"}}switch(this.mode){case Template.modes.EVAL:this.source+=" ; "+line+"\n";break;case Template.modes.ESCAPED:this.source+=" ; __append(escapeFn("+stripSemi(line)+"))"+"\n";break;case Template.modes.RAW:this.source+=" ; __append("+stripSemi(line)+")"+"\n";break;case Template.modes.COMMENT:break;case Template.modes.LITERAL:this._addOutput(line);break}}else{this._addOutput(line)}}if(self.opts.compileDebug&&newLineCount){this.currentLine+=newLineCount;this.source+=" ; __line = "+this.currentLine+"\n"}}};exports.escapeXML=utils.escapeXML;exports.__express=exports.renderFile;exports.VERSION=_VERSION_STRING;exports.name=_NAME;if(typeof window!="undefined"){window.ejs=exports}},{"../package.json":6,"./utils":2,fs:3,path:4}],2:[function(require,module,exports){"use strict";var regExpChars=/[|\\{}()[\]^$+*?.]/g;exports.escapeRegExpChars=function(string){if(!string){return""}return String(string).replace(regExpChars,"\\$&")};var _ENCODE_HTML_RULES={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&#34;","'":"&#39;"};var _MATCH_HTML=/[&<>'"]/g;function encode_char(c){return _ENCODE_HTML_RULES[c]||c}var escapeFuncStr="var _ENCODE_HTML_RULES = {\n"+' "&": "&amp;"\n'+' , "<": "&lt;"\n'+' , ">": "&gt;"\n'+' , \'"\': "&#34;"\n'+' , "\'": "&#39;"\n'+" }\n"+" , _MATCH_HTML = /[&<>'\"]/g;\n"+"function encode_char(c) {\n"+" return _ENCODE_HTML_RULES[c] || c;\n"+"};\n";exports.escapeXML=function(markup){return markup==undefined?"":String(markup).replace(_MATCH_HTML,encode_char)};exports.escapeXML.toString=function(){return Function.prototype.toString.call(this)+";\n"+escapeFuncStr};exports.shallowCopy=function(to,from){from=from||{};for(var p in from){to[p]=from[p]}return to};exports.shallowCopyFromList=function(to,from,list){for(var i=0;i<list.length;i++){var p=list[i];if(typeof from[p]!="undefined"){to[p]=from[p]}}return to};exports.cache={_data:{},set:function(key,val){this._data[key]=val},get:function(key){return this._data[key]},remove:function(key){delete this._data[key]},reset:function(){this._data={}}};exports.hyphenToCamel=function(str){return str.replace(/-[a-z]/g,function(match){return match[1].toUpperCase()})}},{}],3:[function(require,module,exports){},{}],4:[function(require,module,exports){(function(process){function normalizeArray(parts,allowAboveRoot){var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up--;up){parts.unshift("..")}}return parts}exports.resolve=function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:process.cwd();if(typeof path!=="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){continue}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=path.charAt(0)==="/"}resolvedPath=normalizeArray(filter(resolvedPath.split("/"),function(p){return!!p}),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."};exports.normalize=function(path){var isAbsolute=exports.isAbsolute(path),trailingSlash=substr(path,-1)==="/";path=normalizeArray(filter(path.split("/"),function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path};exports.isAbsolute=function(path){return path.charAt(0)==="/"};exports.join=function(){var paths=Array.prototype.slice.call(arguments,0);return exports.normalize(filter(paths,function(p,index){if(typeof p!=="string"){throw new TypeError("Arguments to path.join must be strings")}return p}).join("/"))};exports.relative=function(from,to){from=exports.resolve(from).substr(1);to=exports.resolve(to).substr(1);function trim(arr){var start=0;for(;start<arr.length;start++){if(arr[start]!=="")break}var end=arr.length-1;for(;end>=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i<length;i++){if(fromParts[i]!==toParts[i]){samePartsLength=i;break}}var outputParts=[];for(var i=samePartsLength;i<fromParts.length;i++){outputParts.push("..")}outputParts=outputParts.concat(toParts.slice(samePartsLength));return outputParts.join("/")};exports.sep="/";exports.delimiter=":";exports.dirname=function(path){if(typeof path!=="string")path=path+"";if(path.length===0)return".";var code=path.charCodeAt(0);var hasRoot=code===47;var end=-1;var matchedSlash=true;for(var i=path.length-1;i>=1;--i){code=path.charCodeAt(i);if(code===47){if(!matchedSlash){end=i;break}}else{matchedSlash=false}}if(end===-1)return hasRoot?"/":".";if(hasRoot&&end===1){return"/"}return path.slice(0,end)};function basename(path){if(typeof path!=="string")path=path+"";var start=0;var end=-1;var matchedSlash=true;var i;for(i=path.length-1;i>=0;--i){if(path.charCodeAt(i)===47){if(!matchedSlash){start=i+1;break}}else if(end===-1){matchedSlash=false;end=i+1}}if(end===-1)return"";return path.slice(start,end)}exports.basename=function(path,ext){var f=basename(path);if(ext&&f.substr(-1*ext.length)===ext){f=f.substr(0,f.length-ext.length)}return f};exports.extname=function(path){if(typeof path!=="string")path=path+"";var startDot=-1;var startPart=0;var end=-1;var matchedSlash=true;var preDotState=0;for(var i=path.length-1;i>=0;--i){var code=path.charCodeAt(i);if(code===47){if(!matchedSlash){startPart=i+1;break}continue}if(end===-1){matchedSlash=false;end=i+1}if(code===46){if(startDot===-1)startDot=i;else if(preDotState!==1)preDotState=1}else if(startDot!==-1){preDotState=-1}}if(startDot===-1||end===-1||preDotState===0||preDotState===1&&startDot===end-1&&startDot===startPart+1){return""}return path.slice(startDot,end)};function filter(xs,f){if(xs.filter)return xs.filter(f);var res=[];for(var i=0;i<xs.length;i++){if(f(xs[i],i,xs))res.push(xs[i])}return res}var substr="ab".substr(-1)==="b"?function(str,start,len){return str.substr(start,len)}:function(str,start,len){if(start<0)start=str.length+start;return str.substr(start,len)}}).call(this,require("_process"))},{_process:5}],5:[function(require,module,exports){var process=module.exports={};var cachedSetTimeout;var cachedClearTimeout;function defaultSetTimout(){throw new Error("setTimeout has not been defined")}function defaultClearTimeout(){throw new Error("clearTimeout has not been defined")}(function(){try{if(typeof setTimeout==="function"){cachedSetTimeout=setTimeout}else{cachedSetTimeout=defaultSetTimout}}catch(e){cachedSetTimeout=defaultSetTimout}try{if(typeof clearTimeout==="function"){cachedClearTimeout=clearTimeout}else{cachedClearTimeout=defaultClearTimeout}}catch(e){cachedClearTimeout=defaultClearTimeout}})();function runTimeout(fun){if(cachedSetTimeout===setTimeout){return setTimeout(fun,0)}if((cachedSetTimeout===defaultSetTimout||!cachedSetTimeout)&&setTimeout){cachedSetTimeout=setTimeout;return setTimeout(fun,0)}try{return cachedSetTimeout(fun,0)}catch(e){try{return cachedSetTimeout.call(null,fun,0)}catch(e){return cachedSetTimeout.call(this,fun,0)}}}function runClearTimeout(marker){if(cachedClearTimeout===clearTimeout){return clearTimeout(marker)}if((cachedClearTimeout===defaultClearTimeout||!cachedClearTimeout)&&clearTimeout){cachedClearTimeout=clearTimeout;return clearTimeout(marker)}try{return cachedClearTimeout(marker)}catch(e){try{return cachedClearTimeout.call(null,marker)}catch(e){return cachedClearTimeout.call(this,marker)}}}var queue=[];var draining=false;var currentQueue;var queueIndex=-1;function cleanUpNextTick(){if(!draining||!currentQueue){return}draining=false;if(currentQueue.length){queue=currentQueue.concat(queue)}else{queueIndex=-1}if(queue.length){drainQueue()}}function drainQueue(){if(draining){return}var timeout=runTimeout(cleanUpNextTick);draining=true;var len=queue.length;while(len){currentQueue=queue;queue=[];while(++queueIndex<len){if(currentQueue){currentQueue[queueIndex].run()}}queueIndex=-1;len=queue.length}currentQueue=null;draining=false;runClearTimeout(timeout)}process.nextTick=function(fun){var args=new Array(arguments.length-1);if(arguments.length>1){for(var i=1;i<arguments.length;i++){args[i-1]=arguments[i]}}queue.push(new Item(fun,args));if(queue.length===1&&!draining){runTimeout(drainQueue)}};function Item(fun,array){this.fun=fun;this.array=array}Item.prototype.run=function(){this.fun.apply(null,this.array)};process.title="browser";process.browser=true;process.env={};process.argv=[];process.version="";process.versions={};function noop(){}process.on=noop;process.addListener=noop;process.once=noop;process.off=noop;process.removeListener=noop;process.removeAllListeners=noop;process.emit=noop;process.prependListener=noop;process.prependOnceListener=noop;process.listeners=function(name){return[]};process.binding=function(name){throw new Error("process.binding is not supported")};process.cwd=function(){return"/"};process.chdir=function(dir){throw new Error("process.chdir is not supported")};process.umask=function(){return 0}},{}],6:[function(require,module,exports){module.exports={name:"ejs",description:"Embedded JavaScript templates",keywords:["template","engine","ejs"],version:"3.1.6",author:"Matthew Eernisse <mde@fleegix.org> (http://fleegix.org)",license:"Apache-2.0",bin:{ejs:"./bin/cli.js"},main:"./lib/ejs.js",jsdelivr:"ejs.min.js",unpkg:"ejs.min.js",repository:{type:"git",url:"git://github.com/mde/ejs.git"},bugs:"https://github.com/mde/ejs/issues",homepage:"https://github.com/mde/ejs",dependencies:{jake:"^10.6.1"},devDependencies:{browserify:"^16.5.1",eslint:"^6.8.0","git-directory-deploy":"^1.5.1",jsdoc:"^3.6.4","lru-cache":"^4.0.1",mocha:"^7.1.1","uglify-js":"^3.3.16"},engines:{node:">=0.10.0"},scripts:{test:"mocha"}}},{}]},{},[1])(1)});
1 +var fs = require('fs');
2 +var execSync = require('child_process').execSync;
3 +var exec = function (cmd) {
4 + execSync(cmd, {stdio: 'inherit'});
5 +};
6 +
7 +/* global jake, task, desc, publishTask */
8 +
9 +task('build', ['lint', 'clean', 'browserify', 'minify'], function () {
10 + console.log('Build completed.');
11 +});
12 +
13 +desc('Cleans browerified/minified files and package files');
14 +task('clean', ['clobber'], function () {
15 + jake.rmRf('./ejs.js');
16 + jake.rmRf('./ejs.min.js');
17 + console.log('Cleaned up compiled files.');
18 +});
19 +
20 +desc('Lints the source code');
21 +task('lint', ['clean'], function () {
22 + exec('./node_modules/.bin/eslint "**/*.js"');
23 + console.log('Linting completed.');
24 +});
25 +
26 +task('browserify', function () {
27 + exec('./node_modules/browserify/bin/cmd.js --standalone ejs lib/ejs.js > ejs.js');
28 + console.log('Browserification completed.');
29 +});
30 +
31 +task('minify', function () {
32 + exec('./node_modules/uglify-js/bin/uglifyjs ejs.js > ejs.min.js');
33 + console.log('Minification completed.');
34 +});
35 +
36 +desc('Generates the EJS API docs for the public API');
37 +task('doc', function () {
38 + jake.rmRf('out');
39 + exec('./node_modules/.bin/jsdoc --verbose -c jsdoc.json lib/* docs/jsdoc/*');
40 + console.log('Documentation generated in ./out.');
41 +});
42 +
43 +desc('Generates the EJS API docs for the public and private API');
44 +task('devdoc', function () {
45 + jake.rmRf('out');
46 + exec('./node_modules/.bin/jsdoc --verbose -p -c jsdoc.json lib/* docs/jsdoc/*');
47 + console.log('Documentation generated in ./out.');
48 +});
49 +
50 +desc('Publishes the EJS API docs');
51 +task('docPublish', ['doc'], function () {
52 + fs.writeFileSync('out/CNAME', 'api.ejs.co');
53 + console.log('Pushing docs to gh-pages...');
54 + exec('./node_modules/.bin/git-directory-deploy --directory out/');
55 + console.log('Docs published to gh-pages.');
56 +});
57 +
58 +desc('Runs the EJS test suite');
59 +task('test', ['lint'], function () {
60 + exec('./node_modules/.bin/mocha');
61 +});
62 +
63 +publishTask('ejs', ['build'], function () {
64 + this.packageFiles.include([
65 + 'jakefile.js',
66 + 'README.md',
67 + 'LICENSE',
68 + 'package.json',
69 + 'ejs.js',
70 + 'ejs.min.js',
71 + 'lib/**',
72 + 'bin/**',
73 + 'usage.txt'
74 + ]);
75 +});
76 +
77 +jake.Task.publish.on('complete', function () {
78 + console.log('Updating hosted docs...');
79 + console.log('If this fails, run jake docPublish to re-try.');
80 + jake.Task.docPublish.invoke();
81 +});
1 +/*
2 + * EJS Embedded JavaScript templates
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +'use strict';
20 +
21 +/**
22 + * @file Embedded JavaScript templating engine. {@link http://ejs.co}
23 + * @author Matthew Eernisse <mde@fleegix.org>
24 + * @author Tiancheng "Timothy" Gu <timothygu99@gmail.com>
25 + * @project EJS
26 + * @license {@link http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0}
27 + */
28 +
29 +/**
30 + * EJS internal functions.
31 + *
32 + * Technically this "module" lies in the same file as {@link module:ejs}, for
33 + * the sake of organization all the private functions re grouped into this
34 + * module.
35 + *
36 + * @module ejs-internal
37 + * @private
38 + */
39 +
40 +/**
41 + * Embedded JavaScript templating engine.
42 + *
43 + * @module ejs
44 + * @public
45 + */
46 +
47 +var fs = require('fs');
48 +var path = require('path');
49 +var utils = require('./utils');
50 +
51 +var scopeOptionWarned = false;
52 +/** @type {string} */
53 +var _VERSION_STRING = require('../package.json').version;
54 +var _DEFAULT_OPEN_DELIMITER = '<';
55 +var _DEFAULT_CLOSE_DELIMITER = '>';
56 +var _DEFAULT_DELIMITER = '%';
57 +var _DEFAULT_LOCALS_NAME = 'locals';
58 +var _NAME = 'ejs';
59 +var _REGEX_STRING = '(<%%|%%>|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)';
60 +var _OPTS_PASSABLE_WITH_DATA = ['delimiter', 'scope', 'context', 'debug', 'compileDebug',
61 + 'client', '_with', 'rmWhitespace', 'strict', 'filename', 'async'];
62 +// We don't allow 'cache' option to be passed in the data obj for
63 +// the normal `render` call, but this is where Express 2 & 3 put it
64 +// so we make an exception for `renderFile`
65 +var _OPTS_PASSABLE_WITH_DATA_EXPRESS = _OPTS_PASSABLE_WITH_DATA.concat('cache');
66 +var _BOM = /^\uFEFF/;
67 +
68 +/**
69 + * EJS template function cache. This can be a LRU object from lru-cache NPM
70 + * module. By default, it is {@link module:utils.cache}, a simple in-process
71 + * cache that grows continuously.
72 + *
73 + * @type {Cache}
74 + */
75 +
76 +exports.cache = utils.cache;
77 +
78 +/**
79 + * Custom file loader. Useful for template preprocessing or restricting access
80 + * to a certain part of the filesystem.
81 + *
82 + * @type {fileLoader}
83 + */
84 +
85 +exports.fileLoader = fs.readFileSync;
86 +
87 +/**
88 + * Name of the object containing the locals.
89 + *
90 + * This variable is overridden by {@link Options}`.localsName` if it is not
91 + * `undefined`.
92 + *
93 + * @type {String}
94 + * @public
95 + */
96 +
97 +exports.localsName = _DEFAULT_LOCALS_NAME;
98 +
99 +/**
100 + * Promise implementation -- defaults to the native implementation if available
101 + * This is mostly just for testability
102 + *
103 + * @type {PromiseConstructorLike}
104 + * @public
105 + */
106 +
107 +exports.promiseImpl = (new Function('return this;'))().Promise;
108 +
109 +/**
110 + * Get the path to the included file from the parent file path and the
111 + * specified path.
112 + *
113 + * @param {String} name specified path
114 + * @param {String} filename parent file path
115 + * @param {Boolean} [isDir=false] whether the parent file path is a directory
116 + * @return {String}
117 + */
118 +exports.resolveInclude = function(name, filename, isDir) {
119 + var dirname = path.dirname;
120 + var extname = path.extname;
121 + var resolve = path.resolve;
122 + var includePath = resolve(isDir ? filename : dirname(filename), name);
123 + var ext = extname(name);
124 + if (!ext) {
125 + includePath += '.ejs';
126 + }
127 + return includePath;
128 +};
129 +
130 +/**
131 + * Try to resolve file path on multiple directories
132 + *
133 + * @param {String} name specified path
134 + * @param {Array<String>} paths list of possible parent directory paths
135 + * @return {String}
136 + */
137 +function resolvePaths(name, paths) {
138 + var filePath;
139 + if (paths.some(function (v) {
140 + filePath = exports.resolveInclude(name, v, true);
141 + return fs.existsSync(filePath);
142 + })) {
143 + return filePath;
144 + }
145 +}
146 +
147 +/**
148 + * Get the path to the included file by Options
149 + *
150 + * @param {String} path specified path
151 + * @param {Options} options compilation options
152 + * @return {String}
153 + */
154 +function getIncludePath(path, options) {
155 + var includePath;
156 + var filePath;
157 + var views = options.views;
158 + var match = /^[A-Za-z]+:\\|^\//.exec(path);
159 +
160 + // Abs path
161 + if (match && match.length) {
162 + path = path.replace(/^\/*/, '');
163 + if (Array.isArray(options.root)) {
164 + includePath = resolvePaths(path, options.root);
165 + } else {
166 + includePath = exports.resolveInclude(path, options.root || '/', true);
167 + }
168 + }
169 + // Relative paths
170 + else {
171 + // Look relative to a passed filename first
172 + if (options.filename) {
173 + filePath = exports.resolveInclude(path, options.filename);
174 + if (fs.existsSync(filePath)) {
175 + includePath = filePath;
176 + }
177 + }
178 + // Then look in any views directories
179 + if (!includePath && Array.isArray(views)) {
180 + includePath = resolvePaths(path, views);
181 + }
182 + if (!includePath && typeof options.includer !== 'function') {
183 + throw new Error('Could not find the include file "' +
184 + options.escapeFunction(path) + '"');
185 + }
186 + }
187 + return includePath;
188 +}
189 +
190 +/**
191 + * Get the template from a string or a file, either compiled on-the-fly or
192 + * read from cache (if enabled), and cache the template if needed.
193 + *
194 + * If `template` is not set, the file specified in `options.filename` will be
195 + * read.
196 + *
197 + * If `options.cache` is true, this function reads the file from
198 + * `options.filename` so it must be set prior to calling this function.
199 + *
200 + * @memberof module:ejs-internal
201 + * @param {Options} options compilation options
202 + * @param {String} [template] template source
203 + * @return {(TemplateFunction|ClientFunction)}
204 + * Depending on the value of `options.client`, either type might be returned.
205 + * @static
206 + */
207 +
208 +function handleCache(options, template) {
209 + var func;
210 + var filename = options.filename;
211 + var hasTemplate = arguments.length > 1;
212 +
213 + if (options.cache) {
214 + if (!filename) {
215 + throw new Error('cache option requires a filename');
216 + }
217 + func = exports.cache.get(filename);
218 + if (func) {
219 + return func;
220 + }
221 + if (!hasTemplate) {
222 + template = fileLoader(filename).toString().replace(_BOM, '');
223 + }
224 + }
225 + else if (!hasTemplate) {
226 + // istanbul ignore if: should not happen at all
227 + if (!filename) {
228 + throw new Error('Internal EJS error: no file name or template '
229 + + 'provided');
230 + }
231 + template = fileLoader(filename).toString().replace(_BOM, '');
232 + }
233 + func = exports.compile(template, options);
234 + if (options.cache) {
235 + exports.cache.set(filename, func);
236 + }
237 + return func;
238 +}
239 +
240 +/**
241 + * Try calling handleCache with the given options and data and call the
242 + * callback with the result. If an error occurs, call the callback with
243 + * the error. Used by renderFile().
244 + *
245 + * @memberof module:ejs-internal
246 + * @param {Options} options compilation options
247 + * @param {Object} data template data
248 + * @param {RenderFileCallback} cb callback
249 + * @static
250 + */
251 +
252 +function tryHandleCache(options, data, cb) {
253 + var result;
254 + if (!cb) {
255 + if (typeof exports.promiseImpl == 'function') {
256 + return new exports.promiseImpl(function (resolve, reject) {
257 + try {
258 + result = handleCache(options)(data);
259 + resolve(result);
260 + }
261 + catch (err) {
262 + reject(err);
263 + }
264 + });
265 + }
266 + else {
267 + throw new Error('Please provide a callback function');
268 + }
269 + }
270 + else {
271 + try {
272 + result = handleCache(options)(data);
273 + }
274 + catch (err) {
275 + return cb(err);
276 + }
277 +
278 + cb(null, result);
279 + }
280 +}
281 +
282 +/**
283 + * fileLoader is independent
284 + *
285 + * @param {String} filePath ejs file path.
286 + * @return {String} The contents of the specified file.
287 + * @static
288 + */
289 +
290 +function fileLoader(filePath){
291 + return exports.fileLoader(filePath);
292 +}
293 +
294 +/**
295 + * Get the template function.
296 + *
297 + * If `options.cache` is `true`, then the template is cached.
298 + *
299 + * @memberof module:ejs-internal
300 + * @param {String} path path for the specified file
301 + * @param {Options} options compilation options
302 + * @return {(TemplateFunction|ClientFunction)}
303 + * Depending on the value of `options.client`, either type might be returned
304 + * @static
305 + */
306 +
307 +function includeFile(path, options) {
308 + var opts = utils.shallowCopy({}, options);
309 + opts.filename = getIncludePath(path, opts);
310 + if (typeof options.includer === 'function') {
311 + var includerResult = options.includer(path, opts.filename);
312 + if (includerResult) {
313 + if (includerResult.filename) {
314 + opts.filename = includerResult.filename;
315 + }
316 + if (includerResult.template) {
317 + return handleCache(opts, includerResult.template);
318 + }
319 + }
320 + }
321 + return handleCache(opts);
322 +}
323 +
324 +/**
325 + * Re-throw the given `err` in context to the `str` of ejs, `filename`, and
326 + * `lineno`.
327 + *
328 + * @implements {RethrowCallback}
329 + * @memberof module:ejs-internal
330 + * @param {Error} err Error object
331 + * @param {String} str EJS source
332 + * @param {String} flnm file name of the EJS file
333 + * @param {Number} lineno line number of the error
334 + * @param {EscapeCallback} esc
335 + * @static
336 + */
337 +
338 +function rethrow(err, str, flnm, lineno, esc) {
339 + var lines = str.split('\n');
340 + var start = Math.max(lineno - 3, 0);
341 + var end = Math.min(lines.length, lineno + 3);
342 + var filename = esc(flnm);
343 + // Error context
344 + var context = lines.slice(start, end).map(function (line, i){
345 + var curr = i + start + 1;
346 + return (curr == lineno ? ' >> ' : ' ')
347 + + curr
348 + + '| '
349 + + line;
350 + }).join('\n');
351 +
352 + // Alter exception message
353 + err.path = filename;
354 + err.message = (filename || 'ejs') + ':'
355 + + lineno + '\n'
356 + + context + '\n\n'
357 + + err.message;
358 +
359 + throw err;
360 +}
361 +
362 +function stripSemi(str){
363 + return str.replace(/;(\s*$)/, '$1');
364 +}
365 +
366 +/**
367 + * Compile the given `str` of ejs into a template function.
368 + *
369 + * @param {String} template EJS template
370 + *
371 + * @param {Options} [opts] compilation options
372 + *
373 + * @return {(TemplateFunction|ClientFunction)}
374 + * Depending on the value of `opts.client`, either type might be returned.
375 + * Note that the return type of the function also depends on the value of `opts.async`.
376 + * @public
377 + */
378 +
379 +exports.compile = function compile(template, opts) {
380 + var templ;
381 +
382 + // v1 compat
383 + // 'scope' is 'context'
384 + // FIXME: Remove this in a future version
385 + if (opts && opts.scope) {
386 + if (!scopeOptionWarned){
387 + console.warn('`scope` option is deprecated and will be removed in EJS 3');
388 + scopeOptionWarned = true;
389 + }
390 + if (!opts.context) {
391 + opts.context = opts.scope;
392 + }
393 + delete opts.scope;
394 + }
395 + templ = new Template(template, opts);
396 + return templ.compile();
397 +};
398 +
399 +/**
400 + * Render the given `template` of ejs.
401 + *
402 + * If you would like to include options but not data, you need to explicitly
403 + * call this function with `data` being an empty object or `null`.
404 + *
405 + * @param {String} template EJS template
406 + * @param {Object} [data={}] template data
407 + * @param {Options} [opts={}] compilation and rendering options
408 + * @return {(String|Promise<String>)}
409 + * Return value type depends on `opts.async`.
410 + * @public
411 + */
412 +
413 +exports.render = function (template, d, o) {
414 + var data = d || {};
415 + var opts = o || {};
416 +
417 + // No options object -- if there are optiony names
418 + // in the data, copy them to options
419 + if (arguments.length == 2) {
420 + utils.shallowCopyFromList(opts, data, _OPTS_PASSABLE_WITH_DATA);
421 + }
422 +
423 + return handleCache(opts, template)(data);
424 +};
425 +
426 +/**
427 + * Render an EJS file at the given `path` and callback `cb(err, str)`.
428 + *
429 + * If you would like to include options but not data, you need to explicitly
430 + * call this function with `data` being an empty object or `null`.
431 + *
432 + * @param {String} path path to the EJS file
433 + * @param {Object} [data={}] template data
434 + * @param {Options} [opts={}] compilation and rendering options
435 + * @param {RenderFileCallback} cb callback
436 + * @public
437 + */
438 +
439 +exports.renderFile = function () {
440 + var args = Array.prototype.slice.call(arguments);
441 + var filename = args.shift();
442 + var cb;
443 + var opts = {filename: filename};
444 + var data;
445 + var viewOpts;
446 +
447 + // Do we have a callback?
448 + if (typeof arguments[arguments.length - 1] == 'function') {
449 + cb = args.pop();
450 + }
451 + // Do we have data/opts?
452 + if (args.length) {
453 + // Should always have data obj
454 + data = args.shift();
455 + // Normal passed opts (data obj + opts obj)
456 + if (args.length) {
457 + // Use shallowCopy so we don't pollute passed in opts obj with new vals
458 + utils.shallowCopy(opts, args.pop());
459 + }
460 + // Special casing for Express (settings + opts-in-data)
461 + else {
462 + // Express 3 and 4
463 + if (data.settings) {
464 + // Pull a few things from known locations
465 + if (data.settings.views) {
466 + opts.views = data.settings.views;
467 + }
468 + if (data.settings['view cache']) {
469 + opts.cache = true;
470 + }
471 + // Undocumented after Express 2, but still usable, esp. for
472 + // items that are unsafe to be passed along with data, like `root`
473 + viewOpts = data.settings['view options'];
474 + if (viewOpts) {
475 + utils.shallowCopy(opts, viewOpts);
476 + }
477 + }
478 + // Express 2 and lower, values set in app.locals, or people who just
479 + // want to pass options in their data. NOTE: These values will override
480 + // anything previously set in settings or settings['view options']
481 + utils.shallowCopyFromList(opts, data, _OPTS_PASSABLE_WITH_DATA_EXPRESS);
482 + }
483 + opts.filename = filename;
484 + }
485 + else {
486 + data = {};
487 + }
488 +
489 + return tryHandleCache(opts, data, cb);
490 +};
491 +
492 +/**
493 + * Clear intermediate JavaScript cache. Calls {@link Cache#reset}.
494 + * @public
495 + */
496 +
497 +/**
498 + * EJS template class
499 + * @public
500 + */
501 +exports.Template = Template;
502 +
503 +exports.clearCache = function () {
504 + exports.cache.reset();
505 +};
506 +
507 +function Template(text, opts) {
508 + opts = opts || {};
509 + var options = {};
510 + this.templateText = text;
511 + /** @type {string | null} */
512 + this.mode = null;
513 + this.truncate = false;
514 + this.currentLine = 1;
515 + this.source = '';
516 + options.client = opts.client || false;
517 + options.escapeFunction = opts.escape || opts.escapeFunction || utils.escapeXML;
518 + options.compileDebug = opts.compileDebug !== false;
519 + options.debug = !!opts.debug;
520 + options.filename = opts.filename;
521 + options.openDelimiter = opts.openDelimiter || exports.openDelimiter || _DEFAULT_OPEN_DELIMITER;
522 + options.closeDelimiter = opts.closeDelimiter || exports.closeDelimiter || _DEFAULT_CLOSE_DELIMITER;
523 + options.delimiter = opts.delimiter || exports.delimiter || _DEFAULT_DELIMITER;
524 + options.strict = opts.strict || false;
525 + options.context = opts.context;
526 + options.cache = opts.cache || false;
527 + options.rmWhitespace = opts.rmWhitespace;
528 + options.root = opts.root;
529 + options.includer = opts.includer;
530 + options.outputFunctionName = opts.outputFunctionName;
531 + options.localsName = opts.localsName || exports.localsName || _DEFAULT_LOCALS_NAME;
532 + options.views = opts.views;
533 + options.async = opts.async;
534 + options.destructuredLocals = opts.destructuredLocals;
535 + options.legacyInclude = typeof opts.legacyInclude != 'undefined' ? !!opts.legacyInclude : true;
536 +
537 + if (options.strict) {
538 + options._with = false;
539 + }
540 + else {
541 + options._with = typeof opts._with != 'undefined' ? opts._with : true;
542 + }
543 +
544 + this.opts = options;
545 +
546 + this.regex = this.createRegex();
547 +}
548 +
549 +Template.modes = {
550 + EVAL: 'eval',
551 + ESCAPED: 'escaped',
552 + RAW: 'raw',
553 + COMMENT: 'comment',
554 + LITERAL: 'literal'
555 +};
556 +
557 +Template.prototype = {
558 + createRegex: function () {
559 + var str = _REGEX_STRING;
560 + var delim = utils.escapeRegExpChars(this.opts.delimiter);
561 + var open = utils.escapeRegExpChars(this.opts.openDelimiter);
562 + var close = utils.escapeRegExpChars(this.opts.closeDelimiter);
563 + str = str.replace(/%/g, delim)
564 + .replace(/</g, open)
565 + .replace(/>/g, close);
566 + return new RegExp(str);
567 + },
568 +
569 + compile: function () {
570 + /** @type {string} */
571 + var src;
572 + /** @type {ClientFunction} */
573 + var fn;
574 + var opts = this.opts;
575 + var prepended = '';
576 + var appended = '';
577 + /** @type {EscapeCallback} */
578 + var escapeFn = opts.escapeFunction;
579 + /** @type {FunctionConstructor} */
580 + var ctor;
581 + /** @type {string} */
582 + var sanitizedFilename = opts.filename ? JSON.stringify(opts.filename) : 'undefined';
583 +
584 + if (!this.source) {
585 + this.generateSource();
586 + prepended +=
587 + ' var __output = "";\n' +
588 + ' function __append(s) { if (s !== undefined && s !== null) __output += s }\n';
589 + if (opts.outputFunctionName) {
590 + prepended += ' var ' + opts.outputFunctionName + ' = __append;' + '\n';
591 + }
592 + if (opts.destructuredLocals && opts.destructuredLocals.length) {
593 + var destructuring = ' var __locals = (' + opts.localsName + ' || {}),\n';
594 + for (var i = 0; i < opts.destructuredLocals.length; i++) {
595 + var name = opts.destructuredLocals[i];
596 + if (i > 0) {
597 + destructuring += ',\n ';
598 + }
599 + destructuring += name + ' = __locals.' + name;
600 + }
601 + prepended += destructuring + ';\n';
602 + }
603 + if (opts._with !== false) {
604 + prepended += ' with (' + opts.localsName + ' || {}) {' + '\n';
605 + appended += ' }' + '\n';
606 + }
607 + appended += ' return __output;' + '\n';
608 + this.source = prepended + this.source + appended;
609 + }
610 +
611 + if (opts.compileDebug) {
612 + src = 'var __line = 1' + '\n'
613 + + ' , __lines = ' + JSON.stringify(this.templateText) + '\n'
614 + + ' , __filename = ' + sanitizedFilename + ';' + '\n'
615 + + 'try {' + '\n'
616 + + this.source
617 + + '} catch (e) {' + '\n'
618 + + ' rethrow(e, __lines, __filename, __line, escapeFn);' + '\n'
619 + + '}' + '\n';
620 + }
621 + else {
622 + src = this.source;
623 + }
624 +
625 + if (opts.client) {
626 + src = 'escapeFn = escapeFn || ' + escapeFn.toString() + ';' + '\n' + src;
627 + if (opts.compileDebug) {
628 + src = 'rethrow = rethrow || ' + rethrow.toString() + ';' + '\n' + src;
629 + }
630 + }
631 +
632 + if (opts.strict) {
633 + src = '"use strict";\n' + src;
634 + }
635 + if (opts.debug) {
636 + console.log(src);
637 + }
638 + if (opts.compileDebug && opts.filename) {
639 + src = src + '\n'
640 + + '//# sourceURL=' + sanitizedFilename + '\n';
641 + }
642 +
643 + try {
644 + if (opts.async) {
645 + // Have to use generated function for this, since in envs without support,
646 + // it breaks in parsing
647 + try {
648 + ctor = (new Function('return (async function(){}).constructor;'))();
649 + }
650 + catch(e) {
651 + if (e instanceof SyntaxError) {
652 + throw new Error('This environment does not support async/await');
653 + }
654 + else {
655 + throw e;
656 + }
657 + }
658 + }
659 + else {
660 + ctor = Function;
661 + }
662 + fn = new ctor(opts.localsName + ', escapeFn, include, rethrow', src);
663 + }
664 + catch(e) {
665 + // istanbul ignore else
666 + if (e instanceof SyntaxError) {
667 + if (opts.filename) {
668 + e.message += ' in ' + opts.filename;
669 + }
670 + e.message += ' while compiling ejs\n\n';
671 + e.message += 'If the above error is not helpful, you may want to try EJS-Lint:\n';
672 + e.message += 'https://github.com/RyanZim/EJS-Lint';
673 + if (!opts.async) {
674 + e.message += '\n';
675 + e.message += 'Or, if you meant to create an async function, pass `async: true` as an option.';
676 + }
677 + }
678 + throw e;
679 + }
680 +
681 + // Return a callable function which will execute the function
682 + // created by the source-code, with the passed data as locals
683 + // Adds a local `include` function which allows full recursive include
684 + var returnedFn = opts.client ? fn : function anonymous(data) {
685 + var include = function (path, includeData) {
686 + var d = utils.shallowCopy({}, data);
687 + if (includeData) {
688 + d = utils.shallowCopy(d, includeData);
689 + }
690 + return includeFile(path, opts)(d);
691 + };
692 + return fn.apply(opts.context, [data || {}, escapeFn, include, rethrow]);
693 + };
694 + if (opts.filename && typeof Object.defineProperty === 'function') {
695 + var filename = opts.filename;
696 + var basename = path.basename(filename, path.extname(filename));
697 + try {
698 + Object.defineProperty(returnedFn, 'name', {
699 + value: basename,
700 + writable: false,
701 + enumerable: false,
702 + configurable: true
703 + });
704 + } catch (e) {/* ignore */}
705 + }
706 + return returnedFn;
707 + },
708 +
709 + generateSource: function () {
710 + var opts = this.opts;
711 +
712 + if (opts.rmWhitespace) {
713 + // Have to use two separate replace here as `^` and `$` operators don't
714 + // work well with `\r` and empty lines don't work well with the `m` flag.
715 + this.templateText =
716 + this.templateText.replace(/[\r\n]+/g, '\n').replace(/^\s+|\s+$/gm, '');
717 + }
718 +
719 + // Slurp spaces and tabs before <%_ and after _%>
720 + this.templateText =
721 + this.templateText.replace(/[ \t]*<%_/gm, '<%_').replace(/_%>[ \t]*/gm, '_%>');
722 +
723 + var self = this;
724 + var matches = this.parseTemplateText();
725 + var d = this.opts.delimiter;
726 + var o = this.opts.openDelimiter;
727 + var c = this.opts.closeDelimiter;
728 +
729 + if (matches && matches.length) {
730 + matches.forEach(function (line, index) {
731 + var closing;
732 + // If this is an opening tag, check for closing tags
733 + // FIXME: May end up with some false positives here
734 + // Better to store modes as k/v with openDelimiter + delimiter as key
735 + // Then this can simply check against the map
736 + if ( line.indexOf(o + d) === 0 // If it is a tag
737 + && line.indexOf(o + d + d) !== 0) { // and is not escaped
738 + closing = matches[index + 2];
739 + if (!(closing == d + c || closing == '-' + d + c || closing == '_' + d + c)) {
740 + throw new Error('Could not find matching close tag for "' + line + '".');
741 + }
742 + }
743 + self.scanLine(line);
744 + });
745 + }
746 +
747 + },
748 +
749 + parseTemplateText: function () {
750 + var str = this.templateText;
751 + var pat = this.regex;
752 + var result = pat.exec(str);
753 + var arr = [];
754 + var firstPos;
755 +
756 + while (result) {
757 + firstPos = result.index;
758 +
759 + if (firstPos !== 0) {
760 + arr.push(str.substring(0, firstPos));
761 + str = str.slice(firstPos);
762 + }
763 +
764 + arr.push(result[0]);
765 + str = str.slice(result[0].length);
766 + result = pat.exec(str);
767 + }
768 +
769 + if (str) {
770 + arr.push(str);
771 + }
772 +
773 + return arr;
774 + },
775 +
776 + _addOutput: function (line) {
777 + if (this.truncate) {
778 + // Only replace single leading linebreak in the line after
779 + // -%> tag -- this is the single, trailing linebreak
780 + // after the tag that the truncation mode replaces
781 + // Handle Win / Unix / old Mac linebreaks -- do the \r\n
782 + // combo first in the regex-or
783 + line = line.replace(/^(?:\r\n|\r|\n)/, '');
784 + this.truncate = false;
785 + }
786 + if (!line) {
787 + return line;
788 + }
789 +
790 + // Preserve literal slashes
791 + line = line.replace(/\\/g, '\\\\');
792 +
793 + // Convert linebreaks
794 + line = line.replace(/\n/g, '\\n');
795 + line = line.replace(/\r/g, '\\r');
796 +
797 + // Escape double-quotes
798 + // - this will be the delimiter during execution
799 + line = line.replace(/"/g, '\\"');
800 + this.source += ' ; __append("' + line + '")' + '\n';
801 + },
802 +
803 + scanLine: function (line) {
804 + var self = this;
805 + var d = this.opts.delimiter;
806 + var o = this.opts.openDelimiter;
807 + var c = this.opts.closeDelimiter;
808 + var newLineCount = 0;
809 +
810 + newLineCount = (line.split('\n').length - 1);
811 +
812 + switch (line) {
813 + case o + d:
814 + case o + d + '_':
815 + this.mode = Template.modes.EVAL;
816 + break;
817 + case o + d + '=':
818 + this.mode = Template.modes.ESCAPED;
819 + break;
820 + case o + d + '-':
821 + this.mode = Template.modes.RAW;
822 + break;
823 + case o + d + '#':
824 + this.mode = Template.modes.COMMENT;
825 + break;
826 + case o + d + d:
827 + this.mode = Template.modes.LITERAL;
828 + this.source += ' ; __append("' + line.replace(o + d + d, o + d) + '")' + '\n';
829 + break;
830 + case d + d + c:
831 + this.mode = Template.modes.LITERAL;
832 + this.source += ' ; __append("' + line.replace(d + d + c, d + c) + '")' + '\n';
833 + break;
834 + case d + c:
835 + case '-' + d + c:
836 + case '_' + d + c:
837 + if (this.mode == Template.modes.LITERAL) {
838 + this._addOutput(line);
839 + }
840 +
841 + this.mode = null;
842 + this.truncate = line.indexOf('-') === 0 || line.indexOf('_') === 0;
843 + break;
844 + default:
845 + // In script mode, depends on type of tag
846 + if (this.mode) {
847 + // If '//' is found without a line break, add a line break.
848 + switch (this.mode) {
849 + case Template.modes.EVAL:
850 + case Template.modes.ESCAPED:
851 + case Template.modes.RAW:
852 + if (line.lastIndexOf('//') > line.lastIndexOf('\n')) {
853 + line += '\n';
854 + }
855 + }
856 + switch (this.mode) {
857 + // Just executing code
858 + case Template.modes.EVAL:
859 + this.source += ' ; ' + line + '\n';
860 + break;
861 + // Exec, esc, and output
862 + case Template.modes.ESCAPED:
863 + this.source += ' ; __append(escapeFn(' + stripSemi(line) + '))' + '\n';
864 + break;
865 + // Exec and output
866 + case Template.modes.RAW:
867 + this.source += ' ; __append(' + stripSemi(line) + ')' + '\n';
868 + break;
869 + case Template.modes.COMMENT:
870 + // Do nothing
871 + break;
872 + // Literal <%% mode, append as raw output
873 + case Template.modes.LITERAL:
874 + this._addOutput(line);
875 + break;
876 + }
877 + }
878 + // In string mode, just add the output
879 + else {
880 + this._addOutput(line);
881 + }
882 + }
883 +
884 + if (self.opts.compileDebug && newLineCount) {
885 + this.currentLine += newLineCount;
886 + this.source += ' ; __line = ' + this.currentLine + '\n';
887 + }
888 + }
889 +};
890 +
891 +/**
892 + * Escape characters reserved in XML.
893 + *
894 + * This is simply an export of {@link module:utils.escapeXML}.
895 + *
896 + * If `markup` is `undefined` or `null`, the empty string is returned.
897 + *
898 + * @param {String} markup Input string
899 + * @return {String} Escaped string
900 + * @public
901 + * @func
902 + * */
903 +exports.escapeXML = utils.escapeXML;
904 +
905 +/**
906 + * Express.js support.
907 + *
908 + * This is an alias for {@link module:ejs.renderFile}, in order to support
909 + * Express.js out-of-the-box.
910 + *
911 + * @func
912 + */
913 +
914 +exports.__express = exports.renderFile;
915 +
916 +/**
917 + * Version of EJS.
918 + *
919 + * @readonly
920 + * @type {String}
921 + * @public
922 + */
923 +
924 +exports.VERSION = _VERSION_STRING;
925 +
926 +/**
927 + * Name for detection of EJS.
928 + *
929 + * @readonly
930 + * @type {String}
931 + * @public
932 + */
933 +
934 +exports.name = _NAME;
935 +
936 +/* istanbul ignore if */
937 +if (typeof window != 'undefined') {
938 + window.ejs = exports;
939 +}
1 +/*
2 + * EJS Embedded JavaScript templates
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +/**
20 + * Private utility functions
21 + * @module utils
22 + * @private
23 + */
24 +
25 +'use strict';
26 +
27 +var regExpChars = /[|\\{}()[\]^$+*?.]/g;
28 +
29 +/**
30 + * Escape characters reserved in regular expressions.
31 + *
32 + * If `string` is `undefined` or `null`, the empty string is returned.
33 + *
34 + * @param {String} string Input string
35 + * @return {String} Escaped string
36 + * @static
37 + * @private
38 + */
39 +exports.escapeRegExpChars = function (string) {
40 + // istanbul ignore if
41 + if (!string) {
42 + return '';
43 + }
44 + return String(string).replace(regExpChars, '\\$&');
45 +};
46 +
47 +var _ENCODE_HTML_RULES = {
48 + '&': '&amp;',
49 + '<': '&lt;',
50 + '>': '&gt;',
51 + '"': '&#34;',
52 + "'": '&#39;'
53 +};
54 +var _MATCH_HTML = /[&<>'"]/g;
55 +
56 +function encode_char(c) {
57 + return _ENCODE_HTML_RULES[c] || c;
58 +}
59 +
60 +/**
61 + * Stringified version of constants used by {@link module:utils.escapeXML}.
62 + *
63 + * It is used in the process of generating {@link ClientFunction}s.
64 + *
65 + * @readonly
66 + * @type {String}
67 + */
68 +
69 +var escapeFuncStr =
70 + 'var _ENCODE_HTML_RULES = {\n'
71 ++ ' "&": "&amp;"\n'
72 ++ ' , "<": "&lt;"\n'
73 ++ ' , ">": "&gt;"\n'
74 ++ ' , \'"\': "&#34;"\n'
75 ++ ' , "\'": "&#39;"\n'
76 ++ ' }\n'
77 ++ ' , _MATCH_HTML = /[&<>\'"]/g;\n'
78 ++ 'function encode_char(c) {\n'
79 ++ ' return _ENCODE_HTML_RULES[c] || c;\n'
80 ++ '};\n';
81 +
82 +/**
83 + * Escape characters reserved in XML.
84 + *
85 + * If `markup` is `undefined` or `null`, the empty string is returned.
86 + *
87 + * @implements {EscapeCallback}
88 + * @param {String} markup Input string
89 + * @return {String} Escaped string
90 + * @static
91 + * @private
92 + */
93 +
94 +exports.escapeXML = function (markup) {
95 + return markup == undefined
96 + ? ''
97 + : String(markup)
98 + .replace(_MATCH_HTML, encode_char);
99 +};
100 +exports.escapeXML.toString = function () {
101 + return Function.prototype.toString.call(this) + ';\n' + escapeFuncStr;
102 +};
103 +
104 +/**
105 + * Naive copy of properties from one object to another.
106 + * Does not recurse into non-scalar properties
107 + * Does not check to see if the property has a value before copying
108 + *
109 + * @param {Object} to Destination object
110 + * @param {Object} from Source object
111 + * @return {Object} Destination object
112 + * @static
113 + * @private
114 + */
115 +exports.shallowCopy = function (to, from) {
116 + from = from || {};
117 + for (var p in from) {
118 + to[p] = from[p];
119 + }
120 + return to;
121 +};
122 +
123 +/**
124 + * Naive copy of a list of key names, from one object to another.
125 + * Only copies property if it is actually defined
126 + * Does not recurse into non-scalar properties
127 + *
128 + * @param {Object} to Destination object
129 + * @param {Object} from Source object
130 + * @param {Array} list List of properties to copy
131 + * @return {Object} Destination object
132 + * @static
133 + * @private
134 + */
135 +exports.shallowCopyFromList = function (to, from, list) {
136 + for (var i = 0; i < list.length; i++) {
137 + var p = list[i];
138 + if (typeof from[p] != 'undefined') {
139 + to[p] = from[p];
140 + }
141 + }
142 + return to;
143 +};
144 +
145 +/**
146 + * Simple in-process cache implementation. Does not implement limits of any
147 + * sort.
148 + *
149 + * @implements {Cache}
150 + * @static
151 + * @private
152 + */
153 +exports.cache = {
154 + _data: {},
155 + set: function (key, val) {
156 + this._data[key] = val;
157 + },
158 + get: function (key) {
159 + return this._data[key];
160 + },
161 + remove: function (key) {
162 + delete this._data[key];
163 + },
164 + reset: function () {
165 + this._data = {};
166 + }
167 +};
168 +
169 +/**
170 + * Transforms hyphen case variable into camel case.
171 + *
172 + * @param {String} string Hyphen case string
173 + * @return {String} Camel case string
174 + * @static
175 + * @private
176 + */
177 +exports.hyphenToCamel = function (str) {
178 + return str.replace(/-[a-z]/g, function (match) { return match[1].toUpperCase(); });
179 +};
1 +{
2 + "name": "ejs",
3 + "description": "Embedded JavaScript templates",
4 + "keywords": [
5 + "template",
6 + "engine",
7 + "ejs"
8 + ],
9 + "version": "3.1.6",
10 + "author": "Matthew Eernisse <mde@fleegix.org> (http://fleegix.org)",
11 + "license": "Apache-2.0",
12 + "bin": {
13 + "ejs": "./bin/cli.js"
14 + },
15 + "main": "./lib/ejs.js",
16 + "jsdelivr": "ejs.min.js",
17 + "unpkg": "ejs.min.js",
18 + "repository": {
19 + "type": "git",
20 + "url": "git://github.com/mde/ejs.git"
21 + },
22 + "bugs": "https://github.com/mde/ejs/issues",
23 + "homepage": "https://github.com/mde/ejs",
24 + "dependencies": {
25 + "jake": "^10.6.1"
26 + },
27 + "devDependencies": {
28 + "browserify": "^16.5.1",
29 + "eslint": "^6.8.0",
30 + "git-directory-deploy": "^1.5.1",
31 + "jsdoc": "^3.6.4",
32 + "lru-cache": "^4.0.1",
33 + "mocha": "^7.1.1",
34 + "uglify-js": "^3.3.16"
35 + },
36 + "engines": {
37 + "node": ">=0.10.0"
38 + },
39 + "scripts": {
40 + "test": "mocha"
41 + }
42 +}
1 +EJS Embedded JavaScript templates
2 +{Usage}: ejs [options ...] template-file [data variables ...]
3 +
4 +{Options}:
5 + -o, --output-file FILE Write the rendered output to FILE rather than stdout.
6 + -f, --data-file FILE Must be JSON-formatted. Use parsed input from FILE as data for rendering.
7 + -i, --data-input STRING Must be JSON-formatted and URI-encoded. Use parsed input from STRING as data for rendering.
8 + -m, --delimiter CHARACTER Use CHARACTER with angle brackets for open/close (defaults to %).
9 + -p, --open-delimiter CHARACTER Use CHARACTER instead of left angle bracket to open.
10 + -c, --close-delimiter CHARACTER Use CHARACTER instead of right angle bracket to close.
11 + -s, --strict When set to `true`, generated function is in strict mode
12 + -n --no-with Use 'locals' object for vars rather than using `with` (implies --strict).
13 + -l --locals-name Name to use for the object storing local variables when not using `with`.
14 + -w --rm-whitespace Remove all safe-to-remove whitespace, including leading and trailing whitespace.
15 + -d --debug Outputs generated function body
16 + -h, --help Display this help message.
17 + -V/v, --version Display the EJS version.
18 +
19 +{Examples}:
20 + ejs -m $ ./test/fixtures/user.ejs -f ./user_data.json
21 + ejs -m $ ./test/fixtures/user.ejs name=Lerxst
22 + ejs -p [ -c ] ./template_file.ejs -o ./output.html
23 + ejs -n -l _ ./some_template.ejs -f ./data_file.json
24 + ejs -w ./template_with_whitspace.ejs -o ./output_file.html
1 +'use strict';
2 +
3 +var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
4 +
5 +module.exports = function (str) {
6 + if (typeof str !== 'string') {
7 + throw new TypeError('Expected a string');
8 + }
9 +
10 + return str.replace(matchOperatorsRe, '\\$&');
11 +};
1 +The MIT License (MIT)
2 +
3 +Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
4 +
5 +Permission is hereby granted, free of charge, to any person obtaining a copy
6 +of this software and associated documentation files (the "Software"), to deal
7 +in the Software without restriction, including without limitation the rights
8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 +copies of the Software, and to permit persons to whom the Software is
10 +furnished to do so, subject to the following conditions:
11 +
12 +The above copyright notice and this permission notice shall be included in
13 +all copies or substantial portions of the Software.
14 +
15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 +THE SOFTWARE.
1 +{
2 + "name": "escape-string-regexp",
3 + "version": "1.0.5",
4 + "description": "Escape RegExp special characters",
5 + "license": "MIT",
6 + "repository": "sindresorhus/escape-string-regexp",
7 + "author": {
8 + "name": "Sindre Sorhus",
9 + "email": "sindresorhus@gmail.com",
10 + "url": "sindresorhus.com"
11 + },
12 + "maintainers": [
13 + "Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)",
14 + "Joshua Boy Nicolai Appelman <joshua@jbna.nl> (jbna.nl)"
15 + ],
16 + "engines": {
17 + "node": ">=0.8.0"
18 + },
19 + "scripts": {
20 + "test": "xo && ava"
21 + },
22 + "files": [
23 + "index.js"
24 + ],
25 + "keywords": [
26 + "escape",
27 + "regex",
28 + "regexp",
29 + "re",
30 + "regular",
31 + "expression",
32 + "string",
33 + "str",
34 + "special",
35 + "characters"
36 + ],
37 + "devDependencies": {
38 + "ava": "*",
39 + "xo": "*"
40 + }
41 +}
1 +# escape-string-regexp [![Build Status](https://travis-ci.org/sindresorhus/escape-string-regexp.svg?branch=master)](https://travis-ci.org/sindresorhus/escape-string-regexp)
2 +
3 +> Escape RegExp special characters
4 +
5 +
6 +## Install
7 +
8 +```
9 +$ npm install --save escape-string-regexp
10 +```
11 +
12 +
13 +## Usage
14 +
15 +```js
16 +const escapeStringRegexp = require('escape-string-regexp');
17 +
18 +const escapedString = escapeStringRegexp('how much $ for a unicorn?');
19 +//=> 'how much \$ for a unicorn\?'
20 +
21 +new RegExp(escapedString);
22 +```
23 +
24 +
25 +## License
26 +
27 +MIT © [Sindre Sorhus](http://sindresorhus.com)
1 +## FileList
2 +
3 +A FileList is a lazy-evaluated list of files. When given a list
4 +of glob patterns for possible files to be included in the file
5 +list, instead of searching the file structures to find the files,
6 +a FileList holds the pattern for latter use.
7 +
8 +This allows you to define a FileList to match any number of
9 +files, but only search out the actual files when then FileList
10 +itself is actually used. The key is that the first time an
11 +element of the FileList/Array is requested, the pending patterns
12 +are resolved into a real list of file names.
13 +
14 +### Usage
15 +
16 +Add files to the list with the `include` method. You can add glob
17 +patterns, individual files, or RegExp objects. When the Array
18 +methods are invoked on the FileList, these items are resolved to
19 +an actual list of files.
20 +
21 +```javascript
22 +var fl = new FileList();
23 +fl.include('test/*.js');
24 +fl.exclude('test/helpers.js');
25 +```
26 +
27 +Use the `exclude` method to override inclusions. You can use this
28 +when your inclusions are too broad.
29 +
30 +### Array methods
31 +
32 +FileList has lazy-evaluated versions of most of the array
33 +methods, including the following:
34 +
35 +* join
36 +* pop
37 +* push
38 +* concat
39 +* reverse
40 +* shift
41 +* unshift
42 +* slice
43 +* splice
44 +* sort
45 +* filter
46 +* forEach
47 +* some
48 +* every
49 +* map
50 +* indexOf
51 +* lastIndexOf
52 +* reduce
53 +* reduceRight
54 +
55 +When you call one of these methods, the items in the FileList
56 +will be resolved to the full list of files, and the method will
57 +be invoked on that result.
58 +
59 +### Special `length` method
60 +
61 +`length`: FileList includes a length *method* (instead of a
62 +property) which returns the number of actual files in the list
63 +once it's been resolved.
64 +
65 +### FileList-specific methods
66 +
67 +`include`: Add a filename/glob/regex to the list
68 +
69 +`exclude`: Override inclusions by excluding a filename/glob/regex
70 +
71 +`resolve`: Resolve the items in the FileList to the full list of
72 +files. This method is invoked automatically when one of the array
73 +methods is called.
74 +
75 +`toArray`: Immediately resolves the list of items, and returns an
76 +actual array of filepaths.
77 +
78 +`clearInclusions`: Clears any pending items -- must be used
79 +before resolving the list.
80 +
81 +`clearExclusions`: Clears the list of exclusions rules.
82 +
83 +
84 +
1 +// Type definitions for filelist v0.0.6
2 +// Project: https://github.com/mde/filelist
3 +// Definitions by: Christophe MASSOLIN <https://github.com/FuriouZz>
4 +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
5 +
6 +declare module "filelist" {
7 + export class FileList {
8 + pendingAdd: string[]
9 + pending: boolean
10 + excludes: {
11 + pats: RegExp[],
12 + funcs: Function[],
13 + regex: null | RegExp
14 + }
15 + items: string[]
16 + static clone(): FileList
17 + static verbose: boolean
18 + toArray(): string[]
19 + include(options: any, ...items: string[]): void
20 + exclude(...items: string[]): void
21 + resolve(): void
22 + clearInclusions(): void
23 + clearExclusions(): void
24 + length(): number
25 + toString(): string;
26 + toLocaleString(): string;
27 + push(...items: string[]): number;
28 + pop(): string | undefined;
29 + concat(...items: ReadonlyArray<string>[]): string[];
30 + concat(...items: (string | ReadonlyArray<string>)[]): string[];
31 + join(separator?: string): string;
32 + reverse(): string[];
33 + shift(): string | undefined;
34 + slice(start?: number, end?: number): string[];
35 + sort(compareFn?: (a: string, b: string) => number): this;
36 + splice(start: number, deleteCount?: number): string[];
37 + splice(start: number, deleteCount: number, ...items: string[]): string[];
38 + unshift(...items: string[]): number;
39 + indexOf(searchElement: string, fromIndex?: number): number;
40 + lastIndexOf(searchElement: string, fromIndex?: number): number;
41 + every(callbackfn: (value: string, index: number, array: string[]) => boolean, thisArg?: any): boolean;
42 + some(callbackfn: (value: string, index: number, array: string[]) => boolean, thisArg?: any): boolean;
43 + forEach(callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any): void;
44 + map<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any): U[];
45 + filter<S extends string>(callbackfn: (value: string, index: number, array: string[]) => value is S, thisArg?: any): S[];
46 + filter(callbackfn: (value: string, index: number, array: string[]) => any, thisArg?: any): string[];
47 + reduce(callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string;
48 + reduce(callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string;
49 + reduce<U>(callbackfn: (previousValue: U, currentValue: string, currentIndex: number, array: string[]) => U, initialValue: U): U;
50 + reduceRight(callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string): string;
51 + reduceRight(callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string;
52 + reduceRight<U>(callbackfn: (previousValue: U, currentValue: string, currentIndex: number, array: string[]) => U, initialValue: U): U;
53 + }
54 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +var fs = require('fs')
19 +, path = require('path')
20 +, minimatch = require('minimatch')
21 +, escapeRegExpChars
22 +, merge
23 +, basedir
24 +, _readDir
25 +, readdirR
26 +, globSync;
27 +
28 + /**
29 + @name escapeRegExpChars
30 + @function
31 + @return {String} A string of escaped characters
32 + @description Escapes regex control-characters in strings
33 + used to build regexes dynamically
34 + @param {String} string The string of chars to escape
35 + */
36 + escapeRegExpChars = (function () {
37 + var specials = [ '^', '$', '/', '.', '*', '+', '?', '|', '(', ')',
38 + '[', ']', '{', '}', '\\' ];
39 + var sRE = new RegExp('(\\' + specials.join('|\\') + ')', 'g');
40 + return function (string) {
41 + var str = string || '';
42 + str = String(str);
43 + return str.replace(sRE, '\\$1');
44 + };
45 + })();
46 +
47 + /**
48 + @name merge
49 + @function
50 + @return {Object} Returns the merged object
51 + @description Merge merges `otherObject` into `object` and takes care of deep
52 + merging of objects
53 + @param {Object} object Object to merge into
54 + @param {Object} otherObject Object to read from
55 + */
56 + merge = function (object, otherObject) {
57 + var obj = object || {}
58 + , otherObj = otherObject || {}
59 + , key, value;
60 +
61 + for (key in otherObj) {
62 + value = otherObj[key];
63 +
64 + // Check if a value is an Object, if so recursively add it's key/values
65 + if (typeof value === 'object' && !(value instanceof Array)) {
66 + // Update value of object to the one from otherObj
67 + obj[key] = merge(obj[key], value);
68 + }
69 + // Value is anything other than an Object, so just add it
70 + else {
71 + obj[key] = value;
72 + }
73 + }
74 +
75 + return obj;
76 + };
77 + /**
78 + Given a patern, return the base directory of it (ie. the folder
79 + that will contain all the files matching the path).
80 + eg. file.basedir('/test/**') => '/test/'
81 + Path ending by '/' are considerd as folder while other are considerd
82 + as files, eg.:
83 + file.basedir('/test/a/') => '/test/a'
84 + file.basedir('/test/a') => '/test'
85 + The returned path always end with a '/' so we have:
86 + file.basedir(file.basedir(x)) == file.basedir(x)
87 + */
88 + basedir = function (pathParam) {
89 + var bd = ''
90 + , parts
91 + , part
92 + , pos = 0
93 + , p = pathParam || '';
94 +
95 + // If the path has a leading asterisk, basedir is the current dir
96 + if (p.indexOf('*') == 0 || p.indexOf('**') == 0) {
97 + return '.';
98 + }
99 +
100 + // always consider .. at the end as a folder and not a filename
101 + if (/(?:^|\/|\\)\.\.$/.test(p.slice(-3))) {
102 + p += '/';
103 + }
104 +
105 + parts = p.split(/\\|\//);
106 + for (var i = 0, l = parts.length - 1; i < l; i++) {
107 + part = parts[i];
108 + if (part.indexOf('*') > -1 || part.indexOf('**') > -1) {
109 + break;
110 + }
111 + pos += part.length + 1;
112 + bd += part + p[pos - 1];
113 + }
114 + if (!bd) {
115 + bd = '.';
116 + }
117 + // Strip trailing slashes
118 + if (!(bd == '\\' || bd == '/')) {
119 + bd = bd.replace(/\\$|\/$/, '');
120 + }
121 + return bd;
122 +
123 + };
124 +
125 + // Return the contents of a given directory
126 + _readDir = function (dirPath) {
127 + var dir = path.normalize(dirPath)
128 + , paths = []
129 + , ret = [dir]
130 + , msg;
131 +
132 + try {
133 + paths = fs.readdirSync(dir);
134 + }
135 + catch (e) {
136 + msg = 'Could not read path ' + dir + '\n';
137 + if (e.stack) {
138 + msg += e.stack;
139 + }
140 + throw new Error(msg);
141 + }
142 +
143 + paths.forEach(function (p) {
144 + var curr = path.join(dir, p);
145 + var stat = fs.statSync(curr);
146 + if (stat.isDirectory()) {
147 + ret = ret.concat(_readDir(curr));
148 + }
149 + else {
150 + ret.push(curr);
151 + }
152 + });
153 +
154 + return ret;
155 + };
156 +
157 + /**
158 + @name file#readdirR
159 + @function
160 + @return {Array} Returns the contents as an Array, can be configured via opts.format
161 + @description Reads the given directory returning it's contents
162 + @param {String} dir The directory to read
163 + @param {Object} opts Options to use
164 + @param {String} [opts.format] Set the format to return(Default: Array)
165 + */
166 + readdirR = function (dir, opts) {
167 + var options = opts || {}
168 + , format = options.format || 'array'
169 + , ret;
170 + ret = _readDir(dir);
171 + return format == 'string' ? ret.join('\n') : ret;
172 + };
173 +
174 +
175 +globSync = function (pat, opts) {
176 + var dirname = basedir(pat)
177 + , files
178 + , matches;
179 +
180 + try {
181 + files = readdirR(dirname).map(function(file){
182 + return file.replace(/\\/g, '/');
183 + });
184 + }
185 + // Bail if path doesn't exist -- assume no files
186 + catch(e) {
187 + if (FileList.verbose) console.error(e.message);
188 + }
189 +
190 + if (files) {
191 + pat = path.normalize(pat);
192 + matches = minimatch.match(files, pat, opts || {});
193 + }
194 + return matches || [];
195 +};
196 +
197 +// Constants
198 +// ---------------
199 +// List of all the builtin Array methods we want to override
200 +var ARRAY_METHODS = Object.getOwnPropertyNames(Array.prototype)
201 +// Array methods that return a copy instead of affecting the original
202 + , SPECIAL_RETURN = {
203 + 'concat': true
204 + , 'slice': true
205 + , 'filter': true
206 + , 'map': true
207 + }
208 +// Default file-patterns we want to ignore
209 + , DEFAULT_IGNORE_PATTERNS = [
210 + /(^|[\/\\])CVS([\/\\]|$)/
211 + , /(^|[\/\\])\.svn([\/\\]|$)/
212 + , /(^|[\/\\])\.git([\/\\]|$)/
213 + , /\.bak$/
214 + , /~$/
215 + ]
216 +// Ignore core files
217 + , DEFAULT_IGNORE_FUNCS = [
218 + function (name) {
219 + var isDir = false
220 + , stats;
221 + try {
222 + stats = fs.statSync(name);
223 + isDir = stats.isDirectory();
224 + }
225 + catch(e) {}
226 + return (/(^|[\/\\])core$/).test(name) && !isDir;
227 + }
228 + ];
229 +
230 +var FileList = function () {
231 + var self = this
232 + , wrap;
233 +
234 + // List of glob-patterns or specific filenames
235 + this.pendingAdd = [];
236 + // Switched to false after lazy-eval of files
237 + this.pending = true;
238 + // Used to calculate exclusions from the list of files
239 + this.excludes = {
240 + pats: DEFAULT_IGNORE_PATTERNS.slice()
241 + , funcs: DEFAULT_IGNORE_FUNCS.slice()
242 + , regex: null
243 + };
244 + this.items = [];
245 +
246 + // Wrap the array methods with the delegates
247 + wrap = function (prop) {
248 + var arr;
249 + self[prop] = function () {
250 + if (self.pending) {
251 + self.resolve();
252 + }
253 + if (typeof self.items[prop] == 'function') {
254 + // Special method that return a copy
255 + if (SPECIAL_RETURN[prop]) {
256 + arr = self.items[prop].apply(self.items, arguments);
257 + return FileList.clone(self, arr);
258 + }
259 + else {
260 + return self.items[prop].apply(self.items, arguments);
261 + }
262 + }
263 + else {
264 + return self.items[prop];
265 + }
266 + };
267 + };
268 + for (var i = 0, ii = ARRAY_METHODS.length; i < ii; i++) {
269 + wrap(ARRAY_METHODS[i]);
270 + }
271 +
272 + // Include whatever files got passed to the constructor
273 + this.include.apply(this, arguments);
274 +
275 + // Fix constructor linkage
276 + this.constructor = FileList;
277 +};
278 +
279 +FileList.prototype = new (function () {
280 + var globPattern = /[*?\[\{]/;
281 +
282 + var _addMatching = function (item) {
283 + var matches = globSync(item.path, item.options);
284 + this.items = this.items.concat(matches);
285 + }
286 +
287 + , _resolveAdd = function (item) {
288 + if (globPattern.test(item.path)) {
289 + _addMatching.call(this, item);
290 + }
291 + else {
292 + this.push(item.path);
293 + }
294 + }
295 +
296 + , _calculateExcludeRe = function () {
297 + var pats = this.excludes.pats
298 + , pat
299 + , excl = []
300 + , matches = [];
301 +
302 + for (var i = 0, ii = pats.length; i < ii; i++) {
303 + pat = pats[i];
304 + if (typeof pat == 'string') {
305 + // Glob, look up files
306 + if (/[*?]/.test(pat)) {
307 + matches = globSync(pat);
308 + matches = matches.map(function (m) {
309 + return escapeRegExpChars(m);
310 + });
311 + excl = excl.concat(matches);
312 + }
313 + // String for regex
314 + else {
315 + excl.push(escapeRegExpChars(pat));
316 + }
317 + }
318 + // Regex, grab the string-representation
319 + else if (pat instanceof RegExp) {
320 + excl.push(pat.toString().replace(/^\/|\/$/g, ''));
321 + }
322 + }
323 + if (excl.length) {
324 + this.excludes.regex = new RegExp('(' + excl.join(')|(') + ')');
325 + }
326 + else {
327 + this.excludes.regex = /^$/;
328 + }
329 + }
330 +
331 + , _resolveExclude = function () {
332 + var self = this;
333 + _calculateExcludeRe.call(this);
334 + // No `reject` method, so use reverse-filter
335 + this.items = this.items.filter(function (name) {
336 + return !self.shouldExclude(name);
337 + });
338 + };
339 +
340 + /**
341 + * Includes file-patterns in the FileList. Should be called with one or more
342 + * pattern for finding file to include in the list. Arguments should be strings
343 + * for either a glob-pattern or a specific file-name, or an array of them
344 + */
345 + this.include = function () {
346 + var args = Array.prototype.slice.call(arguments)
347 + , arg
348 + , includes = { items: [], options: {} };
349 +
350 + for (var i = 0, ilen = args.length; i < ilen; i++) {
351 + arg = args[i];
352 +
353 + if (typeof arg === 'object' && !Array.isArray(arg)) {
354 + merge(includes.options, arg);
355 + } else {
356 + includes.items = includes.items.concat(arg).filter(function (item) {
357 + return !!item;
358 + });
359 + }
360 + }
361 +
362 + var items = includes.items.map(function(item) {
363 + return { path: item, options: includes.options };
364 + });
365 +
366 + this.pendingAdd = this.pendingAdd.concat(items);
367 +
368 + return this;
369 + };
370 +
371 + /**
372 + * Indicates whether a particular file would be filtered out by the current
373 + * exclusion rules for this FileList.
374 + * @param {String} name The filename to check
375 + * @return {Boolean} Whether or not the file should be excluded
376 + */
377 + this.shouldExclude = function (name) {
378 + if (!this.excludes.regex) {
379 + _calculateExcludeRe.call(this);
380 + }
381 + var excl = this.excludes;
382 + return excl.regex.test(name) || excl.funcs.some(function (f) {
383 + return !!f(name);
384 + });
385 + };
386 +
387 + /**
388 + * Excludes file-patterns from the FileList. Should be called with one or more
389 + * pattern for finding file to include in the list. Arguments can be:
390 + * 1. Strings for either a glob-pattern or a specific file-name
391 + * 2. Regular expression literals
392 + * 3. Functions to be run on the filename that return a true/false
393 + */
394 + this.exclude = function () {
395 + var args = Array.isArray(arguments[0]) ? arguments[0] : arguments
396 + , arg;
397 + for (var i = 0, ii = args.length; i < ii; i++) {
398 + arg = args[i];
399 + if (typeof arg == 'function' && !(arg instanceof RegExp)) {
400 + this.excludes.funcs.push(arg);
401 + }
402 + else {
403 + this.excludes.pats.push(arg);
404 + }
405 + }
406 + if (!this.pending) {
407 + _resolveExclude.call(this);
408 + }
409 + return this;
410 + };
411 +
412 + /**
413 + * Populates the FileList from the include/exclude rules with a list of
414 + * actual files
415 + */
416 + this.resolve = function () {
417 + var item
418 + , uniqueFunc = function (p, c) {
419 + if (p.indexOf(c) < 0) {
420 + p.push(c);
421 + }
422 + return p;
423 + };
424 + if (this.pending) {
425 + this.pending = false;
426 + while ((item = this.pendingAdd.shift())) {
427 + _resolveAdd.call(this, item);
428 + }
429 + // Reduce to a unique list
430 + this.items = this.items.reduce(uniqueFunc, []);
431 + // Remove exclusions
432 + _resolveExclude.call(this);
433 + }
434 + return this;
435 + };
436 +
437 + /**
438 + * Convert to a plain-jane array
439 + */
440 + this.toArray = function () {
441 + // Call slice to ensure lazy-resolution before slicing items
442 + var ret = this.slice().items.slice();
443 + return ret;
444 + };
445 +
446 + /**
447 + * Clear any pending items -- only useful before
448 + * calling `resolve`
449 + */
450 + this.clearInclusions = function () {
451 + this.pendingAdd = [];
452 + return this;
453 + };
454 +
455 + /**
456 + * Clear any current exclusion rules
457 + */
458 + this.clearExclusions = function () {
459 + this.excludes = {
460 + pats: []
461 + , funcs: []
462 + , regex: null
463 + };
464 + return this;
465 + };
466 +
467 +})();
468 +
469 +// Static method, used to create copy returned by special
470 +// array methods
471 +FileList.clone = function (list, items) {
472 + var clone = new FileList();
473 + if (items) {
474 + clone.items = items;
475 + }
476 + clone.pendingAdd = list.pendingAdd;
477 + clone.pending = list.pending;
478 + for (var p in list.excludes) {
479 + clone.excludes[p] = list.excludes[p];
480 + }
481 + return clone;
482 +};
483 +
484 +FileList.verbose = true
485 +
486 +exports.FileList = FileList;
1 +testTask('FileList', function () {
2 + this.testFiles.include('test/*.js');
3 +});
4 +
5 +publishTask('FileList', function () {
6 + this.packageFiles.include([
7 + 'jakefile.js',
8 + 'README.md',
9 + 'package.json',
10 + 'index.js',
11 + 'index.d.ts'
12 + ]);
13 +});
14 +
15 +
1 +{
2 + "name": "filelist",
3 + "version": "1.0.2",
4 + "description": "Lazy-evaluating list of files, based on globs or regex patterns",
5 + "main": "index.js",
6 + "types": "index.d.ts",
7 + "scripts": {
8 + "test": "jake test"
9 + },
10 + "repository": {
11 + "type": "git",
12 + "url": "git://github.com/mde/filelist.git"
13 + },
14 + "keywords": [
15 + "file",
16 + "utility",
17 + "glob"
18 + ],
19 + "author": "Matthew Eernisse <mde@fleegix.org> (http://fleegix.org)",
20 + "license": "Apache-2.0",
21 + "bugs": {
22 + "url": "https://github.com/mde/filelist/issues"
23 + },
24 + "homepage": "https://github.com/mde/filelist",
25 + "dependencies": {
26 + "minimatch": "^3.0.4"
27 + }
28 +}
1 +'use strict';
2 +module.exports = (flag, argv) => {
3 + argv = argv || process.argv;
4 + const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--');
5 + const pos = argv.indexOf(prefix + flag);
6 + const terminatorPos = argv.indexOf('--');
7 + return pos !== -1 && (terminatorPos === -1 ? true : pos < terminatorPos);
8 +};
1 +MIT License
2 +
3 +Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
4 +
5 +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:
6 +
7 +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 +
9 +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.
1 +{
2 + "name": "has-flag",
3 + "version": "3.0.0",
4 + "description": "Check if argv has a specific flag",
5 + "license": "MIT",
6 + "repository": "sindresorhus/has-flag",
7 + "author": {
8 + "name": "Sindre Sorhus",
9 + "email": "sindresorhus@gmail.com",
10 + "url": "sindresorhus.com"
11 + },
12 + "engines": {
13 + "node": ">=4"
14 + },
15 + "scripts": {
16 + "test": "xo && ava"
17 + },
18 + "files": [
19 + "index.js"
20 + ],
21 + "keywords": [
22 + "has",
23 + "check",
24 + "detect",
25 + "contains",
26 + "find",
27 + "flag",
28 + "cli",
29 + "command-line",
30 + "argv",
31 + "process",
32 + "arg",
33 + "args",
34 + "argument",
35 + "arguments",
36 + "getopt",
37 + "minimist",
38 + "optimist"
39 + ],
40 + "devDependencies": {
41 + "ava": "*",
42 + "xo": "*"
43 + }
44 +}
1 +# has-flag [![Build Status](https://travis-ci.org/sindresorhus/has-flag.svg?branch=master)](https://travis-ci.org/sindresorhus/has-flag)
2 +
3 +> Check if [`argv`](https://nodejs.org/docs/latest/api/process.html#process_process_argv) has a specific flag
4 +
5 +Correctly stops looking after an `--` argument terminator.
6 +
7 +
8 +## Install
9 +
10 +```
11 +$ npm install has-flag
12 +```
13 +
14 +
15 +## Usage
16 +
17 +```js
18 +// foo.js
19 +const hasFlag = require('has-flag');
20 +
21 +hasFlag('unicorn');
22 +//=> true
23 +
24 +hasFlag('--unicorn');
25 +//=> true
26 +
27 +hasFlag('f');
28 +//=> true
29 +
30 +hasFlag('-f');
31 +//=> true
32 +
33 +hasFlag('foo=bar');
34 +//=> true
35 +
36 +hasFlag('foo');
37 +//=> false
38 +
39 +hasFlag('rainbow');
40 +//=> false
41 +```
42 +
43 +```
44 +$ node foo.js -f --unicorn --foo=bar -- --rainbow
45 +```
46 +
47 +
48 +## API
49 +
50 +### hasFlag(flag, [argv])
51 +
52 +Returns a boolean for whether the flag exists.
53 +
54 +#### flag
55 +
56 +Type: `string`
57 +
58 +CLI flag to look for. The `--` prefix is optional.
59 +
60 +#### argv
61 +
62 +Type: `string[]`<br>
63 +Default: `process.argv`
64 +
65 +CLI arguments.
66 +
67 +
68 +## License
69 +
70 +MIT © [Sindre Sorhus](https://sindresorhus.com)
1 +#
2 +# Jake JavaScript build tool
3 +# Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 +#
5 +# Licensed under the Apache License, Version 2.0 (the "License");
6 +# you may not use this file except in compliance with the License.
7 +# You may obtain a copy of the License at
8 +#
9 +# http://www.apache.org/licenses/LICENSE-2.0
10 +#
11 +# Unless required by applicable law or agreed to in writing, software
12 +# distributed under the License is distributed on an "AS IS" BASIS,
13 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 +# See the License for the specific language governing permissions and
15 +# limitations under the License.
16 +#
17 +
18 +.PHONY: all build install clean uninstall
19 +
20 +PREFIX=/usr/local
21 +DESTDIR=
22 +
23 +all: build
24 +
25 +build:
26 + @echo 'Jake built.'
27 +
28 +install:
29 + @mkdir -p $(DESTDIR)$(PREFIX)/bin && \
30 + mkdir -p $(DESTDIR)$(PREFIX)/lib/node_modules/jake && \
31 + mkdir -p ./node_modules && \
32 + npm install utilities minimatch && \
33 + cp -R ./* $(DESTDIR)$(PREFIX)/lib/node_modules/jake/ && \
34 + ln -snf ../lib/node_modules/jake/bin/cli.js $(DESTDIR)$(PREFIX)/bin/jake && \
35 + chmod 755 $(DESTDIR)$(PREFIX)/lib/node_modules/jake/bin/cli.js && \
36 + echo 'Jake installed.'
37 +
38 +clean:
39 + @true
40 +
41 +uninstall:
42 + @rm -f $(DESTDIR)$(PREFIX)/bin/jake && \
43 + rm -fr $(DESTDIR)$(PREFIX)/lib/node_modules/jake/ && \
44 + echo 'Jake uninstalled.'
1 +### Jake -- the JavaScript build tool for Node.js
2 +
3 +[![Build Status](https://travis-ci.org/jakejs/jake.svg?branch=master)](https://travis-ci.org/jakejs/jake)
4 +
5 +Documentation site at [http://jakejs.com](http://jakejs.com/)
6 +
7 +### Contributing
8 +1. [Install node](http://nodejs.org/#download).
9 +2. Clone this repository `$ git clone git@github.com:jakejs/jake.git`.
10 +3. Install dependencies `$ npm install`.
11 +4. Run tests with `$ npm test`.
12 +5. Start Hacking!
13 +
14 +### License
15 +
16 +Licensed under the Apache License, Version 2.0
17 +(<http://www.apache.org/licenses/LICENSE-2.0>)
1 +#!/bin/bash
2 +
3 +# http://stackoverflow.com/a/246128
4 +SOURCE="${BASH_SOURCE[0]}"
5 +while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
6 + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
7 + SOURCE="$(readlink "$SOURCE")"
8 + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
9 +done
10 +JAKE_BIN_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
11 +
12 +# http://stackoverflow.com/a/12495480
13 +# http://stackoverflow.com/a/28647824
14 +_auto_jake()
15 +{
16 + local cur
17 + local -a COMPGEN=()
18 + _get_comp_words_by_ref -n : -c cur
19 +
20 + # run auto-completions in jake via our auto_complete.js wrapper
21 + local -a auto_complete_info=( $(export COMP_LINE="${COMP_LINE}" && ${JAKE_BIN_DIR}/auto_complete.js "$cur" "${3}") )
22 + # check reply flag
23 + local reply_flag="${auto_complete_info[0]}"
24 + if [[ "${reply_flag}" == "no-complete" ]]; then
25 + return 1
26 + fi
27 + local auto_completions=("${auto_complete_info[@]:1}")
28 + COMPGEN=( $(compgen -W "${auto_completions[*]}" -- "$cur") )
29 + COMPREPLY=( "${COMPGEN[@]}" )
30 +
31 + __ltrim_colon_completions "$cur"
32 +
33 + # do we need another space??
34 + if [[ "${reply_flag}" == "yes-space" ]]; then
35 + COMPREPLY=( "${COMPGEN[@]}" " " )
36 + fi
37 +
38 + return 0
39 +}
40 +
41 +complete -o default -F _auto_jake jake
1 +#!/usr/bin/env node
2 +/*
3 + * Jake JavaScript build tool
4 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
5 + *
6 + * Licensed under the Apache License, Version 2.0 (the "License");
7 + * you may not use this file except in compliance with the License.
8 + * You may obtain a copy of the License at
9 + *
10 + * http://www.apache.org/licenses/LICENSE-2.0
11 + *
12 + * Unless required by applicable law or agreed to in writing, software
13 + * distributed under the License is distributed on an "AS IS" BASIS,
14 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 + * See the License for the specific language governing permissions and
16 + * limitations under the License.
17 + *
18 +*/
19 +
20 +// Try to load a local jake
21 +try {
22 + require(`${ process.cwd() }/node_modules/jake`);
23 +}
24 +// If that fails, likely running globally
25 +catch(e) {
26 + require('../lib/jake');
27 +}
28 +
29 +var args = process.argv.slice(2);
30 +
31 +jake.run.apply(jake, args);
1 +let fs = require('fs')
2 +let path = require('path');
3 +let proc = require('child_process');
4 +
5 +const PROJECT_DIR = process.cwd();
6 +process.env.PROJECT_DIR = PROJECT_DIR;
7 +
8 +namespace('doc', function () {
9 + task('generate', ['doc:clobber'], function () {
10 + var cmd = '../node-jsdoc-toolkit/app/run.js -n -r=100 ' +
11 + '-t=../node-jsdoc-toolkit/templates/codeview -d=./doc/ ./lib';
12 + jake.logger.log('Generating docs ...');
13 + jake.exec([cmd], function () {
14 + jake.logger.log('Done.');
15 + complete();
16 + });
17 + }, {async: true});
18 +
19 + task('clobber', function () {
20 + var cmd = 'rm -fr ./doc/*';
21 + jake.exec([cmd], function () {
22 + jake.logger.log('Clobbered old docs.');
23 + complete();
24 + });
25 + }, {async: true});
26 +
27 +});
28 +
29 +desc('Generate docs for Jake');
30 +task('doc', ['doc:generate']);
31 +
32 +npmPublishTask('jake', function () {
33 + this.packageFiles.include([
34 + 'Makefile',
35 + 'jakefile.js',
36 + 'README.md',
37 + 'package.json',
38 + 'usage.txt',
39 + 'lib/**',
40 + 'bin/**',
41 + 'test/**'
42 + ]);
43 + this.packageFiles.exclude([
44 + 'test/tmp'
45 + ]);
46 +});
47 +
48 +jake.Task['publish:package'].directory = PROJECT_DIR;
49 +
50 +namespace('test', function () {
51 +
52 + let integrationTest = task('integration', ['publish:package'], async function () {
53 + let pkg = JSON.parse(fs.readFileSync(`${PROJECT_DIR}/package.json`).toString());
54 + let version = pkg.version;
55 +
56 + proc.execSync('rm -rf ./node_modules');
57 + // Install from the actual package, run tests from the packaged binary
58 + proc.execSync(`mkdir -p node_modules/.bin && mv ${PROJECT_DIR}/pkg/jake-v` +
59 + `${version} node_modules/jake && ln -s ${process.cwd()}` +
60 + '/node_modules/jake/bin/cli.js ./node_modules/.bin/jake');
61 +
62 + let testArgs = [];
63 + if (process.env.filter) {
64 + testArgs.push(process.env.filter);
65 + }
66 + else {
67 + testArgs.push('*.js');
68 + }
69 + let spawned = proc.spawn(`${PROJECT_DIR}/node_modules/.bin/mocha`, testArgs, {
70 + stdio: 'inherit'
71 + });
72 + return new Promise((resolve, reject) => {
73 + spawned.on('exit', () => {
74 + if (!(process.env.noclobber || process.env.noClobber)) {
75 + proc.execSync('rm -rf tmp_publish && rm -rf package.json' +
76 + ' && rm -rf package-lock.json && rm -rf node_modules');
77 + // Rather than invoking 'clobber' task
78 + jake.rmRf(`${PROJECT_DIR}/pkg`);
79 + }
80 + resolve();
81 + });
82 + });
83 +
84 + });
85 +
86 + integrationTest.directory = `${PROJECT_DIR}/test/integration`;
87 +
88 + let unitTest = task('unit', async function () {
89 + let testArgs = [];
90 + if (process.env.filter) {
91 + testArgs.push(process.env.filter);
92 + }
93 + else {
94 + testArgs.push('*.js');
95 + }
96 + let spawned = proc.spawn(`${PROJECT_DIR}/node_modules/.bin/mocha`, testArgs, {
97 + stdio: 'inherit'
98 + });
99 + });
100 +
101 + unitTest.directory = `${PROJECT_DIR}/test/unit`;
102 +});
103 +
104 +desc('Runs all tests');
105 +task('test', ['test:unit', 'test:integration']);
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +let { uuid } = require('./utils');
19 +
20 +let api = new (function () {
21 + /**
22 + @name task
23 + @static
24 + @function
25 + @description Creates a Jake Task
26 + `
27 + @param {String} name The name of the Task
28 + @param {Array} [prereqs] Prerequisites to be run before this task
29 + @param {Function} [action] The action to perform for this task
30 + @param {Object} [opts]
31 + @param {Boolean} [opts.asyc=false] Perform this task asynchronously.
32 + If you flag a task with this option, you must call the global
33 + `complete` method inside the task's action, for execution to proceed
34 + to the next task.
35 +
36 + @example
37 + desc('This is the default task.');
38 + task('default', function (params) {
39 + console.log('This is the default task.');
40 + });
41 +
42 + desc('This task has prerequisites.');
43 + task('hasPrereqs', ['foo', 'bar', 'baz'], function (params) {
44 + console.log('Ran some prereqs first.');
45 + });
46 +
47 + desc('This is an asynchronous task.');
48 + task('asyncTask', function () {
49 + setTimeout(complete, 1000);
50 + }, {async: true});
51 + */
52 + this.task = function (name, prereqs, action, opts) {
53 + let args = Array.prototype.slice.call(arguments);
54 + let createdTask;
55 + args.unshift('task');
56 + createdTask = jake.createTask.apply(global, args);
57 + jake.currentTaskDescription = null;
58 + return createdTask;
59 + };
60 +
61 + /**
62 + @name rule
63 + @static
64 + @function
65 + @description Creates a Jake Suffix Rule
66 + `
67 + @param {String} pattern The suffix name of the objective
68 + @param {String} source The suffix name of the objective
69 + @param {Array} [prereqs] Prerequisites to be run before this task
70 + @param {Function} [action] The action to perform for this task
71 + @param {Object} [opts]
72 + @param {Boolean} [opts.asyc=false] Perform this task asynchronously.
73 + If you flag a task with this option, you must call the global
74 + `complete` method inside the task's action, for execution to proceed
75 + to the next task.
76 + @example
77 + desc('This is a rule, which does not support namespace or pattern.');
78 + rule('.o', '.c', {async: true}, function () {
79 + let cmd = util.format('gcc -o %s %s', this.name, this.source);
80 + jake.exec([cmd], function () {
81 + complete();
82 + }, {printStdout: true});
83 + });
84 +
85 + desc('This rule has prerequisites.');
86 + rule('.o', '.c', ['util.h'], {async: true}, function () {
87 + let cmd = util.format('gcc -o %s %s', this.name, this.source);
88 + jake.exec([cmd], function () {
89 + complete();
90 + }, {printStdout: true});
91 + });
92 +
93 + desc('This is a rule with patterns.');
94 + rule('%.o', '%.c', {async: true}, function () {
95 + let cmd = util.format('gcc -o %s %s', this.name, this.source);
96 + jake.exec([cmd], function () {
97 + complete();
98 + }, {printStdout: true});
99 + });
100 +
101 + desc('This is another rule with patterns.');
102 + rule('obj/%.o', 'src/%.c', {async: true}, function () {
103 + let cmd = util.format('gcc -o %s %s', this.name, this.source);
104 + jake.exec([cmd], function () {
105 + complete();
106 + }, {printStdout: true});
107 + });
108 +
109 + desc('This is an example with chain rules.');
110 + rule('%.pdf', '%.dvi', {async: true}, function () {
111 + let cmd = util.format('dvipdfm %s',this.source);
112 + jake.exec([cmd], function () {
113 + complete();
114 + }, {printStdout: true});
115 + });
116 +
117 + rule('%.dvi', '%.tex', {async: true}, function () {
118 + let cmd = util.format('latex %s',this.source);
119 + jake.exec([cmd], function () {
120 + complete();
121 + }, {printStdout: true});
122 + });
123 +
124 + desc('This rule has a namespace.');
125 + task('default', ['debug:obj/main.o]);
126 +
127 + namespace('debug', {async: true}, function() {
128 + rule('obj/%.o', 'src/%.c', function () {
129 + // ...
130 + });
131 + }
132 + */
133 + this.rule = function () {
134 + let args = Array.prototype.slice.call(arguments);
135 + let arg;
136 + let pattern = args.shift();
137 + let source = args.shift();
138 + let prereqs = [];
139 + let action = function () {};
140 + let opts = {};
141 + let key = pattern.toString(); // May be a RegExp
142 +
143 + while ((arg = args.shift())) {
144 + if (typeof arg == 'function') {
145 + action = arg;
146 + }
147 + else if (Array.isArray(arg)) {
148 + prereqs = arg;
149 + }
150 + else {
151 + opts = arg;
152 + }
153 + }
154 +
155 + jake.currentNamespace.rules[key] = new jake.Rule({
156 + pattern: pattern,
157 + source: source,
158 + prereqs: prereqs,
159 + action: action,
160 + opts: opts,
161 + desc: jake.currentTaskDescription,
162 + ns: jake.currentNamespace
163 + });
164 + jake.currentTaskDescription = null;
165 + };
166 +
167 + /**
168 + @name directory
169 + @static
170 + @function
171 + @description Creates a Jake DirectoryTask. Can be used as a prerequisite
172 + for FileTasks, or for simply ensuring a directory exists for use with a
173 + Task's action.
174 + `
175 + @param {String} name The name of the DiretoryTask
176 +
177 + @example
178 +
179 + // Creates the package directory for distribution
180 + directory('pkg');
181 + */
182 + this.directory = function (name) {
183 + let args = Array.prototype.slice.call(arguments);
184 + let createdTask;
185 + args.unshift('directory');
186 + createdTask = jake.createTask.apply(global, args);
187 + jake.currentTaskDescription = null;
188 + return createdTask;
189 + };
190 +
191 + /**
192 + @name file
193 + @static
194 + @function
195 + @description Creates a Jake FileTask.
196 + `
197 + @param {String} name The name of the FileTask
198 + @param {Array} [prereqs] Prerequisites to be run before this task
199 + @param {Function} [action] The action to create this file, if it doesn't
200 + exist already.
201 + @param {Object} [opts]
202 + @param {Array} [opts.asyc=false] Perform this task asynchronously.
203 + If you flag a task with this option, you must call the global
204 + `complete` method inside the task's action, for execution to proceed
205 + to the next task.
206 +
207 + */
208 + this.file = function (name, prereqs, action, opts) {
209 + let args = Array.prototype.slice.call(arguments);
210 + let createdTask;
211 + args.unshift('file');
212 + createdTask = jake.createTask.apply(global, args);
213 + jake.currentTaskDescription = null;
214 + return createdTask;
215 + };
216 +
217 + /**
218 + @name desc
219 + @static
220 + @function
221 + @description Creates a description for a Jake Task (or FileTask,
222 + DirectoryTask). When invoked, the description that iscreated will
223 + be associated with whatever Task is created next.
224 + `
225 + @param {String} description The description for the Task
226 + */
227 + this.desc = function (description) {
228 + jake.currentTaskDescription = description;
229 + };
230 +
231 + /**
232 + @name namespace
233 + @static
234 + @function
235 + @description Creates a namespace which allows logical grouping
236 + of tasks, and prevents name-collisions with task-names. Namespaces
237 + can be nested inside of other namespaces.
238 + `
239 + @param {String} name The name of the namespace
240 + @param {Function} scope The enclosing scope for the namespaced tasks
241 +
242 + @example
243 + namespace('doc', function () {
244 + task('generate', ['doc:clobber'], function () {
245 + // Generate some docs
246 + });
247 +
248 + task('clobber', function () {
249 + // Clobber the doc directory first
250 + });
251 + });
252 + */
253 + this.namespace = function (name, closure) {
254 + let curr = jake.currentNamespace;
255 + let ns = curr.childNamespaces[name] || new jake.Namespace(name, curr);
256 + let fn = closure || function () {};
257 + curr.childNamespaces[name] = ns;
258 + jake.currentNamespace = ns;
259 + fn();
260 + jake.currentNamespace = curr;
261 + jake.currentTaskDescription = null;
262 + return ns;
263 + };
264 +
265 + /**
266 + @name complete
267 + @static
268 + @function
269 + @description Completes an asynchronous task, allowing Jake's
270 + execution to proceed to the next task. Calling complete globally or without
271 + arguments completes the last task on the invocationChain. If you use parallel
272 + execution of prereqs this will probably complete a wrong task. You should call this
273 + function with this task as the first argument, before the optional return value.
274 + Alternatively you can call task.complete()
275 + `
276 + @example
277 + task('generate', ['doc:clobber'], function () {
278 + exec('./generate_docs.sh', function (err, stdout, stderr) {
279 + if (err || stderr) {
280 + fail(err || stderr);
281 + }
282 + else {
283 + console.log(stdout);
284 + complete();
285 + }
286 + });
287 + }, {async: true});
288 + */
289 + this.complete = function (task, val) {
290 + //this should detect if the first arg is a task, but I guess it should be more thorough
291 + if(task && task. _currentPrereqIndex >=0 ) {
292 + task.complete(val);
293 + }
294 + else {
295 + val = task;
296 + if(jake._invocationChain.length > 0) {
297 + jake._invocationChain[jake._invocationChain.length-1].complete(val);
298 + }
299 + }
300 + };
301 +
302 + /**
303 + @name fail
304 + @static
305 + @function
306 + @description Causes Jake execution to abort with an error.
307 + Allows passing an optional error code, which will be used to
308 + set the exit-code of exiting process.
309 + `
310 + @param {Error|String} err The error to thow when aborting execution.
311 + If this argument is an Error object, it will simply be thrown. If
312 + a String, it will be used as the error-message. (If it is a multi-line
313 + String, the first line will be used as the Error message, and the
314 + remaining lines will be used as the error-stack.)
315 +
316 + @example
317 + task('createTests, function () {
318 + if (!fs.existsSync('./tests')) {
319 + fail('Test directory does not exist.');
320 + }
321 + else {
322 + // Do some testing stuff ...
323 + }
324 + });
325 + */
326 + this.fail = function (err, code) {
327 + let msg;
328 + let errObj;
329 + if (code) {
330 + jake.errorCode = code;
331 + }
332 + if (err) {
333 + if (typeof err == 'string') {
334 + // Use the initial or only line of the error as the error-message
335 + // If there was a multi-line error, use the rest as the stack
336 + msg = err.split('\n');
337 + errObj = new Error(msg.shift());
338 + if (msg.length) {
339 + errObj.stack = msg.join('\n');
340 + }
341 + throw errObj;
342 + }
343 + else if (err instanceof Error) {
344 + throw err;
345 + }
346 + else {
347 + throw new Error(err.toString());
348 + }
349 + }
350 + else {
351 + throw new Error();
352 + }
353 + };
354 +
355 + this.packageTask = function (name, version, prereqs, definition) {
356 + return new jake.PackageTask(name, version, prereqs, definition);
357 + };
358 +
359 + this.publishTask = function (name, prereqs, opts, definition) {
360 + return new jake.PublishTask(name, prereqs, opts, definition);
361 + };
362 +
363 + // Backward-compat
364 + this.npmPublishTask = function (name, prereqs, opts, definition) {
365 + return new jake.PublishTask(name, prereqs, opts, definition);
366 + };
367 +
368 + this.testTask = function () {
369 + let ctor = function () {};
370 + let t;
371 + ctor.prototype = jake.TestTask.prototype;
372 + t = new ctor();
373 + jake.TestTask.apply(t, arguments);
374 + return t;
375 + };
376 +
377 + this.setTaskTimeout = function (t) {
378 + this._taskTimeout = t;
379 + };
380 +
381 + this.setSeriesAutoPrefix = function (prefix) {
382 + this._seriesAutoPrefix = prefix;
383 + };
384 +
385 + this.series = function (...args) {
386 + let prereqs = args.map((arg) => {
387 + let name = (this._seriesAutoPrefix || '') + arg.name;
388 + jake.task(name, arg);
389 + return name;
390 + });
391 + let seriesName = uuid();
392 + let seriesTask = jake.task(seriesName, prereqs);
393 + seriesTask._internal = true;
394 + let res = function () {
395 + return new Promise((resolve) => {
396 + seriesTask.invoke();
397 + seriesTask.on('complete', (val) => {
398 + resolve(val);
399 + });
400 + });
401 + };
402 + Object.defineProperty(res, 'name', {value: uuid(),
403 + writable: false});
404 + return res;
405 + };
406 +
407 +})();
408 +
409 +module.exports = api;
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +if (!global.jake) {
20 +
21 + let EventEmitter = require('events').EventEmitter;
22 + // And so it begins
23 + global.jake = new EventEmitter();
24 +
25 + let fs = require('fs');
26 + let chalk = require('chalk');
27 + let taskNs = require('./task');
28 + let Task = taskNs.Task;
29 + let FileTask = taskNs.FileTask;
30 + let DirectoryTask = taskNs.DirectoryTask;
31 + let Rule = require('./rule').Rule;
32 + let Namespace = require('./namespace').Namespace;
33 + let RootNamespace = require('./namespace').RootNamespace;
34 + let api = require('./api');
35 + let utils = require('./utils');
36 + let Program = require('./program').Program;
37 + let loader = require('./loader')();
38 + let pkg = JSON.parse(fs.readFileSync(__dirname + '/../package.json').toString());
39 +
40 + const MAX_RULE_RECURSION_LEVEL = 16;
41 +
42 + // Globalize jake and top-level API methods (e.g., `task`, `desc`)
43 + Object.assign(global, api);
44 +
45 + // Copy utils onto base jake
46 + jake.logger = utils.logger;
47 + jake.exec = utils.exec;
48 +
49 + // File utils should be aliased directly on base jake as well
50 + Object.assign(jake, utils.file);
51 +
52 + // Also add top-level API methods to exported object for those who don't want to
53 + // use the globals (`file` here will overwrite the 'file' utils namespace)
54 + Object.assign(jake, api);
55 +
56 + Object.assign(jake, new (function () {
57 +
58 + this._invocationChain = [];
59 + this._taskTimeout = 30000;
60 +
61 + // Public properties
62 + // =================
63 + this.version = pkg.version;
64 + // Used when Jake exits with a specific error-code
65 + this.errorCode = null;
66 + // Loads Jakefiles/jakelibdirs
67 + this.loader = loader;
68 + // The root of all ... namespaces
69 + this.rootNamespace = new RootNamespace();
70 + // Non-namespaced tasks are placed into the default
71 + this.defaultNamespace = this.rootNamespace;
72 + // Start in the default
73 + this.currentNamespace = this.defaultNamespace;
74 + // Saves the description created by a 'desc' call that prefaces a
75 + // 'task' call that defines a task.
76 + this.currentTaskDescription = null;
77 + this.program = new Program();
78 + this.FileList = require('filelist').FileList;
79 + this.PackageTask = require('./package_task').PackageTask;
80 + this.PublishTask = require('./publish_task').PublishTask;
81 + this.TestTask = require('./test_task').TestTask;
82 + this.Task = Task;
83 + this.FileTask = FileTask;
84 + this.DirectoryTask = DirectoryTask;
85 + this.Namespace = Namespace;
86 + this.Rule = Rule;
87 +
88 + this.parseAllTasks = function () {
89 + let _parseNs = function (ns) {
90 + let nsTasks = ns.tasks;
91 + let nsNamespaces = ns.childNamespaces;
92 + for (let q in nsTasks) {
93 + let nsTask = nsTasks[q];
94 + jake.Task[nsTask.fullName] = nsTask;
95 + }
96 + for (let p in nsNamespaces) {
97 + let nsNamespace = nsNamespaces[p];
98 + _parseNs(nsNamespace);
99 + }
100 + };
101 + _parseNs(jake.defaultNamespace);
102 + };
103 +
104 + /**
105 + * Displays the list of descriptions avaliable for tasks defined in
106 + * a Jakefile
107 + */
108 + this.showAllTaskDescriptions = function (f) {
109 + let p;
110 + let maxTaskNameLength = 0;
111 + let task;
112 + let padding;
113 + let name;
114 + let descr;
115 + let filter = typeof f == 'string' ? f : null;
116 +
117 + for (p in jake.Task) {
118 + if (!Object.prototype.hasOwnProperty.call(jake.Task, p)) {
119 + continue;
120 + }
121 + if (filter && p.indexOf(filter) == -1) {
122 + continue;
123 + }
124 + task = jake.Task[p];
125 + // Record the length of the longest task name -- used for
126 + // pretty alignment of the task descriptions
127 + if (task.description) {
128 + maxTaskNameLength = p.length > maxTaskNameLength ?
129 + p.length : maxTaskNameLength;
130 + }
131 + }
132 + // Print out each entry with descriptions neatly aligned
133 + for (p in jake.Task) {
134 + if (!Object.prototype.hasOwnProperty.call(jake.Task, p)) {
135 + continue;
136 + }
137 + if (filter && p.indexOf(filter) == -1) {
138 + continue;
139 + }
140 + task = jake.Task[p];
141 +
142 + //name = '\033[32m' + p + '\033[39m ';
143 + name = chalk.green(p);
144 +
145 + descr = task.description;
146 + if (descr) {
147 + descr = chalk.gray('# ' + descr);
148 +
149 + // Create padding-string with calculated length
150 + padding = (new Array(maxTaskNameLength - p.length + 2)).join(' ');
151 +
152 + console.log('jake ' + name + padding + descr);
153 + }
154 + }
155 + };
156 +
157 + this.createTask = function () {
158 + let args = Array.prototype.slice.call(arguments);
159 + let arg;
160 + let obj;
161 + let task;
162 + let type;
163 + let name;
164 + let action;
165 + let opts = {};
166 + let prereqs = [];
167 +
168 + type = args.shift();
169 +
170 + // name, [deps], [action]
171 + // Name (string) + deps (array) format
172 + if (typeof args[0] == 'string') {
173 + name = args.shift();
174 + if (Array.isArray(args[0])) {
175 + prereqs = args.shift();
176 + }
177 + }
178 + // name:deps, [action]
179 + // Legacy object-literal syntax, e.g.: {'name': ['depA', 'depB']}
180 + else {
181 + obj = args.shift();
182 + for (let p in obj) {
183 + prereqs = prereqs.concat(obj[p]);
184 + name = p;
185 + }
186 + }
187 +
188 + // Optional opts/callback or callback/opts
189 + while ((arg = args.shift())) {
190 + if (typeof arg == 'function') {
191 + action = arg;
192 + }
193 + else {
194 + opts = Object.assign(Object.create(null), arg);
195 + }
196 + }
197 +
198 + task = jake.currentNamespace.resolveTask(name);
199 + if (task && !action) {
200 + // Task already exists and no action, just update prereqs, and return it.
201 + task.prereqs = task.prereqs.concat(prereqs);
202 + return task;
203 + }
204 +
205 + switch (type) {
206 + case 'directory':
207 + action = function () {
208 + jake.mkdirP(name);
209 + };
210 + task = new DirectoryTask(name, prereqs, action, opts);
211 + break;
212 + case 'file':
213 + task = new FileTask(name, prereqs, action, opts);
214 + break;
215 + default:
216 + task = new Task(name, prereqs, action, opts);
217 + }
218 +
219 + jake.currentNamespace.addTask(task);
220 +
221 + if (jake.currentTaskDescription) {
222 + task.description = jake.currentTaskDescription;
223 + jake.currentTaskDescription = null;
224 + }
225 +
226 + // FIXME: Should only need to add a new entry for the current
227 + // task-definition, not reparse the entire structure
228 + jake.parseAllTasks();
229 +
230 + return task;
231 + };
232 +
233 + this.attemptRule = function (name, ns, level) {
234 + let prereqRule;
235 + let prereq;
236 + if (level > MAX_RULE_RECURSION_LEVEL) {
237 + return null;
238 + }
239 + // Check Rule
240 + prereqRule = ns.matchRule(name);
241 + if (prereqRule) {
242 + prereq = prereqRule.createTask(name, level);
243 + }
244 + return prereq || null;
245 + };
246 +
247 + this.createPlaceholderFileTask = function (name, namespace) {
248 + let parsed = name.split(':');
249 + let filePath = parsed.pop(); // Strip any namespace
250 + let task;
251 +
252 + task = namespace.resolveTask(name);
253 +
254 + // If there's not already an existing dummy FileTask for it,
255 + // create one
256 + if (!task) {
257 + // Create a dummy FileTask only if file actually exists
258 + if (fs.existsSync(filePath)) {
259 + task = new jake.FileTask(filePath);
260 + task.dummy = true;
261 + let ns;
262 + if (parsed.length) {
263 + ns = namespace.resolveNamespace(parsed.join(':'));
264 + }
265 + else {
266 + ns = namespace;
267 + }
268 + if (!namespace) {
269 + throw new Error('Invalid namespace, cannot add FileTask');
270 + }
271 + ns.addTask(task);
272 + // Put this dummy Task in the global Tasks list so
273 + // modTime will be eval'd correctly
274 + jake.Task[`${ns.path}:${filePath}`] = task;
275 + }
276 + }
277 +
278 + return task || null;
279 + };
280 +
281 +
282 + this.run = function () {
283 + let args = Array.prototype.slice.call(arguments);
284 + let program = this.program;
285 + let loader = this.loader;
286 + let preempt;
287 + let opts;
288 +
289 + program.parseArgs(args);
290 + program.init();
291 +
292 + preempt = program.firstPreemptiveOption();
293 + if (preempt) {
294 + preempt();
295 + }
296 + else {
297 + opts = program.opts;
298 + // jakefile flag set but no jakefile yet
299 + if (opts.autocomplete && opts.jakefile === true) {
300 + process.stdout.write('no-complete');
301 + return;
302 + }
303 + // Load Jakefile and jakelibdir files
304 + let jakefileLoaded = loader.loadFile(opts.jakefile);
305 + let jakelibdirLoaded = loader.loadDirectory(opts.jakelibdir);
306 +
307 + if(!jakefileLoaded && !jakelibdirLoaded && !opts.autocomplete) {
308 + fail('No Jakefile. Specify a valid path with -f/--jakefile, ' +
309 + 'or place one in the current directory.');
310 + }
311 +
312 + program.run();
313 + }
314 + };
315 +
316 + })());
317 +}
318 +
319 +module.exports = jake;
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +let path = require('path');
20 +let fs = require('fs');
21 +let existsSync = fs.existsSync;
22 +let utils = require('./utils');
23 +
24 +// Files like jakelib/foobar.jake.js
25 +const JAKELIB_FILE_PAT = /\.jake$|\.js$/;
26 +const SUPPORTED_EXTENSIONS = {
27 + 'js': null,
28 + 'coffee': function () {
29 + try {
30 + let cs = require('coffeescript');
31 + if (typeof cs.register == 'function') {
32 + cs.register();
33 + }
34 + }
35 + catch(e) {
36 + throw new Error('You have a CoffeeScript Jakefile, but have not installed CoffeeScript');
37 + }
38 + },
39 + 'ls': function () {
40 + try {
41 + require('livescript');
42 + }
43 + catch (e) {
44 + throw new Error('You have a LiveScript Jakefile, but have not installed LiveScript');
45 + }
46 + }
47 +};
48 +const IMPLICIT_JAKEFILE_NAMES = [
49 + 'Jakefile',
50 + 'Gulpfile'
51 +];
52 +
53 +let Loader = function () {
54 + // Load a Jakefile, running the code inside -- this may result in
55 + // tasks getting defined using the original Jake API, e.g.,
56 + // `task('foo' ['bar', 'baz']);`, or can also auto-create tasks
57 + // from any functions exported from the file
58 + function loadFile(filePath) {
59 + let exported = require(filePath);
60 + for (let [key, value] of Object.entries(exported)) {
61 + let t;
62 + if (typeof value == 'function') {
63 + t = jake.task(key, value);
64 + t.description = '(Exported function)';
65 + }
66 + }
67 + }
68 +
69 + function fileExists(name) {
70 + let nameWithExt = null;
71 + // Support no file extension as well
72 + let exts = Object.keys(SUPPORTED_EXTENSIONS).concat(['']);
73 + exts.some((ext) => {
74 + let fname = ext ? `${name}.${ext}` : name;
75 + if (existsSync(fname)) {
76 + nameWithExt = fname;
77 + return true;
78 + }
79 + });
80 + return nameWithExt;
81 + }
82 +
83 + // Recursive
84 + function findImplicitJakefile() {
85 + let cwd = process.cwd();
86 + let names = IMPLICIT_JAKEFILE_NAMES;
87 + let found = null;
88 + names.some((name) => {
89 + let n;
90 + // Prefer all-lowercase
91 + n = name.toLowerCase();
92 + if ((found = fileExists(n))) {
93 + return found;
94 + }
95 + // Check mixed-case as well
96 + n = name;
97 + if ((found = fileExists(n))) {
98 + return found;
99 + }
100 + });
101 + if (found) {
102 + return found;
103 + }
104 + else {
105 + process.chdir("..");
106 + // If we've walked all the way up the directory tree,
107 + // bail out with no result
108 + if (cwd === process.cwd()) {
109 + return null;
110 + }
111 + return findImplicitJakefile();
112 + }
113 + }
114 +
115 + this.loadFile = function (fileSpecified) {
116 + let jakefile;
117 + let origCwd = process.cwd();
118 +
119 + if (fileSpecified) {
120 + if (existsSync(fileSpecified)) {
121 + jakefile = fileSpecified;
122 + }
123 + }
124 + else {
125 + jakefile = findImplicitJakefile();
126 + }
127 +
128 + if (jakefile) {
129 + let ext = jakefile.split('.')[1];
130 + let loaderFunc = SUPPORTED_EXTENSIONS[ext];
131 + loaderFunc && loaderFunc();
132 +
133 + loadFile(utils.file.absolutize(jakefile));
134 + return true;
135 + }
136 + else {
137 + if (!fileSpecified) {
138 + // Restore the working directory on failure
139 + process.chdir(origCwd);
140 + }
141 + return false;
142 + }
143 + };
144 +
145 + this.loadDirectory = function (d) {
146 + let dirname = d || 'jakelib';
147 + let dirlist;
148 + dirname = utils.file.absolutize(dirname);
149 + if (existsSync(dirname)) {
150 + dirlist = fs.readdirSync(dirname);
151 + dirlist.forEach(function (filePath) {
152 + if (JAKELIB_FILE_PAT.test(filePath)) {
153 + loadFile(path.join(dirname, filePath));
154 + }
155 + });
156 + return true;
157 + }
158 + return false;
159 + };
160 +
161 +};
162 +
163 +module.exports = function () {
164 + return new Loader();
165 +};
1 +const ROOT_NAMESPACE_NAME = '__rootNamespace__';
2 +
3 +class Namespace {
4 + constructor(name, parentNamespace) {
5 + this.name = name;
6 + this.parentNamespace = parentNamespace;
7 + this.childNamespaces = {};
8 + this.tasks = {};
9 + this.rules = {};
10 + this.path = this.getPath();
11 + }
12 +
13 + get fullName() {
14 + return this._getFullName();
15 + }
16 +
17 + addTask(task) {
18 + this.tasks[task.name] = task;
19 + task.namespace = this;
20 + }
21 +
22 + resolveTask(name) {
23 + if (!name) {
24 + return;
25 + }
26 +
27 + let taskPath = name.split(':');
28 + let taskName = taskPath.pop();
29 + let task;
30 + let ns;
31 +
32 + // Namespaced, return either relative to current, or from root
33 + if (taskPath.length) {
34 + taskPath = taskPath.join(':');
35 + ns = this.resolveNamespace(taskPath) ||
36 + Namespace.ROOT_NAMESPACE.resolveNamespace(taskPath);
37 + task = (ns && ns.resolveTask(taskName));
38 + }
39 + // Bare task, return either local, or top-level
40 + else {
41 + task = this.tasks[name] || Namespace.ROOT_NAMESPACE.tasks[name];
42 + }
43 +
44 + return task || null;
45 + }
46 +
47 +
48 + resolveNamespace(relativeName) {
49 + if (!relativeName) {
50 + return this;
51 + }
52 +
53 + let parts = relativeName.split(':');
54 + let ns = this;
55 +
56 + for (let i = 0, ii = parts.length; (ns && i < ii); i++) {
57 + ns = ns.childNamespaces[parts[i]];
58 + }
59 +
60 + return ns || null;
61 + }
62 +
63 + matchRule(relativeName) {
64 + let parts = relativeName.split(':');
65 + parts.pop();
66 + let ns = this.resolveNamespace(parts.join(':'));
67 + let rules = ns ? ns.rules : [];
68 + let r;
69 + let match;
70 +
71 + for (let p in rules) {
72 + r = rules[p];
73 + if (r.match(relativeName)) {
74 + match = r;
75 + }
76 + }
77 +
78 + return (ns && match) ||
79 + (this.parentNamespace &&
80 + this.parentNamespace.matchRule(relativeName));
81 + }
82 +
83 + getPath() {
84 + let parts = [];
85 + let next = this.parentNamespace;
86 + while (next) {
87 + parts.push(next.name);
88 + next = next.parentNamespace;
89 + }
90 + parts.pop(); // Remove '__rootNamespace__'
91 + return parts.reverse().join(':');
92 + }
93 +
94 + _getFullName() {
95 + let path = this.path;
96 + path = (path && path.split(':')) || [];
97 + path.push(this.name);
98 + return path.join(':');
99 + }
100 +
101 + isRootNamespace() {
102 + return !this.parentNamespace;
103 + }
104 +}
105 +
106 +class RootNamespace extends Namespace {
107 + constructor() {
108 + super(ROOT_NAMESPACE_NAME, null);
109 + Namespace.ROOT_NAMESPACE = this;
110 + }
111 +}
112 +
113 +module.exports.Namespace = Namespace;
114 +module.exports.RootNamespace = RootNamespace;
115 +
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +let path = require('path');
20 +let fs = require('fs');
21 +let exec = require('child_process').exec;
22 +let FileList = require('filelist').FileList;
23 +
24 +/**
25 + @name jake
26 + @namespace jake
27 +*/
28 +/**
29 + @name jake.PackageTask
30 + @constructor
31 + @description Instantiating a PackageTask creates a number of Jake
32 + Tasks that make packaging and distributing your software easy.
33 +
34 + @param {String} name The name of the project
35 + @param {String} version The current project version (will be
36 + appended to the project-name in the package-archive
37 + @param {Function} definition Defines the contents of the package,
38 + and format of the package-archive. Will be executed on the instantiated
39 + PackageTask (i.e., 'this', will be the PackageTask instance),
40 + to set the various instance-propertiess.
41 +
42 + @example
43 + let t = new jake.PackageTask('rous', 'v' + version, function () {
44 + let files = [
45 + 'Capfile'
46 + , 'Jakefile'
47 + , 'README.md'
48 + , 'package.json'
49 + , 'app/*'
50 + , 'bin/*'
51 + , 'config/*'
52 + , 'lib/*'
53 + , 'node_modules/*'
54 + ];
55 + this.packageFiles.include(files);
56 + this.packageFiles.exclude('node_modules/foobar');
57 + this.needTarGz = true;
58 + });
59 +
60 + */
61 +let PackageTask = function () {
62 + let args = Array.prototype.slice.call(arguments);
63 + let name = args.shift();
64 + let version = args.shift();
65 + let definition = args.pop();
66 + let prereqs = args.pop() || []; // Optional
67 +
68 + prereqs = [].concat(prereqs); // Accept string or list
69 +
70 + /**
71 + @name jake.PackageTask#name
72 + @public
73 + @type {String}
74 + @description The name of the project
75 + */
76 + this.name = name;
77 + /**
78 + @name jake.PackageTask#version
79 + @public
80 + @type {String}
81 + @description The project version-string
82 + */
83 + this.version = version;
84 + /**
85 + @name jake.PackageTask#prereqs
86 + @public
87 + @type {Array}
88 + @description Tasks to run before packaging
89 + */
90 + this.prereqs = prereqs;
91 + /**
92 + @name jake.PackageTask#packageDir
93 + @public
94 + @type {String='pkg'}
95 + @description The directory-name to use for packaging the software
96 + */
97 + this.packageDir = 'pkg';
98 + /**
99 + @name jake.PackageTask#packageFiles
100 + @public
101 + @type {jake.FileList}
102 + @description The list of files and directories to include in the
103 + package-archive
104 + */
105 + this.packageFiles = new FileList();
106 + /**
107 + @name jake.PackageTask#needTar
108 + @public
109 + @type {Boolean=false}
110 + @description If set to true, uses the `tar` utility to create
111 + a gzip .tgz archive of the package
112 + */
113 + this.needTar = false;
114 + /**
115 + @name jake.PackageTask#needTarGz
116 + @public
117 + @type {Boolean=false}
118 + @description If set to true, uses the `tar` utility to create
119 + a gzip .tar.gz archive of the package
120 + */
121 + this.needTarGz = false;
122 + /**
123 + @name jake.PackageTask#needTarBz2
124 + @public
125 + @type {Boolean=false}
126 + @description If set to true, uses the `tar` utility to create
127 + a bzip2 .bz2 archive of the package
128 + */
129 + this.needTarBz2 = false;
130 + /**
131 + @name jake.PackageTask#needJar
132 + @public
133 + @type {Boolean=false}
134 + @description If set to true, uses the `jar` utility to create
135 + a .jar archive of the package
136 + */
137 + this.needJar = false;
138 + /**
139 + @name jake.PackageTask#needZip
140 + @public
141 + @type {Boolean=false}
142 + @description If set to true, uses the `zip` utility to create
143 + a .zip archive of the package
144 + */
145 + this.needZip = false;
146 + /**
147 + @name jake.PackageTask#manifestFile
148 + @public
149 + @type {String=null}
150 + @description Can be set to point the `jar` utility at a manifest
151 + file to use in a .jar archive. If unset, one will be automatically
152 + created by the `jar` utility. This path should be relative to the
153 + root of the package directory (this.packageDir above, likely 'pkg')
154 + */
155 + this.manifestFile = null;
156 + /**
157 + @name jake.PackageTask#tarCommand
158 + @public
159 + @type {String='tar'}
160 + @description The shell-command to use for creating tar archives.
161 + */
162 + this.tarCommand = 'tar';
163 + /**
164 + @name jake.PackageTask#jarCommand
165 + @public
166 + @type {String='jar'}
167 + @description The shell-command to use for creating jar archives.
168 + */
169 + this.jarCommand = 'jar';
170 + /**
171 + @name jake.PackageTask#zipCommand
172 + @public
173 + @type {String='zip'}
174 + @description The shell-command to use for creating zip archives.
175 + */
176 + this.zipCommand = 'zip';
177 + /**
178 + @name jake.PackageTask#archiveNoBaseDir
179 + @public
180 + @type {Boolean=false}
181 + @description Simple option for performing the archive on the
182 + contents of the directory instead of the directory itself
183 + */
184 + this.archiveNoBaseDir = false;
185 + /**
186 + @name jake.PackageTask#archiveChangeDir
187 + @public
188 + @type {String=null}
189 + @description Equivalent to the '-C' command for the `tar` and `jar`
190 + commands. ("Change to this directory before adding files.")
191 + */
192 + this.archiveChangeDir = null;
193 + /**
194 + @name jake.PackageTask#archiveContentDir
195 + @public
196 + @type {String=null}
197 + @description Specifies the files and directories to include in the
198 + package-archive. If unset, this will default to the main package
199 + directory -- i.e., name + version.
200 + */
201 + this.archiveContentDir = null;
202 +
203 + if (typeof definition == 'function') {
204 + definition.call(this);
205 + }
206 + this.define();
207 +};
208 +
209 +PackageTask.prototype = new (function () {
210 +
211 + let _compressOpts = {
212 + Tar: {
213 + ext: '.tgz',
214 + flags: 'czf',
215 + cmd: 'tar'
216 + },
217 + TarGz: {
218 + ext: '.tar.gz',
219 + flags: 'czf',
220 + cmd: 'tar'
221 + },
222 + TarBz2: {
223 + ext: '.tar.bz2',
224 + flags: 'cjf',
225 + cmd: 'tar'
226 + },
227 + Jar: {
228 + ext: '.jar',
229 + flags: 'cf',
230 + cmd: 'jar'
231 + },
232 + Zip: {
233 + ext: '.zip',
234 + flags: 'qr',
235 + cmd: 'zip'
236 + }
237 + };
238 +
239 + this.define = function () {
240 + let self = this;
241 + let packageDirPath = this.packageDirPath();
242 + let compressTaskArr = [];
243 +
244 + desc('Build the package for distribution');
245 + task('package', self.prereqs.concat(['clobberPackage', 'buildPackage']));
246 + // Backward-compat alias
247 + task('repackage', ['package']);
248 +
249 + task('clobberPackage', function () {
250 + jake.rmRf(self.packageDir, {silent: true});
251 + });
252 +
253 + desc('Remove the package');
254 + task('clobber', ['clobberPackage']);
255 +
256 + let doCommand = function (p) {
257 + let filename = path.resolve(self.packageDir + '/' + self.packageName() +
258 + _compressOpts[p].ext);
259 + if (process.platform == 'win32') {
260 + // Windows full path may have drive letter, which is going to cause
261 + // namespace problems, so strip it.
262 + if (filename.length > 2 && filename[1] == ':') {
263 + filename = filename.substr(2);
264 + }
265 + }
266 + compressTaskArr.push(filename);
267 +
268 + file(filename, [packageDirPath], function () {
269 + let cmd;
270 + let opts = _compressOpts[p];
271 + // Directory to move to when doing the compression-task
272 + // Changes in the case of zip for emulating -C option
273 + let chdir = self.packageDir;
274 + // Save the current dir so it's possible to pop back up
275 + // after compressing
276 + let currDir = process.cwd();
277 + let archiveChangeDir;
278 + let archiveContentDir;
279 +
280 + if (self.archiveNoBaseDir) {
281 + archiveChangeDir = self.packageName();
282 + archiveContentDir = '.';
283 + }
284 + else {
285 + archiveChangeDir = self.archiveChangeDir;
286 + archiveContentDir = self.archiveContentDir;
287 + }
288 +
289 + cmd = self[opts.cmd + 'Command'];
290 + cmd += ' -' + opts.flags;
291 + if (opts.cmd == 'jar' && self.manifestFile) {
292 + cmd += 'm';
293 + }
294 +
295 + // The name of the archive to create -- use full path
296 + // so compression can be performed from a different dir
297 + // if needed
298 + cmd += ' ' + filename;
299 +
300 + if (opts.cmd == 'jar' && self.manifestFile) {
301 + cmd += ' ' + self.manifestFile;
302 + }
303 +
304 + // Where to perform the compression -- -C option isn't
305 + // supported in zip, so actually do process.chdir for this
306 + if (archiveChangeDir) {
307 + if (opts.cmd == 'zip') {
308 + chdir = path.join(chdir, archiveChangeDir);
309 + }
310 + else {
311 + cmd += ' -C ' + archiveChangeDir;
312 + }
313 + }
314 +
315 + // Where to get the archive content
316 + if (archiveContentDir) {
317 + cmd += ' ' + archiveContentDir;
318 + }
319 + else {
320 + cmd += ' ' + self.packageName();
321 + }
322 +
323 + // Move into the desired dir (usually packageDir) to compress
324 + // Return back up to the current dir after the exec
325 + process.chdir(chdir);
326 +
327 + exec(cmd, function (err, stdout, stderr) {
328 + if (err) { throw err; }
329 +
330 + // Return back up to the starting directory (see above,
331 + // before exec)
332 + process.chdir(currDir);
333 +
334 + complete();
335 + });
336 + }, {async: true});
337 + };
338 +
339 + for (let p in _compressOpts) {
340 + if (this['need' + p]) {
341 + doCommand(p);
342 + }
343 + }
344 +
345 + task('buildPackage', compressTaskArr, function () {});
346 +
347 + directory(this.packageDir);
348 +
349 + file(packageDirPath, this.packageFiles, function () {
350 + jake.mkdirP(packageDirPath);
351 + let fileList = [];
352 + self.packageFiles.forEach(function (name) {
353 + let f = path.join(self.packageDirPath(), name);
354 + let fDir = path.dirname(f);
355 + jake.mkdirP(fDir, {silent: true});
356 +
357 + // Add both files and directories
358 + fileList.push({
359 + from: name,
360 + to: f
361 + });
362 + });
363 + let _copyFile = function () {
364 + let file = fileList.pop();
365 + let stat;
366 + if (file) {
367 + stat = fs.statSync(file.from);
368 + // Target is a directory, just create it
369 + if (stat.isDirectory()) {
370 + jake.mkdirP(file.to, {silent: true});
371 + _copyFile();
372 + }
373 + // Otherwise copy the file
374 + else {
375 + jake.cpR(file.from, file.to, {silent: true});
376 + _copyFile();
377 + }
378 + }
379 + else {
380 + complete();
381 + }
382 + };
383 + _copyFile();
384 + }, {async: true});
385 +
386 +
387 + };
388 +
389 + this.packageName = function () {
390 + if (this.version) {
391 + return this.name + '-' + this.version;
392 + }
393 + else {
394 + return this.name;
395 + }
396 + };
397 +
398 + this.packageDirPath = function () {
399 + return this.packageDir + '/' + this.packageName();
400 + };
401 +
402 +})();
403 +
404 +jake.PackageTask = PackageTask;
405 +exports.PackageTask = PackageTask;
406 +
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +let parseargs = {};
20 +let isOpt = function (arg) { return arg.indexOf('-') === 0 };
21 +let removeOptPrefix = function (opt) { return opt.replace(/^--/, '').replace(/^-/, '') };
22 +
23 +/**
24 + * @constructor
25 + * Parses a list of command-line args into a key/value object of
26 + * options and an array of positional commands.
27 + * @ param {Array} opts A list of options in the following format:
28 + * [{full: 'foo', abbr: 'f'}, {full: 'bar', abbr: 'b'}]]
29 + */
30 +parseargs.Parser = function (opts) {
31 + // A key/value object of matching options parsed out of the args
32 + this.opts = {};
33 + this.taskNames = null;
34 + this.envVars = null;
35 +
36 + // Data structures used for parsing
37 + this.reg = opts;
38 + this.shortOpts = {};
39 + this.longOpts = {};
40 +
41 + let self = this;
42 + [].forEach.call(opts, function (item) {
43 + self.shortOpts[item.abbr] = item;
44 + self.longOpts[item.full] = item;
45 + });
46 +};
47 +
48 +parseargs.Parser.prototype = new function () {
49 +
50 + let _trueOrNextVal = function (argParts, args) {
51 + if (argParts[1]) {
52 + return argParts[1];
53 + }
54 + else {
55 + return (!args[0] || isOpt(args[0])) ?
56 + true : args.shift();
57 + }
58 + };
59 +
60 + /**
61 + * Parses an array of arguments into options and positional commands
62 + * @param {Array} args The command-line args to parse
63 + */
64 + this.parse = function (args) {
65 + let cmds = [];
66 + let cmd;
67 + let envVars = {};
68 + let opts = {};
69 + let arg;
70 + let argItem;
71 + let argParts;
72 + let cmdItems;
73 + let taskNames = [];
74 + let preempt;
75 +
76 + while (args.length) {
77 + arg = args.shift();
78 +
79 + if (isOpt(arg)) {
80 + arg = removeOptPrefix(arg);
81 + argParts = arg.split('=');
82 + argItem = this.longOpts[argParts[0]] || this.shortOpts[argParts[0]];
83 + if (argItem) {
84 + // First-encountered preemptive opt takes precedence -- no further opts
85 + // or possibility of ambiguity, so just look for a value, or set to
86 + // true and then bail
87 + if (argItem.preempts) {
88 + opts[argItem.full] = _trueOrNextVal(argParts, args);
89 + preempt = true;
90 + break;
91 + }
92 + // If the opt requires a value, see if we can get a value from the
93 + // next arg, or infer true from no-arg -- if it's followed by another
94 + // opt, throw an error
95 + if (argItem.expectValue || argItem.allowValue) {
96 + opts[argItem.full] = _trueOrNextVal(argParts, args);
97 + if (argItem.expectValue && !opts[argItem.full]) {
98 + throw new Error(argItem.full + ' option expects a value.');
99 + }
100 + }
101 + else {
102 + opts[argItem.full] = true;
103 + }
104 + }
105 + }
106 + else {
107 + cmds.unshift(arg);
108 + }
109 + }
110 +
111 + if (!preempt) {
112 + // Parse out any env-vars and task-name
113 + while ((cmd = cmds.pop())) {
114 + cmdItems = cmd.split('=');
115 + if (cmdItems.length > 1) {
116 + envVars[cmdItems[0]] = cmdItems[1];
117 + }
118 + else {
119 + taskNames.push(cmd);
120 + }
121 + }
122 +
123 + }
124 +
125 + return {
126 + opts: opts,
127 + envVars: envVars,
128 + taskNames: taskNames
129 + };
130 + };
131 +
132 +};
133 +
134 +module.exports = parseargs;
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +let fs = require('fs');
20 +let parseargs = require('./parseargs');
21 +let utils = require('./utils');
22 +let Program;
23 +let usage = require('fs').readFileSync(`${__dirname}/../usage.txt`).toString();
24 +let { Task } = require('./task/task');
25 +
26 +function die(msg) {
27 + console.log(msg);
28 + process.stdout.write('', function () {
29 + process.stderr.write('', function () {
30 + process.exit();
31 + });
32 + });
33 +}
34 +
35 +let preempts = {
36 + version: function () {
37 + die(jake.version);
38 + },
39 + help: function () {
40 + die(usage);
41 + }
42 +};
43 +
44 +let AVAILABLE_OPTS = [
45 + { full: 'jakefile',
46 + abbr: 'f',
47 + expectValue: true
48 + },
49 + { full: 'quiet',
50 + abbr: 'q',
51 + expectValue: false
52 + },
53 + { full: 'directory',
54 + abbr: 'C',
55 + expectValue: true
56 + },
57 + { full: 'always-make',
58 + abbr: 'B',
59 + expectValue: false
60 + },
61 + { full: 'tasks',
62 + abbr: 'T',
63 + expectValue: false,
64 + allowValue: true
65 + },
66 + // Alias t
67 + { full: 'tasks',
68 + abbr: 't',
69 + expectValue: false,
70 + allowValue: true
71 + },
72 + // Alias ls
73 + { full: 'tasks',
74 + abbr: 'ls',
75 + expectValue: false,
76 + allowValue: true
77 + },
78 + { full: 'help',
79 + abbr: 'h',
80 + },
81 + { full: 'version',
82 + abbr: 'V',
83 + },
84 + // Alias lowercase v
85 + { full: 'version',
86 + abbr: 'v',
87 + },
88 + { full: 'jakelibdir',
89 + abbr: 'J',
90 + expectValue: true
91 + },
92 + { full: 'allow-rejection',
93 + abbr: 'ar',
94 + expectValue: false
95 + }
96 +];
97 +
98 +Program = function () {
99 + this.availableOpts = AVAILABLE_OPTS;
100 + this.opts = {};
101 + this.taskNames = null;
102 + this.taskArgs = null;
103 + this.envVars = null;
104 + this.die = die;
105 +};
106 +
107 +Program.prototype = new (function () {
108 +
109 + this.handleErr = function (err) {
110 + if (jake.listeners('error').length !== 0) {
111 + jake.emit('error', err);
112 + return;
113 + }
114 +
115 + if (jake.listeners('error').length) {
116 + jake.emit('error', err);
117 + return;
118 + }
119 +
120 + utils.logger.error('jake aborted.');
121 + if (err.stack) {
122 + utils.logger.error(err.stack);
123 + }
124 + else {
125 + utils.logger.error(err.message);
126 + }
127 +
128 + process.stdout.write('', function () {
129 + process.stderr.write('', function () {
130 + jake.errorCode = jake.errorCode || 1;
131 + process.exit(jake.errorCode);
132 + });
133 + });
134 + };
135 +
136 + this.parseArgs = function (args) {
137 + let result = (new parseargs.Parser(this.availableOpts)).parse(args);
138 + this.setOpts(result.opts);
139 + this.setTaskNames(result.taskNames);
140 + this.setEnvVars(result.envVars);
141 + };
142 +
143 + this.setOpts = function (options) {
144 + let opts = options || {};
145 + Object.assign(this.opts, opts);
146 + };
147 +
148 + this.internalOpts = function (options) {
149 + this.availableOpts = this.availableOpts.concat(options);
150 + };
151 +
152 + this.autocompletions = function (cur) {
153 + let p; let i; let task;
154 + let commonPrefix = '';
155 + let matches = [];
156 +
157 + for (p in jake.Task) {
158 + task = jake.Task[p];
159 + if (
160 + 'fullName' in task
161 + && (
162 + // if empty string, program converts to true
163 + cur === true ||
164 + task.fullName.indexOf(cur) === 0
165 + )
166 + ) {
167 + if (matches.length === 0) {
168 + commonPrefix = task.fullName;
169 + }
170 + else {
171 + for (i = commonPrefix.length; i > -1; --i) {
172 + commonPrefix = commonPrefix.substr(0, i);
173 + if (task.fullName.indexOf(commonPrefix) === 0) {
174 + break;
175 + }
176 + }
177 + }
178 + matches.push(task.fullName);
179 + }
180 + }
181 +
182 + if (matches.length > 1 && commonPrefix === cur) {
183 + matches.unshift('yes-space');
184 + }
185 + else {
186 + matches.unshift('no-space');
187 + }
188 +
189 + process.stdout.write(matches.join(' '));
190 + };
191 +
192 + this.setTaskNames = function (names) {
193 + if (names && !Array.isArray(names)) {
194 + throw new Error('Task names must be an array');
195 + }
196 + this.taskNames = (names && names.length) ? names : ['default'];
197 + };
198 +
199 + this.setEnvVars = function (vars) {
200 + this.envVars = vars || null;
201 + };
202 +
203 + this.firstPreemptiveOption = function () {
204 + let opts = this.opts;
205 + for (let p in opts) {
206 + if (preempts[p]) {
207 + return preempts[p];
208 + }
209 + }
210 + return false;
211 + };
212 +
213 + this.init = function (configuration) {
214 + let self = this;
215 + let config = configuration || {};
216 + if (config.options) {
217 + this.setOpts(config.options);
218 + }
219 + if (config.taskNames) {
220 + this.setTaskNames(config.taskNames);
221 + }
222 + if (config.envVars) {
223 + this.setEnvVars(config.envVars);
224 + }
225 + process.addListener('uncaughtException', function (err) {
226 + self.handleErr(err);
227 + });
228 + if (!this.opts['allow-rejection']) {
229 + process.addListener('unhandledRejection', (reason, promise) => {
230 + utils.logger.error('Unhandled rejection at:', promise, 'reason:', reason);
231 + self.handleErr(reason);
232 + });
233 + }
234 + if (this.envVars) {
235 + Object.assign(process.env, this.envVars);
236 + }
237 + };
238 +
239 + this.run = function () {
240 + let rootTask;
241 + let taskNames;
242 + let dirname;
243 + let opts = this.opts;
244 +
245 + if (opts.autocomplete) {
246 + return this.autocompletions(opts['autocomplete-cur'], opts['autocomplete-prev']);
247 + }
248 + // Run with `jake -T`, just show descriptions
249 + if (opts.tasks) {
250 + return jake.showAllTaskDescriptions(opts.tasks);
251 + }
252 +
253 + taskNames = this.taskNames;
254 + if (!(Array.isArray(taskNames) && taskNames.length)) {
255 + throw new Error('Please pass jake.runTasks an array of task-names');
256 + }
257 +
258 + // Set working dir
259 + dirname = opts.directory;
260 + if (dirname) {
261 + if (fs.existsSync(dirname) &&
262 + fs.statSync(dirname).isDirectory()) {
263 + process.chdir(dirname);
264 + }
265 + else {
266 + throw new Error(dirname + ' is not a valid directory path');
267 + }
268 + }
269 +
270 + rootTask = task(Task.ROOT_TASK_NAME, taskNames, function () {});
271 + rootTask._internal = true;
272 +
273 + rootTask.once('complete', function () {
274 + jake.emit('complete');
275 + });
276 + jake.emit('start');
277 + rootTask.invoke();
278 + };
279 +
280 +})();
281 +
282 +module.exports.Program = Program;
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +let fs = require('fs');
20 +let path = require('path');
21 +let exec = require('child_process').execSync;
22 +let FileList = require('filelist').FileList;
23 +
24 +let PublishTask = function () {
25 + let args = Array.prototype.slice.call(arguments).filter(function (item) {
26 + return typeof item != 'undefined';
27 + });
28 + let arg;
29 + let opts = {};
30 + let definition;
31 + let prereqs = [];
32 + let createDef = function (arg) {
33 + return function () {
34 + this.packageFiles.include(arg);
35 + };
36 + };
37 +
38 + this.name = args.shift();
39 +
40 + // Old API, just name + list of files
41 + if (args.length == 1 && (Array.isArray(args[0]) || typeof args[0] == 'string')) {
42 + definition = createDef(args.pop());
43 + }
44 + // Current API, name + [prereqs] + [opts] + definition
45 + else {
46 + while ((arg = args.pop())) {
47 + // Definition func
48 + if (typeof arg == 'function') {
49 + definition = arg;
50 + }
51 + // Prereqs
52 + else if (Array.isArray(arg) || typeof arg == 'string') {
53 + prereqs = arg;
54 + }
55 + // Opts
56 + else {
57 + opts = arg;
58 + }
59 + }
60 + }
61 +
62 + this.prereqs = prereqs;
63 + this.packageFiles = new FileList();
64 + this.publishCmd = opts.publishCmd || 'npm publish %filename';
65 + this.publishMessage = opts.publishMessage || 'BOOM! Published.';
66 + this.gitCmd = opts.gitCmd || 'git';
67 + this.versionFiles = opts.versionFiles || ['package.json'];
68 + this.scheduleDelay = 5000;
69 +
70 + // Override utility funcs for testing
71 + this._ensureRepoClean = function (stdout) {
72 + if (stdout.length) {
73 + fail(new Error('Git repository is not clean.'));
74 + }
75 + };
76 + this._getCurrentBranch = function (stdout) {
77 + return String(stdout).trim();
78 + };
79 +
80 + if (typeof definition == 'function') {
81 + definition.call(this);
82 + }
83 + this.define();
84 +};
85 +
86 +
87 +PublishTask.prototype = new (function () {
88 +
89 + let _currentBranch = null;
90 +
91 + let getPackage = function () {
92 + let pkg = JSON.parse(fs.readFileSync(path.join(process.cwd(),
93 + '/package.json')).toString());
94 + return pkg;
95 + };
96 + let getPackageVersionNumber = function () {
97 + return getPackage().version;
98 + };
99 +
100 + this.define = function () {
101 + let self = this;
102 +
103 + namespace('publish', function () {
104 + task('fetchTags', function () {
105 + // Make sure local tags are up to date
106 + exec(self.gitCmd + ' fetch --tags');
107 + console.log('Fetched remote tags.');
108 + });
109 +
110 + task('getCurrentBranch', function () {
111 + // Figure out what branch to push to
112 + let stdout = exec(self.gitCmd + ' symbolic-ref --short HEAD').toString();
113 + if (!stdout) {
114 + throw new Error('No current Git branch found');
115 + }
116 + _currentBranch = self._getCurrentBranch(stdout);
117 + console.log('On branch ' + _currentBranch);
118 + });
119 +
120 + task('ensureClean', function () {
121 + // Only bump, push, and tag if the Git repo is clean
122 + let stdout = exec(self.gitCmd + ' status --porcelain --untracked-files=no').toString();
123 + // Throw if there's output
124 + self._ensureRepoClean(stdout);
125 + });
126 +
127 + task('updateVersionFiles', function () {
128 + let pkg;
129 + let version;
130 + let arr;
131 + let patch;
132 +
133 + // Grab the current version-string
134 + pkg = getPackage();
135 + version = pkg.version;
136 + // Increment the patch-number for the version
137 + arr = version.split('.');
138 + patch = parseInt(arr.pop(), 10) + 1;
139 + arr.push(patch);
140 + version = arr.join('.');
141 +
142 + // Update package.json or other files with the new version-info
143 + self.versionFiles.forEach(function (file) {
144 + let p = path.join(process.cwd(), file);
145 + let data = JSON.parse(fs.readFileSync(p).toString());
146 + data.version = version;
147 + fs.writeFileSync(p, JSON.stringify(data, true, 2) + '\n');
148 + });
149 + // Return the version string so that listeners for the 'complete' event
150 + // for this task can use it (e.g., to update other files before pushing
151 + // to Git)
152 + return version;
153 + });
154 +
155 + task('pushVersion', ['ensureClean', 'updateVersionFiles'], function () {
156 + let version = getPackageVersionNumber();
157 + let message = 'Version ' + version;
158 + let cmds = [
159 + self.gitCmd + ' commit -a -m "' + message + '"',
160 + self.gitCmd + ' push origin ' + _currentBranch,
161 + self.gitCmd + ' tag -a v' + version + ' -m "' + message + '"',
162 + self.gitCmd + ' push --tags'
163 + ];
164 + cmds.forEach((cmd) => {
165 + exec(cmd);
166 + });
167 + version = getPackageVersionNumber();
168 + console.log('Bumped version number to v' + version + '.');
169 + });
170 +
171 + let defineTask = task('definePackage', function () {
172 + let version = getPackageVersionNumber();
173 + new jake.PackageTask(self.name, 'v' + version, self.prereqs, function () {
174 + // Replace the PackageTask's FileList with the PublishTask's FileList
175 + this.packageFiles = self.packageFiles;
176 + this.needTarGz = true; // Default to tar.gz
177 + // If any of the need<CompressionFormat> or archive opts are set
178 + // proxy them to the PackageTask
179 + for (let p in this) {
180 + if (p.indexOf('need') === 0 || p.indexOf('archive') === 0) {
181 + if (typeof self[p] != 'undefined') {
182 + this[p] = self[p];
183 + }
184 + }
185 + }
186 + });
187 + });
188 + defineTask._internal = true;
189 +
190 + task('package', function () {
191 + let definePack = jake.Task['publish:definePackage'];
192 + let pack = jake.Task['package'];
193 + let version = getPackageVersionNumber();
194 +
195 + // May have already been run
196 + if (definePack.taskStatus == jake.Task.runStatuses.DONE) {
197 + definePack.reenable(true);
198 + }
199 + definePack.invoke();
200 + // Set manually, completion happens in next tick, creating deadlock
201 + definePack.taskStatus = jake.Task.runStatuses.DONE;
202 + pack.invoke();
203 + console.log('Created package for ' + self.name + ' v' + version);
204 + });
205 +
206 + task('publish', function () {
207 + return new Promise((resolve) => {
208 + let version = getPackageVersionNumber();
209 + let filename;
210 + let cmd;
211 +
212 + console.log('Publishing ' + self.name + ' v' + version);
213 +
214 + if (typeof self.createPublishCommand == 'function') {
215 + cmd = self.createPublishCommand(version);
216 + }
217 + else {
218 + filename = './pkg/' + self.name + '-v' + version + '.tar.gz';
219 + cmd = self.publishCmd.replace(/%filename/gi, filename);
220 + }
221 +
222 + if (typeof cmd == 'function') {
223 + cmd(function (err) {
224 + if (err) {
225 + throw err;
226 + }
227 + console.log(self.publishMessage);
228 + resolve();
229 + });
230 + }
231 + else {
232 + // Hackity hack -- NPM publish sometimes returns errror like:
233 + // Error sending version data\nnpm ERR!
234 + // Error: forbidden 0.2.4 is modified, should match modified time
235 + setTimeout(function () {
236 + let stdout = exec(cmd).toString() || '';
237 + stdout = stdout.trim();
238 + if (stdout) {
239 + console.log(stdout);
240 + }
241 + console.log(self.publishMessage);
242 + resolve();
243 + }, self.scheduleDelay);
244 + }
245 + });
246 + });
247 +
248 + task('cleanup', function () {
249 + return new Promise((resolve) => {
250 + let clobber = jake.Task.clobber;
251 + clobber.reenable(true);
252 + clobber.on('complete', function () {
253 + console.log('Cleaned up package');
254 + resolve();
255 + });
256 + clobber.invoke();
257 + });
258 + });
259 +
260 + });
261 +
262 + let prefixNs = function (item) {
263 + return 'publish:' + item;
264 + };
265 +
266 + // Create aliases in the default namespace
267 + desc('Create a new version and release.');
268 + task('publish', self.prereqs.concat(['version', 'release']
269 + .map(prefixNs)));
270 +
271 + desc('Release the existing version.');
272 + task('publishExisting', self.prereqs.concat(['release']
273 + .map(prefixNs)));
274 +
275 + task('version', ['fetchTags', 'getCurrentBranch', 'pushVersion']
276 + .map(prefixNs));
277 +
278 + task('release', ['package', 'publish', 'cleanup']
279 + .map(prefixNs));
280 +
281 + // Invoke proactively so there will be a callable 'package' task
282 + // which can be used apart from 'publish'
283 + jake.Task['publish:definePackage'].invoke();
284 + };
285 +
286 +})();
287 +
288 +jake.PublishTask = PublishTask;
289 +exports.PublishTask = PublishTask;
290 +
1 +let path = require('path');
2 +let fs = require('fs');
3 +let Task = require('./task/task').Task;
4 +
5 +// Split a task to two parts, name space and task name.
6 +// For example, given 'foo:bin/a%.c', return an object with
7 +// - 'ns' : foo
8 +// - 'name' : bin/a%.c
9 +function splitNs(task) {
10 + let parts = task.split(':');
11 + let name = parts.pop();
12 + let ns = resolveNs(parts);
13 + return {
14 + 'name' : name,
15 + 'ns' : ns
16 + };
17 +}
18 +
19 +// Return the namespace based on an array of names.
20 +// For example, given ['foo', 'baz' ], return the namespace
21 +//
22 +// default -> foo -> baz
23 +//
24 +// where default is the global root namespace
25 +// and -> means child namespace.
26 +function resolveNs(parts) {
27 + let ns = jake.defaultNamespace;
28 + for(let i = 0, l = parts.length; ns && i < l; i++) {
29 + ns = ns.childNamespaces[parts[i]];
30 + }
31 + return ns;
32 +}
33 +
34 +// Given a pattern p, say 'foo:bin/a%.c'
35 +// Return an object with
36 +// - 'ns' : foo
37 +// - 'dir' : bin
38 +// - 'prefix' : a
39 +// - 'suffix' : .c
40 +function resolve(p) {
41 + let task = splitNs(p);
42 + let name = task.name;
43 + let ns = task.ns;
44 + let split = path.basename(name).split('%');
45 + return {
46 + ns: ns,
47 + dir: path.dirname(name),
48 + prefix: split[0],
49 + suffix: split[1]
50 + };
51 +}
52 +
53 +// Test whether string a is a suffix of string b
54 +function stringEndWith(a, b) {
55 + let l;
56 + return (l = b.lastIndexOf(a)) == -1 ? false : l + a.length == b.length;
57 +}
58 +
59 +// Replace the suffix a of the string s with b.
60 +// Note that, it is assumed a is a suffix of s.
61 +function stringReplaceSuffix(s, a, b) {
62 + return s.slice(0, s.lastIndexOf(a)) + b;
63 +}
64 +
65 +class Rule {
66 + constructor(opts) {
67 + this.pattern = opts.pattern;
68 + this.source = opts.source;
69 + this.prereqs = opts.prereqs;
70 + this.action = opts.action;
71 + this.opts = opts.opts;
72 + this.desc = opts.desc;
73 + this.ns = opts.ns;
74 + }
75 +
76 + // Create a file task based on this rule for the specified
77 + // task-name
78 + // ======
79 + // FIXME: Right now this just throws away any passed-in args
80 + // for the synthsized task (taskArgs param)
81 + // ======
82 + createTask(fullName, level) {
83 + let self = this;
84 + let pattern;
85 + let source;
86 + let action;
87 + let opts;
88 + let prereqs;
89 + let valid;
90 + let src;
91 + let tNs;
92 + let createdTask;
93 + let name = Task.getBaseTaskName(fullName);
94 + let nsPath = Task.getBaseNamespacePath(fullName);
95 + let ns = this.ns.resolveNamespace(nsPath);
96 +
97 + pattern = this.pattern;
98 + source = this.source;
99 +
100 + if (typeof source == 'string') {
101 + src = Rule.getSource(name, pattern, source);
102 + }
103 + else {
104 + src = source(name);
105 + }
106 +
107 + // TODO: Write a utility function that appends a
108 + // taskname to a namespace path
109 + src = nsPath.split(':').filter(function (item) {
110 + return !!item;
111 + }).concat(src).join(':');
112 +
113 + // Generate the prerequisite for the matching task.
114 + // It is the original prerequisites plus the prerequisite
115 + // representing source file, i.e.,
116 + //
117 + // rule( '%.o', '%.c', ['some.h'] ...
118 + //
119 + // If the objective is main.o, then new task should be
120 + //
121 + // file( 'main.o', ['main.c', 'some.h' ] ...
122 + prereqs = this.prereqs.slice(); // Get a copy to work with
123 + prereqs.unshift(src);
124 +
125 + // Prereq should be:
126 + // 1. an existing task
127 + // 2. an existing file on disk
128 + // 3. a valid rule (i.e., not at too deep a level)
129 + valid = prereqs.some(function (p) {
130 + let ns = self.ns;
131 + return ns.resolveTask(p) ||
132 + fs.existsSync(Task.getBaseTaskName(p)) ||
133 + jake.attemptRule(p, ns, level + 1);
134 + });
135 +
136 + // If any of the prereqs aren't valid, the rule isn't valid
137 + if (!valid) {
138 + return null;
139 + }
140 + // Otherwise, hunky-dory, finish creating the task for the rule
141 + else {
142 + // Create the action for the task
143 + action = function () {
144 + let task = this;
145 + self.action.apply(task);
146 + };
147 +
148 + opts = this.opts;
149 +
150 + // Insert the file task into Jake
151 + //
152 + // Since createTask function stores the task as a child task
153 + // of currentNamespace. Here we temporariliy switch the namespace.
154 + // FIXME: Should allow optional ns passed in instead of this hack
155 + tNs = jake.currentNamespace;
156 + jake.currentNamespace = ns;
157 + createdTask = jake.createTask('file', name, prereqs, action, opts);
158 + createdTask.source = src.split(':').pop();
159 + jake.currentNamespace = tNs;
160 +
161 + return createdTask;
162 + }
163 + }
164 +
165 + match(name) {
166 + return Rule.match(this.pattern, name);
167 + }
168 +
169 + // Test wether the a prerequisite matchs the pattern.
170 + // The arg 'pattern' does not have namespace as prefix.
171 + // For example, the following tests are true
172 + //
173 + // pattern | name
174 + // bin/%.o | bin/main.o
175 + // bin/%.o | foo:bin/main.o
176 + //
177 + // The following tests are false (trivally)
178 + //
179 + // pattern | name
180 + // bin/%.o | foobin/main.o
181 + // bin/%.o | bin/main.oo
182 + static match(pattern, name) {
183 + let p;
184 + let task;
185 + let obj;
186 + let filename;
187 +
188 + if (pattern instanceof RegExp) {
189 + return pattern.test(name);
190 + }
191 + else if (pattern.indexOf('%') == -1) {
192 + // No Pattern. No Folder. No Namespace.
193 + // A Simple Suffix Rule. Just test suffix
194 + return stringEndWith(pattern, name);
195 + }
196 + else {
197 + // Resolve the dir, prefix and suffix of pattern
198 + p = resolve(pattern);
199 +
200 + // Resolve the namespace and task-name
201 + task = splitNs(name);
202 + name = task.name;
203 +
204 + // Set the objective as the task-name
205 + obj = name;
206 +
207 + // Namespace is already matched.
208 +
209 + // Check dir
210 + if (path.dirname(obj) != p.dir) {
211 + return false;
212 + }
213 +
214 + filename = path.basename(obj);
215 +
216 + // Check file name length
217 + if ((p.prefix.length + p.suffix.length + 1) > filename.length) {
218 + // Length does not match.
219 + return false;
220 + }
221 +
222 + // Check prefix
223 + if (filename.indexOf(p.prefix) !== 0) {
224 + return false;
225 + }
226 +
227 + // Check suffix
228 + if (!stringEndWith(p.suffix, filename)) {
229 + return false;
230 + }
231 +
232 + // OK. Find a match.
233 + return true;
234 + }
235 + }
236 +
237 + // Generate the source based on
238 + // - name name for the synthesized task
239 + // - pattern pattern for the objective
240 + // - source pattern for the source
241 + //
242 + // Return the source with properties
243 + // - dep the prerequisite of source
244 + // (with the namespace)
245 + //
246 + // - file the file name of source
247 + // (without the namespace)
248 + //
249 + // For example, given
250 + //
251 + // - name foo:bin/main.o
252 + // - pattern bin/%.o
253 + // - source src/%.c
254 + //
255 + // return 'foo:src/main.c',
256 + //
257 + static getSource(name, pattern, source) {
258 + let dep;
259 + let pat;
260 + let match;
261 + let file;
262 + let src;
263 +
264 + // Regex pattern -- use to look up the extension
265 + if (pattern instanceof RegExp) {
266 + match = pattern.exec(name);
267 + if (match) {
268 + if (typeof source == 'function') {
269 + src = source(name);
270 + }
271 + else {
272 + src = stringReplaceSuffix(name, match[0], source);
273 + }
274 + }
275 + }
276 + // Assume string
277 + else {
278 + // Simple string suffix replacement
279 + if (pattern.indexOf('%') == -1) {
280 + if (typeof source == 'function') {
281 + src = source(name);
282 + }
283 + else {
284 + src = stringReplaceSuffix(name, pattern, source);
285 + }
286 + }
287 + // Percent-based substitution
288 + else {
289 + pat = pattern.replace('%', '(.*?)');
290 + pat = new RegExp(pat);
291 + match = pat.exec(name);
292 + if (match) {
293 + if (typeof source == 'function') {
294 + src = source(name);
295 + }
296 + else {
297 + file = match[1];
298 + file = source.replace('%', file);
299 + dep = match[0];
300 + src = name.replace(dep, file);
301 + }
302 + }
303 + }
304 + }
305 +
306 + return src;
307 + }
308 +}
309 +
310 +
311 +exports.Rule = Rule;
1 +let fs = require('fs');
2 +let FileTask = require('./file_task').FileTask;
3 +
4 +/**
5 + @name jake
6 + @namespace jake
7 +*/
8 +/**
9 + @name jake.DirectoryTask
10 + @constructor
11 + @augments EventEmitter
12 + @augments jake.Task
13 + @augments jake.FileTask
14 + @description A Jake DirectoryTask
15 +
16 + @param {String} name The name of the directory to create.
17 + */
18 +class DirectoryTask extends FileTask {
19 + constructor(...args) {
20 + super(...args);
21 + if (fs.existsSync(this.name)) {
22 + this.updateModTime();
23 + }
24 + else {
25 + this.modTime = null;
26 + }
27 + }
28 +}
29 +
30 +exports.DirectoryTask = DirectoryTask;
1 +let fs = require('fs');
2 +let Task = require('./task').Task;
3 +
4 +function isFileOrDirectory(t) {
5 + return (t instanceof FileTask ||
6 + t instanceof DirectoryTask);
7 +}
8 +
9 +function isFile(t) {
10 + return (t instanceof FileTask && !(t instanceof DirectoryTask));
11 +}
12 +
13 +/**
14 + @name jake
15 + @namespace jake
16 +*/
17 +/**
18 + @name jake.FileTask
19 + @class`
20 + @extentds Task
21 + @description A Jake FileTask
22 +
23 + @param {String} name The name of the Task
24 + @param {Array} [prereqs] Prerequisites to be run before this task
25 + @param {Function} [action] The action to perform to create this file
26 + @param {Object} [opts]
27 + @param {Array} [opts.asyc=false] Perform this task asynchronously.
28 + If you flag a task with this option, you must call the global
29 + `complete` method inside the task's action, for execution to proceed
30 + to the next task.
31 + */
32 +class FileTask extends Task {
33 + constructor(...args) {
34 + super(...args);
35 + this.dummy = false;
36 + if (fs.existsSync(this.name)) {
37 + this.updateModTime();
38 + }
39 + else {
40 + this.modTime = null;
41 + }
42 + }
43 +
44 + isNeeded() {
45 + let prereqs = this.prereqs;
46 + let prereqName;
47 + let prereqTask;
48 +
49 + // No repeatsies
50 + if (this.taskStatus == Task.runStatuses.DONE) {
51 + return false;
52 + }
53 + // The always-make override
54 + else if (jake.program.opts['always-make']) {
55 + return true;
56 + }
57 + // Default case
58 + else {
59 +
60 + // We need either an existing file, or an action to create one.
61 + // First try grabbing the actual mod-time of the file
62 + try {
63 + this.updateModTime();
64 + }
65 + // Then fall back to looking for an action
66 + catch(e) {
67 + if (typeof this.action == 'function') {
68 + return true;
69 + }
70 + else {
71 + throw new Error('File-task ' + this.fullName + ' has no ' +
72 + 'existing file, and no action to create one.');
73 + }
74 + }
75 +
76 + // Compare mod-time of all the prereqs with its mod-time
77 + // If any prereqs are newer, need to run the action to update
78 + if (prereqs && prereqs.length) {
79 + for (let i = 0, ii = prereqs.length; i < ii; i++) {
80 + prereqName = prereqs[i];
81 + prereqTask = this.namespace.resolveTask(prereqName) ||
82 + jake.createPlaceholderFileTask(prereqName, this.namespace);
83 + // Run the action if:
84 + // 1. The prereq is a normal task (not file/dir)
85 + // 2. The prereq is a file-task with a mod-date more recent than
86 + // the one for this file/dir
87 + if (prereqTask) {
88 + if (!isFileOrDirectory(prereqTask) ||
89 + (isFile(prereqTask) && prereqTask.modTime > this.modTime)) {
90 + return true;
91 + }
92 + }
93 + }
94 + }
95 + // File/dir has no prereqs, and exists -- no need to run
96 + else {
97 + // Effectively done
98 + this.taskStatus = Task.runStatuses.DONE;
99 + return false;
100 + }
101 + }
102 + }
103 +
104 + updateModTime() {
105 + let stats = fs.statSync(this.name);
106 + this.modTime = stats.mtime;
107 + }
108 +
109 + complete() {
110 + if (!this.dummy) {
111 + this.updateModTime();
112 + }
113 + // Hackity hack
114 + Task.prototype.complete.apply(this, arguments);
115 + }
116 +
117 +}
118 +
119 +exports.FileTask = FileTask;
120 +
121 +// DirectoryTask is a subclass of FileTask, depends on it
122 +// being defined
123 +let DirectoryTask = require('./directory_task').DirectoryTask;
124 +
1 +
2 +let Task = require('./task').Task;
3 +let FileTask = require('./file_task').FileTask;
4 +let DirectoryTask = require('./directory_task').DirectoryTask;
5 +
6 +exports.Task = Task;
7 +exports.FileTask = FileTask;
8 +exports.DirectoryTask = DirectoryTask;
9 +
1 +let EventEmitter = require('events').EventEmitter;
2 +let async = require('async');
3 +let chalk = require('chalk');
4 +// 'rule' module is required at the bottom because circular deps
5 +
6 +// Used for task value, so better not to use
7 +// null, since value should be unset/uninitialized
8 +let UNDEFINED_VALUE;
9 +
10 +const ROOT_TASK_NAME = '__rootTask__';
11 +const POLLING_INTERVAL = 100;
12 +
13 +// Parse any positional args attached to the task-name
14 +function parsePrereqName(name) {
15 + let taskArr = name.split('[');
16 + let taskName = taskArr[0];
17 + let taskArgs = [];
18 + if (taskArr[1]) {
19 + taskArgs = taskArr[1].replace(/\]$/, '');
20 + taskArgs = taskArgs.split(',');
21 + }
22 + return {
23 + name: taskName,
24 + args: taskArgs
25 + };
26 +}
27 +
28 +/**
29 + @name jake.Task
30 + @class
31 + @extends EventEmitter
32 + @description A Jake Task
33 +
34 + @param {String} name The name of the Task
35 + @param {Array} [prereqs] Prerequisites to be run before this task
36 + @param {Function} [action] The action to perform for this task
37 + @param {Object} [opts]
38 + @param {Array} [opts.asyc=false] Perform this task asynchronously.
39 + If you flag a task with this option, you must call the global
40 + `complete` method inside the task's action, for execution to proceed
41 + to the next task.
42 + */
43 +class Task extends EventEmitter {
44 +
45 + constructor(name, prereqs, action, options) {
46 + // EventEmitter ctor takes no args
47 + super();
48 +
49 + if (name.indexOf(':') > -1) {
50 + throw new Error('Task name cannot include a colon. It is used internally as namespace delimiter.');
51 + }
52 + let opts = options || {};
53 +
54 + this._currentPrereqIndex = 0;
55 + this._internal = false;
56 + this._skipped = false;
57 +
58 + this.name = name;
59 + this.prereqs = prereqs;
60 + this.action = action;
61 + this.async = false;
62 + this.taskStatus = Task.runStatuses.UNSTARTED;
63 + this.description = null;
64 + this.args = [];
65 + this.value = UNDEFINED_VALUE;
66 + this.concurrency = 1;
67 + this.startTime = null;
68 + this.endTime = null;
69 + this.directory = null;
70 + this.namespace = null;
71 +
72 + // Support legacy async-flag -- if not explicitly passed or falsy, will
73 + // be set to empty-object
74 + if (typeof opts == 'boolean' && opts === true) {
75 + this.async = true;
76 + }
77 + else {
78 + if (opts.async) {
79 + this.async = true;
80 + }
81 + if (opts.concurrency) {
82 + this.concurrency = opts.concurrency;
83 + }
84 + }
85 +
86 + //Do a test on self dependencies for this task
87 + if(Array.isArray(this.prereqs) && this.prereqs.indexOf(this.name) !== -1) {
88 + throw new Error("Cannot use prereq " + this.name + " as a dependency of itself");
89 + }
90 + }
91 +
92 + get fullName() {
93 + return this._getFullName();
94 + }
95 +
96 + _initInvocationChain() {
97 + // Legacy global invocation chain
98 + jake._invocationChain.push(this);
99 +
100 + // New root chain
101 + if (!this._invocationChain) {
102 + this._invocationChainRoot = true;
103 + this._invocationChain = [];
104 + if (jake.currentRunningTask) {
105 + jake.currentRunningTask._waitForChains = jake.currentRunningTask._waitForChains || [];
106 + jake.currentRunningTask._waitForChains.push(this._invocationChain);
107 + }
108 + }
109 + }
110 +
111 + /**
112 + @name jake.Task#invoke
113 + @function
114 + @description Runs prerequisites, then this task. If the task has already
115 + been run, will not run the task again.
116 + */
117 + invoke() {
118 + this._initInvocationChain();
119 +
120 + this.args = Array.prototype.slice.call(arguments);
121 + this.reenabled = false
122 + this.runPrereqs();
123 + }
124 +
125 + /**
126 + @name jake.Task#execute
127 + @function
128 + @description Run only this task, without prereqs. If the task has already
129 + been run, *will* run the task again.
130 + */
131 + execute() {
132 + this._initInvocationChain();
133 +
134 + this.args = Array.prototype.slice.call(arguments);
135 + this.reenable();
136 + this.reenabled = true
137 + this.run();
138 + }
139 +
140 + runPrereqs() {
141 + if (this.prereqs && this.prereqs.length) {
142 +
143 + if (this.concurrency > 1) {
144 + async.eachLimit(this.prereqs, this.concurrency,
145 +
146 + (name, cb) => {
147 + let parsed = parsePrereqName(name);
148 +
149 + let prereq = this.namespace.resolveTask(parsed.name) ||
150 + jake.attemptRule(name, this.namespace, 0) ||
151 + jake.createPlaceholderFileTask(name, this.namespace);
152 +
153 + if (!prereq) {
154 + throw new Error('Unknown task "' + name + '"');
155 + }
156 +
157 + //Test for circular invocation
158 + if(prereq === this) {
159 + setImmediate(function () {
160 + cb(new Error("Cannot use prereq " + prereq.name + " as a dependency of itself"));
161 + });
162 + }
163 +
164 + if (prereq.taskStatus == Task.runStatuses.DONE) {
165 + //prereq already done, return
166 + setImmediate(cb);
167 + }
168 + else {
169 + //wait for complete before calling cb
170 + prereq.once('_done', () => {
171 + prereq.removeAllListeners('_done');
172 + setImmediate(cb);
173 + });
174 + // Start the prereq if we are the first to encounter it
175 + if (prereq.taskStatus === Task.runStatuses.UNSTARTED) {
176 + prereq.taskStatus = Task.runStatuses.STARTED;
177 + prereq.invoke.apply(prereq, parsed.args);
178 + }
179 + }
180 + },
181 +
182 + (err) => {
183 + //async callback is called after all prereqs have run.
184 + if (err) {
185 + throw err;
186 + }
187 + else {
188 + setImmediate(this.run.bind(this));
189 + }
190 + }
191 + );
192 + }
193 + else {
194 + setImmediate(this.nextPrereq.bind(this));
195 + }
196 + }
197 + else {
198 + setImmediate(this.run.bind(this));
199 + }
200 + }
201 +
202 + nextPrereq() {
203 + let self = this;
204 + let index = this._currentPrereqIndex;
205 + let name = this.prereqs[index];
206 + let prereq;
207 + let parsed;
208 +
209 + if (name) {
210 +
211 + parsed = parsePrereqName(name);
212 +
213 + prereq = this.namespace.resolveTask(parsed.name) ||
214 + jake.attemptRule(name, this.namespace, 0) ||
215 + jake.createPlaceholderFileTask(name, this.namespace);
216 +
217 + if (!prereq) {
218 + throw new Error('Unknown task "' + name + '"');
219 + }
220 +
221 + // Do when done
222 + if (prereq.taskStatus == Task.runStatuses.DONE) {
223 + self.handlePrereqDone(prereq);
224 + }
225 + else {
226 + prereq.once('_done', () => {
227 + this.handlePrereqDone(prereq);
228 + prereq.removeAllListeners('_done');
229 + });
230 + if (prereq.taskStatus == Task.runStatuses.UNSTARTED) {
231 + prereq.taskStatus = Task.runStatuses.STARTED;
232 + prereq._invocationChain = this._invocationChain;
233 + prereq.invoke.apply(prereq, parsed.args);
234 + }
235 + }
236 + }
237 + }
238 +
239 + /**
240 + @name jake.Task#reenable
241 + @function
242 + @description Reenables a task so that it can be run again.
243 + */
244 + reenable(deep) {
245 + let prereqs;
246 + let prereq;
247 + this._skipped = false;
248 + this.taskStatus = Task.runStatuses.UNSTARTED;
249 + this.value = UNDEFINED_VALUE;
250 + if (deep && this.prereqs) {
251 + prereqs = this.prereqs;
252 + for (let i = 0, ii = prereqs.length; i < ii; i++) {
253 + prereq = jake.Task[prereqs[i]];
254 + if (prereq) {
255 + prereq.reenable(deep);
256 + }
257 + }
258 + }
259 + }
260 +
261 + handlePrereqDone(prereq) {
262 + this._currentPrereqIndex++;
263 + if (this._currentPrereqIndex < this.prereqs.length) {
264 + setImmediate(this.nextPrereq.bind(this));
265 + }
266 + else {
267 + setImmediate(this.run.bind(this));
268 + }
269 + }
270 +
271 + isNeeded() {
272 + let needed = true;
273 + if (this.taskStatus == Task.runStatuses.DONE) {
274 + needed = false;
275 + }
276 + return needed;
277 + }
278 +
279 + run() {
280 + let val, previous;
281 + let hasAction = typeof this.action == 'function';
282 +
283 + if (!this.isNeeded()) {
284 + this.emit('skip');
285 + this.emit('_done');
286 + }
287 + else {
288 + if (this._invocationChain.length) {
289 + previous = this._invocationChain[this._invocationChain.length - 1];
290 + // If this task is repeating and its previous is equal to this, don't check its status because it was set to UNSTARTED by the reenable() method
291 + if (!(this.reenabled && previous == this)) {
292 + if (previous.taskStatus != Task.runStatuses.DONE) {
293 + let now = (new Date()).getTime();
294 + if (now - this.startTime > jake._taskTimeout) {
295 + return jake.fail(`Timed out waiting for task: ${previous.name} with status of ${previous.taskStatus}`);
296 + }
297 + setTimeout(this.run.bind(this), POLLING_INTERVAL);
298 + return;
299 + }
300 + }
301 + }
302 + if (!(this.reenabled && previous == this)) {
303 + this._invocationChain.push(this);
304 + }
305 +
306 + if (!(this._internal || jake.program.opts.quiet)) {
307 + console.log("Starting '" + chalk.green(this.fullName) + "'...");
308 + }
309 +
310 + this.startTime = (new Date()).getTime();
311 + this.emit('start');
312 +
313 + jake.currentRunningTask = this;
314 +
315 + if (hasAction) {
316 + try {
317 + if (this.directory) {
318 + process.chdir(this.directory);
319 + }
320 +
321 + val = this.action.apply(this, this.args);
322 +
323 + if (typeof val == 'object' && typeof val.then == 'function') {
324 + this.async = true;
325 +
326 + val.then(
327 + (result) => {
328 + setImmediate(() => {
329 + this.complete(result);
330 + });
331 + },
332 + (err) => {
333 + setImmediate(() => {
334 + this.errorOut(err);
335 + });
336 + });
337 + }
338 + }
339 + catch (err) {
340 + this.errorOut(err);
341 + return; // Bail out, not complete
342 + }
343 + }
344 +
345 + if (!(hasAction && this.async)) {
346 + setImmediate(() => {
347 + this.complete(val);
348 + });
349 + }
350 + }
351 + }
352 +
353 + errorOut(err) {
354 + this.taskStatus = Task.runStatuses.ERROR;
355 + this._invocationChain.chainStatus = Task.runStatuses.ERROR;
356 + this.emit('error', err);
357 + }
358 +
359 + complete(val) {
360 +
361 + if (Array.isArray(this._waitForChains)) {
362 + let stillWaiting = this._waitForChains.some((chain) => {
363 + return !(chain.chainStatus == Task.runStatuses.DONE ||
364 + chain.chainStatus == Task.runStatuses.ERROR);
365 + });
366 + if (stillWaiting) {
367 + let now = (new Date()).getTime();
368 + let elapsed = now - this.startTime;
369 + if (elapsed > jake._taskTimeout) {
370 + return jake.fail(`Timed out waiting for task: ${this.name} with status of ${this.taskStatus}. Elapsed: ${elapsed}`);
371 + }
372 + setTimeout(() => {
373 + this.complete(val);
374 + }, POLLING_INTERVAL);
375 + return;
376 + }
377 + }
378 +
379 + jake._invocationChain.splice(jake._invocationChain.indexOf(this), 1);
380 +
381 + if (this._invocationChainRoot) {
382 + this._invocationChain.chainStatus = Task.runStatuses.DONE;
383 + }
384 +
385 + this._currentPrereqIndex = 0;
386 +
387 + // If 'complete' getting called because task has been
388 + // run already, value will not be passed -- leave in place
389 + if (!this._skipped) {
390 + this.taskStatus = Task.runStatuses.DONE;
391 + this.value = val;
392 +
393 + this.emit('complete', this.value);
394 + this.emit('_done');
395 +
396 + this.endTime = (new Date()).getTime();
397 + let taskTime = this.endTime - this.startTime;
398 +
399 + if (!(this._internal || jake.program.opts.quiet)) {
400 + console.log("Finished '" + chalk.green(this.fullName) + "' after " + chalk.magenta(taskTime + ' ms'));
401 + }
402 +
403 + }
404 + }
405 +
406 + _getFullName() {
407 + let ns = this.namespace;
408 + let path = (ns && ns.path) || '';
409 + path = (path && path.split(':')) || [];
410 + if (this.namespace !== jake.defaultNamespace) {
411 + path.push(this.namespace.name);
412 + }
413 + path.push(this.name);
414 + return path.join(':');
415 + }
416 +
417 + static getBaseNamespacePath(fullName) {
418 + return fullName.split(':').slice(0, -1).join(':');
419 + }
420 +
421 + static getBaseTaskName(fullName) {
422 + return fullName.split(':').pop();
423 + }
424 +}
425 +
426 +Task.runStatuses = {
427 + UNSTARTED: 'unstarted',
428 + DONE: 'done',
429 + STARTED: 'started',
430 + ERROR: 'error'
431 +};
432 +
433 +Task.ROOT_TASK_NAME = ROOT_TASK_NAME;
434 +
435 +exports.Task = Task;
436 +
437 +// Required here because circular deps
438 +require('../rule');
439 +
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +let path = require('path');
20 +let currDir = process.cwd();
21 +
22 +/**
23 + @name jake
24 + @namespace jake
25 +*/
26 +/**
27 + @name jake.TestTask
28 + @constructor
29 + @description Instantiating a TestTask creates a number of Jake
30 + Tasks that make running tests for your software easy.
31 +
32 + @param {String} name The name of the project
33 + @param {Function} definition Defines the list of files containing the tests,
34 + and the name of the namespace/task for running them. Will be executed on the
35 + instantiated TestTask (i.e., 'this', will be the TestTask instance), to set
36 + the various instance-propertiess.
37 +
38 + @example
39 + let t = new jake.TestTask('bij-js', function () {
40 + this.testName = 'testSpecial';
41 + this.testFiles.include('test/**');
42 + });
43 +
44 + */
45 +let TestTask = function () {
46 + let self = this;
47 + let args = Array.prototype.slice.call(arguments);
48 + let name = args.shift();
49 + let definition = args.pop();
50 + let prereqs = args.pop() || [];
51 +
52 + /**
53 + @name jake.TestTask#testNam
54 + @public
55 + @type {String}
56 + @description The name of the namespace to place the tests in, and
57 + the top-level task for running tests. Defaults to "test"
58 + */
59 + this.testName = 'test';
60 +
61 + /**
62 + @name jake.TestTask#testFiles
63 + @public
64 + @type {jake.FileList}
65 + @description The list of files containing tests to load
66 + */
67 + this.testFiles = new jake.FileList();
68 +
69 + /**
70 + @name jake.TestTask#showDescription
71 + @public
72 + @type {Boolean}
73 + @description Show the created task when doing Jake -T
74 + */
75 + this.showDescription = true;
76 +
77 + /*
78 + @name jake.TestTask#totalTests
79 + @public
80 + @type {Number}
81 + @description The total number of tests to run
82 + */
83 + this.totalTests = 0;
84 +
85 + /*
86 + @name jake.TestTask#executedTests
87 + @public
88 + @type {Number}
89 + @description The number of tests successfully run
90 + */
91 + this.executedTests = 0;
92 +
93 + if (typeof definition == 'function') {
94 + definition.call(this);
95 + }
96 +
97 + if (this.showDescription) {
98 + desc('Run the tests for ' + name);
99 + }
100 +
101 + task(this.testName, prereqs, {async: true}, function () {
102 + let t = jake.Task[this.fullName + ':run'];
103 + t.on('complete', function () {
104 + complete();
105 + });
106 + // Pass args to the namespaced test
107 + t.invoke.apply(t, arguments);
108 + });
109 +
110 + namespace(self.testName, function () {
111 +
112 + let runTask = task('run', {async: true}, function (pat) {
113 + let re;
114 + let testFiles;
115 +
116 + // Don't nest; make a top-level namespace. Don't want
117 + // re-calling from inside to nest infinitely
118 + jake.currentNamespace = jake.defaultNamespace;
119 +
120 + re = new RegExp(pat);
121 + // Get test files that match the passed-in pattern
122 + testFiles = self.testFiles.toArray()
123 + .filter(function (f) {
124 + return (re).test(f);
125 + }) // Don't load the same file multiple times -- should this be in FileList?
126 + .reduce(function (p, c) {
127 + if (p.indexOf(c) < 0) {
128 + p.push(c);
129 + }
130 + return p;
131 + }, []);
132 +
133 + // Create a namespace for all the testing tasks to live in
134 + namespace(self.testName + 'Exec', function () {
135 + // Each test will be a prereq for the dummy top-level task
136 + let prereqs = [];
137 + // Continuation to pass to the async tests, wrapping `continune`
138 + let next = function () {
139 + complete();
140 + };
141 + // Create the task for this test-function
142 + let createTask = function (name, action) {
143 + // If the test-function is defined with a continuation
144 + // param, flag the task as async
145 + let t;
146 + let isAsync = !!action.length;
147 +
148 + // Define the actual namespaced task with the name, the
149 + // wrapped action, and the correc async-flag
150 + t = task(name, createAction(name, action), {
151 + async: isAsync
152 + });
153 + t.once('complete', function () {
154 + self.executedTests++;
155 + });
156 + t._internal = true;
157 + return t;
158 + };
159 + // Used as the action for the defined task for each test.
160 + let createAction = function (n, a) {
161 + // A wrapped function that passes in the `next` function
162 + // for any tasks that run asynchronously
163 + return function () {
164 + let cb;
165 + if (a.length) {
166 + cb = next;
167 + }
168 + if (!(n == 'before' || n == 'after' ||
169 + /_beforeEach$/.test(n) || /_afterEach$/.test(n))) {
170 + jake.logger.log(n);
171 + }
172 + // 'this' will be the task when action is run
173 + return a.call(this, cb);
174 + };
175 + };
176 + // Dummy top-level task for everything to be prereqs for
177 + let topLevel;
178 +
179 + // Pull in each test-file, and iterate over any exported
180 + // test-functions. Register each test-function as a prereq task
181 + testFiles.forEach(function (file) {
182 + let exp = require(path.join(currDir, file));
183 +
184 + // Create a namespace for each filename, so test-name collisions
185 + // won't be a problem
186 + namespace(file, function () {
187 + let testPrefix = self.testName + 'Exec:' + file + ':';
188 + let testName;
189 + // Dummy task for displaying file banner
190 + testName = '*** Running ' + file + ' ***';
191 + prereqs.push(testPrefix + testName);
192 + createTask(testName, function () {});
193 +
194 + // 'before' setup
195 + if (typeof exp.before == 'function') {
196 + prereqs.push(testPrefix + 'before');
197 + // Create the task
198 + createTask('before', exp.before);
199 + }
200 +
201 + // Walk each exported function, and create a task for each
202 + for (let p in exp) {
203 + if (p == 'before' || p == 'after' ||
204 + p == 'beforeEach' || p == 'afterEach') {
205 + continue;
206 + }
207 +
208 + if (typeof exp.beforeEach == 'function') {
209 + prereqs.push(testPrefix + p + '_beforeEach');
210 + // Create the task
211 + createTask(p + '_beforeEach', exp.beforeEach);
212 + }
213 +
214 + // Add the namespace:name of this test to the list of prereqs
215 + // for the dummy top-level task
216 + prereqs.push(testPrefix + p);
217 + // Create the task
218 + createTask(p, exp[p]);
219 +
220 + if (typeof exp.afterEach == 'function') {
221 + prereqs.push(testPrefix + p + '_afterEach');
222 + // Create the task
223 + createTask(p + '_afterEach', exp.afterEach);
224 + }
225 + }
226 +
227 + // 'after' teardown
228 + if (typeof exp.after == 'function') {
229 + prereqs.push(testPrefix + 'after');
230 + // Create the task
231 + let afterTask = createTask('after', exp.after);
232 + afterTask._internal = true;
233 + }
234 +
235 + });
236 + });
237 +
238 + self.totalTests = prereqs.length;
239 + process.on('exit', function () {
240 + // Throw in the case where the process exits without
241 + // finishing tests, but no error was thrown
242 + if (!jake.errorCode && (self.totalTests > self.executedTests)) {
243 + throw new Error('Process exited without all tests completing.');
244 + }
245 + });
246 +
247 + // Create the dummy top-level task. When calling a task internally
248 + // with `invoke` that is async (or has async prereqs), have to listen
249 + // for the 'complete' event to know when it's done
250 + topLevel = task('__top__', prereqs);
251 + topLevel._internal = true;
252 + topLevel.addListener('complete', function () {
253 + jake.logger.log('All tests ran successfully');
254 + complete();
255 + });
256 +
257 + topLevel.invoke(); // Do the thing!
258 + });
259 +
260 + });
261 + runTask._internal = true;
262 +
263 + });
264 +
265 +
266 +};
267 +
268 +jake.TestTask = TestTask;
269 +exports.TestTask = TestTask;
270 +
1 +/*
2 + * Utilities: A classic collection of JavaScript utilities
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +let fs = require('fs');
20 +let path = require('path');
21 +
22 +/**
23 + @name file
24 + @namespace file
25 +*/
26 +
27 +let fileUtils = new (function () {
28 +
29 + // Recursively copy files and directories
30 + let _copyFile = function (fromPath, toPath, opts) {
31 + let from = path.normalize(fromPath)
32 + let to = path.normalize(toPath)
33 + let options = opts || {}
34 + let fromStat;
35 + let toStat;
36 + let destExists;
37 + let destDoesNotExistErr;
38 + let content;
39 + let filename;
40 + let dirContents;
41 + let targetDir;
42 +
43 + fromStat = fs.statSync(from);
44 +
45 + try {
46 + //console.dir(to + ' destExists');
47 + toStat = fs.statSync(to);
48 + destExists = true;
49 + }
50 + catch(e) {
51 + //console.dir(to + ' does not exist');
52 + destDoesNotExistErr = e;
53 + destExists = false;
54 + }
55 + // Destination dir or file exists, copy into (directory)
56 + // or overwrite (file)
57 + if (destExists) {
58 +
59 + // If there's a rename-via-copy file/dir name passed, use it.
60 + // Otherwise use the actual file/dir name
61 + filename = options.rename || path.basename(from);
62 +
63 + // Copying a directory
64 + if (fromStat.isDirectory()) {
65 + dirContents = fs.readdirSync(from);
66 + targetDir = path.join(to, filename);
67 + // We don't care if the target dir already exists
68 + try {
69 + fs.mkdirSync(targetDir, {mode: fromStat.mode & 0o777});
70 + }
71 + catch(e) {
72 + if (e.code !== 'EEXIST') {
73 + throw e;
74 + }
75 + }
76 + for (let i = 0, ii = dirContents.length; i < ii; i++) {
77 + _copyFile(path.join(from, dirContents[i]), targetDir, {preserveMode: options.preserveMode});
78 + }
79 + }
80 + // Copying a file
81 + else {
82 + content = fs.readFileSync(from);
83 + let mode = fromStat.mode & 0o777;
84 + let targetFile = to;
85 +
86 + if (toStat.isDirectory()) {
87 + targetFile = path.join(to, filename);
88 + }
89 +
90 + let fileExists = fs.existsSync(targetFile);
91 + fs.writeFileSync(targetFile, content);
92 +
93 + // If the file didn't already exist, use the original file mode.
94 + // Otherwise, only update the mode if preserverMode is true.
95 + if(!fileExists || options.preserveMode) {
96 + fs.chmodSync(targetFile, mode);
97 + }
98 + }
99 + }
100 + // Dest doesn't exist, can't create it
101 + else {
102 + throw destDoesNotExistErr;
103 + }
104 + };
105 +
106 + // Remove the given directory
107 + let _rmDir = function (dirPath) {
108 + let dir = path.normalize(dirPath);
109 + let paths = [];
110 + paths = fs.readdirSync(dir);
111 + paths.forEach(function (p) {
112 + let curr = path.join(dir, p);
113 + let stat = fs.lstatSync(curr);
114 + if (stat.isDirectory()) {
115 + _rmDir(curr);
116 + }
117 + else {
118 + try {
119 + fs.unlinkSync(curr);
120 + } catch(e) {
121 + if (e.code === 'EPERM') {
122 + fs.chmodSync(curr, parseInt(666, 8));
123 + fs.unlinkSync(curr);
124 + } else {
125 + throw e;
126 + }
127 + }
128 + }
129 + });
130 + fs.rmdirSync(dir);
131 + };
132 +
133 + /**
134 + @name file#cpR
135 + @public
136 + @function
137 + @description Copies a directory/file to a destination
138 + @param {String} fromPath The source path to copy from
139 + @param {String} toPath The destination path to copy to
140 + @param {Object} opts Options to use
141 + @param {Boolean} [opts.preserveMode] If target file already exists, this
142 + determines whether the original file's mode is copied over. The default of
143 + false mimics the behavior of the `cp` command line tool. (Default: false)
144 + */
145 + this.cpR = function (fromPath, toPath, options) {
146 + let from = path.normalize(fromPath);
147 + let to = path.normalize(toPath);
148 + let toStat;
149 + let doesNotExistErr;
150 + let filename;
151 + let opts = options || {};
152 +
153 + if (from == to) {
154 + throw new Error('Cannot copy ' + from + ' to itself.');
155 + }
156 +
157 + // Handle rename-via-copy
158 + try {
159 + toStat = fs.statSync(to);
160 + }
161 + catch(e) {
162 + doesNotExistErr = e;
163 +
164 + // Get abs path so it's possible to check parent dir
165 + if (!this.isAbsolute(to)) {
166 + to = path.join(process.cwd(), to);
167 + }
168 +
169 + // Save the file/dir name
170 + filename = path.basename(to);
171 + // See if a parent dir exists, so there's a place to put the
172 + /// renamed file/dir (resets the destination for the copy)
173 + to = path.dirname(to);
174 + try {
175 + toStat = fs.statSync(to);
176 + }
177 + catch(e) {}
178 + if (toStat && toStat.isDirectory()) {
179 + // Set the rename opt to pass to the copy func, will be used
180 + // as the new file/dir name
181 + opts.rename = filename;
182 + //console.log('filename ' + filename);
183 + }
184 + else {
185 + throw doesNotExistErr;
186 + }
187 + }
188 +
189 + _copyFile(from, to, opts);
190 + };
191 +
192 + /**
193 + @name file#mkdirP
194 + @public
195 + @function
196 + @description Create the given directory(ies) using the given mode permissions
197 + @param {String} dir The directory to create
198 + @param {Number} mode The mode to give the created directory(ies)(Default: 0755)
199 + */
200 + this.mkdirP = function (dir, mode) {
201 + let dirPath = path.normalize(dir);
202 + let paths = dirPath.split(/\/|\\/);
203 + let currPath = '';
204 + let next;
205 +
206 + if (paths[0] == '' || /^[A-Za-z]+:/.test(paths[0])) {
207 + currPath = paths.shift() || '/';
208 + currPath = path.join(currPath, paths.shift());
209 + //console.log('basedir');
210 + }
211 + while ((next = paths.shift())) {
212 + if (next == '..') {
213 + currPath = path.join(currPath, next);
214 + continue;
215 + }
216 + currPath = path.join(currPath, next);
217 + try {
218 + //console.log('making ' + currPath);
219 + fs.mkdirSync(currPath, mode || parseInt(755, 8));
220 + }
221 + catch(e) {
222 + if (e.code != 'EEXIST') {
223 + throw e;
224 + }
225 + }
226 + }
227 + };
228 +
229 + /**
230 + @name file#rmRf
231 + @public
232 + @function
233 + @description Deletes the given directory/file
234 + @param {String} p The path to delete, can be a directory or file
235 + */
236 + this.rmRf = function (p, options) {
237 + let stat;
238 + try {
239 + stat = fs.lstatSync(p);
240 + if (stat.isDirectory()) {
241 + _rmDir(p);
242 + }
243 + else {
244 + fs.unlinkSync(p);
245 + }
246 + }
247 + catch (e) {}
248 + };
249 +
250 + /**
251 + @name file#isAbsolute
252 + @public
253 + @function
254 + @return {Boolean/String} If it's absolute the first character is returned otherwise false
255 + @description Checks if a given path is absolute or relative
256 + @param {String} p Path to check
257 + */
258 + this.isAbsolute = function (p) {
259 + let match = /^[A-Za-z]+:\\|^\//.exec(p);
260 + if (match && match.length) {
261 + return match[0];
262 + }
263 + return false;
264 + };
265 +
266 + /**
267 + @name file#absolutize
268 + @public
269 + @function
270 + @return {String} Returns the absolute path for the given path
271 + @description Returns the absolute path for the given path
272 + @param {String} p The path to get the absolute path for
273 + */
274 + this.absolutize = function (p) {
275 + if (this.isAbsolute(p)) {
276 + return p;
277 + }
278 + else {
279 + return path.join(process.cwd(), p);
280 + }
281 + };
282 +
283 +})();
284 +
285 +module.exports = fileUtils;
286 +
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +
20 +let util = require('util'); // Native Node util module
21 +let spawn = require('child_process').spawn;
22 +let EventEmitter = require('events').EventEmitter;
23 +let logger = require('./logger');
24 +let file = require('./file');
25 +let Exec;
26 +
27 +const _UUID_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
28 +
29 +let parseArgs = function (argumentsObj) {
30 + let args;
31 + let arg;
32 + let cmds;
33 + let callback;
34 + let opts = {
35 + interactive: false,
36 + printStdout: false,
37 + printStderr: false,
38 + breakOnError: true
39 + };
40 +
41 + args = Array.prototype.slice.call(argumentsObj);
42 +
43 + cmds = args.shift();
44 + // Arrayize if passed a single string command
45 + if (typeof cmds == 'string') {
46 + cmds = [cmds];
47 + }
48 + // Make a copy if it's an actual list
49 + else {
50 + cmds = cmds.slice();
51 + }
52 +
53 + // Get optional callback or opts
54 + while((arg = args.shift())) {
55 + if (typeof arg == 'function') {
56 + callback = arg;
57 + }
58 + else if (typeof arg == 'object') {
59 + opts = Object.assign(opts, arg);
60 + }
61 + }
62 +
63 + // Backward-compat shim
64 + if (typeof opts.stdout != 'undefined') {
65 + opts.printStdout = opts.stdout;
66 + delete opts.stdout;
67 + }
68 + if (typeof opts.stderr != 'undefined') {
69 + opts.printStderr = opts.stderr;
70 + delete opts.stderr;
71 + }
72 +
73 + return {
74 + cmds: cmds,
75 + opts: opts,
76 + callback: callback
77 + };
78 +};
79 +
80 +/**
81 + @name jake
82 + @namespace jake
83 +*/
84 +let utils = new (function () {
85 + /**
86 + @name jake.exec
87 + @static
88 + @function
89 + @description Executes shell-commands asynchronously with an optional
90 + final callback.
91 + `
92 + @param {String[]} cmds The list of shell-commands to execute
93 + @param {Object} [opts]
94 + @param {Boolean} [opts.printStdout=false] Print stdout from each command
95 + @param {Boolean} [opts.printStderr=false] Print stderr from each command
96 + @param {Boolean} [opts.breakOnError=true] Stop further execution on
97 + the first error.
98 + @param {Boolean} [opts.windowsVerbatimArguments=false] Don't translate
99 + arguments on Windows.
100 + @param {Function} [callback] Callback to run after executing the
101 + commands
102 +
103 + @example
104 + let cmds = [
105 + 'echo "showing directories"'
106 + , 'ls -al | grep ^d'
107 + , 'echo "moving up a directory"'
108 + , 'cd ../'
109 + ]
110 + , callback = function () {
111 + console.log('Finished running commands.');
112 + }
113 + jake.exec(cmds, {stdout: true}, callback);
114 + */
115 + this.exec = function (a, b, c) {
116 + let parsed = parseArgs(arguments);
117 + let cmds = parsed.cmds;
118 + let opts = parsed.opts;
119 + let callback = parsed.callback;
120 +
121 + let ex = new Exec(cmds, opts, callback);
122 +
123 + ex.addListener('error', function (msg, code) {
124 + if (opts.breakOnError) {
125 + fail(msg, code);
126 + }
127 + });
128 + ex.run();
129 +
130 + return ex;
131 + };
132 +
133 + this.createExec = function (a, b, c) {
134 + return new Exec(a, b, c);
135 + };
136 +
137 + // From Math.uuid.js, https://github.com/broofa/node-uuid
138 + // Robert Kieffer (robert@broofa.com), MIT license
139 + this.uuid = function (length, radix) {
140 + var chars = _UUID_CHARS
141 + , uuid = []
142 + , r
143 + , i;
144 +
145 + radix = radix || chars.length;
146 +
147 + if (length) {
148 + // Compact form
149 + i = -1;
150 + while (++i < length) {
151 + uuid[i] = chars[0 | Math.random()*radix];
152 + }
153 + } else {
154 + // rfc4122, version 4 form
155 +
156 + // rfc4122 requires these characters
157 + uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
158 + uuid[14] = '4';
159 +
160 + // Fill in random data. At i==19 set the high bits of clock sequence as
161 + // per rfc4122, sec. 4.1.5
162 + i = -1;
163 + while (++i < 36) {
164 + if (!uuid[i]) {
165 + r = 0 | Math.random()*16;
166 + uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
167 + }
168 + }
169 + }
170 +
171 + return uuid.join('');
172 + };
173 +
174 +})();
175 +
176 +Exec = function () {
177 + let parsed = parseArgs(arguments);
178 + let cmds = parsed.cmds;
179 + let opts = parsed.opts;
180 + let callback = parsed.callback;
181 +
182 + this._cmds = cmds;
183 + this._callback = callback;
184 + this._config = opts;
185 +};
186 +
187 +util.inherits(Exec, EventEmitter);
188 +
189 +Object.assign(Exec.prototype, new (function () {
190 +
191 + let _run = function () {
192 + let self = this;
193 + let sh;
194 + let cmd;
195 + let args;
196 + let next = this._cmds.shift();
197 + let config = this._config;
198 + let errData = '';
199 + let shStdio;
200 + let handleStdoutData = function (data) {
201 + self.emit('stdout', data);
202 + };
203 + let handleStderrData = function (data) {
204 + let d = data.toString();
205 + self.emit('stderr', data);
206 + // Accumulate the error-data so we can use it as the
207 + // stack if the process exits with an error
208 + errData += d;
209 + };
210 +
211 + // Keep running as long as there are commands in the array
212 + if (next) {
213 + let spawnOpts = {};
214 + this.emit('cmdStart', next);
215 +
216 + // Ganking part of Node's child_process.exec to get cmdline args parsed
217 + if (process.platform == 'win32') {
218 + cmd = 'cmd';
219 + args = ['/c', next];
220 + if (config.windowsVerbatimArguments) {
221 + spawnOpts.windowsVerbatimArguments = true;
222 + }
223 + }
224 + else {
225 + cmd = '/bin/sh';
226 + args = ['-c', next];
227 + }
228 +
229 + if (config.interactive) {
230 + spawnOpts.stdio = 'inherit';
231 + sh = spawn(cmd, args, spawnOpts);
232 + }
233 + else {
234 + shStdio = [
235 + process.stdin
236 + ];
237 + if (config.printStdout) {
238 + shStdio.push(process.stdout);
239 + }
240 + else {
241 + shStdio.push('pipe');
242 + }
243 + if (config.printStderr) {
244 + shStdio.push(process.stderr);
245 + }
246 + else {
247 + shStdio.push('pipe');
248 + }
249 + spawnOpts.stdio = shStdio;
250 + sh = spawn(cmd, args, spawnOpts);
251 + if (!config.printStdout) {
252 + sh.stdout.addListener('data', handleStdoutData);
253 + }
254 + if (!config.printStderr) {
255 + sh.stderr.addListener('data', handleStderrData);
256 + }
257 + }
258 +
259 + // Exit, handle err or run next
260 + sh.on('exit', function (code) {
261 + let msg;
262 + if (code !== 0) {
263 + msg = errData || 'Process exited with error.';
264 + msg = msg.trim();
265 + self.emit('error', msg, code);
266 + }
267 + if (code === 0 || !config.breakOnError) {
268 + self.emit('cmdEnd', next);
269 + setTimeout(function () { _run.call(self); }, 0);
270 + }
271 + });
272 +
273 + }
274 + else {
275 + self.emit('end');
276 + if (typeof self._callback == 'function') {
277 + self._callback();
278 + }
279 + }
280 + };
281 +
282 + this.append = function (cmd) {
283 + this._cmds.push(cmd);
284 + };
285 +
286 + this.run = function () {
287 + _run.call(this);
288 + };
289 +
290 +})());
291 +
292 +utils.Exec = Exec;
293 +utils.file = file;
294 +utils.logger = logger;
295 +
296 +module.exports = utils;
297 +
1 +let util = require('util');
2 +
3 +let logger = new (function () {
4 + let _output = function (type, out) {
5 + let quiet = typeof jake != 'undefined' && jake.program &&
6 + jake.program.opts && jake.program.opts.quiet;
7 + let msg;
8 + if (!quiet) {
9 + msg = typeof out == 'string' ? out : util.inspect(out);
10 + console[type](msg);
11 + }
12 + };
13 +
14 + this.log = function (out) {
15 + _output('log', out);
16 + };
17 +
18 + this.error = function (out) {
19 + _output('error', out);
20 + };
21 +
22 +})();
23 +
24 +module.exports = logger;
1 +{
2 + "name": "jake",
3 + "description": "JavaScript build tool, similar to Make or Rake",
4 + "keywords": [
5 + "build",
6 + "cli",
7 + "make",
8 + "rake"
9 + ],
10 + "version": "10.8.2",
11 + "author": "Matthew Eernisse <mde@fleegix.org> (http://fleegix.org)",
12 + "license": "Apache-2.0",
13 + "bin": {
14 + "jake": "./bin/cli.js"
15 + },
16 + "main": "./lib/jake.js",
17 + "scripts": {
18 + "lint": "eslint --format codeframe \"lib/**/*.js\" \"test/**/*.js\"",
19 + "lint:fix": "eslint --fix \"lib/**/*.js\" \"test/**/*.js\"",
20 + "test": "./bin/cli.js test",
21 + "test:ci": "npm run lint && npm run test"
22 + },
23 + "repository": {
24 + "type": "git",
25 + "url": "git://github.com/jakejs/jake.git"
26 + },
27 + "preferGlobal": true,
28 + "dependencies": {
29 + "filelist": "^1.0.1",
30 + "minimatch": "^3.0.4",
31 + "chalk": "^2.4.2",
32 + "async": "0.9.x"
33 + },
34 + "devDependencies": {
35 + "eslint": "^6.8.0",
36 + "mocha": "^7.1.1",
37 + "q": "^1.5.1"
38 + },
39 + "engines": {
40 + "node": "*"
41 + }
42 +}
1 +let assert = require('assert');
2 +let exec = require('child_process').execSync;
3 +
4 +suite('concurrent', function () {
5 +
6 + this.timeout(7000);
7 +
8 + test(' simple concurrent prerequisites 1', function () {
9 + let out = exec('./node_modules/.bin/jake -q concurrent:simple1').toString().trim()
10 + assert.equal('Started A\nStarted B\nFinished B\nFinished A', out);
11 + });
12 +
13 + test(' simple concurrent prerequisites 2', function () {
14 + let out = exec('./node_modules/.bin/jake -q concurrent:simple2').toString().trim()
15 + assert.equal('Started C\nStarted D\nFinished C\nFinished D', out);
16 + });
17 +
18 + test(' sequential concurrent prerequisites', function () {
19 + let out = exec('./node_modules/.bin/jake -q concurrent:seqconcurrent').toString().trim()
20 + assert.equal('Started A\nStarted B\nFinished B\nFinished A\nStarted C\nStarted D\nFinished C\nFinished D', out);
21 + });
22 +
23 + test(' concurrent concurrent prerequisites', function () {
24 + let out = exec('./node_modules/.bin/jake -q concurrent:concurrentconcurrent').toString().trim()
25 + assert.equal('Started A\nStarted B\nStarted C\nStarted D\nFinished B\nFinished C\nFinished A\nFinished D', out);
26 + });
27 +
28 + test(' concurrent prerequisites with subdependency', function () {
29 + let out = exec('./node_modules/.bin/jake -q concurrent:subdep').toString().trim()
30 + assert.equal('Started A\nFinished A\nStarted Ba\nFinished Ba', out);
31 + });
32 +
33 + test(' failing in concurrent prerequisites', function () {
34 + try {
35 + exec('./node_modules/.bin/jake -q concurrent:Cfail');
36 + }
37 + catch(err) {
38 + assert(err.message.indexOf('Command failed') > -1);
39 + }
40 + });
41 +
42 +});
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +const PROJECT_DIR = process.env.PROJECT_DIR;
20 +
21 +let assert = require('assert');
22 +let fs = require('fs');
23 +let path = require('path');
24 +let file = require(`${PROJECT_DIR}/lib/utils/file`);
25 +let existsSync = fs.existsSync || path.existsSync;
26 +let exec = require('child_process').execSync;
27 +
28 +suite('fileUtils', function () {
29 +
30 + test('mkdirP', function () {
31 + let expected = [
32 + ['foo'],
33 + ['foo', 'bar'],
34 + ['foo', 'bar', 'baz'],
35 + ['foo', 'bar', 'baz', 'qux']
36 + ];
37 + file.mkdirP('foo/bar/baz/qux');
38 + let res = exec('find foo').toString().trim().split('\n');
39 + for (let i = 0, ii = res.length; i < ii; i++) {
40 + assert.equal(path.join.apply(path, expected[i]), res[i]);
41 + }
42 + file.rmRf('foo');
43 + });
44 +
45 + test('rmRf', function () {
46 + file.mkdirP('foo/bar/baz/qux');
47 + file.rmRf('foo/bar');
48 + let res = exec('find foo').toString().trim().split('\n');
49 + assert.equal(1, res.length);
50 + assert.equal('foo', res[0]);
51 + fs.rmdirSync('foo');
52 + });
53 +
54 + test('rmRf with symlink subdir', function () {
55 + file.mkdirP('foo');
56 + file.mkdirP('bar');
57 + fs.writeFileSync('foo/hello.txt', 'hello, it\'s me');
58 + fs.symlinkSync('../foo', 'bar/foo'); file.rmRf('bar');
59 +
60 + // Make sure the bar directory was successfully deleted
61 + let barDeleted = false;
62 + try {
63 + fs.statSync('bar');
64 + } catch(err) {
65 + if(err.code == 'ENOENT') {
66 + barDeleted = true;
67 + }
68 + }
69 + assert.equal(true, barDeleted);
70 +
71 + // Make sure that the file inside the linked folder wasn't deleted
72 + let res = fs.readdirSync('foo');
73 + assert.equal(1, res.length);
74 + assert.equal('hello.txt', res[0]);
75 +
76 + // Cleanup
77 + fs.unlinkSync('foo/hello.txt');
78 + fs.rmdirSync('foo');
79 + });
80 +
81 + test('rmRf with symlinked dir', function () {
82 + file.mkdirP('foo');
83 + fs.writeFileSync('foo/hello.txt', 'hello!');
84 + fs.symlinkSync('foo', 'bar');
85 + file.rmRf('bar');
86 +
87 + // Make sure the bar directory was successfully deleted
88 + let barDeleted = false;
89 + try {
90 + fs.statSync('bar');
91 + } catch(err) {
92 + if(err.code == 'ENOENT') {
93 + barDeleted = true;
94 + }
95 + }
96 + assert.equal(true, barDeleted);
97 +
98 + // Make sure that the file inside the linked folder wasn't deleted
99 + let res = fs.readdirSync('foo');
100 + assert.equal(1, res.length);
101 + assert.equal('hello.txt', res[0]);
102 +
103 + // Cleanup
104 + fs.unlinkSync('foo/hello.txt');
105 + fs.rmdirSync('foo');
106 + });
107 +
108 + test('cpR with same name and different directory', function () {
109 + file.mkdirP('foo');
110 + fs.writeFileSync('foo/bar.txt', 'w00t');
111 + file.cpR('foo', 'bar');
112 + assert.ok(existsSync('bar/bar.txt'));
113 + file.rmRf('foo');
114 + file.rmRf('bar');
115 + });
116 +
117 + test('cpR with same to and from will throw', function () {
118 + assert.throws(function () {
119 + file.cpR('foo.txt', 'foo.txt');
120 + });
121 + });
122 +
123 + test('cpR rename via copy in directory', function () {
124 + file.mkdirP('foo');
125 + fs.writeFileSync('foo/bar.txt', 'w00t');
126 + file.cpR('foo/bar.txt', 'foo/baz.txt');
127 + assert.ok(existsSync('foo/baz.txt'));
128 + file.rmRf('foo');
129 + });
130 +
131 + test('cpR rename via copy in base', function () {
132 + fs.writeFileSync('bar.txt', 'w00t');
133 + file.cpR('bar.txt', 'baz.txt');
134 + assert.ok(existsSync('baz.txt'));
135 + file.rmRf('bar.txt');
136 + file.rmRf('baz.txt');
137 + });
138 +
139 + test('cpR keeps file mode', function () {
140 + fs.writeFileSync('bar.txt', 'w00t', {mode: 0o750});
141 + fs.writeFileSync('bar1.txt', 'w00t!', {mode: 0o744});
142 + file.cpR('bar.txt', 'baz.txt');
143 + file.cpR('bar1.txt', 'baz1.txt');
144 +
145 + assert.ok(existsSync('baz.txt'));
146 + assert.ok(existsSync('baz1.txt'));
147 + let bazStat = fs.statSync('baz.txt');
148 + let bazStat1 = fs.statSync('baz1.txt');
149 + assert.equal(0o750, bazStat.mode & 0o7777);
150 + assert.equal(0o744, bazStat1.mode & 0o7777);
151 +
152 + file.rmRf('bar.txt');
153 + file.rmRf('baz.txt');
154 + file.rmRf('bar1.txt');
155 + file.rmRf('baz1.txt');
156 + });
157 +
158 + test('cpR keeps file mode when overwriting with preserveMode', function () {
159 + fs.writeFileSync('bar.txt', 'w00t', {mode: 0o755});
160 + fs.writeFileSync('baz.txt', 'w00t!', {mode: 0o744});
161 + file.cpR('bar.txt', 'baz.txt', {silent: true, preserveMode: true});
162 +
163 + assert.ok(existsSync('baz.txt'));
164 + let bazStat = fs.statSync('baz.txt');
165 + assert.equal(0o755, bazStat.mode & 0o777);
166 +
167 + file.rmRf('bar.txt');
168 + file.rmRf('baz.txt');
169 + });
170 +
171 + test('cpR does not keep file mode when overwriting', function () {
172 + fs.writeFileSync('bar.txt', 'w00t', {mode: 0o766});
173 + fs.writeFileSync('baz.txt', 'w00t!', {mode: 0o744});
174 + file.cpR('bar.txt', 'baz.txt');
175 +
176 + assert.ok(existsSync('baz.txt'));
177 + let bazStat = fs.statSync('baz.txt');
178 + assert.equal(0o744, bazStat.mode & 0o777);
179 +
180 + file.rmRf('bar.txt');
181 + file.rmRf('baz.txt');
182 + });
183 +
184 + test('cpR copies file mode recursively', function () {
185 + fs.mkdirSync('foo');
186 + fs.writeFileSync('foo/bar.txt', 'w00t', {mode: 0o740});
187 + file.cpR('foo', 'baz');
188 +
189 + assert.ok(existsSync('baz'));
190 + let barStat = fs.statSync('baz/bar.txt');
191 + assert.equal(0o740, barStat.mode & 0o777);
192 +
193 + file.rmRf('foo');
194 + file.rmRf('baz');
195 + });
196 +
197 + test('cpR keeps file mode recursively', function () {
198 + fs.mkdirSync('foo');
199 + fs.writeFileSync('foo/bar.txt', 'w00t', {mode: 0o740});
200 + fs.mkdirSync('baz');
201 + fs.mkdirSync('baz/foo');
202 + fs.writeFileSync('baz/foo/bar.txt', 'w00t!', {mode: 0o755});
203 + file.cpR('foo', 'baz', {silent: true, preserveMode: true});
204 +
205 + assert.ok(existsSync('baz'));
206 + let barStat = fs.statSync('baz/foo/bar.txt');
207 + assert.equal(0o740, barStat.mode & 0o777);
208 +
209 + file.rmRf('foo');
210 + file.rmRf('baz');
211 + });
212 +
213 + test('cpR copies directory mode recursively', function () {
214 + fs.mkdirSync('foo', 0o755);
215 + fs.mkdirSync('foo/bar', 0o700);
216 + file.cpR('foo', 'bar');
217 +
218 + assert.ok(existsSync('foo'));
219 + let fooBarStat = fs.statSync('bar/bar');
220 + assert.equal(0o700, fooBarStat.mode & 0o777);
221 +
222 + file.rmRf('foo');
223 + file.rmRf('bar');
224 + });
225 +
226 +});
227 +
228 +
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +const PROJECT_DIR = process.env.PROJECT_DIR;
20 +
21 +let assert = require('assert');
22 +let fs = require('fs');
23 +let exec = require('child_process').execSync;
24 +let { rmRf } = require(`${PROJECT_DIR}/lib/jake`);
25 +
26 +let cleanUpAndNext = function (callback) {
27 + rmRf('./foo', {
28 + silent: true
29 + });
30 + callback && callback();
31 +};
32 +
33 +suite('fileTask', function () {
34 + this.timeout(7000);
35 +
36 + setup(function () {
37 + cleanUpAndNext();
38 + });
39 +
40 + test('where a file-task prereq does not change with --always-make', function () {
41 + let out;
42 + out = exec('./node_modules/.bin/jake -q fileTest:foo/from-src1.txt').toString().trim();
43 + assert.equal('fileTest:foo/src1.txt task\nfileTest:foo/from-src1.txt task',
44 + out);
45 + out = exec('./node_modules/.bin/jake -q -B fileTest:foo/from-src1.txt').toString().trim();
46 + assert.equal('fileTest:foo/src1.txt task\nfileTest:foo/from-src1.txt task',
47 + out);
48 + cleanUpAndNext();
49 + });
50 +
51 + test('concating two files', function () {
52 + let out;
53 + out = exec('./node_modules/.bin/jake -q fileTest:foo/concat.txt').toString().trim();
54 + assert.equal('fileTest:foo/src1.txt task\ndefault task\nfileTest:foo/src2.txt task\n' +
55 + 'fileTest:foo/concat.txt task', out);
56 + // Check to see the two files got concat'd
57 + let data = fs.readFileSync(process.cwd() + '/foo/concat.txt');
58 + assert.equal('src1src2', data.toString());
59 + cleanUpAndNext();
60 + });
61 +
62 + test('where a file-task prereq does not change', function () {
63 + let out;
64 + out = exec('./node_modules/.bin/jake -q fileTest:foo/from-src1.txt').toString().trim();
65 + assert.equal('fileTest:foo/src1.txt task\nfileTest:foo/from-src1.txt task', out);
66 + out = exec('./node_modules/.bin/jake -q fileTest:foo/from-src1.txt').toString().trim();
67 + // Second time should be a no-op
68 + assert.equal('', out);
69 + cleanUpAndNext();
70 + });
71 +
72 + test('where a file-task prereq does change, then does not', function (next) {
73 + exec('mkdir -p ./foo');
74 + exec('touch ./foo/from-src1.txt');
75 + setTimeout(() => {
76 + fs.writeFileSync('./foo/src1.txt', '-SRC');
77 + // Task should run the first time
78 + let out;
79 + out = exec('./node_modules/.bin/jake -q fileTest:foo/from-src1.txt').toString().trim();
80 + assert.equal('fileTest:foo/from-src1.txt task', out);
81 + // Task should not run on subsequent invocation
82 + out = exec('./node_modules/.bin/jake -q fileTest:foo/from-src1.txt').toString().trim();
83 + assert.equal('', out);
84 + cleanUpAndNext(next);
85 + }, 1000);
86 + });
87 +
88 + test('a preexisting file', function () {
89 + let prereqData = 'howdy';
90 + exec('mkdir -p ./foo');
91 + fs.writeFileSync('foo/prereq.txt', prereqData);
92 + let out;
93 + out = exec('./node_modules/.bin/jake -q fileTest:foo/from-prereq.txt').toString().trim();
94 + assert.equal('fileTest:foo/from-prereq.txt task', out);
95 + let data = fs.readFileSync(process.cwd() + '/foo/from-prereq.txt');
96 + assert.equal(prereqData, data.toString());
97 + out = exec('./node_modules/.bin/jake -q fileTest:foo/from-prereq.txt').toString().trim();
98 + // Second time should be a no-op
99 + assert.equal('', out);
100 + cleanUpAndNext();
101 + });
102 +
103 + test('a preexisting file with --always-make flag', function () {
104 + let prereqData = 'howdy';
105 + exec('mkdir -p ./foo');
106 + fs.writeFileSync('foo/prereq.txt', prereqData);
107 + let out;
108 + out = exec('./node_modules/.bin/jake -q fileTest:foo/from-prereq.txt').toString().trim();
109 + assert.equal('fileTest:foo/from-prereq.txt task', out);
110 + let data = fs.readFileSync(process.cwd() + '/foo/from-prereq.txt');
111 + assert.equal(prereqData, data.toString());
112 + out = exec('./node_modules/.bin/jake -q -B fileTest:foo/from-prereq.txt').toString().trim();
113 + assert.equal('fileTest:foo/from-prereq.txt task', out);
114 + cleanUpAndNext();
115 + });
116 +
117 + test('nested directory-task', function () {
118 + exec('./node_modules/.bin/jake -q fileTest:foo/bar/baz/bamf.txt');
119 + let data = fs.readFileSync(process.cwd() + '/foo/bar/baz/bamf.txt');
120 + assert.equal('w00t', data);
121 + cleanUpAndNext();
122 + });
123 +
124 +});
125 +
1 +var exec = require('child_process').exec;
2 +
3 +var helpers = new (function () {
4 + var _tests;
5 + var _names = [];
6 + var _name;
7 + var _callback;
8 + var _runner = function () {
9 + if ((_name = _names.shift())) {
10 + console.log('Running ' + _name);
11 + _tests[_name]();
12 + }
13 + else {
14 + _callback();
15 + }
16 + };
17 +
18 + this.exec = function () {
19 + var args = Array.prototype.slice.call(arguments);
20 + var arg;
21 + var cmd = args.shift();
22 + var opts = {};
23 + var callback;
24 + // Optional opts/callback or callback/opts
25 + while ((arg = args.shift())) {
26 + if (typeof arg == 'function') {
27 + callback = arg;
28 + }
29 + else {
30 + opts = arg;
31 + }
32 + }
33 +
34 + cmd += ' --trace';
35 + var execOpts = opts.execOpts ? opts.execOpts : {};
36 + exec(cmd, execOpts, function (err, stdout, stderr) {
37 + var out = helpers.trim(stdout);
38 + if (err) {
39 + if (opts.breakOnError === false) {
40 + return callback(err);
41 + }
42 + else {
43 + throw err;
44 + }
45 + }
46 + if (stderr) {
47 + callback(stderr);
48 + }
49 + else {
50 + callback(out);
51 + }
52 + });
53 + };
54 +
55 + this.trim = function (s) {
56 + var str = s || '';
57 + return str.replace(/^\s*|\s*$/g, '');
58 + };
59 +
60 + this.parse = function (s) {
61 + var str = s || '';
62 + str = helpers.trim(str);
63 + str = str.replace(/'/g, '"');
64 + return JSON.parse(str);
65 + };
66 +
67 + this.run = function (tests, callback) {
68 + _tests = tests;
69 + _names = Object.keys(tests);
70 + _callback = callback;
71 + _runner();
72 + };
73 +
74 + this.next = function () {
75 + _runner();
76 + };
77 +
78 +})();
79 +
80 +module.exports = helpers;
1 +let fs = require('fs');
2 +let Q = require('q');
3 +
4 +desc('The default t.');
5 +task('default', function () {
6 + console.log('default task');
7 +});
8 +
9 +desc('No action.');
10 +task({'noAction': ['default']});
11 +
12 +desc('No action, no prereqs.');
13 +task('noActionNoPrereqs');
14 +
15 +desc('Top-level zerbofrangazoomy task');
16 +task('zerbofrangazoomy', function () {
17 + console.log('Whaaaaaaaa? Ran the zerbofrangazoomy task!')
18 +});
19 +
20 +desc('Task that throws');
21 +task('throwy', function () {
22 + let errorListener = function (err) {
23 + console.log('Emitted');
24 + console.log(err.toString());
25 +
26 + jake.removeListener('error', errorListener);
27 + };
28 +
29 + jake.on('error', errorListener);
30 +
31 + throw new Error('I am bad');
32 +});
33 +
34 +desc('Task that rejects a Promise');
35 +task('promiseRejecter', function () {
36 + const originalOption = jake.program.opts['allow-rejection'];
37 +
38 + const errorListener = function (err) {
39 + console.log(err.toString());
40 + jake.removeListener('error', errorListener);
41 + jake.program.opts['allow-rejection'] = originalOption; // Restore original 'allow-rejection' option
42 + };
43 + jake.on('error', errorListener);
44 +
45 + jake.program.opts['allow-rejection'] = false; // Do not allow rejection so the rejection is passed to error handlers
46 +
47 + Promise.reject('<promise rejected on purpose>');
48 +});
49 +
50 +desc('Accepts args and env vars.');
51 +task('argsEnvVars', function () {
52 + let res = {
53 + args: arguments
54 + , env: {
55 + foo: process.env.foo
56 + , baz: process.env.baz
57 + }
58 + };
59 + console.log(JSON.stringify(res));
60 +});
61 +
62 +namespace('foo', function () {
63 + desc('The foo:bar t.');
64 + task('bar', function () {
65 + if (arguments.length) {
66 + console.log('foo:bar[' +
67 + Array.prototype.join.call(arguments, ',') +
68 + '] task');
69 + }
70 + else {
71 + console.log('foo:bar task');
72 + }
73 + });
74 +
75 + desc('The foo:baz task, calls foo:bar as a prerequisite.');
76 + task('baz', ['foo:bar'], function () {
77 + console.log('foo:baz task');
78 + });
79 +
80 + desc('The foo:qux task, calls foo:bar with cmdline args as a prerequisite.');
81 + task('qux', ['foo:bar[asdf,qwer]'], function () {
82 + console.log('foo:qux task');
83 + });
84 +
85 + desc('The foo:frang task,`invokes` foo:bar with passed args as a prerequisite.');
86 + task('frang', function () {
87 + let t = jake.Task['foo:bar'];
88 + // Do args pass-through
89 + t.invoke.apply(t, arguments);
90 + t.on('complete', () => {
91 + console.log('foo:frang task');
92 + });
93 + });
94 +
95 + desc('The foo:zerb task, `executes` foo:bar with passed args as a prerequisite.');
96 + task('zerb', function () {
97 + let t = jake.Task['foo:bar'];
98 + // Do args pass-through
99 + t.execute.apply(t, arguments);
100 + t.on('complete', () => {
101 + console.log('foo:zerb task');
102 + });
103 + });
104 +
105 + desc('The foo:zoobie task, has no prerequisites.');
106 + task('zoobie', function () {
107 + console.log('foo:zoobie task');
108 + });
109 +
110 + desc('The foo:voom task, run the foo:zoobie task repeatedly.');
111 + task('voom', function () {
112 + let t = jake.Task['foo:bar'];
113 + t.on('complete', function () {
114 + console.log('complete');
115 + });
116 + t.execute.apply(t);
117 + t.execute.apply(t);
118 + });
119 +
120 + desc('The foo:asdf task, has the same prereq twice.');
121 + task('asdf', ['foo:bar', 'foo:baz'], function () {
122 + console.log('foo:asdf task');
123 + });
124 +
125 +});
126 +
127 +namespace('bar', function () {
128 + desc('The bar:foo task, has no prerequisites, is async, returns Promise which resolves.');
129 + task('foo', async function () {
130 + return new Promise((resolve, reject) => {
131 + console.log('bar:foo task');
132 + resolve();
133 + });
134 + });
135 +
136 + desc('The bar:promise task has no prerequisites, is async, returns Q-based promise.');
137 + task('promise', function () {
138 + return Q()
139 + .then(function () {
140 + console.log('bar:promise task');
141 + return 123654;
142 + });
143 + });
144 +
145 + desc('The bar:dependOnpromise task waits for a promise based async test');
146 + task('dependOnpromise', ['promise'], function () {
147 + console.log('bar:dependOnpromise task saw value', jake.Task["bar:promise"].value);
148 + });
149 +
150 + desc('The bar:brokenPromise task is a failing Q-promise based async task.');
151 + task('brokenPromise', function () {
152 + return Q()
153 + .then(function () {
154 + throw new Error("nom nom nom");
155 + });
156 + });
157 +
158 + desc('The bar:bar task, has the async bar:foo task as a prerequisite.');
159 + task('bar', ['bar:foo'], function () {
160 + console.log('bar:bar task');
161 + });
162 +
163 +});
164 +
165 +namespace('hoge', function () {
166 + desc('The hoge:hoge task, has no prerequisites.');
167 + task('hoge', function () {
168 + console.log('hoge:hoge task');
169 + });
170 +
171 + desc('The hoge:piyo task, has no prerequisites.');
172 + task('piyo', function () {
173 + console.log('hoge:piyo task');
174 + });
175 +
176 + desc('The hoge:fuga task, has hoge:hoge and hoge:piyo as prerequisites.');
177 + task('fuga', ['hoge:hoge', 'hoge:piyo'], function () {
178 + console.log('hoge:fuga task');
179 + });
180 +
181 + desc('The hoge:charan task, has hoge:fuga as a prerequisite.');
182 + task('charan', ['hoge:fuga'], function () {
183 + console.log('hoge:charan task');
184 + });
185 +
186 + desc('The hoge:gero task, has hoge:fuga as a prerequisite.');
187 + task('gero', ['hoge:fuga'], function () {
188 + console.log('hoge:gero task');
189 + });
190 +
191 + desc('The hoge:kira task, has hoge:charan and hoge:gero as prerequisites.');
192 + task('kira', ['hoge:charan', 'hoge:gero'], function () {
193 + console.log('hoge:kira task');
194 + });
195 +
196 +});
197 +
198 +namespace('fileTest', function () {
199 + directory('foo');
200 +
201 + desc('File task, concatenating two files together');
202 + file('foo/concat.txt', ['fileTest:foo', 'fileTest:foo/src1.txt', 'fileTest:foo/src2.txt'], function () {
203 + console.log('fileTest:foo/concat.txt task');
204 + let data1 = fs.readFileSync('foo/src1.txt');
205 + let data2 = fs.readFileSync('foo/src2.txt');
206 + fs.writeFileSync('foo/concat.txt', data1 + data2);
207 + });
208 +
209 + desc('File task, async creation with writeFile');
210 + file('foo/src1.txt', function () {
211 + return new Promise(function (resolve, reject) {
212 + fs.writeFile('foo/src1.txt', 'src1', function (err) {
213 + if (err) {
214 + reject(err);
215 + }
216 + else {
217 + console.log('fileTest:foo/src1.txt task');
218 + resolve();
219 + }
220 + });
221 + });
222 + });
223 +
224 + desc('File task, sync creation with writeFileSync');
225 + file('foo/src2.txt', ['default'], function () {
226 + fs.writeFileSync('foo/src2.txt', 'src2');
227 + console.log('fileTest:foo/src2.txt task');
228 + });
229 +
230 + desc('File task, do not run unless the prereq file changes');
231 + file('foo/from-src1.txt', ['fileTest:foo', 'fileTest:foo/src1.txt'], function () {
232 + let data = fs.readFileSync('foo/src1.txt').toString();
233 + fs.writeFileSync('foo/from-src1.txt', data);
234 + console.log('fileTest:foo/from-src1.txt task');
235 + });
236 +
237 + desc('File task, run if the prereq file changes');
238 + task('touch-prereq', function () {
239 + fs.writeFileSync('foo/prereq.txt', 'UPDATED');
240 + })
241 +
242 + desc('File task, has a preexisting file (with no associated task) as a prereq');
243 + file('foo/from-prereq.txt', ['fileTest:foo', 'foo/prereq.txt'], function () {
244 + let data = fs.readFileSync('foo/prereq.txt');
245 + fs.writeFileSync('foo/from-prereq.txt', data);
246 + console.log('fileTest:foo/from-prereq.txt task');
247 + });
248 +
249 + directory('foo/bar/baz');
250 +
251 + desc('Write a file in a nested subdirectory');
252 + file('foo/bar/baz/bamf.txt', ['foo/bar/baz'], function () {
253 + fs.writeFileSync('foo/bar/baz/bamf.txt', 'w00t');
254 + });
255 +
256 +});
257 +
258 +task('blammo');
259 +// Define task
260 +task('voom', ['blammo'], function () {
261 + console.log(this.prereqs.length);
262 +});
263 +
264 +// Modify, add a prereq
265 +task('voom', ['noActionNoPrereqs']);
266 +
267 +namespace('vronk', function () {
268 + task('groo', function () {
269 + let t = jake.Task['vronk:zong'];
270 + t.addListener('error', function (e) {
271 + console.log(e.message);
272 + });
273 + t.invoke();
274 + });
275 + task('zong', function () {
276 + throw new Error('OMFGZONG');
277 + });
278 +});
279 +
280 +// define namespace
281 +namespace('one', function () {
282 + task('one', function () {
283 + console.log('one:one');
284 + });
285 +});
286 +
287 +// modify namespace (add task)
288 +namespace('one', function () {
289 + task('two', ['one:one'], function () {
290 + console.log('one:two');
291 + });
292 +});
293 +
294 +task('selfdepconst', [], function () {
295 + task('selfdep', ['selfdep'], function () {
296 + console.log("I made a task that depends on itself");
297 + });
298 +});
299 +task('selfdepdyn', function () {
300 + task('selfdeppar', [], {concurrency: 2}, function () {
301 + console.log("I will depend on myself and will fail at runtime");
302 + });
303 + task('selfdeppar', ['selfdeppar']);
304 + jake.Task['selfdeppar'].invoke();
305 +});
306 +
307 +namespace("large", function () {
308 + task("leaf", function () {
309 + console.log("large:leaf");
310 + });
311 +
312 + const same = [];
313 + for (let i = 0; i < 2000; i++) {
314 + same.push("leaf");
315 + }
316 +
317 + desc("Task with a large number of same prereqs");
318 + task("same", same, { concurrency: 2 }, function () {
319 + console.log("large:same");
320 + });
321 +
322 + const different = [];
323 + for (let i = 0; i < 2000; i++) {
324 + const name = "leaf-" + i;
325 + task(name, function () {
326 + if (name === "leaf-12" || name === "leaf-123") {
327 + console.log(name);
328 + }
329 + });
330 + different.push(name);
331 + }
332 +
333 + desc("Task with a large number of different prereqs");
334 + task("different", different, { concurrency: 2 } , function () {
335 + console.log("large:different")
336 + })
337 +});
1 +
2 +namespace('concurrent', function () {
3 + task('A', function () {
4 + console.log('Started A');
5 + return new Promise((resolve, reject) => {
6 + setTimeout(() => {
7 + console.log('Finished A');
8 + resolve();
9 + }, 200);
10 + });
11 + });
12 +
13 + task('B', function () {
14 + console.log('Started B');
15 + return new Promise((resolve, reject) => {
16 + setTimeout(() => {
17 + console.log('Finished B');
18 + resolve();
19 + }, 50);
20 + });
21 + });
22 +
23 + task('C', function () {
24 + console.log('Started C');
25 + return new Promise((resolve, reject) => {
26 + setTimeout(() => {
27 + console.log('Finished C');
28 + resolve();
29 + }, 100);
30 + });
31 + });
32 +
33 + task('D', function () {
34 + console.log('Started D');
35 + return new Promise((resolve, reject) => {
36 + setTimeout(() => {
37 + console.log('Finished D');
38 + resolve();
39 + }, 300);
40 + });
41 + });
42 +
43 + task('Ba', ['A'], function () {
44 + console.log('Started Ba');
45 + return new Promise((resolve, reject) => {
46 + setTimeout(() => {
47 + console.log('Finished Ba');
48 + resolve();
49 + }, 50);
50 + });
51 + });
52 +
53 + task('Afail', function () {
54 + console.log('Started failing task');
55 + return new Promise((resolve, reject) => {
56 + setTimeout(() => {
57 + console.log('Failing B with error');
58 + throw new Error('I failed');
59 + }, 50);
60 + });
61 + });
62 +
63 + task('simple1', ['A','B'], {concurrency: 2}, function () {
64 + return new Promise((resolve, reject) => {
65 + setTimeout(() => {
66 + resolve();
67 + }, 50);
68 + });
69 + });
70 +
71 + task('simple2', ['C','D'], {concurrency: 2}, function () {
72 + return new Promise((resolve, reject) => {
73 + setTimeout(() => {
74 + resolve();
75 + }, 50);
76 + });
77 + });
78 +
79 + task('seqconcurrent', ['simple1','simple2'], function () {
80 + return new Promise((resolve, reject) => {
81 + setTimeout(() => {
82 + resolve();
83 + }, 50);
84 + });
85 + });
86 +
87 + task('concurrentconcurrent', ['simple1','simple2'], {concurrency: 2}, function () {
88 + return new Promise((resolve, reject) => {
89 + setTimeout(() => {
90 + resolve();
91 + }, 50);
92 + });
93 + });
94 +
95 + task('subdep', ['A','Ba'], {concurrency: 2}, function () {
96 + return new Promise((resolve, reject) => {
97 + setTimeout(() => {
98 + resolve();
99 + }, 50);
100 + });
101 + });
102 +
103 + task('fail', ['A', 'B', 'Afail'], {concurrency: 3}, function () {
104 + return new Promise((resolve, reject) => {
105 + setTimeout(() => {
106 + resolve();
107 + }, 50);
108 + });
109 + });
110 +
111 +});
112 +
113 +
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +const PROJECT_DIR = process.env.PROJECT_DIR;
20 +
21 +let fs = require('fs');
22 +let { publishTask, rmRf, mkdirP } = require(`${PROJECT_DIR}/lib/jake`);
23 +
24 +fs.writeFileSync('package.json', '{"version": "0.0.1"}');
25 +mkdirP('tmp_publish');
26 +fs.writeFileSync('tmp_publish/foo.txt', 'FOO');
27 +
28 +publishTask('zerb', function () {
29 + this.packageFiles.include([
30 + 'package.json'
31 + , 'tmp_publish/**'
32 + ]);
33 + this.publishCmd = 'node -p -e "\'%filename\'"';
34 + this.gitCmd = 'echo'
35 + this.scheduleDelay = 0;
36 +
37 + this._ensureRepoClean = function () {};
38 + this._getCurrentBranch = function () {
39 + return 'v0.0'
40 + };
41 +});
42 +
43 +jake.setTaskTimeout(5000);
44 +
45 +jake.Task['publish'].on('complete', function () {
46 + rmRf('tmp_publish', {silent: true});
47 + rmRf('package.json', {silent: true});
48 +});
49 +
1 +let { task, namespace } = require("jake");
2 +
3 +namespace('usingRequire', function () {
4 + task('test', () => {
5 + console.log('howdy test');
6 + });
7 +});
8 +
9 +
10 +
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +const PROJECT_DIR = process.env.PROJECT_DIR;
20 +
21 +let exec = require('child_process').execSync;
22 +let fs = require('fs');
23 +let util = require('util');
24 +let { rule, rmRf } = require(`${PROJECT_DIR}/lib/jake`);
25 +
26 +directory('tmpsrc');
27 +directory('tmpbin');
28 +
29 +////////////////////////////////////////////////////////////
30 +// Simple Suffix Rule
31 +file('tmp', ['tmp_init', 'tmp_dep1.o', 'tmp_dep2.o'], function (params) {
32 + console.log('tmp task');
33 + let data1 = fs.readFileSync('tmp_dep1.o');
34 + let data2 = fs.readFileSync('tmp_dep2.o');
35 + fs.writeFileSync('tmp', data1 + data2);
36 +});
37 +
38 +rule('.o', '.c', function () {
39 + let cmd = util.format('cp %s %s', this.source, this.name);
40 + console.log(cmd + ' task');
41 + exec(cmd);
42 +});
43 +
44 +file('tmp_dep1.c', function () {
45 + fs.writeFileSync('tmp_dep1.c', 'src_1');
46 + console.log('tmp_dep1.c task');
47 +});
48 +
49 +// note that tmp_dep2.o depends on tmp_dep2.c, which is a
50 +// static file.
51 +task('tmp_init', function () {
52 + fs.writeFileSync('tmp_dep2.c', 'src_2');
53 + console.log('tmp_dep2.c task');
54 +});
55 +////////////////////////////////////////////////////////////
56 +
57 +////////////////////////////////////////////////////////////
58 +// Pattern Rule
59 +file('tmp_p', ['tmp_init', 'tmp_dep1.oo', 'tmp_dep2.oo'], function (params) {
60 + console.log('tmp pattern task');
61 + let data1 = fs.readFileSync('tmp_dep1.oo');
62 + let data2 = fs.readFileSync('tmp_dep2.oo');
63 + fs.writeFileSync('tmp_p', data1 + data2 + ' pattern');
64 +});
65 +
66 +rule('%.oo', '%.c', function () {
67 + let cmd = util.format('cp %s %s', this.source, this.name);
68 + console.log(cmd + ' task');
69 + exec(cmd);
70 +});
71 +////////////////////////////////////////////////////////////
72 +
73 +////////////////////////////////////////////////////////////
74 +// Pattern Rule with Folder
75 +// i.e. rule('tmpbin/%.oo', 'tmpsrc/%.c', ...
76 +file('tmp_pf', [
77 + 'tmp_src_init'
78 + , 'tmpbin'
79 + , 'tmpbin/tmp_dep1.oo'
80 + , 'tmpbin/tmp_dep2.oo' ], function (params) {
81 + console.log('tmp pattern folder task');
82 + let data1 = fs.readFileSync('tmpbin/tmp_dep1.oo');
83 + let data2 = fs.readFileSync('tmpbin/tmp_dep2.oo');
84 + fs.writeFileSync('tmp_pf', data1 + data2 + ' pattern folder');
85 +});
86 +
87 +rule('tmpbin/%.oo', 'tmpsrc/%.c', function () {
88 + let cmd = util.format('cp %s %s', this.source, this.name);
89 + console.log(cmd + ' task');
90 + exec(cmd);
91 +});
92 +
93 +file('tmpsrc/tmp_dep2.c',['tmpsrc'], function () {
94 + fs.writeFileSync('tmpsrc/tmp_dep2.c', 'src/src_2');
95 + console.log('tmpsrc/tmp_dep2.c task');
96 +});
97 +
98 +// Create static files in folder tmpsrc.
99 +task('tmp_src_init', ['tmpsrc'], function () {
100 + fs.writeFileSync('tmpsrc/tmp_dep1.c', 'src/src_1');
101 + console.log('tmpsrc/tmp_dep1.c task');
102 +});
103 +////////////////////////////////////////////////////////////
104 +
105 +
106 +////////////////////////////////////////////////////////////
107 +// Namespace Test. This is a Mixed Test.
108 +// Test for
109 +// - rules belonging to different namespace.
110 +// - rules with folder and pattern
111 +task('tmp_ns', [
112 + 'tmpbin'
113 + , 'rule:init'
114 + , 'tmpbin/tmp_dep2.oo' // *** This relies on a rule defined before.
115 + , 'rule:tmpbin/dep1.oo'
116 + , 'rule:tmpbin/file2.oo' ], function () {
117 + console.log('tmp pattern folder namespace task');
118 + let data1 = fs.readFileSync('tmpbin/dep1.oo');
119 + let data2 = fs.readFileSync('tmpbin/tmp_dep2.oo');
120 + let data3 = fs.readFileSync('tmpbin/file2.oo');
121 + fs.writeFileSync('tmp_ns', data1 + data2 + data3 + ' pattern folder namespace');
122 +});
123 +
124 +namespace('rule', function () {
125 + task('init', ['tmpsrc'], function () {
126 + fs.writeFileSync('tmpsrc/file2.c', 'src/src_3');
127 + console.log('tmpsrc/file2.c init task');
128 + });
129 +
130 + file('tmpsrc/dep1.c',['tmpsrc'], function () {
131 + fs.writeFileSync('tmpsrc/dep1.c', 'src/src_1');
132 + console.log('tmpsrc/dep1.c task');
133 + }, {async: true});
134 +
135 + rule('tmpbin/%.oo', 'tmpsrc/%.c', function () {
136 + let cmd = util.format('cp %s %s', this.source, this.name);
137 + console.log(cmd + ' ns task');
138 + exec(cmd);
139 + });
140 +});
141 +////////////////////////////////////////////////////////////
142 +
143 +////////////////////////////////////////////////////////////
144 +// Chain rule
145 +// rule('tmpbin/%.pdf', 'tmpbin/%.dvi', function() { ...
146 +// rule('tmpbin/%.dvi', 'tmpsrc/%.tex', ['tmpbin'], function() { ...
147 +task('tmp_cr', [
148 + 'chainrule:init'
149 + , 'chainrule:tmpbin/file1.pdf'
150 + , 'chainrule:tmpbin/file2.pdf' ], function () {
151 + console.log('tmp chainrule namespace task');
152 + let data1 = fs.readFileSync('tmpbin/file1.pdf');
153 + let data2 = fs.readFileSync('tmpbin/file2.pdf');
154 + fs.writeFileSync('tmp_cr', data1 + data2 + ' chainrule namespace');
155 +});
156 +
157 +namespace('chainrule', function () {
158 + task('init', ['tmpsrc', 'tmpbin'], function () {
159 + fs.writeFileSync('tmpsrc/file1.tex', 'tex1 ');
160 + fs.writeFileSync('tmpsrc/file2.tex', 'tex2 ');
161 + console.log('chainrule init task');
162 + });
163 +
164 + rule('tmpbin/%.pdf', 'tmpbin/%.dvi', function () {
165 + let cmd = util.format('cp %s %s', this.source, this.name);
166 + console.log(cmd + ' dvi->pdf task');
167 + exec(cmd);
168 + });
169 +
170 + rule('tmpbin/%.dvi', 'tmpsrc/%.tex', ['tmpbin'], function () {
171 + let cmd = util.format('cp %s %s', this.source, this.name);
172 + console.log(cmd + ' tex->dvi task');
173 + exec(cmd);
174 + });
175 +});
176 +////////////////////////////////////////////////////////////
177 +namespace('precedence', function () {
178 + task('test', ['foo.html'], function () {
179 + console.log('ran test');
180 + });
181 +
182 + rule('.html', '.txt', function () {
183 + console.log('created html');
184 + let data = fs.readFileSync(this.source);
185 + fs.writeFileSync(this.name, data.toString());
186 + });
187 +});
188 +
189 +namespace('regexPattern', function () {
190 + task('test', ['foo.html'], function () {
191 + console.log('ran test');
192 + });
193 +
194 + rule(/\.html$/, '.txt', function () {
195 + console.log('created html');
196 + let data = fs.readFileSync(this.source);
197 + fs.writeFileSync(this.name, data.toString());
198 + });
199 +});
200 +
201 +namespace('sourceFunction', function () {
202 +
203 + let srcFunc = function (taskName) {
204 + return taskName.replace(/\.[^.]+$/, '.txt');
205 + };
206 +
207 + task('test', ['foo.html'], function () {
208 + console.log('ran test');
209 + });
210 +
211 + rule('.html', srcFunc, function () {
212 + console.log('created html');
213 + let data = fs.readFileSync(this.source);
214 + fs.writeFileSync(this.name, data.toString());
215 + });
216 +});
217 +
218 +////////////////////////////////////////////////////////////
219 +task('clean', function () {
220 + rmRf('./foo');
221 + rmRf('./tmp');
222 +});
1 +let assert = require('assert');
2 +let exec = require('child_process').execSync;
3 +
4 +suite('publishTask', function () {
5 +
6 + this.timeout(7000);
7 +
8 + test('default task', function () {
9 + let out = exec('./node_modules/.bin/jake -q publish').toString().trim();
10 + let expected = [
11 + 'Fetched remote tags.'
12 + , 'On branch v0.0'
13 + , 'Bumped version number to v0.0.2.'
14 + , 'Created package for zerb v0.0.2'
15 + , 'Publishing zerb v0.0.2'
16 + , './pkg/zerb-v0.0.2.tar.gz'
17 + , 'BOOM! Published.'
18 + , 'Cleaned up package'
19 + ].join('\n');
20 + assert.equal(expected, out);
21 + });
22 +
23 +});
24 +
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +const PROJECT_DIR = process.env.PROJECT_DIR;
20 +
21 +let assert = require('assert');
22 +let exec = require('child_process').execSync;
23 +let fs = require('fs');
24 +let { Rule } = require(`${PROJECT_DIR}/lib/rule`);
25 +let { rmRf } = require(`${PROJECT_DIR}/lib/jake`);
26 +
27 +let cleanUpAndNext = function (callback) {
28 + // Gotta add globbing to file utils rmRf
29 + let tmpFiles = [
30 + 'tmp'
31 + , 'tmp_ns'
32 + , 'tmp_cr'
33 + , 'tmp_p'
34 + , 'tmp_pf'
35 + , 'tmpbin'
36 + , 'tmpsrc'
37 + , 'tmp_dep1.c'
38 + , 'tmp_dep1.o'
39 + , 'tmp_dep1.oo'
40 + , 'tmp_dep2.c'
41 + , 'tmp_dep2.o'
42 + , 'tmp_dep2.oo'
43 + , 'foo'
44 + , 'foo.html'
45 + ];
46 + tmpFiles.forEach(function (f) {
47 + rmRf(f, {
48 + silent: true
49 + });
50 + });
51 + callback && callback();
52 +};
53 +
54 +suite('rule', function () {
55 +
56 + this.timeout(7000);
57 +
58 + setup(function (next) {
59 + cleanUpAndNext(next);
60 + });
61 +
62 +
63 + // - name foo:bin/main.o
64 + // - pattern bin/%.o
65 + // - source src/%.c
66 + //
67 + // return {
68 + // 'dep' : 'foo:src/main.c',
69 + // 'file': 'src/main.c'
70 + // };
71 + test('Rule.getSource', function () {
72 + let src = Rule.getSource('foo:bin/main.o', 'bin/%.o', 'src/%.c');
73 + assert.equal('foo:src/main.c', src);
74 + });
75 +
76 + test('rule w/o pattern', function () {
77 + let out = exec( './node_modules/.bin/jake -q tmp').toString().trim();
78 + let output = [
79 + "tmp_dep2.c task"
80 + , "tmp_dep1.c task"
81 + , "cp tmp_dep1.c tmp_dep1.o task"
82 + , "cp tmp_dep2.c tmp_dep2.o task"
83 + , "tmp task"];
84 + assert.equal( output.join('\n'), out);
85 + let data = fs.readFileSync(process.cwd() + '/tmp');
86 + assert.equal('src_1src_2', data.toString());
87 + cleanUpAndNext();
88 + });
89 +
90 + test('rule w pattern w/o folder w/o namespace', function () {
91 + let out = exec( './node_modules/.bin/jake -q tmp_p').toString().trim();
92 + let output = [
93 + "tmp_dep2.c task"
94 + , "tmp_dep1.c task"
95 + , "cp tmp_dep1.c tmp_dep1.oo task"
96 + , "cp tmp_dep2.c tmp_dep2.oo task"
97 + , "tmp pattern task"];
98 + let data;
99 + assert.equal( output.join('\n'), out);
100 + data = fs.readFileSync(process.cwd() + '/tmp_p');
101 + assert.equal('src_1src_2 pattern', data.toString());
102 + cleanUpAndNext();
103 + });
104 +
105 + test('rule w pattern w folder w/o namespace', function () {
106 + let out = exec( './node_modules/.bin/jake -q tmp_pf').toString().trim();
107 + let output = [
108 + "tmpsrc/tmp_dep1.c task"
109 + , "cp tmpsrc/tmp_dep1.c tmpbin/tmp_dep1.oo task"
110 + , "tmpsrc/tmp_dep2.c task"
111 + , "cp tmpsrc/tmp_dep2.c tmpbin/tmp_dep2.oo task"
112 + , "tmp pattern folder task"];
113 + let data;
114 + assert.equal( output.join('\n'), out);
115 + data = fs.readFileSync(process.cwd() + '/tmp_pf');
116 + assert.equal('src/src_1src/src_2 pattern folder', data.toString());
117 + cleanUpAndNext();
118 + });
119 +
120 + test.skip('rule w pattern w folder w namespace', function () {
121 + let out = exec( './node_modules/.bin/jake -q tmp_ns').toString().trim();
122 + let output = [
123 + "tmpsrc/file2.c init task" // yes
124 + , "tmpsrc/tmp_dep2.c task" // no
125 + , "cp tmpsrc/tmp_dep2.c tmpbin/tmp_dep2.oo task" // no
126 + , "tmpsrc/dep1.c task" // no
127 + , "cp tmpsrc/dep1.c tmpbin/dep1.oo ns task" // no
128 + , "cp tmpsrc/file2.c tmpbin/file2.oo ns task" // yes
129 + , "tmp pattern folder namespace task"]; // yes
130 + let data;
131 + assert.equal( output.join('\n'), out);
132 + data = fs.readFileSync(process.cwd() + '/tmp_ns');
133 + assert.equal('src/src_1src/src_2src/src_3 pattern folder namespace', data.toString());
134 + cleanUpAndNext();
135 + });
136 +
137 + test.skip('rule w chain w pattern w folder w namespace', function () {
138 + let out = exec( './node_modules/.bin/jake -q tmp_cr').toString().trim();
139 + let output = [
140 + "chainrule init task"
141 + , "cp tmpsrc/file1.tex tmpbin/file1.dvi tex->dvi task"
142 + , "cp tmpbin/file1.dvi tmpbin/file1.pdf dvi->pdf task"
143 + , "cp tmpsrc/file2.tex tmpbin/file2.dvi tex->dvi task"
144 + , "cp tmpbin/file2.dvi tmpbin/file2.pdf dvi->pdf task"
145 + , "tmp chainrule namespace task"];
146 + let data;
147 + assert.equal( output.join('\n'), out);
148 + data = fs.readFileSync(process.cwd() + '/tmp_cr');
149 + assert.equal('tex1 tex2 chainrule namespace', data.toString());
150 + cleanUpAndNext();
151 + });
152 +
153 +
154 + ['precedence', 'regexPattern', 'sourceFunction'].forEach(function (key) {
155 +
156 + test('rule with source file not created yet (' + key + ')', function () {
157 + let write = process.stderr.write;
158 + process.stderr.write = () => {};
159 + rmRf('foo.txt', {silent: true});
160 + rmRf('foo.html', {silent: true});
161 + try {
162 + exec('./node_modules/.bin/jake ' + key + ':test');
163 + }
164 + catch(err) {
165 + // foo.txt prereq doesn't exist yet
166 + assert.ok(err.message.indexOf('Unknown task "foo.html"') > -1);
167 + }
168 + process.stderr.write = write;
169 + });
170 +
171 + test('rule with source file now created (' + key + ')', function () {
172 + fs.writeFileSync('foo.txt', '');
173 + let out = exec('./node_modules/.bin/jake -q ' + key + ':test').toString().trim();
174 + // Should run prereq and test task
175 + let output = [
176 + 'created html'
177 + , 'ran test'
178 + ];
179 + assert.equal(output.join('\n'), out);
180 + });
181 +
182 + test('rule with source file modified (' + key + ')', function (next) {
183 + setTimeout(function () {
184 + fs.writeFileSync('foo.txt', '');
185 + let out = exec('./node_modules/.bin/jake -q ' + key + ':test').toString().trim();
186 + // Should again run both prereq and test task
187 + let output = [
188 + 'created html'
189 + , 'ran test'
190 + ];
191 + assert.equal(output.join('\n'), out);
192 + //next();
193 + cleanUpAndNext(next);
194 + }, 1000); // Wait to do the touch to ensure mod-time is different
195 + });
196 +
197 + test('rule with existing objective file and no source ' +
198 + ' (should be normal file-task) (' + key + ')', function () {
199 + // Remove just the source file
200 + fs.writeFileSync('foo.html', '');
201 + rmRf('foo.txt', {silent: true});
202 + let out = exec('./node_modules/.bin/jake -q ' + key + ':test').toString().trim();
203 + // Should treat existing objective file as plain file-task,
204 + // and just run test-task
205 + let output = [
206 + 'ran test'
207 + ];
208 + assert.equal(output.join('\n'), out);
209 + cleanUpAndNext();
210 + });
211 +
212 + });
213 +
214 +});
215 +
216 +
1 +let assert = require('assert');
2 +let exec = require('child_process').execSync;
3 +
4 +suite('selfDep', function () {
5 +
6 + this.timeout(7000);
7 +
8 + let origStderrWrite;
9 +
10 + setup(function () {
11 + origStderrWrite = process.stderr.write;
12 + process.stderr.write = function () {};
13 + });
14 +
15 + teardown(function () {
16 + process.stderr.write = origStderrWrite;
17 + });
18 +
19 + test('self dep const', function () {
20 + try {
21 + exec('./node_modules/.bin/jake selfdepconst');
22 + }
23 + catch(e) {
24 + assert(e.message.indexOf('dependency of itself') > -1)
25 + }
26 + });
27 +
28 + test('self dep dyn', function () {
29 + try {
30 + exec('./node_modules/.bin/jake selfdepdyn');
31 + }
32 + catch(e) {
33 + assert(e.message.indexOf('dependency of itself') > -1)
34 + }
35 + });
36 +
37 +});
38 +
39 +
1 +let assert = require('assert');
2 +let h = require('./helpers');
3 +let exec = require('child_process').execSync;
4 +
5 +suite('taskBase', function () {
6 +
7 + this.timeout(7000);
8 +
9 + test('default task', function () {
10 + let out;
11 + out = exec('./node_modules/.bin/jake -q').toString().trim();
12 + assert.equal(out, 'default task');
13 + out = exec('./node_modules/.bin/jake -q default').toString().trim();
14 + assert.equal(out, 'default task');
15 + });
16 +
17 + test('task with no action', function () {
18 + let out = exec('./node_modules/.bin/jake -q noAction').toString().trim();
19 + assert.equal(out, 'default task');
20 + });
21 +
22 + test('a task with no action and no prereqs', function () {
23 + exec('./node_modules/.bin/jake noActionNoPrereqs');
24 + });
25 +
26 + test('a task that exists at the top-level, and not in the specified namespace, should error', function () {
27 + let res = require('child_process').spawnSync('./node_modules/.bin/jake',
28 + ['asdfasdfasdf:zerbofrangazoomy']);
29 + let err = res.stderr.toString();
30 + assert.ok(err.indexOf('Unknown task' > -1));
31 + });
32 +
33 + test('passing args to a task', function () {
34 + let out = exec('./node_modules/.bin/jake -q argsEnvVars[foo,bar]').toString().trim();
35 + let parsed = h.parse(out);
36 + let args = parsed.args;
37 + assert.equal(args[0], 'foo');
38 + assert.equal(args[1], 'bar');
39 + });
40 +
41 + test('a task with environment vars', function () {
42 + let out = exec('./node_modules/.bin/jake -q argsEnvVars foo=bar baz=qux').toString().trim();
43 + let parsed = h.parse(out);
44 + let env = parsed.env;
45 + assert.equal(env.foo, 'bar');
46 + assert.equal(env.baz, 'qux');
47 + });
48 +
49 + test('passing args and using environment vars', function () {
50 + let out = exec('./node_modules/.bin/jake -q argsEnvVars[foo,bar] foo=bar baz=qux').toString().trim();
51 + let parsed = h.parse(out);
52 + let args = parsed.args;
53 + let env = parsed.env;
54 + assert.equal(args[0], 'foo');
55 + assert.equal(args[1], 'bar');
56 + assert.equal(env.foo, 'bar');
57 + assert.equal(env.baz, 'qux');
58 + });
59 +
60 + test('a simple prereq', function () {
61 + let out = exec('./node_modules/.bin/jake -q foo:baz').toString().trim();
62 + assert.equal(out, 'foo:bar task\nfoo:baz task');
63 + });
64 +
65 + test('a duplicate prereq only runs once', function () {
66 + let out = exec('./node_modules/.bin/jake -q foo:asdf').toString().trim();
67 + assert.equal(out, 'foo:bar task\nfoo:baz task\nfoo:asdf task');
68 + });
69 +
70 + test('a prereq with command-line args', function () {
71 + let out = exec('./node_modules/.bin/jake -q foo:qux').toString().trim();
72 + assert.equal(out, 'foo:bar[asdf,qwer] task\nfoo:qux task');
73 + });
74 +
75 + test('a prereq with args via invoke', function () {
76 + let out = exec('./node_modules/.bin/jake -q foo:frang[zxcv,uiop]').toString().trim();
77 + assert.equal(out, 'foo:bar[zxcv,uiop] task\nfoo:frang task');
78 + });
79 +
80 + test('a prereq with args via execute', function () {
81 + let out = exec('./node_modules/.bin/jake -q foo:zerb[zxcv,uiop]').toString().trim();
82 + assert.equal(out, 'foo:bar[zxcv,uiop] task\nfoo:zerb task');
83 + });
84 +
85 + test('repeating the task via execute', function () {
86 + let out = exec('./node_modules/.bin/jake -q foo:voom').toString().trim();
87 + assert.equal(out, 'foo:bar task\nfoo:bar task\ncomplete\ncomplete');
88 + });
89 +
90 + test('prereq execution-order', function () {
91 + let out = exec('./node_modules/.bin/jake -q hoge:fuga').toString().trim();
92 + assert.equal(out, 'hoge:hoge task\nhoge:piyo task\nhoge:fuga task');
93 + });
94 +
95 + test('basic async task', function () {
96 + let out = exec('./node_modules/.bin/jake -q bar:bar').toString().trim();
97 + assert.equal(out, 'bar:foo task\nbar:bar task');
98 + });
99 +
100 + test('promise async task', function () {
101 + let out = exec('./node_modules/.bin/jake -q bar:dependOnpromise').toString().trim();
102 + assert.equal(out, 'bar:promise task\nbar:dependOnpromise task saw value 123654');
103 + });
104 +
105 + test('failing promise async task', function () {
106 + try {
107 + exec('./node_modules/.bin/jake -q bar:brokenPromise');
108 + }
109 + catch(e) {
110 + assert(e.message.indexOf('Command failed') > -1);
111 + }
112 + });
113 +
114 + test('that current-prereq index gets reset', function () {
115 + let out = exec('./node_modules/.bin/jake -q hoge:kira').toString().trim();
116 + assert.equal(out, 'hoge:hoge task\nhoge:piyo task\nhoge:fuga task\n' +
117 + 'hoge:charan task\nhoge:gero task\nhoge:kira task');
118 + });
119 +
120 + test('modifying a task by adding prereq during execution', function () {
121 + let out = exec('./node_modules/.bin/jake -q voom').toString().trim();
122 + assert.equal(out, 2);
123 + });
124 +
125 + test('listening for task error-event', function () {
126 + try {
127 + exec('./node_modules/.bin/jake -q vronk:groo').toString().trim();
128 + }
129 + catch(e) {
130 + assert(e.message.indexOf('OMFGZONG') > -1);
131 + }
132 + });
133 +
134 + test('listening for jake error-event', function () {
135 + let out = exec('./node_modules/.bin/jake -q throwy').toString().trim();
136 + assert(out.indexOf('Emitted\nError: I am bad') > -1);
137 + });
138 +
139 + test('listening for jake unhandledRejection-event', function () {
140 + let out = exec('./node_modules/.bin/jake -q promiseRejecter').toString().trim();
141 + assert.equal(out, '<promise rejected on purpose>');
142 + });
143 +
144 + test('large number of same prereqs', function () {
145 + let out = exec('./node_modules/.bin/jake -q large:same').toString().trim();
146 + assert.equal(out, 'large:leaf\nlarge:same');
147 + });
148 +
149 + test('large number of different prereqs', function () {
150 + let out = exec('./node_modules/.bin/jake -q large:different').toString().trim();
151 + assert.equal(out, 'leaf-12\nleaf-123\nlarge:different');
152 + });
153 +
154 + test('large number of different prereqs', function () {
155 + let out = exec('./node_modules/.bin/jake -q usingRequire:test').toString().trim();
156 + assert.equal(out, 'howdy test');
157 + });
158 +
159 + test('modifying a namespace by adding a new task', function () {
160 + let out = exec('./node_modules/.bin/jake -q one:two').toString().trim();
161 + assert.equal('one:one\none:two', out);
162 + });
163 +
164 +});
1 +
2 +task('foo', function () {
3 + console.log('ran top-level foo');
4 +});
5 +
6 +task('bar', function () {
7 + console.log('ran top-level bar');
8 +});
9 +
10 +task('zerb', function () {
11 + console.log('ran zerb');
12 +});
13 +
14 +namespace('zooby', function () {
15 + task('zerp', function () {});
16 +
17 + task('derp', ['zerp'], function () {});
18 +
19 + namespace('frang', function () {
20 +
21 + namespace('w00t', function () {
22 + task('bar', function () {
23 + console.log('ran zooby:frang:w00t:bar');
24 + });
25 + });
26 +
27 + task('asdf', function () {});
28 + });
29 +
30 +});
31 +
32 +namespace('hurr', function () {
33 + namespace('durr');
34 +});
35 +
36 +
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +const PROJECT_DIR = process.env.PROJECT_DIR;
20 +
21 +// Load the jake global
22 +require(`${PROJECT_DIR}/lib/jake`);
23 +let { Namespace } = require(`${PROJECT_DIR}/lib/namespace`);
24 +
25 +require('./jakefile');
26 +
27 +let assert = require('assert');
28 +
29 +suite('namespace', function () {
30 +
31 + this.timeout(7000);
32 +
33 + test('resolve namespace by relative name', function () {
34 + let aaa, bbb, ccc;
35 + aaa = namespace('aaa', function () {
36 + bbb = namespace('bbb', function () {
37 + ccc = namespace('ccc', function () {
38 + });
39 + });
40 + });
41 +
42 + assert.ok(aaa, Namespace.ROOT_NAMESPACE.resolveNamespace('aaa'));
43 + assert.ok(bbb === aaa.resolveNamespace('bbb'));
44 + assert.ok(ccc === aaa.resolveNamespace('bbb:ccc'));
45 + });
46 +
47 + test('resolve task in sub-namespace by relative path', function () {
48 + let curr = Namespace.ROOT_NAMESPACE.resolveNamespace('zooby');
49 + let task = curr.resolveTask('frang:w00t:bar');
50 + assert.ok(task.action.toString().indexOf('zooby:frang:w00t:bar') > -1);
51 + });
52 +
53 + test('prefer local to top-level', function () {
54 + let curr = Namespace.ROOT_NAMESPACE.resolveNamespace('zooby:frang:w00t');
55 + let task = curr.resolveTask('bar');
56 + assert.ok(task.action.toString().indexOf('zooby:frang:w00t:bar') > -1);
57 + });
58 +
59 + test('does resolve top-level', function () {
60 + let curr = Namespace.ROOT_NAMESPACE.resolveNamespace('zooby:frang:w00t');
61 + let task = curr.resolveTask('foo');
62 + assert.ok(task.action.toString().indexOf('top-level foo') > -1);
63 + });
64 +
65 + test('absolute lookup works from sub-namespaces', function () {
66 + let curr = Namespace.ROOT_NAMESPACE.resolveNamespace('hurr:durr');
67 + let task = curr.resolveTask('zooby:frang:w00t:bar');
68 + assert.ok(task.action.toString().indexOf('zooby:frang:w00t:bar') > -1);
69 + });
70 +
71 + test('resolution miss with throw error', function () {
72 + let curr = Namespace.ROOT_NAMESPACE;
73 + let task = curr.resolveTask('asdf:qwer');
74 + assert.ok(!task);
75 + });
76 +
77 +});
1 +/*
2 + * Jake JavaScript build tool
3 + * Copyright 2112 Matthew Eernisse (mde@fleegix.org)
4 + *
5 + * Licensed under the Apache License, Version 2.0 (the "License");
6 + * you may not use this file except in compliance with the License.
7 + * You may obtain a copy of the License at
8 + *
9 + * http://www.apache.org/licenses/LICENSE-2.0
10 + *
11 + * Unless required by applicable law or agreed to in writing, software
12 + * distributed under the License is distributed on an "AS IS" BASIS,
13 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + * See the License for the specific language governing permissions and
15 + * limitations under the License.
16 + *
17 +*/
18 +
19 +const PROJECT_DIR = process.env.PROJECT_DIR;
20 +
21 +let parseargs = require(`${PROJECT_DIR}/lib/parseargs`);
22 +let assert = require('assert');
23 +let optsReg = [
24 + { full: 'directory',
25 + abbr: 'C',
26 + preempts: false,
27 + expectValue: true
28 + },
29 + { full: 'jakefile',
30 + abbr: 'f',
31 + preempts: false,
32 + expectValue: true
33 + },
34 + { full: 'tasks',
35 + abbr: 'T',
36 + preempts: true
37 + },
38 + { full: 'tasks',
39 + abbr: 'ls',
40 + preempts: true
41 + },
42 + { full: 'trace',
43 + abbr: 't',
44 + preempts: false,
45 + expectValue: false
46 + },
47 + { full: 'help',
48 + abbr: 'h',
49 + preempts: true
50 + },
51 + { full: 'version',
52 + abbr: 'V',
53 + preempts: true
54 + }
55 +];
56 +let p = new parseargs.Parser(optsReg);
57 +let z = function (s) { return s.split(' '); };
58 +let res;
59 +
60 +suite('parseargs', function () {
61 +
62 + test('long preemptive opt and val with equal-sign, ignore further opts', function () {
63 + res = p.parse(z('--tasks=foo --jakefile=asdf'));
64 + assert.equal('foo', res.opts.tasks);
65 + assert.equal(undefined, res.opts.jakefile);
66 + });
67 +
68 + test('long preemptive opt and val without equal-sign, ignore further opts', function () {
69 + res = p.parse(z('--tasks foo --jakefile=asdf'));
70 + assert.equal('foo', res.opts.tasks);
71 + assert.equal(undefined, res.opts.jakefile);
72 + });
73 +
74 + test('long preemptive opt and no val, ignore further opts', function () {
75 + res = p.parse(z('--tasks --jakefile=asdf'));
76 + assert.equal(true, res.opts.tasks);
77 + assert.equal(undefined, res.opts.jakefile);
78 + });
79 +
80 + test('preemptive opt with no val, should be true', function () {
81 + res = p.parse(z('-T'));
82 + assert.equal(true, res.opts.tasks);
83 + });
84 +
85 + test('preemptive opt with no val, should be true and ignore further opts', function () {
86 + res = p.parse(z('-T -f'));
87 + assert.equal(true, res.opts.tasks);
88 + assert.equal(undefined, res.opts.jakefile);
89 + });
90 +
91 + test('preemptive opt with val, should be val', function () {
92 + res = p.parse(z('-T zoobie -f foo/bar/baz'));
93 + assert.equal('zoobie', res.opts.tasks);
94 + assert.equal(undefined, res.opts.jakefile);
95 + });
96 +
97 + test('-f expects a value, -t does not (howdy is task-name)', function () {
98 + res = p.parse(z('-f zoobie -t howdy'));
99 + assert.equal('zoobie', res.opts.jakefile);
100 + assert.equal(true, res.opts.trace);
101 + assert.equal('howdy', res.taskNames[0]);
102 + });
103 +
104 + test('different order, -f expects a value, -t does not (howdy is task-name)', function () {
105 + res = p.parse(z('-f zoobie howdy -t'));
106 + assert.equal('zoobie', res.opts.jakefile);
107 + assert.equal(true, res.opts.trace);
108 + assert.equal('howdy', res.taskNames[0]);
109 + });
110 +
111 + test('-f expects a value, -t does not (foo=bar is env var)', function () {
112 + res = p.parse(z('-f zoobie -t foo=bar'));
113 + assert.equal('zoobie', res.opts.jakefile);
114 + assert.equal(true, res.opts.trace);
115 + assert.equal('bar', res.envVars.foo);
116 + assert.equal(undefined, res.taskNames[0]);
117 + });
118 +
119 + test('-f expects a value, -t does not (foo=bar is env-var, task-name follows)', function () {
120 + res = p.parse(z('-f zoobie -t howdy foo=bar'));
121 + assert.equal('zoobie', res.opts.jakefile);
122 + assert.equal(true, res.opts.trace);
123 + assert.equal('bar', res.envVars.foo);
124 + assert.equal('howdy', res.taskNames[0]);
125 + });
126 +
127 + test('-t does not expect a value, -f does (howdy is task-name)', function () {
128 + res = p.parse(z('-t howdy -f zoobie'));
129 + assert.equal(true, res.opts.trace);
130 + assert.equal('zoobie', res.opts.jakefile);
131 + assert.equal('howdy', res.taskNames[0]);
132 + });
133 +
134 + test('--trace does not expect a value, -f does (howdy is task-name)', function () {
135 + res = p.parse(z('--trace howdy --jakefile zoobie'));
136 + assert.equal(true, res.opts.trace);
137 + assert.equal('zoobie', res.opts.jakefile);
138 + assert.equal('howdy', res.taskNames[0]);
139 + });
140 +
141 + test('--trace does not expect a value (equal), -f does (throw howdy away)', function () {
142 + res = p.parse(z('--trace=howdy --jakefile=zoobie'));
143 + assert.equal(true, res.opts.trace);
144 + assert.equal('zoobie', res.opts.jakefile);
145 + assert.equal(undefined, res.taskNames[0]);
146 + });
147 +
148 + /*
149 +, test('task-name with positional args', function () {
150 + res = p.parse(z('foo:bar[asdf,qwer]'));
151 + assert.equal('asdf', p.taskArgs[0]);
152 + assert.equal('qwer', p.taskArgs[1]);
153 + }
154 +
155 +, test('opts, env vars, task-name with positional args', function () {
156 + res = p.parse(z('-f ./tests/Jakefile -t default[asdf,qwer] foo=bar'));
157 + assert.equal('./tests/Jakefile', res.opts.jakefile);
158 + assert.equal(true, res.opts.trace);
159 + assert.equal('bar', res.envVars.foo);
160 + assert.equal('default', res.taskName);
161 + assert.equal('asdf', p.taskArgs[0]);
162 + assert.equal('qwer', p.taskArgs[1]);
163 + }
164 +*/
165 +
166 +
167 +});
168 +
169 +
1 +Jake JavaScript build tool
2 +********************************************************************************
3 +If no flags are given, Jake looks for a Jakefile or Jakefile.js in the current directory.
4 +********************************************************************************
5 +{Usage}: jake [options ...] [env variables ...] target
6 +
7 +{Options}:
8 + -f, --jakefile FILE Use FILE as the Jakefile.
9 + -C, --directory DIRECTORY Change to DIRECTORY before running tasks.
10 + -B, --always-make Unconditionally make all targets.
11 + -T/ls, --tasks Display the tasks (matching optional PATTERN) with descriptions, then exit.
12 + -J, --jakelibdir JAKELIBDIR Auto-import any .jake files in JAKELIBDIR. (default is \'jakelib\')
13 + -h, --help Display this help message.
14 + -V/v, --version Display the Jake version.
15 + -ar, --allow-rejection Keep running even after unhandled promise rejection
16 +
1 +The ISC License
2 +
3 +Copyright (c) Isaac Z. Schlueter and Contributors
4 +
5 +Permission to use, copy, modify, and/or distribute this software for any
6 +purpose with or without fee is hereby granted, provided that the above
7 +copyright notice and this permission notice appear in all copies.
8 +
9 +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
15 +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1 +# minimatch
2 +
3 +A minimal matching utility.
4 +
5 +[![Build Status](https://secure.travis-ci.org/isaacs/minimatch.svg)](http://travis-ci.org/isaacs/minimatch)
6 +
7 +
8 +This is the matching library used internally by npm.
9 +
10 +It works by converting glob expressions into JavaScript `RegExp`
11 +objects.
12 +
13 +## Usage
14 +
15 +```javascript
16 +var minimatch = require("minimatch")
17 +
18 +minimatch("bar.foo", "*.foo") // true!
19 +minimatch("bar.foo", "*.bar") // false!
20 +minimatch("bar.foo", "*.+(bar|foo)", { debug: true }) // true, and noisy!
21 +```
22 +
23 +## Features
24 +
25 +Supports these glob features:
26 +
27 +* Brace Expansion
28 +* Extended glob matching
29 +* "Globstar" `**` matching
30 +
31 +See:
32 +
33 +* `man sh`
34 +* `man bash`
35 +* `man 3 fnmatch`
36 +* `man 5 gitignore`
37 +
38 +## Minimatch Class
39 +
40 +Create a minimatch object by instantiating the `minimatch.Minimatch` class.
41 +
42 +```javascript
43 +var Minimatch = require("minimatch").Minimatch
44 +var mm = new Minimatch(pattern, options)
45 +```
46 +
47 +### Properties
48 +
49 +* `pattern` The original pattern the minimatch object represents.
50 +* `options` The options supplied to the constructor.
51 +* `set` A 2-dimensional array of regexp or string expressions.
52 + Each row in the
53 + array corresponds to a brace-expanded pattern. Each item in the row
54 + corresponds to a single path-part. For example, the pattern
55 + `{a,b/c}/d` would expand to a set of patterns like:
56 +
57 + [ [ a, d ]
58 + , [ b, c, d ] ]
59 +
60 + If a portion of the pattern doesn't have any "magic" in it
61 + (that is, it's something like `"foo"` rather than `fo*o?`), then it
62 + will be left as a string rather than converted to a regular
63 + expression.
64 +
65 +* `regexp` Created by the `makeRe` method. A single regular expression
66 + expressing the entire pattern. This is useful in cases where you wish
67 + to use the pattern somewhat like `fnmatch(3)` with `FNM_PATH` enabled.
68 +* `negate` True if the pattern is negated.
69 +* `comment` True if the pattern is a comment.
70 +* `empty` True if the pattern is `""`.
71 +
72 +### Methods
73 +
74 +* `makeRe` Generate the `regexp` member if necessary, and return it.
75 + Will return `false` if the pattern is invalid.
76 +* `match(fname)` Return true if the filename matches the pattern, or
77 + false otherwise.
78 +* `matchOne(fileArray, patternArray, partial)` Take a `/`-split
79 + filename, and match it against a single row in the `regExpSet`. This
80 + method is mainly for internal use, but is exposed so that it can be
81 + used by a glob-walker that needs to avoid excessive filesystem calls.
82 +
83 +All other methods are internal, and will be called as necessary.
84 +
85 +### minimatch(path, pattern, options)
86 +
87 +Main export. Tests a path against the pattern using the options.
88 +
89 +```javascript
90 +var isJS = minimatch(file, "*.js", { matchBase: true })
91 +```
92 +
93 +### minimatch.filter(pattern, options)
94 +
95 +Returns a function that tests its
96 +supplied argument, suitable for use with `Array.filter`. Example:
97 +
98 +```javascript
99 +var javascripts = fileList.filter(minimatch.filter("*.js", {matchBase: true}))
100 +```
101 +
102 +### minimatch.match(list, pattern, options)
103 +
104 +Match against the list of
105 +files, in the style of fnmatch or glob. If nothing is matched, and
106 +options.nonull is set, then return a list containing the pattern itself.
107 +
108 +```javascript
109 +var javascripts = minimatch.match(fileList, "*.js", {matchBase: true}))
110 +```
111 +
112 +### minimatch.makeRe(pattern, options)
113 +
114 +Make a regular expression object from the pattern.
115 +
116 +## Options
117 +
118 +All options are `false` by default.
119 +
120 +### debug
121 +
122 +Dump a ton of stuff to stderr.
123 +
124 +### nobrace
125 +
126 +Do not expand `{a,b}` and `{1..3}` brace sets.
127 +
128 +### noglobstar
129 +
130 +Disable `**` matching against multiple folder names.
131 +
132 +### dot
133 +
134 +Allow patterns to match filenames starting with a period, even if
135 +the pattern does not explicitly have a period in that spot.
136 +
137 +Note that by default, `a/**/b` will **not** match `a/.d/b`, unless `dot`
138 +is set.
139 +
140 +### noext
141 +
142 +Disable "extglob" style patterns like `+(a|b)`.
143 +
144 +### nocase
145 +
146 +Perform a case-insensitive match.
147 +
148 +### nonull
149 +
150 +When a match is not found by `minimatch.match`, return a list containing
151 +the pattern itself if this option is set. When not set, an empty list
152 +is returned if there are no matches.
153 +
154 +### matchBase
155 +
156 +If set, then patterns without slashes will be matched
157 +against the basename of the path if it contains slashes. For example,
158 +`a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`.
159 +
160 +### nocomment
161 +
162 +Suppress the behavior of treating `#` at the start of a pattern as a
163 +comment.
164 +
165 +### nonegate
166 +
167 +Suppress the behavior of treating a leading `!` character as negation.
168 +
169 +### flipNegate
170 +
171 +Returns from negate expressions the same as if they were not negated.
172 +(Ie, true on a hit, false on a miss.)
173 +
174 +
175 +## Comparisons to other fnmatch/glob implementations
176 +
177 +While strict compliance with the existing standards is a worthwhile
178 +goal, some discrepancies exist between minimatch and other
179 +implementations, and are intentional.
180 +
181 +If the pattern starts with a `!` character, then it is negated. Set the
182 +`nonegate` flag to suppress this behavior, and treat leading `!`
183 +characters normally. This is perhaps relevant if you wish to start the
184 +pattern with a negative extglob pattern like `!(a|B)`. Multiple `!`
185 +characters at the start of a pattern will negate the pattern multiple
186 +times.
187 +
188 +If a pattern starts with `#`, then it is treated as a comment, and
189 +will not match anything. Use `\#` to match a literal `#` at the
190 +start of a line, or set the `nocomment` flag to suppress this behavior.
191 +
192 +The double-star character `**` is supported by default, unless the
193 +`noglobstar` flag is set. This is supported in the manner of bsdglob
194 +and bash 4.1, where `**` only has special significance if it is the only
195 +thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but
196 +`a/**b` will not.
197 +
198 +If an escaped pattern has no matches, and the `nonull` flag is set,
199 +then minimatch.match returns the pattern as-provided, rather than
200 +interpreting the character escapes. For example,
201 +`minimatch.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than
202 +`"*a?"`. This is akin to setting the `nullglob` option in bash, except
203 +that it does not resolve escaped pattern characters.
204 +
205 +If brace expansion is not disabled, then it is performed before any
206 +other interpretation of the glob pattern. Thus, a pattern like
207 +`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded
208 +**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are
209 +checked for validity. Since those two are valid, matching proceeds.
1 +module.exports = minimatch
2 +minimatch.Minimatch = Minimatch
3 +
4 +var path = { sep: '/' }
5 +try {
6 + path = require('path')
7 +} catch (er) {}
8 +
9 +var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {}
10 +var expand = require('brace-expansion')
11 +
12 +var plTypes = {
13 + '!': { open: '(?:(?!(?:', close: '))[^/]*?)'},
14 + '?': { open: '(?:', close: ')?' },
15 + '+': { open: '(?:', close: ')+' },
16 + '*': { open: '(?:', close: ')*' },
17 + '@': { open: '(?:', close: ')' }
18 +}
19 +
20 +// any single thing other than /
21 +// don't need to escape / when using new RegExp()
22 +var qmark = '[^/]'
23 +
24 +// * => any number of characters
25 +var star = qmark + '*?'
26 +
27 +// ** when dots are allowed. Anything goes, except .. and .
28 +// not (^ or / followed by one or two dots followed by $ or /),
29 +// followed by anything, any number of times.
30 +var twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?'
31 +
32 +// not a ^ or / followed by a dot,
33 +// followed by anything, any number of times.
34 +var twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?'
35 +
36 +// characters that need to be escaped in RegExp.
37 +var reSpecials = charSet('().*{}+?[]^$\\!')
38 +
39 +// "abc" -> { a:true, b:true, c:true }
40 +function charSet (s) {
41 + return s.split('').reduce(function (set, c) {
42 + set[c] = true
43 + return set
44 + }, {})
45 +}
46 +
47 +// normalizes slashes.
48 +var slashSplit = /\/+/
49 +
50 +minimatch.filter = filter
51 +function filter (pattern, options) {
52 + options = options || {}
53 + return function (p, i, list) {
54 + return minimatch(p, pattern, options)
55 + }
56 +}
57 +
58 +function ext (a, b) {
59 + a = a || {}
60 + b = b || {}
61 + var t = {}
62 + Object.keys(b).forEach(function (k) {
63 + t[k] = b[k]
64 + })
65 + Object.keys(a).forEach(function (k) {
66 + t[k] = a[k]
67 + })
68 + return t
69 +}
70 +
71 +minimatch.defaults = function (def) {
72 + if (!def || !Object.keys(def).length) return minimatch
73 +
74 + var orig = minimatch
75 +
76 + var m = function minimatch (p, pattern, options) {
77 + return orig.minimatch(p, pattern, ext(def, options))
78 + }
79 +
80 + m.Minimatch = function Minimatch (pattern, options) {
81 + return new orig.Minimatch(pattern, ext(def, options))
82 + }
83 +
84 + return m
85 +}
86 +
87 +Minimatch.defaults = function (def) {
88 + if (!def || !Object.keys(def).length) return Minimatch
89 + return minimatch.defaults(def).Minimatch
90 +}
91 +
92 +function minimatch (p, pattern, options) {
93 + if (typeof pattern !== 'string') {
94 + throw new TypeError('glob pattern string required')
95 + }
96 +
97 + if (!options) options = {}
98 +
99 + // shortcut: comments match nothing.
100 + if (!options.nocomment && pattern.charAt(0) === '#') {
101 + return false
102 + }
103 +
104 + // "" only matches ""
105 + if (pattern.trim() === '') return p === ''
106 +
107 + return new Minimatch(pattern, options).match(p)
108 +}
109 +
110 +function Minimatch (pattern, options) {
111 + if (!(this instanceof Minimatch)) {
112 + return new Minimatch(pattern, options)
113 + }
114 +
115 + if (typeof pattern !== 'string') {
116 + throw new TypeError('glob pattern string required')
117 + }
118 +
119 + if (!options) options = {}
120 + pattern = pattern.trim()
121 +
122 + // windows support: need to use /, not \
123 + if (path.sep !== '/') {
124 + pattern = pattern.split(path.sep).join('/')
125 + }
126 +
127 + this.options = options
128 + this.set = []
129 + this.pattern = pattern
130 + this.regexp = null
131 + this.negate = false
132 + this.comment = false
133 + this.empty = false
134 +
135 + // make the set of regexps etc.
136 + this.make()
137 +}
138 +
139 +Minimatch.prototype.debug = function () {}
140 +
141 +Minimatch.prototype.make = make
142 +function make () {
143 + // don't do it more than once.
144 + if (this._made) return
145 +
146 + var pattern = this.pattern
147 + var options = this.options
148 +
149 + // empty patterns and comments match nothing.
150 + if (!options.nocomment && pattern.charAt(0) === '#') {
151 + this.comment = true
152 + return
153 + }
154 + if (!pattern) {
155 + this.empty = true
156 + return
157 + }
158 +
159 + // step 1: figure out negation, etc.
160 + this.parseNegate()
161 +
162 + // step 2: expand braces
163 + var set = this.globSet = this.braceExpand()
164 +
165 + if (options.debug) this.debug = console.error
166 +
167 + this.debug(this.pattern, set)
168 +
169 + // step 3: now we have a set, so turn each one into a series of path-portion
170 + // matching patterns.
171 + // These will be regexps, except in the case of "**", which is
172 + // set to the GLOBSTAR object for globstar behavior,
173 + // and will not contain any / characters
174 + set = this.globParts = set.map(function (s) {
175 + return s.split(slashSplit)
176 + })
177 +
178 + this.debug(this.pattern, set)
179 +
180 + // glob --> regexps
181 + set = set.map(function (s, si, set) {
182 + return s.map(this.parse, this)
183 + }, this)
184 +
185 + this.debug(this.pattern, set)
186 +
187 + // filter out everything that didn't compile properly.
188 + set = set.filter(function (s) {
189 + return s.indexOf(false) === -1
190 + })
191 +
192 + this.debug(this.pattern, set)
193 +
194 + this.set = set
195 +}
196 +
197 +Minimatch.prototype.parseNegate = parseNegate
198 +function parseNegate () {
199 + var pattern = this.pattern
200 + var negate = false
201 + var options = this.options
202 + var negateOffset = 0
203 +
204 + if (options.nonegate) return
205 +
206 + for (var i = 0, l = pattern.length
207 + ; i < l && pattern.charAt(i) === '!'
208 + ; i++) {
209 + negate = !negate
210 + negateOffset++
211 + }
212 +
213 + if (negateOffset) this.pattern = pattern.substr(negateOffset)
214 + this.negate = negate
215 +}
216 +
217 +// Brace expansion:
218 +// a{b,c}d -> abd acd
219 +// a{b,}c -> abc ac
220 +// a{0..3}d -> a0d a1d a2d a3d
221 +// a{b,c{d,e}f}g -> abg acdfg acefg
222 +// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg
223 +//
224 +// Invalid sets are not expanded.
225 +// a{2..}b -> a{2..}b
226 +// a{b}c -> a{b}c
227 +minimatch.braceExpand = function (pattern, options) {
228 + return braceExpand(pattern, options)
229 +}
230 +
231 +Minimatch.prototype.braceExpand = braceExpand
232 +
233 +function braceExpand (pattern, options) {
234 + if (!options) {
235 + if (this instanceof Minimatch) {
236 + options = this.options
237 + } else {
238 + options = {}
239 + }
240 + }
241 +
242 + pattern = typeof pattern === 'undefined'
243 + ? this.pattern : pattern
244 +
245 + if (typeof pattern === 'undefined') {
246 + throw new TypeError('undefined pattern')
247 + }
248 +
249 + if (options.nobrace ||
250 + !pattern.match(/\{.*\}/)) {
251 + // shortcut. no need to expand.
252 + return [pattern]
253 + }
254 +
255 + return expand(pattern)
256 +}
257 +
258 +// parse a component of the expanded set.
259 +// At this point, no pattern may contain "/" in it
260 +// so we're going to return a 2d array, where each entry is the full
261 +// pattern, split on '/', and then turned into a regular expression.
262 +// A regexp is made at the end which joins each array with an
263 +// escaped /, and another full one which joins each regexp with |.
264 +//
265 +// Following the lead of Bash 4.1, note that "**" only has special meaning
266 +// when it is the *only* thing in a path portion. Otherwise, any series
267 +// of * is equivalent to a single *. Globstar behavior is enabled by
268 +// default, and can be disabled by setting options.noglobstar.
269 +Minimatch.prototype.parse = parse
270 +var SUBPARSE = {}
271 +function parse (pattern, isSub) {
272 + if (pattern.length > 1024 * 64) {
273 + throw new TypeError('pattern is too long')
274 + }
275 +
276 + var options = this.options
277 +
278 + // shortcuts
279 + if (!options.noglobstar && pattern === '**') return GLOBSTAR
280 + if (pattern === '') return ''
281 +
282 + var re = ''
283 + var hasMagic = !!options.nocase
284 + var escaping = false
285 + // ? => one single character
286 + var patternListStack = []
287 + var negativeLists = []
288 + var stateChar
289 + var inClass = false
290 + var reClassStart = -1
291 + var classStart = -1
292 + // . and .. never match anything that doesn't start with .,
293 + // even when options.dot is set.
294 + var patternStart = pattern.charAt(0) === '.' ? '' // anything
295 + // not (start or / followed by . or .. followed by / or end)
296 + : options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))'
297 + : '(?!\\.)'
298 + var self = this
299 +
300 + function clearStateChar () {
301 + if (stateChar) {
302 + // we had some state-tracking character
303 + // that wasn't consumed by this pass.
304 + switch (stateChar) {
305 + case '*':
306 + re += star
307 + hasMagic = true
308 + break
309 + case '?':
310 + re += qmark
311 + hasMagic = true
312 + break
313 + default:
314 + re += '\\' + stateChar
315 + break
316 + }
317 + self.debug('clearStateChar %j %j', stateChar, re)
318 + stateChar = false
319 + }
320 + }
321 +
322 + for (var i = 0, len = pattern.length, c
323 + ; (i < len) && (c = pattern.charAt(i))
324 + ; i++) {
325 + this.debug('%s\t%s %s %j', pattern, i, re, c)
326 +
327 + // skip over any that are escaped.
328 + if (escaping && reSpecials[c]) {
329 + re += '\\' + c
330 + escaping = false
331 + continue
332 + }
333 +
334 + switch (c) {
335 + case '/':
336 + // completely not allowed, even escaped.
337 + // Should already be path-split by now.
338 + return false
339 +
340 + case '\\':
341 + clearStateChar()
342 + escaping = true
343 + continue
344 +
345 + // the various stateChar values
346 + // for the "extglob" stuff.
347 + case '?':
348 + case '*':
349 + case '+':
350 + case '@':
351 + case '!':
352 + this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c)
353 +
354 + // all of those are literals inside a class, except that
355 + // the glob [!a] means [^a] in regexp
356 + if (inClass) {
357 + this.debug(' in class')
358 + if (c === '!' && i === classStart + 1) c = '^'
359 + re += c
360 + continue
361 + }
362 +
363 + // if we already have a stateChar, then it means
364 + // that there was something like ** or +? in there.
365 + // Handle the stateChar, then proceed with this one.
366 + self.debug('call clearStateChar %j', stateChar)
367 + clearStateChar()
368 + stateChar = c
369 + // if extglob is disabled, then +(asdf|foo) isn't a thing.
370 + // just clear the statechar *now*, rather than even diving into
371 + // the patternList stuff.
372 + if (options.noext) clearStateChar()
373 + continue
374 +
375 + case '(':
376 + if (inClass) {
377 + re += '('
378 + continue
379 + }
380 +
381 + if (!stateChar) {
382 + re += '\\('
383 + continue
384 + }
385 +
386 + patternListStack.push({
387 + type: stateChar,
388 + start: i - 1,
389 + reStart: re.length,
390 + open: plTypes[stateChar].open,
391 + close: plTypes[stateChar].close
392 + })
393 + // negation is (?:(?!js)[^/]*)
394 + re += stateChar === '!' ? '(?:(?!(?:' : '(?:'
395 + this.debug('plType %j %j', stateChar, re)
396 + stateChar = false
397 + continue
398 +
399 + case ')':
400 + if (inClass || !patternListStack.length) {
401 + re += '\\)'
402 + continue
403 + }
404 +
405 + clearStateChar()
406 + hasMagic = true
407 + var pl = patternListStack.pop()
408 + // negation is (?:(?!js)[^/]*)
409 + // The others are (?:<pattern>)<type>
410 + re += pl.close
411 + if (pl.type === '!') {
412 + negativeLists.push(pl)
413 + }
414 + pl.reEnd = re.length
415 + continue
416 +
417 + case '|':
418 + if (inClass || !patternListStack.length || escaping) {
419 + re += '\\|'
420 + escaping = false
421 + continue
422 + }
423 +
424 + clearStateChar()
425 + re += '|'
426 + continue
427 +
428 + // these are mostly the same in regexp and glob
429 + case '[':
430 + // swallow any state-tracking char before the [
431 + clearStateChar()
432 +
433 + if (inClass) {
434 + re += '\\' + c
435 + continue
436 + }
437 +
438 + inClass = true
439 + classStart = i
440 + reClassStart = re.length
441 + re += c
442 + continue
443 +
444 + case ']':
445 + // a right bracket shall lose its special
446 + // meaning and represent itself in
447 + // a bracket expression if it occurs
448 + // first in the list. -- POSIX.2 2.8.3.2
449 + if (i === classStart + 1 || !inClass) {
450 + re += '\\' + c
451 + escaping = false
452 + continue
453 + }
454 +
455 + // handle the case where we left a class open.
456 + // "[z-a]" is valid, equivalent to "\[z-a\]"
457 + if (inClass) {
458 + // split where the last [ was, make sure we don't have
459 + // an invalid re. if so, re-walk the contents of the
460 + // would-be class to re-translate any characters that
461 + // were passed through as-is
462 + // TODO: It would probably be faster to determine this
463 + // without a try/catch and a new RegExp, but it's tricky
464 + // to do safely. For now, this is safe and works.
465 + var cs = pattern.substring(classStart + 1, i)
466 + try {
467 + RegExp('[' + cs + ']')
468 + } catch (er) {
469 + // not a valid class!
470 + var sp = this.parse(cs, SUBPARSE)
471 + re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]'
472 + hasMagic = hasMagic || sp[1]
473 + inClass = false
474 + continue
475 + }
476 + }
477 +
478 + // finish up the class.
479 + hasMagic = true
480 + inClass = false
481 + re += c
482 + continue
483 +
484 + default:
485 + // swallow any state char that wasn't consumed
486 + clearStateChar()
487 +
488 + if (escaping) {
489 + // no need
490 + escaping = false
491 + } else if (reSpecials[c]
492 + && !(c === '^' && inClass)) {
493 + re += '\\'
494 + }
495 +
496 + re += c
497 +
498 + } // switch
499 + } // for
500 +
501 + // handle the case where we left a class open.
502 + // "[abc" is valid, equivalent to "\[abc"
503 + if (inClass) {
504 + // split where the last [ was, and escape it
505 + // this is a huge pita. We now have to re-walk
506 + // the contents of the would-be class to re-translate
507 + // any characters that were passed through as-is
508 + cs = pattern.substr(classStart + 1)
509 + sp = this.parse(cs, SUBPARSE)
510 + re = re.substr(0, reClassStart) + '\\[' + sp[0]
511 + hasMagic = hasMagic || sp[1]
512 + }
513 +
514 + // handle the case where we had a +( thing at the *end*
515 + // of the pattern.
516 + // each pattern list stack adds 3 chars, and we need to go through
517 + // and escape any | chars that were passed through as-is for the regexp.
518 + // Go through and escape them, taking care not to double-escape any
519 + // | chars that were already escaped.
520 + for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
521 + var tail = re.slice(pl.reStart + pl.open.length)
522 + this.debug('setting tail', re, pl)
523 + // maybe some even number of \, then maybe 1 \, followed by a |
524 + tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, function (_, $1, $2) {
525 + if (!$2) {
526 + // the | isn't already escaped, so escape it.
527 + $2 = '\\'
528 + }
529 +
530 + // need to escape all those slashes *again*, without escaping the
531 + // one that we need for escaping the | character. As it works out,
532 + // escaping an even number of slashes can be done by simply repeating
533 + // it exactly after itself. That's why this trick works.
534 + //
535 + // I am sorry that you have to see this.
536 + return $1 + $1 + $2 + '|'
537 + })
538 +
539 + this.debug('tail=%j\n %s', tail, tail, pl, re)
540 + var t = pl.type === '*' ? star
541 + : pl.type === '?' ? qmark
542 + : '\\' + pl.type
543 +
544 + hasMagic = true
545 + re = re.slice(0, pl.reStart) + t + '\\(' + tail
546 + }
547 +
548 + // handle trailing things that only matter at the very end.
549 + clearStateChar()
550 + if (escaping) {
551 + // trailing \\
552 + re += '\\\\'
553 + }
554 +
555 + // only need to apply the nodot start if the re starts with
556 + // something that could conceivably capture a dot
557 + var addPatternStart = false
558 + switch (re.charAt(0)) {
559 + case '.':
560 + case '[':
561 + case '(': addPatternStart = true
562 + }
563 +
564 + // Hack to work around lack of negative lookbehind in JS
565 + // A pattern like: *.!(x).!(y|z) needs to ensure that a name
566 + // like 'a.xyz.yz' doesn't match. So, the first negative
567 + // lookahead, has to look ALL the way ahead, to the end of
568 + // the pattern.
569 + for (var n = negativeLists.length - 1; n > -1; n--) {
570 + var nl = negativeLists[n]
571 +
572 + var nlBefore = re.slice(0, nl.reStart)
573 + var nlFirst = re.slice(nl.reStart, nl.reEnd - 8)
574 + var nlLast = re.slice(nl.reEnd - 8, nl.reEnd)
575 + var nlAfter = re.slice(nl.reEnd)
576 +
577 + nlLast += nlAfter
578 +
579 + // Handle nested stuff like *(*.js|!(*.json)), where open parens
580 + // mean that we should *not* include the ) in the bit that is considered
581 + // "after" the negated section.
582 + var openParensBefore = nlBefore.split('(').length - 1
583 + var cleanAfter = nlAfter
584 + for (i = 0; i < openParensBefore; i++) {
585 + cleanAfter = cleanAfter.replace(/\)[+*?]?/, '')
586 + }
587 + nlAfter = cleanAfter
588 +
589 + var dollar = ''
590 + if (nlAfter === '' && isSub !== SUBPARSE) {
591 + dollar = '$'
592 + }
593 + var newRe = nlBefore + nlFirst + nlAfter + dollar + nlLast
594 + re = newRe
595 + }
596 +
597 + // if the re is not "" at this point, then we need to make sure
598 + // it doesn't match against an empty path part.
599 + // Otherwise a/* will match a/, which it should not.
600 + if (re !== '' && hasMagic) {
601 + re = '(?=.)' + re
602 + }
603 +
604 + if (addPatternStart) {
605 + re = patternStart + re
606 + }
607 +
608 + // parsing just a piece of a larger pattern.
609 + if (isSub === SUBPARSE) {
610 + return [re, hasMagic]
611 + }
612 +
613 + // skip the regexp for non-magical patterns
614 + // unescape anything in it, though, so that it'll be
615 + // an exact match against a file etc.
616 + if (!hasMagic) {
617 + return globUnescape(pattern)
618 + }
619 +
620 + var flags = options.nocase ? 'i' : ''
621 + try {
622 + var regExp = new RegExp('^' + re + '$', flags)
623 + } catch (er) {
624 + // If it was an invalid regular expression, then it can't match
625 + // anything. This trick looks for a character after the end of
626 + // the string, which is of course impossible, except in multi-line
627 + // mode, but it's not a /m regex.
628 + return new RegExp('$.')
629 + }
630 +
631 + regExp._glob = pattern
632 + regExp._src = re
633 +
634 + return regExp
635 +}
636 +
637 +minimatch.makeRe = function (pattern, options) {
638 + return new Minimatch(pattern, options || {}).makeRe()
639 +}
640 +
641 +Minimatch.prototype.makeRe = makeRe
642 +function makeRe () {
643 + if (this.regexp || this.regexp === false) return this.regexp
644 +
645 + // at this point, this.set is a 2d array of partial
646 + // pattern strings, or "**".
647 + //
648 + // It's better to use .match(). This function shouldn't
649 + // be used, really, but it's pretty convenient sometimes,
650 + // when you just want to work with a regex.
651 + var set = this.set
652 +
653 + if (!set.length) {
654 + this.regexp = false
655 + return this.regexp
656 + }
657 + var options = this.options
658 +
659 + var twoStar = options.noglobstar ? star
660 + : options.dot ? twoStarDot
661 + : twoStarNoDot
662 + var flags = options.nocase ? 'i' : ''
663 +
664 + var re = set.map(function (pattern) {
665 + return pattern.map(function (p) {
666 + return (p === GLOBSTAR) ? twoStar
667 + : (typeof p === 'string') ? regExpEscape(p)
668 + : p._src
669 + }).join('\\\/')
670 + }).join('|')
671 +
672 + // must match entire pattern
673 + // ending in a * or ** will make it less strict.
674 + re = '^(?:' + re + ')$'
675 +
676 + // can match anything, as long as it's not this.
677 + if (this.negate) re = '^(?!' + re + ').*$'
678 +
679 + try {
680 + this.regexp = new RegExp(re, flags)
681 + } catch (ex) {
682 + this.regexp = false
683 + }
684 + return this.regexp
685 +}
686 +
687 +minimatch.match = function (list, pattern, options) {
688 + options = options || {}
689 + var mm = new Minimatch(pattern, options)
690 + list = list.filter(function (f) {
691 + return mm.match(f)
692 + })
693 + if (mm.options.nonull && !list.length) {
694 + list.push(pattern)
695 + }
696 + return list
697 +}
698 +
699 +Minimatch.prototype.match = match
700 +function match (f, partial) {
701 + this.debug('match', f, this.pattern)
702 + // short-circuit in the case of busted things.
703 + // comments, etc.
704 + if (this.comment) return false
705 + if (this.empty) return f === ''
706 +
707 + if (f === '/' && partial) return true
708 +
709 + var options = this.options
710 +
711 + // windows: need to use /, not \
712 + if (path.sep !== '/') {
713 + f = f.split(path.sep).join('/')
714 + }
715 +
716 + // treat the test path as a set of pathparts.
717 + f = f.split(slashSplit)
718 + this.debug(this.pattern, 'split', f)
719 +
720 + // just ONE of the pattern sets in this.set needs to match
721 + // in order for it to be valid. If negating, then just one
722 + // match means that we have failed.
723 + // Either way, return on the first hit.
724 +
725 + var set = this.set
726 + this.debug(this.pattern, 'set', set)
727 +
728 + // Find the basename of the path by looking for the last non-empty segment
729 + var filename
730 + var i
731 + for (i = f.length - 1; i >= 0; i--) {
732 + filename = f[i]
733 + if (filename) break
734 + }
735 +
736 + for (i = 0; i < set.length; i++) {
737 + var pattern = set[i]
738 + var file = f
739 + if (options.matchBase && pattern.length === 1) {
740 + file = [filename]
741 + }
742 + var hit = this.matchOne(file, pattern, partial)
743 + if (hit) {
744 + if (options.flipNegate) return true
745 + return !this.negate
746 + }
747 + }
748 +
749 + // didn't get any hits. this is success if it's a negative
750 + // pattern, failure otherwise.
751 + if (options.flipNegate) return false
752 + return this.negate
753 +}
754 +
755 +// set partial to true to test if, for example,
756 +// "/a/b" matches the start of "/*/b/*/d"
757 +// Partial means, if you run out of file before you run
758 +// out of pattern, then that's fine, as long as all
759 +// the parts match.
760 +Minimatch.prototype.matchOne = function (file, pattern, partial) {
761 + var options = this.options
762 +
763 + this.debug('matchOne',
764 + { 'this': this, file: file, pattern: pattern })
765 +
766 + this.debug('matchOne', file.length, pattern.length)
767 +
768 + for (var fi = 0,
769 + pi = 0,
770 + fl = file.length,
771 + pl = pattern.length
772 + ; (fi < fl) && (pi < pl)
773 + ; fi++, pi++) {
774 + this.debug('matchOne loop')
775 + var p = pattern[pi]
776 + var f = file[fi]
777 +
778 + this.debug(pattern, p, f)
779 +
780 + // should be impossible.
781 + // some invalid regexp stuff in the set.
782 + if (p === false) return false
783 +
784 + if (p === GLOBSTAR) {
785 + this.debug('GLOBSTAR', [pattern, p, f])
786 +
787 + // "**"
788 + // a/**/b/**/c would match the following:
789 + // a/b/x/y/z/c
790 + // a/x/y/z/b/c
791 + // a/b/x/b/x/c
792 + // a/b/c
793 + // To do this, take the rest of the pattern after
794 + // the **, and see if it would match the file remainder.
795 + // If so, return success.
796 + // If not, the ** "swallows" a segment, and try again.
797 + // This is recursively awful.
798 + //
799 + // a/**/b/**/c matching a/b/x/y/z/c
800 + // - a matches a
801 + // - doublestar
802 + // - matchOne(b/x/y/z/c, b/**/c)
803 + // - b matches b
804 + // - doublestar
805 + // - matchOne(x/y/z/c, c) -> no
806 + // - matchOne(y/z/c, c) -> no
807 + // - matchOne(z/c, c) -> no
808 + // - matchOne(c, c) yes, hit
809 + var fr = fi
810 + var pr = pi + 1
811 + if (pr === pl) {
812 + this.debug('** at the end')
813 + // a ** at the end will just swallow the rest.
814 + // We have found a match.
815 + // however, it will not swallow /.x, unless
816 + // options.dot is set.
817 + // . and .. are *never* matched by **, for explosively
818 + // exponential reasons.
819 + for (; fi < fl; fi++) {
820 + if (file[fi] === '.' || file[fi] === '..' ||
821 + (!options.dot && file[fi].charAt(0) === '.')) return false
822 + }
823 + return true
824 + }
825 +
826 + // ok, let's see if we can swallow whatever we can.
827 + while (fr < fl) {
828 + var swallowee = file[fr]
829 +
830 + this.debug('\nglobstar while', file, fr, pattern, pr, swallowee)
831 +
832 + // XXX remove this slice. Just pass the start index.
833 + if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
834 + this.debug('globstar found match!', fr, fl, swallowee)
835 + // found a match.
836 + return true
837 + } else {
838 + // can't swallow "." or ".." ever.
839 + // can only swallow ".foo" when explicitly asked.
840 + if (swallowee === '.' || swallowee === '..' ||
841 + (!options.dot && swallowee.charAt(0) === '.')) {
842 + this.debug('dot detected!', file, fr, pattern, pr)
843 + break
844 + }
845 +
846 + // ** swallows a segment, and continue.
847 + this.debug('globstar swallow a segment, and continue')
848 + fr++
849 + }
850 + }
851 +
852 + // no match was found.
853 + // However, in partial mode, we can't say this is necessarily over.
854 + // If there's more *pattern* left, then
855 + if (partial) {
856 + // ran out of file
857 + this.debug('\n>>> no match, partial?', file, fr, pattern, pr)
858 + if (fr === fl) return true
859 + }
860 + return false
861 + }
862 +
863 + // something other than **
864 + // non-magic patterns just have to match exactly
865 + // patterns with magic have been turned into regexps.
866 + var hit
867 + if (typeof p === 'string') {
868 + if (options.nocase) {
869 + hit = f.toLowerCase() === p.toLowerCase()
870 + } else {
871 + hit = f === p
872 + }
873 + this.debug('string match', p, f, hit)
874 + } else {
875 + hit = f.match(p)
876 + this.debug('pattern match', p, f, hit)
877 + }
878 +
879 + if (!hit) return false
880 + }
881 +
882 + // Note: ending in / means that we'll get a final ""
883 + // at the end of the pattern. This can only match a
884 + // corresponding "" at the end of the file.
885 + // If the file ends in /, then it can only match a
886 + // a pattern that ends in /, unless the pattern just
887 + // doesn't have any more for it. But, a/b/ should *not*
888 + // match "a/b/*", even though "" matches against the
889 + // [^/]*? pattern, except in partial mode, where it might
890 + // simply not be reached yet.
891 + // However, a/b/ should still satisfy a/*
892 +
893 + // now either we fell off the end of the pattern, or we're done.
894 + if (fi === fl && pi === pl) {
895 + // ran out of pattern and filename at the same time.
896 + // an exact hit!
897 + return true
898 + } else if (fi === fl) {
899 + // ran out of file, but still had pattern left.
900 + // this is ok if we're doing the match as part of
901 + // a glob fs traversal.
902 + return partial
903 + } else if (pi === pl) {
904 + // ran out of pattern, still have file left.
905 + // this is only acceptable if we're on the very last
906 + // empty segment of a file with a trailing slash.
907 + // a/* should match a/b/
908 + var emptyFileEnd = (fi === fl - 1) && (file[fi] === '')
909 + return emptyFileEnd
910 + }
911 +
912 + // should be unreachable.
913 + throw new Error('wtf?')
914 +}
915 +
916 +// replace stuff like \* with *
917 +function globUnescape (s) {
918 + return s.replace(/\\(.)/g, '$1')
919 +}
920 +
921 +function regExpEscape (s) {
922 + return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
923 +}
1 +{
2 + "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
3 + "name": "minimatch",
4 + "description": "a glob matcher in javascript",
5 + "version": "3.0.4",
6 + "repository": {
7 + "type": "git",
8 + "url": "git://github.com/isaacs/minimatch.git"
9 + },
10 + "main": "minimatch.js",
11 + "scripts": {
12 + "test": "tap test/*.js --cov",
13 + "preversion": "npm test",
14 + "postversion": "npm publish",
15 + "postpublish": "git push origin --all; git push origin --tags"
16 + },
17 + "engines": {
18 + "node": "*"
19 + },
20 + "dependencies": {
21 + "brace-expansion": "^1.1.7"
22 + },
23 + "devDependencies": {
24 + "tap": "^10.3.2"
25 + },
26 + "license": "ISC",
27 + "files": [
28 + "minimatch.js"
29 + ]
30 +}
1 +'use strict';
2 +module.exports = {
3 + stdout: false,
4 + stderr: false
5 +};
1 +'use strict';
2 +const os = require('os');
3 +const hasFlag = require('has-flag');
4 +
5 +const env = process.env;
6 +
7 +let forceColor;
8 +if (hasFlag('no-color') ||
9 + hasFlag('no-colors') ||
10 + hasFlag('color=false')) {
11 + forceColor = false;
12 +} else if (hasFlag('color') ||
13 + hasFlag('colors') ||
14 + hasFlag('color=true') ||
15 + hasFlag('color=always')) {
16 + forceColor = true;
17 +}
18 +if ('FORCE_COLOR' in env) {
19 + forceColor = env.FORCE_COLOR.length === 0 || parseInt(env.FORCE_COLOR, 10) !== 0;
20 +}
21 +
22 +function translateLevel(level) {
23 + if (level === 0) {
24 + return false;
25 + }
26 +
27 + return {
28 + level,
29 + hasBasic: true,
30 + has256: level >= 2,
31 + has16m: level >= 3
32 + };
33 +}
34 +
35 +function supportsColor(stream) {
36 + if (forceColor === false) {
37 + return 0;
38 + }
39 +
40 + if (hasFlag('color=16m') ||
41 + hasFlag('color=full') ||
42 + hasFlag('color=truecolor')) {
43 + return 3;
44 + }
45 +
46 + if (hasFlag('color=256')) {
47 + return 2;
48 + }
49 +
50 + if (stream && !stream.isTTY && forceColor !== true) {
51 + return 0;
52 + }
53 +
54 + const min = forceColor ? 1 : 0;
55 +
56 + if (process.platform === 'win32') {
57 + // Node.js 7.5.0 is the first version of Node.js to include a patch to
58 + // libuv that enables 256 color output on Windows. Anything earlier and it
59 + // won't work. However, here we target Node.js 8 at minimum as it is an LTS
60 + // release, and Node.js 7 is not. Windows 10 build 10586 is the first Windows
61 + // release that supports 256 colors. Windows 10 build 14931 is the first release
62 + // that supports 16m/TrueColor.
63 + const osRelease = os.release().split('.');
64 + if (
65 + Number(process.versions.node.split('.')[0]) >= 8 &&
66 + Number(osRelease[0]) >= 10 &&
67 + Number(osRelease[2]) >= 10586
68 + ) {
69 + return Number(osRelease[2]) >= 14931 ? 3 : 2;
70 + }
71 +
72 + return 1;
73 + }
74 +
75 + if ('CI' in env) {
76 + if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI'].some(sign => sign in env) || env.CI_NAME === 'codeship') {
77 + return 1;
78 + }
79 +
80 + return min;
81 + }
82 +
83 + if ('TEAMCITY_VERSION' in env) {
84 + return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
85 + }
86 +
87 + if (env.COLORTERM === 'truecolor') {
88 + return 3;
89 + }
90 +
91 + if ('TERM_PROGRAM' in env) {
92 + const version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);
93 +
94 + switch (env.TERM_PROGRAM) {
95 + case 'iTerm.app':
96 + return version >= 3 ? 3 : 2;
97 + case 'Apple_Terminal':
98 + return 2;
99 + // No default
100 + }
101 + }
102 +
103 + if (/-256(color)?$/i.test(env.TERM)) {
104 + return 2;
105 + }
106 +
107 + if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
108 + return 1;
109 + }
110 +
111 + if ('COLORTERM' in env) {
112 + return 1;
113 + }
114 +
115 + if (env.TERM === 'dumb') {
116 + return min;
117 + }
118 +
119 + return min;
120 +}
121 +
122 +function getSupportLevel(stream) {
123 + const level = supportsColor(stream);
124 + return translateLevel(level);
125 +}
126 +
127 +module.exports = {
128 + supportsColor: getSupportLevel,
129 + stdout: getSupportLevel(process.stdout),
130 + stderr: getSupportLevel(process.stderr)
131 +};
1 +MIT License
2 +
3 +Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
4 +
5 +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:
6 +
7 +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 +
9 +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.
1 +{
2 + "name": "supports-color",
3 + "version": "5.5.0",
4 + "description": "Detect whether a terminal supports color",
5 + "license": "MIT",
6 + "repository": "chalk/supports-color",
7 + "author": {
8 + "name": "Sindre Sorhus",
9 + "email": "sindresorhus@gmail.com",
10 + "url": "sindresorhus.com"
11 + },
12 + "engines": {
13 + "node": ">=4"
14 + },
15 + "scripts": {
16 + "test": "xo && ava"
17 + },
18 + "files": [
19 + "index.js",
20 + "browser.js"
21 + ],
22 + "keywords": [
23 + "color",
24 + "colour",
25 + "colors",
26 + "terminal",
27 + "console",
28 + "cli",
29 + "ansi",
30 + "styles",
31 + "tty",
32 + "rgb",
33 + "256",
34 + "shell",
35 + "xterm",
36 + "command-line",
37 + "support",
38 + "supports",
39 + "capability",
40 + "detect",
41 + "truecolor",
42 + "16m"
43 + ],
44 + "dependencies": {
45 + "has-flag": "^3.0.0"
46 + },
47 + "devDependencies": {
48 + "ava": "^0.25.0",
49 + "import-fresh": "^2.0.0",
50 + "xo": "^0.20.0"
51 + },
52 + "browser": "browser.js"
53 +}
1 +# supports-color [![Build Status](https://travis-ci.org/chalk/supports-color.svg?branch=master)](https://travis-ci.org/chalk/supports-color)
2 +
3 +> Detect whether a terminal supports color
4 +
5 +
6 +## Install
7 +
8 +```
9 +$ npm install supports-color
10 +```
11 +
12 +
13 +## Usage
14 +
15 +```js
16 +const supportsColor = require('supports-color');
17 +
18 +if (supportsColor.stdout) {
19 + console.log('Terminal stdout supports color');
20 +}
21 +
22 +if (supportsColor.stdout.has256) {
23 + console.log('Terminal stdout supports 256 colors');
24 +}
25 +
26 +if (supportsColor.stderr.has16m) {
27 + console.log('Terminal stderr supports 16 million colors (truecolor)');
28 +}
29 +```
30 +
31 +
32 +## API
33 +
34 +Returns an `Object` with a `stdout` and `stderr` property for testing either streams. Each property is an `Object`, or `false` if color is not supported.
35 +
36 +The `stdout`/`stderr` objects specifies a level of support for color through a `.level` property and a corresponding flag:
37 +
38 +- `.level = 1` and `.hasBasic = true`: Basic color support (16 colors)
39 +- `.level = 2` and `.has256 = true`: 256 color support
40 +- `.level = 3` and `.has16m = true`: Truecolor support (16 million colors)
41 +
42 +
43 +## Info
44 +
45 +It obeys the `--color` and `--no-color` CLI flags.
46 +
47 +Can be overridden by the user with the flags `--color` and `--no-color`. For situations where using `--color` is not possible, add the environment variable `FORCE_COLOR=1` to forcefully enable color or `FORCE_COLOR=0` to forcefully disable. The use of `FORCE_COLOR` overrides all other color support checks.
48 +
49 +Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color=16m` flags, respectively.
50 +
51 +
52 +## Related
53 +
54 +- [supports-color-cli](https://github.com/chalk/supports-color-cli) - CLI for this module
55 +- [chalk](https://github.com/chalk/chalk) - Terminal string styling done right
56 +
57 +
58 +## Maintainers
59 +
60 +- [Sindre Sorhus](https://github.com/sindresorhus)
61 +- [Josh Junon](https://github.com/qix-)
62 +
63 +
64 +## License
65 +
66 +MIT
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
10 "license": "ISC", 10 "license": "ISC",
11 "dependencies": { 11 "dependencies": {
12 "body-parser": "^1.19.0", 12 "body-parser": "^1.19.0",
13 + "ejs": "^3.1.6",
13 "express": "^4.17.1", 14 "express": "^4.17.1",
14 "mongodb": "^3.6.4" 15 "mongodb": "^3.6.4"
15 } 16 }
...@@ -26,11 +27,32 @@ ...@@ -26,11 +27,32 @@
26 "node": ">= 0.6" 27 "node": ">= 0.6"
27 } 28 }
28 }, 29 },
30 + "node_modules/ansi-styles": {
31 + "version": "3.2.1",
32 + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
33 + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
34 + "dependencies": {
35 + "color-convert": "^1.9.0"
36 + },
37 + "engines": {
38 + "node": ">=4"
39 + }
40 + },
29 "node_modules/array-flatten": { 41 "node_modules/array-flatten": {
30 "version": "1.1.1", 42 "version": "1.1.1",
31 "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 43 "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
32 "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 44 "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
33 }, 45 },
46 + "node_modules/async": {
47 + "version": "0.9.2",
48 + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
49 + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0="
50 + },
51 + "node_modules/balanced-match": {
52 + "version": "1.0.2",
53 + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
54 + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
55 + },
34 "node_modules/bl": { 56 "node_modules/bl": {
35 "version": "2.2.1", 57 "version": "2.2.1",
36 "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", 58 "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
...@@ -60,6 +82,15 @@ ...@@ -60,6 +82,15 @@
60 "node": ">= 0.8" 82 "node": ">= 0.8"
61 } 83 }
62 }, 84 },
85 + "node_modules/brace-expansion": {
86 + "version": "1.1.11",
87 + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
88 + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
89 + "dependencies": {
90 + "balanced-match": "^1.0.0",
91 + "concat-map": "0.0.1"
92 + }
93 + },
63 "node_modules/bson": { 94 "node_modules/bson": {
64 "version": "1.1.6", 95 "version": "1.1.6",
65 "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", 96 "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz",
...@@ -76,6 +107,37 @@ ...@@ -76,6 +107,37 @@
76 "node": ">= 0.8" 107 "node": ">= 0.8"
77 } 108 }
78 }, 109 },
110 + "node_modules/chalk": {
111 + "version": "2.4.2",
112 + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
113 + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
114 + "dependencies": {
115 + "ansi-styles": "^3.2.1",
116 + "escape-string-regexp": "^1.0.5",
117 + "supports-color": "^5.3.0"
118 + },
119 + "engines": {
120 + "node": ">=4"
121 + }
122 + },
123 + "node_modules/color-convert": {
124 + "version": "1.9.3",
125 + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
126 + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
127 + "dependencies": {
128 + "color-name": "1.1.3"
129 + }
130 + },
131 + "node_modules/color-name": {
132 + "version": "1.1.3",
133 + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
134 + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
135 + },
136 + "node_modules/concat-map": {
137 + "version": "0.0.1",
138 + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
139 + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
140 + },
79 "node_modules/content-disposition": { 141 "node_modules/content-disposition": {
80 "version": "0.5.3", 142 "version": "0.5.3",
81 "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", 143 "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
...@@ -147,6 +209,20 @@ ...@@ -147,6 +209,20 @@
147 "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 209 "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
148 "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 210 "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
149 }, 211 },
212 + "node_modules/ejs": {
213 + "version": "3.1.6",
214 + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz",
215 + "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==",
216 + "dependencies": {
217 + "jake": "^10.6.1"
218 + },
219 + "bin": {
220 + "ejs": "bin/cli.js"
221 + },
222 + "engines": {
223 + "node": ">=0.10.0"
224 + }
225 + },
150 "node_modules/encodeurl": { 226 "node_modules/encodeurl": {
151 "version": "1.0.2", 227 "version": "1.0.2",
152 "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 228 "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
...@@ -160,6 +236,14 @@ ...@@ -160,6 +236,14 @@
160 "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 236 "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
161 "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 237 "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
162 }, 238 },
239 + "node_modules/escape-string-regexp": {
240 + "version": "1.0.5",
241 + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
242 + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
243 + "engines": {
244 + "node": ">=0.8.0"
245 + }
246 + },
163 "node_modules/etag": { 247 "node_modules/etag": {
164 "version": "1.8.1", 248 "version": "1.8.1",
165 "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 249 "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
...@@ -208,6 +292,14 @@ ...@@ -208,6 +292,14 @@
208 "node": ">= 0.10.0" 292 "node": ">= 0.10.0"
209 } 293 }
210 }, 294 },
295 + "node_modules/filelist": {
296 + "version": "1.0.2",
297 + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz",
298 + "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==",
299 + "dependencies": {
300 + "minimatch": "^3.0.4"
301 + }
302 + },
211 "node_modules/finalhandler": { 303 "node_modules/finalhandler": {
212 "version": "1.1.2", 304 "version": "1.1.2",
213 "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", 305 "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
...@@ -241,6 +333,14 @@ ...@@ -241,6 +333,14 @@
241 "node": ">= 0.6" 333 "node": ">= 0.6"
242 } 334 }
243 }, 335 },
336 + "node_modules/has-flag": {
337 + "version": "3.0.0",
338 + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
339 + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
340 + "engines": {
341 + "node": ">=4"
342 + }
343 + },
244 "node_modules/http-errors": { 344 "node_modules/http-errors": {
245 "version": "1.7.2", 345 "version": "1.7.2",
246 "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", 346 "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
...@@ -285,6 +385,23 @@ ...@@ -285,6 +385,23 @@
285 "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 385 "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
286 "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 386 "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
287 }, 387 },
388 + "node_modules/jake": {
389 + "version": "10.8.2",
390 + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz",
391 + "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==",
392 + "dependencies": {
393 + "async": "0.9.x",
394 + "chalk": "^2.4.2",
395 + "filelist": "^1.0.1",
396 + "minimatch": "^3.0.4"
397 + },
398 + "bin": {
399 + "jake": "bin/cli.js"
400 + },
401 + "engines": {
402 + "node": "*"
403 + }
404 + },
288 "node_modules/media-typer": { 405 "node_modules/media-typer": {
289 "version": "0.3.0", 406 "version": "0.3.0",
290 "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 407 "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
...@@ -342,6 +459,17 @@ ...@@ -342,6 +459,17 @@
342 "node": ">= 0.6" 459 "node": ">= 0.6"
343 } 460 }
344 }, 461 },
462 + "node_modules/minimatch": {
463 + "version": "3.0.4",
464 + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
465 + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
466 + "dependencies": {
467 + "brace-expansion": "^1.1.7"
468 + },
469 + "engines": {
470 + "node": "*"
471 + }
472 + },
345 "node_modules/mongodb": { 473 "node_modules/mongodb": {
346 "version": "3.6.4", 474 "version": "3.6.4",
347 "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.4.tgz", 475 "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.4.tgz",
...@@ -597,6 +725,17 @@ ...@@ -597,6 +725,17 @@
597 "safe-buffer": "~5.1.0" 725 "safe-buffer": "~5.1.0"
598 } 726 }
599 }, 727 },
728 + "node_modules/supports-color": {
729 + "version": "5.5.0",
730 + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
731 + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
732 + "dependencies": {
733 + "has-flag": "^3.0.0"
734 + },
735 + "engines": {
736 + "node": ">=4"
737 + }
738 + },
600 "node_modules/toidentifier": { 739 "node_modules/toidentifier": {
601 "version": "1.0.0", 740 "version": "1.0.0",
602 "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 741 "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
...@@ -657,11 +796,29 @@ ...@@ -657,11 +796,29 @@
657 "negotiator": "0.6.2" 796 "negotiator": "0.6.2"
658 } 797 }
659 }, 798 },
799 + "ansi-styles": {
800 + "version": "3.2.1",
801 + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
802 + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
803 + "requires": {
804 + "color-convert": "^1.9.0"
805 + }
806 + },
660 "array-flatten": { 807 "array-flatten": {
661 "version": "1.1.1", 808 "version": "1.1.1",
662 "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 809 "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
663 "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 810 "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
664 }, 811 },
812 + "async": {
813 + "version": "0.9.2",
814 + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
815 + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0="
816 + },
817 + "balanced-match": {
818 + "version": "1.0.2",
819 + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
820 + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
821 + },
665 "bl": { 822 "bl": {
666 "version": "2.2.1", 823 "version": "2.2.1",
667 "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", 824 "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
...@@ -688,6 +845,15 @@ ...@@ -688,6 +845,15 @@
688 "type-is": "~1.6.17" 845 "type-is": "~1.6.17"
689 } 846 }
690 }, 847 },
848 + "brace-expansion": {
849 + "version": "1.1.11",
850 + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
851 + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
852 + "requires": {
853 + "balanced-match": "^1.0.0",
854 + "concat-map": "0.0.1"
855 + }
856 + },
691 "bson": { 857 "bson": {
692 "version": "1.1.6", 858 "version": "1.1.6",
693 "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", 859 "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz",
...@@ -698,6 +864,34 @@ ...@@ -698,6 +864,34 @@
698 "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 864 "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
699 "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" 865 "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
700 }, 866 },
867 + "chalk": {
868 + "version": "2.4.2",
869 + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
870 + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
871 + "requires": {
872 + "ansi-styles": "^3.2.1",
873 + "escape-string-regexp": "^1.0.5",
874 + "supports-color": "^5.3.0"
875 + }
876 + },
877 + "color-convert": {
878 + "version": "1.9.3",
879 + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
880 + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
881 + "requires": {
882 + "color-name": "1.1.3"
883 + }
884 + },
885 + "color-name": {
886 + "version": "1.1.3",
887 + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
888 + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
889 + },
890 + "concat-map": {
891 + "version": "0.0.1",
892 + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
893 + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
894 + },
701 "content-disposition": { 895 "content-disposition": {
702 "version": "0.5.3", 896 "version": "0.5.3",
703 "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", 897 "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
...@@ -754,6 +948,14 @@ ...@@ -754,6 +948,14 @@
754 "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 948 "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
755 "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 949 "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
756 }, 950 },
951 + "ejs": {
952 + "version": "3.1.6",
953 + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz",
954 + "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==",
955 + "requires": {
956 + "jake": "^10.6.1"
957 + }
958 + },
757 "encodeurl": { 959 "encodeurl": {
758 "version": "1.0.2", 960 "version": "1.0.2",
759 "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 961 "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
...@@ -764,6 +966,11 @@ ...@@ -764,6 +966,11 @@
764 "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 966 "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
765 "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 967 "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
766 }, 968 },
969 + "escape-string-regexp": {
970 + "version": "1.0.5",
971 + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
972 + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
973 + },
767 "etag": { 974 "etag": {
768 "version": "1.8.1", 975 "version": "1.8.1",
769 "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 976 "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
...@@ -806,6 +1013,14 @@ ...@@ -806,6 +1013,14 @@
806 "vary": "~1.1.2" 1013 "vary": "~1.1.2"
807 } 1014 }
808 }, 1015 },
1016 + "filelist": {
1017 + "version": "1.0.2",
1018 + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz",
1019 + "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==",
1020 + "requires": {
1021 + "minimatch": "^3.0.4"
1022 + }
1023 + },
809 "finalhandler": { 1024 "finalhandler": {
810 "version": "1.1.2", 1025 "version": "1.1.2",
811 "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", 1026 "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
...@@ -830,6 +1045,11 @@ ...@@ -830,6 +1045,11 @@
830 "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 1045 "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
831 "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 1046 "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
832 }, 1047 },
1048 + "has-flag": {
1049 + "version": "3.0.0",
1050 + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
1051 + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
1052 + },
833 "http-errors": { 1053 "http-errors": {
834 "version": "1.7.2", 1054 "version": "1.7.2",
835 "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", 1055 "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
...@@ -865,6 +1085,17 @@ ...@@ -865,6 +1085,17 @@
865 "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1085 "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
866 "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 1086 "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
867 }, 1087 },
1088 + "jake": {
1089 + "version": "10.8.2",
1090 + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz",
1091 + "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==",
1092 + "requires": {
1093 + "async": "0.9.x",
1094 + "chalk": "^2.4.2",
1095 + "filelist": "^1.0.1",
1096 + "minimatch": "^3.0.4"
1097 + }
1098 + },
868 "media-typer": { 1099 "media-typer": {
869 "version": "0.3.0", 1100 "version": "0.3.0",
870 "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 1101 "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
...@@ -904,6 +1135,14 @@ ...@@ -904,6 +1135,14 @@
904 "mime-db": "1.51.0" 1135 "mime-db": "1.51.0"
905 } 1136 }
906 }, 1137 },
1138 + "minimatch": {
1139 + "version": "3.0.4",
1140 + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
1141 + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
1142 + "requires": {
1143 + "brace-expansion": "^1.1.7"
1144 + }
1145 + },
907 "mongodb": { 1146 "mongodb": {
908 "version": "3.6.4", 1147 "version": "3.6.4",
909 "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.4.tgz", 1148 "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.4.tgz",
...@@ -1097,6 +1336,14 @@ ...@@ -1097,6 +1336,14 @@
1097 "safe-buffer": "~5.1.0" 1336 "safe-buffer": "~5.1.0"
1098 } 1337 }
1099 }, 1338 },
1339 + "supports-color": {
1340 + "version": "5.5.0",
1341 + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1342 + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1343 + "requires": {
1344 + "has-flag": "^3.0.0"
1345 + }
1346 + },
1100 "toidentifier": { 1347 "toidentifier": {
1101 "version": "1.0.0", 1348 "version": "1.0.0",
1102 "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 1349 "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
14 "license": "ISC", 14 "license": "ISC",
15 "dependencies": { 15 "dependencies": {
16 "body-parser": "^1.19.0", 16 "body-parser": "^1.19.0",
17 + "ejs": "^3.1.6",
17 "express": "^4.17.1", 18 "express": "^4.17.1",
18 "mongodb": "^3.6.4" 19 "mongodb": "^3.6.4"
19 } 20 }
......
...@@ -2,6 +2,7 @@ const express = require('express'); ...@@ -2,6 +2,7 @@ const express = require('express');
2 const app = express(); 2 const app = express();
3 const bodyParser = require('body-parser') 3 const bodyParser = require('body-parser')
4 app.use(bodyParser.urlencoded({extended : true})); 4 app.use(bodyParser.urlencoded({extended : true}));
5 +app.set('view engine', 'ejs');
5 6
6 var db; 7 var db;
7 const MongoClient = require('mongodb').MongoClient; 8 const MongoClient = require('mongodb').MongoClient;
...@@ -10,13 +11,8 @@ MongoClient.connect('mongodb+srv://admin:qwer1234@cluster0.m2pvs.mongodb.net/myF ...@@ -10,13 +11,8 @@ MongoClient.connect('mongodb+srv://admin:qwer1234@cluster0.m2pvs.mongodb.net/myF
10 if(에러){ 11 if(에러){
11 return console.log(에러); 12 return console.log(에러);
12 } 13 }
13 -
14 db = clinet.db('todoapp'); 14 db = clinet.db('todoapp');
15 15
16 - db.collection('post').insertOne({이름 : 'John', _id : 100}, function(에러, 결과){
17 - console.log('저장완료')
18 - });
19 -
20 app.listen(8080, function(){ 16 app.listen(8080, function(){
21 console.log('listening on 8080') 17 console.log('listening on 8080')
22 }); 18 });
...@@ -41,7 +37,11 @@ app.get('/write', function(요청, 응답){ ...@@ -41,7 +37,11 @@ app.get('/write', function(요청, 응답){
41 37
42 app.post('/add', function(요청, 응답){ 38 app.post('/add', function(요청, 응답){
43 응답.send('전송완료'); 39 응답.send('전송완료');
44 - db.collection('post').insertOne({제목 : 요청.body.title, 날짜 : 요청.body.date ,_id : 500}, function(에러, 결과){ 40 + db.collection('post').insertOne({제목 : 요청.body.title, 날짜 : 요청.body.date}, function(에러, 결과){
45 console.log('저장완료') 41 console.log('저장완료')
46 }); 42 });
47 }); 43 });
44 +
45 +app.get('/list',function(요청, 응답){
46 + 응답.render('list.ejs');
47 +});
...\ No newline at end of file ...\ No newline at end of file
......
1 +<!doctype html>
2 +<html>
3 + <head>
4 + <!-- Required meta tags -->
5 + <meta charset="utf-8">
6 + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
7 +
8 + <!-- Bootstrap CSS -->
9 + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous">
10 +
11 +
12 + </head>
13 + <body>
14 +
15 + <nav class="navbar navbar-expand-lg navbar-light bg-light">
16 + <a class="navbar-brand" href="#">Todo App</a>
17 + <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
18 + <span class="navbar-toggler-icon"></span>
19 + </button>
20 + <div class="collapse navbar-collapse" id="navbarNav">
21 + <ul class="navbar-nav">
22 + <li class="nav-item active">
23 + <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
24 + </li>
25 + <li class="nav-item"
26 + <a class="nav-link" href="#">Write</a>
27 + </li>
28 + <li class="nav-item">
29 + <a class="nav-link" href="#">임시</a>
30 + </li>
31 + </ul>
32 + </div>
33 + </nav>
34 +
35 + <!--서버에서 가져온 할 일 리스트-->
36 + <h4>할일 제목 : <%= %></h4>
37 + <p>할일 마감날짜 : ???</p>
38 +
39 + <!-- Optional JavaScript; choose one of the two! -->
40 +
41 + <!-- Option 1: jQuery and Bootstrap Bundle (includes Popper) -->
42 + <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
43 + <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script>
44 +
45 + <!-- Option 2: Separate Popper and Bootstrap JS -->
46 + <!--
47 + <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
48 + <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
49 + <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.min.js" integrity="sha384-VHvPCCyXqtD5DqJeNxl2dtTyhF78xXNXdkwX1CZeRusQfRKp+tA7hAShOK/B/fQ2" crossorigin="anonymous"></script>
50 + -->
51 + </body>
52 +</html>
...\ No newline at end of file ...\ No newline at end of file