]>
Commit | Line | Data |
---|---|---|
91e44d91 S |
1 | /*! |
2 | * Bootstrap's Gruntfile | |
3 | * https://getbootstrap.com | |
4 | * Copyright 2013-2017 The Bootstrap Authors | |
5 | * Copyright 2013-2017 Twitter, Inc. | |
6 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |
7 | */ | |
8 | ||
9 | module.exports = function (grunt) { | |
10 | 'use strict' | |
11 | ||
12 | // Force use of Unix newlines | |
13 | grunt.util.linefeed = '\n' | |
14 | ||
15 | RegExp.quote = function (string) { | |
16 | return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&') | |
17 | } | |
18 | ||
19 | var path = require('path') | |
20 | var isTravis = require('is-travis') | |
21 | ||
22 | var configBridge = grunt.file.readJSON('./grunt/configBridge.json', { encoding: 'utf8' }) | |
23 | ||
24 | Object.keys(configBridge.paths).forEach(function (key) { | |
25 | configBridge.paths[key].forEach(function (val, i, arr) { | |
26 | arr[i] = path.join('./docs', val) | |
27 | }) | |
28 | }) | |
29 | ||
30 | // Project configuration. | |
31 | grunt.initConfig({ | |
32 | ||
33 | // Metadata. | |
34 | pkg: grunt.file.readJSON('package.json'), | |
35 | banner: '/*!\n' + | |
36 | ' * Bootstrap v<%= pkg.version %> (<%= pkg.homepage %>)\n' + | |
37 | ' * Copyright 2011-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' + | |
38 | ' * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n' + | |
39 | ' */\n', | |
40 | jqueryCheck: 'if (typeof jQuery === \'undefined\') {\n' + | |
41 | ' throw new Error(\'Bootstrap\\\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\\\'s JavaScript.\')\n' + | |
42 | '}\n', | |
43 | jqueryVersionCheck: '+function ($) {\n' + | |
44 | ' var version = $.fn.jquery.split(\' \')[0].split(\'.\')\n' + | |
45 | ' if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] >= 4)) {\n' + | |
46 | ' throw new Error(\'Bootstrap\\\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0\')\n' + | |
47 | ' }\n' + | |
48 | '}(jQuery);\n\n', | |
49 | ||
50 | // Task configuration. | |
51 | clean: { | |
52 | dist: 'dist', | |
53 | docs: 'docs/dist' | |
54 | }, | |
55 | ||
56 | // JS build configuration | |
57 | babel: { | |
58 | dev: { | |
59 | options: { | |
60 | sourceMap: true | |
61 | }, | |
62 | files: { | |
63 | 'js/dist/util.js' : 'js/src/util.js', | |
64 | 'js/dist/alert.js' : 'js/src/alert.js', | |
65 | 'js/dist/button.js' : 'js/src/button.js', | |
66 | 'js/dist/carousel.js' : 'js/src/carousel.js', | |
67 | 'js/dist/collapse.js' : 'js/src/collapse.js', | |
68 | 'js/dist/dropdown.js' : 'js/src/dropdown.js', | |
69 | 'js/dist/modal.js' : 'js/src/modal.js', | |
70 | 'js/dist/scrollspy.js' : 'js/src/scrollspy.js', | |
71 | 'js/dist/tab.js' : 'js/src/tab.js', | |
72 | 'js/dist/tooltip.js' : 'js/src/tooltip.js', | |
73 | 'js/dist/popover.js' : 'js/src/popover.js' | |
74 | } | |
75 | }, | |
76 | dist: { | |
77 | options: { | |
78 | extends: '../../js/.babelrc' | |
79 | }, | |
80 | files: { | |
81 | '<%= concat.bootstrap.dest %>' : '<%= concat.bootstrap.dest %>' | |
82 | } | |
83 | } | |
84 | }, | |
85 | ||
86 | stamp: { | |
87 | options: { | |
88 | banner: '<%= banner %>\n<%= jqueryCheck %>\n<%= jqueryVersionCheck %>\n+function () {\n', | |
89 | footer: '\n}();' | |
90 | }, | |
91 | bootstrap: { | |
92 | files: { | |
93 | src: '<%= concat.bootstrap.dest %>' | |
94 | } | |
95 | } | |
96 | }, | |
97 | ||
98 | concat: { | |
99 | options: { | |
100 | // Custom function to remove all export and import statements | |
101 | process: function (src) { | |
102 | return src.replace(/^(export|import).*/gm, '') | |
103 | } | |
104 | }, | |
105 | bootstrap: { | |
106 | src: [ | |
107 | 'js/src/util.js', | |
108 | 'js/src/alert.js', | |
109 | 'js/src/button.js', | |
110 | 'js/src/carousel.js', | |
111 | 'js/src/collapse.js', | |
112 | 'js/src/dropdown.js', | |
113 | 'js/src/modal.js', | |
114 | 'js/src/scrollspy.js', | |
115 | 'js/src/tab.js', | |
116 | 'js/src/tooltip.js', | |
117 | 'js/src/popover.js' | |
118 | ], | |
119 | dest: 'dist/js/<%= pkg.name %>.js' | |
120 | } | |
121 | }, | |
122 | ||
123 | qunit: { | |
124 | options: { | |
125 | inject: 'js/tests/unit/phantom.js' | |
126 | }, | |
127 | files: 'js/tests/index.html' | |
128 | }, | |
129 | ||
130 | // CSS build configuration | |
131 | copy: { | |
132 | docs: { | |
133 | expand: true, | |
134 | cwd: 'dist/', | |
135 | src: [ | |
136 | '**/*' | |
137 | ], | |
138 | dest: 'docs/dist/' | |
139 | } | |
140 | }, | |
141 | ||
142 | connect: { | |
143 | server: { | |
144 | options: { | |
145 | port: 3000, | |
146 | base: '.' | |
147 | } | |
148 | } | |
149 | }, | |
150 | ||
151 | jekyll: { | |
152 | options: { | |
153 | bundleExec: true, | |
154 | config: '_config.yml', | |
155 | incremental: false | |
156 | }, | |
157 | docs: {}, | |
158 | github: { | |
159 | options: { | |
160 | raw: 'github: true' | |
161 | } | |
162 | } | |
163 | }, | |
164 | ||
165 | htmllint: { | |
166 | options: { | |
167 | ignore: [ | |
168 | 'Attribute “autocomplete” is only allowed when the input type is “color”, “date”, “datetime”, “datetime-local”, “email”, “hidden”, “month”, “number”, “password”, “range”, “search”, “tel”, “text”, “time”, “url”, or “week”.', | |
169 | 'Attribute “autocomplete” not allowed on element “button” at this point.', | |
170 | 'Consider using the “h1” element as a top-level heading only (all “h1” elements are treated as top-level headings by many screen readers and other tools).', | |
171 | 'Element “div” not allowed as child of element “progress” in this context. (Suppressing further errors from this subtree.)', | |
172 | 'Element “img” is missing required attribute “src”.', | |
173 | 'The “color” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', | |
174 | 'The “date” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', | |
175 | 'The “datetime” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', | |
176 | 'The “datetime-local” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', | |
177 | 'The “month” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', | |
178 | 'The “time” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.', | |
179 | 'The “week” input type is not supported in all browsers. Please be sure to test, and consider using a polyfill.' | |
180 | ] | |
181 | }, | |
182 | src: ['_gh_pages/**/*.html', 'js/tests/visual/*.html'] | |
183 | }, | |
184 | ||
185 | watch: { | |
186 | src: { | |
187 | files: '<%= concat.bootstrap.src %>', | |
188 | tasks: ['babel:dev'] | |
189 | }, | |
190 | sass: { | |
191 | files: 'scss/**/*.scss', | |
192 | tasks: ['dist-css', 'docs'] | |
193 | }, | |
194 | docs: { | |
195 | files: 'docs/assets/scss/**/*.scss', | |
196 | tasks: ['dist-css', 'docs'] | |
197 | } | |
198 | }, | |
199 | ||
200 | 'saucelabs-qunit': { | |
201 | all: { | |
202 | options: { | |
203 | build: process.env.TRAVIS_JOB_ID, | |
204 | concurrency: 10, | |
205 | maxRetries: 3, | |
206 | maxPollRetries: 4, | |
207 | urls: ['http://127.0.0.1:3000/js/tests/index.html?hidepassed'], | |
208 | browsers: grunt.file.readYAML('grunt/sauce_browsers.yml') | |
209 | } | |
210 | } | |
211 | }, | |
212 | ||
213 | exec: { | |
214 | 'clean-css': { | |
215 | command: 'npm run clean-css' | |
216 | }, | |
217 | 'clean-css-docs': { | |
218 | command: 'npm run clean-css-docs' | |
219 | }, | |
220 | postcss: { | |
221 | command: 'npm run postcss' | |
222 | }, | |
223 | 'postcss-docs': { | |
224 | command: 'npm run postcss-docs' | |
225 | }, | |
226 | htmlhint: { | |
227 | command: 'npm run htmlhint' | |
228 | }, | |
229 | sass: { | |
230 | command: 'npm run sass' | |
231 | }, | |
232 | 'sass-docs': { | |
233 | command: 'npm run sass-docs' | |
234 | }, | |
235 | 'scss-lint': { | |
236 | command: 'npm run scss-lint' | |
237 | }, | |
238 | 'scss-lint-docs': { | |
239 | command: 'npm run scss-lint-docs' | |
240 | }, | |
241 | uglify: { | |
242 | command: 'npm run uglify' | |
243 | }, | |
244 | 'uglify-docs': { | |
245 | command: 'npm run uglify-docs' | |
246 | } | |
247 | }, | |
248 | ||
249 | buildcontrol: { | |
250 | options: { | |
251 | dir: '_gh_pages', | |
252 | commit: true, | |
253 | push: true, | |
254 | message: 'Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%' | |
255 | }, | |
256 | pages: { | |
257 | options: { | |
258 | remote: 'git@github.com:twbs/derpstrap.git', | |
259 | branch: 'gh-pages' | |
260 | } | |
261 | } | |
262 | }, | |
263 | ||
264 | compress: { | |
265 | main: { | |
266 | options: { | |
267 | archive: 'bootstrap-<%= pkg.version %>-dist.zip', | |
268 | mode: 'zip', | |
269 | level: 9, | |
270 | pretty: true | |
271 | }, | |
272 | files: [ | |
273 | { | |
274 | expand: true, | |
275 | cwd: 'dist/', | |
276 | src: ['**'], | |
277 | dest: 'bootstrap-<%= pkg.version %>-dist' | |
278 | } | |
279 | ] | |
280 | } | |
281 | } | |
282 | ||
283 | }) | |
284 | ||
285 | ||
286 | // These plugins provide necessary tasks. | |
287 | require('load-grunt-tasks')(grunt) | |
288 | require('time-grunt')(grunt) | |
289 | ||
290 | // Docs HTML validation task | |
291 | grunt.registerTask('validate-html', ['jekyll:docs', 'htmllint', 'exec:htmlhint']) | |
292 | ||
293 | var runSubset = function (subset) { | |
294 | return !process.env.TWBS_TEST || process.env.TWBS_TEST === subset | |
295 | } | |
296 | var isUndefOrNonZero = function (val) { | |
297 | return val === undefined || val !== '0' | |
298 | } | |
299 | ||
300 | // Test task. | |
301 | var testSubtasks = [] | |
302 | // Skip core tests if running a different subset of the test suite | |
303 | if (runSubset('core') && | |
304 | // Skip core tests if this is a Savage build | |
305 | process.env.TRAVIS_REPO_SLUG !== 'twbs-savage/bootstrap') { | |
306 | testSubtasks = testSubtasks.concat(['dist-css', 'dist-js', 'test-scss', 'qunit', 'docs']) | |
307 | } | |
308 | // Skip HTML validation if running a different subset of the test suite | |
309 | if (runSubset('validate-html') && | |
310 | isTravis && | |
311 | // Skip HTML5 validator when [skip validator] is in the commit message | |
312 | isUndefOrNonZero(process.env.TWBS_DO_VALIDATOR)) { | |
313 | testSubtasks.push('validate-html') | |
314 | } | |
315 | // Only run Sauce Labs tests if there's a Sauce access key | |
316 | if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined' && | |
317 | // Skip Sauce if running a different subset of the test suite | |
318 | runSubset('sauce-js-unit')) { | |
319 | testSubtasks = testSubtasks.concat(['dist', 'docs-css', 'docs-js', 'clean:docs', 'copy:docs']) | |
320 | // Skip Sauce on Travis when [skip sauce] is in the commit message | |
321 | if (isUndefOrNonZero(process.env.TWBS_DO_SAUCE)) { | |
322 | testSubtasks.push('connect') | |
323 | testSubtasks.push('saucelabs-qunit') | |
324 | } | |
325 | } | |
326 | grunt.registerTask('test', testSubtasks) | |
327 | ||
328 | // JS distribution task. | |
329 | grunt.registerTask('dist-js', ['babel:dev', 'concat', 'babel:dist', 'stamp', 'exec:uglify']) | |
330 | ||
331 | grunt.registerTask('test-scss', ['exec:scss-lint']) | |
332 | ||
333 | // CSS distribution task. | |
334 | grunt.registerTask('sass-compile', ['exec:sass', 'exec:sass-docs']) | |
335 | ||
336 | grunt.registerTask('dist-css', ['sass-compile', 'exec:postcss', 'exec:clean-css', 'exec:clean-css-docs']) | |
337 | ||
338 | // Full distribution task. | |
339 | grunt.registerTask('dist', ['clean:dist', 'dist-css', 'dist-js']) | |
340 | ||
341 | // Default task. | |
342 | grunt.registerTask('default', ['clean:dist', 'test']) | |
343 | ||
344 | // Docs task. | |
345 | grunt.registerTask('docs-css', ['exec:clean-css-docs', 'exec:postcss-docs']) | |
346 | grunt.registerTask('lint-docs-css', ['exec:scss-lint-docs']) | |
347 | grunt.registerTask('docs-js', ['exec:uglify-docs']) | |
348 | grunt.registerTask('docs', ['lint-docs-css', 'docs-css', 'docs-js', 'clean:docs', 'copy:docs']) | |
349 | grunt.registerTask('docs-github', ['jekyll:github']) | |
350 | ||
351 | grunt.registerTask('prep-release', ['dist', 'docs', 'docs-github', 'compress']) | |
352 | ||
353 | // Publish to GitHub | |
354 | grunt.registerTask('publish', ['buildcontrol:pages']) | |
355 | } |