@microsoft/atlas-css 3.43.0 → 3.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +42 -42
  2. package/dist/class-names.json +1 -1
  3. package/dist/index.css +1 -1
  4. package/dist/index.css.map +1 -1
  5. package/package.json +91 -91
  6. package/src/atomics/README.md +56 -56
  7. package/src/atomics/aspect-ratio.scss +13 -13
  8. package/src/atomics/background.scss +11 -11
  9. package/src/atomics/border.scss +113 -113
  10. package/src/atomics/colors.scss +204 -204
  11. package/src/atomics/display.scss +33 -33
  12. package/src/atomics/flex.scss +74 -71
  13. package/src/atomics/gap.scss +60 -60
  14. package/src/atomics/image.scss +15 -15
  15. package/src/atomics/index.scss +18 -18
  16. package/src/atomics/line-clamp.scss +15 -15
  17. package/src/atomics/list.scss +3 -3
  18. package/src/atomics/overflow.scss +9 -9
  19. package/src/atomics/position.scss +19 -19
  20. package/src/atomics/shadow.scss +19 -19
  21. package/src/atomics/spacing-auto.scss +52 -52
  22. package/src/atomics/spacing.scss +98 -98
  23. package/src/atomics/typography.scss +203 -203
  24. package/src/atomics/visually-hidden.scss +4 -4
  25. package/src/atomics/width.scss +44 -44
  26. package/src/components/README.md +69 -69
  27. package/src/components/banner.scss +69 -69
  28. package/src/components/breadcrumbs.scss +37 -37
  29. package/src/components/button-reset.scss +8 -8
  30. package/src/components/button.scss +241 -241
  31. package/src/components/buttons.scss +93 -93
  32. package/src/components/card.scss +252 -252
  33. package/src/components/form/checkbox.scss +141 -141
  34. package/src/components/form/form.scss +67 -67
  35. package/src/components/form/help.scss +18 -18
  36. package/src/components/form/index.scss +8 -8
  37. package/src/components/form/input.scss +143 -143
  38. package/src/components/form/label.scss +14 -14
  39. package/src/components/form/radio.scss +121 -121
  40. package/src/components/form/select.scss +116 -116
  41. package/src/components/form/textarea.scss +82 -82
  42. package/src/components/gradient-card.scss +14 -14
  43. package/src/components/gradient.scss +85 -85
  44. package/src/components/hero.scss +197 -197
  45. package/src/components/icon.scss +20 -20
  46. package/src/components/image.scss +44 -44
  47. package/src/components/index.scss +27 -27
  48. package/src/components/layout.scss +189 -189
  49. package/src/components/link-button.scss +34 -34
  50. package/src/components/markdown.scss +158 -158
  51. package/src/components/media.scss +22 -22
  52. package/src/components/message.scss +74 -74
  53. package/src/components/notification.scss +101 -101
  54. package/src/components/pagination.scss +183 -183
  55. package/src/components/persona.scss +60 -60
  56. package/src/components/popover.scss +42 -42
  57. package/src/components/scroll.scss +26 -26
  58. package/src/components/segmented-control.scss +128 -128
  59. package/src/components/site-header.scss +255 -255
  60. package/src/components/stretched-link.scss +8 -8
  61. package/src/components/table.scss +114 -114
  62. package/src/components/toggle.scss +86 -86
  63. package/src/core/animations.scss +55 -55
  64. package/src/core/bare-elements.scss +38 -38
  65. package/src/core/focus.scss +45 -45
  66. package/src/core/font-stack.scss +28 -28
  67. package/src/core/index.scss +7 -7
  68. package/src/core/minireset.scss +79 -79
  69. package/src/core/normalize.scss +353 -353
  70. package/src/core/themes.scss +91 -91
  71. package/src/index.scss +5 -5
  72. package/src/mixins/center.scss +11 -11
  73. package/src/mixins/code-block.scss +43 -43
  74. package/src/mixins/colors.scss +6 -6
  75. package/src/mixins/control.scss +43 -43
  76. package/src/mixins/dismiss.scss +22 -22
  77. package/src/mixins/focus.scss +23 -23
  78. package/src/mixins/font-size.scss +35 -35
  79. package/src/mixins/force-colors.scss +5 -5
  80. package/src/mixins/gradient.scss +11 -11
  81. package/src/mixins/index.scss +17 -17
  82. package/src/mixins/layout-gap.scss +7 -7
  83. package/src/mixins/line-clamp.scss +15 -15
  84. package/src/mixins/loader.scss +16 -16
  85. package/src/mixins/media-queries.scss +61 -61
  86. package/src/mixins/overlay.scss +12 -12
  87. package/src/mixins/transparency.scss +15 -15
  88. package/src/mixins/unselectable.scss +13 -13
  89. package/src/mixins/visually-hidden.scss +12 -12
  90. package/src/tokens/animation.scss +8 -8
  91. package/src/tokens/border.scss +12 -12
  92. package/src/tokens/breakpoints.scss +11 -11
  93. package/src/tokens/colors.scss +239 -239
  94. package/src/tokens/direction.scss +25 -25
  95. package/src/tokens/display.scss +5 -5
  96. package/src/tokens/focus.scss +9 -9
  97. package/src/tokens/font-stack.scss +10 -10
  98. package/src/tokens/index.scss +17 -17
  99. package/src/tokens/layout.scss +17 -17
  100. package/src/tokens/palette.scss +200 -200
  101. package/src/tokens/position.scss +5 -5
  102. package/src/tokens/schemes.scss +14 -14
  103. package/src/tokens/shadow.scss +11 -11
  104. package/src/tokens/spacing.scss +25 -25
  105. package/src/tokens/themes.scss +318 -318
  106. package/src/tokens/typography.scss +33 -33
  107. package/src/tokens/z-index.scss +20 -20
  108. package/tokens/README.md +34 -34
  109. package/tokens/index.js +246 -246
  110. package/tokens/types.d.ts +35 -35
