Skip to content

Commit 8bd6996

Browse files
Merge pull request #692 from dtaylor113/add-less-to-sass
feat(sass): Added Support for Less to Sass Conversion
2 parents a50b9be + c45f3d4 commit 8bd6996

File tree

7 files changed

+1236
-1703
lines changed

7 files changed

+1236
-1703
lines changed

Gruntfile.js

Lines changed: 166 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ module.exports = function (grunt) {
55

66
function init () {
77

8+
// '--sass' command line argument exists?
9+
var sassBuild = grunt.option('sass');
10+
811
grunt.initConfig({
912
availabletasks: {
1013
tasks: {
@@ -94,6 +97,23 @@ module.exports = function (grunt) {
9497
dest: 'dist/less/dependencies/patternfly',
9598
expand: true,
9699
flatten: true
100+
},
101+
distsass: {
102+
src: ['styles/_angular-patternfly.scss'],
103+
dest: 'dist/sass',
104+
expand: true,
105+
flatten: true
106+
},
107+
sassBuild:{
108+
files: [
109+
{
110+
// copy css built from sass into dist/styles
111+
expand: true,
112+
cwd: 'dist/sass',
113+
src: ['**/*.css', '**/*.map'],
114+
dest: 'dist/styles/'
115+
}
116+
]
97117
}
98118
},
99119
'string-replace': {
@@ -115,6 +135,128 @@ module.exports = function (grunt) {
115135
}
116136
}
117137
},
138+
lessToSass: {
139+
convert_within_custom_replacements: {
140+
files: [
141+
{
142+
expand: true,
143+
cwd: 'styles',
144+
src: ['**/*.less', '!angular-patternfly.less'],
145+
dest: 'dist/sass/',
146+
rename: function(dest, src) {
147+
return dest + '_' + src.replace('.less', '.scss');
148+
}
149+
},
150+
{
151+
expand: true,
152+
cwd: 'src',
153+
src: ['**/*.less'],
154+
dest: 'dist/sass/',
155+
rename: function(dest, src) {
156+
return dest + '_' + src.split('/').pop().replace('.less', '.scss');
157+
}
158+
}
159+
],
160+
options: {
161+
excludes: ['variables', 'default'],
162+
replacements: [
163+
{
164+
// Customize variable conversion to include newer css reserved words.
165+
pattern: /(?!@debug|@import|@media|@keyframes|@font-face|@include|@extend|@mixin|@supports|@-\w)@/gi,
166+
replacement: '$',
167+
order: 0
168+
},
169+
{
170+
// Add !default flag to variable declarations without leading whitespace.
171+
pattern: /^(\$.*?:.*?);(\s*\/\/.*)?$/mgi,
172+
replacement: '$1 !default;$2',
173+
order: 2
174+
},
175+
{
176+
// Include mixins with no arguments
177+
pattern: /(\s+)\.([\w\-]+)\(\)/gi,
178+
replacement: '$1@include $2()',
179+
order: 3
180+
},
181+
{
182+
// Interpolates second ampersand where double ampersands are used
183+
pattern: /\&\&/gi,
184+
replacement: '&#{&}',
185+
order: 20
186+
},
187+
{
188+
// Interpolates ampersands that directly follow (are touching) a definition
189+
// e.g. somedef& becomes somedef#{&}
190+
pattern: /(\w+)\&/gi,
191+
replacement: '$1#{&}',
192+
order: 30
193+
},
194+
{
195+
// Namespaced mixins are detected as includes by default conversion
196+
// process. Remove namespacing by concatenating namespace and mixin name.
197+
// #gradient {
198+
// @include striped(){...}
199+
// }
200+
//
201+
// becomes
202+
//
203+
// @mixin gradient-striped(){...}
204+
pattern: /^#([\w\-]+)\s*{\s*@include\s*([\w\-]*)\((.*)\)\s*{([\s\S]*?)}\s*}/mgi,
205+
replacement: '@mixin $1-$2($3){$4}',
206+
order: 40
207+
},
208+
// Fix invocation of namespaced mixins. Replace #namespace > .mixin()
209+
// or #namespace.mixin() with @include namespace-mixin()
210+
{
211+
pattern: /#(\w*)\s*\>?\s*\.(\w*)(\(.*\))/gi,
212+
replacement: '@include $1-$2$3',
213+
order: 50
214+
},
215+
{
216+
// Remove "!default" flag from mixin declarations
217+
pattern: /@mixin.*!default.*/gi,
218+
replacement: function(match) {
219+
return match.replace(/\s*!default\s*/gi, '');
220+
},
221+
order: 60
222+
},
223+
{
224+
// Replace semi-colons with commas in mixins and includes
225+
pattern: /(@mixin |@include )([\w\-]*)\s*(\(.*\))(\s*[{;]?)/gi,
226+
replacement: function(match, p1, p2, p3, p4) {
227+
return p1 + p2 + p3.replace(/;/g, ',') + p4;
228+
},
229+
order: 70
230+
},
231+
{
232+
// Fix bug in grunt-less-to-sass that puts "!important" inside mixin and css function parens.
233+
pattern: /^(\s*[\w\-]*:\s*[\w\-]*)\((.*?)\s*!important.*\)(.*);(.*)$/mgi,
234+
replacement: '$1($2) !important$3;$4',
235+
order: 80
236+
},
237+
{
238+
pattern: /\&:extend\((.*)\)/gi,
239+
replacement: '@extend $1',
240+
order: 90
241+
},
242+
]
243+
}
244+
}
245+
},
246+
sass: {
247+
patternfly: {
248+
files: {
249+
'dist/sass/angular-patternfly.css': ['styles/build.scss']
250+
},
251+
options: {
252+
outputStyle: 'expanded',
253+
includePaths: [
254+
'dist/sass',
255+
'node_modules/patternfly/dist/sass'
256+
]
257+
}
258+
}
259+
},
118260
less: {
119261
patternfly: {
120262
files: {
@@ -355,7 +497,13 @@ module.exports = function (grunt) {
355497
}
356498
});
357499

358-
grunt.registerTask('copymain', ['copy:docdata', 'copy:fa', 'copy:img', 'copy:distimg', 'copy:distless', 'copy:distlessDependencies']);
500+
grunt.registerTask('shipcss', function() {
501+
if (sassBuild) {
502+
grunt.task.run('copy:sassBuild');
503+
}
504+
});
505+
506+
grunt.registerTask('copymain', ['copy:docdata', 'copy:fa', 'copy:img', 'copy:distimg', 'copy:distless', 'copy:distlessDependencies', 'copy:distsass']);
359507

360508
// You can specify which modules to build as arguments of the build task.
361509
grunt.registerTask('build', 'Create bootstrap build files', function () {
@@ -375,7 +523,23 @@ module.exports = function (grunt) {
375523
concatSrc = 'src/**/*.js';
376524
}
377525

378-
grunt.task.run(['clean', 'lint', 'test', 'ngtemplates', 'concat', 'ngAnnotate', 'uglify:build', 'less', 'cssmin', 'copymain', 'string-replace', 'ngdocs', 'clean:templates']);
526+
grunt.task.run([
527+
'clean',
528+
'lint',
529+
'test',
530+
'ngtemplates',
531+
'concat',
532+
'ngAnnotate',
533+
'uglify:build',
534+
'less',
535+
'lessToSass',
536+
'sass',
537+
'shipcss',
538+
'cssmin',
539+
'copymain',
540+
'string-replace',
541+
'ngdocs',
542+
'clean:templates']);
379543
});
380544

381545
// Runs all the tasks of build with the exception of tests

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,22 @@ Note:
194194
</style>
195195
```
196196
197+
#### Less to Sass Conversion
198+
199+
During the build process Less files are converted to Sass files in `/dist/sass`. Then the Sass files are compiled into `/dist/sass/angular-patternfly.css`. If you would like to copy the Sass generated css into the main `/dist/styles` directory, execute:
200+
201+
```
202+
grunt build --sass
203+
```
204+
205+
This task will copy `/dist/sass/angular-patternfly.css` to `/dist/styles/angular-patternfly.css`. Then the build process will minimize the css in `/dist/styles`.
206+
207+
The Less to Sass Conversion step will be accomplished and managed as a part of any Pull Request which includes Less file changes. Although contributors may want to build and test their style changes with Sass before submitting a Pull Request, this step should always be tested and validated by reviewers before a style change is merged and released. If a contributor is having issues with Sass conversion that they cannot resolve, Pull Request reviewers will need to ensure that the Sass conversion step is successfully accomplished, tested, and included in the Pull Request before it is approved and merged.
208+
209+
For more detailed information, please read [PatternFly Less to Sass Conversion](https://github.com/patternfly/patternfly#less-to-sass-conversion)
210+
211+
*Note:* When a Less file is added/deleted/renamed it needs to be updated in the main Less import file `/styles/angular-patternfly.less` and the main Sass import file `styles/_angular-patternfly.scss`.
212+
197213
### Using with Webpack
198214
199215
In order to use Angular-Patternfly in a Webpack-bundled application there are some things you need to keep in mind:

eslint.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ globals:
1111
rules:
1212
strict: [2, "function"]
1313
quotes: 0
14-
camelcase: 2
14+
camelcase: 1
1515
indent: [2, 2]
1616
new-cap:
1717
- 2

0 commit comments

Comments
 (0)