Skip to content

Commit a03e0cb

Browse files
committed
feat(ui-scripts): use tokens from external repo and convert JS to TS
INSTUI-5002
1 parent 69bba40 commit a03e0cb

148 files changed

Lines changed: 285 additions & 33196 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/ui-scripts/lib/build/build-themes.js renamed to packages/ui-scripts/lib/build/build-themes.ts

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,14 @@
2222
* SOFTWARE.
2323
*/
2424

25-
import path, { dirname } from 'path'
26-
import { fileURLToPath } from 'url'
27-
import { promises } from 'fs'
28-
import pkg from 'glob'
29-
import setupThemes from './buildThemes/setupThemes.js'
30-
31-
const { glob } = pkg
32-
const __filename = fileURLToPath(import.meta.url)
33-
const __dirname = dirname(__filename)
25+
// @ts-ignore -- package ships JS source without type declarations
26+
import { themeTokens } from '@instructure/instructure-design-tokens'
27+
import setupThemes from './buildThemes/setupThemes.ts'
3428

3529
export default {
3630
command: 'build-themes',
3731
desc: 'Generate themes',
3832
handler: async () => {
39-
const tokensStudioDir = path.join(__dirname, 'tokensStudio')
40-
const jsonFiles = glob.sync('**/*.json', { cwd: tokensStudioDir })
41-
42-
const themeTokens = {}
43-
for (const filePath of jsonFiles) {
44-
const fullPath = path.join(tokensStudioDir, filePath)
45-
const rawData = await promises.readFile(fullPath, 'utf8')
46-
const relativePath = filePath.replace('.json', '')
47-
themeTokens[relativePath] = JSON.parse(rawData)
48-
}
49-
5033
await setupThemes(
5134
'packages/ui-themes/src/themes/newThemeTokens',
5235
themeTokens

packages/ui-scripts/lib/build/buildThemes/generateSemantics.js renamed to packages/ui-scripts/lib/build/buildThemes/generateSemantics.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@
2222
* SOFTWARE.
2323
*/
2424

25-
const isReference = (expression) =>
25+
const isReference = (expression: any): boolean =>
2626
expression[0] === '{' && expression[expression.length - 1] === '}'
2727

28-
const formatSemantic = (collection, key) => {
28+
const formatSemantic = (collection: any, key?: any): any => {
2929
const value = key ? collection[key] : collection
3030
if (typeof value === 'object' && !value.value && !value.type) {
3131
return Object.keys(value).reduce((acc, key) => {
@@ -35,7 +35,7 @@ const formatSemantic = (collection, key) => {
3535
return value.value
3636
}
3737

38-
const formatReference = (reference) => {
38+
const formatReference = (reference: string): string => {
3939
const referenceArr = reference.slice(1, -1).split('.')
4040
const lastElement = referenceArr[referenceArr.length - 1]
4141

@@ -47,7 +47,7 @@ const formatReference = (reference) => {
4747
return `primitives.${reference.slice(1, -1)},\n`
4848
}
4949

50-
export const resolveReferences = (semantics, key) => {
50+
export const resolveReferences = (semantics: any, key?: any): string => {
5151
const value = key ? semantics[key] : semantics
5252
if (typeof value === 'object' && !value.value && !value.type) {
5353
return Object.keys(value).reduce((acc, key, index) => {
@@ -74,7 +74,7 @@ export const resolveReferences = (semantics, key) => {
7474
return `"${value}",\n`
7575
}
7676

77-
export const resolveTypeReferences = (semantics, key) => {
77+
export const resolveTypeReferences = (semantics: any, key?: any): string => {
7878
const value = key ? semantics[key] : semantics
7979
if (typeof value === 'object') {
8080
return Object.keys(value).reduce((acc, key, index) => {
@@ -94,7 +94,7 @@ export const resolveTypeReferences = (semantics, key) => {
9494
return `Primitives${value
9595
.slice(1, -1)
9696
.split('.')
97-
.map((val) => `['${val}']`)
97+
.map((val: string) => `['${val}']`)
9898
.join('')}, `
9999
}
100100

@@ -104,16 +104,16 @@ export const resolveTypeReferences = (semantics, key) => {
104104
return `${typeof value}, `
105105
}
106106

107-
export const mergeSemanticSets = (data, semanticList) =>
108-
semanticList.reduce((acc, semantic) => ({ ...acc, ...data[semantic] }), {})
107+
export const mergeSemanticSets = (semanticList: any[]) =>
108+
semanticList.reduce((acc, semantic) => ({ ...acc, ...semantic }), {})
109109

110-
const generateSemantics = (data) => {
110+
const generateSemantics = (data: any): string => {
111111
const formattedSemantic = formatSemantic(data)
112112

113113
return resolveReferences(formattedSemantic)
114114
}
115115

116-
export const generateSemanticsType = (data) => {
116+
export const generateSemanticsType = (data: any): string => {
117117
const formattedSemantic = formatSemantic(data)
118118

119119
return `{${resolveTypeReferences(formattedSemantic)}}`

packages/ui-scripts/lib/build/buildThemes/setupThemes.js renamed to packages/ui-scripts/lib/build/buildThemes/setupThemes.ts

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -28,42 +28,53 @@ import { generatePrimitives, generateType } from './generatePrimitives.js'
2828
import generateSemantics, {
2929
generateSemanticsType,
3030
mergeSemanticSets
31-
} from './generateSemantics.js'
31+
} from './generateSemantics.ts'
3232
import generateComponent, {
3333
generateComponentType
3434
} from './generateComponents.js'
3535
import { exec } from 'child_process'
3636
import { promisify } from 'node:util'
3737

3838
// transform to an object for easier handling
39-
export const transformThemes = (themes) =>
39+
export const transformThemes = (themes: any, input: any) =>
4040
//TODO-rework the Primitive theme is a hackaround for design and only for the duration of the v12 work. This should be removed before the release (.filter(t=>t!=="Primitive"))
4141
themes
42-
.filter((t) => t.name !== 'Primitive')
43-
.reduce((acc, theme) => {
44-
const tokenSets = Object.keys(theme.selectedTokenSets).reduce(
45-
(acc, tokenSet) => {
46-
if (tokenSet.includes('primitives')) {
47-
return { ...acc, primitives: tokenSet }
42+
.filter((t: any) => t.name !== 'Primitive')
43+
.reduce((acc: any, theme: any) => {
44+
const tokenSets = Object.entries(theme.selectedTokenSets).reduce(
45+
(acc, [path, status]) => {
46+
const value = path
47+
.split('/')
48+
.reduce((node, key) => node?.[key], input)
49+
if (path.includes('primitives')) {
50+
return { ...acc, primitives: value }
4851
}
49-
if (tokenSet.includes('semantic')) {
50-
return { ...acc, semantic: [...acc.semantic, tokenSet] }
52+
if (path.includes('semantic')) {
53+
return { ...acc, semantic: [...acc.semantic, value] }
5154
}
52-
if (theme.selectedTokenSets[tokenSet] === 'enabled') {
53-
return { ...acc, components: [...acc.components, tokenSet] }
55+
if (status === 'enabled') {
56+
return {
57+
...acc,
58+
components: [
59+
...acc.components,
60+
{ name: path.split('/').at(-1), data: value }
61+
]
62+
}
5463
}
5564
return acc
5665
},
57-
{ primitives: '', semantic: '', components: [] }
66+
{ primitives: null, semantic: [], components: [] } as any
5867
)
5968

6069
return { ...acc, [theme.name]: tokenSets }
6170
}, {})
6271

63-
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1)
64-
const unCapitalize = (str) => str.charAt(0).toLowerCase() + str.slice(1)
72+
const capitalize = (str: string): string =>
73+
str.charAt(0).toUpperCase() + str.slice(1)
74+
const unCapitalize = (str: string): string =>
75+
str.charAt(0).toLowerCase() + str.slice(1)
6576

66-
const getTypeImports = (componentTypes, theme) => {
77+
const getTypeImports = (componentTypes: any, theme: any): string => {
6778
let imports = ''
6879
if (componentTypes.includes(`Semantics[`)) {
6980
imports =
@@ -86,7 +97,7 @@ const getTypeImports = (componentTypes, theme) => {
8697
return imports
8798
}
8899

89-
const setupThemes = async (targetPath, input) => {
100+
const setupThemes = async (targetPath: string, input: any): Promise<void> => {
90101
//clear old themes
91102
await promises.rm(targetPath, { recursive: true, force: true })
92103
//make new root folder
@@ -95,7 +106,7 @@ const setupThemes = async (targetPath, input) => {
95106
// we need to put sharedTokensTypes to the commonTypes where it makes sense, however it comes from token studio as a component. This variable is seen by both parts of the code
96107
let sharedTokensTypes = ''
97108

98-
const themeData = transformThemes(input['$themes'])
109+
const themeData = transformThemes(input['$themes'], input)
99110
//TODO-rework the Primitive theme is a hackaround for design and only for the duration of the v12 work. This should be removed before the release (.filter(t=>t!=="Primitive"))
100111
const themes = Object.keys(themeData).filter((t) => t !== 'Primitive')
101112
for (let themeIndex = 0; themeIndex < themes.length; themeIndex++) {
@@ -104,7 +115,7 @@ const setupThemes = async (targetPath, input) => {
104115
await promises.mkdir(themePath, { recursive: true })
105116

106117
// primitives
107-
const primitives = generatePrimitives(input[themeData[theme].primitives])
118+
const primitives = generatePrimitives(themeData[theme].primitives)
108119
const primitiveTypes = generateType(primitives)
109120
const primitivesFileContent = `
110121
export type Primitives = ${primitiveTypes}
@@ -115,10 +126,7 @@ const setupThemes = async (targetPath, input) => {
115126
await createFile(`${themePath}/primitives.ts`, primitivesFileContent)
116127

117128
// semantics
118-
const mergedSemanticData = mergeSemanticSets(
119-
input,
120-
themeData[theme].semantic
121-
)
129+
const mergedSemanticData = mergeSemanticSets(themeData[theme].semantic)
122130
const semantics = generateSemantics(mergedSemanticData)
123131
const semanticsTypes = generateSemanticsType(mergedSemanticData)
124132
const semanticsFileContent = `
@@ -133,20 +141,18 @@ const setupThemes = async (targetPath, input) => {
133141

134142
const componentAndSubcomponentNames = []
135143
//components
136-
for (const componentpath of themeData[theme].components) {
137-
const rawComponentName =
138-
componentpath.split('/')[componentpath.split('/').length - 1]
144+
for (const component of themeData[theme].components) {
145+
const rawComponentName = component.name
139146
// e.g. ['tabs', 'tabsPanel', 'tabsTab']
140-
const componentAndSubComponents = Object.keys(input[componentpath])
141-
const componentNameDict = {}
147+
const componentAndSubComponents = Object.keys(component.data)
148+
const componentNameDict: Record<string, boolean> = {}
142149
for (let i = 0; i < componentAndSubComponents.length; i++) {
143150
// e.g. 'tag' or 'menuSeparator'
144151
const fullComponentName = componentAndSubComponents[i]
145152
if (componentNameDict[fullComponentName]) {
146153
throw new Error(
147-
'Component names must be unique. The following name' +
148-
' appears more than once: ',
149-
fullComponentName
154+
'Component names must be unique. The following name appears more than once: ' +
155+
fullComponentName
150156
)
151157
} else {
152158
componentNameDict[fullComponentName] = true
@@ -155,11 +161,11 @@ const setupThemes = async (targetPath, input) => {
155161
componentAndSubcomponentNames.push(fullComponentName)
156162
}
157163
const componentThemeVars = generateComponent(
158-
input[componentpath][fullComponentName]
164+
component.data[fullComponentName]
159165
)
160166

161167
const componentTypes = generateComponentType(
162-
input[componentpath][fullComponentName]
168+
component.data[fullComponentName]
163169
)
164170
const usesSemantic = componentThemeVars.includes('semantics.')
165171

@@ -368,13 +374,12 @@ const setupThemes = async (targetPath, input) => {
368374
const { stdout, stderr } = await execAsync(
369375
"dprint fmt '" + targetPath + "/**/*.*'"
370376
)
371-
// eslint-disable-next-line no-console
372377
console.log('[dprint]', stdout)
373378
if (stderr) {
374379
console.error('[dprint error]:', stderr)
375380
}
376381
} catch (error) {
377-
throw new Error('dprint: ' + error.message)
382+
throw new Error('dprint: ' + (error as any).message)
378383
}
379384
}
380385

0 commit comments

Comments
 (0)