From 874d5fcbb69972287a32ca7cf1dd8c4ab7d1426b Mon Sep 17 00:00:00 2001 From: jorenbroekema Date: Fri, 12 Apr 2024 10:22:36 +0200 Subject: [PATCH] feat: allow nested token folders for --- src/style-dictionary.js | 38 ++++++++++++-- src/utils/file-tree.js | 113 ++++------------------------------------ 2 files changed, 45 insertions(+), 106 deletions(-) diff --git a/src/style-dictionary.js b/src/style-dictionary.js index 1227eef..4e1c828 100644 --- a/src/style-dictionary.js +++ b/src/style-dictionary.js @@ -1,20 +1,21 @@ import { fs } from "style-dictionary/fs"; import StyleDictionary from "style-dictionary"; +import { permutateThemes } from "@tokens-studio/sd-transforms"; +import { posix } from "path-unified"; import { repopulateFileTree, getFileTreeEl, currentFileOutput, } from "./utils/file-tree.js"; -import { permutateThemes } from "@tokens-studio/sd-transforms"; import { bundle } from "./utils/rollup-bundle.js"; import { findUsedConfigPath } from "./utils/findUsedConfigPath.js"; import { THEME_STRING, SD_FUNCTIONS_PATH, SD_CHANGED_EVENT, + SD_CONFIG_PATH, } from "./constants.js"; import { snackbar } from "./components/snackbar/SnackbarManager.js"; -import { html } from "lit"; const { promises } = fs; @@ -41,6 +42,7 @@ class SdState extends EventTarget { this._sd = []; this._themes = {}; this.themedConfigs = []; + this.rootDir = "/"; this.hasInitializedConfig = new Promise((resolve) => { this.hasInitializedConfigResolve = resolve; }); @@ -83,6 +85,30 @@ class SdState extends EventTarget { } } + async determineRootFolder() { + let rootDir = "/"; + // the $themes.json and tokens could be in any nested + // folder structure. this code recursively goes through them + // until it finds more than just 1 nested folder + const getDirContents = async () => { + const contents = (await promises.readdir(rootDir)).filter( + (f) => ![SD_FUNCTIONS_PATH, SD_CONFIG_PATH].includes(f) + ); + if ( + contents.length === 1 && + (await promises.lstat(posix.join(rootDir, contents[0]))).isDirectory() + ) { + return contents[0]; + } + }; + + let dir; + while ((dir = await getDirContents(rootDir))) { + rootDir = posix.join(rootDir, dir); + } + this.rootDir = rootDir; + } + async processConfigForThemes(cfg) { const addThemeToFilePath = (file) => { const fileParts = file.split("."); @@ -94,7 +120,9 @@ class SdState extends EventTarget { }; try { - const $themes = JSON.parse(await promises.readFile("$themes.json")); + const $themes = JSON.parse( + await promises.readFile(posix.join(this.rootDir, "$themes.json")) + ); if ($themes.length > 0) { // 1) adjust config source and platform files names to themed @@ -246,7 +274,9 @@ class SdState extends EventTarget { injectThemeVariables(cfg, theme, tokensets) { const reg = new RegExp(THEME_STRING, "g"); const newCfg = JSON.parse(JSON.stringify(cfg).replace(reg, theme)); - newCfg.source = tokensets.map((set) => `${set}.json`); + newCfg.source = tokensets.map((set) => + posix.join(this.rootDir, `${set}.json`) + ); return newCfg; } diff --git a/src/utils/file-tree.js b/src/utils/file-tree.js index c060c51..9c10487 100644 --- a/src/utils/file-tree.js +++ b/src/utils/file-tree.js @@ -68,8 +68,7 @@ async function createFilesFromURL(project) { snackbar.show( "Flate could not be loaded to decode the URL to project files.\nCreating default tokens studio template instead." ); - createConfig(); - createStudioTokens(); + await Promise.all([createConfig(), createStudioTokens()]); return; } @@ -85,6 +84,7 @@ async function createFilesFromURL(project) { return fs.promises.writeFile(file, content); }) ); + await sdState.determineRootFolder(); } export async function createStudioTokens() { @@ -92,104 +92,11 @@ export async function createStudioTokens() { await fetch(new URL("./core.json", import.meta.url).href) ).json(); - fs.writeFileSync("studio.json", JSON.stringify(tokens, null, 2)); + fs.promises.writeFile("studio.json", JSON.stringify(tokens, null, 2)); } -export function createStandardTokens() { - fs.mkdirSync(`color`); - fs.mkdirSync(`card`); - fs.mkdirSync(`radii`); - fs.writeFileSync( - path.join(`color`, "base.json"), - JSON.stringify( - { - color: { - base: { - gray: { - light: { value: "#CCCCCC" }, - medium: { value: "#999999" }, - dark: { value: "#111111" }, - }, - red: { value: "#FF0000" }, - green: { value: "#00FF00" }, - }, - }, - }, - null, - 2 - ) - ); - - fs.writeFileSync( - path.join(`color`, "font.json"), - JSON.stringify( - { - color: { - font: { - base: { value: "{color.base.red}" }, - secondary: { value: "{color.base.green}" }, - tertiary: { value: "{color.base.gray.dark}" }, - }, - }, - }, - null, - 2 - ) - ); - - fs.writeFileSync( - path.join(`card`, "card.json"), - JSON.stringify( - { - card: { - border: { - radius: { - mobile: { - value: "{radii.none}", - }, - desktop: { - value: "{radii.sm}", - }, - }, - }, - heading: { - color: { - value: "{color.font.base}", - }, - }, - text: { - color: { - value: "{color.font.tertiary}", - }, - }, - }, - }, - null, - 2 - ) - ); - - fs.writeFileSync( - path.join(`radii`, "base.json"), - JSON.stringify( - { - radii: { - none: { - value: "0", - }, - sm: { - value: "8px", - }, - }, - }, - null, - 2 - ) - ); -} - -export function createConfig() { - fs.writeFileSync( +export async function createConfig() { + fs.promises.writeFile( // take the .js by default SD_CONFIG_PATH, JSON.stringify( @@ -221,7 +128,8 @@ export function createConfig() { }, null, 2 - ) + ), + "utf-8" ); } @@ -253,6 +161,8 @@ export async function replaceSource(files, { clear = true, run = true } = {}) { await switchToFile(findUsedConfigPath(), editorConfig); resizeMonacoLayout(); if (run) { + // reset rootDir + await sdState.determineRootFolder(); await sdState.runStyleDictionary({ force: true }); } await openAllFolders(); @@ -263,8 +173,7 @@ export async function createInputFiles() { if (urlSplit.length > 1 && window.__configurator_standalone__) { await createFilesFromURL(urlSplit[1]); } else { - createConfig(); - createStudioTokens(); + await Promise.all([createConfig(), createStudioTokens()]); } } @@ -282,12 +191,12 @@ export async function createFolder(foldername) { resolve(); }); }); + await sdState.determineRootFolder(); } export async function editFileName(filePath, newName, isFolder = false) { const newPath = path.join(path.dirname(filePath), newName); fs.renameSync(filePath, newPath); - // await sdState.runStyleDictionary(); } export async function removeFile(file) {