├── .gitignore
├── CHANGELOG.md
├── Examples
├── Example1
│ └── ProjectDir
│ │ └── tokens
│ │ ├── myTokens.json
│ │ └── myTokens.scss
├── Example2
│ └── ProjectDir
│ │ └── tokens
│ │ ├── colors.js
│ │ ├── colors.scss
│ │ ├── fontSizes.json
│ │ └── fontSizes.scss
├── Example3
│ └── ProjectDir
│ │ ├── sass
│ │ ├── colors.sass
│ │ └── fontSizes.sass
│ │ └── tokens
│ │ ├── colors.js
│ │ └── fontSizes.json
├── Example4
│ └── ProjectDir
│ │ └── tokens
│ │ ├── myTokens.json
│ │ └── myTokensRenamed.scss
└── Example5
│ └── ProjectDir
│ ├── scss
│ ├── mergedTokenFiles.scss
│ └── mergedTokenFilesAndObjects.scss
│ └── tokens
│ ├── colors.js
│ └── fontSizes.json
├── LICENSE.md
├── README.md
├── bin
└── cli.js
├── lib
├── jsJsonFilesToSassScssFiles.js
├── jsValueToSassString.js
└── utils
│ ├── inspection
│ ├── isBoolean.js
│ ├── isNull.js
│ ├── isPositiveInteger.js
│ ├── isString.js
│ └── isUndefined.js
│ ├── path
│ ├── basename.js
│ ├── createPathDirectories.js
│ ├── hasExtension.js
│ └── removeExtension.js
│ └── transformation
│ └── flattenObject.js
├── package.json
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .idea
3 | dist
4 | node_modules
5 | test.*
6 | test
7 | test/*.*
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # CHANGE LOG
2 |
3 | ### Release 1.6.2
4 | - Fixed bug occurring when more than 2 files are being merged and the merge object option (--mo) is activated.
5 | - see https://github.com/rlapoele/json-to-scss/issues/10
6 |
7 | ### Release 1.6.1
8 | - Fixed typos in CLI (json-to-scss) help text & README.md
9 |
10 | ### Release 1.6.0
11 | - New Features:
12 | - added option allowing users to obtain a list of sass/scss variables obtained from a flattened JSON/js object.
13 | - flattened keys can either be in kebab-case (default) or camel-case.
14 | - when flattening with kebab-case, json-to-scss does currently not change the nested key case.
15 | - when flattening with came-case, json-to-scss does currently only uppercase the first letter of the nested keys.
16 |
17 | ### Release 1.5.0
18 | - New Feature:
19 | - added option (i.e. --sk='font-family') allowing users to force matching JSON/js object key values to be quoted.
20 |
21 | ### Release 1.4.0
22 | - Upgraded dependencies.
23 | - New Features:
24 | - added option allowing users to ask for converted Sass map keys to be wrapped in single or double quote characters.
25 | - added option allowing users to ask for converted Sass map values (other than nested maps) to be wrapped in single or double quote characters.
26 |
27 | ### Release 1.3.1
28 | - README.md typo fixes for example 5.2.
29 | - command line output format updates for merge object scenario.
30 |
31 | ### Release 1.3.0
32 | - New Feature:
33 | - added possibility to merge multiple converted sources into one single destination file.
34 | - in this context, the prefix & suffix are repeated for each converted source content;
35 | - the destination file therefore contains as many prefixed & suffixed block as there are sources.
36 | - if no prefix is specified then each source file name becomes a prefix ($source-file-name: ...).
37 | - by default, each converted source becomes a distinct/separated sass variable in the destination file.
38 | - when merging multiple source files, added possibility to merge content as well using global option "--mo" (merge object);
39 | - in this context, the prefix & suffix are only used once in the destination file and each individual converted block are comma+linefeed separated.
40 | - Code modifications:
41 | - further simplified code when possible (remove levels of nested internal function declarations).
42 | - updated object property existence checks such as "if (property.object)..." and used "'property' in object ..." expressions instead.
43 | - converted all switch statements into function + literal object declarations.
44 |
45 | ### Release 1.2.4
46 | - Code modifications
47 | - simplified code by removing all options & config objects as well unnecessary validations.
48 | - Remove TextIndentation.js file/function (use String.prototype.repeat(...) directly instead).
49 |
50 | ### Release 1.2.3
51 | - Code cleanups & comments addition.
52 |
53 | ### Release 1.2.2
54 | - Code Fixes:
55 | - changed jsJsonFilesToSassScssFiles default config to ensure fn input validation flag is set to true by default.
56 | - updated cli.js to handle above change.
57 | - fixed typo in jsJsonFilesToSassScssFiles.js input validation (sourceFilepaths arg was checked 2 times instead of sourceFilepaths check + destinationFilepaths check.)
58 | - Enhancements:
59 | - re-organized jsJsonFilesToSassScssFiles code to be more functional.
60 |
61 | ### Release 1.2.1
62 | - Documentation updates.
63 | - Enhancements:
64 | - improved function input param validation
65 | - leveraged const default config.
66 |
67 | ### Release 1.2.0
68 | - New Feature:
69 | - expanded definition of .js/.json self config ('_jsonToScssConfig') to add a new 'filename' property.
70 | - this allows users to define custom destination file name directly within the .js/.json file(s) they want to convert to sass or scss.
71 | - Enhancements:
72 | - Added error message when specified source is invalid. This prevents situation when source is invalid and app appears to react as if nothing happened.
73 | - Updates:
74 | - remove jsdoc docs - users can still generate it from their side if interested.
75 | - added an Examples folder with 4 examples.
76 | - added explanations and examples to README.md.
77 |
78 | ### Release 1.1.1
79 | - Added code documentation & generated it with _jsdoc_ in the `docs` folder.
80 |
81 | ### Release 1.1.0
82 | - New Features:
83 | - auto-detection of a '_jsonToScssConfig' property within .js/.json files:
84 | - this allows users to define a local configuration for individual .js/.json files; when detected this _local_ config (options) takes precedence over the command line options.
85 | - new CLI option '**--no-underscore**' allowing users to tell _json-to-scss_ to remove any leading `_` (underscore) character from the prefix when the later corresponds to a sass variable.
86 | - Fixes/Enhancements
87 | - added missing support for empty string setup options.
88 | - wrapped "require(content.js/.json) ..." code portion in try / catch to improve code robustness.
89 | - removed what seems to be an unnecessary json to string & string to json conversion.
90 | - Updates
91 | - README.md updates to reflect the updated usage and so on.
92 |
93 | ### Release 1.0.2
94 | - Fixes
95 | - swapped package.json "bin" & "main" values.
96 | - added a missing CHANGELOG.md file.
97 |
98 | ### Release 1.0.1
99 | - Cleanups
100 | - removed experimental index.js.
101 |
--------------------------------------------------------------------------------
/Examples/Example1/ProjectDir/tokens/myTokens.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors": {
3 | "primary-color": "#FFFFFF",
4 | "accent-color": "#0099FF"
5 | },
6 | "font-sizes": {
7 | "small": ".875rem",
8 | "medium": "1rem",
9 | "large": "2rem"
10 | },
11 | "web-browser-default-font-size": "16px"
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/Example1/ProjectDir/tokens/myTokens.scss:
--------------------------------------------------------------------------------
1 | $myTokens: (
2 | colors: (
3 | primary-color: #FFFFFF,
4 | accent-color: #0099FF
5 | ),
6 | font-sizes: (
7 | small: .875rem,
8 | medium: 1rem,
9 | large: 2rem
10 | ),
11 | web-browser-default-font-size: 16px
12 | );
13 |
--------------------------------------------------------------------------------
/Examples/Example2/ProjectDir/tokens/colors.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | colors: {
3 | "primary-color": "#FFFFFF",
4 | "accent-color": "#0099FF"
5 | }
6 | };
--------------------------------------------------------------------------------
/Examples/Example2/ProjectDir/tokens/colors.scss:
--------------------------------------------------------------------------------
1 | $colors: (
2 | colors: (
3 | primary-color: #FFFFFF,
4 | accent-color: #0099FF
5 | )
6 | );
7 |
--------------------------------------------------------------------------------
/Examples/Example2/ProjectDir/tokens/fontSizes.json:
--------------------------------------------------------------------------------
1 | {
2 | "font-sizes": {
3 | "small": ".875rem",
4 | "medium": "1rem",
5 | "large": "2rem"
6 | },
7 | "web-browser-default-font-size": "16px"
8 | }
--------------------------------------------------------------------------------
/Examples/Example2/ProjectDir/tokens/fontSizes.scss:
--------------------------------------------------------------------------------
1 | $fontSizes: (
2 | font-sizes: (
3 | small: .875rem,
4 | medium: 1rem,
5 | large: 2rem
6 | ),
7 | web-browser-default-font-size: 16px
8 | );
9 |
--------------------------------------------------------------------------------
/Examples/Example3/ProjectDir/sass/colors.sass:
--------------------------------------------------------------------------------
1 | $colors: (colors: (primary-color: #FFFFFF, accent-color: #0099FF))
2 |
--------------------------------------------------------------------------------
/Examples/Example3/ProjectDir/sass/fontSizes.sass:
--------------------------------------------------------------------------------
1 | $fontSizes: (font-sizes: (small: .875rem, medium: 1rem, large: 2rem), web-browser-default-font-size: 16px)
2 |
--------------------------------------------------------------------------------
/Examples/Example3/ProjectDir/tokens/colors.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | colors: {
3 | "primary-color": "#FFFFFF",
4 | "accent-color": "#0099FF"
5 | }
6 | };
--------------------------------------------------------------------------------
/Examples/Example3/ProjectDir/tokens/fontSizes.json:
--------------------------------------------------------------------------------
1 | {
2 | "font-sizes": {
3 | "small": ".875rem",
4 | "medium": "1rem",
5 | "large": "2rem"
6 | },
7 | "web-browser-default-font-size": "16px"
8 | }
--------------------------------------------------------------------------------
/Examples/Example4/ProjectDir/tokens/myTokens.json:
--------------------------------------------------------------------------------
1 | {
2 | "_jsonToScss": {
3 | "sassVariableName": "__example-4",
4 | "filename": "myTokensRenamed",
5 | "prefix": "garbage",
6 | "suffix": "; // an scss comment.",
7 | "emptyString": "''",
8 | "indentationText": " ",
9 | "indentationSize": 2,
10 | "noUnderscore": true
11 |
12 | },
13 | "colors": {
14 | "primary-color": "#FFFFFF",
15 | "accent-color": "#0099FF"
16 | },
17 | "font-sizes": {
18 | "small": ".875rem",
19 | "medium": "1rem",
20 | "large": "2rem"
21 |
22 | },
23 | "example-of-empty-string": "",
24 | "web-browser-default-font-size": "16px"
25 | }
26 |
--------------------------------------------------------------------------------
/Examples/Example4/ProjectDir/tokens/myTokensRenamed.scss:
--------------------------------------------------------------------------------
1 | $example-4: (
2 | colors: (
3 | primary-color: #FFFFFF,
4 | accent-color: #0099FF
5 | ),
6 | font-sizes: (
7 | small: .875rem,
8 | medium: 1rem,
9 | large: 2rem
10 | ),
11 | example-of-empty-string: '',
12 | web-browser-default-font-size: 16px
13 | ); // an scss comment.
14 |
--------------------------------------------------------------------------------
/Examples/Example5/ProjectDir/scss/mergedTokenFiles.scss:
--------------------------------------------------------------------------------
1 | $colors: (
2 | colors: (
3 | primary-color: #FFFFFF,
4 | accent-color: #0099FF
5 | )
6 | );
7 | $fontSizes: (
8 | font-sizes: (
9 | small: .875rem,
10 | medium: 1rem,
11 | large: 2rem
12 | ),
13 | web-browser-default-font-size: 16px
14 | );
15 |
--------------------------------------------------------------------------------
/Examples/Example5/ProjectDir/scss/mergedTokenFilesAndObjects.scss:
--------------------------------------------------------------------------------
1 | $mergedTokenFilesAndObjects: (
2 | colors: (
3 | primary-color: #FFFFFF,
4 | accent-color: #0099FF
5 | ),
6 | font-sizes: (
7 | small: .875rem,
8 | medium: 1rem,
9 | large: 2rem
10 | ),
11 | web-browser-default-font-size: 16px
12 | );
13 |
--------------------------------------------------------------------------------
/Examples/Example5/ProjectDir/tokens/colors.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | colors: {
3 | 'primary-color': '#FFFFFF',
4 | 'accent-color': '#0099FF'
5 | }
6 | };
7 |
--------------------------------------------------------------------------------
/Examples/Example5/ProjectDir/tokens/fontSizes.json:
--------------------------------------------------------------------------------
1 | {
2 | "font-sizes": {
3 | "small": ".875rem",
4 | "medium": "1rem",
5 | "large": "2rem"
6 | },
7 | "web-browser-default-font-size": "16px"
8 | }
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # The MIT License (MIT)
2 | MIT License
3 |
4 | Copyright © 2018-present, Renaud Lapoële
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JSON-TO-SCSS
2 |
3 |
4 |
5 |
6 |
7 |
8 | > Convert your js & json files to sass or scss files.
9 |
10 | A small utility to convert js & json file(s) to scss/sass file(s).
11 |
12 | ## Motivation
13 | This library has initially been created to contribute to & facilitate the maintenance of living style guides.
14 |
15 | As far as living style guides go, defining and using an agreed upon a set of design properties is a good starting point and best practice (c.f. [_design tokens_](https://uxdesign.cc/design-tokens-for-dummies-8acebf010d71), [_Salesforce Lightning Design System_](https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/tokens_intro.htm), etc... ).
16 |
17 | While many file formats can be used (YAML, TOML, etc...) to store such properties, it is very easy to use javascript or json files.
18 |
19 | Now, defining & storing design properties in one place is one thing but it is obviously useless if it cannot be easily consumed.
20 |
21 | Developers will find it convenient to work with .js or .json file but what about others and, for example, people interested in leveraging such props in SASS for instance?
22 |
23 | This is where _json-to-scss_ comes into play; this is obviously not the first (nor last) conversion tool (see below) but this is mine and I hope that you will find it useful. :)
24 |
25 | [Andrew Clark](https://github.com/acdlite)'s [json-sass](https://github.com/acdlite/json-sass) library has been a significant source of inspiration for this version. Feel free to check-it out.
26 |
27 |
28 | ## Installation
29 | To use _json-to-scss_ as development dependency with...
30 |
31 | #### Yarn
32 | ```shell
33 | yarn add -D json-to-scss
34 | ```
35 |
36 | #### Npm
37 | ```shell
38 | npm install json-to-scss --save-dev
39 | ```
40 |
41 | ## Usage
42 | ```
43 | Usage: json-to-scss [destination] [options]
44 |
45 | source: the path to a javascript, json or group of files to be converted.
46 | (required) - only '.js' and '.json' are processed.
47 |
48 | destination: the full or partial destination of the converted files.
49 | (optional) - when the destination is a directory path only, all generated
50 | files are saved in it with a default '.scss' extension. If
51 | a '.sass' extension is required instead, the --sass option must be included.
52 |
53 |
54 | options:
55 |
56 | --h (help) Show this message.
57 | --p='prefix' (prefix) Prepend the converted sass/scss content with the prefix.
58 | Prefix is usually used & set to be used as sass variable name.
59 | Default '${source-filename} :'.
60 | --no-underscore (no leading _) Remove any leading '_' (underscore) characters from the
61 | prefix when used as sass variable name.
62 | --s='suffix' (suffix) Append the converted sass/scss content with the suffix.
63 | Default: ';' (default not used if --sass)
64 | --tt='tabText' (tab text) Text to be used to indent or tabulate sass map.
65 | Default: ' ' (two space characters)
66 | --tn=tabNumber (tab number) Number of tabulations.
67 | Default: 1 (set to 0 if --sass)
68 | --es='sq'||'dq' (empty string) Sass/scss representation for an empty string (single or double quote).
69 | Default is '""': { "prop": "" } => $xyzfilename: ( prop: "" );
70 | --sass (sass ext.) Use sass extension.
71 | --mo (merge objects) Merge obtained sass strings into a single sass map/list.
72 | Enabled only if destination contains a full file name (name + .ext)
73 | --k='auto'|| (sass map keys) Sass/scss format for map keys.
74 | 'sq'||'dq' 'auto' (default): keys are formatted as per their converted type (number, ...)
75 | 'sq': all keys are single quoted.
76 | 'dq': all keys are doubled quoted.
77 | --v='auto'|| (sass map val.) Sass/scss format for map values other than nested maps.
78 | 'sq'||'dq' 'auto' (default): values are formatted as per their converted type
79 | 'sq': all values are single quoted.
80 | 'dq': all values are doubled quoted.
81 | Notes regarding 'sq' or 'dq' usage:
82 | 1- nested quote characters are automatically replaced by their counterpart.
83 | { "prop": "Arial, 'sans-serif'"} with 'sq' => ( prop: 'Arial, "sans-serif"' );
84 | 2- empty strings are formatted as per the given 'sq' or 'dq' option value regardless
85 | of the --es option.
86 | --sk='family,..' (string keys) Comma separated property names (keys) for which values must be quoted.
87 | Property names are case insensitive (fontFamily will be treated like FontFamily, etc...).
88 | Only non-object value keys are compared against the "string keys":
89 | { "key 1": { "key 2": "some,possible,values" }} => only "key 2" will be considered.
90 | Default "string keys" (property names) are:
91 | family,font-family,fontfamily,stack,font-stack,fontstack,face,font-face,fontface
92 | Turn this option off by setting it to '' (e.g. --sk='').
93 | --fk (flatten keys) Flatten JSON/js object keys to produce series of sass/scss variables instead of a map.
94 | Provided prefix and suffix, if any, are applied to each flatten key.
95 | Key name elements (nested JSON object props) are dash separated (kebab-case).
96 | In case of flatten key name conflict(s), the latest processed key value is used.
97 | This option is not available in the js/JSON embed-able config.
98 | --fkc='kebab'|| (flat. key case) Flattened key case.
99 | 'camel' 'kebab' (default): nested keys are dash separated. No letter case change.
100 | 'camel': top level keys are left as-is whereas nested keys are capitalized before
101 | being concatenated. The nested key capitalization does not change the case of the
102 | subsequent letters: 'hEllO' => 'HEllO'.
103 |
104 |
105 | ```
106 |
107 | ## Regarding `.js` files
108 |
109 | _json-to-scss_ can convert `.js` files as long as these are a nodejs modules exporting a **javascript object**.
110 |
111 | #### Javascript (node module) file sample
112 |
113 | ```js
114 | const colorRed = "#FF0000";
115 | const colorBlue = "#0099FF";
116 |
117 | module.exports = {
118 | colors: {
119 | red: colorRed,
120 | green: "#00FF00",
121 | blue: colorBlue
122 | }
123 | }
124 | ```
125 |
126 | ## Examples
127 |
128 | #### Example #1
129 |
130 | This example shows how to convert a single specific file using the default _json-to-scss_ options and storing the converted file in the same source directory.
131 |
132 | ##### Directory Structure:
133 |
134 | ```
135 | .
136 | ├─ Examples
137 | │ ├─ Example1
138 | │ │ └─ ProjectDir
139 | │ │ └─ tokens
140 | │ │ └─ myTokens.json
141 | . .
142 | ```
143 |
144 | ##### myTokens.json
145 |
146 | ```json
147 | {
148 | "colors": {
149 | "primary-color": "#FFFFFF",
150 | "accent-color": "#0099FF"
151 | },
152 | "font-sizes": {
153 | "small": ".875rem",
154 | "medium": "1rem",
155 | "large": "2rem"
156 | },
157 | "font-family": {
158 | "sans-serif": "'Roboto, Helvetica, Arial, sans-serif'"
159 | },
160 | "web-browser-default-font-size": "16px"
161 | }
162 | ```
163 |
164 | Note: values corresponding to sass/scss list and which you cannot or do not want to store as an array in your JSON should be quoted such as "'my, list, of, values'".
165 |
166 | ##### Command:
167 |
168 | ```
169 | $ json-to-scss ./Examples/Example1/ProjectDir/tokens/myTokens.json
170 | $ json-to-scss vX.Y.Z
171 | $ /.../Examples/Example1/ProjectDir/tokens/myTokens.json: content converted. File created!
172 | $ /.../Examples/Example1/ProjectDir/tokens/myTokens.scss
173 | ```
174 |
175 | ##### Results:
176 |
177 | ###### Directory Structure:
178 |
179 | ```
180 | .
181 | ├─ Examples
182 | │ ├─ Example1
183 | │ │ └─ ProjectDir
184 | │ │ └─ tokens
185 | │ │ ├─ myTokens.json
186 | │ │ └─ myTokens.scss
187 | . .
188 | ```
189 |
190 | ###### myTokens.scss
191 |
192 | ```scss
193 | $myTokens: (
194 | colors: (
195 | primary-color: #FFFFFF,
196 | accent-color: #0099FF
197 | ),
198 | font-sizes: (
199 | small: .875rem,
200 | medium: 1rem,
201 | large: 2rem
202 | ),
203 | font-family: (
204 | sans-serif: 'Roboto, Helvetica, Arial, sans-serif'
205 | ),
206 | web-browser-default-font-size: 16px
207 | );
208 | ```
209 |
210 | #### Example #2
211 | In this example, we will demonstrate _json-to-scss_ ability to accept glob patterns.
212 |
213 | Note that when using a glob pattern, the source argument must be wrapped in single quotes such as `'...**/*.*'`.
214 |
215 | ##### Directory Structure:
216 |
217 | ```
218 | .
219 | ├─ Examples
220 | │ ├─ Example2
221 | │ │ └─ ProjectDir
222 | │ │ └─ tokens
223 | │ │ ├─ colors.js
224 | │ │ └─ fontSizes.js
225 | . .
226 | ```
227 |
228 | ##### colors.js
229 | ```js
230 | module.exports = {
231 | colors: {
232 | "primary-color": "#FFFFFF",
233 | "accent-color": "#0099FF"
234 | }
235 | };
236 | ```
237 |
238 | ##### fontSizes.json
239 | ```json
240 | {
241 | "font-sizes": {
242 | "small": ".875rem",
243 | "medium": "1rem",
244 | "large": "2rem"
245 | },
246 | "web-browser-default-font-size": "16px"
247 | }
248 | ```
249 |
250 | ##### Command:
251 |
252 | ```
253 | $ json-to-scss './Examples/Example2/**/*.*'
254 | $ json-to-scss vX.Y.Z
255 | $ /.../Examples/Example2/ProjectDir/tokens/colors.js: content converted. File created!
256 | $ /.../Examples/Example2/ProjectDir/tokens/colors.scss
257 | $ /.../Examples/Example2/ProjectDir/tokens/fontSizes.json: content converted. File created!
258 | $ /.../Examples/Example2/ProjectDir/tokens/fontSizes.scss
259 | ```
260 |
261 | ##### Results:
262 |
263 | ###### Directory Structure:
264 |
265 | ```
266 | .
267 | ├─ Examples
268 | │ ├─ Example2
269 | │ │ └─ ProjectDir
270 | │ │ └─ tokens
271 | │ │ ├─ colors.js
272 | │ │ ├─ colors.js
273 | │ │ ├─ fontSizes.json
274 | │ │ └─ fontSizes.scss
275 | . .
276 | ```
277 |
278 | ###### colors.scss
279 |
280 | ```scss
281 | $colors: (
282 | colors: (
283 | primary-color: #FFFFFF,
284 | accent-color: #0099FF
285 | )
286 | );
287 | ```
288 |
289 |
290 | ###### fontSizes.scss
291 |
292 | ```scss
293 | $fontSizes: (
294 | font-sizes: (
295 | small: .875rem,
296 | medium: 1rem,
297 | large: 2rem
298 | ),
299 | web-browser-default-font-size: 16px
300 | );
301 | ```
302 |
303 | #### Example #3
304 | This example will target a similar directory source structure & the same set of files however, this time, we will specify a `sass` target directory for the converted files and request _json-to-scss_ to format the output in `sass` format.
305 |
306 | Additionally, we will ask _json-to-scss_ to use a tab text (_--tt option_) such as `' '` (4 spaces) and to use a tab number/size (_--tn option_) of `5`...
307 |
308 | ##### Directory Structure:
309 |
310 | ```
311 | .
312 | ├─ Examples
313 | │ ├─ Example3
314 | │ │ └─ ProjectDir
315 | │ │ └─ tokens
316 | │ │ ├─ colors.js
317 | │ │ └─ fontSizes.js
318 | . .
319 | ```
320 |
321 | ##### Command:
322 |
323 | ```
324 | $ json-to-scss './Examples/Example3/**/*.*' ./Examples/Example3/ProjectDir/sass --sass --tt=' ' --tn=5
325 | $ json-to-scss vX.Y.Z
326 | $ /.../Examples/Example3/ProjectDir/tokens/colors.js: content converted. File created!
327 | $ /.../Examples/Example3/ProjectDir/sass/colors.sass
328 | $ /.../Examples/Example3/ProjectDir/tokens/fontSizes.json: content converted. File created!
329 | $ /.../Examples/Example3/ProjectDir/sass/fontSizes.sass
330 | ```
331 |
332 | ##### Results:
333 |
334 | ###### Directory Structure:
335 |
336 | ```
337 | .
338 | ├─ Examples
339 | │ ├─ Example3
340 | │ │ └─ ProjectDir
341 | │ │ ├─ sass
342 | │ │ │ ├─ colors.sass
343 | │ │ │ └─ fontSizes.sass
344 | │ │ └─ tokens
345 | │ │ ├─ colors.js
346 | │ │ └─ fontSizes.js
347 | . .
348 | ```
349 |
350 |
351 | ###### /sass/colors.sass
352 |
353 | ```sass
354 | $colors: (colors: (primary-color: #FFFFFF, accent-color: #0099FF))
355 | ```
356 |
357 | ###### /sass/fontSizes.sass
358 |
359 | ```sass
360 | $fontSizes: (font-sizes: (small: .875rem, medium: 1rem, large: 2rem), web-browser-default-font-size: 16px)
361 | ```
362 |
363 | As you can notice in the produced sass content presented above, the options related to the text indentation (_--tt_ and _--tn_) have both been ignored and, since we asked to produce sass here, the default indentation has even been removed.
364 |
365 | #### Example #4
366 |
367 | For this example, we'll reuse the same directory structure as in the first example.
368 |
369 | However this time, we will include a local conversion configuration directly within the json file that we want to convert.
370 |
371 | As you will see, this local config will overwrite/supersede the default & command line (through options) configs.
372 |
373 | ##### Directory Structure:
374 |
375 | ```
376 | .
377 | ├─ Examples
378 | │ ├─ Example4
379 | │ │ └─ ProjectDir
380 | │ │ └─ tokens
381 | │ │ └─ myTokens.json
382 | . .
383 | ```
384 |
385 | ##### myTokens.json:
386 |
387 | ```json
388 | {
389 | "_jsonToScss": {
390 | "sassVariableName": "__example-4",
391 | "filename": "myTokensRenamed",
392 | "prefix": "garbage",
393 | "suffix": "; // an scss comment.",
394 | "emptyString": "''",
395 | "indentationText": " ",
396 | "indentationSize": 2,
397 | "noUnderscore": true,
398 | "keyFormat": "dq",
399 | "valueFormat": "auto"
400 | },
401 | "colors": {
402 | "primary-color": "#FFFFFF",
403 | "accent-color": "#0099FF"
404 | },
405 | "font-sizes": {
406 | "small": ".875rem",
407 | "medium": "1rem",
408 | "large": "2rem"
409 |
410 | },
411 | "example-of-empty-string": "",
412 | "web-browser-default-font-size": "16px"
413 | }
414 | ```
415 |
416 | Notice the **`"_jsonToScss"`** property & object in our `myTokens.json` file.
417 |
418 | This object is treated as a local conversion configuration; let us see what properties it contains:
419 |
420 | - **sassVariableName**
421 | - this tells _json-to-scss_ to prefix the converted content using `__example-4`. Notice here that you do not need to include the `$` character since _json-to-scss_ will automatically insert it for you.
422 |
423 | - **notes:**
424 | - this feature only exists in the context of local config and there is therefore no direct equivalent option at the command line level; the command line option which could potentially yield similar results is `--prefix`.
425 | - when specified, the `"sassVariableName"` property value takes precedence over the `"prefix"` property value (and therefore equivalent command line option `--prefix`).
426 |
427 | - **filename**
428 | - this informs _json-to-scss_ that the destination file will have to be renamed ("myTokensRenamed" in this example); any specified extension will be ignored.
429 |
430 | - **prefix**
431 | - allows one to define or locally override the content prefix. In this example, the "garbage" value will be ignored due to the definition of **sassVariableName** in the same local configuration.
432 |
433 | - **suffix**
434 | - allows one to define or locally override the content suffix. In this example, "; // an scss comment." will be appended to "myTokens.json" converted content.
435 |
436 | - **emptyString**
437 | - tells _json-to-scss_ how to format sass values equal to empty strings. By default and here too, empty string values are represented as `''` (two single quotes)
438 |
439 | - **indentationText**
440 | - specifies the portion of text to be used as indentation "space". Here, `" "` (two white spaces) is set as the indentation text.
441 |
442 | - **indentationSize**
443 | - indicates the number of indentation "space"(s) which must be used when indenting content; in our example, since the value is 2, it will indent nested sass maps/values with 2 "space" text chunks per indentation level.
444 |
445 | - **noUnderscore**
446 | - when set to `true` (as it is the case in our example), this tells _json-to-scss_ to remove any `_` (underscore) character possibly present in the prefix and if such a prefix starts with `$_`. The same result can be achieved for all converted files using the command line option "--no-underscore".
447 |
448 | - **keyFormat**
449 | - allows one to force sass map keys to be wrapped (or not - use "auto") in single (use "sq") or double quote (use "dq").
450 |
451 | - **valueFormat**
452 | - allows one to force sass map values to be wrapped (or not - use "auto") in single (use "sq") or double quote (use "dq").
453 |
454 | ##### Command:
455 |
456 | ```
457 | $ json-to-scss ./Examples/Example4/ProjectDir/tokens/myTokens.json
458 | $ json-to-scss vX.Y.Z
459 | $ /.../Examples/Example4/ProjectDir/tokens/myTokens.json: content converted. File created!
460 | $ /.../Examples/Example4/ProjectDir/tokens/myTokensRenamed.scss
461 | ```
462 |
463 | ##### Results:
464 |
465 | ###### Directory Structure:
466 |
467 | ```
468 | .
469 | ├─ Examples
470 | │ ├─ Example4
471 | │ │ └─ ProjectDir
472 | │ │ └─ tokens
473 | │ │ ├─ myTokens.json
474 | │ │ └─ myTokensRenamed.scss
475 | . .
476 | ```
477 |
478 | Notice now how "myTokens" got renamed "myTokensRenamed".
479 |
480 |
481 | ###### myTokensRenamed.scss:
482 |
483 | ```scss
484 | $example-4: (
485 | "colors": (
486 | "primary-color": #FFFFFF,
487 | "accent-color": #0099FF
488 | ),
489 | "font-sizes": (
490 | "small": .875rem,
491 | "medium": 1rem,
492 | "large": 2rem
493 | ),
494 | "example-of-empty-string": '',
495 | "web-browser-default-font-size": 16px
496 | ); // an scss comment.
497 | ```
498 |
499 | As expected, the `"_scssToJson"` local configuration property/object has been removed and the converted content has been prefixed using "__example-4".
500 |
501 | Additionally and due to the presence of `"noUnderscore": true`, all "`_`" (underscore) characters have been stripped out from the prefix/variable name after the automatically added "`$`" (dollar sign).
502 |
503 | #### Example #5
504 |
505 | This example illustrates 2 merge features (new as of v1.3.0).
506 |
507 | **Example #3**'s directory structure and source files are used.
508 |
509 | ##### #5.1 - Merging of several source files into 1 destination file:
510 |
511 | In order to merge the converted content of several source files, one must specify a destination including a file name + extension (.sass or .scss).
512 |
513 | The destination file extension is important here as this is thanks to it that _json-to-scss_ can detect the merge request...
514 |
515 | ###### Directory Structure:
516 |
517 | ```
518 | .
519 | ├─ Examples
520 | │ ├─ Example5
521 | │ │ └─ ProjectDir
522 | │ │ └─ tokens
523 | │ │ ├─ colors.js
524 | │ │ └─ fontSizes.js
525 | . .
526 | ```
527 |
528 |
529 | ###### Command
530 |
531 | ```
532 | $ json-to-scss './Examples/Example5/ProjectDir/tokens/*.*' ./Examples/Example5/ProjectDir/scss/mergedTokenFiles.scss
533 | $ json-to-scss vX.Y.Z
534 | $ /.../Examples/Example5/ProjectDir/tokens/colors.js: content converted.
535 | $ /.../Examples/Example5/ProjectDir/tokens/fontSizes.json: content converted. File created!
536 | $ /.../Examples/Example5/ProjectDir/scss/mergedTokenFiles.scss
537 | ```
538 |
539 | ###### Output
540 |
541 | ###### _Directory Structure:_
542 |
543 | ```
544 | .
545 | ├─ Examples
546 | │ ├─ Example5
547 | │ │ └─ ProjectDir
548 | │ │ ├─ scss
549 | │ │ │ └─ mergedTokenFiles.scss
550 | │ │ └─ tokens
551 | │ │ ├─ colors.js
552 | │ │ └─ fontSizes.js
553 | . .
554 | ```
555 |
556 | ###### _mergedTokenFiles.scss:_
557 | ```scss
558 | $colors: (
559 | colors: (
560 | primary-color: #FFFFFF,
561 | accent-color: #0099FF
562 | )
563 | );
564 | $fontSizes: (
565 | font-sizes: (
566 | small: .875rem,
567 | medium: 1rem,
568 | large: 2rem
569 | ),
570 | web-browser-default-font-size: 16px
571 | );
572 | ```
573 |
574 |
575 | ##### #5.2 - Merging of several source files AND of the converted content into 1 sass map/block.
576 |
577 | Note that in addition to specifying one specific destination file, we are using the `--mo` command line option here to tell _json-to-scss_ to also merge sass objects.
578 |
579 | ###### Directory Structure:
580 |
581 | ```
582 | .
583 | ├─ Examples
584 | │ ├─ Example5
585 | │ │ └─ ProjectDir
586 | │ │ └─ tokens
587 | │ │ ├─ colors.js
588 | │ │ └─ fontSizes.js
589 | . .
590 | ```
591 |
592 | ###### Command:
593 |
594 | ```
595 | $ json-to-scss './Examples/Example5/ProjectDir/tokens/*.*' ./Examples/Example5/ProjectDir/scss/mergedTokenFilesAndObjects.scss --mo
596 | $ json-to-scss vX.Y.Z
597 | $ /.../Examples/Example5/ProjectDir/tokens/colors.js: content converted.
598 | $ /.../Examples/Example5/ProjectDir/tokens/fontSizes.json: content converted & merged. File created!
599 | $ /.../Examples/Example5/ProjectDir/scss/mergedTokenFilesAndObjects.scss
600 | ```
601 |
602 | ###### Output:
603 |
604 | ###### _Directory Structure:_
605 |
606 | ```
607 | .
608 | ├─ Examples
609 | │ ├─ Example5
610 | │ │ └─ ProjectDir
611 | │ │ ├─ scss
612 | │ │ │ └─ mergedTokenFilesAndObjects.scss
613 | │ │ └─ tokens
614 | │ │ ├─ colors.js
615 | │ │ └─ fontSizes.js
616 | . .
617 | ```
618 |
619 | ###### _mergedTokenFilesAndObjects.scss_
620 |
621 | ```scss
622 | $mergedTokenFilesAndObjects: (
623 | colors: (
624 | primary-color: #FFFFFF,
625 | accent-color: #0099FF
626 | ),
627 | font-sizes: (
628 | small: .875rem,
629 | medium: 1rem,
630 | large: 2rem
631 | ),
632 | web-browser-default-font-size: 16px
633 | );
634 | ```
635 |
--------------------------------------------------------------------------------
/bin/cli.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict';
3 | /**
4 | * JSON-TO-SCSS Command Line Interface.
5 | * @author Renaud Lapoële
6 | */
7 |
8 | /**
9 | * Module dependencies.
10 | */
11 | const path = require('path');
12 | const packageJson = require(path.join(__dirname, '../package.json'));
13 | const args = require('yargs').argv;
14 | const chalk = require('chalk');
15 | const glob = require('glob');
16 | const pathBasename = require('../lib/utils/path/basename');
17 | const removePathExtension = require('../lib/utils/path/removeExtension');
18 | const isString = require('../lib/utils/inspection/isString');
19 | const jsJsonFilesToSassScssFiles = require('../lib/jsJsonFilesToSassScssFiles');
20 |
21 | /**
22 | * @function banner
23 | * @param {string} name - the name of the package the banner is getting built for.
24 | * @param {string} version - the version number of the package the banner is getting built for.
25 | * @returns {string} this lib/package's name & version.
26 | * @description Returns a string containing the name and the version of this lib/package.
27 | */
28 | function banner(name, version) {
29 | return `${chalk.bold(`${name || 'NO NAME'} v${version || '0.0.0'}`)}`;
30 | }
31 |
32 | /**
33 | * @function usage
34 | * @param {string} name - the name of the package usage instructions are generated for.
35 | * @returns {string} the lib/package's usage text.
36 | * @description Returns the usage description of this lib/package.
37 | */
38 | function usage(name) {
39 | return `
40 | ${chalk.bold('Usage')}: ${chalk.yellow(
41 | name || 'NO NAME'
42 | )} [destination] [options]
43 |
44 | ${chalk.bold(
45 | 'source'
46 | )}: the path to a javascript, json or group of files to be converted.
47 | (required) - only '.js' and '.json' are processed.
48 |
49 | ${chalk.bold(
50 | 'destination'
51 | )}: the full or partial destination of the converted files.
52 | (optional) - when the destination is a directory path only, all generated
53 | files are saved in it with a default '.scss' extension. If
54 | a '.sass' extension is required instead, the --sass option must be included.
55 |
56 |
57 | ${chalk.bold('options')}:
58 |
59 | --h (help) Show this message.
60 | --p='prefix' (prefix) Prepend the converted sass/scss content with the prefix.
61 | Prefix is usually used & set to be used as sass variable name.
62 | Default '\${source-filename} :'.
63 | --no-underscore (no leading _) Remove any leading '_' (underscore) characters from the
64 | prefix when used as sass variable name.
65 | --s='suffix' (suffix) Append the converted sass/scss content with the suffix.
66 | Default: ';' (default not used if --sass)
67 | --tt='tabText' (tab text) Text to be used to indent or tabulate sass map.
68 | Default: ' ' (two space characters)
69 | --tn=tabNumber (tab number) Number of tabulations.
70 | Default: 1 (set to 0 if --sass)
71 | --es='sq'||'dq' (empty string) Sass/scss representation for an empty string (single or double quote).
72 | Default is '""': { "prop": "" } => $xyzfilename: ( prop: "" );
73 | --sass (sass ext.) Use sass extension.
74 | --mo (merge objects) Merge obtained sass strings into a single sass map/list.
75 | Enabled only if destination contains a full file name (name + .ext)
76 | --k='auto'|| (sass map keys) Sass/scss format for map keys.
77 | 'sq'||'dq' 'auto' (default): keys are formatted as per their converted type (number, ...)
78 | 'sq': all keys are single quoted.
79 | 'dq': all keys are doubled quoted.
80 | --v='auto'|| (sass map val.) Sass/scss format for map values other than nested maps.
81 | 'sq'||'dq' 'auto' (default): values are formatted as per their converted type
82 | 'sq': all values are single quoted.
83 | 'dq': all values are doubled quoted.
84 | Notes regarding 'sq' or 'dq' usage:
85 | 1- nested quote characters are automatically replaced by their counterpart.
86 | { "prop": 'Arial, "sans-serif"'} with 'dq' => ( prop: "Arial, 'sans-serif'" );
87 | 2- empty strings are formatted as per the given 'sq' or 'dq' option value regardless
88 | of the --es option.
89 | --fk (flatten keys) Flatten JSON/js object keys to produce series of sass/scss variables instead of a map.
90 | Provided prefix and suffix, if any, are applied to each flatten key.
91 | Key name elements (nested JSON object props) are dash separated (kebab-case).
92 | In case of flatten key name conflict(s), the latest processed key value is used.
93 | This option is not available in the js/JSON embed-able config.
94 | --fkc='kebab'|| (flat. key case) Flattened key case.
95 | 'camel' 'kebab' (default): nested keys are dash separated. No letter case change.
96 | 'camel': top level keys are left as-is whereas nested keys are capitalized before
97 | being concatenated. The nested key capitalization does not change the case of the
98 | subsequent letters: 'hEllO' => 'HEllO'.
99 |
100 |
101 |
102 |
103 | `;
104 | }
105 |
106 | /**
107 | * @function hasArgs
108 | * @param {object} args - command line arguments extracted via/from/with yargs.
109 | * @returns {boolean} true if args has an "_" property and if this property has a length property different than 0.
110 | * @description This is an internal small helper function to quickly assess if 'json-to-scss' is called without any params. Note that the code written here relies on the fact that we are using the 'yargs' package.
111 | */
112 | function hasArgs(args) {
113 | return '_' in args && args._.length;
114 | }
115 |
116 | /**
117 | * @function extensionCorrector
118 | * @param {string} defaultExtension - the destination file extension to be used by default.
119 | * @param {string} requiredExtension - the destination file extension which must be used.
120 | * @returns {Function} a function to be used as input for an Array.map(fn) function call.
121 | * @description Internal helper function encapsulating the destination file extension transformations.
122 | */
123 | function extensionCorrector(defaultExtension, requiredExtension) {
124 | return filepath => {
125 | function _correctFilepathExtension(extensionName) {
126 | let _switch = {
127 | '': () =>
128 | `${filepath}${
129 | '' !== requiredExtension ? requiredExtension : defaultExtension
130 | }`,
131 | '.scss': () =>
132 | '' === requiredExtension || requiredExtension === extensionName
133 | ? filepath
134 | : `${removePathExtension(filepath)}${requiredExtension}`,
135 | '.sass': () =>
136 | '' === requiredExtension || requiredExtension === extensionName
137 | ? filepath
138 | : `${removePathExtension(filepath)}${requiredExtension}`,
139 | default: () =>
140 | `${removePathExtension(filepath)}${
141 | '' !== requiredExtension ? requiredExtension : defaultExtension
142 | }`
143 | };
144 | return (_switch[extensionName] || _switch['default'])();
145 | }
146 |
147 | return _correctFilepathExtension(path.extname(filepath).toLowerCase());
148 | };
149 | }
150 |
151 | /**
152 | * @function basenameExtractor
153 | * @param {string} filepath - the file path from which we want to extract the basename.
154 | * @returns {string} the file path basename.
155 | * @description Internal helper & wrapper function extracting the file path's base name.
156 | */
157 | function basenameExtractor(filepath) {
158 | return pathBasename(filepath);
159 | }
160 |
161 | /**
162 | * @function dirnameSetter
163 | * @param {string} dirname - the directory name we want to use for our destination file paths.
164 | * @returns {function} a function to be used as input for an Array.map(fn) function call.
165 | * @description set the directory(ies) for the given destination file path.
166 | */
167 | function dirnameSetter(dirname) {
168 | return filepath => path.resolve(path.join(dirname, filepath));
169 | }
170 |
171 | /**
172 | * @function normalizeArgs
173 | * @param {object} args - command line program arguments (built by the yargs package) to be normalized.
174 | * @returns {{source: {paths: *}, destination: {paths: (*|Array)}, options: {prefix: string | string, suffix: (*|string), emptyString: string, indentationText: (*|string), indentationSize: (*|number), noUnderscore: boolean, format: string}}}
175 | * @description check & normalize the command line program arguments.
176 | */
177 | function normalizeArgs(args) {
178 | const _source = path.resolve(process.cwd(), `${args._[0]}`);
179 | const _sourcePaths = glob.sync(_source);
180 | const _defaultExtension = '.scss';
181 | let _requiredExtension = 'sass' in args ? '.sass' : '';
182 |
183 | const _destination =
184 | args._.length > 1 ? path.resolve(process.cwd(), `${args._[1]}`) : '';
185 | const _destinationExtname = path.extname(_destination).toLowerCase();
186 |
187 | let _destinationPaths = [];
188 | if ('' === _destination) {
189 | _destinationPaths = _sourcePaths.map(
190 | extensionCorrector(_defaultExtension, _requiredExtension)
191 | );
192 | } else {
193 | if ('' !== _destinationExtname) {
194 | if ('.sass' === _destinationExtname || '.scss' === _destinationExtname) {
195 | _requiredExtension = _destinationExtname;
196 | _destinationPaths = [_destination];
197 | } else {
198 | _destinationPaths = [removePathExtension(_destination)].map(
199 | extensionCorrector(_defaultExtension, _requiredExtension)
200 | );
201 | }
202 | } else {
203 | _destinationPaths = _sourcePaths
204 | .map(basenameExtractor)
205 | .map(extensionCorrector(_defaultExtension, _requiredExtension))
206 | .map(dirnameSetter(_destination));
207 | }
208 | }
209 | const _mergeSourceFiles =
210 | _sourcePaths.length > 1 && _sourcePaths.length !== _destinationPaths.length;
211 |
212 | return {
213 | source: {
214 | paths: _sourcePaths
215 | },
216 | destination: {
217 | paths: _destinationPaths
218 | },
219 | options: {
220 | prefix: 'p' in args ? args.p : '',
221 | suffix: 's' in args ? args.s : ';',
222 | emptyString: 'es' in args && 'sq' === args.es ? "''" : '""',
223 | indentationText: 'tt' in args ? args.tt : ' ',
224 | indentationSize: 'tn' in args ? args.tn : 1,
225 | noUnderscore: !('underscore' in args),
226 | format:
227 | '' === _requiredExtension ? _defaultExtension : _requiredExtension,
228 | mergeSourceFiles: _mergeSourceFiles,
229 | mergeSassObjects: _mergeSourceFiles && 'mo' in args,
230 | keys: 'k' in args ? ['auto', 'sq', 'dq'].indexOf(args.k) > -1 ? args.k : 'auto' : 'auto',
231 | values: 'v' in args ? ['auto', 'sq', 'dq'].indexOf(args.v) > -1 ? args.v : 'auto' : 'auto',
232 | stringKeys: 'sk' in args && isString(args.sk) ? args.sk : 'family,font-family,fontfamily,font-stack,fontstack,font-face,fontface',
233 | flattenKeys: 'fk' in args,
234 | flattenedKeyCase: 'fkc' in args ? ['kebab', 'camel'].indexOf(args.fkc) > -1 ? args.fkc : 'kebab' : 'kebab'
235 | }
236 | };
237 | }
238 |
239 | /**
240 | * The 'json-to-scss' main function in charge of parsing arguments and, if possible,
241 | * executing the file conversion.
242 | */
243 | function main() {
244 | console.log(banner(packageJson.name, packageJson.version));
245 | if (hasArgs(args)) {
246 | if ('h' in args) {
247 | console.log(usage(packageJson.name));
248 | } else {
249 | const _nargs = normalizeArgs(args);
250 | if (_nargs.source.paths.length) {
251 | jsJsonFilesToSassScssFiles(
252 | _nargs.source.paths,
253 | _nargs.destination.paths,
254 | _nargs.options.prefix,
255 | _nargs.options.suffix,
256 | _nargs.options.format,
257 | _nargs.options.indentationText,
258 | _nargs.options.indentationSize,
259 | _nargs.options.emptyString,
260 | _nargs.options.noUnderscore,
261 | _nargs.options.mergeSourceFiles,
262 | _nargs.options.mergeSassObjects,
263 | _nargs.options.keys,
264 | _nargs.options.values,
265 | _nargs.options.stringKeys,
266 | _nargs.options.flattenKeys,
267 | _nargs.options.flattenedKeyCase
268 | );
269 | } else {
270 | console.log(
271 | `Hmmm strange... ${chalk.red(
272 | args._[0]
273 | )} cannot be found. Could there be a small mistake in the source path?`
274 | );
275 | }
276 | }
277 | } else {
278 | console.log(usage(packageJson.name));
279 | }
280 | }
281 |
282 | /**
283 | * Execute the main module function.
284 | */
285 | main();
286 |
--------------------------------------------------------------------------------
/lib/jsJsonFilesToSassScssFiles.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /**
3 | * @module json-to-scss/lib/jsJsonFilesToSassScssFiles
4 | * @author Renaud Lapoële
5 | */
6 |
7 | /**
8 | * Modules imports/dependencies.
9 | */
10 | const fs = require('fs');
11 | const path = require('path');
12 | const terminal = require('terminal-overwrite');
13 | const emoji = require('node-emoji');
14 | const chalk = require('chalk');
15 | const pathBasename = require('../lib/utils/path/basename');
16 | const hasExtension = require('../lib/utils/path/hasExtension');
17 | const createPathDirectories = require('../lib/utils/path/createPathDirectories');
18 | const isBoolean = require('../lib/utils/inspection/isBoolean');
19 | const isPositiveInteger = require('../lib/utils/inspection/isPositiveInteger');
20 | const isString = require('../lib/utils/inspection/isString');
21 | const jsValueToSassString = require('../lib/jsValueToSassString');
22 | const flattenObject = require('../lib/utils/transformation/flattenObject');
23 |
24 | /**
25 | * @function jsJsonFilesToSassScssFiles
26 | * @param {array} sourceFilepaths - an array of "resolved" source file paths.
27 | * @param {array} destinationFilepaths - an array of destination file paths; it length must be equal to the source file path array's length.
28 | * @param {string} prefix
29 | * @param {string} suffix
30 | * @param {string} format
31 | * @param {string} indentationText
32 | * @param {number} indentationSize
33 | * @param {string} emptyString - '' or "".
34 | * @param {boolean} noUnderscore
35 | * @param {boolean} mergeSourceFiles
36 | * @param {boolean} mergeSassObjects
37 | * @param {string} keyFormat - 'auto', 'sq' or 'dq'
38 | * @param {string} valueFormat - 'auto', 'sq' or 'dq'
39 | * @param {string} stringKeys
40 | * @param {boolean} flattenKeys
41 | * @param {string} flattenedKeyCase
42 | * @description Converts node js (.js files exporting an object...) & json files to sass or scss files.
43 | */
44 | function jsJsonFilesToSassScssFiles(
45 | sourceFilepaths,
46 | destinationFilepaths,
47 | prefix,
48 | suffix,
49 | format,
50 | indentationText,
51 | indentationSize,
52 | emptyString,
53 | noUnderscore,
54 | mergeSourceFiles,
55 | mergeSassObjects,
56 | keyFormat,
57 | valueFormat,
58 | stringKeys,
59 | flattenKeys,
60 | flattenedKeyCase
61 | ) {
62 | let mergedSassStrings = '';
63 |
64 | /**
65 | * @private
66 | * @function _convertFile
67 | * @param {string} filepath
68 | * @param {number} fileindex
69 | * @description loads, converts and potentially (no merge context) saves converted content into a file.
70 | */
71 | function _convertFile(filepath, fileindex) {
72 | terminal(`${emoji.get('gear')} ${chalk.blue(filepath)}:`);
73 | const _filepathExtension = path.extname(filepath);
74 |
75 | // skip any files if extension is <> than ".js" or ".json".
76 | if (-1 === ['.js', '.json'].indexOf(_filepathExtension)) {
77 | terminal(
78 | `${emoji.get('x')} ${chalk.blue(
79 | filepath
80 | )}: unsupported file format: "${_filepathExtension}". ${chalk.yellow(
81 | 'File skipped!'
82 | )}\n`
83 | );
84 | } else {
85 | let _prefix = prefix;
86 | let _suffix = suffix;
87 | let _indentationText = indentationText;
88 | let _indentationSize = indentationSize;
89 | let _emptyString = emptyString;
90 | let _noUnderscore = noUnderscore;
91 | let _destinationFilepath = mergeSourceFiles
92 | ? destinationFilepaths[0]
93 | : destinationFilepaths[fileindex];
94 | let _destinationFilename = '';
95 | let _keyFormat = keyFormat;
96 | let _valueFormat = valueFormat;
97 | let _stringKeys = stringKeys.split(',').map((v) => v.trim().toUpperCase());
98 | let _flattenKeys = flattenKeys;
99 | let _jsObject = {};
100 | let _errorFlag = false;
101 |
102 | // let's try to "import" the source file.
103 | try {
104 | _jsObject = require(filepath);
105 | } catch (error) {
106 | // Oops - something went wrong (most likely a JSON format error).
107 | terminal(
108 | `${emoji.get('-1')} ${chalk.blue(
109 | filepath
110 | )}: error(s) found while parsing; content skipped. ${chalk.yellow(
111 | 'File skipped!'
112 | )}\n`
113 | );
114 | _errorFlag = true;
115 | }
116 |
117 | // verify that no error occurred previously and if it did, then skip the
118 | // rest of the process for the concerned file.
119 | if (!_errorFlag) {
120 | // let's check if the source content has a local config (option set)
121 | // defined.
122 | if ('_jsonToScss' in _jsObject) {
123 | const { _jsonToScss } = _jsObject;
124 |
125 | // if yes, then use its content:
126 | // get prefix if there is one defined.
127 | if ('prefix' in _jsonToScss && isString(_jsonToScss.prefix)) {
128 | _prefix = _jsObject._jsonToScss.prefix;
129 | }
130 |
131 | // get suffix if one is specified.
132 | if ('suffix' in _jsonToScss && isString(_jsonToScss.suffix)) {
133 | _suffix = _jsObject._jsonToScss.suffix;
134 | }
135 |
136 | // if no merge && indentationText then grab it.
137 | if (
138 | !mergeSourceFiles &&
139 | 'indentationText' in _jsonToScss &&
140 | isString(_jsonToScss.indentationText)
141 | ) {
142 | _indentationText = _jsObject._jsonToScss.indentationText;
143 | }
144 |
145 | // if no merge && indentationSize then grab it.
146 | if (
147 | !mergeSourceFiles &&
148 | 'indentationSize' in _jsonToScss &&
149 | isPositiveInteger(_jsonToScss.indentationSize)
150 | ) {
151 | _indentationSize = _jsObject._jsonToScss.indentationSize;
152 | }
153 |
154 | // if no merge && emptyString then get it.
155 | if (
156 | !mergeSourceFiles &&
157 | 'emptyString' in _jsonToScss &&
158 | ('""' === _jsonToScss.emptyString ||
159 | "''" === _jsonToScss.emptyString)
160 | ) {
161 | _emptyString = _jsObject._jsonToScss.emptyString;
162 | }
163 |
164 | // if noUnderscore, then use it.
165 | if (
166 | 'noUnderscore' in _jsonToScss &&
167 | isBoolean(_jsonToScss.noUnderscore)
168 | ) {
169 | _noUnderscore = _jsObject._jsonToScss.noUnderscore;
170 | }
171 |
172 | // if sassVariableName, then grab it and reset prefix if no file merge.
173 | if (
174 | !mergeSourceFiles &&
175 | 'sassVariableName' in _jsonToScss &&
176 | isString(_jsonToScss.sassVariableName) &&
177 | _jsonToScss.sassVariableName.length
178 | ) {
179 | _prefix = _flattenKeys
180 | ? `$${_jsonToScss.sassVariableName}`
181 | : `$${_jsonToScss.sassVariableName}: `;
182 | }
183 |
184 |
185 | // if no merge and good filename :) then prepare it and update the
186 | // "copy" of the original destination file path.
187 | if (
188 | !mergeSourceFiles &&
189 | 'filename' in _jsonToScss &&
190 | isString(_jsonToScss.filename) &&
191 | _jsonToScss.filename.length
192 | ) {
193 | _destinationFilename = hasExtension(_jsonToScss.filename)
194 | ? pathBasename(_jsonToScss.filename)
195 | : _jsObject._jsonToScss.filename;
196 |
197 | if (_destinationFilename.length) {
198 | _destinationFilepath = `${path.join(
199 | path.dirname(_destinationFilepath),
200 | _destinationFilename
201 | )}${path.extname(_destinationFilepath)}`;
202 | }
203 | }
204 |
205 | // check if sass map keys formatting (wrapping in quotes) is required.
206 | if (
207 | 'keyFormat' in _jsonToScss &&
208 | -1 !== ['auto','sq','dq'].indexOf(_jsonToScss.keyFormat)
209 | ) {
210 | _keyFormat = _jsonToScss.keyFormat;
211 | }
212 |
213 | // check if sass map values formatting (wrapping in quotes) is required.
214 | if (
215 | 'valueFormat' in _jsonToScss &&
216 | -1 !== ['auto','sq','dq'].indexOf(_jsonToScss.valueFormat)
217 | ) {
218 | _valueFormat = _jsonToScss.valueFormat;
219 | }
220 |
221 | // check if some props must be treated as string forcefully.
222 | if (
223 | 'stringKeys' in _jsonToScss &&
224 | isString(_jsonToScss.stringKeys)) {
225 | _stringKeys = _jsonToScss.stringKeys.split(',').map((v) => v.trim().toUpperCase())
226 | }
227 |
228 | // let us remove the local config from the content.
229 | delete _jsObject._jsonToScss;
230 | }
231 |
232 | // if no prefix is specified then set one using:
233 | // - $ if flattenKeys option is on
234 | // else
235 | // - the source filename (as sass variable) if we are merging several
236 | // sources into one destination.
237 | // or at last
238 | // - the destination filename otherwise.
239 | if ('' === _prefix) {
240 | _prefix =
241 | _flattenKeys
242 | ? '$'
243 | : (mergeSourceFiles && mergeSassObjects) || !mergeSourceFiles
244 | ? `$${pathBasename(_destinationFilepath)}: `
245 | : `$${pathBasename(filepath)}: `;
246 | }
247 |
248 | // if sass format is required then disable the sass content indentation
249 | // and if the suffix starts and/or ends with ";" then remove it.
250 | // this is currently kept basic as it could become very complex very
251 | // fast otherwise.
252 | if ('.sass' === format) {
253 | _indentationSize = 0;
254 | _suffix = _suffix.trim();
255 |
256 | if (_suffix.startsWith(';')) {
257 | _suffix = _suffix.slice(1);
258 | }
259 |
260 | if (_suffix.endsWith(';')) {
261 | _suffix = _suffix.slice(0, -1);
262 | }
263 | }
264 |
265 | // let's see if the --no-underscore option was set and if so, then while
266 | // the prefix starts with "$_" let's remove the "_".
267 | if (_noUnderscore) {
268 | while (_prefix.startsWith('$_')) {
269 | _prefix = `$${_prefix.slice(2)}`;
270 | }
271 | }
272 |
273 | let _sassString = '';
274 |
275 | if (_flattenKeys && !!Object.keys(_jsObject).length) {
276 | // convert all nested objects into flat objects and convert the results
277 | // into a series of sass/scss variables.
278 | let _flattenObject = flattenObject(_jsObject, flattenedKeyCase);
279 |
280 | let count = 0;
281 | for (let _aJsObjectKey in _flattenObject) {
282 | let _newSassString = `${jsValueToSassString(
283 | _flattenObject[_aJsObjectKey],
284 | _indentationText,
285 | _indentationSize,
286 | _emptyString,
287 | _keyFormat,
288 | _valueFormat,
289 | _stringKeys
290 | )}`;
291 |
292 | _sassString = 0 === count
293 | ? `${_prefix}${_aJsObjectKey}: ${_newSassString}${_suffix}`
294 | : `${_sassString}\n${_prefix}${_aJsObjectKey}: ${_newSassString}${_suffix}`
295 |
296 | count++;
297 | }
298 | //if (0 < _sassString.length) {
299 | // _sassString = `${_sassString}\n`;
300 | //}
301 | }
302 | else {
303 | // convert the js object into a sass string.
304 | _sassString = `${jsValueToSassString(
305 | _jsObject,
306 | _indentationText,
307 | _indentationSize,
308 | _emptyString,
309 | _keyFormat,
310 | _valueFormat,
311 | _stringKeys
312 | )}`;
313 | }
314 |
315 | terminal(
316 | `${emoji.get('hourglass_flowing_sand')} ${chalk.blue(
317 | filepath
318 | )}: content converted.`
319 | );
320 | if (0 === Object.keys(_jsObject).length) {
321 | terminal(
322 | `${emoji.get('-1')} ${chalk.blue(
323 | filepath
324 | )}: no convertible content found. ${chalk.yellow(
325 | 'File skipped!'
326 | )}\n`
327 | );
328 | }
329 | else {
330 | if (!mergeSourceFiles) {
331 | try {
332 | // ensure that the destination directory(ies) exist and if not
333 | // create it.
334 | createPathDirectories(_destinationFilepath);
335 |
336 | // let's write the file.
337 | // Ignore prefix and suffix if js object has been flatten.
338 | fs.writeFileSync(
339 | _destinationFilepath,
340 | _flattenKeys ? `${_sassString}\n` : `${_prefix}${_sassString}${_suffix}\n`
341 | );
342 |
343 | terminal(
344 | `${emoji.get('hourglass')} ${chalk.blue(filepath)}: content converted. ${chalk.green('File created!')}\n`
345 | );
346 | terminal(
347 | ` ${emoji.get('+1')} ${chalk.green(_destinationFilepath)}\n`
348 | );
349 | } catch (error) {
350 | terminal(
351 | `${emoji.get('-1')} ${chalk.blue(
352 | filepath
353 | )}: Oops! Something went wrong when trying to write the converted file. ${chalk.yellow(
354 | 'File skipped!'
355 | )}\n`
356 | );
357 | }
358 | }
359 | else {
360 | if (mergeSassObjects && !_flattenKeys) {
361 | // Objects coming from several files must be merged but not flattened.
362 |
363 | // First file to be processed?
364 | if (0 === fileindex) {
365 | // first file of many and sass value is map?
366 | if (
367 | fileindex < sourceFilepaths.length - 1 &&
368 | _sassString.endsWith('\n)')
369 | ) {
370 | _sassString = _sassString.slice(0, -2);
371 | }
372 | mergedSassStrings = `${_prefix}${_sassString}`;
373 | terminal(
374 | `${emoji.get('hourglass')} ${chalk.blue(
375 | filepath
376 | )}: content converted.\n`
377 | );
378 | }
379 | // Not the first file?
380 | if (
381 | 0 < fileindex &&
382 | fileindex <= sourceFilepaths.length - 1
383 | ) {
384 | // is sass value map?
385 | if (_sassString.startsWith('(\n')) {
386 | _sassString = _sassString.slice(2);
387 | }
388 |
389 | // is sass value map and file is not last?
390 | if (
391 | fileindex < sourceFilepaths.length - 1 &&
392 | _sassString.endsWith('\n)')
393 | ) {
394 | _sassString = _sassString.slice(0, -2);
395 | }
396 |
397 | mergedSassStrings = `${mergedSassStrings},\n${_sassString}`;
398 | if (fileindex < sourceFilepaths.length - 1) {
399 | terminal(
400 | `${emoji.get('hourglass')} ${chalk.blue(
401 | filepath
402 | )}: content converted & merged.\n`
403 | );
404 | } else {
405 | }
406 | }
407 | // Is file being processed the last?
408 | if (fileindex === sourceFilepaths.length - 1) {
409 | mergedSassStrings = `${mergedSassStrings}${_suffix}\n`;
410 | try {
411 | // file being processed is the last one so now we can save the
412 | // "merged" content.
413 | createPathDirectories(_destinationFilepath);
414 |
415 | // let's write the file.
416 | fs.writeFileSync(_destinationFilepath, mergedSassStrings);
417 |
418 | terminal(
419 | `${emoji.get('hourglass')} ${chalk.blue(
420 | filepath
421 | )}: content converted & merged. ${chalk.green(
422 | 'File created!'
423 | )}\n`
424 | );
425 | terminal(
426 | ` ${emoji.get('+1')} ${chalk.green(
427 | _destinationFilepath
428 | )}\n`
429 | );
430 | } catch (error) {
431 | terminal(
432 | `${emoji.get('-1')} ${chalk.blue(
433 | filepath
434 | )}: Oops! Something went wrong when trying to write the converted content file. ${chalk.yellow(
435 | 'File skipped!'
436 | )}\n`
437 | );
438 | }
439 | }
440 | }
441 | else {
442 | // merge scenario so append new converted content to the existing
443 | // one.
444 | mergedSassStrings = _flattenKeys
445 | ? `${mergedSassStrings}${_sassString}\n`
446 | : `${mergedSassStrings}${_prefix}${_sassString}${_suffix}\n`;
447 |
448 | // is the source file being processed the last one?
449 | // No, then let the user know that the source content was
450 | // converted but nothing more/else.
451 | if (fileindex < sourceFilepaths.length - 1) {
452 | terminal(
453 | `${emoji.get('hourglass')} ${chalk.blue(
454 | filepath
455 | )}: content converted.\n`
456 | );
457 | }
458 | else {
459 | try {
460 | // file being processed is the last one so now we can save the
461 | // "merged" content.
462 | createPathDirectories(_destinationFilepath);
463 |
464 | // let's write the file.
465 | fs.writeFileSync(_destinationFilepath, mergedSassStrings);
466 |
467 | terminal(
468 | `${emoji.get('hourglass')} ${chalk.blue(
469 | filepath
470 | )}: content converted. ${chalk.green('File created!')}\n`
471 | );
472 | terminal(
473 | ` ${emoji.get('+1')} ${chalk.green(
474 | _destinationFilepath
475 | )}\n`
476 | );
477 | } catch (error) {
478 | terminal(
479 | `${emoji.get('-1')} ${chalk.blue(
480 | filepath
481 | )}: Oops! Something went wrong when trying to write the converted content file. ${chalk.yellow(
482 | 'File skipped!'
483 | )}\n`
484 | );
485 | }
486 | }
487 | }
488 | }
489 | }
490 | }
491 | }
492 | }
493 |
494 | // iterate through each input source file and perform conversion when possible.
495 | sourceFilepaths.forEach(_convertFile);
496 | }
497 |
498 | /**
499 | * Module exports.
500 | */
501 | module.exports = jsJsonFilesToSassScssFiles;
502 |
--------------------------------------------------------------------------------
/lib/jsValueToSassString.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /**
3 | * @module json-to-scss/lib/jsValueToSassString
4 | * @author Renaud Lapoële
5 | */
6 |
7 | /**
8 | * Module imports/dependencies.
9 | */
10 | const isPlainObject = require('lodash.isplainobject');
11 | const isNull = require('./utils/inspection/isNull');
12 | const isUndefined = require('./utils/inspection/isUndefined');
13 | const { isArray } = Array;
14 |
15 | /**
16 | * Module constants (or alike)
17 | */
18 | const FN_DEFAULT_INDENTATION_TEXT = ' ';
19 | const FN_DEFAULT_INDENTATION_SIZE = 1;
20 | const FN_DEFAULT_EMPTY_STRING = '""';
21 | const FN_FORMAT_AUTO = 'auto';
22 | const FN_DEFAULT_KEY_FORMAT = FN_FORMAT_AUTO;
23 | const FN_DEFAULT_VALUE_FORMAT = FN_FORMAT_AUTO;
24 | const FN_DEFAULT_STRING_KEYS = [];
25 | const FN_FORMAT_SINGLE_QUOTED = 'sq';
26 |
27 | /**
28 | * @function jsValueToSassString
29 | * @param {*} value - the js value to be converted into a string compatible with sass/scss syntax.
30 | * @param {string} indentationText - the string to be used as indentation text.
31 | * @param {number} indentationSize - the number of time the indentation text must be repeated per indentation level.
32 | * @param {string} emptyString
33 | * @param {string} keyFormat - an indicator telling how sass map keys must be formatted.
34 | * @param {string} valueFormat - an indicator telling how sass map values must be formatted.
35 | * @param {array} stringKeys - an array containing property names for which values must be forcefully "quoted" (e.g: font-family).
36 | * @returns {string} string sass representation of the value.
37 | * @description Converts a javascript value into a string compatible with sass/scss syntax.
38 | */
39 | function jsValueToSassString(
40 | value,
41 | indentationText = FN_DEFAULT_INDENTATION_TEXT,
42 | indentationSize = FN_DEFAULT_INDENTATION_SIZE,
43 | emptyString = FN_DEFAULT_EMPTY_STRING,
44 | keyFormat = FN_DEFAULT_KEY_FORMAT,
45 | valueFormat = FN_DEFAULT_VALUE_FORMAT,
46 | stringKeys= FN_DEFAULT_STRING_KEYS
47 | ) {
48 |
49 | /**
50 | * @private
51 | * @function _formatString
52 | * @param {string} string - the string to be formatted.
53 | * @param {string} format - the format to be used.
54 | * @returns {string}
55 | */
56 | function _formatString(string, format) {
57 | if ('string' !== typeof string) {
58 | return string;
59 | }
60 | if (!string) {
61 | return format === FN_FORMAT_AUTO ?
62 | emptyString :
63 | format === FN_FORMAT_SINGLE_QUOTED ?
64 | "''":
65 | '""';
66 | }
67 | else {
68 | let sqRegExp = /'/g;
69 | let dqRegExp = /"/g;
70 | let _sqString = string.replace(sqRegExp, '"');
71 | let _dqString = string.replace(dqRegExp, "'");
72 | return format === FN_FORMAT_AUTO ?
73 | string :
74 | format === FN_FORMAT_SINGLE_QUOTED ?
75 | `'${_sqString}'` :
76 | `"${_dqString}"`;
77 | }
78 | }
79 |
80 | function _quoteIfStringKey(propertyName, value, quoteFormat) {
81 | if ('' !== propertyName) {
82 | if (stringKeys.includes(propertyName.toUpperCase())) {
83 | return quoteFormat === FN_FORMAT_SINGLE_QUOTED ? `'${value}'` : `"${value}"`;
84 | }
85 | }
86 | return value;
87 | }
88 |
89 |
90 | // computed flag.
91 | const mustIndent = '' !== indentationText && 0 !== indentationSize;
92 |
93 | /**
94 | * @private
95 | * @function _process
96 | * @param {*|string} propertyName - the property for which the value is being processed.
97 | * @param {*} value - the js value to be converted into a sass string.
98 | * @param {number} indentationLevel - a positive integer reflecting the desired level of indentation.
99 | * @returns {*|string} string sass representation of the value.
100 | * @description actual implementation of the `jsValueToSassString` function.
101 | */
102 | function _process(propertyName, value, indentationLevel) {
103 | const _switch = {
104 | boolean: () => _formatString(value.toString(), valueFormat),
105 | number: () => _formatString(value.toString(), valueFormat),
106 | string: () => _formatString(value, valueFormat),
107 | object: () => {
108 | if (isPlainObject(value)) {
109 | let _jsObj = value;
110 | let _sassKeyValPairs = Object.keys(_jsObj).reduce(
111 | (result, key) => {
112 | let _jsVal = _jsObj[key];
113 | let _propName = isPlainObject(_jsVal) ? '' : key;
114 | let _sassVal = _process(_propName, _jsVal, indentationLevel + 1);
115 | if (!isUndefined(_sassVal)) {
116 | result.push(`${_formatString(key, keyFormat)}: ${_quoteIfStringKey(_propName, _sassVal, valueFormat)}`);
117 | }
118 | return result;
119 | },
120 | []
121 | );
122 |
123 | let _result = '';
124 | if (mustIndent) {
125 | let _indentIn = indentationText.repeat(
126 | indentationSize * (indentationLevel + 1)
127 | );
128 | let _indentOut = indentationText.repeat(
129 | indentationSize * indentationLevel
130 | );
131 | _result = `(\n${_indentIn +
132 | _sassKeyValPairs.join(`,\n${_indentIn}`)}\n${_indentOut})`;
133 | } else
134 | _result = `(${_sassKeyValPairs.join(', ')})`;
135 |
136 | return _result;
137 | }
138 | else if (isArray(value)) {
139 | let _sassVals = value.reduce(
140 | (result, v) => {
141 | if (!isUndefined(v))
142 | result.push(_process('', v, indentationLevel));
143 | return result;
144 | },
145 | []
146 | );
147 | return `(${_sassVals.join(', ')})`;
148 | }
149 | else if (isNull(value)) {
150 | return 'null';
151 | }
152 | return _formatString(value.toString(), valueFormat);
153 | },
154 | default: () => {}
155 | };
156 | return (_switch[typeof value] || _switch['default'])();
157 | }
158 |
159 | return _process('', value, 0);
160 | }
161 |
162 | /**
163 | * Module exports.
164 | */
165 | module.exports = jsValueToSassString;
166 |
--------------------------------------------------------------------------------
/lib/utils/inspection/isBoolean.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /**
3 | * @module lib/utils/inspection/isBoolean
4 | * @author Renaud Lapoële
5 | */
6 |
7 | /**
8 | * @function isBoolean
9 | * @param {*} value - the value to check.
10 | * @returns {boolean} true if the given value is a boolean, false otherwise.
11 | * @description A Function to verify whether a value is a boolean or not.
12 | */
13 | function isBoolean(value) {
14 | return typeof value === 'boolean';
15 | }
16 |
17 | /**
18 | * Module exports.
19 | */
20 | module.exports = isBoolean;
21 |
--------------------------------------------------------------------------------
/lib/utils/inspection/isNull.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /**
3 | * @module lib/utils/inspection/isNull
4 | * @author Renaud Lapoële
5 | */
6 |
7 | /**
8 | * @function isNull
9 | * @param {*} value
10 | * @returns {boolean} true if the value is null, false otherwise
11 | * @description A function to check whether a given value is null or not.
12 | */
13 | function isNull(value) {
14 | return value === null;
15 | }
16 |
17 | /**
18 | * Module exports.
19 | */
20 | module.exports = isNull;
21 |
--------------------------------------------------------------------------------
/lib/utils/inspection/isPositiveInteger.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /**
3 | * @module lib/utils/inspection/isPositiveInteger
4 | * @author Renaud Lapoële
5 | */
6 |
7 | /**
8 | * Module imports.
9 | */
10 | const isInteger = require('lodash.isinteger');
11 |
12 | /**
13 | * @function isPositiveInteger
14 | * @param {*} value - the value to check.
15 | * @returns {boolean} true if the value passed as argument is an integer and is positive.
16 | * @description A function to check whether a given value is a positive integer or not.
17 | */
18 | function isPositiveInteger(value) {
19 | return isInteger(value) && 0 <= value;
20 | }
21 |
22 | /**
23 | * Module exports.
24 | */
25 | module.exports = isPositiveInteger;
26 |
--------------------------------------------------------------------------------
/lib/utils/inspection/isString.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /**
3 | * @module lib/utils/inspection/isString
4 | * @author Renaud Lapoële
5 | */
6 |
7 | /**
8 | * @function isString
9 | * @param {*} value - the value to check.
10 | * @returns {boolean} true if the given value is a string, false otherwise.
11 | * @description A Function to verify whether a value is a string or not.
12 | */
13 | function isString(value) {
14 | return typeof value === 'string';
15 | }
16 |
17 | /**
18 | * Module exports.
19 | */
20 | module.exports = isString;
21 |
--------------------------------------------------------------------------------
/lib/utils/inspection/isUndefined.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /**
3 | * @module lib/utils/inspection/isUndefined
4 | * @author Renaud Lapoële
5 | */
6 |
7 | /**
8 | * @function isUndefined
9 | * @param {*} value - the value to check.
10 | * @returns {boolean} - true if the typeof value is 'undefined' and false otherwise.
11 | * @description A Function to verify whether a value is undefined or not.
12 | */
13 | function isUndefined(value) {
14 | return typeof value === 'undefined';
15 | }
16 |
17 | /**
18 | * Module exports.
19 | */
20 | module.exports = isUndefined;
21 |
--------------------------------------------------------------------------------
/lib/utils/path/basename.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /**
3 | * @module lib/utils/path/basename
4 | * @author Renaud Lapoële
5 | */
6 |
7 | /**
8 | * Module imports/dependencies.
9 | */
10 | const path = require('path');
11 |
12 | /**
13 | * @function basename
14 | * @param {string} filePath
15 | * @returns {string} the basename of the file path minus its extension(s).
16 | * @description Extract a file name from a file path.
17 | */
18 | function basename(filePath) {
19 | const _filePathExtension = path.extname(filePath);
20 | const _filePathBasename = path.basename(filePath, _filePathExtension);
21 | return '' !== _filePathExtension
22 | ? basename(_filePathBasename)
23 | : _filePathBasename;
24 | }
25 |
26 | /**
27 | * Module exports.
28 | */
29 | module.exports = basename;
30 |
--------------------------------------------------------------------------------
/lib/utils/path/createPathDirectories.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /**
3 | * @module lib/utils/path/createPathDirectories
4 | * @author Renaud Lapoële
5 | */
6 |
7 | /**
8 | * Module imports/dependencies
9 | */
10 | const path = require('path');
11 | const fs = require('fs');
12 |
13 | /**
14 | * @function createPathDirectories
15 | * @param {string} filepath
16 | * @returns {void|boolean} true if the directory(ies) already exist nothing otherwise.
17 | * @description Creates missing path directories.
18 | */
19 | function createPathDirectories(filepath) {
20 | const dirname = path.dirname(filepath);
21 | if (fs.existsSync(dirname)) {
22 | return true;
23 | }
24 | createPathDirectories(dirname);
25 | fs.mkdirSync(dirname);
26 | }
27 |
28 | /**
29 | * Module exports.
30 | */
31 | module.exports = createPathDirectories;
32 |
--------------------------------------------------------------------------------
/lib/utils/path/hasExtension.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /**
3 | * @module lib/utils/path/hasExtension
4 | * @author Renaud Lapoële
5 | */
6 |
7 | /**
8 | * Module imports/dependencies.
9 | */
10 | const path = require('path');
11 |
12 | /**
13 | * @function hasExtension
14 | * @param {string} filePath - the file path for which one wants to know if it has an extension.
15 | * @returns {boolean} true if the file path given as argument has an extension (.xxx), false otherwise.
16 | * @description Returns true if the filePath has an extension.
17 | */
18 | function hasExtension(filePath) {
19 | return '' !== path.extname(filePath);
20 | }
21 |
22 | /**
23 | * Module exports.
24 | */
25 | module.exports = hasExtension;
26 |
--------------------------------------------------------------------------------
/lib/utils/path/removeExtension.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /**
3 | * @module lib/utils/path/removeExtension
4 | * @author Renaud Lapoële
5 | */
6 |
7 | /**
8 | * Module imports/dependencies
9 | */
10 | const path = require('path');
11 |
12 | /**
13 | * @function removeExtension
14 | * @param {string} filePath - path from which file extension(s) must be removed.
15 | * @param {boolean} removeExtensionRecursively - indicates if, in case file path has multiple extensions, extensions must all be removed.
16 | * @returns {string} the file path with less or without any file extension.
17 | * @description Removes one and/or all file extensions from a file path.
18 | */
19 | function removeExtension(filePath, removeExtensionRecursively = false) {
20 | const _extname = path.extname(filePath);
21 | if ('' === _extname) {
22 | return filePath;
23 | } else {
24 | const _filePath = path.join(
25 | path.dirname(filePath),
26 | path.basename(filePath, _extname)
27 | );
28 | if (removeExtensionRecursively) {
29 | if ('' === path.extname(_filePath)) {
30 | return _filePath;
31 | } else {
32 | return removeExtension(_filePath);
33 | }
34 | } else {
35 | return _filePath;
36 | }
37 | }
38 | }
39 |
40 | /**
41 | * Module exports.
42 | */
43 | module.exports = removeExtension;
44 |
--------------------------------------------------------------------------------
/lib/utils/transformation/flattenObject.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | /**
3 | * @module lib/utils/transformation/flattenObject
4 | * @author Renaud Lapoële
5 | */
6 |
7 | /**
8 | * @function flattenObject
9 | * @param {Object} obj
10 | * @param {string} keyCase
11 | * @returns {Object} a flattened object.
12 | * @description A function to flatten an object's nested objects/props.
13 | */
14 | function flattenObject(
15 | obj,
16 | keyCase = 'kebab'
17 | ) {
18 | const _keyCase = -1 < ['kebab','camel'].indexOf(keyCase) ? keyCase : 'kebab';
19 | const _obj = !!obj ? obj : {};
20 |
21 | function _flatten(obj, currentKey = '', keyCase = 'kebab') {
22 | return Object.keys(obj).reduce(
23 | (acc, key) => {
24 | let newKey = '';
25 | if ('camel' === keyCase) {
26 | newKey = '' === currentKey ? key : `${currentKey}${key.charAt(0).toUpperCase() + key.slice(1)}`;
27 | }
28 | else {
29 | newKey = '' === currentKey ? key : `${currentKey}-${key}`;
30 | }
31 | if ('object' === typeof obj[key] && !Array.isArray(obj[key]))
32 | acc = { ...acc, ..._flatten(obj[key], newKey, keyCase) };
33 | else
34 | acc[newKey] = obj[key];
35 | return acc;
36 | },
37 | {}
38 | );
39 | }
40 | return _flatten(_obj, '', _keyCase);
41 | }
42 |
43 | /**
44 | * Module exports.
45 | */
46 | module.exports = flattenObject;
47 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "json-to-scss",
3 | "version": "1.6.2",
4 | "main": "lib/jsJsonFilesToSassScssFiles.js",
5 | "license": "MIT",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/rlapoele/json-to-scss.git"
9 | },
10 | "author": {
11 | "name": "Renaud Lapoële",
12 | "email": "rlapoele@gmail.com"
13 | },
14 | "description": "A small utility to convert js & json file(s) to scss/sass file(s).",
15 | "keywords": [
16 | "converter",
17 | "js",
18 | "json",
19 | "sass",
20 | "scss"
21 | ],
22 | "homepage": "https://github.com/rlapoele/json-to-scss#readme",
23 | "issues": "https://github.com/rlapoele/json-to-scss/issues",
24 | "dependencies": {
25 | "chalk": "^2.4.2",
26 | "glob": "^7.1.4",
27 | "lodash.isinteger": "^4.0.4",
28 | "lodash.isplainobject": "^4.0.6",
29 | "node-emoji": "^1.10.0",
30 | "terminal-overwrite": "^2.0.1",
31 | "yargs": "^13.3.2"
32 | },
33 | "bin": {
34 | "json-to-scss": "bin/cli.js"
35 | },
36 | "devDependencies": {}
37 | }
38 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | ansi-regex@^3.0.0:
6 | version "3.0.0"
7 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
8 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
9 |
10 | ansi-regex@^4.1.0:
11 | version "4.1.0"
12 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
13 | integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
14 |
15 | ansi-styles@^3.2.0, ansi-styles@^3.2.1:
16 | version "3.2.1"
17 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
18 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
19 | dependencies:
20 | color-convert "^1.9.0"
21 |
22 | balanced-match@^1.0.0:
23 | version "1.0.0"
24 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
25 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
26 |
27 | brace-expansion@^1.1.7:
28 | version "1.1.11"
29 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
30 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
31 | dependencies:
32 | balanced-match "^1.0.0"
33 | concat-map "0.0.1"
34 |
35 | camelcase@^5.0.0:
36 | version "5.3.1"
37 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
38 | integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
39 |
40 | chalk@^2.4.2:
41 | version "2.4.2"
42 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
43 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
44 | dependencies:
45 | ansi-styles "^3.2.1"
46 | escape-string-regexp "^1.0.5"
47 | supports-color "^5.3.0"
48 |
49 | cli-cursor@^2.0.0:
50 | version "2.1.0"
51 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
52 | integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=
53 | dependencies:
54 | restore-cursor "^2.0.0"
55 |
56 | cliui@^5.0.0:
57 | version "5.0.0"
58 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
59 | integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==
60 | dependencies:
61 | string-width "^3.1.0"
62 | strip-ansi "^5.2.0"
63 | wrap-ansi "^5.1.0"
64 |
65 | color-convert@^1.9.0:
66 | version "1.9.3"
67 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
68 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
69 | dependencies:
70 | color-name "1.1.3"
71 |
72 | color-name@1.1.3:
73 | version "1.1.3"
74 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
75 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
76 |
77 | concat-map@0.0.1:
78 | version "0.0.1"
79 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
80 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
81 |
82 | decamelize@^1.2.0:
83 | version "1.2.0"
84 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
85 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
86 |
87 | emoji-regex@^7.0.1:
88 | version "7.0.3"
89 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
90 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
91 |
92 | escape-string-regexp@^1.0.5:
93 | version "1.0.5"
94 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
95 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
96 |
97 | find-up@^3.0.0:
98 | version "3.0.0"
99 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
100 | integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
101 | dependencies:
102 | locate-path "^3.0.0"
103 |
104 | fs.realpath@^1.0.0:
105 | version "1.0.0"
106 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
107 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
108 |
109 | get-caller-file@^2.0.1:
110 | version "2.0.5"
111 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
112 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
113 |
114 | glob@^7.1.4:
115 | version "7.1.6"
116 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
117 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
118 | dependencies:
119 | fs.realpath "^1.0.0"
120 | inflight "^1.0.4"
121 | inherits "2"
122 | minimatch "^3.0.4"
123 | once "^1.3.0"
124 | path-is-absolute "^1.0.0"
125 |
126 | has-flag@^3.0.0:
127 | version "3.0.0"
128 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
129 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
130 |
131 | inflight@^1.0.4:
132 | version "1.0.6"
133 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
134 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
135 | dependencies:
136 | once "^1.3.0"
137 | wrappy "1"
138 |
139 | inherits@2:
140 | version "2.0.4"
141 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
142 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
143 |
144 | is-fullwidth-code-point@^2.0.0:
145 | version "2.0.0"
146 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
147 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
148 |
149 | locate-path@^3.0.0:
150 | version "3.0.0"
151 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
152 | integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
153 | dependencies:
154 | p-locate "^3.0.0"
155 | path-exists "^3.0.0"
156 |
157 | lodash.isinteger@^4.0.4:
158 | version "4.0.4"
159 | resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
160 | integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=
161 |
162 | lodash.isplainobject@^4.0.6:
163 | version "4.0.6"
164 | resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
165 | integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
166 |
167 | lodash.toarray@^4.4.0:
168 | version "4.4.0"
169 | resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561"
170 | integrity sha1-JMS/zWsvuji/0FlNsRedjptlZWE=
171 |
172 | mimic-fn@^1.0.0:
173 | version "1.2.0"
174 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
175 | integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
176 |
177 | minimatch@^3.0.4:
178 | version "3.0.4"
179 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
180 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
181 | dependencies:
182 | brace-expansion "^1.1.7"
183 |
184 | node-emoji@^1.10.0:
185 | version "1.10.0"
186 | resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da"
187 | integrity sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==
188 | dependencies:
189 | lodash.toarray "^4.4.0"
190 |
191 | once@^1.3.0:
192 | version "1.4.0"
193 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
194 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
195 | dependencies:
196 | wrappy "1"
197 |
198 | onetime@^2.0.0:
199 | version "2.0.1"
200 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
201 | integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=
202 | dependencies:
203 | mimic-fn "^1.0.0"
204 |
205 | p-limit@^2.0.0:
206 | version "2.3.0"
207 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
208 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
209 | dependencies:
210 | p-try "^2.0.0"
211 |
212 | p-locate@^3.0.0:
213 | version "3.0.0"
214 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
215 | integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
216 | dependencies:
217 | p-limit "^2.0.0"
218 |
219 | p-try@^2.0.0:
220 | version "2.2.0"
221 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
222 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
223 |
224 | path-exists@^3.0.0:
225 | version "3.0.0"
226 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
227 | integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
228 |
229 | path-is-absolute@^1.0.0:
230 | version "1.0.1"
231 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
232 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
233 |
234 | require-directory@^2.1.1:
235 | version "2.1.1"
236 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
237 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
238 |
239 | require-main-filename@^2.0.0:
240 | version "2.0.0"
241 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
242 | integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
243 |
244 | restore-cursor@^2.0.0:
245 | version "2.0.0"
246 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
247 | integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368=
248 | dependencies:
249 | onetime "^2.0.0"
250 | signal-exit "^3.0.2"
251 |
252 | set-blocking@^2.0.0:
253 | version "2.0.0"
254 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
255 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
256 |
257 | signal-exit@^3.0.2:
258 | version "3.0.3"
259 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
260 | integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
261 |
262 | string-width@^2.0.0:
263 | version "2.1.1"
264 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
265 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
266 | dependencies:
267 | is-fullwidth-code-point "^2.0.0"
268 | strip-ansi "^4.0.0"
269 |
270 | string-width@^3.0.0, string-width@^3.1.0:
271 | version "3.1.0"
272 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
273 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
274 | dependencies:
275 | emoji-regex "^7.0.1"
276 | is-fullwidth-code-point "^2.0.0"
277 | strip-ansi "^5.1.0"
278 |
279 | strip-ansi@^4.0.0:
280 | version "4.0.0"
281 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
282 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
283 | dependencies:
284 | ansi-regex "^3.0.0"
285 |
286 | strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
287 | version "5.2.0"
288 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
289 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
290 | dependencies:
291 | ansi-regex "^4.1.0"
292 |
293 | supports-color@^5.3.0:
294 | version "5.5.0"
295 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
296 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
297 | dependencies:
298 | has-flag "^3.0.0"
299 |
300 | terminal-overwrite@^2.0.1:
301 | version "2.0.1"
302 | resolved "https://registry.yarnpkg.com/terminal-overwrite/-/terminal-overwrite-2.0.1.tgz#c732aefeba38900667bf088b4f1b12edbee62841"
303 | integrity sha1-xzKu/ro4kAZnvwiLTxsS7b7mKEE=
304 | dependencies:
305 | cli-cursor "^2.0.0"
306 | string-width "^2.0.0"
307 |
308 | which-module@^2.0.0:
309 | version "2.0.0"
310 | resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
311 | integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
312 |
313 | wrap-ansi@^5.1.0:
314 | version "5.1.0"
315 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
316 | integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==
317 | dependencies:
318 | ansi-styles "^3.2.0"
319 | string-width "^3.0.0"
320 | strip-ansi "^5.0.0"
321 |
322 | wrappy@1:
323 | version "1.0.2"
324 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
325 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
326 |
327 | y18n@^4.0.0:
328 | version "4.0.0"
329 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
330 | integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
331 |
332 | yargs-parser@^13.1.2:
333 | version "13.1.2"
334 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"
335 | integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==
336 | dependencies:
337 | camelcase "^5.0.0"
338 | decamelize "^1.2.0"
339 |
340 | yargs@^13.3.2:
341 | version "13.3.2"
342 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd"
343 | integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==
344 | dependencies:
345 | cliui "^5.0.0"
346 | find-up "^3.0.0"
347 | get-caller-file "^2.0.1"
348 | require-directory "^2.1.1"
349 | require-main-filename "^2.0.0"
350 | set-blocking "^2.0.0"
351 | string-width "^3.0.0"
352 | which-module "^2.0.0"
353 | y18n "^4.0.0"
354 | yargs-parser "^13.1.2"
355 |
--------------------------------------------------------------------------------