mirror of
https://github.com/bower/bower.git
synced 2026-04-24 03:00:19 -04:00
Compare commits
1252 Commits
_pr796_aut
...
lerna
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
965a53db21 | ||
|
|
1334ff67ae | ||
|
|
afb27f446a | ||
|
|
fe011b8462 | ||
|
|
096fc3da0d | ||
|
|
8b6c8eeaa9 | ||
|
|
58ddb59104 | ||
|
|
f26fe38c30 | ||
|
|
9317bb6e33 | ||
|
|
2693bae8ed | ||
|
|
8368539a93 | ||
|
|
8947400487 | ||
|
|
44eeb60529 | ||
|
|
2309cd80c6 | ||
|
|
684ab0c0a6 | ||
|
|
1f6b32a48e | ||
|
|
e4f0295ef1 | ||
|
|
85e39cf190 | ||
|
|
16c134f0f9 | ||
|
|
bcbff32716 | ||
|
|
809117ea73 | ||
|
|
af448ba484 | ||
|
|
89069784bb | ||
|
|
57cc6f7a40 | ||
|
|
cea728c7bc | ||
|
|
f6be8e5e28 | ||
|
|
c6f7ec36de | ||
|
|
3235b3c0d3 | ||
|
|
6ca5d434a4 | ||
|
|
eb27ae8fdc | ||
|
|
353a399f75 | ||
|
|
c718541a4e | ||
|
|
1f4372299a | ||
|
|
e640d0ec5c | ||
|
|
2e5acfe076 | ||
|
|
19f3c53c70 | ||
|
|
26902aec27 | ||
|
|
08feaf2b0a | ||
|
|
db1ed1c08f | ||
|
|
3c2562ca0e | ||
|
|
b1f1b8fae3 | ||
|
|
f1c874b202 | ||
|
|
4757e7353f | ||
|
|
249ac47b9c | ||
|
|
dc59913098 | ||
|
|
343e6ac8bc | ||
|
|
e729829174 | ||
|
|
40e3ee091b | ||
|
|
8ee2d78779 | ||
|
|
7c54812ecf | ||
|
|
3251051d20 | ||
|
|
81052830f2 | ||
|
|
7b2fd5dcd1 | ||
|
|
bbc9b35cb1 | ||
|
|
3aebb34f1d | ||
|
|
8065e5c64a | ||
|
|
b8e6f36a91 | ||
|
|
12d41aeb8c | ||
|
|
8c624bbda6 | ||
|
|
7ee1686cf4 | ||
|
|
8e181c1792 | ||
|
|
9569a8074d | ||
|
|
e8e4c8fdbc | ||
|
|
9e5cd572f8 | ||
|
|
69cd360551 | ||
|
|
4793fc0d1c | ||
|
|
aaaa9cd530 | ||
|
|
c2e0dc9d23 | ||
|
|
fc4446247c | ||
|
|
f4e0b3dfba | ||
|
|
4d7cdb0556 | ||
|
|
037bbff17e | ||
|
|
f05cd5fb94 | ||
|
|
358a73b98e | ||
|
|
32cbb5a0e8 | ||
|
|
8679ad77ae | ||
|
|
1b1d8bdad6 | ||
|
|
aecdf3f365 | ||
|
|
1cf87041cc | ||
|
|
5116fec1ab | ||
|
|
8f2668a24d | ||
|
|
e7516e4bcb | ||
|
|
3853d1297e | ||
|
|
1e398f999b | ||
|
|
3a0ea968f4 | ||
|
|
7de2e5d601 | ||
|
|
b1c45bb586 | ||
|
|
f4cb047e9d | ||
|
|
f494ae7ddd | ||
|
|
44e71267c1 | ||
|
|
52aa684949 | ||
|
|
46655b7c4e | ||
|
|
16cde3118a | ||
|
|
7c2dfc1146 | ||
|
|
53eeca97d3 | ||
|
|
9201a379d6 | ||
|
|
2052ba3eed | ||
|
|
b32bd8b877 | ||
|
|
233f685c61 | ||
|
|
5fe8df2e0a | ||
|
|
a3ae3b66b7 | ||
|
|
2000d2f5db | ||
|
|
84d8d8c57f | ||
|
|
f9ea3846e2 | ||
|
|
8b6c20239e | ||
|
|
73171766e7 | ||
|
|
88b3655829 | ||
|
|
3241e8ed62 | ||
|
|
0a81308e98 | ||
|
|
8d76b87d65 | ||
|
|
f2884656c0 | ||
|
|
6fff6fa707 | ||
|
|
1357f63a1b | ||
|
|
529d702959 | ||
|
|
0155a70457 | ||
|
|
a6ca2ae9bb | ||
|
|
78e443db0a | ||
|
|
5f24eab32d | ||
|
|
f4620b28ab | ||
|
|
9f4c2384ea | ||
|
|
e85a5f778f | ||
|
|
5283a132bc | ||
|
|
db1453f7c0 | ||
|
|
878a228a7d | ||
|
|
b33041c3ec | ||
|
|
c8a6ff38a0 | ||
|
|
573b84f7f4 | ||
|
|
ef67955c21 | ||
|
|
36a14b9b37 | ||
|
|
96d986f436 | ||
|
|
394dd7c8d2 | ||
|
|
6c67d07cc8 | ||
|
|
cd7bbab310 | ||
|
|
4b4a854ed8 | ||
|
|
8194bcb4c6 | ||
|
|
e5d478a1cc | ||
|
|
bbaaee67a1 | ||
|
|
ad27112b58 | ||
|
|
38c3cee1a7 | ||
|
|
b485c5d3cb | ||
|
|
d63047b4ee | ||
|
|
f0a54d0018 | ||
|
|
1d73764788 | ||
|
|
9d2681b0c4 | ||
|
|
f3330e8612 | ||
|
|
11996c04b7 | ||
|
|
35e73a619a | ||
|
|
fe615fd517 | ||
|
|
3e3b64218d | ||
|
|
afe76e57f8 | ||
|
|
6ee3ef7aa8 | ||
|
|
64db869bd4 | ||
|
|
a4ea05800d | ||
|
|
8cf897cd19 | ||
|
|
d06af7a3d7 | ||
|
|
d4fd71986e | ||
|
|
3154444556 | ||
|
|
24f8b913b9 | ||
|
|
fe6b6863ea | ||
|
|
671c23ad50 | ||
|
|
5384fa54b1 | ||
|
|
4bfa8227d9 | ||
|
|
55d78f7928 | ||
|
|
2110148830 | ||
|
|
afc4bfbd42 | ||
|
|
9c42a008aa | ||
|
|
67884744c3 | ||
|
|
ed881e3f29 | ||
|
|
e6e60d5d5e | ||
|
|
d8f166a933 | ||
|
|
bb626d1605 | ||
|
|
daa5b8ddf9 | ||
|
|
db087dfe13 | ||
|
|
848e401efd | ||
|
|
c17c725057 | ||
|
|
2b31f6c07a | ||
|
|
3cf597fccf | ||
|
|
e2adbc37f1 | ||
|
|
6c3b7dbf58 | ||
|
|
d3ab3c1fa7 | ||
|
|
b1ba9be7f6 | ||
|
|
1e5122c023 | ||
|
|
4255d7d4a8 | ||
|
|
cdf45239f4 | ||
|
|
8b2fad32f6 | ||
|
|
d1ae0b1982 | ||
|
|
87cf578ba8 | ||
|
|
3ead440c7c | ||
|
|
e168c894a2 | ||
|
|
75e3661371 | ||
|
|
baf8f7bf6b | ||
|
|
88758cd98c | ||
|
|
3bd2d62e67 | ||
|
|
d3eef5772a | ||
|
|
7c714901d4 | ||
|
|
7792b6d35d | ||
|
|
2db983dba3 | ||
|
|
b9718bb309 | ||
|
|
26f609e614 | ||
|
|
4c2b56096b | ||
|
|
5af929f0be | ||
|
|
6a18cde782 | ||
|
|
32c5538fc5 | ||
|
|
57478d86c7 | ||
|
|
42107e6fea | ||
|
|
686e883d87 | ||
|
|
f2767648e7 | ||
|
|
9e4bdd270d | ||
|
|
7cb88ab49f | ||
|
|
a532c55dca | ||
|
|
c559432c19 | ||
|
|
9aae3b8d7e | ||
|
|
322c49edf4 | ||
|
|
34ec39507c | ||
|
|
fe9b27a647 | ||
|
|
304bb36bbc | ||
|
|
376a2de600 | ||
|
|
1605374a25 | ||
|
|
ac244a1400 | ||
|
|
9e58bbca31 | ||
|
|
027a0694f7 | ||
|
|
d50e50f3b5 | ||
|
|
3030469c59 | ||
|
|
977e0ddc52 | ||
|
|
de3e1089da | ||
|
|
7897ad7dba | ||
|
|
accdab3ece | ||
|
|
612aaa88eb | ||
|
|
338ac99080 | ||
|
|
9605bbea5f | ||
|
|
7bc97a1241 | ||
|
|
bd2c253f99 | ||
|
|
f1efce7d1f | ||
|
|
844cc5a527 | ||
|
|
0e27b6f813 | ||
|
|
3791aee9d6 | ||
|
|
20a223a959 | ||
|
|
9219f54718 | ||
|
|
ea5bd51327 | ||
|
|
5a2272cab1 | ||
|
|
b94c20b8da | ||
|
|
b81ba140e3 | ||
|
|
4ffdb500b9 | ||
|
|
609607b096 | ||
|
|
e9657668a9 | ||
|
|
1696cde273 | ||
|
|
94ffc35b25 | ||
|
|
5a1e5eb9c7 | ||
|
|
8c1f30b1c8 | ||
|
|
e3f402fc66 | ||
|
|
6616d09f47 | ||
|
|
25ad2ef946 | ||
|
|
ba4a1a9d45 | ||
|
|
3a37202dc5 | ||
|
|
12258324d3 | ||
|
|
2adb0b0807 | ||
|
|
19fc84007d | ||
|
|
8fcbd3671d | ||
|
|
0eadbef02d | ||
|
|
107ad1d3fc | ||
|
|
d2ba80e6e9 | ||
|
|
f18b38cde5 | ||
|
|
e6f1805df0 | ||
|
|
4da1b62542 | ||
|
|
852a586d5c | ||
|
|
e8a2d92785 | ||
|
|
50ed13e4ee | ||
|
|
cb9b737b9d | ||
|
|
700b46162c | ||
|
|
0e1153f610 | ||
|
|
8669ed2aac | ||
|
|
6d12ef291b | ||
|
|
ca0a36abcf | ||
|
|
4c6fdc905f | ||
|
|
cdbc4a123c | ||
|
|
bb7c02b07b | ||
|
|
4f42aeabd7 | ||
|
|
b77517ef64 | ||
|
|
b9c3f750eb | ||
|
|
aaecbfab17 | ||
|
|
c4539aa603 | ||
|
|
7f801319bf | ||
|
|
1a990f4563 | ||
|
|
944a328f30 | ||
|
|
e11b60d812 | ||
|
|
c91e99b782 | ||
|
|
da8ec1e4ab | ||
|
|
c8d5199815 | ||
|
|
e7868f0fb1 | ||
|
|
eca46dbd85 | ||
|
|
67bd5d026f | ||
|
|
51de67cc73 | ||
|
|
3d4f9cd919 | ||
|
|
cd8d397e63 | ||
|
|
5a9c099188 | ||
|
|
2137089a70 | ||
|
|
fbd02852a3 | ||
|
|
f2584ade24 | ||
|
|
2f72cd4b7d | ||
|
|
50bfd14968 | ||
|
|
2ff53fc448 | ||
|
|
42cd2e584f | ||
|
|
49de3cca62 | ||
|
|
718db0309f | ||
|
|
d867095f50 | ||
|
|
e51bf20e72 | ||
|
|
89286e628b | ||
|
|
c8042b4781 | ||
|
|
15f8a30cd4 | ||
|
|
9fdd96c92b | ||
|
|
ce15df27ca | ||
|
|
468657bfe2 | ||
|
|
814180d129 | ||
|
|
93be2fef6d | ||
|
|
3ab71f27ff | ||
|
|
38fa1b6858 | ||
|
|
c6ed215260 | ||
|
|
74eba8d2e8 | ||
|
|
5a72dae2c8 | ||
|
|
6194821643 | ||
|
|
37aab9c72e | ||
|
|
0a0dc8cef9 | ||
|
|
c6d89b79b4 | ||
|
|
8a435dff27 | ||
|
|
459925eba7 | ||
|
|
6614a43658 | ||
|
|
88fd65ae34 | ||
|
|
83da088024 | ||
|
|
51a986d0d4 | ||
|
|
0aefe8fc0e | ||
|
|
2845984169 | ||
|
|
2a91dc5fb1 | ||
|
|
5eca9274ee | ||
|
|
d57d81ca85 | ||
|
|
a5dcf9cc24 | ||
|
|
484c8985ed | ||
|
|
931b0a8905 | ||
|
|
bfd1e93325 | ||
|
|
bf23751549 | ||
|
|
b79034fbb9 | ||
|
|
eaa05ac6c1 | ||
|
|
8f0a3d727e | ||
|
|
b6a524e6b4 | ||
|
|
43d00deb88 | ||
|
|
4836a0cae9 | ||
|
|
302c4ade51 | ||
|
|
75d80e014a | ||
|
|
0f790f4293 | ||
|
|
452217e9fa | ||
|
|
f66c0cfe5c | ||
|
|
30898c13d3 | ||
|
|
2330d59ffa | ||
|
|
1316be57dc | ||
|
|
b7c19695e7 | ||
|
|
b85cf2683c | ||
|
|
ff0f2a8f83 | ||
|
|
7e5184d342 | ||
|
|
8fa1fd55e9 | ||
|
|
52463dea09 | ||
|
|
8cf09f5444 | ||
|
|
20a6190ed8 | ||
|
|
402a9f3017 | ||
|
|
af09872fba | ||
|
|
2311d7dc44 | ||
|
|
b261bf8a76 | ||
|
|
140c6d963f | ||
|
|
0c5e457359 | ||
|
|
bfa4295606 | ||
|
|
8ac68ede5d | ||
|
|
a019f887e9 | ||
|
|
eba2c69308 | ||
|
|
8df5970300 | ||
|
|
db265d471f | ||
|
|
0bb1536c99 | ||
|
|
64eb7d598a | ||
|
|
df8e5a16be | ||
|
|
3ce2dd3989 | ||
|
|
99105fbb57 | ||
|
|
96f1e98859 | ||
|
|
d614b057c9 | ||
|
|
aafe02f3e9 | ||
|
|
0441e16bdb | ||
|
|
30a489535e | ||
|
|
ac88ece259 | ||
|
|
9b45c76744 | ||
|
|
059a5f83b7 | ||
|
|
cf5cd61995 | ||
|
|
a499cc5103 | ||
|
|
123779bbd1 | ||
|
|
5365c7b428 | ||
|
|
da961a9c42 | ||
|
|
8ff0e0e2d1 | ||
|
|
ffde6bd228 | ||
|
|
bebb4fb33b | ||
|
|
2c243ea5b7 | ||
|
|
498fe84b99 | ||
|
|
9b8b66ed83 | ||
|
|
9cc3dd4c92 | ||
|
|
bf23d81c9e | ||
|
|
f53100d8d3 | ||
|
|
acbe60cdf1 | ||
|
|
4c7f37e0f8 | ||
|
|
3ba696937c | ||
|
|
1647994471 | ||
|
|
674e09dc56 | ||
|
|
4c129d470f | ||
|
|
c630f01baa | ||
|
|
6018fc13b2 | ||
|
|
c4fc6cd0e2 | ||
|
|
eed8735238 | ||
|
|
8c0155e8bd | ||
|
|
b2d4412e59 | ||
|
|
4e3e45a88b | ||
|
|
af9b386d8a | ||
|
|
201b8a3bc6 | ||
|
|
6e1a994c26 | ||
|
|
2ccc05cb98 | ||
|
|
e7d22ffb11 | ||
|
|
4805c3615b | ||
|
|
44a5260050 | ||
|
|
d72d01823d | ||
|
|
1e166189ba | ||
|
|
66310523d1 | ||
|
|
87a041a212 | ||
|
|
9c52ec2751 | ||
|
|
9010269236 | ||
|
|
aac254d275 | ||
|
|
889b54f309 | ||
|
|
5d13ffda09 | ||
|
|
31b6d5971c | ||
|
|
304b6393d4 | ||
|
|
490f63a838 | ||
|
|
64d990ba10 | ||
|
|
cb019c405b | ||
|
|
26f80d25be | ||
|
|
fe9a1bb5fc | ||
|
|
79679f9b08 | ||
|
|
5ef5403d69 | ||
|
|
23afb3a129 | ||
|
|
fac08cf835 | ||
|
|
dd67cc7de0 | ||
|
|
8531534241 | ||
|
|
0993621bb8 | ||
|
|
45fe5c37cc | ||
|
|
35b60d8d89 | ||
|
|
63b4d37207 | ||
|
|
793268ed54 | ||
|
|
a4a05a5413 | ||
|
|
821979bab1 | ||
|
|
69be742619 | ||
|
|
298982b522 | ||
|
|
9f2b3d1cd4 | ||
|
|
800119fc92 | ||
|
|
725fc26880 | ||
|
|
ed27e87540 | ||
|
|
4fc2b5cf76 | ||
|
|
749d46930d | ||
|
|
7acafc26d6 | ||
|
|
2817936b87 | ||
|
|
022c5a8401 | ||
|
|
50fd944a62 | ||
|
|
9c9cd8164b | ||
|
|
8744449016 | ||
|
|
a23f66d889 | ||
|
|
a1596bb63c | ||
|
|
ada6fc18d9 | ||
|
|
19af145166 | ||
|
|
4ed81be0c6 | ||
|
|
1c62adcdb6 | ||
|
|
95f46930a5 | ||
|
|
50b0186c06 | ||
|
|
2c9d847a1d | ||
|
|
816cdda6bb | ||
|
|
76dd504589 | ||
|
|
938c69c816 | ||
|
|
d5fc402a89 | ||
|
|
065a7a1f1b | ||
|
|
833f97198e | ||
|
|
293d5cc02b | ||
|
|
dbb302f22a | ||
|
|
ccadffea73 | ||
|
|
b3390ce201 | ||
|
|
6039f6c691 | ||
|
|
c65cdc8699 | ||
|
|
7603886e04 | ||
|
|
406a96e4d1 | ||
|
|
87d21e7968 | ||
|
|
9dd79a8061 | ||
|
|
a1287416d4 | ||
|
|
00dc877f0a | ||
|
|
335081053d | ||
|
|
7d74d7d8f6 | ||
|
|
e98d8139bc | ||
|
|
4af22cfbc0 | ||
|
|
8a47aab01d | ||
|
|
395b208a0c | ||
|
|
ab4f8a0e39 | ||
|
|
7e110603b5 | ||
|
|
94455192ad | ||
|
|
c4ca24a537 | ||
|
|
ea1f5d1ff0 | ||
|
|
77b7355433 | ||
|
|
f6178c2f75 | ||
|
|
f1e04e5629 | ||
|
|
cc913a728a | ||
|
|
e727566741 | ||
|
|
0f68da4eb8 | ||
|
|
1a7abfd3b7 | ||
|
|
905c2775d2 | ||
|
|
126da9ee12 | ||
|
|
1080cb71c4 | ||
|
|
39a295901a | ||
|
|
7e55b0b099 | ||
|
|
f8c179b153 | ||
|
|
b4aa90b402 | ||
|
|
bea46fb879 | ||
|
|
379de05a61 | ||
|
|
a1ecf8a413 | ||
|
|
4d59d266c1 | ||
|
|
c2f222760a | ||
|
|
7e0a2ea4cb | ||
|
|
912808b672 | ||
|
|
a352d51711 | ||
|
|
4ad5ed64d7 | ||
|
|
3838a3b4fb | ||
|
|
7d748ae15e | ||
|
|
9aef3b7f1d | ||
|
|
9dab389b50 | ||
|
|
260b4adb8c | ||
|
|
c93bbbd302 | ||
|
|
009e5ce0c8 | ||
|
|
61bb4f53c0 | ||
|
|
182d92f9bd | ||
|
|
61a68a9e38 | ||
|
|
b6e33d70c8 | ||
|
|
7a26bf1a10 | ||
|
|
b6dd5e445e | ||
|
|
6f4b77a440 | ||
|
|
463584ea10 | ||
|
|
fd8d603831 | ||
|
|
a1ec83b002 | ||
|
|
041d3f2843 | ||
|
|
0b22127906 | ||
|
|
0b0b507827 | ||
|
|
df1a87eb4e | ||
|
|
16de289942 | ||
|
|
e203b1aa9a | ||
|
|
02dc97e413 | ||
|
|
f458114c5b | ||
|
|
8db09d2fed | ||
|
|
0ce7053598 | ||
|
|
6a96815c44 | ||
|
|
d7b0db41f4 | ||
|
|
9c9f3e7055 | ||
|
|
2f6d680b6c | ||
|
|
639f7939a3 | ||
|
|
95ce9cbf0c | ||
|
|
1e0ef941c7 | ||
|
|
7e5bd64885 | ||
|
|
de023bc6ea | ||
|
|
c7df6f50ca | ||
|
|
df71d251f0 | ||
|
|
0b9acc18cc | ||
|
|
58a7de3136 | ||
|
|
5bb77b1e03 | ||
|
|
e351322ce4 | ||
|
|
6b53ccc8bd | ||
|
|
33842b6f92 | ||
|
|
5e747b2cfd | ||
|
|
3f8de0efb9 | ||
|
|
63da3e4595 | ||
|
|
a04b69dc6a | ||
|
|
3be4764d54 | ||
|
|
2d4fec01b1 | ||
|
|
85c50eb542 | ||
|
|
ee62d00c96 | ||
|
|
52a32f0887 | ||
|
|
dd30be90ad | ||
|
|
4cb027eb73 | ||
|
|
8e0b8f2faf | ||
|
|
39491b78b1 | ||
|
|
7c82da8389 | ||
|
|
d5c13603a0 | ||
|
|
aad253bfad | ||
|
|
dac055e2ef | ||
|
|
85df5b9983 | ||
|
|
537cd42097 | ||
|
|
9d06fce5f9 | ||
|
|
c029e1005f | ||
|
|
b245a3d611 | ||
|
|
11d89c4268 | ||
|
|
6be84ab93e | ||
|
|
2f2c4d6740 | ||
|
|
703eae72eb | ||
|
|
6a629e963c | ||
|
|
06f4d0c117 | ||
|
|
b5e557ffb0 | ||
|
|
8bd6c4a335 | ||
|
|
29eaff9edc | ||
|
|
08afaf7fa5 | ||
|
|
45bab9fe71 | ||
|
|
514eb8f0e3 | ||
|
|
a7baa58c22 | ||
|
|
e548d8b1a5 | ||
|
|
92ff0fe624 | ||
|
|
a464f5a88e | ||
|
|
962a565d30 | ||
|
|
f242e60c1a | ||
|
|
7db50391f2 | ||
|
|
8b0d55a729 | ||
|
|
de6f341f41 | ||
|
|
c9fb530dbf | ||
|
|
836bcd09ec | ||
|
|
52a6836872 | ||
|
|
c00cadb37a | ||
|
|
b26c072f0d | ||
|
|
c99482f59d | ||
|
|
4aa0f567c3 | ||
|
|
4656021902 | ||
|
|
3df6144b77 | ||
|
|
6d335abe21 | ||
|
|
179b8a28b4 | ||
|
|
c620004168 | ||
|
|
893ff3e9d7 | ||
|
|
eec9a3cb8f | ||
|
|
d3c8042102 | ||
|
|
e590b44c77 | ||
|
|
e97bf479fb | ||
|
|
fe2f71c9b8 | ||
|
|
ee6c483dd4 | ||
|
|
e83ab86f1f | ||
|
|
ef237fc521 | ||
|
|
fd4d68038b | ||
|
|
8e458c21e9 | ||
|
|
4ab36cb3bc | ||
|
|
2d149f3a09 | ||
|
|
dfd2c7a3d2 | ||
|
|
6637762aec | ||
|
|
615eba3b40 | ||
|
|
dc183125fc | ||
|
|
c3b69d1201 | ||
|
|
3e1a50ab9a | ||
|
|
7565c71eb2 | ||
|
|
d743352bc0 | ||
|
|
75ca72e3a8 | ||
|
|
59d26c6825 | ||
|
|
5eed363e10 | ||
|
|
49b2fdbde9 | ||
|
|
623f6e9542 | ||
|
|
32356f23d3 | ||
|
|
321ddabfd5 | ||
|
|
bf93a6a1ab | ||
|
|
91aa5dc6dd | ||
|
|
56ed46b99a | ||
|
|
daaf21a4fe | ||
|
|
06a8f2afab | ||
|
|
cc04530c4a | ||
|
|
0b6f62977a | ||
|
|
2a2996c22b | ||
|
|
254aba0995 | ||
|
|
23a81b3121 | ||
|
|
c4659f816f | ||
|
|
fc13328e2a | ||
|
|
d1427e7d2e | ||
|
|
5584d1062e | ||
|
|
b3f28fac64 | ||
|
|
f65af7a308 | ||
|
|
559f50a3e3 | ||
|
|
18b809314c | ||
|
|
aa1f819c0d | ||
|
|
5a8cecf499 | ||
|
|
79f362abee | ||
|
|
42db74b522 | ||
|
|
8cb41fe5fb | ||
|
|
cd893fec15 | ||
|
|
3309e9f53f | ||
|
|
ae3a017143 | ||
|
|
2a01f178da | ||
|
|
a069d1e07d | ||
|
|
76fa7f5200 | ||
|
|
7a0a86d51c | ||
|
|
8e283e43db | ||
|
|
794744d5a3 | ||
|
|
5c3e69b045 | ||
|
|
9cbd595cfd | ||
|
|
a5074eca7d | ||
|
|
9386b117c1 | ||
|
|
7738248230 | ||
|
|
85f1f808d3 | ||
|
|
6dbafa22bb | ||
|
|
cadcd37681 | ||
|
|
a45ea6e1d8 | ||
|
|
187f24de81 | ||
|
|
8df1f48226 | ||
|
|
7dbf332a94 | ||
|
|
c09ddf6de1 | ||
|
|
9b5fa99d6a | ||
|
|
b9abf32007 | ||
|
|
09ecb80625 | ||
|
|
c4e9a0e340 | ||
|
|
b6cf4e1826 | ||
|
|
ecb1619399 | ||
|
|
83f4b7b699 | ||
|
|
9b81ddf4d5 | ||
|
|
4af17f0e40 | ||
|
|
2fbc036e69 | ||
|
|
d236a12b8f | ||
|
|
232be333ad | ||
|
|
192e5af797 | ||
|
|
deb39b8f34 | ||
|
|
197b41d97a | ||
|
|
7b11a57c6f | ||
|
|
eac7945fae | ||
|
|
1177d2263f | ||
|
|
b9478a1f65 | ||
|
|
025cf91679 | ||
|
|
442aa72ccc | ||
|
|
1c09f9c82d | ||
|
|
c6d2f633ea | ||
|
|
17bd60e3e9 | ||
|
|
1d24e82276 | ||
|
|
43d7a11ba8 | ||
|
|
02e12e17d6 | ||
|
|
e42d3d5620 | ||
|
|
5c83972401 | ||
|
|
b8df18481f | ||
|
|
1690dd4728 | ||
|
|
a86087ed7c | ||
|
|
745060f0b5 | ||
|
|
0a0a490a38 | ||
|
|
4f838685d6 | ||
|
|
6339ba09f0 | ||
|
|
f816a5b0da | ||
|
|
2f02e49716 | ||
|
|
a98a0b1ac2 | ||
|
|
034326c984 | ||
|
|
a965b05400 | ||
|
|
23c2e82c97 | ||
|
|
6c2de4a359 | ||
|
|
e9588279c8 | ||
|
|
7138d3518e | ||
|
|
f852325906 | ||
|
|
3c9082ece3 | ||
|
|
efe3a78499 | ||
|
|
98c77ffe18 | ||
|
|
31969a4939 | ||
|
|
b95d5f9f23 | ||
|
|
adf59d78d7 | ||
|
|
904ae3eab7 | ||
|
|
44d2309700 | ||
|
|
5dd6a3883a | ||
|
|
7a00c5ac71 | ||
|
|
23fbbb5191 | ||
|
|
a58b1ccfa5 | ||
|
|
5f0a3fe1c1 | ||
|
|
37b0a5c04c | ||
|
|
3fb4f60192 | ||
|
|
635fa84731 | ||
|
|
410bf4f0cd | ||
|
|
eebe115b78 | ||
|
|
70eb9f0678 | ||
|
|
b9de179fe8 | ||
|
|
ac29e24c1b | ||
|
|
d83572803d | ||
|
|
87faa4f108 | ||
|
|
ea3a0d64c1 | ||
|
|
8288d2f38b | ||
|
|
ff817dad0d | ||
|
|
ba554d5f45 | ||
|
|
90922a0ce0 | ||
|
|
a91cb546f9 | ||
|
|
3cb21d128f | ||
|
|
1b8d5d0648 | ||
|
|
03f035cdf0 | ||
|
|
ac95654409 | ||
|
|
ba33bb6aa4 | ||
|
|
2898c0507e | ||
|
|
d59edd6cca | ||
|
|
bc3079332c | ||
|
|
3c0395b19f | ||
|
|
9e7b591c78 | ||
|
|
b6107a1198 | ||
|
|
2d94018f12 | ||
|
|
42f0268829 | ||
|
|
74d568b1e7 | ||
|
|
0316fedd4c | ||
|
|
5247d93d7b | ||
|
|
bda5312917 | ||
|
|
e8c071304c | ||
|
|
4e155caae9 | ||
|
|
aedb7e44ba | ||
|
|
c58109c1b4 | ||
|
|
2167c7b6d4 | ||
|
|
22eef989f6 | ||
|
|
edf387363d | ||
|
|
14ffb7443f | ||
|
|
c21ba1e64c | ||
|
|
46b8069c6d | ||
|
|
2fb697f452 | ||
|
|
73f3293314 | ||
|
|
53fc25550b | ||
|
|
961d1775e5 | ||
|
|
bdaa359d11 | ||
|
|
a90cc018dd | ||
|
|
e06f784d35 | ||
|
|
5ce1b6a4c1 | ||
|
|
86d579a7ae | ||
|
|
d031ab5ceb | ||
|
|
dcf7230494 | ||
|
|
20aca45b39 | ||
|
|
4812c380c4 | ||
|
|
98ea43eca9 | ||
|
|
cd541c7a20 | ||
|
|
5a5cf31aba | ||
|
|
3074711828 | ||
|
|
aa97c928e9 | ||
|
|
5b4d6f2fee | ||
|
|
0e833c155a | ||
|
|
9ebb1b17d1 | ||
|
|
3397cf053c | ||
|
|
6e73b5934e | ||
|
|
7120ad5014 | ||
|
|
6286cfac28 | ||
|
|
1af09da2aa | ||
|
|
bea533acf8 | ||
|
|
5316c2479e | ||
|
|
9895f8c71e | ||
|
|
9749a398c0 | ||
|
|
2883a278ee | ||
|
|
6bbb9ec956 | ||
|
|
630556f7fe | ||
|
|
32a79c4fa1 | ||
|
|
eabfee6890 | ||
|
|
6b9b283149 | ||
|
|
a19ad6663c | ||
|
|
dfae97a8d7 | ||
|
|
93d03434eb | ||
|
|
76fcd341f6 | ||
|
|
cea53ddd1f | ||
|
|
cfc061c960 | ||
|
|
09bc1784e4 | ||
|
|
b723cf92e7 | ||
|
|
3d7b9f60da | ||
|
|
b049bdb33f | ||
|
|
a5c49d89d5 | ||
|
|
1f9a92e6ad | ||
|
|
6280611aea | ||
|
|
20c0e6e12b | ||
|
|
9aa6c2bd9f | ||
|
|
4450cce0e9 | ||
|
|
523cd421b3 | ||
|
|
88dbbe7bc3 | ||
|
|
cc63a633b5 | ||
|
|
72578e49dd | ||
|
|
83f1edb9da | ||
|
|
8016bd4e1f | ||
|
|
cb8b25da53 | ||
|
|
c517b98bae | ||
|
|
d66876a9c9 | ||
|
|
ad31df09fb | ||
|
|
1831e507fe | ||
|
|
b12a58632d | ||
|
|
8442373be9 | ||
|
|
0f7a9e5a74 | ||
|
|
74bce91db8 | ||
|
|
469b74ffb3 | ||
|
|
5dd0775737 | ||
|
|
33ed5402f4 | ||
|
|
aa655dadc4 | ||
|
|
0828025450 | ||
|
|
d9db3b695c | ||
|
|
c3e6199ecf | ||
|
|
926b9e0bfd | ||
|
|
05ba2ee2f2 | ||
|
|
cd865e0a0a | ||
|
|
08af876e01 | ||
|
|
a33fb05946 | ||
|
|
de52fa564b | ||
|
|
8e13d406d4 | ||
|
|
504f738cff | ||
|
|
fde7965bc9 | ||
|
|
d3ccc73796 | ||
|
|
a1154bf383 | ||
|
|
c9cf6d157b | ||
|
|
ef2f637d01 | ||
|
|
d130c73e77 | ||
|
|
3ecc389e66 | ||
|
|
3dbddfba41 | ||
|
|
e6cb497d1a | ||
|
|
703ac13185 | ||
|
|
a3e1c86953 | ||
|
|
3d64222655 | ||
|
|
5eb29fa99c | ||
|
|
84a24b76c7 | ||
|
|
89c2a64008 | ||
|
|
c1f992b11f | ||
|
|
ea60442fd6 | ||
|
|
d78c5fd7c2 | ||
|
|
3b98e4962a | ||
|
|
f739a1141d | ||
|
|
c498e9437e | ||
|
|
9f9a7c6b38 | ||
|
|
e3d2949c46 | ||
|
|
53f563ec08 | ||
|
|
d27c36c70c | ||
|
|
820834111b | ||
|
|
0c7b09c237 | ||
|
|
6eb8bb6241 | ||
|
|
ce0b18045b | ||
|
|
10d2d566a3 | ||
|
|
9c404185e8 | ||
|
|
3044c16ce1 | ||
|
|
729ef0190e | ||
|
|
3aab16f6db | ||
|
|
0682882ac1 | ||
|
|
da46cd78a3 | ||
|
|
f3cca3483d | ||
|
|
40dbb0ffaf | ||
|
|
53d3ac570e | ||
|
|
237022baae | ||
|
|
b11ef97b7d | ||
|
|
bccfd7bbbb | ||
|
|
634ed4a341 | ||
|
|
52aa87c145 | ||
|
|
597853cd6c | ||
|
|
1bd6568f94 | ||
|
|
4b2235aef2 | ||
|
|
faf1c26669 | ||
|
|
3aea5fb704 | ||
|
|
ea559592b5 | ||
|
|
c385c08e2f | ||
|
|
a74b925173 | ||
|
|
e84f71cd37 | ||
|
|
bc6428536c | ||
|
|
1c47a0e1a0 | ||
|
|
4d3e2f4fd3 | ||
|
|
a3430f7ce6 | ||
|
|
247b7ee1ab | ||
|
|
58eafce947 | ||
|
|
ed25cf9d23 | ||
|
|
8992c74d32 | ||
|
|
01f56c515b | ||
|
|
864d3a3b2f | ||
|
|
d68d2a4b18 | ||
|
|
d24da615b3 | ||
|
|
84c693ad22 | ||
|
|
747cbc1442 | ||
|
|
722cc54338 | ||
|
|
21abf0d215 | ||
|
|
83cb1b05d9 | ||
|
|
83d4c04646 | ||
|
|
0a7f601dec | ||
|
|
1d079c0879 | ||
|
|
3df4b5b28f | ||
|
|
14dc86e9ea | ||
|
|
b64d8bfab3 | ||
|
|
b41c8ad364 | ||
|
|
03c6709254 | ||
|
|
7a6fb46841 | ||
|
|
5b43407388 | ||
|
|
0e05301588 | ||
|
|
7a501164a9 | ||
|
|
b632984874 | ||
|
|
94407079bf | ||
|
|
57ab7ee6f2 | ||
|
|
62cf372d81 | ||
|
|
d3991ee672 | ||
|
|
b4603069bf | ||
|
|
60c522a696 | ||
|
|
99b0c8974b | ||
|
|
6ae2c8497f | ||
|
|
01b7509e61 | ||
|
|
194a09f21d | ||
|
|
b87b8ea931 | ||
|
|
ab7e7ac12a | ||
|
|
3788e8d7b3 | ||
|
|
041290e1c7 | ||
|
|
1099e786df | ||
|
|
be95169c1b | ||
|
|
a899cb48b3 | ||
|
|
ed8ac01f07 | ||
|
|
12cde3ddce | ||
|
|
860d70551f | ||
|
|
6db6fcc414 | ||
|
|
25c229de73 | ||
|
|
d954a54017 | ||
|
|
78bbf1f04f | ||
|
|
52938202bd | ||
|
|
0f29818030 | ||
|
|
dd39a25dd0 | ||
|
|
6ed4be9135 | ||
|
|
02b6a21276 | ||
|
|
794ca573b8 | ||
|
|
032f771996 | ||
|
|
3dfd7a9ab1 | ||
|
|
1713e5e2eb | ||
|
|
1d7342573b | ||
|
|
64fc295ecc | ||
|
|
6b6dc8311a | ||
|
|
b1d8c3c1e3 | ||
|
|
71037cb482 | ||
|
|
1f4e5cadd2 | ||
|
|
0de9cc82f6 | ||
|
|
7dba46df9b | ||
|
|
9cb09feb65 | ||
|
|
fb084fa4cd | ||
|
|
846b8fb57e | ||
|
|
cb649830a0 | ||
|
|
89510f40d3 | ||
|
|
9f2207eb1f | ||
|
|
dfb18b305d | ||
|
|
1606395546 | ||
|
|
8dbd79d49b | ||
|
|
e2c67fa25a | ||
|
|
cf85177c7f | ||
|
|
bc4a0f448b | ||
|
|
14ef86456f | ||
|
|
12efc85baf | ||
|
|
68124dfdbe | ||
|
|
ee4158e90b | ||
|
|
0b3b7efccf | ||
|
|
6064269936 | ||
|
|
d0929896cf | ||
|
|
990e87de1f | ||
|
|
8da47dcd00 | ||
|
|
c63d88d987 | ||
|
|
c21bde192b | ||
|
|
39f1f8aff5 | ||
|
|
8b699c58ae | ||
|
|
743a97c784 | ||
|
|
ea7ae5698a | ||
|
|
3ed9b3ec39 | ||
|
|
e8f3e3b88a | ||
|
|
82d16fbfde | ||
|
|
766dcd0dd5 | ||
|
|
87302d6d86 | ||
|
|
05b94d1d15 | ||
|
|
ed0c93aec3 | ||
|
|
03b4467173 | ||
|
|
f027cc6a3e | ||
|
|
634ce6829a | ||
|
|
64b5f9af78 | ||
|
|
9269fcb8a7 | ||
|
|
f0d29cb755 | ||
|
|
897e0f1ba6 | ||
|
|
4cfa94d304 | ||
|
|
5e2abb8a33 | ||
|
|
0dc5052e36 | ||
|
|
774ad1e2ff | ||
|
|
52e91cc309 | ||
|
|
d3e6274939 | ||
|
|
ec904eb8a4 | ||
|
|
95a09c5463 | ||
|
|
125fb598d5 | ||
|
|
f8c13f939c | ||
|
|
c846b24ebb | ||
|
|
85324d9109 | ||
|
|
10b410d46f | ||
|
|
c87fe7c265 | ||
|
|
ce0984573b | ||
|
|
b38c3a5035 | ||
|
|
15dca65bd1 | ||
|
|
e1aa43147d | ||
|
|
057b18e4be | ||
|
|
d4f2ced6a3 | ||
|
|
0b6c92fcd2 | ||
|
|
4491e71ee2 | ||
|
|
d09f78801c | ||
|
|
f26ea32897 | ||
|
|
86dbea7ddb | ||
|
|
4221ddbb35 | ||
|
|
eeb0c22d90 | ||
|
|
eb801e66ae | ||
|
|
4d0d4ca6ea | ||
|
|
56cdae67c3 | ||
|
|
b50017cad4 | ||
|
|
c85c38cde3 | ||
|
|
f606eda18d | ||
|
|
08c9e2dde3 | ||
|
|
882bf7b020 | ||
|
|
da4e70bc60 | ||
|
|
f75f720c8a | ||
|
|
8d3aff5ff1 | ||
|
|
4e8c9078f7 | ||
|
|
41e4efcf1f | ||
|
|
f55e6138a5 | ||
|
|
147e24d835 | ||
|
|
4a94858ed1 | ||
|
|
12c90bae04 | ||
|
|
6f7f10b2f7 | ||
|
|
430a2ea2f6 | ||
|
|
87569617ae | ||
|
|
b17beaccf1 | ||
|
|
cddba64151 | ||
|
|
a006bfeb24 | ||
|
|
71e1a8666d | ||
|
|
16e7872a82 | ||
|
|
aa4ebb07f8 | ||
|
|
4366d6a8c7 | ||
|
|
aa76d49234 | ||
|
|
d9df06644e | ||
|
|
554ee01263 | ||
|
|
b3055067d8 | ||
|
|
7f997d4b59 | ||
|
|
d2d959f455 | ||
|
|
a9e497f878 | ||
|
|
e423e9ffba | ||
|
|
ff99fae928 | ||
|
|
3c9983ca12 | ||
|
|
d3412e7de6 | ||
|
|
2841942899 | ||
|
|
415e79b523 | ||
|
|
9a6fdaa42b | ||
|
|
0cdbe998cb | ||
|
|
35b0c49da5 | ||
|
|
d43c9f006b | ||
|
|
01a6ae61d2 | ||
|
|
4b4b233377 | ||
|
|
ccc9907034 | ||
|
|
26520abe2b | ||
|
|
1397c3248d | ||
|
|
c40dc39b88 | ||
|
|
a2753bb27d | ||
|
|
1c5529691b | ||
|
|
8e5bdc6b2b | ||
|
|
39324d6b55 | ||
|
|
b1ad187d1b | ||
|
|
606f15fec5 | ||
|
|
09a0eb26d1 | ||
|
|
bf9e8048ff | ||
|
|
21ebc226e4 | ||
|
|
8e3fef9096 | ||
|
|
829dccc1b6 | ||
|
|
a65caa62b3 | ||
|
|
ddb6f9c5b4 | ||
|
|
e152ab6cf2 | ||
|
|
4085af023a | ||
|
|
686e401368 | ||
|
|
2fdfa64b13 | ||
|
|
f406cfcebb | ||
|
|
80f35725e6 | ||
|
|
6741d99681 | ||
|
|
ad4ec14778 | ||
|
|
2bf16ad88b | ||
|
|
6c56581c15 | ||
|
|
ce89d9fbe0 | ||
|
|
e298f74310 | ||
|
|
c550c1373e | ||
|
|
6a1bb88c3b | ||
|
|
a585e96fdf | ||
|
|
e78ef493a1 | ||
|
|
c139378694 | ||
|
|
d0eb3e760f | ||
|
|
9cfa3e5002 | ||
|
|
82278037ec | ||
|
|
0b592f86d0 | ||
|
|
ee4e003c2d | ||
|
|
b2904bc6fb | ||
|
|
67b94cf52e | ||
|
|
c308d2c9dd | ||
|
|
e36370b080 | ||
|
|
d0f005a6f1 | ||
|
|
a461fa9137 | ||
|
|
22e969fb59 | ||
|
|
34527c8395 | ||
|
|
012f4d68bc | ||
|
|
724283433a | ||
|
|
aea19b93b1 | ||
|
|
73020a711d | ||
|
|
7e62e671e3 | ||
|
|
2e845ac0ab | ||
|
|
2df41e52ed | ||
|
|
bf8e93f581 | ||
|
|
f5eec3283c | ||
|
|
223161c7d6 | ||
|
|
b8ba6e4827 | ||
|
|
15c8259ac2 | ||
|
|
720492932f | ||
|
|
a08a0fb084 | ||
|
|
827fbaac1f | ||
|
|
297224bd31 | ||
|
|
9dc835c60c | ||
|
|
67a96bc2f3 | ||
|
|
ff5bf16111 | ||
|
|
8d22059462 | ||
|
|
91d144f5f7 | ||
|
|
c894b1d335 | ||
|
|
d30a7bf6a1 | ||
|
|
649d5f56c9 | ||
|
|
36b033c2f7 | ||
|
|
dc9bce915b | ||
|
|
c9a7cfafd0 | ||
|
|
9d9585ecba | ||
|
|
0ebd7e6a58 | ||
|
|
a100abc3b6 | ||
|
|
94f6945d5a | ||
|
|
442d771a7a | ||
|
|
242e11eefc | ||
|
|
7fbbae8cd4 | ||
|
|
b80d96d9c7 | ||
|
|
d8e69360b9 | ||
|
|
83ae9b66a3 | ||
|
|
4ac052c10b | ||
|
|
f1717f8319 | ||
|
|
cb000549bd | ||
|
|
2712aa2ae2 | ||
|
|
7dcefa6bee | ||
|
|
70e3528809 | ||
|
|
c7780a2708 | ||
|
|
26bab84d04 | ||
|
|
efea6136e7 | ||
|
|
c56026c18a | ||
|
|
1d9504d0f0 | ||
|
|
780b1f8acc | ||
|
|
9b6c5741de | ||
|
|
0742e18edd | ||
|
|
cb59c2489b | ||
|
|
3158b544d5 | ||
|
|
e80270d1fa | ||
|
|
99b37f24bb | ||
|
|
fdbdcc4130 | ||
|
|
08104966b2 | ||
|
|
1c99133177 | ||
|
|
28780dc67e | ||
|
|
423ce54d8a | ||
|
|
73bab73db6 | ||
|
|
3e90471fa2 | ||
|
|
7f2db8a9a7 | ||
|
|
d5fc147ffd | ||
|
|
77ffd7bbf9 | ||
|
|
42775d3477 | ||
|
|
6932b8c378 | ||
|
|
cff641ef80 | ||
|
|
373abf1b24 | ||
|
|
f668596667 | ||
|
|
93e0e815d7 | ||
|
|
05275c8938 | ||
|
|
19475db7dd | ||
|
|
aa315d7c97 | ||
|
|
080b25e30c | ||
|
|
a7c8c08183 | ||
|
|
bb98627d2b | ||
|
|
3060866586 | ||
|
|
eacf121f78 | ||
|
|
c39535fdd0 | ||
|
|
c3311df2a8 | ||
|
|
5a17314b2c | ||
|
|
07281f050c | ||
|
|
9c3757fb0c | ||
|
|
f5d5e59040 | ||
|
|
70880c066f | ||
|
|
5508c70f3a |
@@ -13,3 +13,7 @@ trim_trailing_whitespace = false
|
||||
|
||||
[**.std]
|
||||
insert_final_newline = false
|
||||
|
||||
[{package,bower}.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
52
.eslintrc
Normal file
52
.eslintrc
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true,
|
||||
"mocha": true
|
||||
},
|
||||
"rules": {
|
||||
"no-bitwise": 0,
|
||||
"curly": 0,
|
||||
"eqeqeq": 0,
|
||||
"guard-for-in": 0,
|
||||
"no-use-before-define": 0,
|
||||
"no-caller": 2,
|
||||
"no-new": 2,
|
||||
"no-plusplus": 0,
|
||||
"no-undef": 2,
|
||||
"no-unused-vars": 0,
|
||||
"strict": 0,
|
||||
"semi": 0,
|
||||
"comma-spacing": 2,
|
||||
"quote-props": [2, "consistent", { "keywords": true }],
|
||||
"quotes": [2, "single", "avoid-escape"],
|
||||
"indent": [2, 4],
|
||||
"no-cond-assign": [ 2, "except-parens" ],
|
||||
"no-debugger": 2,
|
||||
"no-dupe-args": 2,
|
||||
"no-dupe-keys": 2,
|
||||
"no-duplicate-case": 2,
|
||||
"no-unreachable": 2,
|
||||
"valid-typeof": 2,
|
||||
"no-fallthrough": 2,
|
||||
"no-ex-assign": 2,
|
||||
"no-eq-null": 0,
|
||||
"no-eval": 0,
|
||||
"no-unused-expressions": 0,
|
||||
"block-scoped-var": 0,
|
||||
"no-iterator": 0,
|
||||
"no-loop-func": 2,
|
||||
"no-script-url": 0,
|
||||
"no-shadow": 0,
|
||||
"no-new-func": 2,
|
||||
"no-new-wrappers": 2,
|
||||
"no-invalid-this": 0,
|
||||
"space-before-blocks": [2, "always"],
|
||||
"space-before-function-paren": [2, {"anonymous": "always", "named": "never"}],
|
||||
"space-infix-ops": 2,
|
||||
"keyword-spacing": 2,
|
||||
"new-parens": 2,
|
||||
"no-multiple-empty-lines": [2, { max: 2}],
|
||||
"eol-last": 2,
|
||||
"no-trailing-spaces": 2
|
||||
}
|
||||
}
|
||||
44
.github/ISSUE_TEMPLATE.md
vendored
Normal file
44
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<!--
|
||||
|
||||
If you are reporting a new issue, make sure that we do not have any duplicates.
|
||||
You can ensure this by searching the issue list for this repository.
|
||||
|
||||
You are welcome to open issues to discuss important general topics concerning Bower.
|
||||
However for support questions, please consider using http://stackoverflow.com or
|
||||
asking for help in our Discord channel: https://discordapp.com/invite/0fFM7QF0KpZaDeN9
|
||||
|
||||
# BUG REPORT
|
||||
|
||||
Use the commands below to provide key information to reproduce:
|
||||
You do NOT have to include this information if this is a FEATURE REQUEST OR DISCUSSION
|
||||
|
||||
For more information about reporting bugs, see:
|
||||
https://github.com/bower/bower/wiki/Report-a-Bug
|
||||
|
||||
-->
|
||||
|
||||
**Output of `bower -v && npm -v && node -v`:**
|
||||
|
||||
```
|
||||
(paste your output here)
|
||||
```
|
||||
|
||||
**Additional environment details (proxy, private registry, etc.):**
|
||||
|
||||
|
||||
|
||||
**Steps to reproduce the issue:**
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
**Describe the results you received:**
|
||||
|
||||
|
||||
|
||||
**Describe the results you expected:**
|
||||
|
||||
|
||||
|
||||
**Additional information:**
|
||||
14
.gitignore
vendored
14
.gitignore
vendored
@@ -1,12 +1,2 @@
|
||||
/node_modules
|
||||
/npm-debug.log
|
||||
|
||||
/test/assets/temp
|
||||
/test/assets/temp2
|
||||
/test/assets/temp-resolve-cache
|
||||
/test/assets/package-*/
|
||||
/test/reports
|
||||
|
||||
/bower.json
|
||||
/component.json
|
||||
/bower_components
|
||||
npm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
33
.travis.yml
33
.travis.yml
@@ -1,6 +1,33 @@
|
||||
sudo: false
|
||||
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "0.10"
|
||||
- "0.8"
|
||||
before_script:
|
||||
- npm install grunt-cli -g
|
||||
- "0.11"
|
||||
- "0.12"
|
||||
- "4.0"
|
||||
- "4.1"
|
||||
- "4.2"
|
||||
- "5"
|
||||
- "6"
|
||||
|
||||
install:
|
||||
- node --version
|
||||
- npm --version
|
||||
- git --version
|
||||
- svn --version | head -n 1
|
||||
- npm install
|
||||
|
||||
os:
|
||||
- osx
|
||||
- linux
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- os: osx
|
||||
- env: "NODE_VERSION=0.11"
|
||||
|
||||
script:
|
||||
- npm test
|
||||
|
||||
327
CHANGELOG.md
327
CHANGELOG.md
@@ -1,5 +1,322 @@
|
||||
# Changelog
|
||||
|
||||
## 1.7.9 - 2016-04-05
|
||||
|
||||
- Show warnings for invalid bower.json fields
|
||||
- Update bower-json
|
||||
- Less strict validation on package name (allow spaces, slashes, and "@")
|
||||
|
||||
## 1.7.8 - 2016-04-04
|
||||
|
||||
- Don't ask for git credentials in non-interactive session, fixes #956 #1009
|
||||
- Prevent swallowing exceptions with programmatic api, fixes #2187
|
||||
- Update graceful-fs to 4.x in all dependences, fixes nodejs/node#5213
|
||||
- Resolve pluggable resolvers using cwd and fallback to global modules, fixes #1919
|
||||
- Upgrade handlebars to 4.0.5, closes #2195
|
||||
- Replace all % chatacters in defined scripts, instead of only first one, fixes #2174
|
||||
- Update opn package to fix issues with "bower open" command on Windows
|
||||
- Update bower-config
|
||||
- Do not interpolate environment variables in script hooks, fixes bower/config#47
|
||||
- Update bower-json
|
||||
- Validate package name more strictly and allow only latin letters, dots, dashes and underscores
|
||||
- Add support for "save" and "save-exact" in .bowerrc, #2161
|
||||
|
||||
## 1.7.7 - 2016-01-27
|
||||
|
||||
Revert locations of all files while still packaging `node_modules`.
|
||||
|
||||
It's because people are depending on internals of bower, like
|
||||
`bower/lib/renderers/StandardRenderer`. We want to preserve this
|
||||
implicit contract, but we discourage it. The only official way
|
||||
to use bower programmatically is through `require('bower')`.
|
||||
|
||||
## 1.7.6 - 2016-01-27
|
||||
|
||||
- Revert location of "bin/bower" as developers are using it directly ([#2157](https://github.com/bower/bower/issues/2157))
|
||||
Note: Correctly, you should use an alias created in `npm bin --global`.
|
||||
|
||||
## 1.7.5 - 2016-01-26
|
||||
|
||||
- Remove analytics from Bower, fixes ([#2150](https://github.com/bower/bower/pull/2150))
|
||||
- Default to ^ operator on `bower install --save` ([#2145](https://github.com/bower/bower/pull/2145))
|
||||
- Support absolute path in .bowerrc directory option ([#2130](https://github.com/bower/bower/pull/2130))
|
||||
- Display user's name upon `bower login` command ([#2133](https://github.com/bower/bower/pull/2133))
|
||||
- Decompress gzip files ([#2092](https://github.com/bower/bower/pull/2092))
|
||||
- Prevent name clashes in package extraction ([#2102](https://github.com/bower/bower/pull/2102))
|
||||
- When strictSsl is false, set GIT_SSL_NO_VERIFY=true ([#2129](https://github.com/bower/bower/issues/2129))
|
||||
- Distribute bower with npm@3 for better Windows support ([#2146](https://github.com/bower/bower/issues/2146))
|
||||
- Update request to 2.67.0 and fs-write-stream-atomic to 1.0.8
|
||||
- Documentation improvements
|
||||
|
||||
## 1.7.4 - 2016-01-21
|
||||
|
||||
Unpublished because of issue with npm distribution:
|
||||
https://github.com/npm/npm/issues/11227
|
||||
|
||||
## 1.7.3 - 2016-01-20
|
||||
|
||||
Unpublished because of issue with npm distribution:
|
||||
https://github.com/npm/npm/issues/11227
|
||||
|
||||
## 1.7.2 - 2015-12-31
|
||||
|
||||
- Lock "fs-write-stream-atomic" to 1.0.5
|
||||
|
||||
## 1.7.1 - 2015-12-11
|
||||
|
||||
- Rollback "Add `bower update --save` functionality", it causes issues and needs more testing
|
||||
- Fix backward-compatibility of `bower search --json` ([#2066](https://github.com/bower/bower/issues/2066))
|
||||
- Ignore prerelease versions from `bower info` output
|
||||
- Update update-notifier to 0.6.0
|
||||
- Better formatting of help messages (https://github.com/bower/bower/commit/de3e1089da80f47ea3667c5ab80d301cddfd8c3e)
|
||||
- Add help menu for update `--save` and `update --save-dev` (https://github.com/bower/bower/commit/612aaa88eb4d4b268b2d8665c338ac086af3a5b0)
|
||||
|
||||
## 1.7.0 - 2015-12-07
|
||||
|
||||
- Add `bower update --save` functionality ([#2035](https://github.com/bower/bower/issues/2035))
|
||||
- `bower search` shows help message when no package name is specified ([#2066](https://github.com/bower/bower/issues/2066))
|
||||
- Update only those packages that are explicitly requested by the user. Related Issues
|
||||
- [#256](https://github.com/bower/bower/issues/256)
|
||||
- [#924](https://github.com/bower/bower/issues/924)
|
||||
- [#1770](https://github.com/bower/bower/issues/1770)
|
||||
- Allow for @ in username for SVN on windows ([#1650](https://github.com/bower/bower/issues/1650))
|
||||
- Update bower config
|
||||
- Loads the .bowerrc file from the cwd specified on the command line
|
||||
- Allow the use of environment variables in .bowerrc ([#41](https://github.com/bower/config/issues/41))
|
||||
- Allow for array notation in ENV variables ([#44](https://github.com/bower/config/issues/44))
|
||||
|
||||
## 1.6.9 - 2015-12-04
|
||||
|
||||
- Change git version of fs-write-stream-atomic back to npm version ([#2079](https://github.com/bower/bower/issues/2079))
|
||||
|
||||
## 1.6.8 - 2015-11-27
|
||||
|
||||
- Use fs-write-stream-atomic for downloads
|
||||
- Improved downloader that properly cleans after itself
|
||||
- Fix shallow host detection ([#2040](https://github.com/bower/bower/pull/2040))
|
||||
- Upgrade to ([bower-config#1.2.3](https://github.com/bower/config/releases/tag/1.2.3))
|
||||
- Properly restore env variables if they are undefined at the beginning
|
||||
- Properly handle `default` setting for config.ca
|
||||
- Display proper error if .bowerrc is a directory instead of file
|
||||
|
||||
## 1.6.7 - 2015-11-26
|
||||
|
||||
- Bundless all the dependencies again
|
||||
|
||||
## 1.6.6 - 2015-11-25
|
||||
|
||||
- Fixes regression with the published npm version
|
||||
|
||||
## 1.6.5 - 2015-10-24
|
||||
|
||||
- Updates to tests and documentation
|
||||
- Fixes passing options when requesting downloads
|
||||
|
||||
## 1.6.4 - 2015-10-24
|
||||
|
||||
- Fix ignoring dependencies on multiple install run ([#1970](https://github.com/bower/bower/pull/1970))
|
||||
- Use --non-interactive when running svn client ([#1969](https://github.com/bower/bower/pull/1969))
|
||||
- Fix downloading of URLs ending with slash ([#1956](https://github.com/bower/bower/pull/1956))
|
||||
- Add user-agent field for downloads by Bower ([#1960](https://github.com/bower/bower/pull/1960))
|
||||
|
||||
## 1.6.3 - 2015-10-16
|
||||
|
||||
Fixes regression issues introduced with 1.6.2, specifically:
|
||||
|
||||
- Allow for bower_components to be a symlink
|
||||
- Allow setting custom registry in .bowerrc
|
||||
|
||||
## 1.6.2 - 2015-10-15
|
||||
|
||||
Fix dependency issues of 1.6.1. First published release of 1.6.x.
|
||||
|
||||
## 1.6.1 - 2015-10-15
|
||||
|
||||
Fix dependency issues of 1.6.0. Reverted release.
|
||||
|
||||
## 1.6.0 - 2015-10-15
|
||||
|
||||
- Shrinkwrap all dependencies and add them to bundledDependencies ([#1948](https://github.com/bower/bower/pull/1948))
|
||||
- Allow for ignoring of child dependencies ([#1394](https://github.com/bower/bower/pull/1394))
|
||||
- Allow passing `--config.resolvers` through CLI ([#1922](https://github.com/bower/bower/pull/1922))
|
||||
- Use defaults values from package.json if it exists (bower init) ([#1731](https://github.com/bower/bower/issues/1731))
|
||||
- Properly use cerificates set in .bowerrc ([#1869](https://github.com/bower/bower/pull/1869))
|
||||
- Include package name when version conflict occurs ([#1917](https://github.com/bower/bower/pull/1917))
|
||||
- Add timeout for permission check ([yeoman/insight#35](https://github.com/yeoman/insight/pull/35))
|
||||
- Close file-handles when possible. Prevents all sorts of permission issues on Windows ([0bb1536](https://github.com/bower/bower/commit/0bb1536c9972e13f3be06bea9a8619632966c664))
|
||||
- Prevent ENOENT error on Windows when in VM environment ([isaacs/chmodr#8](https://github.com/isaacs/chmodr/pull/8))
|
||||
|
||||
Reverted release.
|
||||
|
||||
## 1.5.4 - 2015-11-24
|
||||
|
||||
- [fix] Lock lru-cache dependency to 2.7.0
|
||||
|
||||
## 1.5.3 - 2015-09-24
|
||||
|
||||
- Revert auto sorting of bower dependencies, fixes ([#1897](https://github.com/bower/bower/issues/1897))
|
||||
- Fix --save-exact feature for github endpoints, fixes ([#1925](https://github.com/bower/bower/issues/1925))
|
||||
- Fix `bower init` to support private flag again ([#1819](https://github.com/bower/bower/pull/1819))
|
||||
- Bump insight dependency to support prompt timeout ([#1102](https://github.com/bower/bower/issues/1102))
|
||||
|
||||
## 1.5.2 - 2015-08-25
|
||||
|
||||
- Revert update semver version from 2.x to 5.x, fixes ([#1896](https://github.com/bower/bower/issues/1896))
|
||||
- Make bower commands work from subdirectories, fixes ([#1893](https://github.com/bower/bower/issues/1893))
|
||||
- Put auto shallow cloning for git behind a flag, fixes ([#1764](https://github.com/bower/bower/issues/1764))
|
||||
|
||||
## 1.5.1 - 2015-08-24
|
||||
|
||||
- If cwd provided explicitly, force using it, fixes #1866
|
||||
|
||||
## 1.5.0 - 2015-08-24
|
||||
|
||||
- Pluggable Resolvers! http://bower.io/docs/pluggable-resolvers/
|
||||
- Update semver version from 2.x to 5.x ([#1852](https://github.com/bower/bower/issues/1852))
|
||||
- Auto-sort dependencies alphabetically ([#1381](https://github.com/bower/bower/issues/1381))
|
||||
- Make bower commands work from subdirectories ([#1866](https://github.com/bower/bower/issues/1866))
|
||||
- No longer prefer installing bower as global module ([#1865](https://github.com/bower/bower/issues/1865))
|
||||
|
||||
## 1.4.2 - 2015-11-24
|
||||
|
||||
- [fix] Lock lru-cache dependency to 2.7.0
|
||||
|
||||
## 1.4.1 - 2015-04-01
|
||||
|
||||
- [fix] Reading .bowerrc upwards directory tree ([#1763](https://github.com/bower/bower/issues/1763))
|
||||
- [fix] Update bower-registry-client so it uses the same bower-config as bower
|
||||
|
||||
## 1.4.0 - 2015-03-30
|
||||
|
||||
- Add login and unregister commands ([#1719](https://github.com/bower/bower/issues/1719))
|
||||
- Automatically detecting smart Git hosts ([#1628](https://github.com/bower/bower/issues/1628))
|
||||
- [bower/config#23] Allow npm config variables ([#1711](https://github.com/bower/bower/issues/1711))
|
||||
- [bower/config#24] Merge .bowerrc files upwards directory tree ([#1689](https://github.com/bower/bower/issues/1689))
|
||||
- Better homedir detection (514eb8f)
|
||||
- Add --save-exact flag ([#1654](https://github.com/bower/bower/issues/1654))
|
||||
- Ensure extracted files are readable (tar-fs) ([#1548](https://github.com/bower/bower/issues/1548))
|
||||
- The version command in the programmatic API now returns the new version ([#1755](https://github.com/bower/bower/issues/1755))
|
||||
- Some minor fixes: #1639, #1620, #1576, #1557, 962a565, a464f5a
|
||||
- Improved Windows support (AppVeyor CI, tests actually passing on Windows)
|
||||
- OSX testing enabled on TravisCI
|
||||
|
||||
It also includes improved test coverage (~60% -> ~85%) and many refactors.
|
||||
|
||||
## 1.3.12 - 2014-09-28
|
||||
|
||||
- [stability] Fix versions for unstable dependencies ([#1532](https://github.com/bower/bower/pull/1532))
|
||||
- [fix] Update tar-fs to support old tar format ([#1537](https://github.com/bower/bower/issues/1537))
|
||||
- [fix] Make analytics work again ([#1529](https://github.com/bower/bower/pull/1529))
|
||||
- [fix] Always disable analytics for non-interactive mode ([#1529](https://github.com/bower/bower/pull/1529))
|
||||
- [fix] Bower init can create private packages again ([#1522](https://github.com/bower/bower/issues/1522))
|
||||
- [fix] Show again missing newline for bower search output ([#1538](https://github.com/bower/bower/issues/1538))
|
||||
|
||||
## 1.3.11 - 2014-09-17
|
||||
|
||||
- [fix] Restore install missing dependencies on update ([1519](https://github.com/bower/bower/pull/1519))
|
||||
|
||||
## 1.3.10 - 2014-09-13
|
||||
|
||||
- [fix] Back down concurrency from 50 to 5 ([#1483](https://github.com/bower/bower/pull/1483))
|
||||
- [fix] Read .bowerrc from specified cwd ([#1301](https://github.com/bower/bower/pull/1301))
|
||||
- [fix] Disable shallow clones except those from GitHub ([#1393](https://github.com/bower/bower/pull/1393))
|
||||
- [fix] Expose bower version ([#1478](https://github.com/bower/bower/pull/1478))
|
||||
- [fix] Bump dependencies, including "request" ([#1467](https://github.com/bower/bower/pull/1467))
|
||||
- [fix] Prevent an error when piping bower output to head ([#1508](https://github.com/bower/bower/pull/1508))
|
||||
- [fix] Disable removing unnecessary resolutions ([#1061](https://github.com/bower/bower/pull/1061))
|
||||
- [fix] Display the output of hooks again ([#1484](https://github.com/bower/bower/issues/1484))
|
||||
- [fix] analytics: true in .bowerrc prevents user prompt ([#1470](https://github.com/bower/bower/pull/1470))
|
||||
- [perf] Use `tar-fs` instead of `tar` for faster TAR extraction ([#1490](https://github.com/bower/bower/pull/1490))
|
||||
|
||||
## 1.3.9 - 2014-08-06
|
||||
|
||||
- [fix] Handle `tmp` sometimes returning an array ([#1434](https://github.com/bower/bower/pull/1434))
|
||||
|
||||
## 1.3.8 - 2014-7-11
|
||||
|
||||
- [fix] Lock down `tmp` package dep ([#1403](https://github.com/bower/bower/pull/1403), [#1407](https://github.com/bower/bower/pull/1407))
|
||||
|
||||
## 1.3.7 - 2014-07-04
|
||||
|
||||
- [fix] callstack error when processing installed packages with circular dependencies ([#1349](https://github.com/bower/bower/issues/1349))
|
||||
- [fix] Prevent bower list --paths` failing with TypeError ([#1383](https://github.com/bower/bower/issues/1383))
|
||||
- "bower install" fails if there's no bower.json in current directory ([#922](https://github.com/bower/bower/issues/922))
|
||||
|
||||
## 1.3.6 - 2014-07-02
|
||||
|
||||
- [fix] Make --force always re-run installation ([#931](https://github.com/bower/bower/issues/931))
|
||||
- [fix] Disable caching for local resources ([#1356](https://github.com/bower/bower/issues/1356))
|
||||
- [fix] Emit errors instead throwing them when using bower.commands API ([#1297](https://github.com/bower/bower/issues/1297))
|
||||
- [fix] Main files and bower.json are never ignored ([#547](https://github.com/bower/bower/issues/547))
|
||||
- [fix] Check if pkgMeta is undefined during uninstall command ([#1329](https://github.com/bower/bower/issues/1329))
|
||||
- [fix] Make custom tmp dir and ignores play well with each other ([#1299](https://github.com/bower/bower/issues/1299))
|
||||
- Warn users when installing package with missing properties ([#694](https://github.com/bower/bower/issues/694))
|
||||
|
||||
|
||||
## 1.3.5 - 2014-06-06
|
||||
- Search compatible versions in fetching packages ([#1147](https://github.com/bower/bower/issues/1147))
|
||||
|
||||
## 1.3.4 - 2014-06-02
|
||||
|
||||
- Resolve a situation in which the install process gets into an infinite loop ([#1169](https://github.com/bower/bower/issues/1169))
|
||||
- Improved CLI output for conflicts ([#1284](https://github.com/bower/bower/issues/1284))
|
||||
- Changed `bower version` to mirror the tag format of `npm version` ([#1278](https://github.com/bower/bower/issues/1278))
|
||||
- Allow short commit SHAs to be used ([#990](https://github.com/bower/bower/issues/990))
|
||||
|
||||
## 1.3.3 - 2014-04-24
|
||||
|
||||
- Do not cache moving targets like branches ([#1242](https://github.com/bower/bower/issues/1242))
|
||||
- Suppress output if --quiet option is specified ([#1124](https://github.com/bower/bower/pull/1124))
|
||||
- Use "svn export" for efficiency ([#1224](https://github.com/bower/bower/pull/1224))
|
||||
- Prevent loading insights and analytics on CI ([#1221](https://github.com/bower/bower/issues/1221))
|
||||
- Make "bower list" respect custom components directory ([#1237](https://github.com/bower/bower/issues/1237))
|
||||
- Improve non-interactive loading performance 2x ([#1238](https://github.com/bower/bower/issues/1238))
|
||||
- Load commands only on demand, improving performance ([#1232](https://github.com/bower/bower/pull/1232))
|
||||
|
||||
## 1.3.2 - 2014-04-05
|
||||
|
||||
- Added yui moduleType [PR #1129](https://github.com/bower/bower/pull/1129)
|
||||
- Fixes for concurrency issues [PR #1211](https://github.com/bower/bower/pull/1211)
|
||||
- `link` now installs package dependencies [PR #891](https://github.com/bower/bower/pull/891)
|
||||
- Improved conflict installation message [Commit](https://github.com/bower/bower/commit/bea533acf87903d4b411bfbaa7df93f852ef46a3)
|
||||
- Add --production switch to "prune" command [PR #1168](https://github.com/bower/bower/pull/1168)
|
||||
|
||||
|
||||
## 1.3.1 - 2014-03-10
|
||||
|
||||
- No longer ask for permission to gather analytics when running on in a CI environment.
|
||||
|
||||
|
||||
## 1.3.0 - 2014-03-10
|
||||
|
||||
- **Removed support for node 0.8.** It may still work but we will no longer fix bugs for older versions of node.
|
||||
- Add **Bower Insight** for opt-in analytics integration to help improve tool and gain insight on community trends
|
||||
- Old overview of [Insight](https://github.com/yeoman/yeoman/wiki/Insight), [Issue #260](https://github.com/bower/bower/issues/260)
|
||||
- Reporting to GA. Public Dashboard is in progress.
|
||||
- [Turn off interactive mode](https://github.com/bower/bower/issues/1162) if you run Bower in a CI environment
|
||||
- Add `moduleType` property to bower init ([#934](https://github.com/bower/bower/pull/934))
|
||||
- Fix prune command to log only after cleanup is completed ([#1023](https://github.com/bower/bower/issues/1023))
|
||||
- Fix git resolver to ignore pre-release versions ([#1017](https://github.com/bower/bower/issues/1017))
|
||||
- Fix shorthand flag for `save` option on `uninstall` command ([#1031](https://github.com/bower/bower/pull/1031))
|
||||
- Add `bower version` command ([#961](https://github.com/bower/bower/pull/961))
|
||||
- Add .bowerrc option to use `--save` by default when using `bower install` command ([#1074](https://github.com/bower/bower/pull/1074))
|
||||
- Fix git resolver caching ([#1083](https://github.com/bower/bower/issues/1083))
|
||||
- Fix reading versions from cache directory ([#1076](https://github.com/bower/bower/pull/1076))
|
||||
- Add svn support ([#1055](https://github.com/bower/bower/pull/1055))
|
||||
- Allow circular dependencies to be installed ([#1104](https://github.com/bower/bower/pull/1104))
|
||||
- Add scripts/hooks support ([#718](https://github.com/bower/bower/pull/718))
|
||||
|
||||
_NOTE_: It's advisable that users use `--config.interactive=false` on automated scripts.
|
||||
|
||||
|
||||
## 1.2.8 - 2013-12-02
|
||||
- Fix absolute paths ending with / not going through the FsResolver, ([#898](https://github.com/bower/bower/issues/898))
|
||||
- Allow query string parameters in package URLs
|
||||
- Swapped 'unzip' module for 'decompress-zip', and some other small unzipping fixes([#873](https://github.com/bower/bower/issues/873), [#896](https://github.com/bower/bower/issues/896))
|
||||
- Allow the root-check to be overridden when calling bower programmatically.
|
||||
- Fixed some bugs relating to packages with a very large dependency tree
|
||||
- Fix a bug caused by a recent change to semver
|
||||
|
||||
|
||||
## 1.2.7 - 2013-09-29
|
||||
|
||||
@@ -79,7 +396,7 @@ _NOTE_: It's advisable that users run `bower cache clean`.
|
||||
- Ignore `component.json` if it looks like a component(1) file ([#556](https://github.com/bower/bower/issues/556))
|
||||
- Fix multi-user usage on bower when it creates temporary directories to hold some files
|
||||
- Fix prompting causing an invalid JSON output when running commands with `--json`
|
||||
- When running Bower commands programmatically, prompting is now disabled by default (see the updated progammatic [usage](https://github.com/bower/bower#programmatic-api) for more info)
|
||||
- When running Bower commands programmatically, prompting is now disabled by default (see the updated programmatic [usage](https://github.com/bower/bower#programmatic-api) for more info)
|
||||
- Other minor improvements and fixes
|
||||
|
||||
Fix for `#788` requires installed components to be re-installed.
|
||||
@@ -141,7 +458,7 @@ Fix for `#788` requires installed components to be re-installed.
|
||||
- Fix `Bower` not working when calling `.bat`/`.cmd` commands on Windows; it affected people using `Git portable` ([#626](https://github.com/bower/bower/issues/626))
|
||||
- Fix `bower list --paths` not resolving all files to absolute paths when the `main` property contained multiple files ([660](https://github.com/bower/bower/issues/660))
|
||||
- Fix `Bower` renaming `bower.json` and `component.json` files to `index.json` when it was the only file in the folder ([#674](https://github.com/bower/bower/issues/674))
|
||||
- Ignore symlinks when copying/extracting since they are not portable, specially accross different hard-drives ([#665](https://github.com/bower/bower/issues/665))
|
||||
- Ignore symlinks when copying/extracting since they are not portable, specially across different hard-drives ([#665](https://github.com/bower/bower/issues/665))
|
||||
- Local file/dir endpoints are now exclusively referenced by an absolute path or relative path starting with `.` ([#666](https://github.com/bower/bower/issues/666))
|
||||
- Linked packages `bower.json` files are now parsed, making `bower list` account linked packages dependencies ([#659](https://github.com/bower/bower/issues/659))
|
||||
- Bower now fails to run with sudo unless `--allow-root` is passed ([#498](https://github.com/bower/bower/issues/498))
|
||||
@@ -154,7 +471,7 @@ Fix for `#788` requires installed components to be re-installed.
|
||||
## 1.0.0 - 2013-07-23
|
||||
|
||||
Total rewrite of bower.
|
||||
The list bellow highlights the most important stuff.
|
||||
The list bellow highlights the most important stuff.
|
||||
For a complete list of changes that this rewrite and release brings please read: https://github.com/bower/bower/wiki/Rewrite-state
|
||||
|
||||
|
||||
@@ -177,7 +494,7 @@ Non-backwards compatible changes:
|
||||
- `--map` and `--sources` from the list command were removed, use `--json` instead
|
||||
- Programmatic usage changed, specially the commands interface
|
||||
|
||||
Users upgrading from `bower-canary` and `bower@~0.x.x` should do a `bower cache clean`.
|
||||
Users upgrading from `bower-canary` and `bower@~0.x.x` should do a `bower cache clean`.
|
||||
Additionally you may remove the `~/.bower` folder manually since it's no longer used.
|
||||
On Windows the folder is located in `AppData/bower`.
|
||||
|
||||
@@ -305,7 +622,7 @@ _NOTE_: The `components` folder will still be used if already created, making it
|
||||
|
||||
## 0.6.1 - 2012-11-22
|
||||
- Fix uninstall when the project component.json has no deps saved ([#153](https://github.com/bower/bower/issues/153))
|
||||
- Fix uncaught errors when using file writter (they are now caught and reported)
|
||||
- Fix uncaught errors when using file writer (they are now caught and reported)
|
||||
- Fix temporary directories not being deleted when an exception occurs ([#153](https://github.com/bower/bower/issues/140))
|
||||
|
||||
## 0.6.0 - 2012-11-21
|
||||
|
||||
@@ -1,13 +1,26 @@
|
||||
# Contributing to Bower
|
||||
|
||||
Please take a moment to review this document in order to make the contribution
|
||||
process easy and effective for everyone involved.
|
||||
Bower is a large community project with many different developers contributing at all levels to the project. We're **actively** looking for more contributors right now. If you're interested in becoming a Bower maintainer or supporting in any way, please fill the following form: http://goo.gl/forms/P1ndzCNoiG. There is more information about [contributing](https://github.com/bower/bower/wiki/Contributor-Guidelines) in the Wiki.
|
||||
|
||||
Following these guidelines helps to communicate that you respect the time of
|
||||
the developers managing and developing this open source project. In return,
|
||||
they should reciprocate that respect in addressing your issue, assessing
|
||||
changes, and helping you finalize your pull requests.
|
||||
<a name="bugs"></a>
|
||||
## 🐛 [Bug reports](https://github.com/bower/bower/wiki/Report-a-Bug)
|
||||
|
||||
## Casual Involvement
|
||||
|
||||
* Improve the bower.io site ([tickets](https://github.com/bower/bower.github.io/issues))
|
||||
* Comment on issues and drive to resolution
|
||||
|
||||
## High-impact Involvement
|
||||
|
||||
* Maintaining the bower client.
|
||||
* Read [Architecture doc](https://github.com/bower/bower/wiki/Rewrite-architecture)
|
||||
* Triage, close, fix and resolve [issues](https://github.com/bower/bower/issues)
|
||||
|
||||
## Team Meetings
|
||||
|
||||
We communicate through a channel on slack: https://gitter.im/bower
|
||||
|
||||
If you'd like to attend the meetings, please fill the [support form](http://goo.gl/forms/P1ndzCNoiG), and you'll get an invite.
|
||||
|
||||
## Using the issue tracker
|
||||
|
||||
@@ -16,7 +29,8 @@ The issue tracker is the preferred channel for [bug reports](#bugs),
|
||||
requests](#pull-requests), but please respect the following restrictions:
|
||||
|
||||
* Please **do not** use the issue tracker for personal support requests. Use
|
||||
[Stack Overflow](http://stackoverflow.com/questions/tagged/bower), our
|
||||
[Stack Overflow](http://stackoverflow.com/questions/tagged/bower)
|
||||
[Gitter Channel](https://gitter.im/bower/bower)
|
||||
[Mailing List](http://groups.google.com/group/twitter-bower)
|
||||
(twitter-bower@googlegroups.com), or
|
||||
[#bower](http://webchat.freenode.net/?channels=bower) on Freenode.
|
||||
@@ -24,49 +38,6 @@ requests](#pull-requests), but please respect the following restrictions:
|
||||
* Please **do not** derail or troll issues. Keep the discussion on topic and
|
||||
respect the opinions of others.
|
||||
|
||||
|
||||
<a name="bugs"></a>
|
||||
## Bug reports
|
||||
|
||||
A bug is a _demonstrable problem_ that is caused by the code in the repository.
|
||||
Good bug reports are extremely helpful - thank you!
|
||||
|
||||
Guidelines for bug reports:
|
||||
|
||||
1. **Use the GitHub issue search** — check if the issue has already been
|
||||
reported.
|
||||
|
||||
2. **Check if the issue has been fixed** — try to reproduce it using the
|
||||
latest `master` or development branch in the repository.
|
||||
|
||||
3. **Isolate the problem** — ideally create a [reduced test
|
||||
case](http://css-tricks.com/6263-reduced-test-cases/).
|
||||
|
||||
A good bug report shouldn't leave others needing to chase you up for more
|
||||
information. Please try to be as detailed as possible in your report. What is
|
||||
your environment? What steps will reproduce the issue? What OS experiences the
|
||||
problem? What would you expect to be the outcome? All these details will help
|
||||
people to fix any potential bugs.
|
||||
|
||||
Example:
|
||||
|
||||
> Short and descriptive example bug report title
|
||||
>
|
||||
> A summary of the issue and the browser/OS environment in which it occurs. If
|
||||
> suitable, include the steps required to reproduce the bug.
|
||||
>
|
||||
> 1. This is the first step
|
||||
> 2. This is the second step
|
||||
> 3. Further steps, etc.
|
||||
>
|
||||
> `<url>` - a link to the reduced test case
|
||||
>
|
||||
> Any other information you want to share that is relevant to the issue being
|
||||
> reported. This might include the lines of code that you have identified as
|
||||
> causing the bug, and potential solutions (and your opinions on their
|
||||
> merits).
|
||||
|
||||
|
||||
<a name="features"></a>
|
||||
## Feature requests
|
||||
|
||||
@@ -150,6 +121,8 @@ included in the project:
|
||||
force push to your remote feature branch. You may also be asked to squash
|
||||
commits.
|
||||
|
||||
10. If you are asked to squash your commits, then please use `git rebase -i master`. It will ask you to pick your commits - pick the major commits and squash the rest.
|
||||
|
||||
**IMPORTANT**: By submitting a patch, you agree to license your work under the
|
||||
same license as that used by the project.
|
||||
|
||||
|
||||
48
Gruntfile.js
48
Gruntfile.js
@@ -1,48 +0,0 @@
|
||||
module.exports = function (grunt) {
|
||||
grunt.initConfig({
|
||||
jshint: {
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
},
|
||||
files: ['Gruntfile.js', 'bin/*', 'lib/**/*.js', 'test/**/*.js', '!test/assets/**/*', '!test/reports/**/*']
|
||||
},
|
||||
simplemocha: {
|
||||
options: {
|
||||
reporter: 'spec',
|
||||
timeout: '5000'
|
||||
},
|
||||
full: { src: ['test/test.js'] },
|
||||
short: {
|
||||
options: {
|
||||
reporter: 'dot'
|
||||
},
|
||||
src: ['test/test.js']
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
assets: {
|
||||
command: 'node test/packages.js'
|
||||
},
|
||||
'assets-force': {
|
||||
command: 'node test/packages.js --force'
|
||||
},
|
||||
cover: {
|
||||
command: 'node node_modules/istanbul/lib/cli.js cover --dir ./test/reports node_modules/mocha/bin/_mocha -- -R dot test/test.js'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
files: ['<%= jshint.files %>'],
|
||||
tasks: ['jshint', 'simplemocha:short']
|
||||
}
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
grunt.loadNpmTasks('grunt-simple-mocha');
|
||||
grunt.loadNpmTasks('grunt-exec');
|
||||
|
||||
grunt.registerTask('assets', ['exec:assets-force']);
|
||||
grunt.registerTask('test', ['jshint', 'exec:assets', 'simplemocha:full']);
|
||||
grunt.registerTask('cover', 'exec:cover');
|
||||
grunt.registerTask('default', 'test');
|
||||
};
|
||||
361
README.md
361
README.md
@@ -1,357 +1,126 @@
|
||||
# BOWER [](http://travis-ci.org/bower/bower)
|
||||
# Bower - A package manager for the web
|
||||
|
||||
Bower is a package manager for the web. It offers a generic, unopinionated
|
||||
solution to the problem of **front-end package management**, while exposing the
|
||||
package dependency model via an API that can be consumed by a more opinionated
|
||||
build stack. There are no system wide dependencies, no dependencies are shared
|
||||
between different apps, and the dependency tree is flat.
|
||||
> Bower needs your help. If you're willing to help, please say hello to team@bower.io or [donate](https://salt.bountysource.com/teams/bower)
|
||||
|
||||
Bower runs over Git, and is package-agnostic. A packaged component can be made
|
||||
up of any type of asset, and use any type of transport (e.g., AMD, CommonJS,
|
||||
etc.).
|
||||
[](https://travis-ci.org/bower/bower)
|
||||
[](https://ci.appveyor.com/project/bower/bower)
|
||||
[](https://coveralls.io/r/bower/bower?branch=master)
|
||||
[](https://discord.gg/0fFM7QF0KpZRh2cY)
|
||||
[](http://issuestats.com/github/bower/bower)
|
||||
[](http://issuestats.com/github/bower/bower)
|
||||
|
||||
[View all packages available through Bower's registry](http://sindresorhus.com/bower-components/).
|
||||
<img align="right" height="300" src="http://bower.io/img/bower-logo.png">
|
||||
|
||||
---
|
||||
|
||||
## Installing Bower
|
||||
Bower offers a generic, unopinionated solution to the problem of **front-end package management**, while exposing the package dependency model via an API that can be consumed by a more opinionated build stack. There are no system wide dependencies, no dependencies are shared between different apps, and the dependency tree is flat.
|
||||
|
||||
Bower depends on [Node](http://nodejs.org/) and [npm](http://npmjs.org/). It's
|
||||
installed globally using npm:
|
||||
Bower runs over Git, and is package-agnostic. A packaged component can be made up of any type of asset, and use any type of transport (e.g., AMD, CommonJS, etc.).
|
||||
|
||||
```
|
||||
npm install -g bower
|
||||
**View complete docs on [bower.io](http://bower.io)**
|
||||
|
||||
[View all packages available through Bower's registry](http://bower.io/search/).
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
$ npm install -g bower
|
||||
```
|
||||
|
||||
Also make sure that [git](http://git-scm.com/) is installed as some bower
|
||||
Bower depends on [Node.js](http://nodejs.org/) and [npm](http://npmjs.org/). Also make sure that [git](http://git-scm.com/) is installed as some bower
|
||||
packages require it to be fetched and installed.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Much more information is available via `bower help` once it's installed. This
|
||||
is just enough to get you started.
|
||||
|
||||
#### Warning
|
||||
|
||||
On `prezto` or `oh-my-zsh`, do not forget to `alias bower='noglob bower'` or `bower install jquery\#1.9.1`
|
||||
|
||||
#### Running commands with sudo
|
||||
|
||||
Bower is a user command, there is no need to execute it with superuser permissions.
|
||||
However, if you still want to run commands with sudo, use `--allow-root` option.
|
||||
See complete command line reference at [bower.io/docs/api/](http://bower.io/docs/api/)
|
||||
|
||||
### Installing packages and dependencies
|
||||
|
||||
Bower offers several ways to install packages:
|
||||
```sh
|
||||
# install dependencies listed in bower.json
|
||||
$ bower install
|
||||
|
||||
# install a package and add it to bower.json
|
||||
$ bower install <package> --save
|
||||
|
||||
# install specific version of a package and add it to bower.json
|
||||
$ bower install <package>#<version> --save
|
||||
```
|
||||
# Using the dependencies listed in the current directory's bower.json
|
||||
bower install
|
||||
# Using a local or remote package
|
||||
bower install <package>
|
||||
# Using a specific version of a package
|
||||
bower install <package>#<version>
|
||||
# Using a different name and a specific version of a package
|
||||
bower install <name>=<package>#<version>
|
||||
```
|
||||
|
||||
Where `<package>` can be any one of the following:
|
||||
|
||||
* A name that maps to a package registered with Bower, e.g, `jquery`. ‡
|
||||
* A remote Git endpoint, e.g., `git://github.com/someone/some-package.git`. Can be
|
||||
public or private. ‡
|
||||
* A local endpoint, i.e., a folder that's a Git repository. ‡
|
||||
* A shorthand endpoint, e.g., `someone/some-package` (defaults to GitHub). ‡
|
||||
* A URL to a file, including `zip` and `tar` files. Its contents will be
|
||||
extracted.
|
||||
|
||||
‡ These types of `<package>` might have versions available. You can specify a
|
||||
[semver](http://semver.org/) compatible version to fetch a specific release, and lock the
|
||||
package to that version. You can also use ranges to specify a range of versions.
|
||||
|
||||
All package contents are installed in the `bower_components` directory by default.
|
||||
You should **never** directly modify the contents of this directory.
|
||||
|
||||
Using `bower list` will show all the packages that are installed locally.
|
||||
|
||||
**N.B.** If you aren't authoring a package that is intended to be consumed by
|
||||
others (e.g., you're building a web app), you should always check installed
|
||||
packages into source control.
|
||||
|
||||
### Finding packages
|
||||
|
||||
To search for packages registered with Bower:
|
||||
|
||||
```
|
||||
bower search [<name>]
|
||||
```
|
||||
|
||||
Using just `bower search` will list all packages in the registry.
|
||||
|
||||
### Using packages
|
||||
|
||||
The easiest approach is to use Bower statically, just reference the package's
|
||||
installed components manually using a `script` tag:
|
||||
We discourage using bower components statically for performance and security reasons (if component has an `upload.php` file that is not ignored, that can be easily exploited to do malicious stuff).
|
||||
|
||||
```html
|
||||
<script src="/bower_components/jquery/index.js"></script>
|
||||
```
|
||||
|
||||
For more complex projects, you'll probably want to concatenate your scripts or
|
||||
use a module loader. Bower is just a package manager, but there are plenty of
|
||||
other tools -- such as [Sprockets](https://github.com/sstephenson/sprockets)
|
||||
and [RequireJS](http://requirejs.org/) -- that will help you do this.
|
||||
|
||||
### Registering packages
|
||||
|
||||
To register a new package:
|
||||
|
||||
* There **must** be a valid manifest JSON in the current working directory.
|
||||
* Your package should use [semver](http://semver.org/) Git tags.
|
||||
* Your package **must** be available at a Git endpoint (e.g., GitHub); remember
|
||||
to push your Git tags!
|
||||
|
||||
Then use the following command:
|
||||
|
||||
```
|
||||
bower register <my-package-name> <git-endpoint>
|
||||
```
|
||||
|
||||
The Bower registry does not have authentication or user management at this point
|
||||
in time. It's on a first come, first served basis. Think of it like a URL
|
||||
shortener. Now anyone can run `bower install <my-package-name>`, and get your
|
||||
library installed.
|
||||
|
||||
There is no direct way to unregister a package yet. For now, you can [request a
|
||||
package be unregistered](https://github.com/bower/bower/issues/120).
|
||||
The best approach is to process components installed by bower with build tool (like [Grunt](http://gruntjs.com/) or [gulp](http://gulpjs.com/)), and serve them concatenated or using a module loader (like [RequireJS](http://requirejs.org/)).
|
||||
|
||||
### Uninstalling packages
|
||||
|
||||
To uninstall a locally installed package:
|
||||
|
||||
```
|
||||
bower uninstall <package-name>
|
||||
```sh
|
||||
$ bower uninstall <package-name>
|
||||
```
|
||||
|
||||
### prezto and oh-my-zsh users
|
||||
|
||||
## Configuration
|
||||
On `prezto` or `oh-my-zsh`, do not forget to `alias bower='noglob bower'` or `bower install jquery\#1.9.1`
|
||||
|
||||
Bower can be configured using JSON in a `.bowerrc` file.
|
||||
### Never run Bower with sudo
|
||||
|
||||
The current spec can be read
|
||||
[here](https://docs.google.com/document/d/1APq7oA9tNao1UYWyOm8dKqlRP2blVkROYLZ2fLIjtWc/edit#heading=h.4pzytc1f9j8k)
|
||||
in the `Configuration` section.
|
||||
Bower is a user command; there is no need to execute it with superuser permissions.
|
||||
|
||||
|
||||
## Defining a package
|
||||
|
||||
You must create a `bower.json` in your project's root, and specify all of its
|
||||
dependencies. This is similar to Node's `package.json`, or Ruby's `Gemfile`,
|
||||
and is useful for locking down a project's dependencies.
|
||||
|
||||
*NOTE:* In versions of Bower before 0.9.0 the package metadata file was called
|
||||
`component.json` rather than `bower.json`. This has changed to avoid a name
|
||||
clash with another tool. You can still use `component.json` for now but it is
|
||||
deprecated and the automatic fallback is likely to be removed in an upcoming
|
||||
release.
|
||||
|
||||
You can interactively create a `bower.json` with the following command:
|
||||
|
||||
```
|
||||
bower init
|
||||
```
|
||||
|
||||
The `bower.json` defines several options:
|
||||
|
||||
* `name` (required): The name of your package.
|
||||
* `version`: A semantic version number (see [semver](http://semver.org/)).
|
||||
* `main` [string|array]: The primary endpoints of your package.
|
||||
* `ignore` [array]: An array of paths not needed in production that you want
|
||||
Bower to ignore when installing your package.
|
||||
* `dependencies` [hash]: Packages your package depends upon in production.
|
||||
* `devDependencies` [hash]: Development dependencies.
|
||||
* `private` [boolean]: Set to true if you want to keep the package private and
|
||||
do not want to register the package in future.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-project",
|
||||
"version": "1.0.0",
|
||||
"main": "path/to/main.css",
|
||||
"ignore": [
|
||||
".jshintrc",
|
||||
"**/*.txt"
|
||||
],
|
||||
"dependencies": {
|
||||
"<name>": "<version>",
|
||||
"<name>": "<folder>",
|
||||
"<name>": "<package>"
|
||||
},
|
||||
"devDependencies": {
|
||||
"<test-framework-name>": "<version>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Consuming a package
|
||||
|
||||
Bower also makes available a source mapping. This can be used by build tools to
|
||||
easily consume Bower packages.
|
||||
|
||||
If you pass the `--paths` option to Bower's `list` command, you will get a
|
||||
simple path-to-name mapping:
|
||||
|
||||
```json
|
||||
{
|
||||
"backbone": "bower_components/backbone/index.js",
|
||||
"jquery": "bower_components/jquery/index.js",
|
||||
"underscore": "bower_components/underscore/index.js"
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, every command supports the `--json` option that makes bower
|
||||
output JSON. Command result is outputted to `stdout` and error/logs to
|
||||
`stderr`.
|
||||
|
||||
|
||||
## Programmatic API
|
||||
|
||||
Bower provides a powerful, programmatic API. All commands can be accessed
|
||||
through the `bower.commands` object.
|
||||
|
||||
```js
|
||||
var bower = require('bower');
|
||||
|
||||
bower.commands
|
||||
.install(['jquery'], { save: true }, { /* custom config */ })
|
||||
.on('end', function (installed) {
|
||||
console.log(installed);
|
||||
});
|
||||
|
||||
bower.commands
|
||||
.search('jquery', {})
|
||||
.on('end', function (results) {
|
||||
console.log(results);
|
||||
});
|
||||
```
|
||||
|
||||
Commands emit four types of events: `log`, `prompt`, `end`, `error`.
|
||||
|
||||
* `log` is emitted to report the state/progress of the command.
|
||||
* `prompt` is emitted whenever the user needs to be prompted.
|
||||
* `error` will only be emitted if something goes wrong.
|
||||
* `end` is emitted when the command successfully ends.
|
||||
|
||||
For a better of idea how this works, you may want to check out [our bin
|
||||
file](https://github.com/bower/bower/blob/master/bin/bower).
|
||||
|
||||
When using bower programmatically, prompting is disabled by default. Though you can enable it when calling commands with `interactive: true` in the config.
|
||||
This requires you to listen for the `prompt` event and handle the prompting yourself. The easiest way is to use the [inquirer](https://npmjs.org/package/inquirer) npm module like so:
|
||||
|
||||
```js
|
||||
var inquirer = require('inquirer');
|
||||
|
||||
bower.commands
|
||||
.install(['jquery'], { save: true }, { interactive: true })
|
||||
// ..
|
||||
.on('prompt', function (prompts, callback) {
|
||||
inquirer.prompt(prompts, callback);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Completion (experimental)
|
||||
|
||||
_NOTE_: Completion is still not implemented for the 1.0.0 release
|
||||
|
||||
Bower now has an experimental `completion` command that is based on, and works
|
||||
similarly to the [npm completion](https://npmjs.org/doc/completion.html). It is
|
||||
not available for Windows users.
|
||||
|
||||
This command will output a Bash / ZSH script to put into your `~/.bashrc`,
|
||||
`~/.bash_profile`, or `~/.zshrc` file.
|
||||
|
||||
```
|
||||
bower completion >> ~/.bash_profile
|
||||
```
|
||||
|
||||
|
||||
## A note for Windows users
|
||||
### Windows users
|
||||
|
||||
To use Bower on Windows, you must install
|
||||
[msysgit](http://code.google.com/p/msysgit/) correctly. Be sure to check the
|
||||
option shown below:
|
||||
[Git for Windows](http://git-for-windows.github.io/) correctly. Be sure to check the
|
||||
options shown below:
|
||||
|
||||

|
||||
<img src="https://cloud.githubusercontent.com/assets/10702007/10532690/d2e8991a-7386-11e5-9a57-613c7f92e84e.png" width="534" height="418" alt="Git for Windows" />
|
||||
|
||||
<img src="https://cloud.githubusercontent.com/assets/10702007/10532694/dbe8857a-7386-11e5-9bd0-367e97644403.png" width="534" height="418" alt="Git for Windows" />
|
||||
|
||||
Note that if you use TortoiseGit and if Bower keeps asking for your SSH
|
||||
password, you should add the following environment variable: `GIT_SSH -
|
||||
C:\Program Files\TortoiseGit\bin\TortoisePlink.exe`. Adjust the `TortoisePlink`
|
||||
path if needed.
|
||||
|
||||
### Ubuntu users
|
||||
|
||||
## Contact
|
||||
To use Bower on Ubuntu, you might need to link `nodejs` executable to `node`:
|
||||
|
||||
Have a question?
|
||||
```
|
||||
sudo ln -s /usr/bin/nodejs /usr/bin/node
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Bower can be configured using JSON in a `.bowerrc` file. Read over available options at [bower.io/docs/config](http://bower.io/docs/config).
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
* [Discord chat](https://discord.gg/0fFM7QF0KpZRh2cY)
|
||||
* [StackOverflow](http://stackoverflow.com/questions/tagged/bower)
|
||||
* [Mailinglist](http://groups.google.com/group/twitter-bower) - twitter-bower@googlegroups.com
|
||||
* [\#bower](http://webchat.freenode.net/?channels=bower) on Freenode
|
||||
|
||||
## Contributing
|
||||
|
||||
## Contributing to this project
|
||||
We welcome [contributions](https://github.com/bower/bower/graphs/contributors) of all kinds from anyone. Please take a moment to review the [guidelines for contributing](CONTRIBUTING.md).
|
||||
|
||||
Anyone and everyone is welcome to contribute. Please take a moment to
|
||||
review the [guidelines for contributing](CONTRIBUTING.md).
|
||||
|
||||
* [Bug reports](CONTRIBUTING.md#bugs)
|
||||
* [Bug reports](https://github.com/bower/bower/wiki/Report-a-Bug)
|
||||
* [Feature requests](CONTRIBUTING.md#features)
|
||||
* [Pull requests](CONTRIBUTING.md#pull-requests)
|
||||
|
||||
|
||||
## Authors
|
||||
|
||||
* [@fat](https://github.com/fat)
|
||||
* [@maccman](https://github.com/maccman)
|
||||
* [@satazor](https://github.com/satazor)
|
||||
|
||||
Thanks for assistance and contributions:
|
||||
|
||||
[@addyosmani](https://github.com/addyosmani),
|
||||
[@angus-c](https://github.com/angus-c),
|
||||
[@borismus](https://github.com/borismus),
|
||||
[@carsonmcdonald](https://github.com/carsonmcdonald),
|
||||
[@chriseppstein](https://github.com/chriseppstein),
|
||||
[@danwrong](https://github.com/danwrong),
|
||||
[@davidmaxwaterman](https://github.com/davidmaxwaterman),
|
||||
[@desandro](https://github.com/desandro),
|
||||
[@hemanth](https://github.com/hemanth),
|
||||
[@isaacs](https://github.com/isaacs),
|
||||
[@josh](https://github.com/josh),
|
||||
[@jrburke](https://github.com/jrburke),
|
||||
[@marcelombc](https://github.com/marcelombc),
|
||||
[@marcooliveira](https://github.com/marcooliveira),
|
||||
[@mklabs](https://github.com/mklabs),
|
||||
[@MrDHat](https://github.com/MrDHat),
|
||||
[@necolas](https://github.com/necolas),
|
||||
[@paulirish](https://github.com/paulirish),
|
||||
[@richo](https://github.com/richo),
|
||||
[@rvagg](https://github.com/rvagg),
|
||||
[@sindresorhus](https://github.com/sindresorhus),
|
||||
[@SlexAxton](https://github.com/SlexAxton),
|
||||
[@sstephenson](https://github.com/sstephenson),
|
||||
[@svnlto](https://github.com/svnlto),
|
||||
[@tomdale](https://github.com/tomdale),
|
||||
[@uzquiano](https://github.com/uzquiano),
|
||||
[@visionmedia](https://github.com/visionmedia),
|
||||
[@wagenet](https://github.com/wagenet),
|
||||
[@wibblymat](https://github.com/wibblymat),
|
||||
[@wycats](https://github.com/wycats)
|
||||
Note that on Windows for tests to pass you need to configure Git before cloning:
|
||||
|
||||
```
|
||||
git config --global core.autocrlf input
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2012 Twitter, Inc.
|
||||
Copyright (c) 2016 Twitter and [other contributors](https://github.com/bower/bower/graphs/contributors)
|
||||
|
||||
Licensed under the MIT License
|
||||
|
||||
45
appveyor.yml
Normal file
45
appveyor.yml
Normal file
@@ -0,0 +1,45 @@
|
||||
# http://www.appveyor.com/docs/appveyor-yml
|
||||
|
||||
# Set build version format here instead of in the admin panel.
|
||||
version: "{build}"
|
||||
|
||||
# Fix line endings in Windows. (runs before repo cloning)
|
||||
init:
|
||||
- git config --global core.autocrlf input
|
||||
|
||||
# Test against these versions of Node.js.
|
||||
environment:
|
||||
matrix:
|
||||
- nodejs_version: "0.10"
|
||||
- nodejs_version: "0.12"
|
||||
- nodejs_version: "4.0"
|
||||
- nodejs_version: "4.1"
|
||||
- nodejs_version: "4.2"
|
||||
- nodejs_version: "5"
|
||||
- nodejs_version: "6"
|
||||
|
||||
# Finish on first failed build
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
# Install node, display versions, install dependencies
|
||||
install:
|
||||
- ps: Install-Product node $env:nodejs_version
|
||||
- node --version && npm --version
|
||||
- git --version && svn --version
|
||||
- npm install
|
||||
|
||||
# Post-install test scripts.
|
||||
test_script:
|
||||
- cmd: npm test
|
||||
|
||||
# Make clone much faster
|
||||
shallow_clone: true
|
||||
|
||||
# Disable Visual Studio build and deploy
|
||||
build: off
|
||||
deploy: off
|
||||
|
||||
# Cache node modules, and refresh if package.json changes
|
||||
cache:
|
||||
- node_modules -> package.json
|
||||
10
lerna.json
Normal file
10
lerna.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"lerna": "2.0.0-beta.23",
|
||||
"version": "independent",
|
||||
"publishConfig": {
|
||||
"ignore": [
|
||||
"ignored-file",
|
||||
"*.md"
|
||||
]
|
||||
}
|
||||
}
|
||||
4
lib/commands/cache/index.js
vendored
4
lib/commands/cache/index.js
vendored
@@ -1,4 +0,0 @@
|
||||
module.exports = {
|
||||
clean: require('./clean'),
|
||||
list: require('./list')
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
var Logger = require('bower-logger');
|
||||
var cli = require('../util/cli');
|
||||
|
||||
function completion(config) {
|
||||
var logger = new Logger();
|
||||
|
||||
process.nextTick(function () {
|
||||
logger.emit('end');
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
completion.line = function (argv) {
|
||||
var options = completion.options(argv);
|
||||
var name = options.argv.remain[1];
|
||||
|
||||
return completion(name);
|
||||
};
|
||||
|
||||
completion.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
|
||||
completion.completion = function () {
|
||||
// TODO:
|
||||
};
|
||||
|
||||
module.exports = completion;
|
||||
@@ -1,52 +0,0 @@
|
||||
var path = require('path');
|
||||
var fs = require('graceful-fs');
|
||||
var Logger = require('bower-logger');
|
||||
var cli = require('../util/cli');
|
||||
var createError = require('../util/createError');
|
||||
|
||||
function help(name) {
|
||||
var json;
|
||||
var logger = new Logger();
|
||||
|
||||
if (name) {
|
||||
json = path.resolve(__dirname, '../../templates/json/help-' + name.replace(/\s+/g, '/') + '.json');
|
||||
} else {
|
||||
json = path.resolve(__dirname, '../../templates/json/help.json');
|
||||
}
|
||||
|
||||
fs.exists(json, function (exists) {
|
||||
if (!exists) {
|
||||
return logger.emit('error', createError('Unknown command: ' + name, 'EUNKOWNCMD', {
|
||||
command: name
|
||||
}));
|
||||
}
|
||||
|
||||
try {
|
||||
json = require(json);
|
||||
} catch (error) {
|
||||
return logger.emit('error', error);
|
||||
}
|
||||
|
||||
logger.emit('end', json);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
help.line = function (argv) {
|
||||
var options = help.options(argv);
|
||||
|
||||
return help(options.argv.remain.slice(1).join(' '));
|
||||
};
|
||||
|
||||
help.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
|
||||
help.completion = function () {
|
||||
// TODO
|
||||
};
|
||||
|
||||
module.exports = help;
|
||||
@@ -1,17 +0,0 @@
|
||||
module.exports = {
|
||||
cache: require('./cache'),
|
||||
completion: require('./completion'),
|
||||
help: require('./help'),
|
||||
home: require('./home'),
|
||||
info: require('./info'),
|
||||
init: require('./init'),
|
||||
install: require('./install'),
|
||||
link: require('./link'),
|
||||
list: require('./list'),
|
||||
lookup: require('./lookup'),
|
||||
prune: require('./prune'),
|
||||
register: require('./register'),
|
||||
search: require('./search'),
|
||||
update: require('./update'),
|
||||
uninstall: require('./uninstall')
|
||||
};
|
||||
@@ -1,53 +0,0 @@
|
||||
var mout = require('mout');
|
||||
var Logger = require('bower-logger');
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
var Project = require('../core/Project');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function install(endpoints, options, config) {
|
||||
var project;
|
||||
var decEndpoints;
|
||||
var logger = new Logger();
|
||||
|
||||
options = options || {};
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
project = new Project(config, logger);
|
||||
|
||||
// Convert endpoints to decomposed endpoints
|
||||
endpoints = endpoints || [];
|
||||
decEndpoints = endpoints.map(function (endpoint) {
|
||||
return endpointParser.decompose(endpoint);
|
||||
});
|
||||
|
||||
project.install(decEndpoints, options)
|
||||
.done(function (installed) {
|
||||
logger.emit('end', installed);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
install.line = function (argv) {
|
||||
var options = install.options(argv);
|
||||
return install(options.argv.remain.slice(1), options);
|
||||
};
|
||||
|
||||
install.options = function (argv) {
|
||||
return cli.readOptions({
|
||||
'force-latest': { type: Boolean, shorthand: 'F'},
|
||||
'production': { type: Boolean, shorthand: 'p' },
|
||||
'save': { type: Boolean, shorthand: 'S' },
|
||||
'save-dev': { type: Boolean, shorthand: 'D' }
|
||||
}, argv);
|
||||
};
|
||||
|
||||
install.completion = function () {
|
||||
// TODO:
|
||||
};
|
||||
|
||||
module.exports = install;
|
||||
@@ -1,56 +0,0 @@
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var Logger = require('bower-logger');
|
||||
var RegistryClient = require('bower-registry-client');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function lookup(name, config) {
|
||||
var registryClient;
|
||||
var logger = new Logger();
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config.cache = config.storage.registry;
|
||||
|
||||
registryClient = new RegistryClient(config, logger);
|
||||
|
||||
Q.nfcall(registryClient.lookup.bind(registryClient), name)
|
||||
.then(function (entry) {
|
||||
// TODO: Handle entry.type.. for now it's only 'alias'
|
||||
// When we got published packages, this needs to be adjusted
|
||||
return !entry ? null : {
|
||||
name: name,
|
||||
url: entry && entry.url
|
||||
};
|
||||
})
|
||||
.done(function (result) {
|
||||
logger.emit('end', result);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
lookup.line = function (argv) {
|
||||
var options = lookup.options(argv);
|
||||
var name = options.argv.remain[1];
|
||||
|
||||
if (!name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return lookup(name);
|
||||
};
|
||||
|
||||
lookup.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
|
||||
lookup.completion = function () {
|
||||
// TODO:
|
||||
};
|
||||
|
||||
module.exports = lookup;
|
||||
@@ -1,131 +0,0 @@
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var chalk = require('chalk');
|
||||
var PackageRepository = require('../core/PackageRepository');
|
||||
var Logger = require('bower-logger');
|
||||
var Config = require('bower-config');
|
||||
var cli = require('../util/cli');
|
||||
var createError = require('../util/createError');
|
||||
var defaultConfig = require('../config');
|
||||
var GitHubResolver = require('../core/resolvers/GitHubResolver');
|
||||
|
||||
function register(name, url, config) {
|
||||
var repository;
|
||||
var registryClient;
|
||||
var logger = new Logger();
|
||||
var force;
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
force = config.force;
|
||||
|
||||
// Bypass any cache
|
||||
config.offline = false;
|
||||
config.force = true;
|
||||
|
||||
// Trim name
|
||||
name = name.trim();
|
||||
|
||||
process.nextTick(function () {
|
||||
// Verify name
|
||||
// TODO: Verify with the new spec regexp?
|
||||
if (!name) {
|
||||
return logger.emit('error', createError('Please type a name', 'EINVNAME'));
|
||||
}
|
||||
|
||||
// The public registry only allows git:// endpoints
|
||||
// As such, we attempt to convert URLs as necessary
|
||||
if (config.registry.register === Config.DEFAULT_REGISTRY) {
|
||||
url = convertUrl(url, logger);
|
||||
|
||||
if (!mout.string.startsWith(url, 'git://')) {
|
||||
return logger.emit('error', createError('The registry only accepts URLs starting with git://', 'EINVFORMAT'));
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to resolve the package referenced by the URL to ensure
|
||||
// everything is ok before registering
|
||||
repository = new PackageRepository(config, logger);
|
||||
repository.fetch({ name: name, source: url, target: '*' })
|
||||
.spread(function (canonicalDir, pkgMeta) {
|
||||
if (pkgMeta.private) {
|
||||
throw createError('The package you are trying to register is marked as private', 'EPRIV');
|
||||
}
|
||||
|
||||
// If non interactive or user forced, bypass confirmation
|
||||
if (!config.interactive || force) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Confirm if the user really wants to register
|
||||
return Q.nfcall(logger.prompt.bind(logger), {
|
||||
type: 'confirm',
|
||||
message: 'Registering a package will make it installable via the registry (' +
|
||||
chalk.cyan.underline(config.registry.register) + '), continue?',
|
||||
default: true
|
||||
});
|
||||
})
|
||||
.then(function (result) {
|
||||
// If user response was negative, abort
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Register
|
||||
registryClient = repository.getRegistryClient();
|
||||
|
||||
logger.action('register', url, {
|
||||
name: name,
|
||||
url: url
|
||||
});
|
||||
|
||||
return Q.nfcall(registryClient.register.bind(registryClient), name, url);
|
||||
})
|
||||
.done(function (result) {
|
||||
logger.emit('end', result);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
function convertUrl(url, logger) {
|
||||
var pair;
|
||||
var newUrl;
|
||||
|
||||
if (!mout.string.startsWith(url, 'git://')) {
|
||||
// Convert GitHub ssh & https to git://
|
||||
pair = GitHubResolver.getOrgRepoPair(url);
|
||||
if (pair) {
|
||||
newUrl = 'git://github.com/' + pair.org + '/' + pair.repo + '.git';
|
||||
logger.warn('convert', 'Converted ' + url + ' to ' + newUrl);
|
||||
}
|
||||
}
|
||||
|
||||
return newUrl || url;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
register.line = function (argv) {
|
||||
var options = register.options(argv);
|
||||
var name = options.argv.remain[1];
|
||||
var url = options.argv.remain[2];
|
||||
|
||||
if (!name || !url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return register(name, url);
|
||||
};
|
||||
|
||||
register.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
|
||||
register.completion = function () {
|
||||
// TODO:
|
||||
};
|
||||
|
||||
module.exports = register;
|
||||
@@ -1,51 +0,0 @@
|
||||
var mout = require('mout');
|
||||
var Q = require('q');
|
||||
var Logger = require('bower-logger');
|
||||
var RegistryClient = require('bower-registry-client');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function search(name, config) {
|
||||
var registryClient;
|
||||
var promise;
|
||||
var logger = new Logger();
|
||||
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
config.cache = config.storage.registry;
|
||||
|
||||
registryClient = new RegistryClient(config, logger);
|
||||
|
||||
// If no name was specified, list all packages
|
||||
if (!name) {
|
||||
promise = Q.nfcall(registryClient.list.bind(registryClient));
|
||||
// Otherwise search it
|
||||
} else {
|
||||
promise = Q.nfcall(registryClient.search.bind(registryClient), name);
|
||||
}
|
||||
|
||||
promise
|
||||
.done(function (results) {
|
||||
logger.emit('end', results);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
search.line = function (argv) {
|
||||
var options = search.options(argv);
|
||||
return search(options.argv.remain.slice(1).join(' '), options);
|
||||
};
|
||||
|
||||
search.options = function (argv) {
|
||||
return cli.readOptions(argv);
|
||||
};
|
||||
|
||||
search.completion = function () {
|
||||
// TODO:
|
||||
};
|
||||
|
||||
module.exports = search;
|
||||
@@ -1,48 +0,0 @@
|
||||
var mout = require('mout');
|
||||
var Logger = require('bower-logger');
|
||||
var Project = require('../core/Project');
|
||||
var cli = require('../util/cli');
|
||||
var defaultConfig = require('../config');
|
||||
|
||||
function update(names, options, config) {
|
||||
var project;
|
||||
var logger = new Logger();
|
||||
|
||||
options = options || {};
|
||||
config = mout.object.deepFillIn(config || {}, defaultConfig);
|
||||
project = new Project(config, logger);
|
||||
|
||||
// If names is an empty array, null them
|
||||
if (names && !names.length) {
|
||||
names = null;
|
||||
}
|
||||
|
||||
project.update(names, options)
|
||||
.done(function (installed) {
|
||||
logger.emit('end', installed);
|
||||
}, function (error) {
|
||||
logger.emit('error', error);
|
||||
});
|
||||
|
||||
return logger;
|
||||
}
|
||||
|
||||
// -------------------
|
||||
|
||||
update.line = function (argv) {
|
||||
var options = update.options(argv);
|
||||
return update(options.argv.remain.slice(1), options);
|
||||
};
|
||||
|
||||
update.options = function (argv) {
|
||||
return cli.readOptions({
|
||||
'force-latest': { type: Boolean, shorthand: 'F' },
|
||||
'production': { type: Boolean, shorthand: 'p' }
|
||||
}, argv);
|
||||
};
|
||||
|
||||
update.completion = function () {
|
||||
// TODO:
|
||||
};
|
||||
|
||||
module.exports = update;
|
||||
@@ -1,26 +0,0 @@
|
||||
var tty = require('tty');
|
||||
var mout = require('mout');
|
||||
var config = require('bower-config').read();
|
||||
var cli = require('./util/cli');
|
||||
|
||||
// Delete the json attribute because it is no longer supported
|
||||
// and conflicts with --json
|
||||
delete config.json;
|
||||
|
||||
// If interactive is auto (null), guess its value
|
||||
if (config.interactive == null) {
|
||||
config.interactive = process.bin === 'bower' && tty.isatty(1);
|
||||
}
|
||||
|
||||
// Merge common CLI options into the config
|
||||
mout.object.mixIn(config, cli.readOptions({
|
||||
force: { type: Boolean, shorthand: 'f' },
|
||||
offline: { type: Boolean, shorthand: 'o' },
|
||||
verbose: { type: Boolean, shorthand: 'V' },
|
||||
quiet: { type: Boolean, shorthand: 'q' },
|
||||
loglevel: { type: String, shorthand: 'l' },
|
||||
json: { type: Boolean, shorthand: 'j' },
|
||||
silent: { type: Boolean, shorthand: 's' }
|
||||
}));
|
||||
|
||||
module.exports = config;
|
||||
@@ -1,154 +0,0 @@
|
||||
var Q = require('q');
|
||||
var fs = require('graceful-fs');
|
||||
var path = require('path');
|
||||
var mout = require('mout');
|
||||
var resolvers = require('./resolvers');
|
||||
var createError = require('../util/createError');
|
||||
|
||||
function createInstance(decEndpoint, config, logger, registryClient) {
|
||||
return getConstructor(decEndpoint.source, config, registryClient)
|
||||
.spread(function (ConcreteResolver, source, fromRegistry) {
|
||||
var decEndpointCopy = mout.object.pick(decEndpoint, ['name', 'target']);
|
||||
|
||||
decEndpointCopy.source = source;
|
||||
|
||||
// Signal if it was fetched from the registry
|
||||
if (fromRegistry) {
|
||||
decEndpoint.registry = true;
|
||||
// If no name was specified, assume the name from the registry
|
||||
if (!decEndpointCopy.name) {
|
||||
decEndpointCopy.name = decEndpoint.name = decEndpoint.source;
|
||||
}
|
||||
}
|
||||
|
||||
return new ConcreteResolver(decEndpointCopy, config, logger);
|
||||
});
|
||||
}
|
||||
|
||||
function getConstructor(source, config, registryClient) {
|
||||
var absolutePath,
|
||||
promise;
|
||||
|
||||
// Git case: git git+ssh, git+http, git+https
|
||||
// .git at the end (probably ssh shorthand)
|
||||
// git@ at the start
|
||||
if (/^git(\+(ssh|https?))?:\/\//i.test(source) || /\.git\/?$/i.test(source) || /^git@/i.test(source)) {
|
||||
source = source.replace(/^git\+/, '');
|
||||
return Q.fcall(function () {
|
||||
|
||||
// If it's a GitHub repository, return the specialized resolver
|
||||
if (resolvers.GitHub.getOrgRepoPair(source)) {
|
||||
return [resolvers.GitHub, source];
|
||||
}
|
||||
|
||||
return [resolvers.GitRemote, source];
|
||||
});
|
||||
}
|
||||
|
||||
// URL case
|
||||
if (/^https?:\/\//i.exec(source)) {
|
||||
return Q.fcall(function () {
|
||||
return [resolvers.Url, source];
|
||||
});
|
||||
}
|
||||
|
||||
// Below we try a series of async tests to guess the type of resolver to use
|
||||
// If a step was unable to guess the resolver, it throws an error
|
||||
// If a step was able to guess the resolver, it resolves with a function
|
||||
// That function returns a promise that will resolve with the concrete type
|
||||
|
||||
// If source is ./ or ../ or an absolute path
|
||||
absolutePath = path.resolve(config.cwd, source);
|
||||
|
||||
if (/^\.\.?[\/\\]/.test(source) || /^~\//.test(source) || path.normalize(source) === absolutePath) {
|
||||
promise = Q.nfcall(fs.stat, path.join(absolutePath, '.git'))
|
||||
.then(function (stats) {
|
||||
if (stats.isDirectory()) {
|
||||
return function () {
|
||||
return Q.resolve([resolvers.GitFs, absolutePath]);
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error('Not a Git repository');
|
||||
})
|
||||
// If not, check if source is a valid file/folder
|
||||
.fail(function () {
|
||||
return Q.nfcall(fs.stat, absolutePath)
|
||||
.then(function () {
|
||||
return function () {
|
||||
return Q.resolve([resolvers.Fs, absolutePath]);
|
||||
};
|
||||
});
|
||||
});
|
||||
} else {
|
||||
promise = Q.reject(new Error('Not an absolute or relative file'));
|
||||
}
|
||||
|
||||
return promise
|
||||
// Check if is a shorthand and expand it
|
||||
.fail(function (err) {
|
||||
var parts;
|
||||
|
||||
// Skip ssh and/or URL with auth
|
||||
if (/[:@]/.test(source)) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
// Ensure exactly only one "/"
|
||||
parts = source.split('/');
|
||||
if (parts.length === 2) {
|
||||
source = mout.string.interpolate(config.shorthandResolver, {
|
||||
shorthand: source,
|
||||
owner: parts[0],
|
||||
package: parts[1]
|
||||
});
|
||||
|
||||
return function () {
|
||||
return getConstructor(source, config, registryClient);
|
||||
};
|
||||
}
|
||||
|
||||
throw err;
|
||||
})
|
||||
// As last resort, we try the registry
|
||||
.fail(function (err) {
|
||||
if (!registryClient) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
return function () {
|
||||
return Q.nfcall(registryClient.lookup.bind(registryClient), source)
|
||||
.then(function (entry) {
|
||||
if (!entry) {
|
||||
throw createError('Package ' + source + ' not found', 'ENOTFOUND');
|
||||
}
|
||||
|
||||
// TODO: Handle entry.type.. for now it's only 'alias'
|
||||
// When we got published packages, this needs to be adjusted
|
||||
source = entry.url;
|
||||
|
||||
return getConstructor(source, config, registryClient)
|
||||
.spread(function (ConcreteResolver, source) {
|
||||
return [ConcreteResolver, source, true];
|
||||
});
|
||||
});
|
||||
};
|
||||
})
|
||||
// If we got the function, simply call and return
|
||||
.then(function (func) {
|
||||
return func();
|
||||
// Finally throw a meaningful error
|
||||
}, function () {
|
||||
throw createError('Could not find appropriate resolver for ' + source, 'ENORESOLVER');
|
||||
});
|
||||
}
|
||||
|
||||
function clearRuntimeCache() {
|
||||
mout.object.values(resolvers).forEach(function (ConcreteResolver) {
|
||||
ConcreteResolver.clearRuntimeCache();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = createInstance;
|
||||
module.exports.getConstructor = getConstructor;
|
||||
module.exports.clearRuntimeCache = clearRuntimeCache;
|
||||
40
lib/index.js
40
lib/index.js
@@ -1,40 +0,0 @@
|
||||
var abbrev = require('abbrev');
|
||||
var mout = require('mout');
|
||||
var commands = require('./commands');
|
||||
var PackageRepository = require('./core/PackageRepository');
|
||||
|
||||
var abbreviations = abbrev(expandNames(commands));
|
||||
abbreviations.i = 'install';
|
||||
abbreviations.rm = 'uninstall';
|
||||
abbreviations.ls = 'list';
|
||||
|
||||
function expandNames(obj, prefix, stack) {
|
||||
prefix = prefix || '';
|
||||
stack = stack || [];
|
||||
|
||||
mout.object.forOwn(obj, function (value, name) {
|
||||
name = prefix + name;
|
||||
|
||||
stack.push(name);
|
||||
|
||||
if (typeof value === 'object' && !value.line) {
|
||||
expandNames(value, name + ' ', stack);
|
||||
}
|
||||
});
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
function clearRuntimeCache() {
|
||||
// Note that in edge cases, some architecture components instance's
|
||||
// in-memory cache might be skipped.
|
||||
// If that's a problem, you should create and fresh instances instead.
|
||||
PackageRepository.clearRuntimeCache();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
commands: commands,
|
||||
config: require('./config'),
|
||||
abbreviations: abbreviations,
|
||||
reset: clearRuntimeCache
|
||||
};
|
||||
@@ -1,109 +0,0 @@
|
||||
var progress = require('request-progress');
|
||||
var request = require('request');
|
||||
var Q = require('q');
|
||||
var mout = require('mout');
|
||||
var retry = require('retry');
|
||||
var fs = require('graceful-fs');
|
||||
var createError = require('./createError');
|
||||
|
||||
var errorCodes = [
|
||||
'EADDRINFO',
|
||||
'ETIMEDOUT',
|
||||
'ECONNRESET',
|
||||
'ESOCKETTIMEDOUT'
|
||||
];
|
||||
|
||||
function download(url, file, options) {
|
||||
var operation;
|
||||
var response;
|
||||
var deferred = Q.defer();
|
||||
var progressDelay = 8000;
|
||||
|
||||
options = mout.object.mixIn({
|
||||
retries: 5,
|
||||
factor: 2,
|
||||
minTimeout: 1000,
|
||||
maxTimeout: 35000,
|
||||
randomize: true
|
||||
}, options || {});
|
||||
|
||||
// Retry on network errors
|
||||
operation = retry.operation(options);
|
||||
operation.attempt(function () {
|
||||
var req;
|
||||
var writeStream;
|
||||
var contentLength;
|
||||
var bytesDownloaded = 0;
|
||||
|
||||
req = progress(request(url, options), {
|
||||
delay: progressDelay
|
||||
})
|
||||
.on('response', function (res) {
|
||||
var status = res.statusCode;
|
||||
|
||||
if (status < 200 || status >= 300) {
|
||||
return deferred.reject(createError('Status code of ' + status, 'EHTTP'));
|
||||
}
|
||||
|
||||
response = res;
|
||||
contentLength = Number(res.headers['content-length']);
|
||||
})
|
||||
.on('data', function (data) {
|
||||
bytesDownloaded += data.length;
|
||||
})
|
||||
.on('progress', function (state) {
|
||||
deferred.notify(state);
|
||||
})
|
||||
.on('end', function () {
|
||||
// Check if the whole file was downloaded
|
||||
// In some unstable connections the ACK/FIN packet might be sent in the
|
||||
// middle of the download
|
||||
// See: https://github.com/joyent/node/issues/6143
|
||||
if (contentLength && bytesDownloaded < contentLength) {
|
||||
req.emit('error', createError('Transfer closed with ' + (contentLength - bytesDownloaded) + ' bytes remaining to read', 'EINCOMPLETE'));
|
||||
}
|
||||
})
|
||||
.on('error', function (error) {
|
||||
var timeout = operation._timeouts[0];
|
||||
|
||||
// Reject if error is not a network error
|
||||
if (errorCodes.indexOf(error.code) === -1) {
|
||||
return deferred.reject(error);
|
||||
}
|
||||
|
||||
// Next attempt will start reporting download progress immediately
|
||||
progressDelay = 0;
|
||||
|
||||
// Check if there are more retries
|
||||
if (operation.retry(error)) {
|
||||
// Ensure that there are no more events from this request
|
||||
req.removeAllListeners();
|
||||
req.on('error', function () {});
|
||||
// Ensure that there are no more events from the write stream
|
||||
writeStream.removeAllListeners();
|
||||
writeStream.on('error', function () {});
|
||||
|
||||
return deferred.notify({
|
||||
retry: true,
|
||||
delay: timeout,
|
||||
error: error
|
||||
});
|
||||
}
|
||||
|
||||
// No more retries, reject!
|
||||
deferred.reject(error);
|
||||
});
|
||||
|
||||
// Pipe read stream to write stream
|
||||
writeStream = req
|
||||
.pipe(fs.createWriteStream(file))
|
||||
.on('error', deferred.reject)
|
||||
.on('close', function () {
|
||||
deferred.resolve(response);
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
module.exports = download;
|
||||
79
package.json
79
package.json
@@ -1,79 +1,10 @@
|
||||
{
|
||||
"name": "bower",
|
||||
"version": "1.2.7",
|
||||
"description": "The browser package manager.",
|
||||
"author": "Twitter",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/bower/bower/blob/master/LICENSE"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/bower/bower.git"
|
||||
},
|
||||
"main": "lib",
|
||||
"homepage": "http://bower.io",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"abbrev": "~1.0.4",
|
||||
"archy": "0.0.2",
|
||||
"bower-config": "~0.5.0",
|
||||
"bower-endpoint-parser": "~0.2.0",
|
||||
"bower-json": "~0.4.0",
|
||||
"bower-logger": "~0.2.1",
|
||||
"bower-registry-client": "~0.1.4",
|
||||
"cardinal": "~0.4.0",
|
||||
"chalk": "~0.2.0",
|
||||
"chmodr": "~0.1.0",
|
||||
"fstream": "~0.1.22",
|
||||
"fstream-ignore": "~0.0.6",
|
||||
"glob": "~3.2.1",
|
||||
"graceful-fs": "~2.0.0",
|
||||
"handlebars": "~1.0.11",
|
||||
"inquirer": "~0.3.0",
|
||||
"junk": "~0.2.0",
|
||||
"mkdirp": "~0.3.5",
|
||||
"mout": "~0.7.0",
|
||||
"nopt": "~2.1.1",
|
||||
"lru-cache": "~2.3.0",
|
||||
"open": "~0.0.3",
|
||||
"osenv": "0.0.3",
|
||||
"promptly": "~0.2.0",
|
||||
"q": "~0.9.2",
|
||||
"request": "~2.27.0",
|
||||
"request-progress": "~0.3.0",
|
||||
"retry": "~0.6.0",
|
||||
"rimraf": "~2.2.0",
|
||||
"semver": "~2.1.0",
|
||||
"stringify-object": "~0.1.4",
|
||||
"sudo-block": "~0.2.0",
|
||||
"tar": "~0.1.17",
|
||||
"tmp": "~0.0.20",
|
||||
"unzip": "~0.1.7",
|
||||
"update-notifier": "~0.1.3",
|
||||
"which": "~1.0.5"
|
||||
},
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"expect.js": "~0.2.0",
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-simple-mocha": "~0.4.0",
|
||||
"grunt-contrib-watch": "~0.5.0",
|
||||
"grunt-contrib-jshint": "~0.6.0",
|
||||
"grunt-exec": "~0.4.2",
|
||||
"mocha": "~1.12.0",
|
||||
"nock": "~0.22.0",
|
||||
"istanbul": "~0.1.42",
|
||||
"proxyquire": "~0.5.0"
|
||||
"lerna": "2.0.0-beta.23"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt test"
|
||||
},
|
||||
"bin": {
|
||||
"bower": "bin/bower"
|
||||
},
|
||||
"preferGlobal": true
|
||||
"postinstall": "lerna bootstrap",
|
||||
"test": "lerna run test"
|
||||
}
|
||||
}
|
||||
|
||||
12
packages/bower-config/.editorconfig
Normal file
12
packages/bower-config/.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
7
packages/bower-config/.gitignore
vendored
Normal file
7
packages/bower-config/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
|
||||
test/assets/github-test-package
|
||||
test/assets/github-test-package-copy
|
||||
test/assets/temp
|
||||
test/reports
|
||||
61
packages/bower-config/.jshintrc
Normal file
61
packages/bower-config/.jshintrc
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"predef": [
|
||||
"console",
|
||||
"describe",
|
||||
"it",
|
||||
"after",
|
||||
"afterEach",
|
||||
"before",
|
||||
"beforeEach"
|
||||
],
|
||||
|
||||
"indent": 4,
|
||||
"node": true,
|
||||
"devel": true,
|
||||
|
||||
"bitwise": false,
|
||||
"curly": false,
|
||||
"eqeqeq": true,
|
||||
"forin": false,
|
||||
"immed": true,
|
||||
"latedef": false,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": false,
|
||||
"nonew": true,
|
||||
"plusplus": false,
|
||||
"regexp": false,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"quotmark": "single",
|
||||
"strict": false,
|
||||
"trailing": true,
|
||||
|
||||
"asi": false,
|
||||
"boss": true,
|
||||
"debug": false,
|
||||
"eqnull": true,
|
||||
"es5": false,
|
||||
"esnext": false,
|
||||
"evil": false,
|
||||
"expr": false,
|
||||
"funcscope": false,
|
||||
"globalstrict": false,
|
||||
"iterator": false,
|
||||
"lastsemic": false,
|
||||
"laxbreak": true,
|
||||
"laxcomma": false,
|
||||
"loopfunc": true,
|
||||
"multistr": false,
|
||||
"onecase": true,
|
||||
"regexdash": false,
|
||||
"scripturl": false,
|
||||
"smarttabs": false,
|
||||
"shadow": false,
|
||||
"sub": false,
|
||||
"supernew": true,
|
||||
"validthis": false,
|
||||
|
||||
"nomen": false,
|
||||
"white": true
|
||||
}
|
||||
9
packages/bower-config/.travis.yml
Normal file
9
packages/bower-config/.travis.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
node_js:
|
||||
- '5'
|
||||
- '4'
|
||||
- '0.12'
|
||||
- '0.10'
|
||||
script:
|
||||
- grunt travis
|
||||
103
packages/bower-config/CHANGELOG.md
Normal file
103
packages/bower-config/CHANGELOG.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Changelog
|
||||
|
||||
## 1.4.0
|
||||
|
||||
- Change default shorthand resolver from git:// to https://
|
||||
|
||||
## 1.3.1
|
||||
|
||||
- Ignore hook scripts for environment variable expansion
|
||||
|
||||
## 1.3.0 - 2015-12-07
|
||||
|
||||
- Allow the use of environment variables in .bowerrc. Fixes [#41](https://github.com/bower/config/issues/41)
|
||||
- Loads the .bowerrc file from the cwd specified on the command line. Fixes [bower/bower#1993](https://github.com/bower/bower/issues/1993)
|
||||
- Allwow for array notation in ENV variables [#44](https://github.com/bower/config/issues/44)
|
||||
|
||||
## 1.2.3 - 2015-11-27
|
||||
|
||||
- Restores env variables if they are undefined at the beginning
|
||||
- Handles default setting for config.ca. Together with [bower/bower PR #1972](https://github.com/bower/bower/pull/1972), fixes downloading with `strict-ssl` using custom CA
|
||||
- Displays an error message if .bowerrc is a directory instead of file. Fixes [bower/bower#2022](https://github.com/bower/bower/issues/2022)
|
||||
|
||||
## 1.2.2 - 2015-10-16
|
||||
- Fixes registry configurartion expanding [bower/bower#1950](https://github.com/bower/bower/issues/1950)
|
||||
|
||||
## 1.2.1 - 2015-10-15
|
||||
- Fixes case insenstivity HTTP_PROXY setting issue on Windows
|
||||
|
||||
## 1.2.0 - 2015-09-28
|
||||
- Prevent defaulting cwd to process.cwd()
|
||||
|
||||
## 1.1.2 - 2015-09-27
|
||||
- Performs only camel case normalisation before merging
|
||||
|
||||
## 1.1.1 - 2015-09-27
|
||||
- Fix: Merge extra options after camel-case normalisation, instead of before it
|
||||
|
||||
## 1.1.0 - 2015-09-27
|
||||
- Allow for overwriting options with .load(overwrites) / .read(cwd, overwrites)
|
||||
|
||||
## 1.0.1 - 2015-09-27
|
||||
- Update dependencies and relax "mout" version range
|
||||
- Most significant changes:
|
||||
- graceful-fs updated from 2.x version to 4.x
|
||||
- osenv updated to from 0.0.x to 0.1.x, [tmp location changed](https://github.com/npm/osenv/commit/d6eddbc026538b09026b1dbd60fbc081a8c67e03)
|
||||
|
||||
## 1.0.0 - 2015-09-27
|
||||
- Support for no-proxy configuration variable
|
||||
- Overwrite HTTP_PROXY, HTTPS_PROXY, and NO_PROXY env variables in load method
|
||||
- Normalise paths to certificates with contents of them, [#28](https://github.com/bower/config/pull/28)
|
||||
|
||||
## 0.6.1 - 2015-04-1
|
||||
- Fixes merging .bowerrc files upward directory tree. [#25](https://github.com/bower/config/issues/25)
|
||||
|
||||
## 0.6.0 - 2015-03-30
|
||||
- Merge .bowerrc files upward directory tree (fixes [bower/bower#1689](https://github.com/bower/bower/issues/1689)) [#24](https://github.com/bower/config/pull/24)
|
||||
- Allow NPM config variables (resolves [bower/bower#1711](https://github.com/bower/bower/issues/1711)) [#23](https://github.com/bower/config/pull/23)
|
||||
|
||||
## 0.5.2 - 2014-06-09
|
||||
- Fixes downloading of bower modules with ignores when .bowerrc is overridden with a relative tmp path. [#17](https://github.com/bower/config/issues/17) [bower/bower#1299](https://github.com/bower/bower/issues/1299)
|
||||
|
||||
## 0.5.1 - 2014-05-21
|
||||
- [perf] Uses the same mout version as bower
|
||||
- [perf] Uses only relevant parts of mout. Related [bower/bower#1134](https://github.com/bower/bower/pull/1134)
|
||||
|
||||
## 0.5.0 - 2013-08-30
|
||||
- Adds a DEFAULT_REGISTRY key to the Config class that exposes the bower registry UR. [#6](https://github.com/bower/config/issues/6)
|
||||
|
||||
## 0.4.5 - 2013-08-28
|
||||
- Fixes crashing when home is not set
|
||||
|
||||
## 0.4.4 - 2013-08-21
|
||||
- Supports nested environment variables [#8](https://github.com/bower/config/issues/8)
|
||||
|
||||
## 0.4.3 - 2013-08-19
|
||||
- Improvement in argv.config parsing
|
||||
|
||||
## 0.4.2 - 2013-08-18
|
||||
- Sets interative to auto
|
||||
|
||||
## 0.4.1 - 2013-08-18
|
||||
- Generates a fake user instead of using 'unknown'
|
||||
|
||||
## 0.4.0 - 2013-08-16
|
||||
- Suffixes temp folder with the user and 'bower'
|
||||
|
||||
## 0.3.5 - 2013-08-14
|
||||
- Casts buffer to string
|
||||
|
||||
## 0.3.4 - 2013-08-11
|
||||
- Empty .bowerrc files no longer throw an error.
|
||||
|
||||
## 0.3.3 - 2013-08-11
|
||||
- Changes git folder to empty (was not being used anyway)
|
||||
|
||||
## 0.3.2 - 2013-08-07
|
||||
- Uses a known user agent by default when a proxy.
|
||||
|
||||
## 0.3.1 - 2013-08-06
|
||||
- Fixes Typo
|
||||
|
||||
## 0.3.0 - 2013-08-06
|
||||
- Appends the username when using the temporary folder.
|
||||
47
packages/bower-config/Gruntfile.js
Normal file
47
packages/bower-config/Gruntfile.js
Normal file
@@ -0,0 +1,47 @@
|
||||
'use strict';
|
||||
module.exports = function (grunt) {
|
||||
require('load-grunt-tasks')(grunt);
|
||||
|
||||
grunt.initConfig({
|
||||
simplemocha: {
|
||||
options: {
|
||||
reporter: 'spec',
|
||||
timeout: '10000'
|
||||
},
|
||||
full: {
|
||||
src: ['test/test.js']
|
||||
},
|
||||
short: {
|
||||
options: {
|
||||
reporter: 'dot'
|
||||
},
|
||||
src: ['test/test.js']
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
cover: {
|
||||
command: 'STRICT_REQUIRE=1 node node_modules/istanbul/lib/cli.js cover --dir ./test/reports node_modules/mocha/bin/_mocha -- --timeout 30000 -R dot test/test.js'
|
||||
},
|
||||
coveralls: {
|
||||
command: 'node node_modules/.bin/coveralls < test/reports/lcov.info'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
files: [
|
||||
'Gruntfile.js',
|
||||
'bin/*',
|
||||
'lib/**/*.js',
|
||||
'test/**/*.js',
|
||||
'!test/assets/**/*',
|
||||
'!test/reports/**/*',
|
||||
'!test/tmp/**/*'
|
||||
],
|
||||
tasks: ['simplemocha:short']
|
||||
}
|
||||
});
|
||||
|
||||
grunt.registerTask('test', ['simplemocha:full']);
|
||||
grunt.registerTask('cover', 'exec:cover');
|
||||
grunt.registerTask('travis', ['exec:cover', 'exec:coveralls']);
|
||||
grunt.registerTask('default', 'test');
|
||||
};
|
||||
76
packages/bower-config/README.md
Normal file
76
packages/bower-config/README.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# bower-config [](http://travis-ci.org/bower/config)[](https://coveralls.io/github/bower/config?branch=master)
|
||||
|
||||
> The Bower config (`.bowerrc`) reader and writer.
|
||||
|
||||
[Bower](http://bower.io/) can be configured using JSON in a `.bowerrc` file. For example:
|
||||
|
||||
{
|
||||
"directory": "app/components/",
|
||||
"timeout": 120000,
|
||||
"registry": {
|
||||
"search": [
|
||||
"http://localhost:8000",
|
||||
"https://bower.herokuapp.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
View the complete [.bowerrc specification](http://bower.io/docs/config/#bowerrc-specification) on the website for more details. Both the `bower.json` and `.bowerrc` specifications are maintained at [github.com/bower/spec](https://github.com/bower/spec).
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
$ npm install --save bower-config
|
||||
```
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
#### .load(overwrites)
|
||||
|
||||
Loads the bower configuration from the configuration files.
|
||||
|
||||
Configuration is overwritten (after camelcase normalisation) with `overwrites` argument.
|
||||
|
||||
This method overwrites following environment variables:
|
||||
|
||||
- `HTTP_PROXY` with `proxy` configuration variable
|
||||
- `HTTPS_PROXY` with `https-proxy` configuration variable
|
||||
- `NO_PROXY` with `no-proxy` configuration variable
|
||||
|
||||
It also clears `http_proxy`, `https_proxy`, and `no_proxy` environment variables.
|
||||
|
||||
To restore those variables you can use `restore` method.
|
||||
|
||||
#### restore()
|
||||
|
||||
Restores environment variables overwritten by `.load` method.
|
||||
|
||||
#### .toObject()
|
||||
|
||||
Returns a deep copy of the underlying configuration object.
|
||||
The returned configuration is normalised.
|
||||
The object keys will be camelCase.
|
||||
|
||||
|
||||
#### #create(cwd)
|
||||
|
||||
Obtains a instance where `cwd` is the current working directory (defaults to `process.cwd`);
|
||||
|
||||
```js
|
||||
var config = require('bower-config').create();
|
||||
// You can also specify a working directory
|
||||
var config2 = require('bower-config').create('./some/path');
|
||||
```
|
||||
|
||||
#### #read(cwd, overrides)
|
||||
|
||||
Alias for:
|
||||
|
||||
```js
|
||||
var configObject = (new Config(cwd)).load(overrides).toJson();
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Released under the [MIT License](http://www.opensource.org/licenses/mit-license.php).
|
||||
109
packages/bower-config/lib/Config.js
Normal file
109
packages/bower-config/lib/Config.js
Normal file
@@ -0,0 +1,109 @@
|
||||
var lang = require('mout/lang');
|
||||
var object = require('mout/object');
|
||||
var rc = require('./util/rc');
|
||||
var expand = require('./util/expand');
|
||||
var EnvProxy = require('./util/proxy');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
|
||||
function Config(cwd) {
|
||||
this._cwd = cwd;
|
||||
this._proxy = new EnvProxy();
|
||||
this._config = {};
|
||||
}
|
||||
|
||||
Config.prototype.load = function (overwrites) {
|
||||
this._config = rc('bower', this._cwd);
|
||||
|
||||
this._config = object.merge(
|
||||
expand(this._config || {}),
|
||||
expand(overwrites || {})
|
||||
);
|
||||
|
||||
this._config = normalise(this._config);
|
||||
|
||||
this._proxy.set(this._config);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Config.prototype.restore = function () {
|
||||
this._proxy.restore();
|
||||
};
|
||||
|
||||
function readCertFile(path) {
|
||||
path = path || '';
|
||||
|
||||
var sep = '-----END CERTIFICATE-----';
|
||||
|
||||
var certificates;
|
||||
|
||||
if (path.indexOf(sep) === -1) {
|
||||
certificates = fs.readFileSync(path, { encoding: 'utf8' });
|
||||
} else {
|
||||
certificates = path;
|
||||
}
|
||||
|
||||
return certificates.
|
||||
split(sep).
|
||||
filter(function(s) { return !s.match(/^\s*$/); }).
|
||||
map(function(s) { return s + sep; });
|
||||
}
|
||||
|
||||
function loadCAs(caConfig) {
|
||||
// If a ca file path has been specified, expand that here to the file's
|
||||
// contents. As a user can specify these individually, we must load them
|
||||
// one by one.
|
||||
for (var p in caConfig) {
|
||||
if (caConfig.hasOwnProperty(p)) {
|
||||
var prop = caConfig[p];
|
||||
if (Array.isArray(prop)) {
|
||||
caConfig[p] = prop.map(function(s) {
|
||||
return readCertFile(s);
|
||||
});
|
||||
} else if (prop) {
|
||||
caConfig[p] = readCertFile(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Config.prototype.toObject = function () {
|
||||
return lang.deepClone(this._config);
|
||||
};
|
||||
|
||||
Config.create = function (cwd) {
|
||||
return new Config(cwd);
|
||||
};
|
||||
|
||||
Config.read = function (cwd, overrides) {
|
||||
var config = Config.create(cwd);
|
||||
return config.load(overrides).toObject();
|
||||
};
|
||||
|
||||
function normalise(config) {
|
||||
config = expand(config);
|
||||
|
||||
// Some backwards compatible things..
|
||||
if (config.shorthandResolver) {
|
||||
config.shorthandResolver = config.shorthandResolver
|
||||
.replace(/\{\{\{/g, '{{')
|
||||
.replace(/\}\}\}/g, '}}');
|
||||
}
|
||||
|
||||
// Ensure that every registry endpoint does not end with /
|
||||
config.registry.search = config.registry.search.map(function (url) {
|
||||
return url.replace(/\/+$/, '');
|
||||
});
|
||||
config.registry.register = config.registry.register.replace(/\/+$/, '');
|
||||
config.registry.publish = config.registry.publish.replace(/\/+$/, '');
|
||||
config.tmp = path.resolve(config.tmp);
|
||||
|
||||
loadCAs(config.ca);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
Config.DEFAULT_REGISTRY = require('./util/defaults').registry;
|
||||
|
||||
module.exports = Config;
|
||||
45
packages/bower-config/lib/util/defaults.js
Normal file
45
packages/bower-config/lib/util/defaults.js
Normal file
@@ -0,0 +1,45 @@
|
||||
var path = require('path');
|
||||
var paths = require('./paths');
|
||||
|
||||
// Guess proxy defined in the env
|
||||
var proxy = process.env.HTTP_PROXY
|
||||
|| process.env.http_proxy
|
||||
|| null;
|
||||
|
||||
var httpsProxy = process.env.HTTPS_PROXY
|
||||
|| process.env.https_proxy
|
||||
|| proxy;
|
||||
|
||||
var noProxy = process.env.NO_PROXY
|
||||
|| process.env.no_proxy;
|
||||
|
||||
// Use a well known user agent (in this case, curl) when using a proxy,
|
||||
// to avoid potential filtering on many corporate proxies with blank or unknown agents
|
||||
var userAgent = !proxy && !httpsProxy
|
||||
? 'node/' + process.version + ' ' + process.platform + ' ' + process.arch
|
||||
: 'curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5';
|
||||
|
||||
var defaults = {
|
||||
'directory': 'bower_components',
|
||||
'registry': 'https://bower.herokuapp.com',
|
||||
'shorthand-resolver': 'https://github.com/{{owner}}/{{package}}.git',
|
||||
'tmp': paths.tmp,
|
||||
'proxy': proxy,
|
||||
'https-proxy': httpsProxy,
|
||||
'no-proxy': noProxy,
|
||||
'timeout': 30000,
|
||||
'ca': { search: [] },
|
||||
'strict-ssl': true,
|
||||
'user-agent': userAgent,
|
||||
'color': true,
|
||||
'interactive': null,
|
||||
'storage': {
|
||||
packages: path.join(paths.cache, 'packages'),
|
||||
links: path.join(paths.data, 'links'),
|
||||
completion: path.join(paths.data, 'completion'),
|
||||
registry: path.join(paths.cache, 'registry'),
|
||||
empty: path.join(paths.data, 'empty') // Empty dir, used in GIT_TEMPLATE_DIR among others
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = defaults;
|
||||
126
packages/bower-config/lib/util/expand.js
Normal file
126
packages/bower-config/lib/util/expand.js
Normal file
@@ -0,0 +1,126 @@
|
||||
var object = require('mout/object');
|
||||
var lang = require('mout/lang');
|
||||
var string = require('mout/string');
|
||||
|
||||
function camelCase(config) {
|
||||
var camelCased = {};
|
||||
|
||||
// Camel case
|
||||
object.forOwn(config, function (value, key) {
|
||||
// Ignore null values
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
key = string.camelCase(key.replace(/_/g, '-'));
|
||||
camelCased[key] = lang.isPlainObject(value) ? camelCase(value) : value;
|
||||
});
|
||||
|
||||
return camelCased;
|
||||
}
|
||||
|
||||
// Function to replace ${VAR} - style variables
|
||||
// with values set in the environment
|
||||
// This function expects to be passed a string
|
||||
function doEnvReplaceStr (f) {
|
||||
|
||||
// Un-tildify
|
||||
var untildify = require('untildify');
|
||||
f = untildify(f);
|
||||
|
||||
// replace any ${ENV} values with the appropriate environ.
|
||||
var envExpr = /(\\*)\$\{([^}]+)\}/g;
|
||||
return f.replace(envExpr, function (orig, esc, name) {
|
||||
esc = esc.length && esc.length % 2;
|
||||
if (esc) return orig;
|
||||
if (undefined === process.env[name]) {
|
||||
throw new Error('Environment variable used in .bowerrc is not defined: ' + orig);
|
||||
}
|
||||
|
||||
return process.env[name];
|
||||
});
|
||||
}
|
||||
|
||||
function envReplace(config) {
|
||||
var envReplaced = {};
|
||||
|
||||
object.forOwn(config, function (value, key) {
|
||||
|
||||
// Ignore null values
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore 'scripts'
|
||||
// These hooks run within the shell
|
||||
// environment variable expansion is not required
|
||||
if ( key === 'scripts' && lang.isPlainObject(value) ){
|
||||
envReplaced[key] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform variable replacements based on var type
|
||||
if ( lang.isPlainObject(value) ) {
|
||||
envReplaced[key] = envReplace(value);
|
||||
}
|
||||
else if ( lang.isString(value) ) {
|
||||
envReplaced[key] = doEnvReplaceStr(value);
|
||||
}
|
||||
else {
|
||||
envReplaced[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
return envReplaced;
|
||||
}
|
||||
|
||||
function expand(config) {
|
||||
config = camelCase(config);
|
||||
config = envReplace(config);
|
||||
|
||||
if (typeof config.registry === 'string') {
|
||||
config.registry = {
|
||||
default: config.registry,
|
||||
search: [config.registry],
|
||||
register: config.registry,
|
||||
publish: config.registry
|
||||
};
|
||||
} else if (typeof config.registry === 'object') {
|
||||
config.registry.default = config.registry.default || 'https://bower.herokuapp.com';
|
||||
|
||||
config.registry = {
|
||||
default: config.registry.default,
|
||||
search: config.registry.search || config.registry.default,
|
||||
register: config.registry.register || config.registry.default,
|
||||
publish: config.registry.publish || config.registry.default
|
||||
};
|
||||
|
||||
if (config.registry.search && !Array.isArray(config.registry.search)) {
|
||||
config.registry.search = [config.registry.search];
|
||||
}
|
||||
}
|
||||
|
||||
// CA
|
||||
if (typeof config.ca === 'string') {
|
||||
config.ca = {
|
||||
default: config.ca,
|
||||
search: [config.ca],
|
||||
register: config.ca,
|
||||
publish: config.ca
|
||||
};
|
||||
} else if (typeof config.ca === 'object') {
|
||||
if (config.ca.search && !Array.isArray(config.ca.search)) {
|
||||
config.ca.search = [config.ca.search];
|
||||
}
|
||||
|
||||
if (config.ca.default) {
|
||||
config.ca.search = config.ca.search || config.ca.default;
|
||||
config.ca.register = config.ca.register || config.ca.default;
|
||||
config.ca.publish = config.ca.publish || config.ca.default;
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
module.exports = expand;
|
||||
44
packages/bower-config/lib/util/paths.js
Normal file
44
packages/bower-config/lib/util/paths.js
Normal file
@@ -0,0 +1,44 @@
|
||||
var os = require('os');
|
||||
var path = require('path');
|
||||
var osenv = require('osenv');
|
||||
var crypto = require('crypto');
|
||||
|
||||
function generateFakeUser() {
|
||||
var uid = process.pid + '-' + Date.now() + '-' + Math.floor(Math.random() * 1000000);
|
||||
return crypto.createHash('md5').update(uid).digest('hex');
|
||||
}
|
||||
|
||||
// Assume XDG defaults
|
||||
// See: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
var paths = {
|
||||
config: process.env.XDG_CONFIG_HOME,
|
||||
data: process.env.XDG_DATA_HOME,
|
||||
cache: process.env.XDG_CACHE_HOME
|
||||
};
|
||||
|
||||
// Guess some needed properties based on the user OS
|
||||
var user = (osenv.user() || generateFakeUser()).replace(/\\/g, '-');
|
||||
var tmp = path.join(os.tmpdir ? os.tmpdir() : os.tmpDir(), user);
|
||||
var home = osenv.home();
|
||||
var base;
|
||||
|
||||
// Fallbacks for windows
|
||||
if (process.platform === 'win32') {
|
||||
base = path.resolve(process.env.LOCALAPPDATA || home || tmp);
|
||||
base = path.join(base, 'bower');
|
||||
|
||||
paths.config = paths.config || path.join(base, 'config');
|
||||
paths.data = paths.data || path.join(base, 'data');
|
||||
paths.cache = paths.cache || path.join(base, 'cache');
|
||||
// Fallbacks for other operating systems
|
||||
} else {
|
||||
base = path.resolve(home || tmp);
|
||||
|
||||
paths.config = paths.config || path.join(base, '.config/bower');
|
||||
paths.data = paths.data || path.join(base, '.local/share/bower');
|
||||
paths.cache = paths.cache || path.join(base, '.cache/bower');
|
||||
}
|
||||
|
||||
paths.tmp = path.resolve(path.join(tmp, 'bower'));
|
||||
|
||||
module.exports = paths;
|
||||
79
packages/bower-config/lib/util/proxy.js
Normal file
79
packages/bower-config/lib/util/proxy.js
Normal file
@@ -0,0 +1,79 @@
|
||||
// EnvProxy uses the proxy vaiables passed to it in set and sets the
|
||||
// process.env uppercase proxy variables to them with the ability
|
||||
// to restore the original values later
|
||||
var EnvProxy = function() {
|
||||
this.restoreFrom = {};
|
||||
};
|
||||
|
||||
EnvProxy.prototype.set = function (config) {
|
||||
this.config = config;
|
||||
|
||||
// Override environment defaults if proxy config options are set
|
||||
// This will make requests.js follow the proxies in config
|
||||
if (Object.prototype.hasOwnProperty.call(config, 'noProxy')) {
|
||||
this.restoreFrom.NO_PROXY = process.env.NO_PROXY;
|
||||
this.restoreFrom.no_proxy = process.env.no_proxy;
|
||||
delete process.env.no_proxy;
|
||||
process.env.NO_PROXY = config.noProxy;
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(config, 'proxy')) {
|
||||
this.restoreFrom.HTTP_PROXY = process.env.HTTP_PROXY;
|
||||
this.restoreFrom.http_proxy = process.env.http_proxy;
|
||||
delete process.env.http_proxy;
|
||||
process.env.HTTP_PROXY = config.proxy;
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(config, 'httpsProxy')) {
|
||||
this.restoreFrom.HTTPS_PROXY = process.env.HTTPS_PROXY;
|
||||
this.restoreFrom.https_proxy = process.env.https_proxy;
|
||||
delete process.env.https_proxy;
|
||||
process.env.HTTPS_PROXY = config.httpsProxy;
|
||||
}
|
||||
};
|
||||
|
||||
EnvProxy.prototype.restore = function () {
|
||||
if (Object.prototype.hasOwnProperty.call(this.config, 'noProxy')) {
|
||||
if (this.restoreFrom.NO_PROXY !== undefined) {
|
||||
process.env.NO_PROXY = this.restoreFrom.NO_PROXY;
|
||||
} else {
|
||||
delete process.env.NO_PROXY;
|
||||
}
|
||||
|
||||
if (this.restoreFrom.no_proxy !== undefined) {
|
||||
process.env.no_proxy = this.restoreFrom.no_proxy;
|
||||
} else {
|
||||
delete process.env.no_proxy;
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.config, 'proxy')) {
|
||||
if (this.restoreFrom.HTTP_PROXY !== undefined) {
|
||||
process.env.HTTP_PROXY = this.restoreFrom.HTTP_PROXY;
|
||||
} else {
|
||||
delete process.env.HTTP_PROXY;
|
||||
}
|
||||
|
||||
if (this.restoreFrom.http_proxy !== undefined) {
|
||||
process.env.http_proxy = this.restoreFrom.http_proxy;
|
||||
} else {
|
||||
delete process.env.http_proxy;
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.config, 'httpsProxy')) {
|
||||
if (this.restoreFrom.HTTPS_PROXY !== undefined) {
|
||||
process.env.HTTPS_PROXY = this.restoreFrom.HTTPS_PROXY;
|
||||
} else {
|
||||
delete process.env.HTTPS_PROXY;
|
||||
}
|
||||
|
||||
if (this.restoreFrom.https_proxy !== undefined) {
|
||||
process.env.https_proxy = this.restoreFrom.https_proxy;
|
||||
} else {
|
||||
delete process.env.https_proxy;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = EnvProxy;
|
||||
158
packages/bower-config/lib/util/rc.js
Normal file
158
packages/bower-config/lib/util/rc.js
Normal file
@@ -0,0 +1,158 @@
|
||||
var path = require('path');
|
||||
var fs = require('graceful-fs');
|
||||
var optimist = require('optimist');
|
||||
var osenv = require('osenv');
|
||||
var object = require('mout/object');
|
||||
var string = require('mout/string');
|
||||
var paths = require('./paths');
|
||||
var defaults = require('./defaults');
|
||||
|
||||
var win = process.platform === 'win32';
|
||||
var home = osenv.home();
|
||||
|
||||
function rc(name, cwd, argv) {
|
||||
var argvConfig;
|
||||
|
||||
argv = argv || optimist.argv;
|
||||
|
||||
// Parse --config.foo=false
|
||||
argvConfig = object.map(argv.config || {}, function (value) {
|
||||
return value === 'false' ? false : value;
|
||||
});
|
||||
|
||||
// If we have specified a cwd then use this as the base for getting config.
|
||||
cwd = argvConfig.cwd ? argvConfig.cwd : cwd;
|
||||
|
||||
if (cwd) {
|
||||
return object.deepMixIn.apply(null, [
|
||||
{},
|
||||
defaults,
|
||||
{ cwd: cwd },
|
||||
win ? {} : json(path.join('/etc', name + 'rc')),
|
||||
!home ? {} : json(path.join(home, '.' + name + 'rc')),
|
||||
json(path.join(paths.config, name + 'rc')),
|
||||
json(find('.' + name + 'rc', cwd)),
|
||||
env('npm_package_config_' + name + '_'),
|
||||
env(name + '_'),
|
||||
argvConfig
|
||||
]);
|
||||
} else {
|
||||
return object.deepMixIn.apply(null, [
|
||||
{},
|
||||
defaults,
|
||||
win ? {} : json(path.join('/etc', name + 'rc')),
|
||||
!home ? {} : json(path.join(home, '.' + name + 'rc')),
|
||||
json(path.join(paths.config, name + 'rc')),
|
||||
env('npm_package_config_' + name + '_'),
|
||||
env(name + '_'),
|
||||
argvConfig
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
function parse(content, file) {
|
||||
var error;
|
||||
|
||||
if (!content.trim().length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(content);
|
||||
} catch (e) {
|
||||
if (file) {
|
||||
error = new Error('Unable to parse ' + file + ': ' + e.message);
|
||||
} else {
|
||||
error = new Error('Unable to parse rc config: ' + e.message);
|
||||
}
|
||||
|
||||
error.details = content;
|
||||
error.code = 'EMALFORMED';
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function json(file) {
|
||||
var content = {};
|
||||
if (!Array.isArray(file)) {
|
||||
try {
|
||||
content = fs.readFileSync(file).toString();
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return parse(content, file);
|
||||
} else {
|
||||
// This is multiple json files
|
||||
file.forEach(function(filename) {
|
||||
if (fs.statSync(filename).isDirectory()) {
|
||||
var error;
|
||||
error = new Error(filename + ' should not be a directory');
|
||||
error.code = 'EFILEISDIR';
|
||||
throw error;
|
||||
}
|
||||
var json = fs.readFileSync(filename).toString();
|
||||
json = parse(json, filename);
|
||||
content = object.merge(content, json);
|
||||
});
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
function env(prefix) {
|
||||
var obj = {};
|
||||
var prefixLength = prefix.length;
|
||||
|
||||
prefix = prefix.toLowerCase();
|
||||
|
||||
object.forOwn(process.env, function (value, key) {
|
||||
key = key.toLowerCase();
|
||||
|
||||
if (string.startsWith(key, prefix)) {
|
||||
var parsedKey = key
|
||||
.substr(prefixLength)
|
||||
.replace(/__/g, '.') // __ is used for nesting
|
||||
.replace(/_/g, '-'); // _ is used as a - separator
|
||||
|
||||
//use a convention patern to accept array from process.env
|
||||
//e.g. export bower_registry__search='["http://abc.com","http://def.com"]'
|
||||
var match = /\[([^\]]*)\]/g.exec(value);
|
||||
var targetValue;
|
||||
if (!match || match.length === 0) {
|
||||
targetValue = value;
|
||||
} else {
|
||||
targetValue = match[1].split(',')
|
||||
.map(function(m) {
|
||||
return m.trim();
|
||||
});
|
||||
}
|
||||
object.set(obj, parsedKey, targetValue);
|
||||
}
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function find(filename, dir) {
|
||||
var files = [];
|
||||
|
||||
var walk = function (filename, dir) {
|
||||
var file = path.join(dir, filename);
|
||||
var parent = path.dirname(dir);
|
||||
|
||||
if (fs.existsSync(file)) {
|
||||
files.push(file);
|
||||
}
|
||||
|
||||
if (parent !== dir) {
|
||||
walk(filename, parent);
|
||||
}
|
||||
};
|
||||
|
||||
walk(filename, dir);
|
||||
files.reverse();
|
||||
return files;
|
||||
}
|
||||
|
||||
module.exports = rc;
|
||||
45
packages/bower-config/package.json
Normal file
45
packages/bower-config/package.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "bower-config",
|
||||
"version": "1.4.0",
|
||||
"description": "The Bower config reader and writer.",
|
||||
"author": "Twitter",
|
||||
"license": "MIT",
|
||||
"repository": "bower/config",
|
||||
"main": "lib/Config",
|
||||
"homepage": "http://bower.io",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.1.3",
|
||||
"mout": "^1.0.0",
|
||||
"optimist": "^0.6.1",
|
||||
"osenv": "^0.1.3",
|
||||
"untildify": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coveralls": "^2.11.4",
|
||||
"expect.js": "^0.3.1",
|
||||
"glob": "^4.5.3",
|
||||
"grunt": "^0.4.5",
|
||||
"grunt-cli": "^0.1.13",
|
||||
"grunt-contrib-jshint": "^0.10.0",
|
||||
"grunt-contrib-watch": "^0.6.1",
|
||||
"grunt-coveralls": "^1.0.0",
|
||||
"grunt-exec": "^0.4.6",
|
||||
"grunt-simple-mocha": "^0.4.0",
|
||||
"istanbul": "^0.4.1",
|
||||
"load-grunt-tasks": "^2.0.0",
|
||||
"mkdirp": "^0.5.0",
|
||||
"mocha": "~1.12.0",
|
||||
"node-uuid": "^1.4.3",
|
||||
"q": "^1.2.0",
|
||||
"rimraf": "^2.3.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt test"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"ca": "Equifax Secure CA\n=================\n-----BEGIN CERTIFICATE-----\nMIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE\nChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5\nMB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT\nB0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB\nnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR\nfM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW\n8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG\nA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE\nCxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG\nA1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS\nspXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB\nAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961\nzgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB\nBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95\n70+sB3c4\n-----END CERTIFICATE-----\n\nGlobalSign Root CA\n==================\n-----BEGIN CERTIFICATE-----\nMIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx\nGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds\nb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV\nBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD\nVQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa\nDuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc\nTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb\nKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP\nc1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX\ngzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\nHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF\nAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj\nY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG\nj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH\nhm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC\nX4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n-----END CERTIFICATE-----"
|
||||
}
|
||||
3
packages/bower-config/test/assets/custom-ca/.bowerrc
Normal file
3
packages/bower-config/test/assets/custom-ca/.bowerrc
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"ca": "test/assets/custom-ca/ca-bundle.crt"
|
||||
}
|
||||
40
packages/bower-config/test/assets/custom-ca/ca-bundle.crt
Normal file
40
packages/bower-config/test/assets/custom-ca/ca-bundle.crt
Normal file
@@ -0,0 +1,40 @@
|
||||
Equifax Secure CA
|
||||
=================
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE
|
||||
ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
|
||||
MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT
|
||||
B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB
|
||||
nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR
|
||||
fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW
|
||||
8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG
|
||||
A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE
|
||||
CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG
|
||||
A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS
|
||||
spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB
|
||||
Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961
|
||||
zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB
|
||||
BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95
|
||||
70+sB3c4
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
GlobalSign Root CA
|
||||
==================
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx
|
||||
GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds
|
||||
b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV
|
||||
BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD
|
||||
VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa
|
||||
DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc
|
||||
THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb
|
||||
Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP
|
||||
c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX
|
||||
gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
|
||||
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF
|
||||
AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj
|
||||
Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG
|
||||
j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH
|
||||
hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC
|
||||
X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"scripts" : {
|
||||
"postinstall" : "${_myshellvar}"
|
||||
},
|
||||
"storage" : {
|
||||
"packages" : "${_BOWERRC_MY_PACKAGES}",
|
||||
"registry" : "~/.bower-test/registry"
|
||||
},
|
||||
"tmp" : "${_BOWERRC_MY_TMP}"
|
||||
}
|
||||
5
packages/bower-config/test/assets/env-variables/.bowerrc
Normal file
5
packages/bower-config/test/assets/env-variables/.bowerrc
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"proxy": "http://HTTP_PROXY",
|
||||
"https-proxy": "http://HTTPS_PROXY",
|
||||
"no-proxy": "google.com"
|
||||
}
|
||||
126
packages/bower-config/test/helpers.js
Normal file
126
packages/bower-config/test/helpers.js
Normal file
@@ -0,0 +1,126 @@
|
||||
var Q = require('q');
|
||||
var mkdirp = require('mkdirp');
|
||||
var rimraf = require('rimraf');
|
||||
var uuid = require('node-uuid');
|
||||
var object = require('mout/object');
|
||||
var fs = require('fs');
|
||||
var glob = require('glob');
|
||||
var os = require('os');
|
||||
var path = require('path');
|
||||
|
||||
// For better promise errors
|
||||
Q.longStackSupport = true;
|
||||
|
||||
var tmpLocation = path.join(
|
||||
os.tmpdir ? os.tmpdir() : os.tmpDir(),
|
||||
'bower-config-tests',
|
||||
uuid.v4().slice(0, 8)
|
||||
);
|
||||
|
||||
after(function () {
|
||||
rimraf.sync(tmpLocation);
|
||||
});
|
||||
|
||||
exports.TempDir = (function() {
|
||||
function TempDir (defaults) {
|
||||
this.path = path.join(tmpLocation, uuid.v4());
|
||||
this.defaults = defaults;
|
||||
}
|
||||
|
||||
TempDir.prototype.create = function (files, defaults) {
|
||||
var that = this;
|
||||
|
||||
defaults = defaults || this.defaults || {};
|
||||
files = object.merge(files || {}, defaults);
|
||||
|
||||
this.meta = function(tag) {
|
||||
if (tag) {
|
||||
return files[tag]['bower.json'];
|
||||
} else {
|
||||
return files['bower.json'];
|
||||
}
|
||||
};
|
||||
|
||||
if (files) {
|
||||
object.forOwn(files, function (contents, filepath) {
|
||||
if (typeof contents === 'object') {
|
||||
contents = JSON.stringify(contents, null, ' ') + '\n';
|
||||
}
|
||||
|
||||
var fullPath = path.join(that.path, filepath);
|
||||
mkdirp.sync(path.dirname(fullPath));
|
||||
fs.writeFileSync(fullPath, contents);
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
TempDir.prototype.prepare = function (files) {
|
||||
rimraf.sync(this.path);
|
||||
mkdirp.sync(this.path);
|
||||
this.create(files);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// TODO: Rewrite to synchronous form
|
||||
TempDir.prototype.prepareGit = function (revisions) {
|
||||
var that = this;
|
||||
|
||||
revisions = object.merge(revisions || {}, this.defaults);
|
||||
|
||||
rimraf.sync(that.path);
|
||||
|
||||
mkdirp.sync(that.path);
|
||||
|
||||
var promise = new Q();
|
||||
|
||||
object.forOwn(revisions, function (files, tag) {
|
||||
promise = promise.then(function () {
|
||||
return that.git('init');
|
||||
}).then(function () {
|
||||
that.glob('./!(.git)').map(function (removePath) {
|
||||
var fullPath = path.join(that.path, removePath);
|
||||
|
||||
rimraf.sync(fullPath);
|
||||
});
|
||||
|
||||
that.create(files, {});
|
||||
}).then(function () {
|
||||
return that.git('add', '-A');
|
||||
}).then(function () {
|
||||
return that.git('commit', '-m"commit"');
|
||||
}).then(function () {
|
||||
return that.git('tag', tag);
|
||||
});
|
||||
});
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
TempDir.prototype.glob = function (pattern) {
|
||||
return glob.sync(pattern, {
|
||||
cwd: this.path,
|
||||
dot: true
|
||||
});
|
||||
};
|
||||
|
||||
TempDir.prototype.getPath = function (name) {
|
||||
return path.join(this.path, name);
|
||||
};
|
||||
|
||||
TempDir.prototype.read = function (name) {
|
||||
return fs.readFileSync(this.getPath(name), 'utf8');
|
||||
};
|
||||
|
||||
TempDir.prototype.readJson = function (name) {
|
||||
return JSON.parse(this.read(name));
|
||||
};
|
||||
|
||||
TempDir.prototype.exists = function (name) {
|
||||
return fs.existsSync(path.join(this.path, name));
|
||||
};
|
||||
|
||||
return TempDir;
|
||||
})();
|
||||
245
packages/bower-config/test/test.js
Normal file
245
packages/bower-config/test/test.js
Normal file
@@ -0,0 +1,245 @@
|
||||
var assert = require('assert');
|
||||
var path = require('path');
|
||||
|
||||
describe('NPM Config on package.json', function () {
|
||||
beforeEach(function () {
|
||||
delete process.env.npm_package_config_bower_directory;
|
||||
delete process.env.npm_package_config_bower_colors;
|
||||
delete process.env.npm_package_config_bower_resolvers;
|
||||
});
|
||||
|
||||
it('defaults registry entries to default registry', function () {
|
||||
var config = require('../lib/Config').read(null, {});
|
||||
|
||||
assert.deepEqual(config.registry, {
|
||||
'default': 'https://bower.herokuapp.com',
|
||||
'search': [
|
||||
'https://bower.herokuapp.com'
|
||||
],
|
||||
'register': 'https://bower.herokuapp.com',
|
||||
'publish': 'https://bower.herokuapp.com'
|
||||
});
|
||||
});
|
||||
|
||||
it('can change default registry', function () {
|
||||
var config = require('../lib/Config').read(null, { registry: 'https://foobar' });
|
||||
|
||||
assert.deepEqual(config.registry, {
|
||||
'default': 'https://foobar',
|
||||
'search': [
|
||||
'https://foobar',
|
||||
],
|
||||
'register': 'https://foobar',
|
||||
'publish': 'https://foobar'
|
||||
});
|
||||
});
|
||||
|
||||
it('can override single entries in registry configuration', function () {
|
||||
var config = require('../lib/Config').read(null, { registry: { search: 'https://foobar' } });
|
||||
|
||||
assert.deepEqual(config.registry, {
|
||||
'default': 'https://bower.herokuapp.com',
|
||||
'search': [
|
||||
'https://foobar',
|
||||
],
|
||||
'register': 'https://bower.herokuapp.com',
|
||||
'publish': 'https://bower.herokuapp.com'
|
||||
});
|
||||
});
|
||||
|
||||
it('can override single entries in registry configuration and defaults', function () {
|
||||
var config = require('../lib/Config').read(null, { registry: { default: 'https://fizfuz', search: 'https://foobar' } });
|
||||
|
||||
assert.deepEqual(config.registry, {
|
||||
'default': 'https://fizfuz',
|
||||
'search': [
|
||||
'https://foobar',
|
||||
],
|
||||
'register': 'https://fizfuz',
|
||||
'publish': 'https://fizfuz'
|
||||
});
|
||||
});
|
||||
|
||||
it('allows for not providing cwd', function () {
|
||||
var config = require('../lib/Config').read();
|
||||
|
||||
config.tmp = '/foo/bar';
|
||||
config.userAgent = 'firefox';
|
||||
delete config.storage;
|
||||
|
||||
assert.deepEqual(config, {
|
||||
'directory': 'bower_components',
|
||||
'registry': {
|
||||
'default': 'https://bower.herokuapp.com',
|
||||
'search': [
|
||||
'https://bower.herokuapp.com'
|
||||
],
|
||||
'register': 'https://bower.herokuapp.com',
|
||||
'publish': 'https://bower.herokuapp.com'
|
||||
},
|
||||
'shorthandResolver': 'https://github.com/{{owner}}/{{package}}.git',
|
||||
'tmp': '/foo/bar',
|
||||
'timeout': 30000,
|
||||
'ca': {
|
||||
'search': []
|
||||
},
|
||||
'strictSsl': true,
|
||||
'userAgent': 'firefox',
|
||||
'color': true
|
||||
});
|
||||
});
|
||||
|
||||
function assertCAContents(caData, name) {
|
||||
var r = /-----BEGIN CERTIFICATE-----[a-zA-Z0-9+\/=\n\r]+-----END CERTIFICATE-----/;
|
||||
|
||||
assert(caData, name + ' should be set');
|
||||
assert(Array.isArray(caData), name + ' should be an array');
|
||||
assert.equal(2, caData.length);
|
||||
caData.forEach(function(c, i) {
|
||||
assert(c.match(r),
|
||||
name + '[' + i + '] should contain a certificate. Given: ' + JSON.stringify(c));
|
||||
});
|
||||
}
|
||||
|
||||
describe('Setting process.env.npm_package_config', function () {
|
||||
process.env.npm_package_config_bower_directory = 'npm-path';
|
||||
process.env.npm_package_config_bower_colors = 'false';
|
||||
process.env.npm_package_config_bower_resolvers = '[foo,bar,baz]';
|
||||
|
||||
var config = require('../lib/Config').read();
|
||||
|
||||
it('should return "npm-path" for "bower_directory"', function () {
|
||||
assert.equal('npm-path', config.directory);
|
||||
});
|
||||
it('should return "false" for "bower_colors"', function () {
|
||||
assert.equal('false', config.colors);
|
||||
});
|
||||
it('should expand array "false" for "bower_resolvers"', function () {
|
||||
assert.deepEqual(['foo', 'bar', 'baz'], config.resolvers);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Specifying custom CA', function() {
|
||||
|
||||
it('should read the CA file', function() {
|
||||
var config = require('../lib/Config')
|
||||
.read(path.resolve('test/assets/custom-ca'));
|
||||
|
||||
['register', 'publish', 'default'].forEach(function (p) {
|
||||
assertCAContents(config.ca[p], 'config.ca.' + p);
|
||||
});
|
||||
|
||||
assert(Array.isArray(config.ca.search),
|
||||
'ca property search should be an array');
|
||||
|
||||
config.ca.search.forEach(function(c, i) {
|
||||
assertCAContents(c, 'config.ca.search[' + i + ']');
|
||||
});
|
||||
});
|
||||
|
||||
it('should backward-support certificate inside .bowerrc', function() {
|
||||
var config = require('../lib/Config')
|
||||
.read(path.resolve('test/assets/custom-ca-embed'));
|
||||
|
||||
['register', 'publish', 'default'].forEach(function (p) {
|
||||
assertCAContents(config.ca[p], 'config.ca.' + p);
|
||||
});
|
||||
|
||||
assert(Array.isArray(config.ca.search),
|
||||
'ca property search should be an array');
|
||||
config.ca.search.forEach(function(c, i) {
|
||||
assertCAContents(c, 'config.ca.search[' + i + ']');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setting ENV variables', function () {
|
||||
beforeEach(function () {
|
||||
delete process.env.no_proxy;
|
||||
delete process.env.http_proxy;
|
||||
delete process.env.https_proxy;
|
||||
delete process.env.NO_PROXY;
|
||||
delete process.env.HTTP_PROXY;
|
||||
delete process.env.HTTPS_PROXY;
|
||||
});
|
||||
|
||||
it('sets env variables', function () {
|
||||
require('../lib/Config').read('test/assets/env-variables');
|
||||
|
||||
assert.equal(process.env.HTTP_PROXY, 'http://HTTP_PROXY');
|
||||
assert.equal(process.env.HTTPS_PROXY, 'http://HTTPS_PROXY');
|
||||
assert.equal(process.env.NO_PROXY, 'google.com');
|
||||
|
||||
assert.equal(process.env.http_proxy, undefined);
|
||||
assert.equal(process.env.https_proxy, undefined);
|
||||
assert.equal(process.env.no_proxy, undefined);
|
||||
});
|
||||
|
||||
it('restores env variables', function () {
|
||||
process.env.HTTP_PROXY = 'a';
|
||||
process.env.HTTPS_PROXY = 'b';
|
||||
process.env.NO_PROXY = 'c';
|
||||
process.env.http_proxy = 'd';
|
||||
process.env.https_proxy = 'e';
|
||||
process.env.no_proxy = 'f';
|
||||
|
||||
var config = require('../lib/Config').create('test/assets/env-variables').load();
|
||||
config.restore();
|
||||
|
||||
assert.equal(process.env.HTTP_PROXY, 'a');
|
||||
assert.equal(process.env.HTTPS_PROXY, 'b');
|
||||
assert.equal(process.env.NO_PROXY, 'c');
|
||||
|
||||
assert.equal(process.env.http_proxy, 'd');
|
||||
assert.equal(process.env.https_proxy, 'e');
|
||||
assert.equal(process.env.no_proxy, 'f');
|
||||
});
|
||||
|
||||
it('restores env variables if they are undefined', function () {
|
||||
var config = require('../lib/Config').create('test/assets/env-variables').load();
|
||||
config.restore();
|
||||
|
||||
assert.equal(process.env.HTTP_PROXY, undefined);
|
||||
assert.equal(process.env.HTTPS_PROXY, undefined);
|
||||
assert.equal(process.env.NO_PROXY, undefined);
|
||||
|
||||
assert.equal(process.env.http_proxy, undefined);
|
||||
assert.equal(process.env.https_proxy, undefined);
|
||||
assert.equal(process.env.no_proxy, undefined);
|
||||
});
|
||||
|
||||
it('allows for overriding options', function () {
|
||||
require('../lib/Config').read('test/assets/env-variables', {
|
||||
httpsProxy: 'http://other-proxy.local'
|
||||
});
|
||||
|
||||
assert.equal(process.env.HTTP_PROXY, 'http://HTTP_PROXY');
|
||||
assert.equal(process.env.HTTPS_PROXY, 'http://other-proxy.local');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Allow ${ENV} variables in .bowerrc', function() {
|
||||
|
||||
it('sets values from process.env', function() {
|
||||
process.env._BOWERRC_MY_PACKAGES = 'a';
|
||||
process.env._BOWERRC_MY_TMP = '/tmp/b';
|
||||
|
||||
var config = require('../lib/Config').read('test/assets/env-variables-values');
|
||||
assert.equal('a', config.storage.packages);
|
||||
assert.equal('/tmp/b', config.tmp);
|
||||
assert.equal('${_myshellvar}', config.scripts.postinstall);
|
||||
});
|
||||
});
|
||||
|
||||
describe('untildify paths in .bowerrc', function() {
|
||||
|
||||
it('resolve ~/ in .bowerrc', function() {
|
||||
var config = require('../lib/Config').read('test/assets/env-variables-values');
|
||||
var untildify = require('untildify');
|
||||
|
||||
assert.equal(untildify('~/.bower-test/registry') , config.storage.registry);
|
||||
});
|
||||
});
|
||||
|
||||
require('./util/index');
|
||||
3
packages/bower-config/test/util/index.js
Normal file
3
packages/bower-config/test/util/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
describe('util', function () {
|
||||
require('./rc');
|
||||
});
|
||||
84
packages/bower-config/test/util/rc.js
Normal file
84
packages/bower-config/test/util/rc.js
Normal file
@@ -0,0 +1,84 @@
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('../helpers');
|
||||
|
||||
describe('rc', function() {
|
||||
var tempDir = new helpers.TempDir();
|
||||
var tempDirBowerrc = new helpers.TempDir();
|
||||
|
||||
var rc = require('../../lib/util/rc');
|
||||
|
||||
tempDir.prepare({
|
||||
'.bowerrc': {
|
||||
key: 'value'
|
||||
},
|
||||
'child/.bowerrc': {
|
||||
key2: 'value2'
|
||||
},
|
||||
'child2/.bowerrc': {
|
||||
key: 'valueShouldBeOverwriteParent'
|
||||
},
|
||||
'child3/bower.json': {
|
||||
name: 'without-bowerrc'
|
||||
},
|
||||
'other_dir/.bowerrc': {
|
||||
key: 'othervalue'
|
||||
}
|
||||
});
|
||||
|
||||
tempDirBowerrc.prepare({
|
||||
'.bowerrc/foo': {
|
||||
key: 'bar'
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
it('correctly reads .bowerrc files', function() {
|
||||
var config = rc('bower', tempDir.path);
|
||||
|
||||
expect(config.key).to.eql('value');
|
||||
expect(config.key2).to.eql(undefined);
|
||||
});
|
||||
|
||||
it('correctly reads .bowerrc files from child', function() {
|
||||
var config = rc('bower', tempDir.path + '/child/');
|
||||
|
||||
expect(config.key).to.eql('value');
|
||||
expect(config.key2).to.eql('value2');
|
||||
});
|
||||
|
||||
it('correctly reads .bowerrc files from child2', function() {
|
||||
var config = rc('bower', tempDir.path + '/child2/');
|
||||
|
||||
expect(config.key).to.eql('valueShouldBeOverwriteParent');
|
||||
expect(config.key2).to.eql(undefined);
|
||||
});
|
||||
|
||||
it('correctly reads .bowerrc files from child3', function() {
|
||||
var config = rc('bower', tempDir.path + '/child3/');
|
||||
|
||||
expect(config.key).to.eql('value');
|
||||
expect(config.key2).to.eql(undefined);
|
||||
});
|
||||
|
||||
it('loads the .bowerrc file from the cwd specified on the command line', function(){
|
||||
var argv = {
|
||||
'config': {
|
||||
'cwd': tempDir.path + '/other_dir/'
|
||||
}
|
||||
};
|
||||
|
||||
var config = rc('bower', tempDir.path, argv);
|
||||
|
||||
expect(config.key).to.eql('othervalue');
|
||||
|
||||
});
|
||||
|
||||
it('throws an easy to understand error if .bowerrc is a dir', function() {
|
||||
// Gotta wrap this to catch the error
|
||||
var config = function () {
|
||||
rc('bower', tempDirBowerrc.path);
|
||||
};
|
||||
|
||||
expect(config).to.throwError(/should not be a directory/);
|
||||
});
|
||||
});
|
||||
12
packages/bower-endpoint-parser/.editorconfig
Normal file
12
packages/bower-endpoint-parser/.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
2
packages/bower-endpoint-parser/.gitignore
vendored
Normal file
2
packages/bower-endpoint-parser/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/node_modules
|
||||
/npm-debug.*
|
||||
61
packages/bower-endpoint-parser/.jshintrc
Normal file
61
packages/bower-endpoint-parser/.jshintrc
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"predef": [
|
||||
"console",
|
||||
"describe",
|
||||
"it",
|
||||
"after",
|
||||
"afterEach",
|
||||
"before",
|
||||
"beforeEach"
|
||||
],
|
||||
|
||||
"indent": 4,
|
||||
"node": true,
|
||||
"devel": true,
|
||||
|
||||
"bitwise": false,
|
||||
"curly": false,
|
||||
"eqeqeq": true,
|
||||
"forin": false,
|
||||
"immed": true,
|
||||
"latedef": false,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": false,
|
||||
"nonew": true,
|
||||
"plusplus": false,
|
||||
"regexp": false,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"quotmark": "single",
|
||||
"strict": false,
|
||||
"trailing": true,
|
||||
"camelcase": true,
|
||||
|
||||
"asi": false,
|
||||
"boss": true,
|
||||
"debug": false,
|
||||
"eqnull": true,
|
||||
"esnext": false,
|
||||
"evil": false,
|
||||
"expr": true,
|
||||
"funcscope": false,
|
||||
"globalstrict": false,
|
||||
"iterator": false,
|
||||
"lastsemic": false,
|
||||
"laxbreak": true,
|
||||
"laxcomma": false,
|
||||
"loopfunc": true,
|
||||
"multistr": false,
|
||||
"onecase": true,
|
||||
"regexdash": false,
|
||||
"scripturl": false,
|
||||
"smarttabs": false,
|
||||
"shadow": false,
|
||||
"sub": false,
|
||||
"supernew": true,
|
||||
"validthis": false,
|
||||
|
||||
"nomen": false,
|
||||
"white": true
|
||||
}
|
||||
4
packages/bower-endpoint-parser/.travis.yml
Normal file
4
packages/bower-endpoint-parser/.travis.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
- "0.8"
|
||||
19
packages/bower-endpoint-parser/LICENSE
Normal file
19
packages/bower-endpoint-parser/LICENSE
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2012 Twitter and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
102
packages/bower-endpoint-parser/README.md
Normal file
102
packages/bower-endpoint-parser/README.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# endpoint-parser [](http://travis-ci.org/bower/endpoint-parser)
|
||||
|
||||
Little module that helps with endpoints parsing.
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### .decompose(endpoint)
|
||||
|
||||
Decomposes a endpoint into `name`, `source` and `target`.
|
||||
|
||||
```js
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
|
||||
endpointParser.decompose('jquery#~2.0.0');
|
||||
// { name: '', source: 'jquery', target: '~2.0.0' }
|
||||
|
||||
endpointParser.decompose('backbone=backbone-amd#~1.0.0');
|
||||
// { name: 'backbone', source: 'backbone-amd', target: '~1.0.0' }
|
||||
|
||||
endpointParser.decompose('http://twitter.github.io/bootstrap/assets/bootstrap.zip');
|
||||
// { name: '', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' }
|
||||
|
||||
endpointParser.decompose('bootstrap=http://twitter.github.io/bootstrap/assets/bootstrap.zip');
|
||||
// { name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' }
|
||||
```
|
||||
|
||||
### .compose(decEndpoint)
|
||||
|
||||
Inverse of `decompose()`.
|
||||
Takes a decomposed endpoint and composes it back into a string.
|
||||
|
||||
```js
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
|
||||
endpointParser.compose({ name: '', source: 'jquery', target: '~2.0.0' });
|
||||
// jquery#~2.0.0
|
||||
|
||||
endpointParser.compose({ name: 'backbone', source: 'backbone-amd', target: '~1.0.0' });
|
||||
// backbone=backbone-amd#~1.0.0
|
||||
|
||||
endpointParser.compose({ name: '', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' });
|
||||
// http://twitter.github.io/bootstrap/assets/bootstrap.zip
|
||||
|
||||
endpointParser.compose({ name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' });
|
||||
// bootstrap=http://twitter.github.io/bootstrap/assets/bootstrap.zip
|
||||
```
|
||||
|
||||
### .json2decomposed(key, value)
|
||||
|
||||
Similar to `decompose()` but specially designed to be used when parsing `bower.json` dependencies.
|
||||
For instance, in a `bower.json` like this:
|
||||
|
||||
```js
|
||||
{
|
||||
"name": "foo",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"jquery": "~1.9.1",
|
||||
"backbone": "backbone-amd#~1.0.0",
|
||||
"bootstrap": "http://twitter.github.io/bootstrap/assets/bootstrap"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You would call `json2decomposed` like so:
|
||||
|
||||
```js
|
||||
endpointParser.json2decomposed('jquery', '~1.9.1');
|
||||
// { name: 'jquery', source: 'jquery', target: '~1.9.1' }
|
||||
|
||||
endpointParser.json2decomposed('backbone', 'backbone-amd#~1.0.0');
|
||||
// { name: 'backbone', source: 'backbone-amd', target: '~1.0.0' }
|
||||
|
||||
endpointParser.json2decomposed('bootstrap', 'http://twitter.github.io/bootstrap/assets/bootstrap');
|
||||
// { name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' }
|
||||
```
|
||||
|
||||
### .decomposed2json(decEndpoint)
|
||||
|
||||
Inverse of `json2decomposed()`.
|
||||
Takes a decomposed endpoint and composes it to be saved to `bower.json`.
|
||||
|
||||
```js
|
||||
var endpointParser = require('bower-endpoint-parser');
|
||||
|
||||
endpointParser.decomposed2json({ name: 'jquery', source: 'jquery', target: '~2.0.0' });
|
||||
// { jquery: '~2.0.0' }
|
||||
|
||||
endpointParser.decomposed2json({ name: 'backbone', source: 'backbone-amd', target: '~1.0.0' });
|
||||
// { backbone: 'backbone-amd#~2.0.0' }
|
||||
|
||||
endpointParser.decomposed2json({ name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' });
|
||||
// { bootstrap: 'http://twitter.github.io/bootstrap/assets/bootstrap' }
|
||||
```
|
||||
|
||||
This function throws an exception if the `name` from the decomposed endpoint is empty.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Released under the [MIT License](http://www.opensource.org/licenses/mit-license.php).
|
||||
128
packages/bower-endpoint-parser/index.js
Normal file
128
packages/bower-endpoint-parser/index.js
Normal file
@@ -0,0 +1,128 @@
|
||||
function decompose(endpoint) {
|
||||
// Note that we allow spaces in targets and sources but they are trimmed
|
||||
var regExp = /^(?:([\w\-]|(?:[\w\.\-]+[\w\-])?)=)?([^\|#]+)(?:#(.*))?$/;
|
||||
var matches = endpoint.match(regExp);
|
||||
var target;
|
||||
var error;
|
||||
|
||||
if (!matches) {
|
||||
error = new Error('Invalid endpoint: ' + endpoint);
|
||||
error.code = 'EINVEND';
|
||||
throw error;
|
||||
}
|
||||
|
||||
target = trim(matches[3]);
|
||||
|
||||
return {
|
||||
name: trim(matches[1]),
|
||||
source: trim(matches[2]),
|
||||
target: isWildcard(target) ? '*' : target
|
||||
};
|
||||
}
|
||||
|
||||
function compose(decEndpoint) {
|
||||
var name = trim(decEndpoint.name);
|
||||
var source = trim(decEndpoint.source);
|
||||
var target = trim(decEndpoint.target);
|
||||
var composed = '';
|
||||
|
||||
if (name) {
|
||||
composed += name + '=';
|
||||
}
|
||||
|
||||
composed += source;
|
||||
|
||||
if (!isWildcard(target)) {
|
||||
composed += '#' + target;
|
||||
}
|
||||
|
||||
return composed;
|
||||
}
|
||||
|
||||
function json2decomposed(key, value) {
|
||||
var endpoint;
|
||||
var split;
|
||||
var error;
|
||||
|
||||
key = trim(key);
|
||||
value = trim(value);
|
||||
|
||||
if (!key) {
|
||||
error = new Error('The key must be specified');
|
||||
error.code = 'EINVEND';
|
||||
throw error;
|
||||
}
|
||||
|
||||
endpoint = key + '=';
|
||||
split = value.split('#').map(trim);
|
||||
|
||||
// If # was found, the source was specified
|
||||
if (split.length > 1) {
|
||||
endpoint += (split[0] || key) + '#' + split[1];
|
||||
// Check if value looks like a source
|
||||
} else if (isSource(value)) {
|
||||
endpoint += value + '#*';
|
||||
// Otherwise use the key as the source
|
||||
} else {
|
||||
endpoint += key + '#' + split[0];
|
||||
}
|
||||
|
||||
return decompose(endpoint);
|
||||
}
|
||||
|
||||
function decomposed2json(decEndpoint) {
|
||||
var error;
|
||||
var name = trim(decEndpoint.name);
|
||||
var source = trim(decEndpoint.source);
|
||||
var target = trim(decEndpoint.target);
|
||||
var value = '';
|
||||
var ret = {};
|
||||
|
||||
if (!name) {
|
||||
error = new Error('Decomposed endpoint must have a name');
|
||||
error.code = 'EINVEND';
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Add source only if different than the name
|
||||
if (source !== name) {
|
||||
value += source;
|
||||
}
|
||||
|
||||
// If value is empty, we append the target always
|
||||
if (!value) {
|
||||
if (isWildcard(target)) {
|
||||
value += '*';
|
||||
} else {
|
||||
if (target.indexOf('/') !== -1) {
|
||||
value += '#' + target;
|
||||
} else {
|
||||
value += target;
|
||||
}
|
||||
}
|
||||
// Otherwise append only if not a wildcard or source does not look like a source
|
||||
} else if (!isWildcard(target) || !isSource(source)) {
|
||||
value += '#' + (target || '*');
|
||||
}
|
||||
|
||||
ret[name] = value;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function trim(str) {
|
||||
return str ? str.trim() : '';
|
||||
}
|
||||
|
||||
function isWildcard(target) {
|
||||
return !target || target === '*' || target === 'latest';
|
||||
}
|
||||
|
||||
function isSource(value) {
|
||||
return (/[\/\\@]/).test(value);
|
||||
}
|
||||
|
||||
module.exports.decompose = decompose;
|
||||
module.exports.compose = compose;
|
||||
module.exports.json2decomposed = json2decomposed;
|
||||
module.exports.decomposed2json = decomposed2json;
|
||||
28
packages/bower-endpoint-parser/package.json
Normal file
28
packages/bower-endpoint-parser/package.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "bower-endpoint-parser",
|
||||
"version": "0.2.2",
|
||||
"description": "Little module that helps with endpoints parsing.",
|
||||
"author": "Twitter",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/bower/endpoint-parser/blob/master/LICENSE"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/bower/endpoint-parser.git"
|
||||
},
|
||||
"main": "index.js",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"expect.js": "~0.2.0",
|
||||
"mocha": "~1.12.0",
|
||||
"mout": "~0.9.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha -R spec"
|
||||
}
|
||||
}
|
||||
263
packages/bower-endpoint-parser/test/test.js
Normal file
263
packages/bower-endpoint-parser/test/test.js
Normal file
@@ -0,0 +1,263 @@
|
||||
var expect = require('expect.js');
|
||||
var lang = require('mout/lang');
|
||||
var object = require('mout/object');
|
||||
var endpointParser = require('../');
|
||||
|
||||
describe('endpoint-parser', function () {
|
||||
describe('.decompose', function () {
|
||||
it('should decompose endpoints correctly', function () {
|
||||
var suite = {
|
||||
'jquery#~2.0.0': { name: '', source: 'jquery', target: '~2.0.0' },
|
||||
'jquery#*': { name: '', source: 'jquery', target: '*' },
|
||||
'jquery#latest': { name: '', source: 'jquery', target: '*' },
|
||||
'jquery#3dc50c62fe2d2d01afc58e7ad42236a35acff4d8': { name: '', source: 'jquery', target: '3dc50c62fe2d2d01afc58e7ad42236a35acff4d8' },
|
||||
'jquery#master': { name: '', source: 'jquery', target: 'master' },
|
||||
'backbone=backbone-amd#~1.0.0': { name: 'backbone', source: 'backbone-amd', target: '~1.0.0' },
|
||||
'backbone=backbone-amd#latest': { name: 'backbone', source: 'backbone-amd', target: '*' },
|
||||
'backbone=backbone-amd#*': { name: 'backbone', source: 'backbone-amd', target: '*' },
|
||||
'http://twitter.github.io/bootstrap/assets/bootstrap.zip': { name: '', source: 'http://twitter.github.io/bootstrap/assets/bootstrap.zip', target: '*' },
|
||||
'bootstrap=http://twitter.github.io/bootstrap/assets/bootstrap.zip': { name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap.zip', target: '*' },
|
||||
'bootstrap=http://twitter.github.io/bootstrap/assets/bootstrap.zip#latest': { name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap.zip', target: '*' }
|
||||
};
|
||||
|
||||
object.forOwn(suite, function (decEndpoint, endpoint) {
|
||||
expect(endpointParser.decompose(endpoint)).to.eql(decEndpoint);
|
||||
});
|
||||
});
|
||||
|
||||
it('should trim sources and targets', function () {
|
||||
var decEndpoint = endpointParser.decompose('foo= source # ~1.0.2 ');
|
||||
expect(decEndpoint.source).to.equal('source');
|
||||
expect(decEndpoint.target).to.equal('~1.0.2');
|
||||
|
||||
decEndpoint = endpointParser.decompose('foo= source # latest');
|
||||
expect(decEndpoint.source).to.equal('source');
|
||||
expect(decEndpoint.target).to.equal('*');
|
||||
|
||||
decEndpoint = endpointParser.decompose('foo= source # *');
|
||||
expect(decEndpoint.source).to.equal('source');
|
||||
expect(decEndpoint.target).to.equal('*');
|
||||
});
|
||||
});
|
||||
|
||||
describe('.compose', function () {
|
||||
it('should compose endpoints correctly', function () {
|
||||
var suite = {
|
||||
'jquery#~2.0.0': { name: '', source: 'jquery', target: '~2.0.0' },
|
||||
'jquery': [{ name: '', source: 'jquery', target: '*' }, { name: '', source: 'jquery', target: 'latest' }, { name: '', source: 'jquery', target: '' }],
|
||||
'jquery#3dc50c62fe2d2d01afc58e7ad42236a35acff4d8': { name: '', source: 'jquery', target: '3dc50c62fe2d2d01afc58e7ad42236a35acff4d8' },
|
||||
'jquery#master': { name: '', source: 'jquery', target: 'master' },
|
||||
'backbone=backbone-amd#~1.0.0': { name: 'backbone', source: 'backbone-amd', target: '~1.0.0' },
|
||||
'backbone=backbone-amd': [{ name: 'backbone', source: 'backbone-amd', target: '*' }, { name: 'backbone', source: 'backbone-amd', target: '*' }, { name: 'backbone', source: 'backbone-amd', target: '' }],
|
||||
'http://twitter.github.io/bootstrap/assets/bootstrap.zip': { name: '', source: 'http://twitter.github.io/bootstrap/assets/bootstrap.zip', target: '*' },
|
||||
'bootstrap=http://twitter.github.io/bootstrap/assets/bootstrap.zip': { name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap.zip', target: '*' }
|
||||
};
|
||||
|
||||
object.forOwn(suite, function (decEndpoints, endpoint) {
|
||||
decEndpoints = lang.toArray(decEndpoints);
|
||||
decEndpoints.forEach(function (decEndpoint) {
|
||||
expect(endpointParser.compose(decEndpoint)).to.equal(endpoint);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should trim values', function () {
|
||||
expect(endpointParser.compose({
|
||||
name: ' foo ',
|
||||
source: ' bar ',
|
||||
target: ' ~1.0.2 '
|
||||
})).to.equal('foo=bar#~1.0.2');
|
||||
|
||||
expect(endpointParser.compose({
|
||||
name: ' foo ',
|
||||
source: ' foo ',
|
||||
target: ' ~1.0.2 '
|
||||
})).to.equal('foo=foo#~1.0.2');
|
||||
|
||||
expect(endpointParser.compose({
|
||||
name: ' foo ',
|
||||
source: ' foo ',
|
||||
target: ' * '
|
||||
})).to.equal('foo=foo');
|
||||
|
||||
expect(endpointParser.compose({
|
||||
name: ' foo ',
|
||||
source: ' foo ',
|
||||
target: ' * '
|
||||
})).to.equal('foo=foo');
|
||||
|
||||
expect(endpointParser.compose({
|
||||
name: ' ',
|
||||
source: ' foo ',
|
||||
target: ''
|
||||
})).to.equal('foo');
|
||||
});
|
||||
});
|
||||
|
||||
describe('.json2decomposed', function () {
|
||||
var expected = [
|
||||
{ name: 'jquery', source: 'jquery', target: '~1.9.1' },
|
||||
{ name: 'foo', source: 'foo', target: '*' },
|
||||
{ name: 'bar', source: 'bar', target: '*' },
|
||||
{ name: 'baz', source: 'baz', target: '~0.2.0' },
|
||||
{ name: 'backbone', source: 'backbone-amd', target: '~1.0.0' },
|
||||
{ name: 'backbone2', source: 'backbone=backbone-amd', target: '~1.0.0' },
|
||||
{ name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' },
|
||||
{ name: 'bootstrap2', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' },
|
||||
{ name: 'ssh', source: 'git@example.com', target: '*' },
|
||||
{ name: 'git', source: 'git://example.com', target: '*' },
|
||||
{ name: 'path', source: '/foo', target: '*' },
|
||||
{ name: 'winpath', source: 'c:\\foo', target: '*' }
|
||||
];
|
||||
|
||||
it('should decompose json endpoints correctly', function () {
|
||||
var dependencies = {
|
||||
jquery: '~1.9.1',
|
||||
foo: 'latest',
|
||||
bar: '*',
|
||||
baz: '#~0.2.0',
|
||||
backbone: 'backbone-amd#~1.0.0',
|
||||
backbone2: 'backbone=backbone-amd#~1.0.0',
|
||||
bootstrap: 'http://twitter.github.io/bootstrap/assets/bootstrap',
|
||||
bootstrap2: 'http://twitter.github.io/bootstrap/assets/bootstrap#*',
|
||||
ssh: 'git@example.com',
|
||||
git: 'git://example.com',
|
||||
path: '/foo',
|
||||
winpath: 'c:\\foo'
|
||||
};
|
||||
var x = 0;
|
||||
|
||||
object.forOwn(dependencies, function (value, key) {
|
||||
expect(endpointParser.json2decomposed(key, value)).to.eql(expected[x]);
|
||||
x += 1;
|
||||
});
|
||||
});
|
||||
|
||||
it('should trim values', function () {
|
||||
var dependencies = {
|
||||
' jquery ': ' ~1.9.1 ',
|
||||
' foo ': ' latest ',
|
||||
' bar ': ' * ',
|
||||
' baz ': '# ~0.2.0 ',
|
||||
' backbone ': ' backbone-amd#~1.0.0 ',
|
||||
' backbone2 ': ' backbone=backbone-amd # ~1.0.0 ',
|
||||
' bootstrap ': ' http://twitter.github.io/bootstrap/assets/bootstrap',
|
||||
' bootstrap2 ': ' http://twitter.github.io/bootstrap/assets/bootstrap # *',
|
||||
' ssh ': ' git@example.com ',
|
||||
' git ': ' git://example.com ',
|
||||
' path ': ' /foo ',
|
||||
' winpath ': ' c:\\foo '
|
||||
};
|
||||
var x = 0;
|
||||
|
||||
object.forOwn(dependencies, function (value, key) {
|
||||
expect(endpointParser.json2decomposed(key, value)).to.eql(expected[x]);
|
||||
x += 1;
|
||||
});
|
||||
});
|
||||
|
||||
it('should error out if key is not specified', function () {
|
||||
try {
|
||||
endpointParser.json2decomposed(null);
|
||||
throw new Error('Should have failed');
|
||||
} catch (e) {
|
||||
expect(e.code).to.equal('EINVEND');
|
||||
expect(e.message).to.contain('key must be specified');
|
||||
}
|
||||
|
||||
try {
|
||||
endpointParser.json2decomposed('');
|
||||
throw new Error('Should have failed');
|
||||
} catch (e) {
|
||||
expect(e.code).to.equal('EINVEND');
|
||||
expect(e.message).to.contain('key must be specified');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('.decomposed2json', function () {
|
||||
var expected = [
|
||||
{ jquery: '~1.9.1' },
|
||||
{ foo: '*' },
|
||||
{ bar: '*' },
|
||||
{ baz: '*' },
|
||||
{ jqueryx: 'jquery#~1.9.1' },
|
||||
{ jqueryy: 'jquery-x#*' },
|
||||
{ jqueryy: 'jquery-x#*' },
|
||||
{ backbone: 'backbone-amd#~1.0.0' },
|
||||
{ backbone : 'backbone=backbone-amd#~1.0.0' },
|
||||
{ bootstrap: 'http://twitter.github.io/bootstrap/assets/bootstrap' },
|
||||
{ bootstrap: 'http://twitter.github.io/bootstrap/assets/bootstrap' },
|
||||
{ ssh: 'git@example.com' },
|
||||
{ git: 'git://example.com' },
|
||||
{ ckeditor: '#full/4.3.3' }
|
||||
];
|
||||
|
||||
it('should compose endpoints to json correctly', function () {
|
||||
var decEndpoints = [
|
||||
{ name: 'jquery', source: 'jquery', target: '~1.9.1' },
|
||||
{ name: 'foo', source: 'foo', target: 'latest' },
|
||||
{ name: 'bar', source: 'bar', target: '*' },
|
||||
{ name: 'baz', source: 'baz', target: '' },
|
||||
{ name: 'jqueryx', source: 'jquery', target: '~1.9.1' },
|
||||
{ name: 'jqueryy', source: 'jquery-x', target: '' },
|
||||
{ name: 'jqueryy', source: 'jquery-x', target: '*' },
|
||||
{ name: 'backbone', source: 'backbone-amd', target: '~1.0.0' },
|
||||
{ name: 'backbone', source: 'backbone=backbone-amd', target: '~1.0.0' },
|
||||
{ name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '' },
|
||||
{ name: 'bootstrap', source: 'http://twitter.github.io/bootstrap/assets/bootstrap', target: '*' },
|
||||
{ name: 'ssh', source: 'git@example.com', target: '*' },
|
||||
{ name: 'git', source: 'git://example.com', target: '*' },
|
||||
{ name: 'ckeditor', source: 'ckeditor', target: 'full/4.3.3' }
|
||||
];
|
||||
var x = 0;
|
||||
|
||||
decEndpoints.forEach(function (decEndpoint) {
|
||||
expect(endpointParser.decomposed2json(decEndpoint)).to.eql(expected[x]);
|
||||
x += 1;
|
||||
});
|
||||
});
|
||||
|
||||
it('should trim values', function () {
|
||||
var decEndpoints = [
|
||||
{ name: ' jquery ', source: ' jquery ', target: ' ~1.9.1 ' },
|
||||
{ name: 'foo', source: ' foo', target: ' latest ' },
|
||||
{ name: 'bar', source: 'bar ', target: ' * ' },
|
||||
{ name: 'baz ', source: 'baz', target: ' ' },
|
||||
{ name: ' jqueryx ', source: ' jquery ', target: ' ~1.9.1 ' },
|
||||
{ name: ' jqueryy ', source: ' jquery-x ', target: ' ' },
|
||||
{ name: ' jqueryy ', source: ' jquery-x ', target: ' * ' },
|
||||
{ name: ' backbone ', source: ' backbone-amd ', target: ' ~1.0.0 ' },
|
||||
{ name: ' backbone ', source: ' backbone=backbone-amd ', target: ' ~1.0.0 ' },
|
||||
{ name: ' bootstrap ', source: ' http://twitter.github.io/bootstrap/assets/bootstrap ', target: ' ' },
|
||||
{ name: ' bootstrap ', source: ' http://twitter.github.io/bootstrap/assets/bootstrap ', target: ' * ' },
|
||||
{ name: ' ssh ', source: ' git@example.com ', target: ' * ' },
|
||||
{ name: ' git ', source: ' git://example.com ', target: ' * ' }
|
||||
];
|
||||
var x = 0;
|
||||
|
||||
decEndpoints.forEach(function (decEndpoint) {
|
||||
expect(endpointParser.decomposed2json(decEndpoint)).to.eql(expected[x]);
|
||||
x += 1;
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error if name is empty', function () {
|
||||
try {
|
||||
endpointParser.decomposed2json({ name: '', source: 'jquery', target: '*' });
|
||||
throw new Error('Should have failed');
|
||||
} catch (e) {
|
||||
expect(e.code).to.equal('EINVEND');
|
||||
expect(e.message).to.contain('must have a name');
|
||||
}
|
||||
|
||||
try {
|
||||
endpointParser.decomposed2json({ name: ' ', source: 'jquery', target: '*' });
|
||||
throw new Error('Should have failed');
|
||||
} catch (e) {
|
||||
expect(e.code).to.equal('EINVEND');
|
||||
expect(e.message).to.contain('must have a name');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
12
packages/bower-json/.editorconfig
Normal file
12
packages/bower-json/.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
4
packages/bower-json/.gitignore
vendored
Normal file
4
packages/bower-json/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/node_modules
|
||||
/npm-debug.*
|
||||
|
||||
/test/reports
|
||||
48
packages/bower-json/.jshintrc
Normal file
48
packages/bower-json/.jshintrc
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"indent": 4,
|
||||
"node": true,
|
||||
"devel": true,
|
||||
"mocha": true,
|
||||
|
||||
"bitwise": false,
|
||||
"curly": false,
|
||||
"eqeqeq": true,
|
||||
"forin": false,
|
||||
"immed": true,
|
||||
"latedef": false,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": false,
|
||||
"nonew": true,
|
||||
"plusplus": false,
|
||||
"regexp": false,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"quotmark": "single",
|
||||
"strict": false,
|
||||
"camelcase": true,
|
||||
|
||||
"asi": false,
|
||||
"boss": true,
|
||||
"debug": false,
|
||||
"eqnull": true,
|
||||
"es5": false,
|
||||
"esnext": false,
|
||||
"evil": false,
|
||||
"expr": false,
|
||||
"funcscope": false,
|
||||
"globalstrict": false,
|
||||
"iterator": false,
|
||||
"lastsemic": false,
|
||||
"laxbreak": true,
|
||||
"laxcomma": false,
|
||||
"loopfunc": true,
|
||||
"multistr": false,
|
||||
"onecase": true,
|
||||
"regexdash": false,
|
||||
"scripturl": false,
|
||||
"shadow": false,
|
||||
"sub": false,
|
||||
"supernew": true,
|
||||
"validthis": false
|
||||
}
|
||||
10
packages/bower-json/.travis.yml
Normal file
10
packages/bower-json/.travis.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
node_js:
|
||||
- '5'
|
||||
- '4'
|
||||
- '0.12'
|
||||
- '0.10'
|
||||
|
||||
script:
|
||||
- grunt travis
|
||||
17
packages/bower-json/CHANGELOG.md
Normal file
17
packages/bower-json/CHANGELOG.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# 0.8.1
|
||||
|
||||
- Revert strict name validations and allow @, spaces and slashes
|
||||
|
||||
# 0.8.0
|
||||
|
||||
- Update graceful-fs to 4.x
|
||||
- Add name validations that reflect what's happening in registry
|
||||
|
||||
# 0.7.1
|
||||
|
||||
- Unpublished
|
||||
|
||||
# 0.7.0
|
||||
|
||||
- Add getIssues function to retrieve all errors and warnings
|
||||
- Add readSync and findSync functions for synchronous read
|
||||
60
packages/bower-json/Gruntfile.js
Normal file
60
packages/bower-json/Gruntfile.js
Normal file
@@ -0,0 +1,60 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = function (grunt) {
|
||||
require('load-grunt-tasks')(grunt);
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
|
||||
jshint: {
|
||||
files: [
|
||||
'Gruntfile.js',
|
||||
'lib/**/*.js',
|
||||
'test/**/*.js',
|
||||
'!test/reports/**/*'
|
||||
],
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
}
|
||||
},
|
||||
|
||||
simplemocha: {
|
||||
options: {
|
||||
reporter: 'spec'
|
||||
},
|
||||
full: { src: ['test/test.js'] },
|
||||
short: {
|
||||
options: {
|
||||
reporter: 'dot'
|
||||
},
|
||||
src: ['test/test.js']
|
||||
},
|
||||
build: {
|
||||
options: {
|
||||
reporter: 'tap'
|
||||
},
|
||||
src: ['test/test.js']
|
||||
}
|
||||
},
|
||||
|
||||
exec: {
|
||||
cover: {
|
||||
command: 'STRICT_REQUIRE=1 node node_modules/istanbul/lib/cli.js cover --dir ./test/reports node_modules/mocha/bin/_mocha -- --timeout 30000 -R dot test/test.js'
|
||||
},
|
||||
coveralls: {
|
||||
command: 'node node_modules/.bin/coveralls < test/reports/lcov.info'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
watch: {
|
||||
files: ['<%= jshint.files %>'],
|
||||
tasks: ['jshint', 'simplemocha:short']
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Default task.
|
||||
grunt.registerTask('test', ['simplemocha:full']);
|
||||
grunt.registerTask('default', ['jshint', 'test']);
|
||||
grunt.registerTask('travis', ['jshint', 'exec:cover', 'exec:coveralls']);
|
||||
};
|
||||
19
packages/bower-json/LICENSE
Normal file
19
packages/bower-json/LICENSE
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2016 Twitter and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
159
packages/bower-json/README.md
Normal file
159
packages/bower-json/README.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# bower-json [](http://travis-ci.org/bower/json) [](https://coveralls.io/github/bower/json?branch=master)
|
||||
|
||||
Read `bower.json` files with semantics, normalisation, defaults and validation.
|
||||
|
||||
Install via [npm](https://www.npmjs.org/package/bower-json): `npm install --save bower-json`
|
||||
|
||||
## Usage
|
||||
|
||||
#### .read(file, options, callback)
|
||||
#### .readSync(file, options)
|
||||
|
||||
Reads `file` and applies normalisation, defaults and validation according to the `bower.json` spec.
|
||||
If the passed `file` does not exist, the callback is called with `error.code` equal to `ENOENT`.
|
||||
If the passed `file` contents are not valid JSON, the callback is called with `error.code` equal to `EMALFORMED`.
|
||||
If the `json` does not comply with the `bower.json` spec, the callback is called with `error.code` equal to `EINVALID`.
|
||||
|
||||
If `file` is a directory, `find()` will be used to search for the json file.
|
||||
The `options` argument is optional and can be omitted. These options will be passed to `parse` method.
|
||||
|
||||
|
||||
```js
|
||||
var bowerJson = require('bower-json');
|
||||
|
||||
// Can also be used by simply calling bowerJson()
|
||||
bowerJson.read('/path/to/bower.json', function (err, json) {
|
||||
if (err) {
|
||||
console.error('There was an error reading the file');
|
||||
console.error(err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('JSON: ', json);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### .parse(json, options)
|
||||
|
||||
Parses an object. Useful when you want to apply normalisation and validation directly to an object.
|
||||
If the `json` does not comply with the `bower.json` spec, an error is thrown with `error.code` equal to `EINVALID`.
|
||||
|
||||
The `options` arguments is optional and can be omitted. Available options:
|
||||
|
||||
- validate: Apply validation, defaults to `true`
|
||||
- normalize: Apply normalisation, defaults to `false`
|
||||
- clone: clone, use and return the passed in `json` object instead of using it directly, defaults to `false`
|
||||
|
||||
|
||||
```js
|
||||
var bowerJson = require('bower-json');
|
||||
|
||||
var json = {
|
||||
name: 'my-package',
|
||||
version: '0.0.1'
|
||||
};
|
||||
|
||||
try {
|
||||
bowerJson.parse(json);
|
||||
} catch (err) {
|
||||
console.error('There was an error parsing the object');
|
||||
console.error(err.message);
|
||||
}
|
||||
```
|
||||
|
||||
#### .getIssues(json) - DEPRECATED
|
||||
|
||||
Validates the passed `json` object.
|
||||
|
||||
Returns an object with errors and warnings of this bower.json contents.
|
||||
|
||||
```js
|
||||
var bowerJson = require('bower-json');
|
||||
|
||||
var json = {
|
||||
name: 'myPackage',
|
||||
version: '0.0.1',
|
||||
main: {}
|
||||
};
|
||||
|
||||
var issues = bowerJson.getIssues(json);
|
||||
|
||||
expect(issues).toEqual({
|
||||
errors: ['The "main" field has to be either an Array or a String'],
|
||||
warnings: ['The "name" must be lowercase']
|
||||
});
|
||||
|
||||
#### .validate(json)
|
||||
|
||||
Validates the passed `json` object.
|
||||
|
||||
Throws an error with `error.code` equal to `EINVALID` if it does not comply with the spec.
|
||||
|
||||
```js
|
||||
var bowerJson = require('bower-json');
|
||||
|
||||
var json = {
|
||||
name: 'myPackage',
|
||||
version: '0.0.1'
|
||||
};
|
||||
|
||||
try {
|
||||
bowerJson.validate(json);
|
||||
} catch (err) {
|
||||
console.error('There was an error validating the object');
|
||||
console.error(err.message);
|
||||
}
|
||||
```
|
||||
|
||||
#### .normalize(json)
|
||||
|
||||
```js
|
||||
var bowerJson = require('bower-json');
|
||||
|
||||
var json = {
|
||||
name: 'my-package',
|
||||
version: '0.0.1',
|
||||
main: 'foo.js,bar.js'
|
||||
};
|
||||
|
||||
bowerJson.normalize(json);
|
||||
json.main // ['foo.js', 'bar.js']
|
||||
```
|
||||
|
||||
|
||||
#### .find(folder, callback)
|
||||
#### .findSync(folder)
|
||||
|
||||
Finds the `json` filename inside a folder.
|
||||
Checks if a `bower.json` exists, falling back to `component.json` (deprecated) and `.bower.json`.
|
||||
If no file was found, the callback is called with a `error.code` of `ENOENT`.
|
||||
|
||||
```js
|
||||
var bowerJson = require('bower-json');
|
||||
|
||||
bowerJson.find('/path/to/folder', function (err, filename) {
|
||||
if (err) {
|
||||
console.error('There is no json file in the folder');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Filename: ', filename);
|
||||
|
||||
// Now that we got the filename, we can read its contents
|
||||
bowerJson.read(filename, function (err, json) {
|
||||
if (err) {
|
||||
console.error('There was an error reading the file');
|
||||
console.error(err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('JSON: ', json);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Released under the [MIT License](http://www.opensource.org/licenses/mit-license.php).
|
||||
297
packages/bower-json/lib/json.js
Normal file
297
packages/bower-json/lib/json.js
Normal file
@@ -0,0 +1,297 @@
|
||||
var fs = require('graceful-fs');
|
||||
var path = require('path');
|
||||
var deepExtend = require('deep-extend');
|
||||
var isAsset = require('./util/isAsset');
|
||||
var isComponent = require('./util/isComponent');
|
||||
var createError = require('./util/createError');
|
||||
|
||||
var possibleJsons = ['bower.json', 'component.json', '.bower.json'];
|
||||
|
||||
function read(file, options, callback) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
// Check if file is a directory
|
||||
fs.stat(file, function (err, stat) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// It's a directory, so we find the json inside it
|
||||
if (stat.isDirectory()) {
|
||||
return find(file, function (err, file) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
read(file, options, callback);
|
||||
});
|
||||
}
|
||||
|
||||
// Otherwise read it
|
||||
fs.readFile(file, function (err, contents) {
|
||||
var json;
|
||||
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
try {
|
||||
json = JSON.parse(contents.toString());
|
||||
} catch (err) {
|
||||
err.file = path.resolve(file);
|
||||
err.code = 'EMALFORMED';
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// Parse it
|
||||
try {
|
||||
json = parse(json, options);
|
||||
} catch (err) {
|
||||
err.file = path.resolve(file);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, json, file);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function readSync(file, options) {
|
||||
var stat;
|
||||
var filename;
|
||||
var contents;
|
||||
var json;
|
||||
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
try {
|
||||
stat = fs.statSync(file);
|
||||
} catch (err) {
|
||||
return err;
|
||||
}
|
||||
if (stat.isDirectory()) {
|
||||
filename = findSync(file);
|
||||
return readSync(filename);
|
||||
}
|
||||
|
||||
contents = fs.readFileSync(file);
|
||||
|
||||
try {
|
||||
json = JSON.parse(contents.toString());
|
||||
} catch (err) {
|
||||
err.file = path.resolve(file);
|
||||
err.code = 'EMALFORMED';
|
||||
return err;
|
||||
}
|
||||
|
||||
try {
|
||||
json = parse(json, options);
|
||||
} catch (err) {
|
||||
err.file = path.resolve(file);
|
||||
return err;
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
function parse(json, options) {
|
||||
options = deepExtend({
|
||||
normalize: false,
|
||||
validate: true,
|
||||
clone: false
|
||||
}, options || {});
|
||||
|
||||
// Clone
|
||||
if (options.clone) {
|
||||
json = deepExtend({}, json);
|
||||
}
|
||||
|
||||
// Validate
|
||||
if (options.validate) {
|
||||
validate(json);
|
||||
}
|
||||
|
||||
// Normalize
|
||||
if (options.normalize) {
|
||||
normalize(json);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
// This function implements:
|
||||
//
|
||||
// https://github.com/bower/bower.json-spec
|
||||
function getIssues(json) {
|
||||
// For things that shouldn't happen
|
||||
var errors = [];
|
||||
|
||||
// For things that happen but they shoudn't
|
||||
var warnings = [];
|
||||
|
||||
if (!json.name) {
|
||||
errors.push('No "name" property set');
|
||||
} else {
|
||||
if (!/^[a-zA-Z0-9_@][a-zA-Z0-9_@\.\- \/]*$/.test(json.name)) {
|
||||
errors.push('Name must be lowercase, can contain digits, dots, dashes, "@" or spaces');
|
||||
}
|
||||
|
||||
if (json.name.length > 50) {
|
||||
warnings.push('The "name" is too long, the limit is 50 characters');
|
||||
}
|
||||
|
||||
if (!/^[a-z0-9_][a-z0-9_\.\-]*$/.test(json.name)) {
|
||||
warnings.push('The "name" is recommended to be lowercase, can contain digits, dots, dashes');
|
||||
}
|
||||
|
||||
if (/^[\.-]/.test(json.name)) {
|
||||
warnings.push('The "name" cannot start with dot or dash');
|
||||
}
|
||||
|
||||
if (/[\.-]$/.test(json.name)) {
|
||||
warnings.push('The "name" cannot end with dot or dash');
|
||||
}
|
||||
}
|
||||
|
||||
if (json.description && json.description.length > 140) {
|
||||
warnings.push('The "description" is too long, the limit is 140 characters');
|
||||
}
|
||||
|
||||
if (json.main !== undefined) {
|
||||
var main = json.main;
|
||||
if (typeof main === 'string') {
|
||||
main = [main];
|
||||
}
|
||||
if (!(main instanceof Array)) {
|
||||
errors.push('The "main" field has to be either an Array or a String');
|
||||
} else {
|
||||
var ext2files = {};
|
||||
main.forEach(function (filename) {
|
||||
if (typeof filename !== 'string') {
|
||||
errors.push('The "main" Array has to contain only Strings');
|
||||
}
|
||||
if (/[*]/.test(filename)) {
|
||||
warnings.push('The "main" field cannot contain globs (example: "*.js")');
|
||||
}
|
||||
if (/[.]min[.][^/]+$/.test(filename)) {
|
||||
warnings.push('The "main" field cannot contain minified files');
|
||||
}
|
||||
if (isAsset(filename)) {
|
||||
warnings.push('The "main" field cannot contain font, image, audio, or video files');
|
||||
}
|
||||
var ext = path.extname(filename);
|
||||
if (ext.length >= 2) {
|
||||
var files = ext2files[ext];
|
||||
if (!files) {
|
||||
files = ext2files[ext] = [];
|
||||
}
|
||||
files.push(filename);
|
||||
}
|
||||
});
|
||||
Object.keys(ext2files).forEach(function (ext) {
|
||||
var files = ext2files[ext];
|
||||
if (files.length > 1) {
|
||||
warnings.push('The "main" field has to contain only 1 file per filetype; found multiple ' + ext + ' files: ' + JSON.stringify(files));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
errors: errors,
|
||||
warnings: warnings
|
||||
};
|
||||
}
|
||||
|
||||
// For backward compatibility, it throws first error
|
||||
function validate(json) {
|
||||
var issues = getIssues(json);
|
||||
|
||||
if (issues.errors && issues.errors.length > 0) {
|
||||
throw createError(issues.errors[0], 'EINVALID');
|
||||
}
|
||||
}
|
||||
|
||||
function normalize(json) {
|
||||
if (typeof json.main === 'string') {
|
||||
json.main = [json.main];
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
function find(folder, files, callback) {
|
||||
var err;
|
||||
var file;
|
||||
|
||||
if (typeof files === 'function') {
|
||||
callback = files;
|
||||
files = possibleJsons;
|
||||
}
|
||||
|
||||
if (!files.length) {
|
||||
err = createError('None of ' + possibleJsons.join(', ') + ' were found in ' + folder, 'ENOENT');
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
file = path.resolve(path.join(folder, files[0]));
|
||||
fs.exists(file, function (exists) {
|
||||
if (!exists) {
|
||||
return find(folder, files.slice(1), callback);
|
||||
}
|
||||
|
||||
if (files[0] !== 'component.json') {
|
||||
return callback(null, file);
|
||||
}
|
||||
|
||||
// If the file is component.json, check it it's a component(1) file
|
||||
// If it is, we ignore it and keep searching
|
||||
isComponent(file, function (is) {
|
||||
if (is) {
|
||||
return find(folder, files.slice(1), callback);
|
||||
}
|
||||
|
||||
callback(null, file);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function findSync(folder, files) {
|
||||
var file;
|
||||
var exists;
|
||||
|
||||
if (files === undefined) {
|
||||
files = possibleJsons;
|
||||
}
|
||||
|
||||
if (!files.length) {
|
||||
return createError('None of ' + possibleJsons.join(', ') + ' were found in ' + folder, 'ENOENT');
|
||||
}
|
||||
|
||||
file = path.resolve(path.join(folder, files[0]));
|
||||
try{
|
||||
exists = fs.statSync(file);
|
||||
}
|
||||
catch (err) {
|
||||
exists = false;
|
||||
}
|
||||
if (exists && exists.isFile()) {
|
||||
return file;
|
||||
} else {
|
||||
return findSync(folder, files.slice(1));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = read;
|
||||
module.exports.read = read;
|
||||
module.exports.readSync = readSync;
|
||||
module.exports.parse = parse;
|
||||
module.exports.getIssues = getIssues;
|
||||
module.exports.validate = validate;
|
||||
module.exports.normalize = normalize;
|
||||
module.exports.find = find;
|
||||
module.exports.findSync = findSync;
|
||||
8
packages/bower-json/lib/util/createError.js
Normal file
8
packages/bower-json/lib/util/createError.js
Normal file
@@ -0,0 +1,8 @@
|
||||
function createError(msg, code) {
|
||||
var err = new Error(msg);
|
||||
err.code = code;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
module.exports = createError;
|
||||
12
packages/bower-json/lib/util/isAsset.js
Normal file
12
packages/bower-json/lib/util/isAsset.js
Normal file
@@ -0,0 +1,12 @@
|
||||
var extName = require('ext-name');
|
||||
|
||||
function isAsset(filename) {
|
||||
var info = extName(filename);
|
||||
|
||||
return info && info.mime && (
|
||||
/^((image)|(audio)|(video)|(font))\//.test(info.mime) ||
|
||||
/application\/((x[-]font[-])|(font[-]woff(\d?))|(vnd[.]ms[-]fontobject))/.test(info.mime)
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = isAsset;
|
||||
41
packages/bower-json/lib/util/isComponent.js
Normal file
41
packages/bower-json/lib/util/isComponent.js
Normal file
@@ -0,0 +1,41 @@
|
||||
var fs = require('graceful-fs');
|
||||
var intersect = require('intersect');
|
||||
|
||||
// Function to check if a file is a component(1) file
|
||||
function isComponent(file, callback) {
|
||||
fs.readFile(file, function (err, contents) {
|
||||
var json;
|
||||
var keys;
|
||||
var common;
|
||||
|
||||
// If an error occurs while reading the file, we ignore it
|
||||
if (err) {
|
||||
return callback(false);
|
||||
}
|
||||
|
||||
try {
|
||||
json = JSON.parse(contents.toString());
|
||||
} catch (err) {
|
||||
return callback(false);
|
||||
}
|
||||
|
||||
// Attempt to find specific things from the component(1) spec
|
||||
// Note that we don't parse the dependencies property because at any point
|
||||
// we can allow / to specify directories
|
||||
// Bellow only some clearly not ambiguous properties are checked
|
||||
keys = Object.keys(json);
|
||||
common = intersect(keys, [
|
||||
'repo',
|
||||
'development',
|
||||
'local',
|
||||
'remotes',
|
||||
'paths',
|
||||
'demo'
|
||||
]);
|
||||
|
||||
// If none were found, than it's a valid component.json bower file
|
||||
callback(common.length ? true : false);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = isComponent;
|
||||
40
packages/bower-json/package.json
Normal file
40
packages/bower-json/package.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "bower-json",
|
||||
"version": "0.8.1",
|
||||
"description": "Read bower.json files with semantics, normalisation, defaults and validation",
|
||||
"author": "Twitter",
|
||||
"license": "MIT",
|
||||
"repository": "bower/json",
|
||||
"main": "lib/json",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"deep-extend": "^0.4.0",
|
||||
"ext-name": "^3.0.0",
|
||||
"graceful-fs": "^4.1.3",
|
||||
"intersect": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coveralls": "^2.11.2",
|
||||
"expect.js": "^0.3.1",
|
||||
"grunt": "^0.4.4",
|
||||
"grunt-cli": "^0.1.13",
|
||||
"grunt-contrib-jshint": "^0.11.2",
|
||||
"grunt-contrib-watch": "^0.6.1",
|
||||
"grunt-coveralls": "^1.0.0",
|
||||
"grunt-exec": "^0.4.6",
|
||||
"grunt-simple-mocha": "^0.4.0",
|
||||
"istanbul": "^0.3.5",
|
||||
"load-grunt-tasks": "^3.3.0",
|
||||
"mocha": "*",
|
||||
"request": "^2.64.0",
|
||||
"underscore.string": "^3.0.3"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt test"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1 @@
|
||||
{
|
||||
5
packages/bower-json/test/pkg-bower-json/bower.json
Normal file
5
packages/bower-json/test/pkg-bower-json/bower.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "some-pkg",
|
||||
"version": "0.0.0",
|
||||
"main": "foo.js"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "route",
|
||||
"repo": "apily/route",
|
||||
"version": "0.0.1",
|
||||
"description": "Route component",
|
||||
"keywords": ["router", "route"],
|
||||
"scripts": ["index.js"],
|
||||
"dependencies": {},
|
||||
"development": {
|
||||
"component/assert": "*",
|
||||
"visionmedia/mocha": "*"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "some-pkg",
|
||||
"version": "0.0.0"
|
||||
}
|
||||
5
packages/bower-json/test/pkg-dot-bower-json/.bower.json
Normal file
5
packages/bower-json/test/pkg-dot-bower-json/.bower.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "some-installed-pkg",
|
||||
"version": "0.0.1",
|
||||
"main": "bar.js"
|
||||
}
|
||||
497
packages/bower-json/test/test.js
Normal file
497
packages/bower-json/test/test.js
Normal file
@@ -0,0 +1,497 @@
|
||||
var path = require('path');
|
||||
var expect = require('expect.js');
|
||||
var _s = require('underscore.string');
|
||||
var bowerJson = require('../lib/json');
|
||||
var request = require('request');
|
||||
|
||||
describe('.find', function () {
|
||||
it('should find the bower.json file', function (done) {
|
||||
bowerJson.find(__dirname + '/pkg-bower-json', function (err, file) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(file).to.equal(path.resolve(__dirname + '/pkg-bower-json/bower.json'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fallback to the component.json file', function (done) {
|
||||
bowerJson.find(__dirname + '/pkg-component-json', function (err, file) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(file).to.equal(path.resolve(__dirname + '/pkg-component-json/component.json'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not fallback to the component.json file if it\'s a component(1) file', function (done) {
|
||||
bowerJson.find(__dirname + '/pkg-component(1)-json', function (err) {
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.code).to.equal('ENOENT');
|
||||
expect(err.message).to.equal('None of bower.json, component.json, .bower.json were found in ' + __dirname + '/pkg-component(1)-json');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fallback to the .bower.json file', function (done) {
|
||||
bowerJson.find(__dirname + '/pkg-dot-bower-json', function (err, file) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(file).to.equal(path.resolve(__dirname + '/pkg-dot-bower-json/.bower.json'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should error if no component.json / bower.json / .bower.json is found', function (done) {
|
||||
bowerJson.find(__dirname, function (err) {
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.code).to.equal('ENOENT');
|
||||
expect(err.message).to.equal('None of bower.json, component.json, .bower.json were found in ' + __dirname);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.findSync', function () {
|
||||
|
||||
it('should find the bower.json file', function (done) {
|
||||
var file = bowerJson.findSync(__dirname + '/pkg-bower-json');
|
||||
|
||||
expect(file).to.equal(path.resolve(__dirname + '/pkg-bower-json/bower.json'));
|
||||
done();
|
||||
});
|
||||
|
||||
it('should fallback to the component.json file', function (done) {
|
||||
var file = bowerJson.findSync(__dirname + '/pkg-component-json');
|
||||
|
||||
expect(file).to.equal(path.resolve(__dirname + '/pkg-component-json/component.json'));
|
||||
done();
|
||||
});
|
||||
|
||||
it('should fallback to the .bower.json file', function (done) {
|
||||
var file = bowerJson.findSync(__dirname + '/pkg-dot-bower-json');
|
||||
|
||||
expect(file).to.equal(path.resolve(__dirname + '/pkg-dot-bower-json/.bower.json'));
|
||||
done();
|
||||
});
|
||||
|
||||
it('should error if no component.json / bower.json / .bower.json is found', function (done) {
|
||||
var err = bowerJson.findSync(__dirname);
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.code).to.equal('ENOENT');
|
||||
expect(err.message).to.equal('None of bower.json, component.json, .bower.json were found in ' + __dirname);
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('.read', function () {
|
||||
it('should give error if file does not exists', function (done) {
|
||||
bowerJson.read(__dirname + '/willneverexist', function (err) {
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.code).to.equal('ENOENT');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should give error if when reading an invalid json', function (done) {
|
||||
bowerJson.read(__dirname + '/pkg-bower-json-malformed/bower.json', function (err) {
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.code).to.equal('EMALFORMED');
|
||||
expect(err.file).to.equal(path.resolve(__dirname + '/pkg-bower-json-malformed/bower.json'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should read the file and give an object', function (done) {
|
||||
bowerJson.read(__dirname + '/pkg-bower-json/bower.json', function (err, json) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(json).to.be.an('object');
|
||||
expect(json.name).to.equal('some-pkg');
|
||||
expect(json.version).to.equal('0.0.0');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should give the json file that was read', function (done) {
|
||||
bowerJson.read(__dirname + '/pkg-bower-json', function (err, json, file) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
|
||||
expect(file).to.equal(__dirname + '/pkg-bower-json/bower.json');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should find for a json file if a directory is given', function (done) {
|
||||
bowerJson.read(__dirname + '/pkg-component-json', function (err, json, file) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(json).to.be.an('object');
|
||||
expect(json.name).to.equal('some-pkg');
|
||||
expect(json.version).to.equal('0.0.0');
|
||||
expect(file).to.equal(path.resolve(__dirname + '/pkg-component-json/component.json'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should validate the returned object unless validate is false', function (done) {
|
||||
bowerJson.read(__dirname + '/pkg-bower-json-invalid/bower.json', function (err) {
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.message).to.contain('name');
|
||||
expect(err.file).to.equal(path.resolve(__dirname + '/pkg-bower-json-invalid/bower.json'));
|
||||
|
||||
bowerJson.read(__dirname + '/pkg-bower-json-invalid/bower.json', { validate: false }, function (err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should normalize the returned object if normalize is true', function (done) {
|
||||
bowerJson.read(__dirname + '/pkg-bower-json/bower.json', function (err, json) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(json.main).to.equal('foo.js');
|
||||
|
||||
bowerJson.read(__dirname + '/pkg-bower-json/bower.json', { normalize: true }, function (err, json) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
expect(json.main).to.eql(['foo.js']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('.readSync', function () {
|
||||
it('should give error if file does not exists', function (done) {
|
||||
var err = bowerJson.readSync(__dirname + '/willneverexist');
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.code).to.equal('ENOENT');
|
||||
done();
|
||||
});
|
||||
|
||||
it('should give error if when reading an invalid json', function (done) {
|
||||
var err = bowerJson.readSync(__dirname + '/pkg-bower-json-malformed/bower.json');
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.code).to.equal('EMALFORMED');
|
||||
expect(err.file).to.equal(path.resolve(__dirname + '/pkg-bower-json-malformed/bower.json'));
|
||||
done();
|
||||
});
|
||||
|
||||
it('should read the file and give an object', function (done) {
|
||||
var json = bowerJson.readSync(__dirname + '/pkg-bower-json/bower.json');
|
||||
|
||||
expect(json).to.be.an('object');
|
||||
expect(json.name).to.equal('some-pkg');
|
||||
expect(json.version).to.equal('0.0.0');
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should find for a json file if a directory is given', function (done) {
|
||||
var json = bowerJson.readSync(__dirname + '/pkg-component-json');
|
||||
|
||||
expect(json).to.be.an('object');
|
||||
expect(json.name).to.equal('some-pkg');
|
||||
expect(json.version).to.equal('0.0.0');
|
||||
done();
|
||||
});
|
||||
|
||||
it('should validate the returned object unless validate is false', function (done) {
|
||||
var err = bowerJson.readSync(__dirname + '/pkg-bower-json-invalid/bower.json');
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.message).to.contain('name');
|
||||
expect(err.file).to.equal(path.resolve(__dirname + '/pkg-bower-json-invalid/bower.json'));
|
||||
|
||||
err = bowerJson.readSync(__dirname + '/pkg-bower-json-invalid/bower.json', { validate: false });
|
||||
expect(err).to.not.be.an(Error);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should normalize the returned object if normalize is true', function (done) {
|
||||
var json = bowerJson.readSync(__dirname + '/pkg-bower-json/bower.json');
|
||||
expect(json.main).to.equal('foo.js');
|
||||
|
||||
json = bowerJson.readSync(__dirname + '/pkg-bower-json/bower.json', { normalize: true });
|
||||
|
||||
expect(json.main).to.eql(['foo.js']);
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('.parse', function () {
|
||||
it('should return the same object, unless clone is true', function () {
|
||||
var json = { name: 'foo' };
|
||||
|
||||
expect(bowerJson.parse(json)).to.equal(json);
|
||||
expect(bowerJson.parse(json, { clone: true })).to.not.equal(json);
|
||||
expect(bowerJson.parse(json, { clone: true })).to.eql(json);
|
||||
});
|
||||
|
||||
it('should validate the passed object, unless validate is false', function () {
|
||||
expect(function () {
|
||||
bowerJson.parse({});
|
||||
}).to.throwException(/name/);
|
||||
|
||||
expect(function () {
|
||||
bowerJson.parse({}, { validate: false });
|
||||
}).to.not.throwException();
|
||||
});
|
||||
|
||||
it('should not normalize the passed object unless normalize is true', function () {
|
||||
var json = { name: 'foo', main: 'foo.js' };
|
||||
|
||||
bowerJson.parse(json);
|
||||
expect(json.main).to.eql('foo.js');
|
||||
|
||||
bowerJson.parse(json, { normalize: true });
|
||||
expect(json.main).to.eql(['foo.js']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.getIssues', function () {
|
||||
it('should print no errors even for weird package names', function () {
|
||||
var json = { name: '@gruNt/my dependency' };
|
||||
|
||||
expect(bowerJson.getIssues(json).errors).to.be.empty();
|
||||
});
|
||||
|
||||
it('should validate the name length', function () {
|
||||
var json = { name: 'a_123456789_123456789_123456789_123456789_123456789_z' };
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "name" is too long, the limit is 50 characters'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate the name is lowercase', function () {
|
||||
var json = { name: 'gruNt' };
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "name" is recommended to be lowercase, can contain digits, dots, dashes'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate the name starts with lowercase', function () {
|
||||
var json = { name: '-runt' };
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "name" cannot start with dot or dash'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate the name starts with lowercase', function () {
|
||||
var json = { name: '.grunt' };
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "name" cannot start with dot or dash'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate the name ends with lowercase', function () {
|
||||
var json = { name: 'grun-' };
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "name" cannot end with dot or dash'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate the name ends with lowercase', function () {
|
||||
var json = { name: 'grun.' };
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "name" cannot end with dot or dash'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate the name is valid', function () {
|
||||
var json = { name: 'gru.n-t' };
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.eql([]);
|
||||
});
|
||||
|
||||
it('should validate the description length', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
description: _s.repeat('æ', 141)
|
||||
};
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "description" is too long, the limit is 140 characters'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate the description is valid', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
description: _s.repeat('æ', 140)
|
||||
};
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.eql([]);
|
||||
});
|
||||
|
||||
it('should validate that main does not contain globs', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
main: ['js/*.js']
|
||||
};
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "main" field cannot contain globs (example: "*.js")'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate that main does not contain minified files', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
main: ['foo.min.css']
|
||||
};
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "main" field cannot contain minified files'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate that main does not contain fonts', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
main: ['foo.woff']
|
||||
};
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "main" field cannot contain font, image, audio, or video files'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate that main does not contain images', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
main: ['foo.png']
|
||||
};
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "main" field cannot contain font, image, audio, or video files'
|
||||
);
|
||||
});
|
||||
|
||||
it('should validate that main does not contain multiple files of the same filetype', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
main: ['foo.js', 'bar.js']
|
||||
};
|
||||
|
||||
expect(bowerJson.getIssues(json).warnings).to.contain(
|
||||
'The "main" field has to contain only 1 file per filetype; found multiple .js files: ["foo.js","bar.js"]'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.validate', function () {
|
||||
it('should validate the name property', function () {
|
||||
expect(function () {
|
||||
bowerJson.validate({});
|
||||
}).to.throwException(/name/);
|
||||
});
|
||||
|
||||
it('should validate the type of main', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
main: {}
|
||||
};
|
||||
expect(function () {
|
||||
bowerJson.validate(json);
|
||||
}).to.throwException();
|
||||
});
|
||||
it('should validate the type of items of an Array main', function () {
|
||||
var json = {
|
||||
name: 'foo',
|
||||
main: [{}]
|
||||
};
|
||||
expect(function () {
|
||||
bowerJson.validate(json);
|
||||
}).to.throwException();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.normalize', function () {
|
||||
it('should normalize the main property', function () {
|
||||
var json = { name: 'foo', main: 'foo.js' };
|
||||
|
||||
bowerJson.normalize(json);
|
||||
expect(json.main).to.eql(['foo.js']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('packages from bower registry', function () {
|
||||
|
||||
var packageList,
|
||||
packageListUrl = 'http://bower.herokuapp.com/packages';
|
||||
|
||||
this.timeout(60000);
|
||||
|
||||
it('can be downloaded from online source ' + packageListUrl, function(done) {
|
||||
request({
|
||||
url: packageListUrl,
|
||||
json: true
|
||||
}, function(error, response, body) {
|
||||
|
||||
if(error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
expect(body).to.be.an('array');
|
||||
expect(body).to.not.be.empty();
|
||||
packageList = body;
|
||||
|
||||
done();
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
it('should validate each listed package', function (done) {
|
||||
|
||||
expect(packageList).to.be.an('array');
|
||||
|
||||
var invalidPackageCount = 0;
|
||||
|
||||
packageList.forEach(function(package) {
|
||||
try {
|
||||
bowerJson.validate(package);
|
||||
} catch(e) {
|
||||
invalidPackageCount++;
|
||||
console.error('validation of "' + package.name + '" failed: ' + e.message);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if(invalidPackageCount) {
|
||||
throw new Error(invalidPackageCount + '/' + packageList.length + ' package names do not validate');
|
||||
}
|
||||
|
||||
done();
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
12
packages/bower-logger/.editorconfig
Normal file
12
packages/bower-logger/.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
2
packages/bower-logger/.gitignore
vendored
Normal file
2
packages/bower-logger/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/node_modules
|
||||
/npm-debug.*
|
||||
@@ -26,7 +26,7 @@
|
||||
"plusplus": false,
|
||||
"regexp": false,
|
||||
"undef": true,
|
||||
"unused": "vars",
|
||||
"unused": true,
|
||||
"quotmark": "single",
|
||||
"strict": false,
|
||||
"trailing": true,
|
||||
6
packages/bower-logger/.travis.yml
Normal file
6
packages/bower-logger/.travis.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
node_js:
|
||||
- 'iojs'
|
||||
- '0.12'
|
||||
- '0.10'
|
||||
19
packages/bower-logger/LICENSE
Normal file
19
packages/bower-logger/LICENSE
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2012 Twitter and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
126
packages/bower-logger/README.md
Normal file
126
packages/bower-logger/README.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# bower-logger [](http://travis-ci.org/bower/logger)
|
||||
|
||||
The logger used in the various architecture components of Bower.
|
||||
|
||||
Install
|
||||
|
||||
```sh
|
||||
npm install --save bower-logger
|
||||
```
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
### .error(id, message, data)
|
||||
|
||||
Alias to `.log('error', id, message, data)`
|
||||
|
||||
|
||||
### .conflict(id, message, data)
|
||||
|
||||
Alias to `.log('conflict', id, message, data)`
|
||||
|
||||
|
||||
### .warn(id, message, data)
|
||||
|
||||
Alias to `.log('warn', id, message, data)`
|
||||
|
||||
|
||||
### .action(id, message, data)
|
||||
|
||||
Alias to `.log('action', id, message, data)`
|
||||
|
||||
|
||||
### .info(id, message, data)
|
||||
|
||||
Alias to `.log('info', id, message, data)`
|
||||
|
||||
|
||||
### .debug(id, message, data)
|
||||
|
||||
Alias to `.log('debug', id, message, data)`
|
||||
|
||||
|
||||
### .log(level, id, message, data)
|
||||
|
||||
Emits a `log` event, with an object like so:
|
||||
|
||||
```js
|
||||
logger.log('warn', 'foo', 'bar', { dog: 'loves cat' })
|
||||
{
|
||||
level: 'warn',
|
||||
id: 'foo',
|
||||
message: 'bar',
|
||||
data: {
|
||||
dog: 'loves cat'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### .prompt(prompts, callback)
|
||||
|
||||
Emits a `prompt` event with an array of `prompts` with a `callback`.
|
||||
`prompts` can be an object or an array of objects. The `callback` will be called with an
|
||||
the answer or an object of answers (if prompts was only one or an array respectively).
|
||||
The `callback` is guaranteed to run only once.
|
||||
|
||||
```js
|
||||
logger.on('prompt', function (prompts, callback) {
|
||||
// "prompts" is always an array of prompts
|
||||
// Call "callback" with an object of answers when done
|
||||
|
||||
// In this example, we will use the inquirer module to do the
|
||||
// prompting for us
|
||||
inquirer(prompts, callback);
|
||||
})
|
||||
|
||||
logger.prompt({
|
||||
type: 'input' // Can be 'input', 'confirm' or 'password'
|
||||
message: 'Type something',
|
||||
validate: function (value) {
|
||||
if (value !== 'I am awesome') {
|
||||
return 'You must type "I am awesome"'
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}, function (err, answer) {
|
||||
// Error will only happen on unsupported 'type'
|
||||
if (err) {
|
||||
return console.error(err.message);
|
||||
}
|
||||
|
||||
console.log(answer);
|
||||
});
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
### .pipe(logger)
|
||||
|
||||
Pipes all logger events to another logger.
|
||||
Basically all events emitted with `.emit()` will get piped.
|
||||
|
||||
|
||||
### .geminate()
|
||||
|
||||
Creates a new logger that pipes events to the parent logger.
|
||||
Alias for `(new Logger()).pipe(logger)`.
|
||||
|
||||
|
||||
### .intercept(fn)
|
||||
|
||||
Intercepts `log` events, calling `fn` before listeners of the instance.
|
||||
|
||||
|
||||
### #LEVELS
|
||||
|
||||
A static property that contains an object where keys are the recognized log levels and values their importance.
|
||||
The higher the importance, the more important the level is.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Released under the [MIT License](http://www.opensource.org/licenses/mit-license.php).
|
||||
150
packages/bower-logger/lib/Logger.js
Normal file
150
packages/bower-logger/lib/Logger.js
Normal file
@@ -0,0 +1,150 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var util = require('util');
|
||||
|
||||
var slice = Array.prototype.slice;
|
||||
|
||||
function Logger() {
|
||||
this._interceptors = [];
|
||||
this._piped = [];
|
||||
}
|
||||
|
||||
util.inherits(Logger, EventEmitter);
|
||||
|
||||
Logger.prototype.intercept = function (fn) {
|
||||
this._interceptors.push(fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
Logger.prototype.emit = function () {
|
||||
var ret;
|
||||
var args = slice.call(arguments);
|
||||
|
||||
// Run interceptors before
|
||||
if (args[0] === 'log') {
|
||||
this._interceptors.forEach(function (interceptor) {
|
||||
interceptor.apply(this, args.slice(1));
|
||||
});
|
||||
}
|
||||
|
||||
ret = EventEmitter.prototype.emit.apply(this, args);
|
||||
|
||||
// Pipe
|
||||
this._piped.forEach(function (emitter) {
|
||||
emitter.emit.apply(emitter, args);
|
||||
});
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
Logger.prototype.pipe = function (emitter) {
|
||||
this._piped.push(emitter);
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
Logger.prototype.geminate = function () {
|
||||
var logger = new Logger();
|
||||
|
||||
logger.pipe(this);
|
||||
return logger;
|
||||
};
|
||||
|
||||
Logger.prototype.log = function (level, id, message, data) {
|
||||
var log = {
|
||||
level: level,
|
||||
id: id,
|
||||
message: message,
|
||||
data: data || {}
|
||||
};
|
||||
|
||||
// Emit log
|
||||
this.emit('log', log);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Logger.prototype.prompt = function (prompts, callback) {
|
||||
var fn;
|
||||
var one;
|
||||
var invalid;
|
||||
var runned;
|
||||
var error;
|
||||
var validPrompts = Logger._validPrompts;
|
||||
|
||||
if (!Array.isArray(prompts)) {
|
||||
prompts.name = 'prompt';
|
||||
prompts = [prompts];
|
||||
one = true;
|
||||
}
|
||||
|
||||
// Validate prompt types
|
||||
invalid = prompts.some(function (prompt) {
|
||||
return validPrompts.indexOf(prompt.type) === -1;
|
||||
});
|
||||
|
||||
if (invalid) {
|
||||
error = new Error('Unknown prompt type');
|
||||
error.code = 'ENOTSUP';
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
fn = function (answers) {
|
||||
// Run callback only once
|
||||
if (runned) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Trim answers automatically
|
||||
Object.keys(answers).forEach(function (key) {
|
||||
var value = answers[key];
|
||||
|
||||
if (typeof value === 'string') {
|
||||
answers[key] = value.trim();
|
||||
} else if (Array.isArray(value)) {
|
||||
answers[key] = value.map(function (item) {
|
||||
if (typeof item === 'string') {
|
||||
return item.trim();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
runned = true;
|
||||
|
||||
// If only one prompt was requested, resolve with its answer
|
||||
if (one) {
|
||||
answers = answers.prompt;
|
||||
}
|
||||
|
||||
callback(null, answers);
|
||||
};
|
||||
|
||||
this.emit('prompt', prompts, fn);
|
||||
};
|
||||
|
||||
// ------------------
|
||||
|
||||
Logger._validPrompts = [
|
||||
'input',
|
||||
'confirm',
|
||||
'password',
|
||||
'checkbox'
|
||||
];
|
||||
|
||||
Logger.LEVELS = {
|
||||
'error': 5,
|
||||
'conflict': 4,
|
||||
'warn': 3,
|
||||
'action': 2,
|
||||
'info': 1,
|
||||
'debug': 0
|
||||
};
|
||||
|
||||
// Add helpful log methods
|
||||
Object.keys(Logger.LEVELS).forEach(function (level) {
|
||||
Logger.prototype[level] = function (id, message, data) {
|
||||
this.log(level, id, message, data);
|
||||
};
|
||||
});
|
||||
|
||||
module.exports = Logger;
|
||||
27
packages/bower-logger/package.json
Normal file
27
packages/bower-logger/package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "bower-logger",
|
||||
"version": "0.2.1",
|
||||
"description": "The logger used in the various architecture components of Bower.",
|
||||
"author": "Bower",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/bower/logger/blob/master/LICENSE"
|
||||
}
|
||||
],
|
||||
"repository": "bower/logger",
|
||||
"main": "lib/Logger",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"expect.js": "~0.2.0",
|
||||
"mocha": "~1.12.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha -R spec"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
]
|
||||
}
|
||||
389
packages/bower-logger/test/test.js
Normal file
389
packages/bower-logger/test/test.js
Normal file
@@ -0,0 +1,389 @@
|
||||
var expect = require('expect.js');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var Logger = require('../');
|
||||
|
||||
describe('Logger', function () {
|
||||
var logger;
|
||||
|
||||
beforeEach(function () {
|
||||
logger = new Logger();
|
||||
});
|
||||
|
||||
describe('.constructor', function () {
|
||||
it('should provide an instance of Logger', function () {
|
||||
expect(logger instanceof Logger).to.be(true);
|
||||
});
|
||||
|
||||
it('should provide an instance of EventEmitter', function () {
|
||||
expect(logger instanceof EventEmitter).to.be(true);
|
||||
});
|
||||
|
||||
it('should have prototype methods', function () {
|
||||
var methods = [
|
||||
'intercept', 'pipe', 'geminate', 'log'
|
||||
];
|
||||
|
||||
methods.forEach(function (method) {
|
||||
expect(logger).to.have.property(method);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('events', function () {
|
||||
var logData = {
|
||||
foo: 'bar',
|
||||
baz: 'string'
|
||||
};
|
||||
|
||||
it('should pass through {}', function (next) {
|
||||
logger.on('log', function (log) {
|
||||
expect(log.data).to.eql({});
|
||||
next();
|
||||
});
|
||||
logger.info();
|
||||
});
|
||||
|
||||
it('should pass through logData', function (next) {
|
||||
logger.on('log', function (log) {
|
||||
expect(log.data).to.eql(logData);
|
||||
next();
|
||||
});
|
||||
logger.info('foo', 'message', logData);
|
||||
});
|
||||
|
||||
it('should emit error event', function (next) {
|
||||
logger.on('log', function (log) {
|
||||
expect(log.level).to.eql('error');
|
||||
expect(log.id).to.eql('foo');
|
||||
expect(log.message).to.eql('error message');
|
||||
expect(log.data).to.eql({});
|
||||
next();
|
||||
});
|
||||
logger.error('foo', 'error message');
|
||||
});
|
||||
|
||||
it('should emit conflict event', function (next) {
|
||||
logger.on('log', function (log) {
|
||||
expect(log.level).to.eql('conflict');
|
||||
expect(log.id).to.eql('foo');
|
||||
expect(log.message).to.eql('conflict message');
|
||||
expect(log.data).to.eql({});
|
||||
next();
|
||||
});
|
||||
logger.conflict('foo', 'conflict message');
|
||||
});
|
||||
|
||||
it('should emit warn event', function (next) {
|
||||
logger.on('log', function (log) {
|
||||
expect(log.level).to.eql('warn');
|
||||
expect(log.id).to.eql('foo');
|
||||
expect(log.message).to.eql('warn message');
|
||||
expect(log.data).to.eql({});
|
||||
next();
|
||||
});
|
||||
logger.warn('foo', 'warn message');
|
||||
});
|
||||
|
||||
it('should emit action event', function (next) {
|
||||
logger.on('log', function (log) {
|
||||
expect(log.level).to.eql('action');
|
||||
expect(log.id).to.eql('foo');
|
||||
expect(log.message).to.eql('action message');
|
||||
expect(log.data).to.eql({});
|
||||
next();
|
||||
});
|
||||
logger.action('foo', 'action message');
|
||||
});
|
||||
|
||||
it('should emit info event', function (next) {
|
||||
logger.on('log', function (log) {
|
||||
expect(log.level).to.eql('info');
|
||||
expect(log.id).to.eql('foo');
|
||||
expect(log.message).to.eql('info message');
|
||||
expect(log.data).to.eql({});
|
||||
next();
|
||||
});
|
||||
logger.info('foo', 'info message');
|
||||
});
|
||||
|
||||
it('should emit debug event', function (next) {
|
||||
logger.on('log', function (log) {
|
||||
expect(log.level).to.eql('debug');
|
||||
expect(log.id).to.eql('foo');
|
||||
expect(log.message).to.eql('debug message');
|
||||
expect(log.data).to.eql({});
|
||||
next();
|
||||
});
|
||||
logger.debug('foo', 'debug message');
|
||||
});
|
||||
});
|
||||
|
||||
describe('.intercept', function () {
|
||||
it('should add the function and call it when a log occurs', function (next) {
|
||||
var called;
|
||||
var data = {
|
||||
'some': 'thing'
|
||||
};
|
||||
|
||||
logger.intercept(function (log) {
|
||||
called = true;
|
||||
|
||||
expect(log).to.eql({
|
||||
level: 'warn',
|
||||
id: 'foo',
|
||||
message: 'bar',
|
||||
data: data
|
||||
});
|
||||
expect(log.data).to.equal(data);
|
||||
});
|
||||
|
||||
logger.log('warn', 'foo', 'bar', data);
|
||||
|
||||
expect(called).to.be(true);
|
||||
next();
|
||||
});
|
||||
|
||||
it('should call the interceptors by order before emitting the event', function (next) {
|
||||
var called = [];
|
||||
|
||||
logger.intercept(function () {
|
||||
called.push(1);
|
||||
});
|
||||
logger.intercept(function () {
|
||||
called.push(2);
|
||||
});
|
||||
|
||||
logger.log('warn', 'foo', 'bar');
|
||||
|
||||
expect(called).to.eql([1, 2]);
|
||||
next();
|
||||
});
|
||||
|
||||
it('should call the interceptors along the chain', function (next) {
|
||||
var called = [];
|
||||
var childLogger = logger.geminate();
|
||||
|
||||
childLogger.intercept(function () {
|
||||
called.push(1);
|
||||
});
|
||||
logger.intercept(function () {
|
||||
called.push(3);
|
||||
});
|
||||
|
||||
childLogger.on('log', function () {
|
||||
called.push(2);
|
||||
});
|
||||
logger.on('log', function () {
|
||||
called.push(4);
|
||||
});
|
||||
|
||||
childLogger.log('warn', 'foo', 'bar');
|
||||
|
||||
expect(called).to.eql([1, 2, 3, 4]);
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.pipe', function () {
|
||||
it('should return the passed emitter', function () {
|
||||
var otherEmitter = new EventEmitter();
|
||||
expect(logger.pipe(otherEmitter)).to.equal(otherEmitter);
|
||||
});
|
||||
|
||||
it('should pipe log events to another emitter', function (next) {
|
||||
var otherEmitter = new EventEmitter();
|
||||
var data = {
|
||||
'some': 'thing'
|
||||
};
|
||||
var piped;
|
||||
|
||||
logger.pipe(otherEmitter);
|
||||
|
||||
otherEmitter.on('log', function (log) {
|
||||
piped = true;
|
||||
expect(log).to.eql({
|
||||
level: 'warn',
|
||||
id: 'foo',
|
||||
message: 'bar',
|
||||
data: data
|
||||
});
|
||||
});
|
||||
|
||||
logger.log('warn', 'foo', 'bar', data);
|
||||
|
||||
expect(piped).to.be(true);
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.geminate', function () {
|
||||
it('should return a new logger instance', function () {
|
||||
var newLogger = logger.geminate();
|
||||
|
||||
expect(newLogger).to.be.an(Logger);
|
||||
expect(newLogger).to.be.an(EventEmitter);
|
||||
expect(newLogger).to.not.be.equal(logger);
|
||||
});
|
||||
|
||||
it('should pipe the new logger events to the original logger', function (next) {
|
||||
var piped = [];
|
||||
var childLogger = logger.geminate();
|
||||
var data = {
|
||||
'some': 'thing'
|
||||
};
|
||||
|
||||
childLogger.on('log', function (log) {
|
||||
piped.push(1);
|
||||
expect(log).to.eql({
|
||||
level: 'warn',
|
||||
id: 'foo',
|
||||
message: 'bar',
|
||||
data: data
|
||||
});
|
||||
expect(log.data).to.equal(data);
|
||||
});
|
||||
|
||||
logger.on('log', function (log) {
|
||||
piped.push(2);
|
||||
expect(log).to.eql({
|
||||
level: 'warn',
|
||||
id: 'foo',
|
||||
message: 'bar',
|
||||
data: data
|
||||
});
|
||||
expect(log.data).to.equal(data);
|
||||
});
|
||||
|
||||
childLogger.log('warn', 'foo', 'bar', data);
|
||||
expect(piped).to.eql([1, 2]);
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.prompt', function () {
|
||||
it('should only allow calling the callback once', function () {
|
||||
var calls = 0;
|
||||
|
||||
logger
|
||||
.once('prompt', function (prompts, callback) {
|
||||
callback({ prompt: 'bar' });
|
||||
callback({ prompt: 'foo' });
|
||||
})
|
||||
.prompt({
|
||||
type: 'input',
|
||||
message: 'foo'
|
||||
}, function () {
|
||||
calls += 1;
|
||||
});
|
||||
|
||||
expect(calls).to.equal(1);
|
||||
});
|
||||
|
||||
it('should accept a prompt', function (next) {
|
||||
logger
|
||||
.once('prompt', function (prompts, callback) {
|
||||
callback({
|
||||
prompt: 'bar'
|
||||
});
|
||||
})
|
||||
.prompt({
|
||||
type: 'input',
|
||||
message: 'foo'
|
||||
}, function (err, answer) {
|
||||
expect(err).to.not.be.ok();
|
||||
expect(answer).to.equal('bar');
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
it('should accept several prompts', function (next) {
|
||||
logger
|
||||
.once('prompt', function (prompts, callback) {
|
||||
callback({
|
||||
foo: 'bar',
|
||||
foz: 'baz'
|
||||
});
|
||||
})
|
||||
.prompt([
|
||||
{
|
||||
name: 'foo',
|
||||
type: 'input',
|
||||
message: 'foo'
|
||||
},
|
||||
{
|
||||
name: 'foz',
|
||||
type: 'confirm',
|
||||
message: 'foz'
|
||||
}
|
||||
], function (err, answer) {
|
||||
expect(err).to.not.be.ok();
|
||||
expect(answer.foo).to.equal('bar');
|
||||
expect(answer.foz).to.equal('baz');
|
||||
|
||||
logger
|
||||
.once('prompt', function (prompts, callback) {
|
||||
callback({
|
||||
foo: 'bar'
|
||||
});
|
||||
})
|
||||
.prompt([
|
||||
{
|
||||
name: 'foo',
|
||||
type: 'input',
|
||||
message: 'foo'
|
||||
}
|
||||
], function (err, answer) {
|
||||
expect(err).to.not.be.ok();
|
||||
expect(answer.foo).to.equal('bar');
|
||||
next();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should error on invalid prompt type', function (next) {
|
||||
logger.prompt({
|
||||
type: 'xxx',
|
||||
message: 'foo'
|
||||
}, function (err) {
|
||||
expect(err).to.be.an(Error);
|
||||
expect(err.code).to.be('ENOTSUP');
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
it('should trim the answers', function (next) {
|
||||
logger
|
||||
.once('prompt', function (prompts, callback) {
|
||||
callback({
|
||||
prompt: ' bar '
|
||||
});
|
||||
})
|
||||
.prompt({
|
||||
type: 'input',
|
||||
message: 'foo'
|
||||
}, function (err, answer) {
|
||||
expect(err).to.not.be.ok();
|
||||
expect(answer).to.equal('bar');
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
it('should trim multiple response answers', function (next) {
|
||||
logger
|
||||
.once('prompt', function (prompts, callback) {
|
||||
callback({
|
||||
prompt: [' bar ', ' foo', 'baz ']
|
||||
});
|
||||
})
|
||||
.prompt({
|
||||
type: 'checkbox',
|
||||
message: 'foo'
|
||||
}, function (err, answer) {
|
||||
expect(err).to.not.be.ok();
|
||||
expect(answer).to.eql(['bar', 'foo', 'baz']);
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
12
packages/bower-registry-client/.editorconfig
Normal file
12
packages/bower-registry-client/.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
2
packages/bower-registry-client/.gitignore
vendored
Normal file
2
packages/bower-registry-client/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/node_modules
|
||||
/npm-debug.*
|
||||
61
packages/bower-registry-client/.jshintrc
Normal file
61
packages/bower-registry-client/.jshintrc
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"predef": [
|
||||
"console",
|
||||
"describe",
|
||||
"it",
|
||||
"after",
|
||||
"afterEach",
|
||||
"before",
|
||||
"beforeEach"
|
||||
],
|
||||
|
||||
"indent": 4,
|
||||
"node": true,
|
||||
"devel": true,
|
||||
|
||||
"bitwise": false,
|
||||
"curly": false,
|
||||
"eqeqeq": true,
|
||||
"forin": false,
|
||||
"immed": true,
|
||||
"latedef": false,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": false,
|
||||
"nonew": true,
|
||||
"plusplus": false,
|
||||
"regexp": false,
|
||||
"undef": true,
|
||||
"unused": "vars",
|
||||
"quotmark": "single",
|
||||
"strict": false,
|
||||
"trailing": true,
|
||||
"camelcase": true,
|
||||
|
||||
"asi": false,
|
||||
"boss": true,
|
||||
"debug": false,
|
||||
"eqnull": true,
|
||||
"esnext": false,
|
||||
"evil": false,
|
||||
"expr": true,
|
||||
"funcscope": false,
|
||||
"globalstrict": false,
|
||||
"iterator": false,
|
||||
"lastsemic": false,
|
||||
"laxbreak": true,
|
||||
"laxcomma": false,
|
||||
"loopfunc": true,
|
||||
"multistr": false,
|
||||
"onecase": true,
|
||||
"regexdash": false,
|
||||
"scripturl": false,
|
||||
"smarttabs": false,
|
||||
"shadow": false,
|
||||
"sub": false,
|
||||
"supernew": true,
|
||||
"validthis": false,
|
||||
|
||||
"nomen": false,
|
||||
"white": true
|
||||
}
|
||||
6
packages/bower-registry-client/.travis.yml
Normal file
6
packages/bower-registry-client/.travis.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
node_js:
|
||||
- 'iojs'
|
||||
- '0.12'
|
||||
- '0.10'
|
||||
70
packages/bower-registry-client/Client.js
Normal file
70
packages/bower-registry-client/Client.js
Normal file
@@ -0,0 +1,70 @@
|
||||
var async = require('async');
|
||||
var methods = require('./lib');
|
||||
var Cache = require('./lib/util/Cache');
|
||||
|
||||
function RegistryClient(config, logger) {
|
||||
this._logger = logger;
|
||||
this._config = config;
|
||||
|
||||
if (!this._config.registry) {
|
||||
throw new Error("You need to pass config as read by bower-config module. Registry field is missing.");
|
||||
}
|
||||
|
||||
// Cache defaults to storage registry
|
||||
if (!Object.prototype.hasOwnProperty.call(this._config, 'cache')) {
|
||||
this._config.cache = this._config.storage ? this._config.storage.registry : null;
|
||||
}
|
||||
|
||||
// Init the cache
|
||||
this._initCache();
|
||||
}
|
||||
|
||||
// Add every method to the prototype
|
||||
RegistryClient.prototype.lookup = methods.lookup;
|
||||
RegistryClient.prototype.search = methods.search;
|
||||
RegistryClient.prototype.list = methods.list;
|
||||
RegistryClient.prototype.register = methods.register;
|
||||
RegistryClient.prototype.unregister = methods.unregister;
|
||||
|
||||
RegistryClient.prototype.clearCache = function (name, callback) {
|
||||
if (typeof name === 'function') {
|
||||
callback = name;
|
||||
name = null;
|
||||
}
|
||||
|
||||
async.parallel([
|
||||
this.lookup.clearCache.bind(this, name),
|
||||
this.search.clearCache.bind(this, name),
|
||||
this.list.clearCache.bind(this)
|
||||
], callback);
|
||||
};
|
||||
|
||||
RegistryClient.prototype.resetCache = function (name) {
|
||||
this.lookup.resetCache.call(this, name);
|
||||
this.search.resetCache.call(this, name);
|
||||
this.list.resetCache.call(this);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
RegistryClient.clearRuntimeCache = function () {
|
||||
Cache.clearRuntimeCache();
|
||||
};
|
||||
|
||||
// -----------------------------
|
||||
|
||||
RegistryClient.prototype._initCache = function () {
|
||||
var cache;
|
||||
var dir = this._config.cache;
|
||||
|
||||
// Cache is stored/retrieved statically to ensure singularity
|
||||
// among instances
|
||||
cache = this.constructor._cache = this.constructor._cache || {};
|
||||
this._cache = cache[dir] = cache[dir] || {};
|
||||
|
||||
this.lookup.initCache.call(this);
|
||||
this.search.initCache.call(this);
|
||||
this.list.initCache.call(this);
|
||||
};
|
||||
|
||||
module.exports = RegistryClient;
|
||||
47
packages/bower-registry-client/Gruntfile.js
Normal file
47
packages/bower-registry-client/Gruntfile.js
Normal file
@@ -0,0 +1,47 @@
|
||||
'use strict';
|
||||
module.exports = function (grunt) {
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
grunt.loadNpmTasks('grunt-simple-mocha');
|
||||
|
||||
grunt.initConfig({
|
||||
jshint: {
|
||||
files: [
|
||||
'Gruntfile.js',
|
||||
'lib/**/*.js',
|
||||
'test/**/*.js'
|
||||
],
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
}
|
||||
},
|
||||
simplemocha: {
|
||||
options: {
|
||||
reporter: 'spec',
|
||||
timeout: 20000
|
||||
},
|
||||
full: {
|
||||
src: ['test/runner.js']
|
||||
},
|
||||
short: {
|
||||
options: {
|
||||
reporter: 'dot'
|
||||
},
|
||||
src: ['test/runner.js']
|
||||
},
|
||||
build: {
|
||||
options: {
|
||||
reporter: 'tap'
|
||||
},
|
||||
src: ['test/runner.js']
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
files: ['<%= jshint.files %>'],
|
||||
tasks: ['jshint', 'simplemocha:short']
|
||||
}
|
||||
});
|
||||
|
||||
grunt.registerTask('test', ['simplemocha:full']);
|
||||
grunt.registerTask('default', ['jshint', 'test']);
|
||||
};
|
||||
19
packages/bower-registry-client/LICENSE
Normal file
19
packages/bower-registry-client/LICENSE
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2012 Twitter and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
155
packages/bower-registry-client/README.md
Normal file
155
packages/bower-registry-client/README.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# bower-registry-client [](https://travis-ci.org/bower/registry-client)
|
||||
|
||||
> Provides easy interaction with the Bower registry
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
$ npm install --save bower-registry-client
|
||||
```
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
var RegistryClient = require('bower-registry-client');
|
||||
var Config = require('bower-config');
|
||||
var config = Config.read(process.cwd(), options);
|
||||
var registry = new RegistryClient(config, logger);
|
||||
```
|
||||
|
||||
The `logger` is optional and is expected to be an instance of the bower [logger](https://github.com/bower/logger).
|
||||
Available constructor options:
|
||||
|
||||
- `cache`: the cache folder to use for some operations; using null will disable persistent cache (defaults to bower registry cache folder)
|
||||
- `registry.search`: an array of registry search endpoints (defaults to the Bower server)
|
||||
- `registry.register`: the endpoint to use when registering packages (defaults to the Bower server)
|
||||
- `registry.publish`: the endpoint to use when publishing packages (defaults to the Bower server)
|
||||
- `ca.search`: an array of CA certificates for each registry.search (defaults to null).
|
||||
- `ca.register`: the CA certificate for registry.register
|
||||
- `ca.publish`: the CA certificate for registry.publish
|
||||
- `proxy`: the proxy to use for http requests (defaults to null)
|
||||
- `httpsProxy`: the proxy to use for https requests (defaults to null)
|
||||
- `strictSsl`: whether or not to do SSL key validation when making requests via https (defaults to true).
|
||||
- `userAgent`: the user agent to use for the requests (defaults to null)
|
||||
- `timeout`: the timeout for the requests to finish (defaults to 60000)
|
||||
- `force`: If set to true, cache will be bypassed and remotes will always be hit (defaults to false).
|
||||
- `offline`: If set to true, only the cache will be used (defaults to false).
|
||||
|
||||
|
||||
Note that `force` and `offline` are mutually exclusive.
|
||||
The cache will speedup operations such as `list`, `lookup` and `search`.
|
||||
Different operations may have different cache expiration times.
|
||||
|
||||
|
||||
#### .lookup(name, callback)
|
||||
|
||||
Looks the registry for the package `name`,
|
||||
|
||||
```js
|
||||
registry.lookup('jquery', function (err, entry) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
// For now resp.type is always 'alias'
|
||||
console.log('type', entry.type);
|
||||
console.log('url', entry.url);
|
||||
});
|
||||
```
|
||||
|
||||
#### .register(name, url, callback)
|
||||
|
||||
Registers a package in the registry.
|
||||
|
||||
```js
|
||||
registry.register('my-package', 'git://github.com/my-org/my-package.git', function (err, pkg) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('name', pkg.name);
|
||||
console.log('url: ', pkg.url);
|
||||
});
|
||||
```
|
||||
|
||||
#### .search(str, callback)
|
||||
|
||||
Searches the registry.
|
||||
|
||||
```js
|
||||
registry.search('jquery', function (err, results) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
results.forEach(function (pkg) {
|
||||
console.log('name', pkg.name);
|
||||
console.log('url', pkg.url);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### .clearCache(name, callback)
|
||||
|
||||
Clears the persistent and runtime cache associated with the `name` package.
|
||||
If `name` is null, clears the cache for every package.
|
||||
|
||||
Note that in most cases, you don't need to clear the cache since it has
|
||||
self expiration times.
|
||||
|
||||
```js
|
||||
// Clear jquery cache
|
||||
registry.clearCache('jquery', function (err) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Done');
|
||||
});
|
||||
|
||||
// Clear all cache
|
||||
registry.clearCache(function (err) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Done');
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
#### .resetCache()
|
||||
|
||||
Clears the in-memory cache used to speed up the instance.
|
||||
|
||||
Note that in most cases, you don't need to clear the runtime cache since it has
|
||||
self expiration times.
|
||||
Might be useful if you use this module in long-living programs.
|
||||
|
||||
```js
|
||||
registry.resetCache();
|
||||
```
|
||||
|
||||
#### #clearRuntimeCache()
|
||||
|
||||
Clears the in-memory cache used to speed up the whole module.
|
||||
This clears the static in-memory cache as well as in-memory cache used by instances.
|
||||
|
||||
Note that in edge cases, some instance's in-memory cache might be skipped.
|
||||
If that's a problem, you should create fresh instances instead.
|
||||
|
||||
```js
|
||||
RegistryClient.clearRuntimeCache();
|
||||
```
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Released under the [MIT License](http://www.opensource.org/licenses/mit-license.php).
|
||||
7
packages/bower-registry-client/lib/index.js
Normal file
7
packages/bower-registry-client/lib/index.js
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
lookup: require('./lookup'),
|
||||
list: require('./list'),
|
||||
register: require('./register'),
|
||||
search: require('./search'),
|
||||
unregister: require('./unregister')
|
||||
};
|
||||
184
packages/bower-registry-client/lib/list.js
Normal file
184
packages/bower-registry-client/lib/list.js
Normal file
@@ -0,0 +1,184 @@
|
||||
var path = require('path');
|
||||
var url = require('url');
|
||||
var async = require('async');
|
||||
var request = require('request');
|
||||
var replay = require('request-replay');
|
||||
var Cache = require('./util/Cache');
|
||||
var createError = require('./util/createError');
|
||||
|
||||
function list(callback) {
|
||||
var data = [];
|
||||
var that = this;
|
||||
var registry = this._config.registry.search;
|
||||
var total = registry.length;
|
||||
var index = 0;
|
||||
|
||||
// If no registry entries were passed, simply
|
||||
// error with package not found
|
||||
if (!total) {
|
||||
return callback(null, []);
|
||||
}
|
||||
|
||||
// List packages in series in each registry
|
||||
async.doUntil(function (next) {
|
||||
var remote = url.parse(registry[index]);
|
||||
var listCache = that._listCache[remote.host];
|
||||
|
||||
// If offline flag is passed, only query the cache
|
||||
if (that._config.offline) {
|
||||
return listCache.get('list', function (err, results) {
|
||||
if (err || !results) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
// Add each result
|
||||
results.forEach(function (result) {
|
||||
addResult.call(that, data, result);
|
||||
});
|
||||
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
// Otherwise make a request to always obtain fresh data
|
||||
doRequest.call(that, index, function (err, results) {
|
||||
if (err || !results) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
// Add each result
|
||||
results.forEach(function (result) {
|
||||
addResult(data, result);
|
||||
});
|
||||
|
||||
// Store in cache for future offline usage
|
||||
listCache.set('list', results, getMaxAge(), next);
|
||||
});
|
||||
}, function () {
|
||||
// Until there's still registries to test
|
||||
return ++index === total;
|
||||
}, function (err) {
|
||||
// Clear runtime cache, keeping the persistent data
|
||||
// in files for future offline usage
|
||||
resetCache();
|
||||
|
||||
// If some of the registry entries failed, error out
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, data);
|
||||
});
|
||||
}
|
||||
|
||||
function addResult(accumulated, result) {
|
||||
var exists = accumulated.some(function (current) {
|
||||
return current.name === result.name;
|
||||
});
|
||||
|
||||
if (!exists) {
|
||||
accumulated.push(result);
|
||||
}
|
||||
}
|
||||
|
||||
function doRequest(index, callback) {
|
||||
var req;
|
||||
var msg;
|
||||
var requestUrl = this._config.registry.search[index] + '/packages';
|
||||
var remote = url.parse(requestUrl);
|
||||
var headers = {};
|
||||
var that = this;
|
||||
|
||||
if (this._config.userAgent) {
|
||||
headers['User-Agent'] = this._config.userAgent;
|
||||
}
|
||||
|
||||
req = replay(request.get(requestUrl, {
|
||||
ca: this._config.ca.search[index],
|
||||
headers: headers,
|
||||
strictSSL: this._config.strictSsl,
|
||||
timeout: this._config.timeout,
|
||||
json: true
|
||||
}, function (err, response, body) {
|
||||
// If there was an internal error (e.g. timeout)
|
||||
if (err) {
|
||||
return callback(createError('Request to ' + requestUrl + ' failed: ' + err.message, err.code));
|
||||
}
|
||||
|
||||
// Abort if there was an error (range different than 2xx)
|
||||
if (response.statusCode < 200 || response.statusCode > 299) {
|
||||
return callback(createError('Request to ' + requestUrl + ' failed with ' + response.statusCode, 'EINVRES'));
|
||||
}
|
||||
|
||||
// Validate response body, since we are expecting a JSON object
|
||||
// If the server returns an invalid JSON, it's still a string
|
||||
if (typeof body !== 'object') {
|
||||
return callback(createError('Response of request to ' + requestUrl + ' is not a valid json', 'EINVRES'));
|
||||
}
|
||||
|
||||
callback(null, body);
|
||||
}));
|
||||
|
||||
if (this._logger) {
|
||||
req.on('replay', function (replay) {
|
||||
msg = 'Request to ' + requestUrl + ' failed with ' + replay.error.code + ', ';
|
||||
msg += 'retrying in ' + (replay.delay / 1000).toFixed(1) + 's';
|
||||
that._logger.warn('retry', msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getMaxAge() {
|
||||
// Make it 5 minutes
|
||||
return 5 * 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
function initCache() {
|
||||
this._listCache = this._cache.list || {};
|
||||
|
||||
// Generate a cache instance for each registry endpoint
|
||||
this._config.registry.search.forEach(function (registry) {
|
||||
var cacheDir;
|
||||
var host = url.parse(registry).host;
|
||||
|
||||
// Skip if there's a cache for the same host
|
||||
if (this._listCache[host]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._config.cache) {
|
||||
cacheDir = path.join(this._config.cache, encodeURIComponent(host), 'list');
|
||||
}
|
||||
|
||||
this._listCache[host] = new Cache(cacheDir, {
|
||||
max: 250,
|
||||
// If offline flag is passed, we use stale entries from the cache
|
||||
useStale: this._config.offline
|
||||
});
|
||||
}, this);
|
||||
}
|
||||
|
||||
function clearCache(callback) {
|
||||
var listCache = this._listCache;
|
||||
var remotes = Object.keys(listCache);
|
||||
|
||||
// There's only one key, which is 'list'..
|
||||
// But we clear everything anyway
|
||||
async.forEach(remotes, function (remote, next) {
|
||||
listCache[remote].clear(next);
|
||||
}, callback);
|
||||
}
|
||||
|
||||
function resetCache() {
|
||||
var remote;
|
||||
|
||||
for (remote in this._listCache) {
|
||||
this._listCache[remote].reset();
|
||||
}
|
||||
}
|
||||
|
||||
list.initCache = initCache;
|
||||
list.clearCache = clearCache;
|
||||
list.resetCache = resetCache;
|
||||
|
||||
module.exports = list;
|
||||
202
packages/bower-registry-client/lib/lookup.js
Normal file
202
packages/bower-registry-client/lib/lookup.js
Normal file
@@ -0,0 +1,202 @@
|
||||
var path = require('path');
|
||||
var url = require('url');
|
||||
var async = require('async');
|
||||
var request = require('request');
|
||||
var replay = require('request-replay');
|
||||
var createError = require('./util/createError');
|
||||
var Cache = require('./util/Cache');
|
||||
|
||||
function lookup(name, callback) {
|
||||
var data;
|
||||
var that = this;
|
||||
var registry = this._config.registry.search;
|
||||
var total = registry.length;
|
||||
var index = 0;
|
||||
|
||||
// If no registry entries were passed..
|
||||
if (!total) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
// Lookup package in series in each registry
|
||||
// endpoint until we got the data
|
||||
async.doUntil(function (next) {
|
||||
var remote = url.parse(registry[index]);
|
||||
var lookupCache = that._lookupCache[remote.host];
|
||||
|
||||
// If force flag is disabled we check the cache
|
||||
if (!that._config.force) {
|
||||
lookupCache.get(name, function (err, value) {
|
||||
data = value;
|
||||
|
||||
// Don't proceed with making a request if we got an error,
|
||||
// a value from the cache or if the offline flag is enabled
|
||||
if (err || data || that._config.offline) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
doRequest.call(that, name, index, function (err, entry) {
|
||||
if (err || !entry) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
data = entry;
|
||||
|
||||
// Store in cache
|
||||
lookupCache.set(name, entry, getMaxAge(entry), next);
|
||||
});
|
||||
});
|
||||
// Otherwise, we totally bypass the cache and
|
||||
// make only the request
|
||||
} else {
|
||||
doRequest.call(that, name, index, function (err, entry) {
|
||||
if (err || !entry) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
data = entry;
|
||||
|
||||
// Store in cache
|
||||
lookupCache.set(name, entry, getMaxAge(entry), next);
|
||||
});
|
||||
}
|
||||
}, function () {
|
||||
// Until the data is unknown or there's still registries to test
|
||||
return !!data || ++index === total;
|
||||
}, function (err) {
|
||||
// If some of the registry entries failed, error out
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, data);
|
||||
});
|
||||
}
|
||||
|
||||
function doRequest(name, index, callback) {
|
||||
var req;
|
||||
var msg;
|
||||
var requestUrl = this._config.registry.search[index] + '/packages/' + encodeURIComponent(name);
|
||||
var remote = url.parse(requestUrl);
|
||||
var headers = {};
|
||||
var that = this;
|
||||
|
||||
if (this._config.userAgent) {
|
||||
headers['User-Agent'] = this._config.userAgent;
|
||||
}
|
||||
|
||||
req = replay(request.get(requestUrl, {
|
||||
headers: headers,
|
||||
ca: this._config.ca.search[index],
|
||||
strictSSL: this._config.strictSsl,
|
||||
timeout: this._config.timeout,
|
||||
json: true
|
||||
}, function (err, response, body) {
|
||||
// If there was an internal error (e.g. timeout)
|
||||
if (err) {
|
||||
return callback(createError('Request to ' + requestUrl + ' failed: ' + err.message, err.code));
|
||||
}
|
||||
|
||||
// If not found, try next
|
||||
if (response.statusCode === 404) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
// Abort if there was an error (range different than 2xx)
|
||||
if (response.statusCode < 200 || response.statusCode > 299) {
|
||||
return callback(createError('Request to ' + requestUrl + ' failed with ' + response.statusCode, 'EINVRES'));
|
||||
}
|
||||
|
||||
// Validate response body, since we are expecting a JSON object
|
||||
// If the server returns an invalid JSON, it's still a string
|
||||
if (typeof body !== 'object') {
|
||||
return callback(createError('Response of request to ' + requestUrl + ' is not a valid json', 'EINVRES'));
|
||||
}
|
||||
|
||||
var data;
|
||||
if (body.url) {
|
||||
data = {
|
||||
type: 'alias',
|
||||
url: body.url
|
||||
};
|
||||
}
|
||||
callback(null, data);
|
||||
}));
|
||||
|
||||
if (this._logger) {
|
||||
req.on('replay', function (replay) {
|
||||
msg = 'Request to ' + requestUrl + ' failed with ' + replay.error.code + ', ';
|
||||
msg += 'retrying in ' + (replay.delay / 1000).toFixed(1) + 's';
|
||||
that._logger.warn('retry', msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getMaxAge(entry) {
|
||||
// If type is alias, make it 5 days
|
||||
if (entry.type === 'alias') {
|
||||
return 5 * 24 * 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
// Otherwise make it 5 minutes
|
||||
return 5 * 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
function initCache() {
|
||||
this._lookupCache = this._cache.lookup || {};
|
||||
|
||||
// Generate a cache instance for each registry endpoint
|
||||
this._config.registry.search.forEach(function (registry) {
|
||||
var cacheDir;
|
||||
var host = url.parse(registry).host;
|
||||
|
||||
// Skip if there's a cache for the same host
|
||||
if (this._lookupCache[host]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._config.cache) {
|
||||
cacheDir = path.join(this._config.cache, encodeURIComponent(host), 'lookup');
|
||||
}
|
||||
|
||||
this._lookupCache[host] = new Cache(cacheDir, {
|
||||
max: 250,
|
||||
// If offline flag is passed, we use stale entries from the cache
|
||||
useStale: this._config.offline
|
||||
});
|
||||
}, this);
|
||||
}
|
||||
|
||||
function clearCache(name, callback) {
|
||||
var lookupCache = this._lookupCache;
|
||||
var remotes = Object.keys(lookupCache);
|
||||
|
||||
if (typeof name === 'function') {
|
||||
callback = name;
|
||||
name = null;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
async.forEach(remotes, function (remote, next) {
|
||||
lookupCache[remote].del(name, next);
|
||||
}, callback);
|
||||
} else {
|
||||
async.forEach(remotes, function (remote, next) {
|
||||
lookupCache[remote].clear(next);
|
||||
}, callback);
|
||||
}
|
||||
}
|
||||
|
||||
function resetCache() {
|
||||
var remote;
|
||||
|
||||
for (remote in this._lookupCache) {
|
||||
this._lookupCache[remote].reset();
|
||||
}
|
||||
}
|
||||
|
||||
lookup.initCache = initCache;
|
||||
lookup.clearCache = clearCache;
|
||||
lookup.resetCache = resetCache;
|
||||
|
||||
module.exports = lookup;
|
||||
58
packages/bower-registry-client/lib/register.js
Normal file
58
packages/bower-registry-client/lib/register.js
Normal file
@@ -0,0 +1,58 @@
|
||||
var parseUrl = require('url').parse;
|
||||
var request = require('request');
|
||||
var createError = require('./util/createError');
|
||||
|
||||
function register(name, url, callback) {
|
||||
var config = this._config;
|
||||
var requestUrl = config.registry.register + '/packages';
|
||||
var remote = parseUrl(requestUrl);
|
||||
var headers = {};
|
||||
|
||||
if (config.userAgent) {
|
||||
headers['User-Agent'] = config.userAgent;
|
||||
}
|
||||
|
||||
if (config.accessToken) {
|
||||
requestUrl += '?access_token=' + config.accessToken;
|
||||
}
|
||||
|
||||
request.post({
|
||||
url: requestUrl,
|
||||
headers: headers,
|
||||
ca: config.ca.register,
|
||||
strictSSL: config.strictSsl,
|
||||
timeout: config.timeout,
|
||||
json: true,
|
||||
form: {
|
||||
name: name,
|
||||
url: url
|
||||
}
|
||||
}, function (err, response) {
|
||||
// If there was an internal error (e.g. timeout)
|
||||
if (err) {
|
||||
return callback(createError('Request to ' + requestUrl + ' failed: ' + err.message, err.code));
|
||||
}
|
||||
|
||||
// Duplicate
|
||||
if (response.statusCode === 403) {
|
||||
return callback(createError('Duplicate package', 'EDUPLICATE'));
|
||||
}
|
||||
|
||||
// Invalid format
|
||||
if (response.statusCode === 400) {
|
||||
return callback(createError('Invalid URL format', 'EINVFORMAT'));
|
||||
}
|
||||
|
||||
// Everything other than 201 is unknown
|
||||
if (response.statusCode !== 201) {
|
||||
return callback(createError('Unknown error: ' + response.statusCode + ' - ' + response.body, 'EUNKNOWN'));
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
name: name,
|
||||
url: url
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = register;
|
||||
200
packages/bower-registry-client/lib/search.js
Normal file
200
packages/bower-registry-client/lib/search.js
Normal file
@@ -0,0 +1,200 @@
|
||||
var path = require('path');
|
||||
var url = require('url');
|
||||
var async = require('async');
|
||||
var request = require('request');
|
||||
var replay = require('request-replay');
|
||||
var Cache = require('./util/Cache');
|
||||
var createError = require('./util/createError');
|
||||
|
||||
// TODO:
|
||||
// The search cache simply stores a specific search result
|
||||
// into a file. This is a very rudimentary algorithm but
|
||||
// works to support elementary offline support
|
||||
// Once the registry server is rewritten, a better strategy
|
||||
// can be implemented (with diffs and local search), similar to npm.
|
||||
|
||||
function search(name, callback) {
|
||||
var data = [];
|
||||
var that = this;
|
||||
var registry = this._config.registry.search;
|
||||
var total = registry.length;
|
||||
var index = 0;
|
||||
|
||||
// If no registry entries were passed, simply
|
||||
// error with package not found
|
||||
if (!total) {
|
||||
return callback(null, []);
|
||||
}
|
||||
|
||||
// Search package in series in each registry,
|
||||
// merging results together
|
||||
async.doUntil(function (next) {
|
||||
var remote = url.parse(registry[index]);
|
||||
var searchCache = that._searchCache[remote.host];
|
||||
|
||||
// If offline flag is passed, only query the cache
|
||||
if (that._config.offline) {
|
||||
return searchCache.get(name, function (err, results) {
|
||||
if (err || !results || !results.length) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
// Add each result
|
||||
results.forEach(function (result) {
|
||||
addResult.call(that, data, result);
|
||||
});
|
||||
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
// Otherwise make a request to always obtain fresh data
|
||||
doRequest.call(that, name, index, function (err, results) {
|
||||
if (err || !results || !results.length) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
// Add each result
|
||||
results.forEach(function (result) {
|
||||
addResult.call(that, data, result);
|
||||
});
|
||||
|
||||
// Store in cache for future offline usage
|
||||
searchCache.set(name, results, getMaxAge(), next);
|
||||
});
|
||||
}, function () {
|
||||
// Until the data is unknown or there's still registries to test
|
||||
return ++index === total;
|
||||
}, function (err) {
|
||||
// Clear runtime cache, keeping the persistent data
|
||||
// in files for future offline usage
|
||||
resetCache();
|
||||
|
||||
// If some of the registry entries failed, error out
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, data);
|
||||
});
|
||||
}
|
||||
|
||||
function addResult(accumulated, result) {
|
||||
var exists = accumulated.some(function (current) {
|
||||
return current.name === result.name;
|
||||
});
|
||||
|
||||
if (!exists) {
|
||||
accumulated.push(result);
|
||||
}
|
||||
}
|
||||
|
||||
function doRequest(name, index, callback) {
|
||||
var req;
|
||||
var msg;
|
||||
var requestUrl = this._config.registry.search[index] + '/packages/search/' + encodeURIComponent(name);
|
||||
var remote = url.parse(requestUrl);
|
||||
var headers = {};
|
||||
var that = this;
|
||||
|
||||
if (this._config.userAgent) {
|
||||
headers['User-Agent'] = this._config.userAgent;
|
||||
}
|
||||
|
||||
req = replay(request.get(requestUrl, {
|
||||
headers: headers,
|
||||
ca: this._config.ca.search[index],
|
||||
strictSSL: this._config.strictSsl,
|
||||
timeout: this._config.timeout,
|
||||
json: true
|
||||
}, function (err, response, body) {
|
||||
// If there was an internal error (e.g. timeout)
|
||||
if (err) {
|
||||
return callback(createError('Request to ' + requestUrl + ' failed: ' + err.message, err.code));
|
||||
}
|
||||
|
||||
// Abort if there was an error (range different than 2xx)
|
||||
if (response.statusCode < 200 || response.statusCode > 299) {
|
||||
return callback(createError('Request to ' + requestUrl + ' failed with ' + response.statusCode, 'EINVRES'));
|
||||
}
|
||||
|
||||
// Validate response body, since we are expecting a JSON object
|
||||
// If the server returns an invalid JSON, it's still a string
|
||||
if (typeof body !== 'object') {
|
||||
return callback(createError('Response of request to ' + requestUrl + ' is not a valid json', 'EINVRES'));
|
||||
}
|
||||
|
||||
callback(null, body);
|
||||
}));
|
||||
|
||||
if (this._logger) {
|
||||
req.on('replay', function (replay) {
|
||||
msg = 'Request to ' + requestUrl + ' failed with ' + replay.error.code + ', ';
|
||||
msg += 'retrying in ' + (replay.delay / 1000).toFixed(1) + 's';
|
||||
that._logger.warn('retry', msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getMaxAge() {
|
||||
// Make it 5 minutes
|
||||
return 5 * 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
function initCache() {
|
||||
this._searchCache = this._cache.search || {};
|
||||
|
||||
// Generate a cache instance for each registry endpoint
|
||||
this._config.registry.search.forEach(function (registry) {
|
||||
var cacheDir;
|
||||
var host = url.parse(registry).host;
|
||||
|
||||
// Skip if there's a cache for the same host
|
||||
if (this._searchCache[host]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._config.cache) {
|
||||
cacheDir = path.join(this._config.cache, encodeURIComponent(host), 'search');
|
||||
}
|
||||
|
||||
this._searchCache[host] = new Cache(cacheDir, {
|
||||
max: 250,
|
||||
// If offline flag is passed, we use stale entries from the cache
|
||||
useStale: this._config.offline
|
||||
});
|
||||
}, this);
|
||||
}
|
||||
|
||||
function clearCache(name, callback) {
|
||||
var searchCache = this._searchCache;
|
||||
var remotes = Object.keys(searchCache);
|
||||
|
||||
if (typeof name === 'function') {
|
||||
callback = name;
|
||||
name = null;
|
||||
}
|
||||
|
||||
// Simply erase everything since other searches could
|
||||
// contain the "name" package
|
||||
// One possible solution would be to read every entry from the cache and
|
||||
// delete if the package is contained in the search results
|
||||
// But this is too expensive
|
||||
async.forEach(remotes, function (remote, next) {
|
||||
searchCache[remote].clear(next);
|
||||
}, callback);
|
||||
}
|
||||
|
||||
function resetCache() {
|
||||
var remote;
|
||||
|
||||
for (remote in this._searchCache) {
|
||||
this._searchCache[remote].reset();
|
||||
}
|
||||
}
|
||||
|
||||
search.initCache = initCache;
|
||||
search.clearCache = clearCache;
|
||||
search.resetCache = resetCache;
|
||||
|
||||
module.exports = search;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user