Skip to content

Commit

Permalink
Merge d5fc597 into 7844ed3
Browse files Browse the repository at this point in the history
  • Loading branch information
aviemet committed Feb 7, 2019
2 parents 7844ed3 + d5fc597 commit 5a86da4
Show file tree
Hide file tree
Showing 5 changed files with 354 additions and 27 deletions.
4 changes: 2 additions & 2 deletions .eslintrc.js
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ module.exports = {
"no-dupe-args": 2,
"no-dupe-keys": 2,
"no-duplicate-case": 2,
"no-empty-character-class": 2,
"no-empty-character-class": 0,
"no-empty": 2,
"no-ex-assign": 2,
"no-extra-boolean-cast": 2,
Expand Down Expand Up @@ -77,7 +77,7 @@ module.exports = {
"no-extra-bind": 2,
"no-fallthrough": 2,
"no-floating-decimal": 2,
"no-implicit-coercion": 2,
"no-implicit-coercion": 0,
"no-implied-eval": 2,
"no-iterator": 2,
"no-labels": 2,
Expand Down
14 changes: 14 additions & 0 deletions README.md
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ Example output:
"@foreground": "black"
}
```
Supports Less Maps:
```less
@colors: {
flat-blue : #4176A7;
dark-blue : darken(#4176A7, 20%);
}
```
Output:
```less
colors: {
'flat-blue' : '#4176A7',
'dark-blue' : 'darken(#4176A7, 20%)'
}
```
**Note:** while it does return variables it finds within rules, it is recommended to use this on files containing only variables, as it's not a parser and is designed to extract design principles for style guides.

### Options
Expand Down
2 changes: 1 addition & 1 deletion package.json
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"@commitlint/config-conventional": "^7.0.1",
"babel-cli": "^6.7.7",
"babel-eslint": "^6.0.3",
"babel-istanbul": "^0.8.0",
"babel-istanbul": "^0.12.2",
"babel-plugin-add-module-exports": "^0.1.2",
"babel-preset-es2015": "^6.6.0",
"babel-register": "^6.7.2",
Expand Down
123 changes: 113 additions & 10 deletions src/index.js
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,30 +1,119 @@
import stripComments from 'strip-json-comments';

const varRgx = /^[@$]/;
const followVar = (value, lessVars, dictionary) => {
if (varRgx.test(value)) {
// value is a variable
return followVar(lessVars[value] || dictionary[value.replace(varRgx, '')]);

const CASES = {
dash: {
testRgx: /-/,
split: str => str.toLowerCase().split('-'),
join: '-'
},
snake: {
testRgx: /_/,
split: str => str.toLowerCase().split('_'),
join: '_'
},
camel: {
testRgx: /[A-Z]/,
split: str => {
return str.replace(/(?!^[A-Z])([A-Z]+|[0-9]+)/g, ' $1').toLowerCase().split(' ');
},
join: ''
}
return value;
};

const replaceVariables = (value, lessVars, dictionary) => {
let replacedValue = value;
const matches = value.match(/(?:[@$][\w-.]*)/g) || [];

// Replace each matched variable within the value
matches.forEach(match => {
const mapped = match.split('.');
const replacement = mapped.length > 1 ?
lessVars[mapped[0]][mapped[1]] :
dictionary[match.replace(varRgx, '')] || lessVars[match];
replacedValue = replacedValue.replace(match, replacement);
});
return replacedValue;
};

const applyChangeCase = (key, changeCase) => {
let parts;
let joinStr = CASES.camel.join; // Default for sentence case to work
const prefix = varRgx.test(key) ? key.charAt(0) : '';

// Find what case the key is in
Object.keys(CASES).forEach(caseKey => {
// Strip the prefix and split into an array of word(s)
if (!parts && CASES[caseKey].testRgx.test(key)) {
parts = CASES[caseKey].split(key.replace(varRgx, ''));
}

// Use the CASES loop to find the join string
if (changeCase === caseKey) {
joinStr = CASES[caseKey].join;
}
});
// If parts is still empyt it was a single word
if (!parts) {
parts = [key.replace(varRgx, '')];
}
// Apply formatting based on the new case
parts = parts.map((part, i) => {
let rPart = part;
if (changeCase === 'camel' || changeCase === 'sentence') {
if (changeCase === 'sentence' || i > 0) {
rPart = rPart.charAt(0).toUpperCase() + rPart.slice(1);
}
}
return rPart;
});
// Put it all back together
return prefix + parts.join(joinStr);
};

export default (sheet, options = {}) => {
const { dictionary = {}, resolveVariables = false, stripPrefix = false } = options;
const { dictionary = {}, resolveVariables = false, stripPrefix = false, changeCase = false } = options;
let lessVars = {};
const matches = stripComments(sheet).match(/[@$](.*:[^;]*)/g) || [];
const matches = stripComments(sheet).match(/(?:[@$][\w-]*)\s*:\s*(?:\{.*?\}|[\s\w-#@()\/"':.%,]*)/gms) || [];

matches.forEach(variable => {
// Get an array with first element as the name of the less variable
const definition = variable.split(/:\s*/);
let value = definition.splice(1).join(':');
value = value.trim().replace(/^["'](.*)["']$/, '$1');

// Reduce the remaining elements to a single string and strip quotes
let value = definition.splice(1).join(':').trim().replace(/^["'](.*)["']$/, '$1');

// Check if the value was a Map
if (value.includes('{')) {
// Manipulate value into serialized JSON string
value = value.replace(/\n\s*/g, '').replace(/([\w-]*)\s*:([\s\w-#@()\/"'.%,]*);/gms, '"$1":"$2",').replace(/,}/, '}');

// Parse the string to JSON
try {
value = JSON.parse(value);
} catch (error) {
console.error('Malformed JSON Error, check the syntax in your less file', error);
}
}

// Add variable definition to the list
lessVars[definition[0].replace(/['"]+/g, '').trim()] = value;
});

if (resolveVariables) {
Object.keys(lessVars).forEach(key => {
const value = lessVars[key];
lessVars[key] = followVar(value, lessVars, dictionary);
// Check any nested values first
if (value.constructor && value.constructor === Object) {
Object.keys(value).forEach(key => {
const nestedValue = value[key];
value[key] = replaceVariables(nestedValue, lessVars, dictionary);
});
lessVars[key] = value;
} else {
lessVars[key] = replaceVariables(value, lessVars, dictionary);
}
});
}

Expand All @@ -37,5 +126,19 @@ export default (sheet, options = {}) => {
}, {});
}

if (changeCase) {
lessVars = Object.keys(lessVars).reduce((prev, key) => {
// Change case of map keys first
if (lessVars[key].constructor === Object) {
lessVars[key] = Object.keys(lessVars[key]).reduce((prev2, key2) => {
prev2[applyChangeCase(key2, changeCase)] = lessVars[key][key2];
return prev2;
}, {});
}
prev[applyChangeCase(key, changeCase)] = lessVars[key];
return prev;
}, {});
}

return lessVars;
};
Loading

0 comments on commit 5a86da4

Please sign in to comment.