@@ -1,33 +1,33 @@
1
- /**
2
- * @sass-export-section="typography"
3
- */
4
-
5
- $document-font-size: 16px;
6
-
7
- // Typography
8
- $font-size-9: 0.75rem !default; // 12px
9
- $font-size-8: 0.875rem !default; // 14px
10
- $font-size-7: 1rem !default; // 16px
11
- $font-size-6: 1.125rem !default; // 18px
12
- $font-size-5: 1.25rem !default; // 20px
13
- $font-size-4: 1.5rem !default; // 24px
14
- $font-size-3: 1.75rem !default; // 28px
15
- $font-size-2: 2.125rem !default; // 34px
16
- $font-size-1: 2.5rem !default; // 40px
17
- $font-size-0: 3.375rem !default; // 54px
18
-
19
- // Font Weight
20
- $weight-light: 100;
21
- $weight-semilight: 200;
22
- $weight-normal: 400;
23
- $weight-semibold: 600;
24
- $weight-bold: 700;
25
-
26
- // Letter spacing
27
- $letter-spacing-medium: 0.125rem;
28
- $letter-spacing-wide: 0.225rem;
29
-
30
- // Line height
31
- $line-height-normal: 1.3;
32
-
33
- //@end-sass-export-section
1
+ /**
2
+ * @sass-export-section="typography"
3
+ */
4
+
5
+ $document-font-size: 16px;
6
+
7
+ // Typography
8
+ $font-size-9: 0.75rem !default; // 12px
9
+ $font-size-8: 0.875rem !default; // 14px
10
+ $font-size-7: 1rem !default; // 16px
11
+ $font-size-6: 1.125rem !default; // 18px
12
+ $font-size-5: 1.25rem !default; // 20px
13
+ $font-size-4: 1.5rem !default; // 24px
14
+ $font-size-3: 1.75rem !default; // 28px
15
+ $font-size-2: 2.125rem !default; // 34px
16
+ $font-size-1: 2.5rem !default; // 40px
17
+ $font-size-0: 3.375rem !default; // 54px
18
+
19
+ // Font Weight
20
+ $weight-light: 100;
21
+ $weight-semilight: 200;
22
+ $weight-normal: 400;
23
+ $weight-semibold: 600;
24
+ $weight-bold: 700;
25
+
26
+ // Letter spacing
27
+ $letter-spacing-medium: 0.125rem;
28
+ $letter-spacing-wide: 0.225rem;
29
+
30
+ // Line height
31
+ $line-height-normal: 1.3;
32
+
33
+ //@end-sass-export-section
@@ -1,20 +1,20 @@
1
- /**
2
- * @sass-export-section="z-index"
3
- */
4
- // Element states
5
- $zindex-active: 1;
6
- $zindex-hover: 2;
7
- $zindex-focus: 3;
8
- $zindex-multi: 4;
9
-
10
- // Components
11
- $zindex-dropdown: 1000;
12
- $zindex-sticky: 1020;
13
- $zindex-fixed: 1030;
14
- $zindex-modal-backdrop: 1040;
15
- $zindex-modal: 1050;
16
- $zindex-popover: 1060;
17
- $zindex-tooltip: 1070;
18
-
19
- $zindex-stretched-link: 1 !default;
20
- //@end-sass-export-section
1
+ /**
2
+ * @sass-export-section="z-index"
3
+ */
4
+ // Element states
5
+ $zindex-active: 1;
6
+ $zindex-hover: 2;
7
+ $zindex-focus: 3;
8
+ $zindex-multi: 4;
9
+
10
+ // Components
11
+ $zindex-dropdown: 1000;
12
+ $zindex-sticky: 1020;
13
+ $zindex-fixed: 1030;
14
+ $zindex-modal-backdrop: 1040;
15
+ $zindex-modal: 1050;
16
+ $zindex-popover: 1060;
17
+ $zindex-tooltip: 1070;
18
+
19
+ $zindex-stretched-link: 1 !default;
20
+ //@end-sass-export-section
package/tokens/README.md CHANGED
@@ -1,34 +1,34 @@
1
- # Atlas CSS Tokens
2
-
3
- A design tokens is a definition of a design-related variable, such as one that affects color, typography, or spacing. Design tokens must be shareable and fairly platform agnostic. Atlas's design tokens are written in Scss (buzzword: source of truth!), and though a [build process](https://github.com/microsoft/atlas-design/blob/main/css/tokens/index.js), translated and published into JSON so they can be more easily shared by solutions that do not use Scss.
4
-
5
- ## Access our design tokens
6
-
7
- Firstly, in order to access these tokens, you must have installed atlas-css in your project. [See installation steps](https://github.com/microsoft/atlas-design). Once this is complete, you'll need to decide whether you want to reference them in Scss or JSON.
8
-
9
- ### Get Scss from NPM
10
-
11
- Reference our tokens in Scss via the following examples, where `./` is the path to your `node_modules` folder.
12
-
13
- ```scss
14
- // Import by referencing node_modules
15
- @import './node_modules/@microsoft/atlas-css/src/tokens/index.scss';
16
- // OR if using a bundler like Parcel you may just reference the package directly
17
- @import '@microsoft/atlas-css/src/tokens/index.scss';
18
- ```
19
-
20
- ### Get JSON from NPM
21
-
22
- In NodeJs, referencing `node_modules` will also allow you to access the token [JSON](http://unpkg.com/browse/@microsoft/atlas-css/dist/tokens.json), which lives at `/dist/tokens.json`.
23
-
24
- You can also access the [TypeScript typings](https://unpkg.com/browse/@microsoft/atlas-css/dist/tokens.d.ts) in the same directory. Note the JSDoc comment in the example below.
25
-
26
- ```js
27
- /**
28
- * Atlas Design Token Types
29
- * @type {import('@microsoft/atlas-css/dist/tokens').AtlasTokens}
30
- */
31
- const atlas = require('@microsoft/atlas-css/dist/tokens.json');
32
- // Access the tokens!
33
- const lightTheme = atlas.themes.tokens.$themes.light;
34
- ```
1
+ # Atlas CSS Tokens
2
+
3
+ A design tokens is a definition of a design-related variable, such as one that affects color, typography, or spacing. Design tokens must be shareable and fairly platform agnostic. Atlas's design tokens are written in Scss (buzzword: source of truth!), and though a [build process](https://github.com/microsoft/atlas-design/blob/main/css/tokens/index.js), translated and published into JSON so they can be more easily shared by solutions that do not use Scss.
4
+
5
+ ## Access our design tokens
6
+
7
+ Firstly, in order to access these tokens, you must have installed atlas-css in your project. [See installation steps](https://github.com/microsoft/atlas-design). Once this is complete, you'll need to decide whether you want to reference them in Scss or JSON.
8
+
9
+ ### Get Scss from NPM
10
+
11
+ Reference our tokens in Scss via the following examples, where `./` is the path to your `node_modules` folder.
12
+
13
+ ```scss
14
+ // Import by referencing node_modules
15
+ @import './node_modules/@microsoft/atlas-css/src/tokens/index.scss';
16
+ // OR if using a bundler like Parcel you may just reference the package directly
17
+ @import '@microsoft/atlas-css/src/tokens/index.scss';
18
+ ```
19
+
20
+ ### Get JSON from NPM
21
+
22
+ In NodeJs, referencing `node_modules` will also allow you to access the token [JSON](http://unpkg.com/browse/@microsoft/atlas-css/dist/tokens.json), which lives at `/dist/tokens.json`.
23
+
24
+ You can also access the [TypeScript typings](https://unpkg.com/browse/@microsoft/atlas-css/dist/tokens.d.ts) in the same directory. Note the JSDoc comment in the example below.
25
+
26
+ ```js
27
+ /**
28
+ * Atlas Design Token Types
29
+ * @type {import('@microsoft/atlas-css/dist/tokens').AtlasTokens}
30
+ */
31
+ const atlas = require('@microsoft/atlas-css/dist/tokens.json');
32
+ // Access the tokens!
33
+ const lightTheme = atlas.themes.tokens.$themes.light;
34
+ ```
package/tokens/index.js CHANGED
@@ -1,246 +1,246 @@
1
- const fs = require('fs-extra');
2
- const path = require('path');
3
- const { quicktype, InputData, jsonInputForTargetLanguage } = require('quicktype-core');
4
- const { exporter } = require('sass-export');
5
-
6
- createTokens();
7
-
8
- async function createTokens() {
9
- const filePathStem = path.join(process.cwd(), './src/tokens');
10
- const indexPath = path.resolve(filePathStem, 'index.scss');
11
-
12
- const filePaths = await getInputFilesFromIndex(filePathStem, indexPath);
13
- checkFileComments(filePaths);
14
-
15
- /** @type {import('./types').SassExportOptions} */
16
- const options = {
17
- inputFiles: filePaths
18
- };
19
-
20
- const exportedTokens = exporter(options).getStructured();
21
- const collection = getSortedOrder(collectTokens(exportedTokens));
22
-
23
- const outfolder = './dist';
24
- const outfileStem = path.join(outfolder, 'tokens');
25
-
26
- try {
27
- await fs.ensureDir(outfolder);
28
- await Promise.all([
29
- fs.writeJSON(`${outfileStem}.json`, collection),
30
- quicktypeJSON('AtlasTokens', JSON.stringify(collection), `${outfileStem}.ts`, 'typescript')
31
- ]);
32
- console.log(`Tokens written to "${path.join(process.cwd(), `/dist/${outfileStem}.json`)}".`);
33
- } catch (err) {
34
- throw new Error(`Problem writing output: ${err}`);
35
- }
36
- }
37
-
38
- /**
39
- * Read the token index file's content and generate a list of import paths in its respective order
40
- * @param {string} filePathStem tokens directory path
41
- * @param {string} indexPath tokens index file path
42
- * @returns {Promise<string[]>}
43
- */
44
- async function getInputFilesFromIndex(filePathStem, indexPath) {
45
- /** @type {string[]} */
46
- const filePaths = [];
47
- try {
48
- const indexFile = (await fs.readFile(indexPath)).toString();
49
- const lines = indexFile.split('\n').reduce((arr, line) => {
50
- if (line.includes('@import')) {
51
- const filePath = line.replace('@import', '').replaceAll(`'`, '').replace(';', '').trim();
52
- arr.push(path.join(filePathStem, filePath));
53
- }
54
- return arr;
55
- }, filePaths);
56
- return lines;
57
- } catch (err) {
58
- throw err;
59
- }
60
- }
61
-
62
- /**
63
- * Print a warning if a token file lacks the required sass-export-section comments.
64
- * @param {string[]} paths token file paths
65
- */
66
- function checkFileComments(paths) {
67
- const promises = paths.map(async path => {
68
- try {
69
- const result = await fs.readFile(path, 'utf8');
70
- if (!result.includes('@sass-export-section')) {
71
- console.log(`Warning: ${path} is missing @sass-export-section annotations.`);
72
- }
73
- } catch (err) {
74
- throw new Error(`Problem reading token files: ${err}`);
75
- }
76
- });
77
-
78
- return Promise.all(promises);
79
- }
80
-
81
- /**
82
- * Sort the grouped tokens alphabetically
83
- * @param {import('./types').SassExportCollection} collection collection of grouped tokens to be sorted
84
- * @returns {import('./types').SassExportCollection}
85
- */
86
- function getSortedOrder(collection) {
87
- return Object.fromEntries(Object.entries(collection).sort());
88
- }
89
-
90
- /**
91
- * Condense the raw data from sass-export into simple objects
92
- * @param {import('./types').SassExportTokens} tokens raw token data by group
93
- * @returns {import('./types').SassExportCollection}
94
- */
95
- function collectTokens(tokens) {
96
- /** @type {import('./types').SassExportCollection} */
97
- const collection = {};
98
- for (const [parent, tokenValues] of Object.entries(tokens)) {
99
- //Currently using sass-export-section annotations in the token files for grouping.
100
- //Tokens without annotations will be combined in the variables array.
101
- if (parent === 'variables') {
102
- continue;
103
- }
104
-
105
- const collectedValues = tokenValues.reduce(
106
- (
107
- /** @type {import('./types').SassExportCollection} */ all,
108
- /** @type {import('./types').SassExportTokenItem} */ current
109
- ) => {
110
- const tokenName = current.name;
111
-
112
- /** @type {string | import('./types').SassExportTokenNestedItem} */
113
- const values = current.mapValue
114
- ? { ...getNestedTokens(current) }[tokenName]
115
- : convertBoolean(current.compiledValue.replaceAll(' , ', ', '));
116
- all[parent] = {
117
- ...all[parent],
118
- [tokenName]: values
119
- };
120
- return all;
121
- },
122
- {}
123
- );
124
- collection[parent] = {
125
- name: parent,
126
- location: `/css/src/tokens/${parent}.scss`,
127
- tokens: collectedValues[parent]
128
- };
129
- }
130
-
131
- return collection;
132
- }
133
-
134
- /**
135
- * Aggregate nested values when token value is a Sass map
136
- * Note, this currently only targets two levels of nesting.
137
- * Sass-export seems to have trouble parsing maps that have more two levels.
138
- * @param {import('./types').SassExportTokenItem} tokenItem
139
- * @returns {import('./types').SassExportNestedCollection}
140
- */
141
- function getNestedTokens(tokenItem) {
142
- const { name, compiledValue, mapValue } = tokenItem;
143
-
144
- /** @type {import('./types').SassExportNestedCollection} */
145
- const newCompiledValue = {};
146
-
147
- const nested = containsMapValue(tokenItem);
148
-
149
- if (!nested) {
150
- parseCompiledValue(compiledValue, name, newCompiledValue);
151
- }
152
-
153
- if (mapValue && nested) {
154
- for (const child of mapValue) {
155
- parseCompiledValue(child.compiledValue, child.name, newCompiledValue);
156
- }
157
- }
158
- return { [name]: nested ? newCompiledValue : newCompiledValue[name] };
159
- }
160
-
161
- /**
162
- * Return a boolean if the token item has nested maps
163
- * Note, this currently only targets two levels of nesting.
164
- * @param {import('./types').SassExportTokenItem} tokenItem
165
- * @returns {boolean}
166
- */
167
- function containsMapValue(tokenItem) {
168
- if (tokenItem.mapValue) {
169
- for (const values of tokenItem.mapValue) {
170
- if (values.hasOwnProperty('mapValue')) {
171
- return true;
172
- }
173
- }
174
- }
175
- return false;
176
- }
177
-
178
- /**
179
- * Return an object of tokens by parsing the token item's compiled value string
180
- * @param {string} compiledValue
181
- * @param {string} name
182
- * @param {{[name: string]: import('./types').SassExportTokenNestedItem}} collection
183
- * @returns {import('./types').SassExportNestedCollection}
184
- */
185
- function parseCompiledValue(compiledValue, name, collection) {
186
- const parsedValue = compiledValue
187
- .replace(/^\(/, '')
188
- .replace(/\((?![^-]*: )/, '')
189
- .replace(/\)$/, '')
190
- .replaceAll(/\){2,}/g, ')')
191
- .split(/\,(?![^"]*\))/);
192
-
193
- return parsedValue.reduce((subCollection, val) => {
194
- const [subKey, value] = val.replaceAll(' ', '').replaceAll('"', '').split(':');
195
-
196
- subCollection[name] = {
197
- ...subCollection[name],
198
- [subKey]: convertBoolean(value.replace(/^\(/, ''))
199
- };
200
-
201
- return subCollection;
202
- }, collection);
203
- }
204
-
205
- /**
206
- * Convert boolean string to a boolean value
207
- * @param {string} str
208
- * @returns {boolean | string}
209
- */
210
- function convertBoolean(str) {
211
- if (str === 'true') {
212
- return true;
213
- }
214
- if (str === 'false') {
215
- return false;
216
- }
217
- return str;
218
- }
219
-
220
- /**
221
- *
222
- * @param {string} typeName The name of the global type
223
- * @param {string} jsonString The JSON to parse
224
- * @param {string} outfile Where to save the file
225
- * @param {string} targetLanguage To which language to convert the types
226
- * @returns promise
227
- */
228
- async function quicktypeJSON(typeName, jsonString, outfile, targetLanguage = 'typescript') {
229
- const jsonInput = jsonInputForTargetLanguage(targetLanguage);
230
-
231
- // We could add multiple samples for the same desired
232
- // type, or many sources for other types. Here we're
233
- // just making one type from one piece of sample JSON.
234
- await jsonInput.addSource({
235
- name: typeName,
236
- samples: [jsonString]
237
- });
238
-
239
- const inputData = new InputData();
240
- inputData.addInput(jsonInput);
241
- const result = await quicktype({
242
- inputData,
243
- lang: targetLanguage
244
- });
245
- return fs.writeFile(outfile, result.lines.join('\n'));
246
- }
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const { quicktype, InputData, jsonInputForTargetLanguage } = require('quicktype-core');
4
+ const { exporter } = require('sass-export');
5
+
6
+ createTokens();
7
+
8
+ async function createTokens() {
9
+ const filePathStem = path.join(process.cwd(), './src/tokens');
10
+ const indexPath = path.resolve(filePathStem, 'index.scss');
11
+
12
+ const filePaths = await getInputFilesFromIndex(filePathStem, indexPath);
13
+ checkFileComments(filePaths);
14
+
15
+ /** @type {import('./types').SassExportOptions} */
16
+ const options = {
17
+ inputFiles: filePaths
18
+ };
19
+
20
+ const exportedTokens = exporter(options).getStructured();
21
+ const collection = getSortedOrder(collectTokens(exportedTokens));
22
+
23
+ const outfolder = './dist';
24
+ const outfileStem = path.join(outfolder, 'tokens');
25
+
26
+ try {
27
+ await fs.ensureDir(outfolder);
28
+ await Promise.all([
29
+ fs.writeJSON(`${outfileStem}.json`, collection),
30
+ quicktypeJSON('AtlasTokens', JSON.stringify(collection), `${outfileStem}.ts`, 'typescript')
31
+ ]);
32
+ console.log(`Tokens written to "${path.join(process.cwd(), `/dist/${outfileStem}.json`)}".`);
33
+ } catch (err) {
34
+ throw new Error(`Problem writing output: ${err}`);
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Read the token index file's content and generate a list of import paths in its respective order
40
+ * @param {string} filePathStem tokens directory path
41
+ * @param {string} indexPath tokens index file path
42
+ * @returns {Promise<string[]>}
43
+ */
44
+ async function getInputFilesFromIndex(filePathStem, indexPath) {
45
+ /** @type {string[]} */
46
+ const filePaths = [];
47
+ try {
48
+ const indexFile = (await fs.readFile(indexPath)).toString();
49
+ const lines = indexFile.split('\n').reduce((arr, line) => {
50
+ if (line.includes('@import')) {
51
+ const filePath = line.replace('@import', '').replaceAll(`'`, '').replace(';', '').trim();
52
+ arr.push(path.join(filePathStem, filePath));
53
+ }
54
+ return arr;
55
+ }, filePaths);
56
+ return lines;
57
+ } catch (err) {
58
+ throw err;
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Print a warning if a token file lacks the required sass-export-section comments.
64
+ * @param {string[]} paths token file paths
65
+ */
66
+ function checkFileComments(paths) {
67
+ const promises = paths.map(async path => {
68
+ try {
69
+ const result = await fs.readFile(path, 'utf8');
70
+ if (!result.includes('@sass-export-section')) {
71
+ console.log(`Warning: ${path} is missing @sass-export-section annotations.`);
72
+ }
73
+ } catch (err) {
74
+ throw new Error(`Problem reading token files: ${err}`);
75
+ }
76
+ });
77
+
78
+ return Promise.all(promises);
79
+ }
80
+
81
+ /**
82
+ * Sort the grouped tokens alphabetically
83
+ * @param {import('./types').SassExportCollection} collection collection of grouped tokens to be sorted
84
+ * @returns {import('./types').SassExportCollection}
85
+ */
86
+ function getSortedOrder(collection) {
87
+ return Object.fromEntries(Object.entries(collection).sort());
88
+ }
89
+
90
+ /**
91
+ * Condense the raw data from sass-export into simple objects
92
+ * @param {import('./types').SassExportTokens} tokens raw token data by group
93
+ * @returns {import('./types').SassExportCollection}
94
+ */
95
+ function collectTokens(tokens) {
96
+ /** @type {import('./types').SassExportCollection} */
97
+ const collection = {};
98
+ for (const [parent, tokenValues] of Object.entries(tokens)) {
99
+ //Currently using sass-export-section annotations in the token files for grouping.
100
+ //Tokens without annotations will be combined in the variables array.
101
+ if (parent === 'variables') {
102
+ continue;
103
+ }
104
+
105
+ const collectedValues = tokenValues.reduce(
106
+ (
107
+ /** @type {import('./types').SassExportCollection} */ all,
108
+ /** @type {import('./types').SassExportTokenItem} */ current
109
+ ) => {
110
+ const tokenName = current.name;
111
+
112
+ /** @type {string | import('./types').SassExportTokenNestedItem} */
113
+ const values = current.mapValue
114
+ ? { ...getNestedTokens(current) }[tokenName]
115
+ : convertBoolean(current.compiledValue.replaceAll(' , ', ', '));
116
+ all[parent] = {
117
+ ...all[parent],
118
+ [tokenName]: values
119
+ };
120
+ return all;
121
+ },
122
+ {}
123
+ );
124
+ collection[parent] = {
125
+ name: parent,
126
+ location: `/css/src/tokens/${parent}.scss`,
127
+ tokens: collectedValues[parent]
128
+ };
129
+ }
130
+
131
+ return collection;
132
+ }
133
+
134
+ /**
135
+ * Aggregate nested values when token value is a Sass map
136
+ * Note, this currently only targets two levels of nesting.
137
+ * Sass-export seems to have trouble parsing maps that have more two levels.
138
+ * @param {import('./types').SassExportTokenItem} tokenItem
139
+ * @returns {import('./types').SassExportNestedCollection}
140
+ */
141
+ function getNestedTokens(tokenItem) {
142
+ const { name, compiledValue, mapValue } = tokenItem;
143
+
144
+ /** @type {import('./types').SassExportNestedCollection} */
145
+ const newCompiledValue = {};
146
+
147
+ const nested = containsMapValue(tokenItem);
148
+
149
+ if (!nested) {
150
+ parseCompiledValue(compiledValue, name, newCompiledValue);
151
+ }
152
+
153
+ if (mapValue && nested) {
154
+ for (const child of mapValue) {
155
+ parseCompiledValue(child.compiledValue, child.name, newCompiledValue);
156
+ }
157
+ }
158
+ return { [name]: nested ? newCompiledValue : newCompiledValue[name] };
159
+ }
160
+
161
+ /**
162
+ * Return a boolean if the token item has nested maps
163
+ * Note, this currently only targets two levels of nesting.
164
+ * @param {import('./types').SassExportTokenItem} tokenItem
165
+ * @returns {boolean}
166
+ */
167
+ function containsMapValue(tokenItem) {
168
+ if (tokenItem.mapValue) {
169
+ for (const values of tokenItem.mapValue) {
170
+ if (values.hasOwnProperty('mapValue')) {
171
+ return true;
172
+ }
173
+ }
174
+ }
175
+ return false;
176
+ }
177
+
178
+ /**
179
+ * Return an object of tokens by parsing the token item's compiled value string
180
+ * @param {string} compiledValue
181
+ * @param {string} name
182
+ * @param {{[name: string]: import('./types').SassExportTokenNestedItem}} collection
183
+ * @returns {import('./types').SassExportNestedCollection}
184
+ */
185
+ function parseCompiledValue(compiledValue, name, collection) {
186
+ const parsedValue = compiledValue
187
+ .replace(/^\(/, '')
188
+ .replace(/\((?![^-]*: )/, '')
189
+ .replace(/\)$/, '')
190
+ .replaceAll(/\){2,}/g, ')')
191
+ .split(/\,(?![^"]*\))/);
192
+
193
+ return parsedValue.reduce((subCollection, val) => {
194
+ const [subKey, value] = val.replaceAll(' ', '').replaceAll('"', '').split(':');
195
+
196
+ subCollection[name] = {
197
+ ...subCollection[name],
198
+ [subKey]: convertBoolean(value.replace(/^\(/, ''))
199
+ };
200
+
201
+ return subCollection;
202
+ }, collection);
203
+ }
204
+
205
+ /**
206
+ * Convert boolean string to a boolean value
207
+ * @param {string} str
208
+ * @returns {boolean | string}
209
+ */
210
+ function convertBoolean(str) {
211
+ if (str === 'true') {
212
+ return true;
213
+ }
214
+ if (str === 'false') {
215
+ return false;
216
+ }
217
+ return str;
218
+ }
219
+
220
+ /**
221
+ *
222
+ * @param {string} typeName The name of the global type
223
+ * @param {string} jsonString The JSON to parse
224
+ * @param {string} outfile Where to save the file
225
+ * @param {string} targetLanguage To which language to convert the types
226
+ * @returns promise
227
+ */
228
+ async function quicktypeJSON(typeName, jsonString, outfile, targetLanguage = 'typescript') {
229
+ const jsonInput = jsonInputForTargetLanguage(targetLanguage);
230
+
231
+ // We could add multiple samples for the same desired
232
+ // type, or many sources for other types. Here we're
233
+ // just making one type from one piece of sample JSON.
234
+ await jsonInput.addSource({
235
+ name: typeName,
236
+ samples: [jsonString]
237
+ });
238
+
239
+ const inputData = new InputData();
240
+ inputData.addInput(jsonInput);
241
+ const result = await quicktype({
242
+ inputData,
243
+ lang: targetLanguage
244
+ });
245
+ return fs.writeFile(outfile, result.lines.join('\n'));
246
+ }