mirror of
https://github.com/bower/bower.git
synced 2026-04-24 03:00:19 -04:00
Compare commits
2110 Commits
| 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 | ||
|
|
3207365e3a | ||
|
|
b87b8ea931 | ||
|
|
58d21ddc15 | ||
|
|
80c1fee406 | ||
|
|
a595c1ceaf | ||
|
|
cc9c440614 | ||
|
|
37425713ba | ||
|
|
8e76d67bdf | ||
|
|
ab7e7ac12a | ||
|
|
99cb553cbd | ||
|
|
dcc396234c | ||
|
|
3788e8d7b3 | ||
|
|
715de1b18c | ||
|
|
7c2384cb94 | ||
|
|
5b1dd15749 | ||
|
|
041290e1c7 | ||
|
|
1f8417041d | ||
|
|
7ecd70a90b | ||
|
|
6d85ae8e8e | ||
|
|
f405877a16 | ||
|
|
d22c6f9d66 | ||
|
|
c87f0495c0 | ||
|
|
15fbf44948 | ||
|
|
10963bd808 | ||
|
|
0866c93573 | ||
|
|
48e475c9f6 | ||
|
|
2c5ab19374 | ||
|
|
9d50c31d2c | ||
|
|
b8b03c88e4 | ||
|
|
a65f57e0f5 | ||
|
|
491027b048 | ||
|
|
5e1971a951 | ||
|
|
1099e786df | ||
|
|
be95169c1b | ||
|
|
f64f672b20 | ||
|
|
7c0a5d60ef | ||
|
|
1f7bd9fd47 | ||
|
|
2a7c3eb2e6 | ||
|
|
32aeba2bb8 | ||
|
|
20e376c214 | ||
|
|
a0c1552726 | ||
|
|
46783e32d5 | ||
|
|
2eafac3ff6 | ||
|
|
9bd85b7023 | ||
|
|
eb9dcce30b | ||
|
|
a899cb48b3 | ||
|
|
ed8ac01f07 | ||
|
|
742ef58d89 | ||
|
|
c98bef5fc7 | ||
|
|
23044b3758 | ||
|
|
107ce78b12 | ||
|
|
5f81b8f0c1 | ||
|
|
83d75e704b | ||
|
|
a860e3eaf7 | ||
|
|
3d84bcc7ad | ||
|
|
c31504220d | ||
|
|
f8501cf7f4 | ||
|
|
81ef5a1dd2 | ||
|
|
29ec793386 | ||
|
|
187457df13 | ||
|
|
2eea214a42 | ||
|
|
639c2290b7 | ||
|
|
3044dcd3af | ||
|
|
3d64b16227 | ||
|
|
7bd22a5103 | ||
|
|
12cde3ddce | ||
|
|
860d70551f | ||
|
|
6db6fcc414 | ||
|
|
25c229de73 | ||
|
|
d954a54017 | ||
|
|
dcdd8cb3db | ||
|
|
e93c5f8265 | ||
|
|
77be4520dc | ||
|
|
cf76bcb2aa | ||
|
|
b272a61eac | ||
|
|
4ed5f278f8 | ||
|
|
6a16850960 | ||
|
|
78bbf1f04f | ||
|
|
52938202bd | ||
|
|
0eac8bb96e | ||
|
|
46ae1e759c | ||
|
|
e0c1308c2a | ||
|
|
0f29818030 | ||
|
|
dd39a25dd0 | ||
|
|
430dc04b09 | ||
|
|
39209f3bda | ||
|
|
0eaa43c05d | ||
|
|
6ed4be9135 | ||
|
|
02b6a21276 | ||
|
|
794ca573b8 | ||
|
|
5eadd36107 | ||
|
|
c6a370309d | ||
|
|
13e2514830 | ||
|
|
0b8be97fb5 | ||
|
|
c327dcb255 | ||
|
|
1b505cc0e6 | ||
|
|
032f771996 | ||
|
|
35d83d2306 | ||
|
|
dd23feb5ea | ||
|
|
e21d7bd000 | ||
|
|
d18cfa7b59 | ||
|
|
eca956cf80 | ||
|
|
587cc5acdd | ||
|
|
b5e9a4c191 | ||
|
|
3ced03ca7f | ||
|
|
9fa08fee99 | ||
|
|
3dfd7a9ab1 | ||
|
|
1713e5e2eb | ||
|
|
1d7342573b | ||
|
|
64fc295ecc | ||
|
|
12baabcc89 | ||
|
|
13839e9384 | ||
|
|
6b6dc8311a | ||
|
|
b1d8c3c1e3 | ||
|
|
d42a564de8 | ||
|
|
71d083a552 | ||
|
|
cf802c368d | ||
|
|
71037cb482 | ||
|
|
1f4e5cadd2 | ||
|
|
72e6e61970 | ||
|
|
4402b80ec9 | ||
|
|
3f0dbef7ea | ||
|
|
1ee8abf098 | ||
|
|
55eb1e2290 | ||
|
|
906990d9b5 | ||
|
|
518f3d2a8f | ||
|
|
6ba6ea0084 | ||
|
|
01c499d73f | ||
|
|
0de9cc82f6 | ||
|
|
7dba46df9b | ||
|
|
7621a71359 | ||
|
|
17f72f0ae2 | ||
|
|
47094ef046 | ||
|
|
6e28e79b29 | ||
|
|
463b258409 | ||
|
|
49d4c96ddf | ||
|
|
197d3e9d36 | ||
|
|
adcc368238 | ||
|
|
eff97c4d28 | ||
|
|
d2aeed7a0c | ||
|
|
9cb09feb65 | ||
|
|
fb084fa4cd | ||
|
|
846b8fb57e | ||
|
|
cb649830a0 | ||
|
|
bf4266c2e3 | ||
|
|
814a0f9016 | ||
|
|
098753520f | ||
|
|
43ae12f63b | ||
|
|
46937bbb87 | ||
|
|
5bf0c768f7 | ||
|
|
f124fd4c23 | ||
|
|
ff49d24743 | ||
|
|
99ca255aad | ||
|
|
d1a63b6fe0 | ||
|
|
3530a33fe7 | ||
|
|
d08efcfe3c | ||
|
|
337c0f2d0a | ||
|
|
1acf4a53d3 | ||
|
|
a2b0fb7d82 | ||
|
|
088c488e2d | ||
|
|
64ef934a3c | ||
|
|
39b690e96a | ||
|
|
08fc86698d | ||
|
|
89510f40d3 | ||
|
|
9f2207eb1f | ||
|
|
7bacf8c425 | ||
|
|
896672c4f4 | ||
|
|
a6552d7d54 | ||
|
|
cacef7b316 | ||
|
|
7a8642db94 | ||
|
|
2b8e0fdf06 | ||
|
|
dfb18b305d | ||
|
|
1606395546 | ||
|
|
abe4264a13 | ||
|
|
60d9bfb2b8 | ||
|
|
9141b3020f | ||
|
|
367c3c3e95 | ||
|
|
41a3903ac9 | ||
|
|
146d6ac538 | ||
|
|
fce93e16ae | ||
|
|
fb12fc03bf | ||
|
|
9c49b097c8 | ||
|
|
524e83fca4 | ||
|
|
f5999e84a2 | ||
|
|
ee2640bc43 | ||
|
|
2b93aa000c | ||
|
|
9c4b30b65c | ||
|
|
160dc5c470 | ||
|
|
bbe2896de2 | ||
|
|
673f641283 | ||
|
|
36d8d308f2 | ||
|
|
3482dd2a6b | ||
|
|
9cee8b7b78 | ||
|
|
4ae1b5e04d | ||
|
|
a34c8dc502 | ||
|
|
b42c1ddbbc | ||
|
|
9cc4860050 | ||
|
|
58921f7422 | ||
|
|
8dbd79d49b | ||
|
|
e2c67fa25a | ||
|
|
f332de8ba9 | ||
|
|
8dce9a6f66 | ||
|
|
1c616115b9 | ||
|
|
a97375552f | ||
|
|
1cf99d757a | ||
|
|
e84e94a8d1 | ||
|
|
cf85177c7f | ||
|
|
2b334774ce | ||
|
|
bc4a0f448b | ||
|
|
14ef86456f | ||
|
|
b083422321 | ||
|
|
12efc85baf | ||
|
|
68124dfdbe | ||
|
|
ee4158e90b | ||
|
|
0b3b7efccf | ||
|
|
b282d02a77 | ||
|
|
e07c813320 | ||
|
|
b76a00b6fe | ||
|
|
77e077d658 | ||
|
|
1cec48c065 | ||
|
|
30fa7f5a7f | ||
|
|
83edff6b26 | ||
|
|
fd58a5fe06 | ||
|
|
6064269936 | ||
|
|
d0929896cf | ||
|
|
990e87de1f | ||
|
|
8da47dcd00 | ||
|
|
15957bc9ac | ||
|
|
59f87bdffe | ||
|
|
ee31e93f98 | ||
|
|
d3f3d17536 | ||
|
|
88c1045180 | ||
|
|
2c06feb6a1 | ||
|
|
5b4fb961af | ||
|
|
3995ec0ff7 | ||
|
|
d2144905db | ||
|
|
b29c9c28fa | ||
|
|
aa2e68d1ad | ||
|
|
85b2ec93c8 | ||
|
|
c63d88d987 | ||
|
|
c21bde192b | ||
|
|
39f1f8aff5 | ||
|
|
3f8fcbf4e3 | ||
|
|
24cabf19af | ||
|
|
ae04f71e55 | ||
|
|
c56f0db891 | ||
|
|
ebf2765f2f | ||
|
|
8dac95d86d | ||
|
|
6125c0423f | ||
|
|
f3d1638131 | ||
|
|
8b699c58ae | ||
|
|
743a97c784 | ||
|
|
ea7ae5698a | ||
|
|
3ed9b3ec39 | ||
|
|
e8f3e3b88a | ||
|
|
82d16fbfde | ||
|
|
73c2e885e9 | ||
|
|
2e615e7570 | ||
|
|
d0f90546f3 | ||
|
|
22091cf272 | ||
|
|
f2f3fa4c9c | ||
|
|
0ab2ce9cf6 | ||
|
|
1b1424fe2f | ||
|
|
ee31c44ff1 | ||
|
|
e64af6b11b | ||
|
|
d6045931a5 | ||
|
|
9f99d5d42a | ||
|
|
327703871b | ||
|
|
b456f71b64 | ||
|
|
9576b8a8e9 | ||
|
|
e0037c7eaf | ||
|
|
59c5caa395 | ||
|
|
e4a35594ba | ||
|
|
5f44d1f2cf | ||
|
|
489c6f6730 | ||
|
|
c66afdf434 | ||
|
|
d62f5142cc | ||
|
|
5d4007918c | ||
|
|
5b49b5c535 | ||
|
|
7bd19e39a7 | ||
|
|
5037aed3ae | ||
|
|
c00bacb790 | ||
|
|
5672019203 | ||
|
|
7cb5da9971 | ||
|
|
62672bc4c8 | ||
|
|
705d62be18 | ||
|
|
d237522e8c | ||
|
|
44308fa026 | ||
|
|
766dcd0dd5 | ||
|
|
87302d6d86 | ||
|
|
aae19206a0 | ||
|
|
212c4c3a71 | ||
|
|
e1a443177e | ||
|
|
1210ea821a | ||
|
|
9721381383 | ||
|
|
5ea9a1d715 | ||
|
|
83f00d720e | ||
|
|
ee76fe584e | ||
|
|
063453b744 | ||
|
|
05b94d1d15 | ||
|
|
ed0c93aec3 | ||
|
|
3a0cb8b35c | ||
|
|
f0ed7f22db | ||
|
|
ac91f07d22 | ||
|
|
d5a7a691a2 | ||
|
|
229b23b350 | ||
|
|
18ee9518ec | ||
|
|
43e0328722 | ||
|
|
12cf93ddd8 | ||
|
|
03b4467173 | ||
|
|
45a5ac28f2 | ||
|
|
635eec013c | ||
|
|
679b9217e0 | ||
|
|
39f3571383 | ||
|
|
f027cc6a3e | ||
|
|
634ce6829a | ||
|
|
64b5f9af78 | ||
|
|
9269fcb8a7 | ||
|
|
571b34c990 | ||
|
|
f0d29cb755 | ||
|
|
897e0f1ba6 | ||
|
|
4cfa94d304 | ||
|
|
5e2abb8a33 | ||
|
|
0dc5052e36 | ||
|
|
774ad1e2ff | ||
|
|
52e91cc309 | ||
|
|
38fb72ece9 | ||
|
|
fcbefa218b | ||
|
|
c06b9d696e | ||
|
|
d3e6274939 | ||
|
|
ec904eb8a4 | ||
|
|
68c5e996d6 | ||
|
|
95a09c5463 | ||
|
|
125fb598d5 | ||
|
|
f8c13f939c | ||
|
|
e55e08339a | ||
|
|
ec86260eb5 | ||
|
|
adee5cec2b | ||
|
|
c846b24ebb | ||
|
|
85324d9109 | ||
|
|
10b410d46f | ||
|
|
c87fe7c265 | ||
|
|
ce0984573b | ||
|
|
b38c3a5035 | ||
|
|
15dca65bd1 | ||
|
|
e1aa43147d | ||
|
|
057b18e4be | ||
|
|
d4f2ced6a3 | ||
|
|
0b6c92fcd2 | ||
|
|
4491e71ee2 | ||
|
|
d09f78801c | ||
|
|
f26ea32897 | ||
|
|
6b7f6aee22 | ||
|
|
514fd0730c | ||
|
|
854596fb04 | ||
|
|
cf6b8f752b | ||
|
|
702f36be0d | ||
|
|
c738bc1e96 | ||
|
|
6c1c13ed11 | ||
|
|
d1b39cce2b | ||
|
|
5e67622374 | ||
|
|
90e95bbd76 | ||
|
|
6deaacadea | ||
|
|
2ae4003f7d | ||
|
|
dd951d5350 | ||
|
|
c86d0230ba | ||
|
|
79345691b8 | ||
|
|
2763cf37f7 | ||
|
|
66cfe050e0 | ||
|
|
e6b1595cde | ||
|
|
3b376a3d3d | ||
|
|
5ed04d97dd | ||
|
|
1e724af838 | ||
|
|
aec00821e5 | ||
|
|
bf1542c35b | ||
|
|
5a6d27cc19 | ||
|
|
2d83abbb85 | ||
|
|
a9afa42f52 | ||
|
|
a37f1c5dcb | ||
|
|
ecac2bd084 | ||
|
|
01aec3760c | ||
|
|
33cac4832f | ||
|
|
41b246903f | ||
|
|
4148e0c7a9 | ||
|
|
729bdd9c68 | ||
|
|
1f2d8d6340 | ||
|
|
de3cf327d4 | ||
|
|
fa3da880ea | ||
|
|
5dea57ddd5 | ||
|
|
caa59cbb62 | ||
|
|
51e32f72de | ||
|
|
32089aefce | ||
|
|
048bc53bd0 | ||
|
|
69e1d04638 | ||
|
|
de4c7a04c3 | ||
|
|
2c79181c05 | ||
|
|
5b37ec0de5 | ||
|
|
86dbea7ddb | ||
|
|
c49e7e181b | ||
|
|
b0dbbc51df | ||
|
|
91779a67fb | ||
|
|
1fe6cde934 | ||
|
|
3b8d00095e | ||
|
|
4221ddbb35 | ||
|
|
eeb0c22d90 | ||
|
|
eb801e66ae | ||
|
|
3fdf639bb4 | ||
|
|
4061ef65e4 | ||
|
|
0cf8af00b3 | ||
|
|
4d0d4ca6ea | ||
|
|
56cdae67c3 | ||
|
|
b50017cad4 | ||
|
|
62c616f197 | ||
|
|
fcfeda9f39 | ||
|
|
c85c38cde3 | ||
|
|
f606eda18d | ||
|
|
08c9e2dde3 | ||
|
|
dd965e03c5 | ||
|
|
3e3f5faacc | ||
|
|
7e41cd0d32 | ||
|
|
882bf7b020 | ||
|
|
da4e70bc60 | ||
|
|
f75f720c8a | ||
|
|
8d3aff5ff1 | ||
|
|
4e8c9078f7 | ||
|
|
41e4efcf1f | ||
|
|
f55e6138a5 | ||
|
|
147e24d835 | ||
|
|
4a94858ed1 | ||
|
|
e1d77e12b9 | ||
|
|
8e51d1eaf3 | ||
|
|
738835088b | ||
|
|
823b287eda | ||
|
|
a2c195e844 | ||
|
|
5a5503ab34 | ||
|
|
6e037a4d46 | ||
|
|
14597f74f4 | ||
|
|
fabf2479ec | ||
|
|
12c90bae04 | ||
|
|
37904db9cd | ||
|
|
499d9da75f | ||
|
|
198d612b87 | ||
|
|
e7667ba34b | ||
|
|
861ef7313b | ||
|
|
0291ffb951 | ||
|
|
93a7f9f3b8 | ||
|
|
62337e34a3 | ||
|
|
a24b70de75 | ||
|
|
6f7f10b2f7 | ||
|
|
bd7579fa65 | ||
|
|
430a2ea2f6 | ||
|
|
87569617ae | ||
|
|
b17beaccf1 | ||
|
|
cddba64151 | ||
|
|
ed3a18529a | ||
|
|
06bffb9cee | ||
|
|
a6e4ff83f0 | ||
|
|
a73025d20b | ||
|
|
0085ebb756 | ||
|
|
5d5f23cddc | ||
|
|
761c947e25 | ||
|
|
ec33766803 | ||
|
|
6daf891c5c | ||
|
|
9b04553fc8 | ||
|
|
a006bfeb24 | ||
|
|
71e1a8666d | ||
|
|
820c7e660a | ||
|
|
e94cb6a4b6 | ||
|
|
16e7872a82 | ||
|
|
aa4ebb07f8 | ||
|
|
4366d6a8c7 | ||
|
|
aa76d49234 | ||
|
|
d9df06644e | ||
|
|
554ee01263 | ||
|
|
b3055067d8 | ||
|
|
7f997d4b59 | ||
|
|
07717b2d08 | ||
|
|
7d2162b2d2 | ||
|
|
d15fa0cfb3 | ||
|
|
d2d959f455 | ||
|
|
a9e497f878 | ||
|
|
e423e9ffba | ||
|
|
3b8b52d222 | ||
|
|
b9514692fe | ||
|
|
73592f76ba | ||
|
|
47f0f1fab8 | ||
|
|
bb3a5620d3 | ||
|
|
268a1475f0 | ||
|
|
a46dad9fde | ||
|
|
3f7bf15cdb | ||
|
|
ed9f883301 | ||
|
|
2386d46609 | ||
|
|
0da1dbdc14 | ||
|
|
dba635aac5 | ||
|
|
e1ca49c082 | ||
|
|
a47d5f4f12 | ||
|
|
e809133c25 | ||
|
|
4e39979852 | ||
|
|
ff99fae928 | ||
|
|
2e0353c725 | ||
|
|
3c9983ca12 | ||
|
|
d3412e7de6 | ||
|
|
908fa55674 | ||
|
|
4a26332133 | ||
|
|
6c17c5a3a2 | ||
|
|
1e6f54f055 | ||
|
|
59da873adf | ||
|
|
fb4b1827db | ||
|
|
2e2263ed58 | ||
|
|
ac18199295 | ||
|
|
4a954853f2 | ||
|
|
1973f1a1de | ||
|
|
d36a448aff | ||
|
|
29aa481d2d | ||
|
|
5c276c34ea | ||
|
|
1d2b654021 | ||
|
|
bdfb0bb14f | ||
|
|
6eeb03f159 | ||
|
|
f806416b84 | ||
|
|
7e64e60625 | ||
|
|
a44d4bccc2 | ||
|
|
b8c3e95068 | ||
|
|
85e55f3be2 | ||
|
|
eaee9e0e49 | ||
|
|
e232c42fc5 | ||
|
|
c7c043c898 | ||
|
|
57b718ff32 | ||
|
|
f2775c18a1 | ||
|
|
d1001aea1a | ||
|
|
39e33f3538 | ||
|
|
a786fa534a | ||
|
|
2a0831ab5a | ||
|
|
c6b61b0838 | ||
|
|
e73e480939 | ||
|
|
e5d53b4964 | ||
|
|
1521fde0bd | ||
|
|
eee0e81e6b | ||
|
|
c7be3d73b9 | ||
|
|
8574d50eaa | ||
|
|
2841942899 | ||
|
|
eb33c9ec81 | ||
|
|
56679d2a8e | ||
|
|
415e79b523 | ||
|
|
9a6fdaa42b | ||
|
|
ff54168a10 | ||
|
|
b2acd5fa75 | ||
|
|
33d0f1fd94 | ||
|
|
bb4f09316a | ||
|
|
b5976dc2ff | ||
|
|
47824ec1ac | ||
|
|
9223b089b1 | ||
|
|
6da9a1285c | ||
|
|
3b90e24ff8 | ||
|
|
93da60c03b | ||
|
|
a3e501a355 | ||
|
|
0cdbe998cb | ||
|
|
35b0c49da5 | ||
|
|
d43c9f006b | ||
|
|
01a6ae61d2 | ||
|
|
a25d9e7aa7 | ||
|
|
440020726f | ||
|
|
36ad643a5f | ||
|
|
2b6800f01b | ||
|
|
b7cb3ee89f | ||
|
|
c9490b9ef8 | ||
|
|
87210a3c15 | ||
|
|
a314d33dea | ||
|
|
4c305b7532 | ||
|
|
19cd6a1bdf | ||
|
|
dbd276dd9c | ||
|
|
28913e3a72 | ||
|
|
d0465eccf1 | ||
|
|
3aedec3e2d | ||
|
|
f931d60ac1 | ||
|
|
4b4b233377 | ||
|
|
ccc9907034 | ||
|
|
7c8146128e | ||
|
|
6c506ba556 | ||
|
|
5a7baa0a3b | ||
|
|
26520abe2b | ||
|
|
1397c3248d | ||
|
|
c40dc39b88 | ||
|
|
a2753bb27d | ||
|
|
1c5529691b | ||
|
|
8e5bdc6b2b | ||
|
|
c5342e4a15 | ||
|
|
47a1cce5fa | ||
|
|
ef60fcb9ec | ||
|
|
b45a1bd913 | ||
|
|
9a8a0932d0 | ||
|
|
ccd06ee534 | ||
|
|
5f5e33027a | ||
|
|
3fbdfa1583 | ||
|
|
624bc1de56 | ||
|
|
597100d108 | ||
|
|
418f97dbba | ||
|
|
6a38671e3c | ||
|
|
4f8542c133 | ||
|
|
0f2d49b2d6 | ||
|
|
39324d6b55 | ||
|
|
b1ad187d1b | ||
|
|
606f15fec5 | ||
|
|
34a2f1ad65 | ||
|
|
ce20fb535d | ||
|
|
bfe8323753 | ||
|
|
f2b86ad3ed | ||
|
|
42b498654b | ||
|
|
888a4e1c0e | ||
|
|
09a0eb26d1 | ||
|
|
bf9e8048ff | ||
|
|
1c6d2864b6 | ||
|
|
21ebc226e4 | ||
|
|
8e3fef9096 | ||
|
|
829dccc1b6 | ||
|
|
a65caa62b3 | ||
|
|
ddb6f9c5b4 | ||
|
|
e152ab6cf2 | ||
|
|
4085af023a | ||
|
|
686e401368 | ||
|
|
8ec079945a | ||
|
|
4d8dbefc85 | ||
|
|
746c05081d | ||
|
|
2fdfa64b13 | ||
|
|
f406cfcebb | ||
|
|
80f35725e6 | ||
|
|
6741d99681 | ||
|
|
ad4ec14778 | ||
|
|
2bf16ad88b | ||
|
|
6c56581c15 | ||
|
|
ce89d9fbe0 | ||
|
|
9517191e35 | ||
|
|
e298f74310 | ||
|
|
c550c1373e | ||
|
|
6a1bb88c3b | ||
|
|
a585e96fdf | ||
|
|
e78ef493a1 | ||
|
|
c139378694 | ||
|
|
e51827bfcd | ||
|
|
d0eb3e760f | ||
|
|
9cfa3e5002 | ||
|
|
bb76621b7f | ||
|
|
c6746f6f77 | ||
|
|
714d453aa0 | ||
|
|
915c8d7afa | ||
|
|
1bf51a047e | ||
|
|
a7b2fe14b9 | ||
|
|
82278037ec | ||
|
|
0b592f86d0 | ||
|
|
ee4e003c2d | ||
|
|
b2904bc6fb | ||
|
|
67b94cf52e | ||
|
|
c308d2c9dd | ||
|
|
e36370b080 | ||
|
|
d0f005a6f1 | ||
|
|
a461fa9137 | ||
|
|
22e969fb59 | ||
|
|
34527c8395 | ||
|
|
012f4d68bc | ||
|
|
da8d0f3265 | ||
|
|
9b57d18143 | ||
|
|
9f0ac51e06 | ||
|
|
74b9e51cf7 | ||
|
|
ec4d8d7f9c | ||
|
|
011a19772d | ||
|
|
d8cef76592 | ||
|
|
856b0f4469 | ||
|
|
ca76d41f9a | ||
|
|
f7ba6e1121 | ||
|
|
df19dbc0de | ||
|
|
3b3e64e752 | ||
|
|
724283433a | ||
|
|
aea19b93b1 | ||
|
|
73020a711d | ||
|
|
7e62e671e3 | ||
|
|
2e845ac0ab | ||
|
|
2df41e52ed | ||
|
|
bf8e93f581 | ||
|
|
f5eec3283c | ||
|
|
223161c7d6 | ||
|
|
b8ba6e4827 | ||
|
|
15c8259ac2 | ||
|
|
720492932f | ||
|
|
a08a0fb084 | ||
|
|
827fbaac1f | ||
|
|
0de3175775 | ||
|
|
008b807803 | ||
|
|
08b53410b4 | ||
|
|
ce06b2cb18 | ||
|
|
d4d5a04487 | ||
|
|
297224bd31 | ||
|
|
9dc835c60c | ||
|
|
67a96bc2f3 | ||
|
|
92d98c8d59 | ||
|
|
7becb19da4 | ||
|
|
deee654426 | ||
|
|
552fd52bd5 | ||
|
|
f58fb3e556 | ||
|
|
ff5bf16111 | ||
|
|
8d22059462 | ||
|
|
91d144f5f7 | ||
|
|
c894b1d335 | ||
|
|
d30a7bf6a1 | ||
|
|
7f18cbf7d5 | ||
|
|
e7741b3d1f | ||
|
|
9d26cd787a | ||
|
|
561bc42259 | ||
|
|
649d5f56c9 | ||
|
|
3e4ca5ceb9 | ||
|
|
81b53112c1 | ||
|
|
fe1a635c14 | ||
|
|
521e6033a2 | ||
|
|
36b033c2f7 | ||
|
|
dc9bce915b | ||
|
|
37a0e733ad | ||
|
|
b3005eeec7 | ||
|
|
b21bfda7f6 | ||
|
|
a2f9662a99 | ||
|
|
274254b12e | ||
|
|
087e17511c | ||
|
|
139e868cce | ||
|
|
b6ec84e94d | ||
|
|
2b09392261 | ||
|
|
2132384736 | ||
|
|
8798f467e1 | ||
|
|
c9a7cfafd0 | ||
|
|
9d9585ecba | ||
|
|
3204bcb7a0 | ||
|
|
645a5206ec | ||
|
|
28baf4de5e | ||
|
|
04ddcd9489 | ||
|
|
a82f392cac | ||
|
|
15d308864c | ||
|
|
9af3a0d725 | ||
|
|
d2494fb97d | ||
|
|
c32ef61d3a | ||
|
|
6020d06038 | ||
|
|
b2b1b1cb47 | ||
|
|
023a605cad | ||
|
|
a61e31f646 | ||
|
|
0361436a66 | ||
|
|
c800670f39 | ||
|
|
7fa42cbdd3 | ||
|
|
f3f39e283e | ||
|
|
c9e1159c42 | ||
|
|
f9f8f7aebd | ||
|
|
ee3941b86a | ||
|
|
f9499e4b2f | ||
|
|
0ebd7e6a58 | ||
|
|
a100abc3b6 | ||
|
|
94f6945d5a | ||
|
|
870d57bfa5 | ||
|
|
a02f26f0eb | ||
|
|
442d771a7a | ||
|
|
242e11eefc | ||
|
|
97edd21784 | ||
|
|
2309656169 | ||
|
|
22ea322fc5 | ||
|
|
17f793a4bb | ||
|
|
2f16e17ed5 | ||
|
|
27ae79f50d | ||
|
|
eb18c0a505 | ||
|
|
103d1adc46 | ||
|
|
db661f124f | ||
|
|
4c3802878a | ||
|
|
23e560b638 | ||
|
|
b82a2ee735 | ||
|
|
7fbbae8cd4 | ||
|
|
83b6820458 | ||
|
|
b80d96d9c7 | ||
|
|
d8e69360b9 | ||
|
|
83ae9b66a3 | ||
|
|
3a7b4fd404 | ||
|
|
578557f3d7 | ||
|
|
92b7668067 | ||
|
|
95f9170736 | ||
|
|
52be2230cb | ||
|
|
8d2cecfd5c | ||
|
|
4738150c55 | ||
|
|
88b4847ba9 | ||
|
|
667fae9442 | ||
|
|
f532eb708e | ||
|
|
94a24b3f57 | ||
|
|
62fadc8200 | ||
|
|
1370625568 | ||
|
|
8eed440840 | ||
|
|
1aed2b9a43 | ||
|
|
6ec31cc7f9 | ||
|
|
6d3b3e6de2 | ||
|
|
10fd2b5b5a | ||
|
|
d020acca22 | ||
|
|
e704733743 | ||
|
|
79522194f1 | ||
|
|
aadc9e64d8 | ||
|
|
2eea258b9b | ||
|
|
796e019f12 | ||
|
|
036bd999fd | ||
|
|
1fdb5373c9 | ||
|
|
0ebe5ff55a | ||
|
|
ef610ab7de | ||
|
|
68454492e9 | ||
|
|
4593b652c4 | ||
|
|
2670915583 | ||
|
|
fb41535c69 | ||
|
|
b0890844e4 | ||
|
|
8239226208 | ||
|
|
49be1638ba | ||
|
|
e188047cfb | ||
|
|
afd01cc40c | ||
|
|
ee0b620d33 | ||
|
|
2d0c0d2aad | ||
|
|
e811236973 | ||
|
|
12078f07c6 | ||
|
|
c9ef3fa1d7 | ||
|
|
0a724e5a73 | ||
|
|
2c9e4aacf2 | ||
|
|
41486d44ee | ||
|
|
7fb326245e | ||
|
|
542645d876 | ||
|
|
9a5cf69251 | ||
|
|
b322633e8b | ||
|
|
487cd384a5 | ||
|
|
0b0055e0e2 | ||
|
|
57a9b313c4 | ||
|
|
81e8b0eb18 | ||
|
|
26da7d5e81 | ||
|
|
76b85ed554 | ||
|
|
d954568f7b | ||
|
|
92a2723815 | ||
|
|
4064fedf55 | ||
|
|
a27ad2e353 | ||
|
|
13aa3914ac | ||
|
|
20ba998383 | ||
|
|
612e718b91 | ||
|
|
cfc4fc354b | ||
|
|
61208817df | ||
|
|
bb58b5cbed | ||
|
|
eed8025ae2 | ||
|
|
a57d2c0e14 | ||
|
|
90afa5b3e1 | ||
|
|
a7c0cd405d | ||
|
|
bed22468ba | ||
|
|
93d4c3c47c | ||
|
|
0c190651cb | ||
|
|
3cf56ff7d5 | ||
|
|
f3f16c96e8 | ||
|
|
70a4ab863d | ||
|
|
d62ccfd234 | ||
|
|
370793a005 | ||
|
|
292c0356f1 | ||
|
|
4d6bcf27e9 | ||
|
|
130e417451 | ||
|
|
e6f2d9de86 | ||
|
|
415a1bffac | ||
|
|
798895d78d | ||
|
|
e24529d8d1 | ||
|
|
454436905c | ||
|
|
26feee1ed5 | ||
|
|
005b3356f2 | ||
|
|
4ac052c10b | ||
|
|
f1717f8319 | ||
|
|
cb000549bd | ||
|
|
c8d4d39068 | ||
|
|
8539298008 | ||
|
|
f7395b7d7c | ||
|
|
86758dcb70 | ||
|
|
f7c3b7c664 | ||
|
|
616d1a2c88 | ||
|
|
9f2b02d98e | ||
|
|
fc193b2d24 | ||
|
|
01d8d0dbec | ||
|
|
2712aa2ae2 | ||
|
|
7dcefa6bee | ||
|
|
70e3528809 | ||
|
|
c7780a2708 | ||
|
|
784d458e62 | ||
|
|
0e1e7875a8 | ||
|
|
03c6614aed | ||
|
|
26f33b9581 | ||
|
|
0ba66d4d47 | ||
|
|
5bc0b24913 | ||
|
|
da87fd7747 | ||
|
|
49b1608af8 | ||
|
|
8bc6d7af8c | ||
|
|
479690f011 | ||
|
|
2510f21c81 | ||
|
|
d6e55dffb0 | ||
|
|
7df0e22664 | ||
|
|
8939fe0b83 | ||
|
|
c4cbfd352e | ||
|
|
aea39080d6 | ||
|
|
658a4dbb2e | ||
|
|
607e16025d | ||
|
|
ecacdfaf49 | ||
|
|
d8719ede12 | ||
|
|
11834a4186 | ||
|
|
81381fac75 | ||
|
|
9fa91aab36 | ||
|
|
2897b66a1c | ||
|
|
ef77ac11ef | ||
|
|
382c857a4b | ||
|
|
c4bfbd3f94 | ||
|
|
f4c1a125e7 | ||
|
|
010e47634b | ||
|
|
086fda5f24 | ||
|
|
27b39c29b8 | ||
|
|
680ac9825a | ||
|
|
cfb3d14028 | ||
|
|
9f6bf62efc | ||
|
|
60ecceafec | ||
|
|
7b0b53a96d | ||
|
|
87d0e1d886 | ||
|
|
e84bc3754f | ||
|
|
26bab84d04 | ||
|
|
efea6136e7 | ||
|
|
c56026c18a | ||
|
|
375b76d46a | ||
|
|
1d9504d0f0 | ||
|
|
780b1f8acc | ||
|
|
b369fa2c7b | ||
|
|
7c96eb0819 | ||
|
|
febc3b7936 | ||
|
|
1e511dd655 | ||
|
|
71eafe436a | ||
|
|
66a5312908 | ||
|
|
14f4cdbbe5 | ||
|
|
e479e84bde | ||
|
|
19e3a2ecc4 | ||
|
|
d2290d509f | ||
|
|
434d4298df | ||
|
|
9b6c5741de | ||
|
|
e09a3b8cbf | ||
|
|
c3b9d3be8c | ||
|
|
0742e18edd | ||
|
|
cb59c2489b | ||
|
|
3158b544d5 | ||
|
|
e80270d1fa | ||
|
|
99b37f24bb | ||
|
|
fdbdcc4130 | ||
|
|
08104966b2 | ||
|
|
1c99133177 | ||
|
|
28780dc67e | ||
|
|
423ce54d8a | ||
|
|
73bab73db6 | ||
|
|
3e90471fa2 | ||
|
|
7f2db8a9a7 | ||
|
|
d5fc147ffd | ||
|
|
77ffd7bbf9 | ||
|
|
42775d3477 | ||
|
|
6932b8c378 | ||
|
|
fb9ac01533 | ||
|
|
cff641ef80 | ||
|
|
373abf1b24 | ||
|
|
f668596667 | ||
|
|
adf14f79e0 | ||
|
|
cd31799c4c | ||
|
|
93e0e815d7 | ||
|
|
05275c8938 | ||
|
|
19475db7dd | ||
|
|
63c005a3de | ||
|
|
4e984f5532 | ||
|
|
5cb79a4c1a | ||
|
|
083cb9cc9a | ||
|
|
f25903905c | ||
|
|
16216147bc | ||
|
|
8069e5568b | ||
|
|
0682df3801 | ||
|
|
b0800c7e38 | ||
|
|
e5c4391900 | ||
|
|
e33e7446ee | ||
|
|
f8c3e6adf3 | ||
|
|
de0eca7890 | ||
|
|
20ca17fcac | ||
|
|
6cbd1963bf | ||
|
|
2d292000a8 | ||
|
|
6e75f94505 | ||
|
|
e748bcb291 | ||
|
|
409a8c2a77 | ||
|
|
4cc09e49ac | ||
|
|
665b5363e3 | ||
|
|
5a05f40428 | ||
|
|
007b3644be | ||
|
|
93eba6ef68 | ||
|
|
0c7e593370 | ||
|
|
6b7df8fd50 | ||
|
|
783869b45c | ||
|
|
4919b9cb48 | ||
|
|
3f81e0ab82 | ||
|
|
96f2e150a1 | ||
|
|
a38af3a31c | ||
|
|
f29023f11d | ||
|
|
3a93600195 | ||
|
|
974373dc40 | ||
|
|
62de48e4ea | ||
|
|
1031af3dbc | ||
|
|
36aacba237 | ||
|
|
2530c577dc | ||
|
|
54b7920697 | ||
|
|
9ead37845e | ||
|
|
bff9141a4f | ||
|
|
f11b2f6782 | ||
|
|
b5054a7a7f | ||
|
|
bf61ed6310 | ||
|
|
e52756bf9f | ||
|
|
b0350d9412 | ||
|
|
824fcf1736 | ||
|
|
77d4895cf0 | ||
|
|
0440e6916b | ||
|
|
4c63a4046a | ||
|
|
624886bf5a | ||
|
|
545f90ba12 | ||
|
|
f97698858a | ||
|
|
424f99cea4 | ||
|
|
b13feea790 | ||
|
|
883b79f05d | ||
|
|
6dad4de8e3 | ||
|
|
daeff92065 | ||
|
|
56b3799a7a | ||
|
|
3244c57417 | ||
|
|
f1fcaccbaf | ||
|
|
4ef26f99fa | ||
|
|
909dca8f9a | ||
|
|
421dbc28bd | ||
|
|
561a5b2b2e | ||
|
|
2bfdd033eb | ||
|
|
938ae7dc8e | ||
|
|
3f7bd98174 | ||
|
|
dc67e8bbde | ||
|
|
d0cef987fe | ||
|
|
af4131bb4d | ||
|
|
d6e0638cd9 | ||
|
|
030b6f9720 | ||
|
|
d9634030d4 | ||
|
|
79f5502b8e | ||
|
|
179781dfee | ||
|
|
413fd61900 | ||
|
|
9f605cae29 | ||
|
|
c557279607 | ||
|
|
aa315d7c97 | ||
|
|
080b25e30c | ||
|
|
75920e0a09 | ||
|
|
f46ec05a3a | ||
|
|
a87969d85f | ||
|
|
3231ac15c9 | ||
|
|
627c75b6b9 | ||
|
|
823a845752 | ||
|
|
f28ac0c037 | ||
|
|
727e02b816 | ||
|
|
a7c8c08183 | ||
|
|
b872f90365 | ||
|
|
8c3446fb1f | ||
|
|
504222b564 | ||
|
|
108fcd5691 | ||
|
|
e78dc4892f | ||
|
|
5cce1af3d7 | ||
|
|
92156e0520 | ||
|
|
9c13e48b62 | ||
|
|
bfc840d1a7 | ||
|
|
8bc7349635 | ||
|
|
ddbfc5c57a | ||
|
|
b1e97266e3 | ||
|
|
bb8c456a04 | ||
|
|
c5c9387226 | ||
|
|
ee6ff7daaa | ||
|
|
29c93d2b0d | ||
|
|
bb98627d2b | ||
|
|
3060866586 | ||
|
|
eacf121f78 | ||
|
|
c39535fdd0 | ||
|
|
c3311df2a8 | ||
|
|
99af52ac2f | ||
|
|
5a17314b2c | ||
|
|
05d974578d | ||
|
|
0d585a4d98 | ||
|
|
b968b4a9a4 | ||
|
|
07281f050c | ||
|
|
9c3757fb0c | ||
|
|
f5d5e59040 | ||
|
|
70880c066f | ||
|
|
5508c70f3a | ||
|
|
f100982b04 | ||
|
|
c8db2a85c6 | ||
|
|
3b086d130f | ||
|
|
cb8394fb07 | ||
|
|
a401f19ca1 | ||
|
|
444fd41d58 | ||
|
|
e3ccc6d558 | ||
|
|
8ed20e35ca | ||
|
|
bd16b485be | ||
|
|
9783de7464 | ||
|
|
9139fa7ec4 | ||
|
|
ba45539375 | ||
|
|
bb99abdebd | ||
|
|
89878dddf6 | ||
|
|
075ac9e280 | ||
|
|
d43f65366b | ||
|
|
052ab2d9bc | ||
|
|
74f7c93a6d | ||
|
|
36c3cac484 | ||
|
|
2fc014af03 | ||
|
|
8abd010d08 | ||
|
|
c117ef3000 | ||
|
|
543407920d | ||
|
|
3dbdb541ed | ||
|
|
8f24858af8 | ||
|
|
f2667bfcae | ||
|
|
4bbafe13e6 | ||
|
|
f33bac5b59 | ||
|
|
85d2a33620 | ||
|
|
643f4fddf9 | ||
|
|
8ec8118d39 | ||
|
|
dcabf2738a | ||
|
|
a4fbe65259 | ||
|
|
83d76a0781 | ||
|
|
59fbc308b0 | ||
|
|
7266410840 | ||
|
|
e4312ed5cc | ||
|
|
1642a7714f | ||
|
|
c62be68bda | ||
|
|
a1befc78e0 | ||
|
|
fdb8e0e2e5 | ||
|
|
7b803d855f | ||
|
|
3116fde51c | ||
|
|
714c542da9 | ||
|
|
1c7e272ac3 | ||
|
|
31f66c7142 | ||
|
|
5e1d49cc7e | ||
|
|
495a72d167 | ||
|
|
e0eabb8d71 | ||
|
|
4c2c804d0d | ||
|
|
733c375afe | ||
|
|
5dce6e416e | ||
|
|
201bf29429 | ||
|
|
408417bbda | ||
|
|
3d8c8a36dd | ||
|
|
ca1b9d35dd | ||
|
|
2841bfe819 | ||
|
|
1694b10690 |
19
.editorconfig
Normal file
19
.editorconfig
Normal file
@@ -0,0 +1,19 @@
|
||||
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
|
||||
|
||||
[**.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:**
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,3 +1,2 @@
|
||||
node_modules
|
||||
components
|
||||
.DS_Store
|
||||
npm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
31
.travis.yml
31
.travis.yml
@@ -1,4 +1,33 @@
|
||||
sudo: false
|
||||
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "0.10"
|
||||
- "0.8"
|
||||
- "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
|
||||
|
||||
608
CHANGELOG.md
608
CHANGELOG.md
@@ -1,20 +1,542 @@
|
||||
# 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
|
||||
|
||||
- Do not swallow sync errors when using the programmatic API ([#849](https://github.com/bower/bower/issues/849))
|
||||
- Fix resolutions not being saved if `--force-latest` is specified ([#861](https://github.com/bower/bower/issues/861))
|
||||
- Fix `bower register` warning about URL conversion, even if no conversion occurred
|
||||
- Fix `bower update` not correctly catching up branch commits
|
||||
- Add configured directory in `.bowerrc` to the ignores in `bower init` ([#854](https://github.com/bower/bower/issues/854))
|
||||
- Fix some case sensitive issues with data stored in registry cache (e.g.: jquery/jQuery, [#859](https://github.com/bower/bower/issues/859))
|
||||
- Fix bower not checking out a tag if it looks like a semver (e.g.: 1.0, [#872](https://github.com/bower/bower/issues/872))
|
||||
- Fix install & update commands printing the wrong versions in some cases ([#879](https://github.com/bower/bower/issues/879))
|
||||
- Give priority to mime type headers when deciding if a package need to be extracted, except if it is `octet-stream`
|
||||
|
||||
_NOTE_: It's advisable that users run `bower cache clean`.
|
||||
|
||||
|
||||
## 1.2.6 - 2013-09-04
|
||||
|
||||
- Bower now reports download progress even for servers that do not respond with `content-length` header.
|
||||
- Do not translate endpoints when registering a package to a private registry server ([#832](https://github.com/bower/bower/issues/832))
|
||||
- Detect corrupted downloads by comparing downloaded bytes with `content-length` header if possible; this fixes Bower silently failing on unstable networks ([#824](https://github.com/bower/bower/issues/824) and [#792](https://github.com/bower/bower/issues/792))
|
||||
- Fix quotes in fields causing Bower to crash in the `init` command ([#841](https://github.com/bower/bower/issues/841))
|
||||
|
||||
|
||||
## 1.2.5 - 2013-08-28
|
||||
|
||||
- Fix persistent conflict resolutions not working correctly for branches ([#818](https://github.com/bower/bower/issues/818))
|
||||
- Fix Bower failing to run if HOME is not set ([#826](https://github.com/bower/bower/issues/826))
|
||||
- Bower now prints a warning if HOME is not set ([#827](https://github.com/bower/bower/issues/827))
|
||||
- Fix progress message being fired after completion of long running `git clone` commands
|
||||
- Other minor improvements
|
||||
|
||||
|
||||
## 1.2.4 - 2013-08-23
|
||||
|
||||
- Fix ignored nested folders not being correctly handled in some cases ([#814](https://github.com/bower/bower/issues/814))
|
||||
|
||||
|
||||
## 1.2.3 - 2013-08-22
|
||||
|
||||
- Fix read of environment variables that map to config properties with dashes and also support nested ones ([#8@bower-config](https://github.com/bower/config/issues/8))
|
||||
- Fix `bower info <package> <property>` printing the available versions (it shouldn't!)
|
||||
- Fix interactive shell not being correctly detected in node `0.8.x` ([#802](https://github.com/bower/bower/issues/802))
|
||||
- Fix `extraneous` flag in the `list` command being incorrectly set for saved dev dependencies in some cases
|
||||
- Fix linked dependencies not being read in `bower list` on Windows ([#813](https://github.com/bower/bower/issues/813))
|
||||
- Fix update notice not working with `--json`
|
||||
|
||||
|
||||
## 1.2.2 - 2013-08-20
|
||||
|
||||
- Standardize prompt behaviour with and without `--json`
|
||||
- Improve detection of `git` servers that do not support shallow clones ([#805](https://github.com/bower/bower/issues/805))
|
||||
- Ignore remote tags (tags ending with ^{})
|
||||
- Fix bower not saving the correct endpoint in some edge cases ([#806](https://github.com/bower/bower/issues/806))
|
||||
|
||||
|
||||
## 1.2.1 - 2013-08-19
|
||||
|
||||
- Fix bower throwing on non-semver targets ([#800](https://github.com/bower/bower/issues/800))
|
||||
|
||||
|
||||
## 1.2.0 - 2013-08-19
|
||||
|
||||
- __Bower no longer installs a pre-release version by default, that is, if no version/range is specified__ ([#782](https://github.com/bower/bower/issues/782))
|
||||
- __`bower info <package>` will now show the latest `<package>` information along with the available versions__ ([#759](https://github.com/bower/bower/issues/759))
|
||||
- __`bower link` no longer requires an elevated user on Windows in most cases__ ([#472](https://github.com/bower/bower/issues/472))
|
||||
- __Init command now prompts for the whole `bower.json` spec properties, filling in default values for `author` and `homepage` based on `git` settings__ ([#693](https://github.com/bower/bower/issues/693))
|
||||
- Changes to endpoint sources in `bower.json` are now catched up by `bower install` and `bower update` ([#788](https://github.com/bower/bower/issues/788))
|
||||
- Allow semver ranges in `bower cache clean`, e.g. `bower cache clean jquery#<2.0.0` ([#688](https://github.com/bower/bower/issues/688))
|
||||
- Normalize `bower list --paths` on Windows ([#279](https://github.com/bower/bower/issues/279))
|
||||
- Multiple mains are now correctly outputted as an array in `bower list --paths` ([#784](https://github.com/bower/bower/issues/784))
|
||||
- Add `--relative` option to `bower list --json` so that Bower outputs relative paths instead of absolute ([#714](https://github.com/bower/bower/issues/714))
|
||||
- `bower list --paths` now outputs relative paths by default; can be turned off with `--no-relative` ([#785](https://github.com/bower/bower/issues/785))
|
||||
- Bower no longer fails if `symlinks` to files are present in the `bower_components` folder ([#783](https://github.com/bower/bower/issues/783) and [#791](https://github.com/bower/bower/issues/791))
|
||||
- Disable git templates/hooks when running `git` ([#761](https://github.com/bower/bower/issues/761))
|
||||
- Add instructions to setup git workaround for proxies when execution of `git` fails ([#250](https://github.com/bower/bower/issues/250))
|
||||
- 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 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.
|
||||
|
||||
|
||||
## 1.1.2 - 2013-08-10
|
||||
|
||||
- Detect and fallback if the git server does not support `--depth=1` when cloning ([#747](https://github.com/bower/bower/issues/747))
|
||||
|
||||
|
||||
## 1.1.1 - 2013-08-08
|
||||
|
||||
- Fix silent fail when spawning child processes in some edge cases ([#722](https://github.com/bower/bower/issues/722))
|
||||
- Fix `home` command not guessing the correct URL for `GitHub` ssh endpoints (requires `bower cache-clean`)
|
||||
- Fix bower not correctly filtering packages with symlinks in some cases ([#730](https://github.com/bower/bower/issues/730))
|
||||
- Fix multi-user usage on bower when it falls back to create a `/tmp/bower` folder ([#743](https://github.com/bower/bower/issues/743))
|
||||
- Bower now sends a fake user agent when behind a proxy by default, so that corporate proxies do not block requests ([#698](https://github.com/bower/bower/issues/698))
|
||||
- Bower now translates GitHub public `git://` URLs to `git@` when behind a proxy ([#731](https://github.com/bower/bower/issues/731))
|
||||
- Minor improvements to the CLI output on small terminals
|
||||
- Minor programmatic usage improvements
|
||||
- Minor help usage fixes
|
||||
|
||||
|
||||
## 1.1.0 - 2013-08-03
|
||||
|
||||
- __Fix `--save` and `--save-dev` not working correctly for the uninstall command in some situations__
|
||||
- __Attempting to register a package that declares `"private": true` in `bower.json` will result in an error ([#162](https://github.com/bower/bower/issues/162))__
|
||||
- __Fix retry strategy on download error that was causing some strange I/O errors__ ([#699](https://github.com/bower/bower/issues/699) and [#704](https://github.com/bower/bower/issues/704))
|
||||
- __`bower prune` now clears pruned packages dependencies if they are also extraneous__ ([#708](https://github.com/bower/bower/issues/708))
|
||||
- __`bower uninstall` now uninstalls uninstalled packages dependencies if they are not shared ([#609](https://github.com/bower/bower/issues/609))__
|
||||
- Fix `bower list` display the `incompatible` label even if they are compatible ([#710](https://github.com/bower/bower/issues/710))
|
||||
- Fix `bower cache clean` not working correctly when `package#non-semver` is specified
|
||||
- Implement no operation `completion` command to prevent weird output when hitting tab ([#691](https://github.com/bower/bower/issues/691))
|
||||
- Fix `bower info --help` ([#703](https://github.com/bower/bower/issues/703))
|
||||
- Add colorized output for `bower info <package>#<version>` ([#571](https://github.com/bower/bower/issues/571))
|
||||
- Added `bower ls` as an alias to `bower list`
|
||||
- Fix regression: do not create a json file when saving is required, warn instead
|
||||
- Ignore linked packages when reading dependencies in `bower init` ([#709](https://github.com/bower/bower/issues/709))
|
||||
- `bower list` is now able to (partially) reconstruct the dependency tree, even for dependencies not declared in `bower.json` ([#622](https://github.com/bower/bower/issues/622))
|
||||
|
||||
|
||||
## 1.0.3 - 2013-07-30
|
||||
|
||||
- Fix some changes not being saved to bower.json ([#685](https://github.com/bower/bower/issues/685))
|
||||
- Fix `bower info <package> <property>` not showing information related to property of the latest version of that package ([#684](https://github.com/bower/bower/issues/684))
|
||||
|
||||
|
||||
## 1.0.2 - 2013-07-30
|
||||
|
||||
- Fix severe bug originated from a wrong merge that caused conflict messages to not show up correctly
|
||||
|
||||
|
||||
## 1.0.1 - 2013-07-29
|
||||
|
||||
- Fix `bower register` going ahead even if the answer was `no` ([#644](https://github.com/bower/bower/issues/644))
|
||||
- Fix local endpoints with backslashes on Windows ([#2@endpoint-parser](https://github.com/bower/endpoint-parser/pull/2))
|
||||
- Fix usage of multiple registries in the registry-client ([#3@registry-client](https://github.com/bower/registry-client/pull/3) and [#2@registry-client](https://github.com/bower/registry-client/pull/2))
|
||||
- File extensions now have more priority than mime types when deciding if extraction is necessary ([#657](https://github.com/bower/bower/pull/657))
|
||||
- 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 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))
|
||||
- Add additional system information such as node version, bower version, OS version when an error occurs ([#670](https://github.com/bower/bower/issues/670))
|
||||
- `bower install` no longer overwrites `linked` packages unless it needs to ([#593](https://github.com/bower/bower/issues/593)).
|
||||
- All endpoint parts are now trimmed so that the Manager can better detect similar endpoints ([#3@endpoint-parser](https://github.com/bower/endpoint-parser/pull/3))
|
||||
- `bower register` now shows the server that will be used ([#647](https://github.com/bower/endpoint-parser/pull/647))
|
||||
|
||||
|
||||
## 1.0.0 - 2013-07-23
|
||||
|
||||
Total rewrite of bower.
|
||||
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
|
||||
|
||||
|
||||
- Clear architecture and separation of concerns
|
||||
- Much much faster
|
||||
- `--json` output for all commands
|
||||
- `--offline` usage for all commands, except `register`
|
||||
- Proper `install` and `update` commands, similar to `npm` in behaviour
|
||||
- Named endpoints when installing, e.g. `bower install backbone-amd=backbone#~1.0.0`
|
||||
- New interactive conflict resolution strategy
|
||||
- Prevent human errors when using `register`
|
||||
- New `home` command, similar to `npm`
|
||||
- New `cache list` command
|
||||
- New `prune` command
|
||||
- Many many general bug fixes
|
||||
|
||||
Non-backwards compatible changes:
|
||||
|
||||
- The value of the `json` property from .bowerrc is no longer used
|
||||
- `--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`.
|
||||
Additionally you may remove the `~/.bower` folder manually since it's no longer used.
|
||||
On Windows the folder is located in `AppData/bower`.
|
||||
|
||||
|
||||
## 0.10.0 - 2013-07-02
|
||||
|
||||
- __Allow specific commits to be targeted__ ([#275](https://github.com/bower/bower/issues/275))
|
||||
- __Change bower default folder from `components` to `bower_components`__ ([#434](https://github.com/bower/bower/issues/434))
|
||||
- __Support semver pre-releases and builds__ ([#188](https://github.com/bower/bower/issues/188))
|
||||
- Use `Content-Type` and `Content-Disposition` to guess file types, such as zip files ([#454](https://github.com/bower/bower/pull/454))
|
||||
- Fix bower failing silently when using an invalid version value in the bower.json file ([#439](https://github.com/bower/bower/issues/439))
|
||||
- Fix bower slowness when downloading after redirects ([#437](https://github.com/bower/bower/issues/437))
|
||||
- Detect and error out with a friendly message when `git` is not installed ([#362](https://github.com/bower/bower/issues/362))
|
||||
- Add `--quiet` and `--silent` CLI options ([#343](https://github.com/bower/bower/issues/343))
|
||||
- Minor programmatic usage improvements
|
||||
|
||||
_NOTE_: The `components` folder will still be used if already created, making it easier for users to upgrade.
|
||||
|
||||
## 0.9.2 - 2013-04-28
|
||||
- Better fix for [#429](https://github.com/bower/bower/issues/429)
|
||||
|
||||
## 0.9.1 - 2013-04-27
|
||||
- Update `package.json`, docs and other stuff to point to the new `Bower` organisation on GitHub
|
||||
- Fix root label of `bower list` being an absolute path; now uses the package name
|
||||
- Fix `bower update <pkg>` updating all packages; now throws when updating an unknown package
|
||||
- Fix `list` command when package use different names than the `guessed` one ([#429](https://github.com/bower/bower/issues/429))
|
||||
|
||||
## 0.9.0 - 2013-04-25
|
||||
- __Change from `component.json` to `bower.json`__ ([#39](https://github.com/twitter/bower/issues/39))
|
||||
- __Change from `component.json` to `bower.json`__ ([#39](https://github.com/bower/bower/issues/39))
|
||||
- __Compatibility with `node 0.10.x`, including fix hangs/errors when extracting `zip` files__
|
||||
- Fix `--save` and `--save-dev` not working with URLs that get redirected ([#417](https://github.com/twitter/bower/issues/417))
|
||||
- Fix `init` command targeting `~commit` instead of `*`. ([#385](https://github.com/twitter/bower/issues/385))
|
||||
- Remove temporary directories before exiting ([#345](https://github.com/twitter/bower/issues/345))
|
||||
- Integrate `update-notifier` ([#202](https://github.com/twitter/bower/issues/202))
|
||||
- Use `json` name when a package name was inferred ([#192](https://github.com/twitter/bower/issues/192))
|
||||
- Fix `bin/bower` not exiting with an exit code greater than zero when an error occurs ([#187](https://github.com/twitter/bower/issues/187))
|
||||
- Fix `--save` and `--save-dev` not working with URLs that get redirected ([#417](https://github.com/bower/bower/issues/417))
|
||||
- Fix `init` command targeting `~commit` instead of `*`. ([#385](https://github.com/bower/bower/issues/385))
|
||||
- Remove temporary directories before exiting ([#345](https://github.com/bower/bower/issues/345))
|
||||
- Integrate `update-notifier` ([#202](https://github.com/bower/bower/issues/202))
|
||||
- Use `json` name when a package name was inferred ([#192](https://github.com/bower/bower/issues/192))
|
||||
- Fix `bin/bower` not exiting with an exit code greater than zero when an error occurs ([#187](https://github.com/bower/bower/issues/187))
|
||||
- Fix `--save` and `--save-dev` saving resolved shorthands instead of the actual shorthands
|
||||
- Fix bower using user defined git templates ([#324](https://github.com/twitter/bower/issues/324))
|
||||
- Add command abbreviations ([#262](https://github.com/twitter/bower/issues/262))
|
||||
- Fix bower using user defined git templates ([#324](https://github.com/bower/bower/issues/324))
|
||||
- Add command abbreviations ([#262](https://github.com/bower/bower/issues/262))
|
||||
- Improve help messages and fix abuse of colors in output
|
||||
- Wait for every package to resolve before printing error messages ([#290](https://github.com/twitter/bower/issues/290))
|
||||
- Add `shorthand_resolver` to allow shorthands to be resolved to repositories other than GitHub ([#278](https://github.com/twitter/bower/issues/278))
|
||||
- Wait for every package to resolve before printing error messages ([#290](https://github.com/bower/bower/issues/290))
|
||||
- Add `shorthand_resolver` to allow shorthands to be resolved to repositories other than GitHub ([#278](https://github.com/bower/bower/issues/278))
|
||||
|
||||
## 0.8.6 - 2013-04-03
|
||||
- Emergency fix for `node 0.8.x` users to make `zip` extraction work again
|
||||
@@ -25,57 +547,57 @@
|
||||
|
||||
## 0.8.4 - 2013-03-01
|
||||
- Fix some more duplicate async callbacks being called twice
|
||||
- Preserve new lines when saving `component.json` ([#285](https://github.com/twitter/bower/issues/285))
|
||||
- Preserve new lines when saving `component.json` ([#285](https://github.com/bower/bower/issues/285))
|
||||
|
||||
## 0.8.3 - 2013-02-27
|
||||
- Fix error when using the `update` command ([#282](https://github.com/twitter/bower/issues/282))
|
||||
- Fix error when using the `update` command ([#282](https://github.com/bower/bower/issues/282))
|
||||
|
||||
## 0.8.2 - 2013-02-26
|
||||
- Fix some errors in windows while removing directories, had to downgrade `rimraf` ([#274](https://github.com/twitter/bower/issues/274))
|
||||
- Prevent duplicate package names in error summaries ([#277](https://github.com/twitter/bower/issues/277))
|
||||
- Fix some errors in windows while removing directories, had to downgrade `rimraf` ([#274](https://github.com/bower/bower/issues/274))
|
||||
- Prevent duplicate package names in error summaries ([#277](https://github.com/bower/bower/issues/277))
|
||||
|
||||
## 0.8.1 - 2013-02-25
|
||||
- Fix some async callbacks being fired twice ([#274](https://github.com/twitter/bower/issues/274))
|
||||
- Fix some async callbacks being fired twice ([#274](https://github.com/bower/bower/issues/274))
|
||||
|
||||
## 0.8.0 - 2013-02-24
|
||||
- __Add init command similar to `npm init`__ ([#219](https://github.com/twitter/bower/issues/219))
|
||||
- __Add devDependencies__ support ([#251](https://github.com/twitter/bower/issues/251))
|
||||
- __Add `--save-dev` flag to install/uninstall commands__ ([#258](https://github.com/twitter/bower/issues/258))
|
||||
- `cache-clean` command now clears links pointing to nonexistent folders ([#182](https://github.com/twitter/bower/issues/182))
|
||||
- Fix issue when downloading assets behind a proxy using `https` ([#230](https://github.com/twitter/bower/issues/230))
|
||||
- Fix --save saving unresolved components ([#240](https://github.com/twitter/bower/issues/240))
|
||||
- Fix issue when extracting some zip files ([#225](https://github.com/twitter/bower/issues/225))
|
||||
- __Add init command similar to `npm init`__ ([#219](https://github.com/bower/bower/issues/219))
|
||||
- __Add devDependencies__ support ([#251](https://github.com/bower/bower/issues/251))
|
||||
- __Add `--save-dev` flag to install/uninstall commands__ ([#258](https://github.com/bower/bower/issues/258))
|
||||
- `cache-clean` command now clears links pointing to nonexistent folders ([#182](https://github.com/bower/bower/issues/182))
|
||||
- Fix issue when downloading assets behind a proxy using `https` ([#230](https://github.com/bower/bower/issues/230))
|
||||
- Fix --save saving unresolved components ([#240](https://github.com/bower/bower/issues/240))
|
||||
- Fix issue when extracting some zip files ([#225](https://github.com/bower/bower/issues/225))
|
||||
- Fix automatic conflict resolver not selecting the correct version
|
||||
- Add `--sources` option to the `list` command ([#235](https://github.com/twitter/bower/issues/235))
|
||||
- Automatically clear cache when git commands fail with code 128 ([#216](https://github.com/twitter/bower/issues/216))
|
||||
- Fix `bower` not working correctly behind a proxy in some commands ([#208](https://github.com/twitter/bower/issues/208))
|
||||
- Add `--sources` option to the `list` command ([#235](https://github.com/bower/bower/issues/235))
|
||||
- Automatically clear cache when git commands fail with code 128 ([#216](https://github.com/bower/bower/issues/216))
|
||||
- Fix `bower` not working correctly behind a proxy in some commands ([#208](https://github.com/bower/bower/issues/208))
|
||||
|
||||
## 0.7.1 - 2013-02-20
|
||||
- Remove postinstall script from `bower` installation
|
||||
|
||||
## 0.7.0 - 2013-02-01
|
||||
- __Ability to resolve conflicts__ ([#214](https://github.com/twitter/bower/issues/214))
|
||||
- __Ability to resolve conflicts__ ([#214](https://github.com/bower/bower/issues/214))
|
||||
- __Ability to search and publish to different endpoints by specifying them in the `.bowerrc` file__
|
||||
- __Experimental autocompletion__
|
||||
- __Ability to exclude (ignore) files__
|
||||
- Fix minor issues in the cache clean command
|
||||
- Better error message for invalid semver tags ([#185](https://github.com/twitter/bower/issues/185))
|
||||
- Better error message for invalid semver tags ([#185](https://github.com/bower/bower/issues/185))
|
||||
- Only show discover message in the list command only if there are packages
|
||||
- Fix mismatch issue due to reading cached component.json files ([#214](https://github.com/twitter/bower/issues/214))
|
||||
- Better error messages when reading invalid .bowerrc files ([#220](https://github.com/twitter/bower/issues/220))
|
||||
- Fix update command when used in packages pointing to assets ([#197](https://github.com/twitter/bower/issues/197))
|
||||
- Bower now obeys packages's `.bowerrc` if they define a different `json` ([#205](https://github.com/twitter/bower/issues/205))
|
||||
- Fix mismatch issue due to reading cached component.json files ([#214](https://github.com/bower/bower/issues/214))
|
||||
- Better error messages when reading invalid .bowerrc files ([#220](https://github.com/bower/bower/issues/220))
|
||||
- Fix update command when used in packages pointing to assets ([#197](https://github.com/bower/bower/issues/197))
|
||||
- Bower now obeys packages's `.bowerrc` if they define a different `json` ([#205](https://github.com/bower/bower/issues/205))
|
||||
|
||||
## 0.6.8 - 2012-12-14
|
||||
- Improve list command
|
||||
- Does not fetch versions if not necessary (for --map and --paths options)
|
||||
- Add --offline option to prevent versions from being fetched
|
||||
- Fix uninstall command not firing the `end` event
|
||||
- Fix error when executing an unknown command ([#179](https://github.com/twitter/bower/issues/179))
|
||||
- Fix error when executing an unknown command ([#179](https://github.com/bower/bower/issues/179))
|
||||
- Fix help for the ls command (alias of list)
|
||||
|
||||
## 0.6.7 - 2012-12-10
|
||||
- Fix uninstall removing all unsaved dependencies ([#178](https://github.com/twitter/bower/issues/178))
|
||||
- Fix uninstall removing all unsaved dependencies ([#178](https://github.com/bower/bower/issues/178))
|
||||
- Fix uninstall --force flag in some cases
|
||||
- Add --silent option to the register option, to avoid questioning
|
||||
- Fix possible issues with options in some commands
|
||||
@@ -90,18 +612,18 @@
|
||||
- Fix bower not fetching latest commits correctly in some cases
|
||||
|
||||
## 0.6.4 - 2012-11-29
|
||||
- Fix permission on downloaded files ([#160](https://github.com/twitter/bower/issues/160))
|
||||
- Fix permission on downloaded files ([#160](https://github.com/bower/bower/issues/160))
|
||||
|
||||
## 0.6.3 - 2012-11-24
|
||||
- Fix version not being correctly set for local packages ([#155](https://github.com/twitter/bower/issues/155))
|
||||
- Fix version not being correctly set for local packages ([#155](https://github.com/bower/bower/issues/155))
|
||||
|
||||
## 0.6.2 - 2012-11-23
|
||||
- Fix uninstall --save when there is no component.json
|
||||
|
||||
## 0.6.1 - 2012-11-22
|
||||
- Fix uninstall when the project component.json has no deps saved ([#153](https://github.com/twitter/bower/issues/153))
|
||||
- Fix uncaught errors when using file writter (they are now caught and reported)
|
||||
- Fix temporary directories not being deleted when an exception occurs ([#153](https://github.com/twitter/bower/issues/140))
|
||||
- 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 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
|
||||
- __Add link command__ (similar to npm)
|
||||
@@ -116,13 +638,13 @@
|
||||
|
||||
## 0.5.0 - 2012-11-19
|
||||
- __Remove package.json support__
|
||||
- __Support for local path repositories__ ([#132](https://github.com/twitter/bower/issues/132))
|
||||
- __Support for local path repositories__ ([#132](https://github.com/bower/bower/issues/132))
|
||||
- `install --save` now saves the correct tag (e.g: ~0.0.1) instead of 'latest'
|
||||
- `install --save` now saves packages pointing directly to assets correctly
|
||||
- Bower automatically creates a component.json when install with `--save` is used
|
||||
- Fix issues with list command ([#142](https://github.com/twitter/bower/issues/142))
|
||||
- Fix local paths not being saved when installing with --save ([#114](https://github.com/twitter/bower/issues/114))
|
||||
- `uninstall` now uninstalls nested dependencies if they are not shared ([#83](https://github.com/twitter/bower/issues/83))
|
||||
- Fix issues with list command ([#142](https://github.com/bower/bower/issues/142))
|
||||
- Fix local paths not being saved when installing with --save ([#114](https://github.com/bower/bower/issues/114))
|
||||
- `uninstall` now uninstalls nested dependencies if they are not shared ([#83](https://github.com/bower/bower/issues/83))
|
||||
- `uninstall` now warns when a dependency conflict occurs and aborts.
|
||||
It will only proceed if the `--force` flag is passed
|
||||
- Bower now detects mismatches between the version specified in the component.json and the tag, informing the user
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -103,7 +74,7 @@ included in the project:
|
||||
# Navigate to the newly cloned directory
|
||||
cd bower
|
||||
# Assign the original repo to a remote called "upstream"
|
||||
git remote add upstream https://github.com/twitter/bower
|
||||
git remote add upstream https://github.com/bower/bower
|
||||
```
|
||||
|
||||
2. If you cloned a while ago, get the latest changes from upstream:
|
||||
@@ -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.
|
||||
|
||||
|
||||
7
LICENSE
7
LICENSE
@@ -1,7 +0,0 @@
|
||||
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.
|
||||
7
Makefile
7
Makefile
@@ -1,7 +0,0 @@
|
||||
test: node_modules
|
||||
./node_modules/.bin/mocha -R spec -t 10000
|
||||
|
||||
node_modules: package.json
|
||||
npm install
|
||||
|
||||
.PHONY: test
|
||||
363
README.md
363
README.md
@@ -1,355 +1,126 @@
|
||||
# BOWER [](http://travis-ci.org/twitter/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.).
|
||||
|
||||
**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
|
||||
```
|
||||
npm install -g 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.
|
||||
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
|
||||
|
||||
```bash
|
||||
# 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 Git-tagged version from a remote package
|
||||
bower install <package>#<version>
|
||||
# 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
|
||||
```
|
||||
|
||||
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 Git 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.gz` files. It's contents will be
|
||||
extracted.
|
||||
|
||||
‡ These types of `<package>` make Git tags available. You can specify a
|
||||
[semver](http://semver.org/) tag to fetch a specific release, and lock the
|
||||
package to that version.
|
||||
|
||||
All package contents are installed in the `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="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 **must** be available at a Git endpoint
|
||||
(e.g., GitHub), and it should use [semver](http://semver.org/) Git tags. Then
|
||||
run:
|
||||
|
||||
```
|
||||
bower register <my-package-name> <git-endpoint>
|
||||
```
|
||||
|
||||
The Bower registry does not have authentication or user management. 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/twitter/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
|
||||
|
||||
Global configuration is handled by creating a `.bowerrc` in your home directory
|
||||
(i.e., `~/.bowerrc`). Local configuration is handled by creating a `.bowerrc`
|
||||
in your project's directory, allowing you to version a project-specific Bower
|
||||
configuration with the rest of your code base.
|
||||
Bower is a user command; there is no need to execute it with superuser permissions.
|
||||
|
||||
Bower will combine the local and global configurations (with local settings
|
||||
taking precedence).
|
||||
|
||||
The `.bowerrc` defines several options:
|
||||
|
||||
* `directory`: Set the default directory to install packaged components into.
|
||||
* `endpoint`: Set a custom registry endpoint.
|
||||
* `json`: Set the default JSON file for Bower to use when resolving dependencies.
|
||||
* `searchpath`: An array of additional URLs pointing to read-only Bower registries.
|
||||
* `shorthand_resolver`: Define a custom template for shorthand package names.
|
||||
|
||||
```json
|
||||
{
|
||||
"directory": "bower_components",
|
||||
"endpoint": "https://bower.mycompany.com",
|
||||
"json": "bower.json",
|
||||
"searchpath": [
|
||||
"https://bower.herokuapp.com"
|
||||
],
|
||||
"shorthand_resolver": "git://example.com/{{{ organization }}}/{{{ package }}}.git"
|
||||
}
|
||||
```
|
||||
|
||||
The `searchpath` array is useful if your organization wishes to maintain a
|
||||
private registry of packages while also taking advantage of public Bower
|
||||
registries. If a package is not found at your private endpoint, Bower will
|
||||
consult the registries specified in the `searchpath` array.
|
||||
|
||||
The `shorthand_resolver` key provides support for defining a custom template
|
||||
which Bower uses when constructing a URL for a given shorthand. For example, if
|
||||
a shorthand of `twitter/flight` or `twitter/flight#v1.0.0` is specified in the
|
||||
package manifest, the following data can be referenced from within the
|
||||
`.bowerrc` as part of the `shorthand_resolver` template:
|
||||
|
||||
* `endpoint`: `twitter/flight`
|
||||
* `organization`: `twitter`
|
||||
* `package`: `flight`
|
||||
|
||||
**N.B.** To run your own Bower Endpoint for custom packages that are behind a
|
||||
firewall, you can use a simple implementation of the [Bower
|
||||
Server](https://github.com/twitter/bower-server).
|
||||
|
||||
|
||||
## Defining a package
|
||||
|
||||
You must create a JSON file -- `bower.json` by default -- 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.
|
||||
|
||||
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.
|
||||
|
||||
```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 `--map` option to Bower's `list` command, it will generate JSON
|
||||
with dependency objects. Alternatively, you can pass the `--paths` option to
|
||||
the `list` command to get a simple path-to-name mapping:
|
||||
|
||||
```json
|
||||
{
|
||||
"backbone": "components/backbone/index.js",
|
||||
"jquery": "components/jquery/index.js",
|
||||
"underscore": "components/underscore/index.js"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## 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(paths, options)
|
||||
.on('end', function (data) {
|
||||
data && console.log(data);
|
||||
});
|
||||
|
||||
bower.commands
|
||||
.search('jquery', {})
|
||||
.on('packages', function(packages) {
|
||||
// `packages` is a list of packages returned by searching for 'jquery'
|
||||
});
|
||||
```
|
||||
|
||||
Commands emit four types of events: `data`, `end`, `result`, and `error`.
|
||||
|
||||
`error` will only be emitted if something goes wrong. Not all commands emit all
|
||||
events; for a detailed look, check out the code in `lib/commands`.
|
||||
|
||||
`data` is typically a colorized string, ready to show to an end user. `search`
|
||||
and `lookup` emit `packages` and `package`, respectively. Those events contain
|
||||
a JSON representation of the result of the command.
|
||||
|
||||
For a better of idea how this works, you may want to check out [our bin
|
||||
file](https://github.com/twitter/bower/blob/master/bin/bower).
|
||||
|
||||
For the install command, there is an additional `package` event that is emitted
|
||||
for each installed/uninstalled package.
|
||||
|
||||
|
||||
## Completion (experimental)
|
||||
|
||||
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/@carsonmcdonald)
|
||||
* [@chriseppstein](https://github.com/chriseppstein)
|
||||
* [@danwrong](https://github.com/danwrong)
|
||||
* [@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)
|
||||
* [@mklabs](https://github.com/mklabs)
|
||||
* [@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)
|
||||
* [@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
|
||||
66
bin/bower
66
bin/bower
@@ -1,66 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var semver = require('semver');
|
||||
var nopt = require('nopt');
|
||||
var path = require('path');
|
||||
var pkg = require(path.join(__dirname, '..', 'package.json'));
|
||||
var updateNotifier = require('update-notifier');
|
||||
|
||||
var template = require('../lib/util/template');
|
||||
var bower = require('../lib');
|
||||
|
||||
var command;
|
||||
var options;
|
||||
var shorthand;
|
||||
var input = process.argv;
|
||||
var nodeVer = process.version;
|
||||
var reqVer = pkg.engines.node;
|
||||
var errors = [];
|
||||
var notifier = updateNotifier({ packageName: pkg.name, packageVersion: pkg.version });
|
||||
|
||||
if (notifier.update) {
|
||||
process.stderr.write(template('update-notice', notifier.update, true));
|
||||
}
|
||||
|
||||
process.title = 'bower';
|
||||
|
||||
if (reqVer && !semver.satisfies(nodeVer, reqVer)) {
|
||||
throw new Error('Required: node ' + reqVer);
|
||||
}
|
||||
|
||||
shorthand = { 'v': ['--version'] };
|
||||
options = { version: Boolean };
|
||||
options = nopt(options, shorthand, process.argv);
|
||||
|
||||
bower.version = pkg.version;
|
||||
|
||||
if (options.version) return console.log(bower.version);
|
||||
|
||||
command = options.argv.remain && options.argv.remain.shift();
|
||||
command = bower.abbreviations[command];
|
||||
|
||||
if (command) bower.command = command;
|
||||
|
||||
|
||||
// Temporarory fix for #22 #320 #187
|
||||
var errStatusHandler = function () {
|
||||
process.removeListener('exit', errStatusHandler);
|
||||
process.exit(errors.length ? 1 : 0);
|
||||
};
|
||||
process.on('exit', errStatusHandler);
|
||||
|
||||
bower.commands[bower.command || 'help'].line(input)
|
||||
.on('data', function (data) {
|
||||
if (data) process.stdout.write(data);
|
||||
})
|
||||
.on('end', function (data) {
|
||||
if (data) process.stdout.write(data);
|
||||
})
|
||||
.on('warn', function (warning) {
|
||||
process.stderr.write(template('warn', { message: warning }, true));
|
||||
})
|
||||
.on('error', function (err) {
|
||||
if (options.verbose) throw err;
|
||||
process.stdout.write(template('error', { message: err.message }, true));
|
||||
errors.push(err);
|
||||
});
|
||||
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"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: CacheClean API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var async = require('async');
|
||||
var nopt = require('nopt');
|
||||
var rimraf = require('rimraf');
|
||||
var path = require('path');
|
||||
var glob = require('glob');
|
||||
var fs = require('fs');
|
||||
var _ = require('lodash');
|
||||
|
||||
var help = require('./help');
|
||||
var config = require('../core/config');
|
||||
var template = require('../util/template');
|
||||
var fileExists = require('../util/file-exists');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'] };
|
||||
|
||||
var processCachedPackage = function (emitter, pkg, next) {
|
||||
removeCachedPackage(pkg, function (err, exists) {
|
||||
if (err) {
|
||||
emitter.emit('error', err);
|
||||
return next();
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
template('action', { name: 'cache cleared', shizzle: pkg })
|
||||
.on('data', emitter.emit.bind(emitter, 'data'));
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
};
|
||||
|
||||
var removeCachedPackage = function (pkg, next) {
|
||||
var folder = path.join(config.cache, pkg);
|
||||
|
||||
fileExists(folder, function (exists) {
|
||||
if (!exists) return next(null, false);
|
||||
rimraf(folder, function (err) {
|
||||
if (err) return next(err);
|
||||
next(null, true);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var processLinkedPackage = function (emitter, pkg, next) {
|
||||
checkAndRemoveLinkToPackage(pkg, function (err, removed) {
|
||||
if (err) {
|
||||
emitter.emit('error', err);
|
||||
return next();
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
template('action', { name: 'link cleared', shizzle: pkg })
|
||||
.on('data', emitter.emit.bind(emitter, 'data'));
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
};
|
||||
|
||||
var checkAndRemoveLinkToPackage = function (pkg, next) {
|
||||
var folder = path.join(config.links, pkg);
|
||||
|
||||
fs.readlink(folder, function (err, linkString) {
|
||||
if (err && err.code === 'ENOENT') return next();
|
||||
|
||||
fileExists(linkString, function (exists) {
|
||||
if (!exists) {
|
||||
return rimraf(folder, function (err) {
|
||||
if (err) return next(err);
|
||||
next(null, true);
|
||||
});
|
||||
}
|
||||
|
||||
next(null, false);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = function (pkgs) {
|
||||
var emitter = new Emitter;
|
||||
|
||||
async.parallel({
|
||||
cache: function (next) {
|
||||
if (!pkgs || !pkgs.length) {
|
||||
glob('./*', { cwd: config.cache }, function (err, dirs) {
|
||||
if (err) {
|
||||
emitter.emit('error', err);
|
||||
return next();
|
||||
}
|
||||
|
||||
var pkgs = dirs.map(function (dir) { return dir.replace(/^\.\//, ''); });
|
||||
async.forEach(pkgs, processCachedPackage.bind(this, emitter), next);
|
||||
});
|
||||
} else {
|
||||
pkgs = _.uniq(pkgs);
|
||||
async.forEach(pkgs, processCachedPackage.bind(this, emitter), next);
|
||||
}
|
||||
},
|
||||
links: function (next) {
|
||||
if (!pkgs || !pkgs.length) {
|
||||
glob('./*', { cwd: config.links }, function (err, dirs) {
|
||||
if (err) {
|
||||
emitter.emit('error', err);
|
||||
return next();
|
||||
}
|
||||
|
||||
var pkgs = dirs.map(function (dir) { return dir.replace(/^\.\//, ''); });
|
||||
async.forEach(pkgs, processLinkedPackage.bind(this, emitter), next);
|
||||
});
|
||||
} else {
|
||||
pkgs = _.uniq(pkgs);
|
||||
async.forEach(pkgs, processLinkedPackage.bind(this, emitter), next);
|
||||
}
|
||||
},
|
||||
completion: function (next) {
|
||||
// Do not run completion cache if packages where passed
|
||||
if (pkgs && pkgs.length) return next();
|
||||
|
||||
rimraf(config.completion, function (err) {
|
||||
if (err) {
|
||||
emitter.emit('error', err);
|
||||
return next();
|
||||
}
|
||||
|
||||
template('action', { name: 'completion cleared', shizzle: 'completion cache' })
|
||||
.on('data', emitter.emit.bind(emitter, 'data'));
|
||||
|
||||
next();
|
||||
});
|
||||
}
|
||||
}, emitter.emit.bind(emitter, 'end'));
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var pkgs = options.argv.remain.slice(1);
|
||||
|
||||
if (options.help) return help('cache-clean');
|
||||
return module.exports(pkgs);
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
glob('./*', { cwd: config.cache }, function (err, dirs) {
|
||||
if (err) return cb(err);
|
||||
dirs = dirs.map(function (dir) {
|
||||
return dir.replace(/^\.\//, '');
|
||||
});
|
||||
cb(null, dirs);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,112 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Completion API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var path = require('path');
|
||||
var nopt = require('nopt');
|
||||
var mkdirp = require('mkdirp');
|
||||
|
||||
var template = require('../util/template');
|
||||
var complete = require('../util/completion');
|
||||
var config = require('../core/config');
|
||||
var help = require('./help');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'] };
|
||||
|
||||
module.exports = function (argv, env) {
|
||||
env = env || process.env;
|
||||
|
||||
var emitter = new Emitter;
|
||||
var commands = require('../commands');
|
||||
|
||||
// top level flags
|
||||
var flags = ['--no-color', '--help', '--version'];
|
||||
|
||||
var done = function done() {
|
||||
process.nextTick(function () {
|
||||
emitter.emit('end');
|
||||
});
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
// if the COMP_* isn't in the env, then just dump the script.
|
||||
if (!env.COMP_CWORD) {
|
||||
template('completion').on('data', emitter.emit.bind(emitter, 'end'));
|
||||
return emitter;
|
||||
}
|
||||
|
||||
// parse environment and arguments, returns a hash of completion config.
|
||||
var opts = complete(argv, env);
|
||||
|
||||
// if only one word, complete the list of command or top level flags
|
||||
if (opts.w === 1) {
|
||||
if (opts.word.charAt(0) === '-') complete.log(flags, opts);
|
||||
else complete.log(Object.keys(commands), opts);
|
||||
return done();
|
||||
}
|
||||
|
||||
// try to find the bower command. first thing after all the configs.
|
||||
var parsed = opts.conf = nopt({}, {}, opts.partialWords, 0);
|
||||
var cmd = parsed.argv.remain[0];
|
||||
|
||||
// unable to find a command, complete the lisf of commands
|
||||
if (!cmd) {
|
||||
complete.log(Object.keys(commands), opts);
|
||||
return done();
|
||||
}
|
||||
|
||||
// if words[0] is a bower command, then complete on it.
|
||||
cmd = commands[cmd];
|
||||
|
||||
if (cmd && cmd.completion) {
|
||||
// prior to that, ensure the completion cache directory is created first
|
||||
mkdirp(path.join(config.completion), function (err) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
var options = cmd.completion.options;
|
||||
if (options && opts.word.charAt(0) === '-') {
|
||||
complete.log(Object.keys(options).map(function (option) {
|
||||
return opts.word.charAt(1) === '-' ? options[option][0] : '-' + option;
|
||||
}), opts);
|
||||
return done();
|
||||
}
|
||||
|
||||
cmd.completion(opts, function (err, data) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
// completing options, then append top level flags
|
||||
if (opts.word.charAt(0) === '-') data = data.concat(flags);
|
||||
|
||||
complete.log(data, opts);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
return emitter;
|
||||
}
|
||||
|
||||
// otherwise, do nothing
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var emitter = new Emitter;
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
|
||||
if (options.help) return help('completion');
|
||||
|
||||
module.exports(options.argv.remain.slice(2), process.env)
|
||||
.on('data', emitter.emit.bind(emitter, 'data'))
|
||||
.on('error', emitter.emit.bind(emitter, 'error'))
|
||||
.on('end', emitter.emit.bind(emitter, 'end'));
|
||||
|
||||
return emitter;
|
||||
};
|
||||
@@ -1,52 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Help API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var events = require('events');
|
||||
var nopt = require('nopt');
|
||||
var _ = require('lodash');
|
||||
|
||||
var template = require('../util/template');
|
||||
var config = require('../core/config');
|
||||
|
||||
module.exports = function (name) {
|
||||
var context = {};
|
||||
var emitter = new events.EventEmitter;
|
||||
var commands = require('../commands');
|
||||
|
||||
// Aliases
|
||||
// At the moment we just have the ls, but we might have more
|
||||
switch (name) {
|
||||
case 'ls':
|
||||
name = 'list';
|
||||
break;
|
||||
}
|
||||
|
||||
var validCommand = !!(name && commands[name]);
|
||||
var templateName = validCommand ? 'help-' + name : 'help';
|
||||
|
||||
if (!validCommand) context = {
|
||||
commands: Object.keys(commands).sort().join(', ')
|
||||
}
|
||||
|
||||
_.extend(context, config);
|
||||
|
||||
template(templateName, context)
|
||||
.on('data', emitter.emit.bind(emitter, 'end'));
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt({}, {}, argv);
|
||||
var paths = options.argv.remain.slice(1);
|
||||
return module.exports(paths[0]);
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
return cb(null, Object.keys(require('../commands')));
|
||||
};
|
||||
@@ -1,24 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Public Commands List
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
module.exports = {
|
||||
'help': require('./help'),
|
||||
'install': require('./install'),
|
||||
'list': require('./list'),
|
||||
'ls': require('./list'),
|
||||
'uninstall': require('./uninstall'),
|
||||
'update': require('./update'),
|
||||
'link': require('./link'),
|
||||
'lookup': require('./lookup'),
|
||||
'info': require('./info'),
|
||||
'init': require('./init'),
|
||||
'register': require('./register'),
|
||||
'search': require('./search'),
|
||||
'cache-clean': require('./cache-clean'),
|
||||
'completion': require('./completion')
|
||||
};
|
||||
@@ -1,50 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Lookup API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var nopt = require('nopt');
|
||||
|
||||
var template = require('../util/template');
|
||||
var source = require('../core/source');
|
||||
var install = require('./install');
|
||||
var help = require('./help');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'] };
|
||||
|
||||
module.exports = function (name) {
|
||||
var emitter = new Emitter;
|
||||
|
||||
if (name) {
|
||||
source.info(name, function (err, result) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
emitter.emit('end', result);
|
||||
});
|
||||
}
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var emitter = new Emitter;
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var names = options.argv.remain.slice(1);
|
||||
|
||||
if (options.help || !names.length) return help('info');
|
||||
|
||||
module.exports(names[0])
|
||||
.on('error', emitter.emit.bind(emitter, 'error'))
|
||||
.on('end', function (data) {
|
||||
template('info', data).on('data', emitter.emit.bind(emitter, 'end'));
|
||||
});
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.completion = install.completion;
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,150 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Init API
|
||||
// ==========================================
|
||||
// Copyright 2013 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var util = require('util');
|
||||
|
||||
var nopt = require('nopt');
|
||||
var promptly = require('promptly');
|
||||
var _ = require('lodash');
|
||||
|
||||
var help = require('./help');
|
||||
var Manager = require('../core/manager');
|
||||
var config = require('../core/config');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'] };
|
||||
|
||||
var commonIgnore = ['**/.*', 'node_modules', 'components'];
|
||||
|
||||
var Init = function () {
|
||||
Manager.call(this);
|
||||
};
|
||||
|
||||
util.inherits(Init, Manager);
|
||||
|
||||
Init.prototype.getDependenciesJSON = function () {
|
||||
var dependencies = Object.keys(this.dependencies);
|
||||
var remaining = dependencies.length;
|
||||
var json = {};
|
||||
|
||||
dependencies.forEach(function (name) {
|
||||
var pkg = this.dependencies[name][0];
|
||||
|
||||
pkg.on('loadJSON', function () {
|
||||
// TODO: use fetch endpoint here
|
||||
json[pkg.name] = pkg.commit ? '*' : '~' + pkg.version;
|
||||
remaining -= 1;
|
||||
if (remaining === 0) {
|
||||
this.manager.emit('loadDependencies', json);
|
||||
}
|
||||
}).loadJSON();
|
||||
}, this);
|
||||
|
||||
if (remaining === 0) {
|
||||
this.emit('loadDependencies', json);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Init.prototype.getMain = function (name) {
|
||||
name = path.basename(name, '.js');
|
||||
if (fs.existsSync(path.join(process.cwd(), 'index.js'))) {
|
||||
return 'index.js';
|
||||
} else if (fs.existsSync(path.join(process.cwd(), name + '.js'))) {
|
||||
return name + '.js';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Init.prototype.showPrompt = function (question, cb) {
|
||||
var prompt = question.prompt + ': [' + (question.yesno ? 'y' : question.value) + ']';
|
||||
if (question.yesno) {
|
||||
promptly.confirm(prompt, {'default': 'y'}, cb);
|
||||
} else {
|
||||
promptly.prompt(prompt, {'default': question.value}, cb);
|
||||
}
|
||||
this.emit('prompt', prompt);
|
||||
};
|
||||
|
||||
Init.prototype.prompts = function (dependencies) {
|
||||
var main = this.json.main || this.getMain(this.json.name) || '';
|
||||
|
||||
var questions = _.compact([
|
||||
{key: 'name', prompt: 'name', value: this.json.name, yesno: false},
|
||||
{key: 'version', prompt: 'version', value: this.json.version, yesno: false},
|
||||
{key: 'main', prompt: 'main file', value: main, yesno: false},
|
||||
_.size(dependencies) ? {key: 'dependencies', prompt: 'add current components as dependencies? (y/n)', value: dependencies, yesno: true} : null,
|
||||
{key: 'ignore', prompt: 'add commonly ignored files to ignore list? (y/n)', value: commonIgnore, yesno: true}
|
||||
]);
|
||||
var index = 0;
|
||||
var question = questions[index];
|
||||
|
||||
var cb = function (err, value) {
|
||||
if (question.yesno) {
|
||||
if (value) {
|
||||
this.json[question.key] = question.value;
|
||||
}
|
||||
} else if (value) {
|
||||
this.json[question.key] = value;
|
||||
}
|
||||
index += 1;
|
||||
if (index < questions.length) {
|
||||
question = questions[index];
|
||||
this.showPrompt(question, cb);
|
||||
} else {
|
||||
this.emit('prompts');
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
this.showPrompt(question, cb);
|
||||
};
|
||||
|
||||
Init.prototype.save = function (data) {
|
||||
fs.writeFileSync(path.join(this.cwd, config.json), JSON.stringify(data, null, 2));
|
||||
};
|
||||
|
||||
module.exports = function () {
|
||||
var init = new Init();
|
||||
|
||||
init
|
||||
.on('resolveLocal', init.loadJSON.bind(init))
|
||||
.on('loadJSON', init.getDependenciesJSON.bind(init))
|
||||
.on('loadDependencies', init.prompts.bind(init))
|
||||
.on('prompts', function () {
|
||||
init.save(init.json);
|
||||
init.emit('end');
|
||||
})
|
||||
.resolveLocal();
|
||||
|
||||
return init;
|
||||
};
|
||||
|
||||
module.exports.Init = Init; // Purely for testing
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
if (options.help) return help('init');
|
||||
return module.exports();
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
var word = opts.word;
|
||||
|
||||
// completing options?
|
||||
if (word.charAt(0) === '-') {
|
||||
return cb(null, Object.keys(optionTypes).map(function (option) {
|
||||
return '--' + option;
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Install API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var nopt = require('nopt');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
var Manager = require('../core/manager');
|
||||
var config = require('../core/config');
|
||||
var source = require('../core/source');
|
||||
var save = require('../util/save');
|
||||
var help = require('./help');
|
||||
|
||||
var optionTypes = { help: Boolean, save: Boolean, 'save-dev': Boolean, force: Boolean, 'force-latest': Boolean, production: Boolean };
|
||||
var shorthand = { 'h': ['--help'], 'S': ['--save'], 'D': ['--save-dev'], 'f': ['--force'], 'F': ['--force-latest'], 'p': ['--production'] };
|
||||
|
||||
module.exports = function (paths, options) {
|
||||
options = options || {};
|
||||
|
||||
var emitter = new Emitter;
|
||||
var manager = new Manager(paths, {
|
||||
force: options.force,
|
||||
forceLatest: options['force-latest'],
|
||||
production: options.production
|
||||
});
|
||||
|
||||
manager
|
||||
.on('data', emitter.emit.bind(emitter, 'data'))
|
||||
.on('warn', emitter.emit.bind(emitter, 'warn'))
|
||||
.on('error', emitter.emit.bind(emitter, 'error'))
|
||||
.on('resolve', function (resolved) {
|
||||
// Handle save/save-dev
|
||||
if (resolved && (options.save || options['save-dev'])) {
|
||||
save(manager, paths, !options.save, emitter.emit.bind(emitter, 'end'));
|
||||
} else {
|
||||
emitter.emit('end');
|
||||
}
|
||||
})
|
||||
.resolve();
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var paths = options.argv.remain.slice(1);
|
||||
|
||||
if (options.help) return help('install');
|
||||
return module.exports(paths, options);
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
var cache = path.join(config.completion, 'install.json');
|
||||
var done = function done(err, results) {
|
||||
if (err) return cb(err);
|
||||
var names = results.map(function (pkg) {
|
||||
return pkg.name;
|
||||
});
|
||||
|
||||
return cb(null, names);
|
||||
};
|
||||
|
||||
fs.readFile(cache, function (err, body) {
|
||||
if (!err) return done(null, JSON.parse(body));
|
||||
|
||||
// expected error, do the first request and cache the results
|
||||
source.all(function (err, results) {
|
||||
if (err) return cb(err);
|
||||
fs.writeFile(cache, JSON.stringify(results, null, 2), function (err) {
|
||||
done(err, results);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,121 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Link API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var nopt = require('nopt');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var mkdirp = require('mkdirp');
|
||||
var rimraf = require('rimraf');
|
||||
|
||||
var Manager = require('../core/manager');
|
||||
var help = require('./help');
|
||||
var template = require('../util/template');
|
||||
var config = require('../core/config');
|
||||
var isRepo = require('../util/is-repo');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'] };
|
||||
|
||||
function linkSelf(emitter) {
|
||||
var manager = new Manager;
|
||||
|
||||
manager
|
||||
.on('error', emitter.emit.bind('error'))
|
||||
.once('loadJSON', function () {
|
||||
var destPath = path.join(config.links, manager.name);
|
||||
var srcPath = process.cwd();
|
||||
|
||||
deleteLink(destPath, function (err) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
createLink(srcPath, destPath, function (err) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
template('link', { src: srcPath, dest: destPath })
|
||||
.on('data', emitter.emit.bind(emitter, 'end'));
|
||||
});
|
||||
});
|
||||
}).loadJSON();
|
||||
}
|
||||
|
||||
function linkTo(name, emitter) {
|
||||
var destPath = path.join(process.cwd(), config.directory, name);
|
||||
var srcPath = path.join(config.links, name);
|
||||
|
||||
deleteLink(destPath, function (err) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
createLink(srcPath, destPath, function (err) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
template('link', { src: srcPath, dest: destPath })
|
||||
.on('data', emitter.emit.bind(emitter, 'end'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function deleteLink(dest, callback) {
|
||||
// Delete symlink if already present
|
||||
// Beware that if the target is a git repo, we can't proceed
|
||||
isRepo(dest, function (is) {
|
||||
if (is) return callback(new Error(dest + ' is a local repository, please remove it manually'));
|
||||
|
||||
fs.lstat(dest, function (err) {
|
||||
if (!err || err.code !== 'ENOENT') rimraf(dest, callback);
|
||||
else callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createLink(src, dest, callback) {
|
||||
var destDir = path.dirname(dest);
|
||||
|
||||
// Create directory
|
||||
mkdirp(destDir, function (err) {
|
||||
if (err) return callback(err);
|
||||
|
||||
fs.lstat(src, function (err) {
|
||||
if (err && err.code === 'ENOENT') {
|
||||
return callback(new Error('Attempting to link an unknown package: ' + path.basename(src)));
|
||||
}
|
||||
|
||||
// Create symlink
|
||||
fs.symlink(src, dest, 'dir', function (err) {
|
||||
callback(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function (name) {
|
||||
var emitter = new Emitter;
|
||||
|
||||
if (!name) linkSelf(emitter);
|
||||
else linkTo(name, emitter);
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var name = options.argv.remain[1];
|
||||
|
||||
if (options.help) return help('link');
|
||||
return module.exports(name);
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
fs.readdir(config.links, function (err, dirs) {
|
||||
// ignore ENOENT, ~/.bower/links not created yet
|
||||
if (err && err.code === 'ENOENT') return cb(null, []);
|
||||
cb(err, dirs);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,234 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: List API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var archy = require('archy');
|
||||
var nopt = require('nopt');
|
||||
var path = require('path');
|
||||
var _ = require('lodash');
|
||||
|
||||
var template = require('../util/template');
|
||||
var Manager = require('../core/manager');
|
||||
var Package = require('../core/package');
|
||||
var config = require('../core/config');
|
||||
var help = require('./help');
|
||||
|
||||
var shorthand = { 'h': ['--help'], 'o': ['--offline'] };
|
||||
var optionTypes = { help: Boolean, paths: Boolean, map: Boolean, offline: Boolean, sources: Boolean };
|
||||
|
||||
var getTree = function (packages, subPackages, result) {
|
||||
result = result || {};
|
||||
|
||||
_.each(subPackages || packages, function (pkg) {
|
||||
|
||||
result[pkg.name] = {};
|
||||
|
||||
Object.keys(pkg.json.dependencies || {}).forEach(function (name) {
|
||||
result[pkg.name][name] = {};
|
||||
});
|
||||
|
||||
var subPackages = {};
|
||||
|
||||
Object.keys(pkg.json.dependencies || {}).forEach(function (name) {
|
||||
subPackages[name] = packages[name] || new Package(name, null);
|
||||
});
|
||||
|
||||
getTree(packages, subPackages, result[pkg.name]);
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var generatePath = function (name, main) {
|
||||
if (typeof main === 'string') {
|
||||
return path.join(config.directory, name, main);
|
||||
} else if (_.isArray(main)) {
|
||||
main = main.map(function (main) { return generatePath(name, main); });
|
||||
return main.length === 1 ? main[0] : main;
|
||||
}
|
||||
};
|
||||
|
||||
var mainTypes = ['main', 'scripts', 'styles', 'templates', 'images'];
|
||||
|
||||
var buildSource = function (pkg, shallow) {
|
||||
var result = {};
|
||||
|
||||
if (pkg) {
|
||||
mainTypes.forEach(function (type) {
|
||||
if (pkg.json[type]) result[type] = generatePath(pkg.name, pkg.json[type]);
|
||||
});
|
||||
}
|
||||
|
||||
if (shallow) {
|
||||
result.main = getMain(result) || generatePath(pkg.name, '');
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var getMain = function (source) {
|
||||
for (var i = 0, len = mainTypes.length; i < len; i += 1) {
|
||||
var type = mainTypes[i];
|
||||
if (source[type]) {
|
||||
return source[type];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var shallowTree = function (packages, tree) {
|
||||
var result = {};
|
||||
|
||||
Object.keys(tree).forEach(function (packageName) {
|
||||
result[packageName] = buildSource(packages[packageName], true).main;
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var deepTree = function (packages, tree) {
|
||||
|
||||
var result = {};
|
||||
|
||||
Object.keys(tree).forEach(function (packageName) {
|
||||
|
||||
result[packageName] = {};
|
||||
result[packageName].source = buildSource(packages[packageName]);
|
||||
|
||||
if (Object.keys(tree[packageName]).length) {
|
||||
result[packageName].dependencies = deepTree(packages, tree[packageName]);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var getNodes = function (packages, tree) {
|
||||
return Object.keys(tree).map(function (key) {
|
||||
var version = packages[key] ? packages[key].version || '' : null;
|
||||
var upgrade;
|
||||
|
||||
if (version && packages[key].tags.indexOf(version)) {
|
||||
upgrade = packages[key].tags[0];
|
||||
}
|
||||
|
||||
if (Object.keys(tree[key]).length) {
|
||||
return {
|
||||
label: template('tree-branch', { 'package': key, version: version, upgrade: upgrade }, true),
|
||||
nodes: getNodes(packages, tree[key])
|
||||
};
|
||||
} else {
|
||||
return template('tree-branch', { 'package': key, version: version, upgrade: upgrade }, true);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var getDependencySrcs = function (list) {
|
||||
var srcs = [];
|
||||
var dependency, main;
|
||||
for (var name in list) {
|
||||
dependency = list[name];
|
||||
main = dependency.source && getMain(dependency.source);
|
||||
|
||||
if (dependency.dependencies) {
|
||||
var depSrcs = getDependencySrcs(dependency.dependencies);
|
||||
srcs.push.apply(srcs, depSrcs);
|
||||
}
|
||||
|
||||
// add main sources to srcs
|
||||
if (main) {
|
||||
if (Array.isArray(main)) {
|
||||
srcs.push.apply(srcs, main);
|
||||
} else {
|
||||
srcs.push(main);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return srcs;
|
||||
};
|
||||
|
||||
var organizeSources = function (tree) {
|
||||
// flat source filepaths
|
||||
var srcs = getDependencySrcs(tree);
|
||||
// remove duplicates, organize by file extension
|
||||
var sources = {};
|
||||
|
||||
srcs.forEach(function (src) {
|
||||
var ext = path.extname(src);
|
||||
sources[ext] = sources[ext] || [];
|
||||
if (sources[ext].indexOf(src) === -1) {
|
||||
sources[ext].push(src);
|
||||
}
|
||||
});
|
||||
|
||||
return sources;
|
||||
};
|
||||
|
||||
module.exports = function (options) {
|
||||
var manager = new Manager;
|
||||
var emitter = new Emitter;
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (options.sources) {
|
||||
options.map = true;
|
||||
}
|
||||
|
||||
var emitOut = function (obj) {
|
||||
// make JSON pretty if started from command line
|
||||
var output = options.argv ? JSON.stringify(obj, null, 2) : obj;
|
||||
emitter.emit('data', output);
|
||||
};
|
||||
manager
|
||||
.on('data', emitter.emit.bind(emitter, 'data'))
|
||||
.on('error', emitter.emit.bind(emitter, 'error'))
|
||||
.on('list', function (packages) {
|
||||
var tree = getTree(packages);
|
||||
if (!options.paths && !options.map) {
|
||||
emitter.emit('data', archy({
|
||||
label: process.cwd(),
|
||||
nodes: getNodes(packages, tree)
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
tree = options.paths ? shallowTree(packages, tree) : deepTree(packages, tree);
|
||||
|
||||
if (options.sources) {
|
||||
// with map, organize it and emit
|
||||
var sources = organizeSources(tree);
|
||||
emitOut(sources);
|
||||
} else {
|
||||
emitOut(tree);
|
||||
}
|
||||
|
||||
})
|
||||
.list(options);
|
||||
|
||||
return emitter;
|
||||
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
if (options.help) return help('list');
|
||||
return module.exports(options);
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
if (!/^-/.test(opts.word)) return cb(null, []);
|
||||
|
||||
var results = Object.keys(optionTypes).map(function (option) {
|
||||
return '--' + option;
|
||||
});
|
||||
|
||||
cb(null, results);
|
||||
};
|
||||
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,64 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Lookup API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var nopt = require('nopt');
|
||||
|
||||
var template = require('../util/template');
|
||||
var source = require('../core/source');
|
||||
var install = require('./install');
|
||||
var help = require('./help');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'] };
|
||||
|
||||
module.exports = function (name) {
|
||||
var emitter = new Emitter;
|
||||
|
||||
source.lookup(name, function (err, url) {
|
||||
if (err) {
|
||||
source.search(name, function (err, packages) {
|
||||
if (packages.length) {
|
||||
template('suggestions', { packages: packages, name: name })
|
||||
.on('data', function (data) {
|
||||
emitter.emit('data', data);
|
||||
emitter.emit('end');
|
||||
});
|
||||
} else {
|
||||
template('warning-missing', {name: name})
|
||||
.on('data', function (data) {
|
||||
emitter.emit('data', data);
|
||||
emitter.emit('end');
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
var result = { name: name, url: url };
|
||||
emitter.emit('package', result);
|
||||
|
||||
template('lookup', result)
|
||||
.on('data', function (data) {
|
||||
emitter.emit('data', data);
|
||||
emitter.emit('end');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var names = options.argv.remain.slice(1);
|
||||
|
||||
if (options.help || !names.length) return help('lookup');
|
||||
return module.exports(names[0]);
|
||||
};
|
||||
|
||||
module.exports.completion = install.completion;
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,66 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Lookup API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var nopt = require('nopt');
|
||||
var readline = require('readline');
|
||||
|
||||
var template = require('../util/template');
|
||||
var source = require('../core/source');
|
||||
var help = require('./help');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'], '-s': ['--silent'] };
|
||||
|
||||
var register = function (name, url, emitter) {
|
||||
source.register(name, url, function (err) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
template('register', {name: name, url: url})
|
||||
.on('data', emitter.emit.bind(emitter, 'data'));
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = function (name, url, options) {
|
||||
var emitter = new Emitter;
|
||||
|
||||
if (options.silent) register(name, url, emitter);
|
||||
else {
|
||||
var rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
||||
|
||||
console.log('Registering a package will make it visible and installable via the registry.');
|
||||
rl.question('Proceed (y/n)? ', function (res) {
|
||||
rl.close();
|
||||
|
||||
res = res.toLowerCase();
|
||||
|
||||
if (res === 'y' || res === 'yes') register(name, url, emitter);
|
||||
});
|
||||
}
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var args = options.argv.remain.slice(1);
|
||||
|
||||
if (options.help || args.length !== 2) return help('register');
|
||||
return module.exports(args[0], args[1], options);
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
var word = opts.word;
|
||||
|
||||
// completing options?
|
||||
if (word.charAt(0) === '-') {
|
||||
return cb(null, Object.keys(optionTypes).map(function (option) {
|
||||
return '--' + option;
|
||||
}));
|
||||
}
|
||||
};
|
||||
@@ -1,61 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Lookup API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var nopt = require('nopt');
|
||||
|
||||
var template = require('../util/template');
|
||||
var source = require('../core/source');
|
||||
var install = require('./install');
|
||||
var help = require('./help');
|
||||
|
||||
var optionTypes = { help: Boolean };
|
||||
var shorthand = { 'h': ['--help'] };
|
||||
|
||||
module.exports = function (name) {
|
||||
var emitter = new Emitter;
|
||||
|
||||
var callback = function (err, results) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
emitter.emit('packages', results);
|
||||
|
||||
if (results.length) {
|
||||
template('search', {results: results})
|
||||
.on('data', function (data) {
|
||||
emitter.emit('data', data);
|
||||
emitter.emit('end');
|
||||
});
|
||||
} else {
|
||||
template('search-empty', {results: results})
|
||||
.on('data', function (data) {
|
||||
emitter.emit('data', data);
|
||||
emitter.emit('end');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (name) {
|
||||
source.search(name, callback);
|
||||
} else {
|
||||
source.all(callback);
|
||||
}
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var names = options.argv.remain.slice(1);
|
||||
|
||||
if (options.help) return help('search');
|
||||
return module.exports(names[0]);
|
||||
};
|
||||
|
||||
module.exports.completion = install.completion;
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,206 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Uninstall API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var async = require('async');
|
||||
var nopt = require('nopt');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var _ = require('lodash');
|
||||
|
||||
var template = require('../util/template');
|
||||
var Manager = require('../core/manager');
|
||||
var config = require('../core/config');
|
||||
var help = require('./help');
|
||||
|
||||
var optionTypes = { help: Boolean, force: Boolean, save: Boolean };
|
||||
var shorthand = { 'h': ['--help'], 'S': ['--save'], 'D': ['--save-dev'], 'f': ['--force'] };
|
||||
|
||||
module.exports = function (names, options) {
|
||||
var packages, uninstallables, packagesCount = {};
|
||||
var emitter = new Emitter;
|
||||
var manager = new Manager;
|
||||
var jsonDeps;
|
||||
var newLine;
|
||||
|
||||
options = options || {};
|
||||
|
||||
manager.on('data', emitter.emit.bind(emitter, 'data'));
|
||||
manager.on('error', emitter.emit.bind(emitter, 'error'));
|
||||
|
||||
var resolveLocal = function () {
|
||||
jsonDeps = manager.json.dependencies || {};
|
||||
packages = _.flatten(_.values(manager.dependencies));
|
||||
uninstallables = packages.filter(function (pkg) {
|
||||
return _.include(names, pkg.name);
|
||||
});
|
||||
async.forEach(packages, function (pkg, next) {
|
||||
pkg.once('loadJSON', next).loadJSON();
|
||||
}, function () {
|
||||
if (showWarnings(options.force) && !options.force) return;
|
||||
expandUninstallabes(options.force);
|
||||
uninstall();
|
||||
});
|
||||
};
|
||||
|
||||
var showWarnings = function (force) {
|
||||
var foundConflicts = false;
|
||||
|
||||
packages.forEach(function (pkg) {
|
||||
if (!pkg.json.dependencies) return;
|
||||
if (containsPkg(uninstallables, pkg)) return;
|
||||
|
||||
var conflicts = _.intersection(
|
||||
Object.keys(pkg.json.dependencies),
|
||||
_.pluck(uninstallables, 'name')
|
||||
);
|
||||
|
||||
if (conflicts.length) {
|
||||
foundConflicts = true;
|
||||
if (!force) {
|
||||
conflicts.forEach(function (conflictName) {
|
||||
emitter.emit('data', template('warning-uninstall', { packageName: pkg.name, conflictName: conflictName }, true));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (foundConflicts && !force) {
|
||||
emitter.emit('data', template('warn', { message: 'To proceed, run uninstall with the --force flag'}, true));
|
||||
}
|
||||
|
||||
return foundConflicts;
|
||||
};
|
||||
|
||||
var expandUninstallabes = function (force) {
|
||||
var x,
|
||||
pkg,
|
||||
forcedUninstallables = {};
|
||||
|
||||
// Direct JSON deps have a count of 1
|
||||
for (var key in jsonDeps) {
|
||||
packagesCount[key] = 1;
|
||||
}
|
||||
|
||||
// Count all packages
|
||||
count(packages, packagesCount);
|
||||
|
||||
if (force) {
|
||||
uninstallables.forEach(function (pkg) {
|
||||
forcedUninstallables[pkg.name] = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Expand the uninstallables deps and nested deps
|
||||
// Also update the count accordingly
|
||||
for (x = uninstallables.length - 1; x >= 0; x -= 1) {
|
||||
parseUninstallableDeps(uninstallables[x]);
|
||||
}
|
||||
|
||||
// Foreach uninstallable, check if it is really to be removed by reading the final count
|
||||
// If the final count is greater than 0, then it is a shared dep
|
||||
// In that case, we remove it from the uninstallables unless it's forced to be uninstalled
|
||||
for (x = uninstallables.length - 1; x >= 0; x -= 1) {
|
||||
pkg = uninstallables[x];
|
||||
if (packagesCount[pkg.name] > 0 && !forcedUninstallables[pkg.name]) uninstallables.splice(x, 1);
|
||||
}
|
||||
};
|
||||
|
||||
var count = function (packages, counts, nested) {
|
||||
packages.forEach(function (pkg) {
|
||||
counts[pkg.name] = (counts[pkg.name] || 0);
|
||||
if (nested) counts[pkg.name] += 1;
|
||||
|
||||
if (pkg.json.dependencies) {
|
||||
for (var key in pkg.json.dependencies) {
|
||||
count(manager.dependencies[key], counts, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var parseUninstallableDeps = function (pkg) {
|
||||
if (!containsPkg(uninstallables, pkg)) uninstallables.push(pkg);
|
||||
packagesCount[pkg.name] -= 1;
|
||||
|
||||
if (pkg.json.dependencies) {
|
||||
for (var key in pkg.json.dependencies) {
|
||||
parseUninstallableDeps(manager.dependencies[key][0]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var containsPkg = function (packages, pkg) {
|
||||
for (var x = packages.length - 1; x >= 0; x -= 1) {
|
||||
if (packages[x].name === pkg.name) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
var uninstall = function () {
|
||||
async.forEach(uninstallables, function (pkg, next) {
|
||||
pkg.on('uninstall', function () {
|
||||
emitter.emit('package', pkg);
|
||||
next();
|
||||
}).uninstall();
|
||||
}, function () {
|
||||
// Finally save
|
||||
if (options.save || options['save-dev']) save(!options.save);
|
||||
emitter.emit('end');
|
||||
});
|
||||
};
|
||||
|
||||
var save = function (dev) {
|
||||
var key = dev ? 'devDependencies' : 'dependencies';
|
||||
var contents;
|
||||
|
||||
if (manager.json[key]) {
|
||||
names.forEach(function (name) {
|
||||
delete manager.json[key][name];
|
||||
});
|
||||
|
||||
contents = JSON.stringify(manager.json, null, 2) + (newLine ? '\n' : '');
|
||||
fs.writeFileSync(path.join(manager.cwd, config.json), contents);
|
||||
}
|
||||
};
|
||||
|
||||
manager.on('loadJSON', function (hasNewLine) {
|
||||
newLine = hasNewLine;
|
||||
manager.on('resolveLocal', resolveLocal).resolveLocal();
|
||||
}).loadJSON();
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
var names = options.argv.remain.slice(1);
|
||||
|
||||
if (options.help || !names.length) return help('uninstall');
|
||||
return module.exports(names, options);
|
||||
};
|
||||
|
||||
module.exports.completion = function (opts, cb) {
|
||||
var word = opts.word;
|
||||
|
||||
// completing options?
|
||||
if (opts.words[0] === 'uninstall' && word.charAt(0) === '-') {
|
||||
return cb(null, Object.keys(optionTypes).map(function (option) {
|
||||
return '--' + option;
|
||||
}));
|
||||
}
|
||||
|
||||
fs.readdir(config.directory, function (err, dirs) {
|
||||
// ignore ENOENT, ./components not created yet
|
||||
if (err && err.code === 'ENOENT') return cb(null, []);
|
||||
cb(err, dirs);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,97 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Update API
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var async = require('async');
|
||||
var nopt = require('nopt');
|
||||
var _ = require('lodash');
|
||||
|
||||
var Manager = require('../core/manager');
|
||||
var help = require('./help');
|
||||
var uninstall = require('./uninstall');
|
||||
var save = require('../util/save');
|
||||
|
||||
var optionTypes = { help: Boolean, save: Boolean, force: Boolean, 'force-latest': Boolean };
|
||||
var shorthand = { 'h': ['--help'], 'S': ['--save'], 'f': ['--force'], 'F': ['--force-latest'] };
|
||||
|
||||
module.exports = function (names, options) {
|
||||
options = options || {};
|
||||
|
||||
var emitter = new Emitter;
|
||||
var manager = new Manager([], {
|
||||
force: options.force,
|
||||
forceLatest: options['force-latest']
|
||||
});
|
||||
|
||||
manager.on('data', emitter.emit.bind(emitter, 'data'));
|
||||
manager.on('warn', emitter.emit.bind(emitter, 'warn'));
|
||||
manager.on('error', emitter.emit.bind(emitter, 'error'));
|
||||
|
||||
var installURLS = function (err, arr) {
|
||||
var mappings = {},
|
||||
endpoints = [];
|
||||
|
||||
arr = _.compact(arr);
|
||||
_.each(arr, function (info) {
|
||||
endpoints.push(info.endpoint);
|
||||
mappings[info.endpoint] = info.name;
|
||||
});
|
||||
|
||||
options.endpointNames = mappings;
|
||||
|
||||
// By default the manager will guess the name of the package from the url
|
||||
// But this leads to problems when the package name does not match the one in the url
|
||||
// So the manager now has an option (endpointNames) to deal with this
|
||||
manager = new Manager(endpoints, options);
|
||||
|
||||
manager
|
||||
.on('data', emitter.emit.bind(emitter, 'data'))
|
||||
.on('warn', emitter.emit.bind(emitter, 'warn'))
|
||||
.on('error', emitter.emit.bind(emitter, 'error'))
|
||||
.on('resolve', function (resolved) {
|
||||
// Handle save
|
||||
if (resolved && options.save) save(manager, null, false, emitter.emit.bind(emitter, 'end'));
|
||||
else emitter.emit('end');
|
||||
})
|
||||
.resolve();
|
||||
};
|
||||
|
||||
manager.once('resolveLocal', function () {
|
||||
names = names.length ? _.uniq(names) : null;
|
||||
|
||||
async.map(_.values(manager.dependencies), function (pkgs, next) {
|
||||
var pkg = pkgs[0];
|
||||
pkg.once('loadJSON', function () {
|
||||
var endpointInfo = pkg.readEndpoint();
|
||||
if (!endpointInfo) return next();
|
||||
|
||||
// Add tag only if the endpoint is a repository
|
||||
var endpoint = endpointInfo.endpoint;
|
||||
var json = pkg.json;
|
||||
if (!json.commit && (endpointInfo.type === 'git' || endpointInfo.type === 'local-repo')) {
|
||||
endpoint += '#' + ((!names || names.indexOf(pkg.name) > -1) ? '~' : '') + pkg.version;
|
||||
}
|
||||
|
||||
next(null, { name: pkg.name, endpoint: endpoint });
|
||||
}).loadJSON();
|
||||
}, installURLS);
|
||||
}).resolveLocal();
|
||||
|
||||
return emitter;
|
||||
};
|
||||
|
||||
module.exports.line = function (argv) {
|
||||
var options = nopt(optionTypes, shorthand, argv);
|
||||
if (options.help) return help('update');
|
||||
|
||||
var paths = options.argv.remain.slice(1);
|
||||
return module.exports(paths, options);
|
||||
};
|
||||
|
||||
module.exports.completion = uninstall.completion;
|
||||
module.exports.completion.options = shorthand;
|
||||
@@ -1,75 +0,0 @@
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var _ = require('lodash');
|
||||
var tmp = require('tmp');
|
||||
var mkdirp = require('mkdirp');
|
||||
var zlib = require('zlib');
|
||||
|
||||
var fileExists = require('../util/file-exists').sync;
|
||||
|
||||
// This forces the default chunk size to something small in an attempt
|
||||
// to avoid issue #314
|
||||
zlib.Z_DEFAULT_CHUNK = 1024*8;
|
||||
|
||||
var temp = process.env.TMPDIR
|
||||
|| process.env.TMP
|
||||
|| process.env.TEMP
|
||||
|| process.platform === 'win32' ? 'c:\\windows\\temp' : '/tmp';
|
||||
|
||||
var home = (process.platform === 'win32'
|
||||
? process.env.USERPROFILE
|
||||
: process.env.HOME) || temp;
|
||||
|
||||
var roaming = process.platform === 'win32'
|
||||
? path.resolve(process.env.APPDATA || home || temp)
|
||||
: path.resolve(home || temp);
|
||||
|
||||
var folder = process.platform === 'win32'
|
||||
? 'bower'
|
||||
: '.bower';
|
||||
|
||||
var proxy = process.env.HTTPS_PROXY
|
||||
|| process.env.https_proxy
|
||||
|| process.env.HTTP_PROXY
|
||||
|| process.env.http_proxy;
|
||||
|
||||
// Bower Config
|
||||
var config;
|
||||
try {
|
||||
config = require('rc') ('bower', {
|
||||
cache : path.join(roaming, folder, 'cache'),
|
||||
links : path.join(roaming, folder, 'links'),
|
||||
completion : path.join(roaming, folder, 'completion'),
|
||||
git_template : path.join(roaming, folder, 'git_template'),
|
||||
json : 'bower.json',
|
||||
endpoint : 'https://bower.herokuapp.com',
|
||||
directory : 'components',
|
||||
proxy : proxy,
|
||||
shorthand_resolver : 'git://github.com/{{{ endpoint }}}.git'
|
||||
});
|
||||
} catch (e) {
|
||||
throw new Error('Unable to parse global .bowerrc file: ' + e.message);
|
||||
}
|
||||
|
||||
// If there is a local .bowerrc file, merge it
|
||||
var localFile = path.join(process.cwd(), '.bowerrc');
|
||||
if (fileExists(localFile)) {
|
||||
try {
|
||||
_.extend(config, JSON.parse(fs.readFileSync(localFile)));
|
||||
} catch (e) {
|
||||
throw new Error('Unable to parse local .bowerrc file: ' + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that we have our git template directory
|
||||
try {
|
||||
mkdirp.sync(config.git_template);
|
||||
} catch (e) {
|
||||
throw new Error('Unable to create git_template directory: ' + e.message);
|
||||
}
|
||||
|
||||
// Configure tmp package to use graceful degradation
|
||||
// If an uncaught exception occurs, the temporary directories will be deleted nevertheless
|
||||
tmp.setGracefulCleanup();
|
||||
|
||||
module.exports = config;
|
||||
@@ -1,378 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Manager Object Definition
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
// Events:
|
||||
// - install: fired when everything is installed
|
||||
// - package: fired for each installed packaged
|
||||
// - resolve: fired when deps resolved (with a true/false indicating success or error)
|
||||
// - error: fired on all errors
|
||||
// - data: fired when trying to output data
|
||||
// - warn: fired when a discouraged but not fatal situation arises
|
||||
// - end: fired when finished installing
|
||||
// ==========================================
|
||||
|
||||
var events = require('events');
|
||||
var semver = require('semver');
|
||||
var async = require('async');
|
||||
var path = require('path');
|
||||
var glob = require('glob');
|
||||
var fs = require('fs');
|
||||
var _ = require('lodash');
|
||||
|
||||
var Package = require('./package');
|
||||
var UnitWork = require('./unit_work');
|
||||
var config = require('./config');
|
||||
var fallback = require('../util/fallback');
|
||||
var template = require('../util/template');
|
||||
var prune = require('../util/prune');
|
||||
|
||||
// read local dependencies (with versions)
|
||||
// read json dependencies (resolving along the way into temp dir)
|
||||
// merge local dependencies with json dependencies
|
||||
// prune and move dependencies into local directory
|
||||
|
||||
var Manager = function (endpoints, opts) {
|
||||
this.dependencies = {};
|
||||
this.cwd = process.cwd();
|
||||
this.endpoints = endpoints || [];
|
||||
this.unitWork = new UnitWork;
|
||||
this.opts = opts || {};
|
||||
this.errors = [];
|
||||
};
|
||||
|
||||
Manager.prototype = Object.create(events.EventEmitter.prototype);
|
||||
Manager.prototype.constructor = Manager;
|
||||
|
||||
Manager.prototype.loadJSON = function () {
|
||||
fallback(this.cwd, [config.json, 'component.json'], function (file) {
|
||||
if (file !== null) {
|
||||
if (file !== config.json) {
|
||||
this.emit('warn', 'Using deprecated "component.json". Please use "bower.json" instead');
|
||||
}
|
||||
|
||||
return this.readJSON(path.join(this.cwd, file));
|
||||
}
|
||||
|
||||
this.createJSON();
|
||||
return this.emit('loadJSON');
|
||||
}.bind(this));
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Manager.prototype.resolve = function () {
|
||||
var resolved = function () {
|
||||
// If there is errors, report them
|
||||
if (this.errors.length) return this.reportErrors();
|
||||
// If there is an error while pruning (conflict) then abort installation
|
||||
if (!this.prune()) return this.emit('resolve', false);
|
||||
// Otherwise all is fine, so we install
|
||||
this.once('install', this.emit.bind(this, 'resolve', true)).install();
|
||||
}.bind(this);
|
||||
|
||||
// Resolve locally first
|
||||
this.once('resolveLocal', function () {
|
||||
if (this.endpoints.length) {
|
||||
// TODO: When resolving specific endpoints we need to restore all the local
|
||||
// packages and their hierarchy (all from the local folder)
|
||||
// If something goes wrong, simply do resolveFromJSON before
|
||||
// calling resolved() (slower)
|
||||
// This will solve issue #200
|
||||
this.once('resolveEndpoints', resolved).resolveEndpoints();
|
||||
} else {
|
||||
this.once('resolveFromJson', resolved).resolveFromJson();
|
||||
}
|
||||
}).resolveLocal();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Manager.prototype.resolveLocal = function () {
|
||||
glob('./' + config.directory + '/*', function (err, dirs) {
|
||||
if (err) return this.emit('error', err);
|
||||
dirs.forEach(function (dir) {
|
||||
var name = path.basename(dir);
|
||||
var pkg = new Package(name, dir, this);
|
||||
|
||||
this.dependencies[name] = [];
|
||||
this.dependencies[name].push(pkg);
|
||||
|
||||
this.gatherPackageErrors(pkg);
|
||||
}.bind(this));
|
||||
this.emit('resolveLocal');
|
||||
}.bind(this));
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Manager.prototype.resolveEndpoints = function () {
|
||||
var endpointNames = this.opts.endpointNames || {};
|
||||
|
||||
async.forEach(this.endpoints, function (endpoint, next) {
|
||||
var name = endpointNames[endpoint];
|
||||
var pkg = new Package(name, endpoint, this);
|
||||
var errorNext;
|
||||
|
||||
pkg.root = true;
|
||||
this.dependencies[name] = this.dependencies[name] || [];
|
||||
this.dependencies[name].push(pkg);
|
||||
|
||||
this.gatherPackageErrors(pkg);
|
||||
pkg.once('error', errorNext = next.bind(next, null));
|
||||
pkg.once('resolve', function () {
|
||||
pkg.removeListener('error', errorNext);
|
||||
next();
|
||||
}).resolve();
|
||||
}.bind(this), this.emit.bind(this, 'resolveEndpoints'));
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Manager.prototype.resolveFromJson = function () {
|
||||
this.once('loadJSON', function () {
|
||||
var dependencies = this.json.dependencies || {};
|
||||
|
||||
// add devDependencies
|
||||
if (!this.opts.production && this.json.devDependencies) {
|
||||
dependencies = _.extend({}, dependencies, this.json.devDependencies);
|
||||
}
|
||||
|
||||
async.forEach(Object.keys(dependencies), function (name, next) {
|
||||
var endpoint = dependencies[name];
|
||||
var pkg = new Package(name, endpoint, this);
|
||||
var errorNext;
|
||||
|
||||
pkg.root = true;
|
||||
|
||||
this.gatherPackageErrors(pkg);
|
||||
|
||||
pkg.once('error', errorNext = next.bind(next, null));
|
||||
pkg.once('resolve', function () {
|
||||
pkg.removeListener('error', errorNext);
|
||||
|
||||
this.dependencies[pkg.name] = this.dependencies[pkg.name] || [];
|
||||
this.dependencies[pkg.name].push(pkg);
|
||||
|
||||
next();
|
||||
}.bind(this)).resolve();
|
||||
}.bind(this), this.emit.bind(this, 'resolveFromJson'));
|
||||
}.bind(this)).loadJSON();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// Private
|
||||
Manager.prototype.createJSON = function () {
|
||||
// If the json does not exist, assume one
|
||||
this.json = {
|
||||
name: path.basename(this.cwd),
|
||||
version: '0.0.0'
|
||||
},
|
||||
this.name = this.json.name;
|
||||
this.version = this.json.version;
|
||||
};
|
||||
|
||||
Manager.prototype.readJSON = function (filename) {
|
||||
fs.readFile(filename, 'utf8', function (err, json) {
|
||||
if (err) return this.emit('error', err);
|
||||
try {
|
||||
this.json = JSON.parse(json);
|
||||
} catch (e) {
|
||||
return this.emit('error', new Error('There was an error while reading the ' + config.json + ': ' + e.message));
|
||||
}
|
||||
this.name = this.json.name;
|
||||
this.version = this.json.version;
|
||||
this.emit('loadJSON', json.slice(-1) === '\n');
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Manager.prototype.getDeepDependencies = function () {
|
||||
var result = {};
|
||||
|
||||
for (var name in this.dependencies) {
|
||||
this.dependencies[name].forEach(function (pkg) {
|
||||
result[pkg.name] = result[pkg.name] || [];
|
||||
result[pkg.name].push(pkg);
|
||||
pkg.getDeepDependencies().forEach(function (pkg) {
|
||||
result[pkg.name] = result[pkg.name] || [];
|
||||
result[pkg.name].push(pkg);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Manager.prototype.prune = function () {
|
||||
var result = prune(this.getDeepDependencies(), this.opts.forceLatest);
|
||||
var name;
|
||||
|
||||
// If there is conflicted deps, print them and fail
|
||||
if (result.conflicted) {
|
||||
for (name in result.conflicted) {
|
||||
this.reportConflicts(name, result.conflicted[name]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
this.dependencies = {};
|
||||
|
||||
// If there is conflicted deps but they where forcebly resolved
|
||||
// Print a warning about them
|
||||
if (result.forceblyResolved) {
|
||||
for (name in result.forceblyResolved) {
|
||||
this.reportForceblyResolved(name, result.forceblyResolved[name]);
|
||||
this.dependencies[name] = result.forceblyResolved[name];
|
||||
this.dependencies[name][0].root = true;
|
||||
}
|
||||
}
|
||||
|
||||
_.extend(this.dependencies, result.resolved);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
Manager.prototype.gatherPackageErrors = function (pkg) {
|
||||
pkg.on('error', function (err, origin) {
|
||||
pkg = origin || pkg;
|
||||
|
||||
// If the error message starts with the package name, strip it
|
||||
if (!err.message.indexOf(pkg.name + ' ')) {
|
||||
err.message = err.message.substr(pkg.name.length + 1);
|
||||
}
|
||||
|
||||
this.errors.push({ pkg: pkg, error: err });
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Manager.prototype.install = function () {
|
||||
async.forEach(Object.keys(this.dependencies), function (name, next) {
|
||||
var pkg = this.dependencies[name][0];
|
||||
pkg.once('install', function () {
|
||||
this.emit('package', pkg);
|
||||
next();
|
||||
}.bind(this)).install();
|
||||
pkg.once('error', next);
|
||||
}.bind(this), function () {
|
||||
if (this.errors.length) this.reportErrors();
|
||||
return this.emit('install');
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Manager.prototype.muteDependencies = function () {
|
||||
for (var name in this.dependencies) {
|
||||
this.dependencies[name].forEach(function (pkg) {
|
||||
pkg.removeAllListeners();
|
||||
pkg.on('error', function () {});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Manager.prototype.reportErrors = function () {
|
||||
this.muteDependencies();
|
||||
template('error-summary', { errors: this.errors }).on('data', function (data) {
|
||||
this.emit('data', data);
|
||||
this.emit('resolve', false);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Manager.prototype.reportConflicts = function (name, packages) {
|
||||
var versions = [];
|
||||
var requirements = [];
|
||||
|
||||
packages = packages.filter(function (pkg) { return !!pkg.version; });
|
||||
packages.forEach(function (pkg) {
|
||||
requirements.push({ pkg: pkg, tag: pkg.originalTag || '~' + pkg.version });
|
||||
versions.push((pkg.originalTag || '~' + pkg.version).white);
|
||||
});
|
||||
|
||||
this.emit('error', new Error('No resolvable version for ' + name));
|
||||
this.emit('data', template('conflict', {
|
||||
name: name,
|
||||
requirements: requirements,
|
||||
json: config.json,
|
||||
versions: versions.slice(0, -1).join(', ') + ' or ' + versions[versions.length - 1]
|
||||
}, true));
|
||||
};
|
||||
|
||||
Manager.prototype.reportForceblyResolved = function (name, packages) {
|
||||
var requirements = [];
|
||||
|
||||
packages = packages.filter(function (pkg) { return !!pkg.version; });
|
||||
packages.forEach(function (pkg) {
|
||||
requirements.push({ pkg: pkg, tag: pkg.originalTag || '~' + pkg.version });
|
||||
});
|
||||
|
||||
this.emit('data', template('resolved-conflict', {
|
||||
name: name,
|
||||
requirements: requirements,
|
||||
json: config.json,
|
||||
resolvedTo: packages[0].version,
|
||||
forceLatest: this.opts.forceLatest
|
||||
}, true));
|
||||
};
|
||||
|
||||
|
||||
// ----- list ----- //
|
||||
|
||||
// Used in list command
|
||||
// TODO: not sure if this belongs here.. maybe move it to the list command?
|
||||
Manager.prototype.list = function (options) {
|
||||
options = options || {};
|
||||
// If the user passed the paths or map options, we don't need to fetch versions
|
||||
this._isCheckingVersions = !options.offline && !options.paths && !options.map && options.argv;
|
||||
this.once('resolveLocal', this.getDependencyList.bind(this))
|
||||
.resolveLocal();
|
||||
};
|
||||
|
||||
Manager.prototype.getDependencyList = function () {
|
||||
|
||||
var packages = {};
|
||||
var values;
|
||||
var checkVersions = this._isCheckingVersions;
|
||||
|
||||
Object.keys(this.dependencies).forEach(function (key) {
|
||||
packages[key] = this.dependencies[key][0];
|
||||
}.bind(this));
|
||||
|
||||
values = _.values(packages);
|
||||
|
||||
// Do not proceed if no values
|
||||
if (!values.length) {
|
||||
return packages;
|
||||
}
|
||||
|
||||
if (checkVersions) {
|
||||
template('action', { name: 'discover', shizzle: 'Please wait while newer package versions are being discovered' })
|
||||
.on('data', this.emit.bind(this, 'data'));
|
||||
}
|
||||
|
||||
// Load JSON and get version for each package
|
||||
async.forEach(values, function (pkg, next) {
|
||||
pkg.once('loadJSON', function () {
|
||||
// Only check versions if not offline and it's a repo
|
||||
var fetchVersions = checkVersions &&
|
||||
pkg.json.repository &&
|
||||
(pkg.json.repository.type === 'git' || pkg.json.repository.type === 'local-repo');
|
||||
|
||||
if (fetchVersions) {
|
||||
pkg.once('versions', function (versions) {
|
||||
pkg.tags = versions.map(function (ver) {
|
||||
return semver.valid(ver) ? semver.clean(ver) : ver;
|
||||
});
|
||||
next();
|
||||
}).versions();
|
||||
} else {
|
||||
pkg.tags = [];
|
||||
next();
|
||||
}
|
||||
}).loadJSON();
|
||||
}.bind(this), this.emit.bind(this, 'list', packages));
|
||||
};
|
||||
|
||||
module.exports = Manager;
|
||||
@@ -1,873 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Package Object Definition
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
// Events:
|
||||
// - install: fired when package installed
|
||||
// - resolve: fired when deps resolved
|
||||
// - error: fired on all errors
|
||||
// - data: fired when trying to output data
|
||||
// ==========================================
|
||||
|
||||
var fstream = require('fstream');
|
||||
var mkdirp = require('mkdirp');
|
||||
var events = require('events');
|
||||
var rimraf = require('rimraf');
|
||||
var semver = require('semver');
|
||||
var async = require('async');
|
||||
var https = require('https');
|
||||
var http = require('http');
|
||||
var path = require('path');
|
||||
var glob = require('glob');
|
||||
var url = require('url');
|
||||
var tmp = require('tmp');
|
||||
var fs = require('fs');
|
||||
var crypto = require('crypto');
|
||||
var unzip = require('unzip');
|
||||
var tar = require('tar');
|
||||
var _ = require('lodash');
|
||||
var hogan = require('hogan.js');
|
||||
|
||||
var config = require('./config');
|
||||
var source = require('./source');
|
||||
var template = require('../util/template');
|
||||
var readJSON = require('../util/read-json');
|
||||
var fileExists = require('../util/file-exists');
|
||||
var fallback = require('../util/fallback');
|
||||
var isRepo = require('../util/is-repo');
|
||||
var git = require('../util/git-cmd');
|
||||
var UnitWork = require('./unit_work');
|
||||
|
||||
var Package = function (name, endpoint, manager) {
|
||||
this.dependencies = {};
|
||||
this.json = {};
|
||||
this.name = name;
|
||||
this.manager = manager;
|
||||
this.unitWork = manager ? manager.unitWork : new UnitWork;
|
||||
this.opts = manager ? manager.opts : {};
|
||||
this.explicitName = true;
|
||||
|
||||
if (endpoint) {
|
||||
var split;
|
||||
|
||||
if (/^(.*\.git)$/.exec(endpoint)) {
|
||||
this.gitUrl = RegExp.$1.replace(/^git\+/, '');
|
||||
this.tag = false;
|
||||
|
||||
} else if (/^(.*\.git)#(.*)$/.exec(endpoint)) {
|
||||
this.tag = RegExp.$2;
|
||||
this.gitUrl = RegExp.$1.replace(/^git\+/, '');
|
||||
|
||||
} else if (/^(?:(git):|git\+(https?):)\/\/([^#]+)#?(.*)$/.exec(endpoint)) {
|
||||
this.gitUrl = (RegExp.$1 || RegExp.$2) + '://' + RegExp.$3;
|
||||
this.tag = RegExp.$4;
|
||||
|
||||
} else if (semver.validRange(endpoint)) {
|
||||
this.tag = endpoint;
|
||||
this.explicitName = false;
|
||||
|
||||
} else if (/^[\.\/~]\.?[^.]*\.(js|css)/.test(endpoint) && fs.statSync(endpoint).isFile()) {
|
||||
this.path = path.resolve(endpoint);
|
||||
this.assetType = path.extname(endpoint);
|
||||
|
||||
} else if (/^https?:\/\//.exec(endpoint)) {
|
||||
this.assetUrl = endpoint;
|
||||
this.assetType = path.extname(endpoint);
|
||||
|
||||
} else if (fileExists.sync((split = endpoint.split('#', 2))[0]) && fs.statSync(split[0]).isDirectory()) {
|
||||
this.path = path.resolve(split[0]);
|
||||
this.tag = split[1];
|
||||
|
||||
} else if (/^[\.\/~]/.test(endpoint)) {
|
||||
this.path = path.resolve(endpoint);
|
||||
|
||||
} else if (endpoint.split('/').length === 2) {
|
||||
this.gitUrl = this.resolveShorthand(config.shorthand_resolver, (split = endpoint.split('#', 2))[0]);
|
||||
this.tag = split[1];
|
||||
this.shorthand = endpoint;
|
||||
|
||||
} else {
|
||||
split = endpoint.split('#', 2);
|
||||
this.tag = split[1];
|
||||
}
|
||||
|
||||
// Guess names
|
||||
if (!this.name) {
|
||||
if (this.gitUrl) this.name = path.basename(endpoint).replace(/(\.git)?(#.*)?$/, '');
|
||||
else if (this.path) this.name = path.basename(this.path, this.assetType);
|
||||
else if (this.assetUrl) this.name = this.name = path.basename(this.assetUrl, this.assetType);
|
||||
else if (split) this.name = split[0];
|
||||
|
||||
this.explicitName = false;
|
||||
}
|
||||
|
||||
this.cacheName = this.name;
|
||||
|
||||
// Store a reference to the original tag & original path
|
||||
// This is because the tag & paths can get rewritten later
|
||||
if (this.tag) this.originalTag = this.tag;
|
||||
if (this.path) this.originalPath = endpoint;
|
||||
if (this.assetUrl) this.originalAssetUrl = this.assetUrl;
|
||||
|
||||
// The id is an unique id that describes this package
|
||||
this.id = crypto.createHash('md5').update(this.name + '%' + this.tag + '%' + this.gitUrl + '%' + this.path + '%' + this.assetUrl).digest('hex');
|
||||
|
||||
// Generate a resource id
|
||||
if (this.gitUrl) this.generateResourceId();
|
||||
}
|
||||
|
||||
if (this.manager) {
|
||||
this.on('data', this.manager.emit.bind(this.manager, 'data'));
|
||||
this.on('warn', this.manager.emit.bind(this.manager, 'warn'));
|
||||
this.on('error', function (err, origin) {
|
||||
// Unlock the unit of work automatically on error (only if the error is from this package)
|
||||
if (!origin && this.unitWork.isLocked(this.cacheName)) this.unitWork.unlock(this.cacheName, this);
|
||||
// Propagate the error event to the parent package/manager
|
||||
this.manager.emit('error', err, origin || this);
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
// Cache a self bound function
|
||||
this.waitUnlock = this.waitUnlock.bind(this);
|
||||
|
||||
this.setMaxListeners(30); // Increase the number of listeners because a package can have more than the default 10 dependencies
|
||||
};
|
||||
|
||||
Package.prototype = Object.create(events.EventEmitter.prototype);
|
||||
|
||||
Package.prototype.constructor = Package;
|
||||
|
||||
Package.prototype.resolve = function () {
|
||||
// Ensure that nobody is resolving the same dep at the same time
|
||||
// If there is, we wait for the unlock event
|
||||
if (this.unitWork.isLocked(this.cacheName)) return this.unitWork.on('unlock', this.waitUnlock);
|
||||
|
||||
var data = this.unitWork.retrieve(this.cacheName);
|
||||
if (data) {
|
||||
// Check if this exact package is the last resolved one
|
||||
// If so, we copy the resolved result and we don't need to do anything else
|
||||
if (data.id === this.id) {
|
||||
this.unserialize(data);
|
||||
this.emit('resolve');
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
// If not, we lock and resolve it
|
||||
this.unitWork.lock(this.cacheName, this);
|
||||
|
||||
if (this.assetUrl) {
|
||||
this.download();
|
||||
} else if (this.gitUrl) {
|
||||
this.clone();
|
||||
} else if (this.path) {
|
||||
this.copy();
|
||||
} else {
|
||||
this.once('lookup', this.clone).lookup();
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Package.prototype.lookup = function () {
|
||||
source.lookup(this.name, function (err, url) {
|
||||
if (err) return this.emit('error', err);
|
||||
this.lookedUp = true;
|
||||
this.gitUrl = url;
|
||||
this.generateResourceId();
|
||||
this.emit('lookup');
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.install = function () {
|
||||
// Only print the installing action if this package has been resolved
|
||||
if (this.unitWork.retrieve(this.cacheName)) {
|
||||
template('action', { name: 'installing', shizzle: this.name + (this.version ? '#' + this.version : '') })
|
||||
.on('data', this.emit.bind(this, 'data'));
|
||||
}
|
||||
|
||||
var localPath = this.localPath;
|
||||
|
||||
if (path.resolve(this.path) === localPath) {
|
||||
this.emit('install');
|
||||
return this;
|
||||
}
|
||||
|
||||
// Remove stuff from the local path (if any)
|
||||
// Rename path to the local path
|
||||
// Beware that if the local path exists and is a git repository, the process is aborted
|
||||
isRepo(localPath, function (is) {
|
||||
if (is) {
|
||||
var err = new Error('Local path is a local repository');
|
||||
err.details = 'To avoid losing work, please remove ' + localPath + ' manually.';
|
||||
return this.emit('error', err, this);
|
||||
}
|
||||
|
||||
mkdirp(path.dirname(localPath), function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
rimraf(localPath, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
return fs.rename(this.path, localPath, function (err) {
|
||||
if (!err) return this.cleanUpLocal();
|
||||
|
||||
var writter = fstream.Writer({
|
||||
type: 'Directory',
|
||||
path: localPath
|
||||
});
|
||||
writter
|
||||
.on('error', this.emit.bind(this, 'error'))
|
||||
.on('end', rimraf.bind(this, this.path, this.cleanUpLocal.bind(this)));
|
||||
|
||||
fstream.Reader(this.path)
|
||||
.on('error', this.emit.bind(this, 'error'))
|
||||
.pipe(writter);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Package.prototype.cleanUpLocal = function () {
|
||||
this.once('readLocalConfig', function () {
|
||||
this.json.name = this.name;
|
||||
this.json.version = this.commit ? '0.0.0' : this.version || '0.0.0';
|
||||
|
||||
// Detect commit and save it in the json for later use
|
||||
if (this.commit) this.json.commit = this.commit;
|
||||
else delete this.json.commit;
|
||||
|
||||
if (this.gitUrl) this.json.repository = { type: 'git', url: this.gitUrl };
|
||||
else if (this.gitPath) this.json.repository = { type: 'local-repo', path: this.originalPath };
|
||||
else if (this.originalPath) this.json.repository = { type: 'local', path: this.originalPath };
|
||||
else if (this.assetUrl) this.json = this.generateAssetJSON();
|
||||
|
||||
var jsonStr = JSON.stringify(this.json, null, 2);
|
||||
|
||||
// Save json file
|
||||
async.parallel({
|
||||
'local': function (next) {
|
||||
fs.writeFile(path.join(this.localPath, this.localConfig.json), jsonStr, next);
|
||||
}.bind(this),
|
||||
'git-path': function (next) {
|
||||
if (!this.gitPath) return next();
|
||||
fileExists(this.gitPath, function (exists) {
|
||||
if (!exists) return next();
|
||||
fs.writeFile(path.join(this.gitPath, this.localConfig.json), jsonStr, next);
|
||||
}.bind(this));
|
||||
}.bind(this)
|
||||
}, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
this.removeLocalPaths();
|
||||
}.bind(this));
|
||||
|
||||
}.bind(this)).readLocalConfig();
|
||||
};
|
||||
|
||||
// finish clean up local by removing .git/ and any ignored files
|
||||
Package.prototype.removeLocalPaths = function () {
|
||||
var removePatterns = ['.git'];
|
||||
if (this.json.ignore) {
|
||||
removePatterns.push.apply(removePatterns, this.json.ignore);
|
||||
}
|
||||
|
||||
var removePaths = [];
|
||||
|
||||
// 3: done
|
||||
var pathsRemoved = function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
this.emit('install');
|
||||
}.bind(this);
|
||||
|
||||
// 2: trigger after paths have been globbed
|
||||
var rimrafPaths = function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
async.forEach(removePaths, function (removePath, next) {
|
||||
// rimraf all the paths
|
||||
rimraf(path.join(this.localPath, removePath), next);
|
||||
}.bind(this), pathsRemoved);
|
||||
}.bind(this);
|
||||
|
||||
// 1: get paths
|
||||
var globOpts = { dot: true, cwd: this.localPath };
|
||||
async.forEach(removePatterns, function (removePattern, next) {
|
||||
// glob path for file path pattern matching
|
||||
glob(removePattern, globOpts, function (err, globPaths) {
|
||||
if (err) return next(err);
|
||||
removePaths.push.apply(removePaths, globPaths);
|
||||
next();
|
||||
}.bind(this));
|
||||
}.bind(this), rimrafPaths);
|
||||
};
|
||||
|
||||
Package.prototype.generateAssetJSON = function () {
|
||||
return {
|
||||
name: this.name,
|
||||
main: this.assetType !== '.zip' && this.assetType !== '.tar' ? 'index' + this.assetType : '',
|
||||
version: '0.0.0',
|
||||
repository: { type: 'asset', url: this.originalAssetUrl }
|
||||
};
|
||||
};
|
||||
|
||||
Package.prototype.uninstall = function () {
|
||||
template('action', { name: 'uninstalling', shizzle: this.path })
|
||||
.on('data', this.emit.bind(this, 'data'));
|
||||
rimraf(this.path, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
this.emit('uninstall');
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
// Private
|
||||
Package.prototype.findJSON = function () {
|
||||
fallback(this.path, [config.json, 'bower.json', 'component.json'], function (name) {
|
||||
if (name) {
|
||||
if (name === 'component.json') {
|
||||
this.emit('warn', 'Package ' + this.name + ' is still using the deprecated "component.json" file');
|
||||
}
|
||||
this.localConfig.json = name;
|
||||
}
|
||||
this.emit('readLocalConfig');
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.readLocalConfig = function () {
|
||||
if (this.localConfig) return this.emit('readLocalConfig');
|
||||
|
||||
fs.readFile(path.join(this.path, '.bowerrc'), function (err, file) {
|
||||
// If the local .bowerrc file do not exists then we check if the
|
||||
// json specific in the config exists (if not, we fallback to bower.json)
|
||||
if (err) {
|
||||
this.localConfig = { json: config.json };
|
||||
this.findJSON();
|
||||
} else {
|
||||
// If the local .bowerrc file exists, we read it and check if a custom json file
|
||||
// is defined. If not, we check if the global config json file exists (if not, we fallback to bower.json)
|
||||
try {
|
||||
this.localConfig = JSON.parse(file);
|
||||
} catch (e) {
|
||||
return this.emit('error', new Error('Unable to parse local .bowerrc file: ' + e.message));
|
||||
}
|
||||
|
||||
if (!this.localConfig.json) {
|
||||
this.localConfig.json = config.json;
|
||||
return this.findJSON();
|
||||
}
|
||||
|
||||
this.emit('readLocalConfig');
|
||||
}
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.loadJSON = function () {
|
||||
if (!this.path || this.assetUrl) return this.emit('loadJSON');
|
||||
|
||||
this.once('readLocalConfig', function () {
|
||||
var jsonFile = path.join(this.path, this.localConfig.json);
|
||||
fileExists(jsonFile, function (exists) {
|
||||
// If the json does not exists, we attempt to get the version
|
||||
if (!exists) {
|
||||
return this.once('describeTag', function (tag) {
|
||||
tag = semver.clean(tag);
|
||||
if (!tag) this.version = this.tag;
|
||||
else {
|
||||
this.version = tag;
|
||||
if (!this.tag) this.tag = this.version;
|
||||
}
|
||||
|
||||
this.emit('loadJSON');
|
||||
}.bind(this)).describeTag();
|
||||
}
|
||||
|
||||
readJSON(jsonFile, function (err, json) {
|
||||
if (err) {
|
||||
err.details = 'An error was caught when reading the ' + this.localConfig.json + ': ' + err.message;
|
||||
return this.emit('error', err);
|
||||
}
|
||||
|
||||
this.json = json;
|
||||
this.version = this.commit || json.commit || json.version;
|
||||
this.commit = this.commit || json.commit;
|
||||
// Only overwrite the name if not already set
|
||||
// This is because some packages have different names declared in the registry and the json
|
||||
if (!this.name || !this.explicitName) {
|
||||
this.name = json.name;
|
||||
}
|
||||
|
||||
// Read the endpoint from the json to ensure it is set correctly
|
||||
this.readEndpoint();
|
||||
|
||||
// Detect if the tag mismatches the json.version
|
||||
// This is very often to happen because developers tag their new releases but forget to update the json accordingly
|
||||
var cleanedTag;
|
||||
if (this.tag && (cleanedTag = semver.clean(this.tag)) && cleanedTag !== this.version) {
|
||||
// Only print the warning once
|
||||
if (!this.unitWork.retrieve('mismatch#' + this.cacheName + '_' + cleanedTag)) {
|
||||
template('warning-mismatch', { name: this.cacheName, json: this.localConfig.json, tag: cleanedTag, version: this.version || 'N/A' })
|
||||
.on('data', this.emit.bind(this, 'data'));
|
||||
this.unitWork.store('mismatch#' + this.cacheName + '_' + cleanedTag, true);
|
||||
}
|
||||
// Assume the tag
|
||||
this.version = cleanedTag;
|
||||
}
|
||||
|
||||
this.emit('loadJSON');
|
||||
}.bind(this), this);
|
||||
}.bind(this));
|
||||
}.bind(this)).readLocalConfig();
|
||||
};
|
||||
|
||||
Package.prototype.download = function () {
|
||||
template('action', { name: 'downloading', shizzle: this.assetUrl })
|
||||
.on('data', this.emit.bind(this, 'data'));
|
||||
|
||||
var src;
|
||||
|
||||
if (config.proxy) {
|
||||
src = url.parse(config.proxy);
|
||||
src.path = this.assetUrl;
|
||||
} else {
|
||||
src = url.parse(this.assetUrl);
|
||||
}
|
||||
|
||||
tmp.dir({
|
||||
prefix: 'bower-' + this.name + '-',
|
||||
mode: parseInt('0777', 8) & (~process.umask()),
|
||||
unsafeCleanup: true
|
||||
}, function (err, tmpPath) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
var req = src.protocol === 'https:' ? https : http;
|
||||
req.get(src, function (res) {
|
||||
// If assetUrl results in a redirect we update the assetUrl to the redirect to url
|
||||
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
||||
template('action', { name: 'redirect detected', shizzle: res.headers.location})
|
||||
.on('data', this.emit.bind(this, 'data'));
|
||||
this.assetUrl = res.headers.location;
|
||||
return this.download();
|
||||
}
|
||||
|
||||
// Detect not OK status codes
|
||||
if (res.statusCode < 200 || res.statusCode >= 300) {
|
||||
return this.emit('error', new Error(res.statusCode + ' status code for ' + this.assetUrl));
|
||||
}
|
||||
|
||||
var file = fs.createWriteStream(path.join((this.path = tmpPath), 'index' + this.assetType));
|
||||
|
||||
res.on('data', function (data) {
|
||||
file.write(data);
|
||||
});
|
||||
|
||||
res.on('end', function () {
|
||||
file.end();
|
||||
|
||||
var next = function () {
|
||||
this.once('loadJSON', this.saveUnit).loadJSON();
|
||||
}.bind(this);
|
||||
|
||||
if (this.assetType === '.zip' || this.assetType === '.tar') this.once('extract', next).extract();
|
||||
else next();
|
||||
}.bind(this));
|
||||
}.bind(this)).on('error', this.emit.bind(this, 'error'));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.extract = function () {
|
||||
var file = path.join(this.path, 'index' + this.assetType);
|
||||
template('action', { name: 'extracting', shizzle: file }).on('data', this.emit.bind(this, 'data'));
|
||||
|
||||
fs.createReadStream(file).pipe(this.assetType === '.zip' ? unzip.Extract({ path: this.path }) : tar.Extract({ path: this.path }))
|
||||
.on('error', this.emit.bind(this, 'error'))
|
||||
.on('close', function () {
|
||||
// Delete zip
|
||||
fs.unlink(file, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
// If we extracted only a folder, move all the files within it to the original path
|
||||
fs.readdir(this.path, function (err, files) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
if (files.length !== 1) return this.emit('extract');
|
||||
|
||||
var dir = path.join(this.path, files[0]);
|
||||
fs.stat(dir, function (err, stat) {
|
||||
if (err) return this.emit('error', err);
|
||||
if (!stat.isDirectory()) return this.emit('extract');
|
||||
|
||||
fs.readdir(dir, function (err, files) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
async.forEachSeries(files, function (file, next) {
|
||||
fs.rename(path.join(dir, file), path.join(this.path, file), next);
|
||||
}.bind(this), function (err) {
|
||||
if (err) return this.emit('error');
|
||||
|
||||
fs.rmdir(dir, function (err) {
|
||||
if (err) return this.emit('error');
|
||||
this.emit('extract');
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.copy = function () {
|
||||
template('action', { name: 'copying', shizzle: this.path }).on('data', this.emit.bind(this, 'data'));
|
||||
|
||||
tmp.dir({
|
||||
prefix: 'bower-' + this.name + '-',
|
||||
unsafeCleanup: true
|
||||
}, function (err, tmpPath) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
fs.stat(this.path, function (err, stats) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
// Copy file permission for directory
|
||||
fs.chmod(tmpPath, stats.mode, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
if (this.assetType) {
|
||||
return fs.readFile(this.path, function (err, data) {
|
||||
fs.writeFile(path.join((this.path = tmpPath), 'index' + this.assetType), data, function () {
|
||||
this.once('loadJSON', this.saveUnit).loadJSON();
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
this.once('loadJSON', function () {
|
||||
if (this.gitUrl) return this.saveUnit();
|
||||
|
||||
// Check if the copied directory is a git repository and is a local endpoint
|
||||
// If so, treat it like a repository.
|
||||
fileExists(path.join(this.path, '.git'), function (exists) {
|
||||
if (!exists) return this.saveUnit();
|
||||
|
||||
this.gitPath = this.path;
|
||||
this.once('loadJSON', this.saveUnit.bind(this)).checkout();
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
|
||||
var writter = fstream.Writer({
|
||||
type: 'Directory',
|
||||
path: tmpPath
|
||||
})
|
||||
.on('error', this.emit.bind(this, 'error'))
|
||||
.on('end', this.loadJSON.bind(this));
|
||||
|
||||
fstream.Reader(this.path)
|
||||
.on('error', this.emit.bind(this, 'error'))
|
||||
.pipe(writter);
|
||||
|
||||
this.path = tmpPath;
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.getDeepDependencies = function (result) {
|
||||
result = result || [];
|
||||
for (var name in this.dependencies) {
|
||||
result.push(this.dependencies[name]);
|
||||
this.dependencies[name].getDeepDependencies(result);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
Package.prototype.saveUnit = function () {
|
||||
this.unitWork.store(this.cacheName, this.serialize(), this);
|
||||
this.unitWork.unlock(this.cacheName, this);
|
||||
this.addDependencies();
|
||||
};
|
||||
|
||||
Package.prototype.addDependencies = function () {
|
||||
var dependencies = this.json.dependencies || {};
|
||||
var callbacks = Object.keys(dependencies).map(function (name) {
|
||||
return function (callback) {
|
||||
var endpoint = dependencies[name];
|
||||
var pkg = new Package(name, endpoint, this);
|
||||
pkg.once('resolve', function () {
|
||||
this.dependencies[pkg.name] = pkg;
|
||||
callback();
|
||||
}.bind(this)).resolve();
|
||||
}.bind(this);
|
||||
}.bind(this));
|
||||
|
||||
async.parallel(callbacks, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
this.emit('resolve');
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.exists = function (callback) {
|
||||
fileExists(this.localPath, callback);
|
||||
};
|
||||
|
||||
Package.prototype.clone = function () {
|
||||
template('action', { name: 'cloning', shizzle: this.gitUrl }).on('data', this.emit.bind(this, 'data'));
|
||||
this.path = this.gitPath;
|
||||
this.once('cache', function () {
|
||||
this.once('loadJSON', this.copy.bind(this)).checkout();
|
||||
}.bind(this)).cache();
|
||||
};
|
||||
|
||||
Package.prototype.cache = function () {
|
||||
// If the force options is true, we need to erase from the cache
|
||||
// Be aware that a similar package might already flushed it
|
||||
// To prevent that we check the unit of work storage
|
||||
if (this.opts.force && !this.unitWork.retrieve('flushed#' + this.cacheName + '_' + this.resourceId)) {
|
||||
rimraf(this.path, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
this.unitWork.store('flushed#' + this.cacheName + '_' + this.resourceId, true);
|
||||
this.cache();
|
||||
}.bind(this));
|
||||
return this;
|
||||
}
|
||||
|
||||
mkdirp(config.cache, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
fileExists(this.path, function (exists) {
|
||||
if (exists) {
|
||||
template('action', { name: 'cached', shizzle: this.gitUrl }).on('data', this.emit.bind(this, 'data'));
|
||||
return this.emit('cache');
|
||||
}
|
||||
template('action', { name: 'caching', shizzle: this.gitUrl }).on('data', this.emit.bind(this, 'data'));
|
||||
var url = this.gitUrl;
|
||||
if (config.proxy) {
|
||||
url = url.replace(/^git:/, 'https:');
|
||||
}
|
||||
|
||||
mkdirp(this.path, function (err) {
|
||||
if (err) return this.emit('error', err);
|
||||
|
||||
var cp = git(['clone', url, this.path], null, this);
|
||||
cp.on('close', function (code) {
|
||||
if (code) return;
|
||||
this.emit('cache');
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.checkout = function () {
|
||||
template('action', { name: 'fetching', shizzle: this.name })
|
||||
.on('data', this.emit.bind(this, 'data'));
|
||||
|
||||
this.once('versions', function (versions) {
|
||||
if (!versions.length) {
|
||||
this.emit('checkout');
|
||||
this.loadJSON();
|
||||
}
|
||||
|
||||
// If tag is specified, try to satisfy it
|
||||
if (this.tag) {
|
||||
if (!semver.validRange(this.tag)) {
|
||||
return this.emit('error', new Error('Tag ' + this.tag + ' is not a valid semver range/version'));
|
||||
}
|
||||
|
||||
versions = versions.filter(function (version) {
|
||||
return semver.satisfies(version, this.tag);
|
||||
}.bind(this));
|
||||
|
||||
if (!versions.length) {
|
||||
var error = new Error('Could not find tag satisfying: ' + this.name + '#' + this.tag);
|
||||
error.details = 'The tag ' + this.tag + ' could not be found within the repository';
|
||||
return this.emit('error', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Use latest version
|
||||
this.tag = versions[0];
|
||||
if (!semver.valid(this.tag)) this.commit = this.tag; // If the version is not valid, then its a commit
|
||||
|
||||
if (this.tag) {
|
||||
template('action', {
|
||||
name: 'checking out',
|
||||
shizzle: this.name + '#' + this.tag
|
||||
}).on('data', this.emit.bind(this, 'data'));
|
||||
|
||||
// Checkout the tag
|
||||
git([ 'checkout', this.tag, '-f'], { cwd: this.path }, this).on('close', function (code) {
|
||||
if (code) return;
|
||||
// Ensure that checkout the tag as it is, removing all untracked files
|
||||
git(['clean', '-f', '-d'], { cwd: this.path }, this).on('close', function (code) {
|
||||
if (code) return;
|
||||
this.emit('checkout');
|
||||
this.loadJSON();
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}
|
||||
}).versions();
|
||||
};
|
||||
|
||||
Package.prototype.describeTag = function () {
|
||||
var cp = git(['describe', '--always', '--tag'], { cwd: this.gitPath || this.path, ignoreCodes: [128] }, this);
|
||||
var tag = '';
|
||||
|
||||
cp.stdout.setEncoding('utf8');
|
||||
cp.stdout.on('data', function (data) {
|
||||
tag += data;
|
||||
});
|
||||
|
||||
cp.on('close', function (code) {
|
||||
if (code === 128) tag = 'unspecified'; // Not a git repo
|
||||
this.emit('describeTag', tag.replace(/\n$/, ''));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.versions = function () {
|
||||
this.once('fetch', function () {
|
||||
var cp = git(['tag'], { cwd: this.gitPath }, this);
|
||||
|
||||
var versions = '';
|
||||
|
||||
cp.stdout.setEncoding('utf8');
|
||||
cp.stdout.on('data', function (data) {
|
||||
versions += data;
|
||||
});
|
||||
|
||||
cp.on('close', function (code) {
|
||||
if (code) return;
|
||||
versions = versions.split('\n');
|
||||
versions = versions.filter(function (ver) {
|
||||
return semver.valid(ver);
|
||||
});
|
||||
versions = versions.sort(function (a, b) {
|
||||
return semver.gt(a, b) ? -1 : 1;
|
||||
});
|
||||
|
||||
if (versions.length) return this.emit('versions', versions);
|
||||
|
||||
// If there is no versions tagged in the repo
|
||||
// then we grab the hash of the last commit
|
||||
versions = '';
|
||||
cp = git(['log', '-n', 1, '--format=%H'], { cwd: this.gitPath }, this);
|
||||
|
||||
cp.stdout.setEncoding('utf8');
|
||||
cp.stdout.on('data', function (data) {
|
||||
versions += data;
|
||||
});
|
||||
cp.on('close', function (code) {
|
||||
if (code) return;
|
||||
versions = _.compact(versions.split('\n'));
|
||||
this.emit('versions', versions);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this)).fetch();
|
||||
};
|
||||
|
||||
Package.prototype.fetch = function () {
|
||||
fileExists(this.gitPath, function (exists) {
|
||||
if (!exists) return this.emit('error', new Error('Unable to fetch package ' + this.name + ' (if the cache was deleted, run install again)'));
|
||||
|
||||
var cp = git(['fetch', '--prune'], { cwd: this.gitPath }, this);
|
||||
cp.on('close', function (code) {
|
||||
if (code) return;
|
||||
cp = git(['reset', '--hard', this.gitUrl ? 'origin/HEAD' : 'HEAD'], { cwd: this.gitPath }, this);
|
||||
cp.on('close', function (code) {
|
||||
if (code) return;
|
||||
this.emit('fetch');
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Package.prototype.readEndpoint = function (replace) {
|
||||
if (!this.json.repository) return;
|
||||
|
||||
if (this.json.repository.type === 'git') {
|
||||
if (replace || !this.gitUrl) {
|
||||
this.gitUrl = this.json.repository.url;
|
||||
this.generateResourceId();
|
||||
}
|
||||
return { type: 'git', endpoint: this.gitUrl };
|
||||
}
|
||||
if (this.json.repository.type === 'local-repo') {
|
||||
if (replace || !this.gitPath) {
|
||||
this.gitPath = path.resolve(this.json.repository.path);
|
||||
}
|
||||
return { type: 'local', endpoint: this.path };
|
||||
}
|
||||
if (this.json.repository.type === 'local') {
|
||||
if (replace || !this.originalPath) {
|
||||
this.originalPath = this.path = path.resolve(this.json.repository.path);
|
||||
}
|
||||
return { type: 'local', endpoint: this.originalPath };
|
||||
}
|
||||
if (this.json.repository.type === 'asset') {
|
||||
if (replace || !this.assetUrl) {
|
||||
this.originalAssetUrl = this.assetUrl = this.json.repository.url;
|
||||
this.assetType = path.extname(this.assetUrl);
|
||||
}
|
||||
return { type: 'asset', endpoint: this.originalAssetUrl };
|
||||
}
|
||||
};
|
||||
|
||||
Package.prototype.waitUnlock = function (name) {
|
||||
if (this.name === name) {
|
||||
this.unitWork.removeListener('unlock', this.waitUnlock);
|
||||
this.resolve();
|
||||
}
|
||||
};
|
||||
|
||||
Package.prototype.serialize = function () {
|
||||
return {
|
||||
id: this.id,
|
||||
resourceId: this.resourceId,
|
||||
path: this.path,
|
||||
originalPath: this.originalPath,
|
||||
tag: this.tag,
|
||||
originalTag: this.originalTag,
|
||||
commit: this.commit,
|
||||
assetUrl: this.assetUrl,
|
||||
originalAssetUrl: this.originalAssetUrl,
|
||||
assetType: this.assetType,
|
||||
lookedUp: this.lookedUp,
|
||||
json: this.json,
|
||||
gitUrl: this.gitUrl,
|
||||
gitPath: this.gitPath,
|
||||
dependencies: this.dependencies,
|
||||
localConfig: this.localConfig
|
||||
};
|
||||
};
|
||||
|
||||
Package.prototype.unserialize = function (obj) {
|
||||
for (var key in obj) {
|
||||
this[key] = obj[key];
|
||||
}
|
||||
|
||||
this.version = this.tag;
|
||||
};
|
||||
|
||||
Package.prototype.generateResourceId = function () {
|
||||
this.resourceId = crypto.createHash('md5').update(this.gitUrl).digest('hex');
|
||||
this.gitPath = path.join(config.cache, this.cacheName, this.resourceId);
|
||||
};
|
||||
|
||||
Package.prototype.resolveShorthand = function (shorthand, path) {
|
||||
shorthand = hogan.compile(shorthand);
|
||||
|
||||
var parts = path.split('/');
|
||||
|
||||
return shorthand.render({
|
||||
organization: parts[0],
|
||||
package: parts[1],
|
||||
endpoint: path
|
||||
});
|
||||
};
|
||||
|
||||
Object.defineProperty(Package.prototype, 'localPath', {
|
||||
get: function () {
|
||||
return path.join(process.cwd(), config.directory, this.name);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Package;
|
||||
@@ -1,146 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Source Api
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var request = require('request');
|
||||
var config = require('./config');
|
||||
|
||||
var endpoint = config.endpoint + '/packages';
|
||||
|
||||
if (config.proxy) {
|
||||
request = request.defaults({ proxy: config.proxy, timeout: 5000 });
|
||||
}
|
||||
|
||||
|
||||
// allow for searchpath endpoints to be used for search and lookup
|
||||
var endpoints = [];
|
||||
endpoints.push(endpoint);
|
||||
if (config.searchpath) {
|
||||
for (var i = 0; i < config.searchpath.length; i += 1) {
|
||||
endpoints.push(config.searchpath[i] + '/packages');
|
||||
}
|
||||
}
|
||||
|
||||
exports.lookup = function (name, callback) {
|
||||
// walk all endpoints to find the first matching component
|
||||
var f = function (i) {
|
||||
var endpoint = endpoints[i];
|
||||
request.get(endpoint + '/' + encodeURIComponent(name), function (err, response, body) {
|
||||
if (err || (response.statusCode !== 200 && response.statusCode !== 404)) {
|
||||
return callback(err || new Error(name + ' failed to look up for endpoint: ' + endpoint));
|
||||
}
|
||||
|
||||
if (response && response.statusCode !== 404) {
|
||||
callback(err, body && JSON.parse(body).url);
|
||||
} else {
|
||||
if (i + 1 < endpoints.length) f(i + 1);
|
||||
else return callback(new Error(name + ' not found'));
|
||||
}
|
||||
});
|
||||
};
|
||||
f(0);
|
||||
};
|
||||
|
||||
exports.register = function (name, url, callback) {
|
||||
var body = {name: name, url: url};
|
||||
|
||||
request.post({url: endpoint, form: body}, function (err, response) {
|
||||
if (err) return callback(err);
|
||||
|
||||
if (response.statusCode === 406) {
|
||||
return callback(new Error('Duplicate package'));
|
||||
}
|
||||
|
||||
if (response.statusCode === 400) {
|
||||
return callback(new Error('Incorrect format'));
|
||||
}
|
||||
|
||||
if (response.statusCode !== 201) {
|
||||
return callback(new Error('Unknown error: ' + response.statusCode));
|
||||
}
|
||||
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
exports.search = function (name, callback) {
|
||||
// walk all endpoints to produced federated search results
|
||||
var f = function (i, map, results) {
|
||||
var endpoint = endpoints[i];
|
||||
|
||||
request.get(endpoint + '/search/' + encodeURIComponent(name), function (err, response, body) {
|
||||
if (err || (response.statusCode !== 200 && response.statusCode !== 404)) {
|
||||
return callback(err || new Error(name + ' failed to look up for endpoint: ' + endpoint));
|
||||
}
|
||||
|
||||
if (response && response.statusCode !== 404) {
|
||||
var array = body && JSON.parse(body);
|
||||
for (var x = 0; x < array.length; x += 1) {
|
||||
var pkgName = array[x].name;
|
||||
if (!map[pkgName]) {
|
||||
map[pkgName] = pkgName;
|
||||
results.push({ name: pkgName, url: array[x].url, endpoint: array[x].endpoint });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i + 1 < endpoints.length) f(i + 1, map, results);
|
||||
else return callback(null, results);
|
||||
});
|
||||
};
|
||||
|
||||
f(0, {}, []);
|
||||
};
|
||||
|
||||
exports.info = function (name, callback) {
|
||||
exports.lookup(name, function (err, url) {
|
||||
if (err) return callback(err);
|
||||
|
||||
var Package = require('./package');
|
||||
var pkg = new Package(name, url);
|
||||
|
||||
pkg.once('error', function (err) {
|
||||
pkg.removeAllListeners();
|
||||
callback(err);
|
||||
});
|
||||
pkg.once('resolve', function () {
|
||||
pkg.once('versions', function (versions) {
|
||||
pkg.removeAllListeners();
|
||||
callback(null, { pkg: pkg, versions: versions });
|
||||
}).versions();
|
||||
}).resolve();
|
||||
});
|
||||
};
|
||||
|
||||
exports.all = function (callback) {
|
||||
// walk all endpoints to produced federated search results
|
||||
var f = function (i, map, results) {
|
||||
var endpoint = endpoints[i];
|
||||
|
||||
request.get(endpoint, function (err, response, body) {
|
||||
if (err || (response.statusCode !== 200 && response.statusCode !== 404)) {
|
||||
return callback(err || new Error('Failed to look up endpoint: ' + endpoint));
|
||||
}
|
||||
|
||||
if (response && response.statusCode !== 404) {
|
||||
var array = body && JSON.parse(body);
|
||||
for (var x = 0; x < array.length; x += 1) {
|
||||
var pkgName = array[x].name;
|
||||
if (!map[pkgName]) {
|
||||
map[pkgName] = pkgName;
|
||||
results.push({ name: pkgName, url: array[x].url, endpoint: array[x].endpoint });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i + 1 < endpoints.length) f(i + 1, map, results);
|
||||
else return callback(null, results);
|
||||
});
|
||||
};
|
||||
|
||||
f(0, {}, []);
|
||||
};
|
||||
@@ -1,64 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Package Object Definition
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
// Events:
|
||||
// - lock: fired when a lock write over a key is acquired
|
||||
// - unlock: fired when an unlock write over a key is acquired
|
||||
// ==========================================
|
||||
|
||||
var events = require('events');
|
||||
|
||||
var UnitWork = function () {
|
||||
this.locks = [];
|
||||
this.data = [];
|
||||
|
||||
this.setMaxListeners(100); // Increase the number of listeners because this is a central storage
|
||||
};
|
||||
|
||||
UnitWork.prototype = Object.create(events.EventEmitter.prototype);
|
||||
|
||||
UnitWork.prototype.constructor = UnitWork;
|
||||
|
||||
UnitWork.prototype.lock = function (key, owner) {
|
||||
if (this.locks[key]) throw new Error('A write lock for "' + key + '" was already acquired.');
|
||||
if (!owner) throw new Error('A lock requires an owner.');
|
||||
this.locks[key] = owner;
|
||||
|
||||
return this.emit('lock', key);
|
||||
};
|
||||
|
||||
UnitWork.prototype.unlock = function (key, owner) {
|
||||
if (!owner) throw new Error('A write lock requires an owner.');
|
||||
if (this.locks[key]) {
|
||||
if (this.locks[key] !== owner) throw new Error('Lock owner for "' + key + '" mismatch.');
|
||||
delete this.locks[key];
|
||||
this.emit('unlock', key);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
UnitWork.prototype.isLocked = function (key) {
|
||||
return !!this.locks[key];
|
||||
};
|
||||
|
||||
UnitWork.prototype.store = function (key, data, owner) {
|
||||
if (this.locks[key] && owner !== this.locks[key]) throw new Error('A write lock for "' + key + '" is acquired therefore only its owner can write to it.');
|
||||
this.data[key] = data;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
UnitWork.prototype.retrieve = function (key) {
|
||||
return this.data[key];
|
||||
};
|
||||
|
||||
UnitWork.prototype.keys = function () {
|
||||
return Object.keys(this.data);
|
||||
};
|
||||
|
||||
module.exports = UnitWork;
|
||||
20
lib/index.js
20
lib/index.js
@@ -1,20 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Public API Definition
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var abbrev = require('abbrev');
|
||||
var commands = require('./commands');
|
||||
|
||||
var abbreviations = abbrev(Object.keys(commands));
|
||||
abbreviations.i = 'install';
|
||||
abbreviations.rm = 'uninstall';
|
||||
|
||||
module.exports = {
|
||||
commands: commands,
|
||||
abbreviations: abbreviations,
|
||||
config: require('./core/config')
|
||||
};
|
||||
@@ -1,65 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: completion
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
// This module exposes a simple helper to parse the environment variables in
|
||||
// case of a tab completion command. It parses the provided `argv` (nopt's
|
||||
// remain arguments after `--`) and `env` (should be process.env)
|
||||
//
|
||||
// It is inspired and based off Isaac's work on npm.
|
||||
|
||||
module.exports = function (argv, env) {
|
||||
var opts = {};
|
||||
|
||||
// w is the words number, based on the cursor position
|
||||
opts.w = +env.COMP_CWORD;
|
||||
|
||||
// words is the escaped sequence of words following `bower`
|
||||
opts.words = argv.map(function (word) {
|
||||
return word.charAt(0) === '"' ?
|
||||
word.replace(/^"|"$/g, '') :
|
||||
word.replace(/\\ /g, ' ');
|
||||
});
|
||||
|
||||
// word is a shortcut to the last word in the line
|
||||
opts.word = opts.words[opts.w - 1];
|
||||
|
||||
// line is the sequence of tab completed words.
|
||||
opts.line = env.COMP_LINE;
|
||||
|
||||
// point is the cursor position in the line
|
||||
opts.point = +env.COMP_POINT;
|
||||
|
||||
// length is the whole line's length.
|
||||
opts.length = opts.line.length;
|
||||
|
||||
// partialLine is the line ignoring the sequence of characters after
|
||||
// cursor position, ie. tabbing at: bower install j|qu
|
||||
// gives back a partialLine: bower install j
|
||||
opts.partialLine = opts.line.slice(0, opts.point);
|
||||
|
||||
// partialWords is only returning the words based on cursor position,
|
||||
// ie tabbing at: bower install ze|pto backbone
|
||||
// gives back a partialWords array: ['install', 'zepto']
|
||||
opts.partialWords = opts.words.slice(0, opts.w);
|
||||
|
||||
return opts;
|
||||
};
|
||||
|
||||
module.exports.log = function (arr, opts) {
|
||||
arr = Array.isArray(arr) ? arr : [arr];
|
||||
arr.filter(module.exports.abbrev(opts)).forEach(function (word) {
|
||||
console.log(word);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.abbrev = function abbrev(opts) {
|
||||
var word = opts.word.replace(/\./g, '\\.');
|
||||
return function (it) {
|
||||
return new RegExp('^' + word).test(it);
|
||||
};
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: fallback
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
// A function that takes a list of files and returns the first one that exists
|
||||
// If none exists, return null
|
||||
|
||||
var fileExists = require('./file-exists');
|
||||
var path = require('path');
|
||||
|
||||
var fallback = function (baseDir, files, callback) {
|
||||
if (!Array.isArray(files) || files.length === 0) {
|
||||
return callback(null);
|
||||
}
|
||||
|
||||
var file = files.shift();
|
||||
|
||||
fileExists(path.join(baseDir, file), function (exists) {
|
||||
if (!exists) {
|
||||
return fallback(baseDir, files, callback);
|
||||
} else {
|
||||
return callback(file);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = fallback;
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: file-exists
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
// This module exposes a version of fs.exists and fs.existsSync with a correct behaviour
|
||||
// See: https://github.com/joyent/node/pull/2603
|
||||
|
||||
module.exports = function (path, callback) {
|
||||
fs.stat(path, function (error) {
|
||||
callback(!error || error.code !== 'ENOENT');
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.sync = function (path) {
|
||||
try {
|
||||
return !!fs.statSync(path);
|
||||
} catch (e) {
|
||||
return e.code !== 'ENOENT';
|
||||
}
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: git-cmd
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
// Extension of the spawn command, that only executes git commands
|
||||
// If a git command fails with code 128 in the cache, that directory
|
||||
// will be deleted to prevent more issues
|
||||
|
||||
var path = require('path');
|
||||
var spawn = require('./spawn');
|
||||
var rimraf = require('rimraf');
|
||||
var config = require('../core/config');
|
||||
|
||||
module.exports = function (args, options, emitter) {
|
||||
process.env.GIT_TEMPLATE_DIR = config.git_template;
|
||||
var cp = spawn('git', args, options, emitter);
|
||||
var cwd = options ? options.cwd || process.cwd() : process.cwd();
|
||||
var isTmp = path.normalize(cwd).indexOf(config.cache) === 0;
|
||||
|
||||
cp.on('exit', function (code) {
|
||||
if (code === 128 && isTmp) rimraf.sync(cwd);
|
||||
});
|
||||
|
||||
return cp;
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Hogan.js renderWithColors extension
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var colors = require('colors');
|
||||
var hogan = require('hogan.js');
|
||||
var _ = require('lodash');
|
||||
var nopt = require('nopt');
|
||||
|
||||
module.exports = hogan.Template.prototype.renderWithColors = function (context, partials, indent) {
|
||||
if (nopt(process.argv).color === false) {
|
||||
colors.mode = 'none';
|
||||
}
|
||||
|
||||
context = _.extend({
|
||||
yellow : function (s) { return s.yellow; },
|
||||
green : function (s) { return s.green; },
|
||||
cyan : function (s) { return s.cyan; },
|
||||
red : function (s) { return s.red; },
|
||||
white : function (s) { return s.white; }
|
||||
}, context);
|
||||
return this.ri([context], partials || {}, indent);
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: is-repo
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var fileExists = require('./file-exists');
|
||||
|
||||
// This module checks if a path is a local repository
|
||||
// If the repository is a link, it will be falsy
|
||||
module.exports = function (dir, callback) {
|
||||
fileExists(path.join(dir, '.git'), function (exists) {
|
||||
if (!exists) return callback(false);
|
||||
fs.lstat(dir, function (err, stat) {
|
||||
if (err) return callback(false);
|
||||
callback(!stat.isSymbolicLink());
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -1,103 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: prune
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var semver = require('semver');
|
||||
var sort = require('stable');
|
||||
|
||||
var versionRequirements = function (dependencyMap) {
|
||||
var result = {};
|
||||
|
||||
for (var name in dependencyMap) {
|
||||
dependencyMap[name].forEach(function (pkg) {
|
||||
result[name] = result[name] || [];
|
||||
if (pkg.originalTag && result[name].indexOf(pkg.originalTag) === -1) {
|
||||
result[name].push(pkg.originalTag);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var validVersions = function (versions, dependency) {
|
||||
if (!versions || !versions.length) return true;
|
||||
|
||||
// If a non resolved dependency is passed, we simply ignore it
|
||||
if (!dependency.version) return false;
|
||||
|
||||
if (!semver.valid(dependency.version)) {
|
||||
throw new Error('Invalid semver version ' + dependency.version + ' specified in ' + dependency.name);
|
||||
}
|
||||
|
||||
return versions.every(function (version) {
|
||||
return semver.satisfies(dependency.version, version);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = function (dependencyMap, forceLatest) {
|
||||
// generate version requirements
|
||||
// compare dependency map with version requirements
|
||||
// check for conflicts
|
||||
// select best version
|
||||
// return an object with the resolved deps, conflict deps and forcebly resolved ones
|
||||
|
||||
var resolved = {};
|
||||
var conflicted = null;
|
||||
var forceblyResolved = null;
|
||||
var versionMap = versionRequirements(dependencyMap);
|
||||
|
||||
var sortFunc = function (a, b) {
|
||||
if (semver.gt(a.version, b.version)) return -1;
|
||||
if (semver.lt(a.version, b.version)) return 1;
|
||||
|
||||
// If the comparison determines that both packages are equal, do not give priority to local ones
|
||||
if (a.path === a.localPath && b.path !== b.localPath) return 1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Note that bellow we use a stable sort algorithm
|
||||
// This is because if two packages are equal, the initial order should be respected
|
||||
|
||||
for (var name in dependencyMap) {
|
||||
var matches = dependencyMap[name].filter(validVersions.bind(this, versionMap[name]));
|
||||
if (!matches.length) {
|
||||
// No resolvable dependency
|
||||
// We resolve to the latest package if the forceLatest is true
|
||||
// Otherwise, check if any of those are root packages
|
||||
// If so, we assume that as the resolver (with a warning)
|
||||
// Otherwise there's a conflict
|
||||
if (forceLatest) {
|
||||
forceblyResolved = forceblyResolved || {};
|
||||
forceblyResolved[name] = sort(dependencyMap[name], sortFunc);
|
||||
continue;
|
||||
}
|
||||
|
||||
matches = dependencyMap[name].filter(function (pkg) { return !!pkg.root; });
|
||||
if (matches.length) {
|
||||
forceblyResolved = forceblyResolved || {};
|
||||
forceblyResolved[name] = dependencyMap[name].sort(function (a, b) {
|
||||
if (a.root && b.root) return sortFunc(a, b);
|
||||
if (a.root) return -1;
|
||||
if (b.root) return 1;
|
||||
return sortFunc(a, b);
|
||||
});
|
||||
} else {
|
||||
conflicted = conflicted || {};
|
||||
conflicted[name] = dependencyMap[name];
|
||||
}
|
||||
} else {
|
||||
resolved[name] = [ sort(matches, sortFunc)[0] ];
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
resolved: resolved,
|
||||
conflicted: conflicted,
|
||||
forceblyResolved: forceblyResolved
|
||||
};
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: read-json.js - with logging fun
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var readJSON = require('read-package-json');
|
||||
var template = require('./template');
|
||||
|
||||
var read = module.exports = function (path, cb, obj) {
|
||||
readJSON.log = {
|
||||
info: function () {},
|
||||
verbose: function () {},
|
||||
warn: function (what, name, shizzle) {
|
||||
if (read.showWarnings) {
|
||||
template('warn', { name: name.replace(/@/, '#'), shizzle: shizzle })
|
||||
.on('data', obj.emit.bind(obj, 'data'));
|
||||
}
|
||||
}
|
||||
};
|
||||
readJSON.cache.reset();
|
||||
readJSON(path, cb);
|
||||
};
|
||||
@@ -1,98 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: save
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var semver = require('semver');
|
||||
|
||||
var _ = require('lodash');
|
||||
|
||||
var config = require('../core/config');
|
||||
|
||||
function save(manager, paths, dev, cb) {
|
||||
// If there is specific paths to save, redirect to the appropriate function
|
||||
if (paths && paths.length) return savePkgs.apply(savePkgs, arguments);
|
||||
|
||||
manager.on('loadJSON', function (newLine) {
|
||||
manager.json.dependencies = manager.json.dependencies || {};
|
||||
manager.json.devDependencies = manager.json.devDependencies || {};
|
||||
|
||||
// Only include the root packages
|
||||
for (var name in manager.dependencies) {
|
||||
var curr = manager.dependencies[name][0];
|
||||
if (curr.root) {
|
||||
addDependency(manager.json, curr, !!manager.json.devDependencies[name]);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup dependencies from the json if empty
|
||||
if (!Object.keys(manager.json.dependencies).length) {
|
||||
delete manager.json.dependencies;
|
||||
}
|
||||
|
||||
// Cleanup dependencies if empty
|
||||
if (!Object.keys(manager.json.devDependencies).length) {
|
||||
delete manager.json.devDependencies;
|
||||
}
|
||||
|
||||
// Finally save the modified json
|
||||
var contents = JSON.stringify(manager.json, null, 2) + (newLine ? '\n' : '');
|
||||
fs.writeFile(path.join(manager.cwd, config.json), contents, cb);
|
||||
}).loadJSON();
|
||||
}
|
||||
|
||||
function savePkgs(manager, paths, dev, cb) {
|
||||
manager.on('loadJSON', function (newLine) {
|
||||
// Find the package names that match the paths
|
||||
var names = _.compact(paths.map(function (endpoint) {
|
||||
endpoint = endpoint.split('#')[0];
|
||||
|
||||
return _.find(Object.keys(manager.dependencies), function (key) {
|
||||
var dep = manager.dependencies[key][0];
|
||||
if (dep.name === endpoint) return true;
|
||||
if (dep.shorthand === endpoint) return true;
|
||||
|
||||
var fetchedEndpoint = dep.readEndpoint();
|
||||
return fetchedEndpoint && fetchedEndpoint.endpoint === endpoint;
|
||||
});
|
||||
}));
|
||||
|
||||
var key = dev ? 'devDependencies' : 'dependencies';
|
||||
manager.json[key] = manager.json[key] || {};
|
||||
|
||||
// Save each of them
|
||||
// Only include the root packages
|
||||
names.forEach(function (name) {
|
||||
addDependency(manager.json, manager.dependencies[name][0], dev);
|
||||
});
|
||||
|
||||
// Finally save the modified json
|
||||
var contents = JSON.stringify(manager.json, null, 2) + (newLine ? '\n' : '');
|
||||
fs.writeFile(path.join(manager.cwd, config.json), contents, cb);
|
||||
}).loadJSON();
|
||||
}
|
||||
|
||||
function addDependency(json, pkg, dev) {
|
||||
var path;
|
||||
var tag;
|
||||
var key = dev ? 'devDependencies' : 'dependencies';
|
||||
|
||||
if (pkg.lookedUp) {
|
||||
tag = pkg.originalTag || '~' + pkg.version;
|
||||
} else {
|
||||
path = (pkg.shorthand || pkg.gitUrl || pkg.originalAssetUrl || pkg.originalPath || '');
|
||||
tag = pkg.originalTag || '~' + pkg.version;
|
||||
}
|
||||
|
||||
// If the tag is not valid (e.g.: a commit), null it
|
||||
if (!semver.valid(tag) && !semver.validRange(tag)) tag = null;
|
||||
|
||||
json[key][pkg.name] = path ? path + (tag ? '#' + tag : '') : tag || 'latest';
|
||||
}
|
||||
|
||||
module.exports = save;
|
||||
@@ -1,36 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: spawn
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var spawn = require('child_process').spawn;
|
||||
|
||||
// This module is similar to child-process spawn
|
||||
// but automatically handles errors
|
||||
// When an error occurs, it emits the error event containing the details of the error
|
||||
// It also removes all the listeners of the command
|
||||
|
||||
module.exports = function (command, args, options, emitter) {
|
||||
var cp = spawn(command, args, options);
|
||||
var stderr = '';
|
||||
|
||||
cp.stderr.on('data', function (data) {
|
||||
stderr += data;
|
||||
});
|
||||
|
||||
cp.on('exit', function (code) {
|
||||
if (code && (!options || !options.ignoreCodes || options.ignoreCodes.indexOf(code) === -1)) {
|
||||
cp.removeAllListeners();
|
||||
var err = new Error('status code of ' + command + ': ' + code);
|
||||
err.details = stderr;
|
||||
err.command = command;
|
||||
err.code = code;
|
||||
emitter.emit('error', err);
|
||||
}
|
||||
});
|
||||
|
||||
return cp;
|
||||
};
|
||||
@@ -1,41 +0,0 @@
|
||||
// ==========================================
|
||||
// BOWER: Hogan Renderer w/ template cache
|
||||
// ==========================================
|
||||
// Copyright 2012 Twitter, Inc
|
||||
// Licensed under The MIT License
|
||||
// http://opensource.org/licenses/MIT
|
||||
// ==========================================
|
||||
|
||||
var events = require('events');
|
||||
var hogan = require('hogan.js');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
|
||||
require('../util/hogan-colors');
|
||||
|
||||
var templates = {};
|
||||
|
||||
module.exports = function (name, context, sync) {
|
||||
var emitter = new events.EventEmitter;
|
||||
|
||||
var templateName = name + '.mustache';
|
||||
var templatePath = path.join(__dirname, '../../templates/', templateName);
|
||||
|
||||
if (sync) {
|
||||
if (!templates[templatePath]) templates[templatePath] = fs.readFileSync(templatePath, 'utf-8');
|
||||
return hogan.compile(templates[templatePath]).renderWithColors(context);
|
||||
} else if (templates[templatePath]) {
|
||||
process.nextTick(function () {
|
||||
emitter.emit('data', hogan.compile(templates[templatePath]).renderWithColors(context));
|
||||
});
|
||||
} else {
|
||||
fs.readFile(templatePath, 'utf-8', function (err, file) {
|
||||
if (err) return emitter.emit('error', err);
|
||||
|
||||
templates[templatePath] = file;
|
||||
emitter.emit('data', hogan.compile(file).renderWithColors(context));
|
||||
});
|
||||
}
|
||||
|
||||
return emitter;
|
||||
};
|
||||
53
package.json
53
package.json
@@ -1,51 +1,10 @@
|
||||
{
|
||||
"name": "bower",
|
||||
"description": "The browser package manager.",
|
||||
"version": "0.9.0",
|
||||
"author": "Twitter",
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/twitter/bower/blob/master/LICENSE"
|
||||
}
|
||||
],
|
||||
"main": "lib",
|
||||
"homepage": "http://twitter.github.com/bower",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tmp": "~0.0.17",
|
||||
"glob": "~3.1.14",
|
||||
"nopt": "~2.0.0",
|
||||
"archy": "~0.0.2",
|
||||
"async": "~0.2.5",
|
||||
"colors": "~0.6.0-1",
|
||||
"rimraf": "~2.0.3",
|
||||
"mkdirp": "~0.3.4",
|
||||
"semver": "~1.1.0",
|
||||
"request": "~2.11.4",
|
||||
"fstream": "~0.1.19",
|
||||
"hogan.js": "~2.0.0",
|
||||
"lodash": "~1.0.1",
|
||||
"read-package-json": "~0.1.8",
|
||||
"stable": "~0.1.2",
|
||||
"rc": "~0.0.6",
|
||||
"unzip": "0.1.7",
|
||||
"tar": "~0.1.13",
|
||||
"promptly": "~0.1.0",
|
||||
"abbrev": "~1.0.4",
|
||||
"update-notifier": "~0.1.3"
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"lerna": "2.0.0-beta.23"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha --reporter spec --timeout 40000"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "~1.8.1",
|
||||
"nock": "~0.17.3"
|
||||
},
|
||||
"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
|
||||
@@ -9,7 +9,7 @@
|
||||
"beforeEach"
|
||||
],
|
||||
|
||||
"indent": 2,
|
||||
"indent": 4,
|
||||
"node": true,
|
||||
"devel": true,
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"noarg": true,
|
||||
"noempty": false,
|
||||
"nonew": true,
|
||||
"plusplus": true,
|
||||
"plusplus": false,
|
||||
"regexp": false,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
@@ -32,7 +32,7 @@
|
||||
"trailing": true,
|
||||
|
||||
"asi": false,
|
||||
"boss": false,
|
||||
"boss": true,
|
||||
"debug": false,
|
||||
"eqnull": true,
|
||||
"es5": false,
|
||||
@@ -57,6 +57,5 @@
|
||||
"validthis": false,
|
||||
|
||||
"nomen": false,
|
||||
"onevar": 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');
|
||||
};
|
||||
19
packages/bower-config/LICENSE
Normal file
19
packages/bower-config/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.
|
||||
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 @@
|
||||
{}
|
||||
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.*
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user