Skip to content

Commit a882d4a

Browse files
Merge pull request #91 from tokens-studio/nested-folders
feat: allow nested token folders for
2 parents 72a9cfd + 874d5fc commit a882d4a

File tree

2 files changed

+45
-106
lines changed

2 files changed

+45
-106
lines changed

src/style-dictionary.js

+34-4
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
import { fs } from "style-dictionary/fs";
22
import StyleDictionary from "style-dictionary";
3+
import { permutateThemes } from "@tokens-studio/sd-transforms";
4+
import { posix } from "path-unified";
35
import {
46
repopulateFileTree,
57
getFileTreeEl,
68
currentFileOutput,
79
} from "./utils/file-tree.js";
8-
import { permutateThemes } from "@tokens-studio/sd-transforms";
910
import { bundle } from "./utils/rollup-bundle.js";
1011
import { findUsedConfigPath } from "./utils/findUsedConfigPath.js";
1112
import {
1213
THEME_STRING,
1314
SD_FUNCTIONS_PATH,
1415
SD_CHANGED_EVENT,
16+
SD_CONFIG_PATH,
1517
} from "./constants.js";
1618
import { snackbar } from "./components/snackbar/SnackbarManager.js";
17-
import { html } from "lit";
1819

1920
const { promises } = fs;
2021

@@ -41,6 +42,7 @@ class SdState extends EventTarget {
4142
this._sd = [];
4243
this._themes = {};
4344
this.themedConfigs = [];
45+
this.rootDir = "/";
4446
this.hasInitializedConfig = new Promise((resolve) => {
4547
this.hasInitializedConfigResolve = resolve;
4648
});
@@ -83,6 +85,30 @@ class SdState extends EventTarget {
8385
}
8486
}
8587

88+
async determineRootFolder() {
89+
let rootDir = "/";
90+
// the $themes.json and tokens could be in any nested
91+
// folder structure. this code recursively goes through them
92+
// until it finds more than just 1 nested folder
93+
const getDirContents = async () => {
94+
const contents = (await promises.readdir(rootDir)).filter(
95+
(f) => ![SD_FUNCTIONS_PATH, SD_CONFIG_PATH].includes(f)
96+
);
97+
if (
98+
contents.length === 1 &&
99+
(await promises.lstat(posix.join(rootDir, contents[0]))).isDirectory()
100+
) {
101+
return contents[0];
102+
}
103+
};
104+
105+
let dir;
106+
while ((dir = await getDirContents(rootDir))) {
107+
rootDir = posix.join(rootDir, dir);
108+
}
109+
this.rootDir = rootDir;
110+
}
111+
86112
async processConfigForThemes(cfg) {
87113
const addThemeToFilePath = (file) => {
88114
const fileParts = file.split(".");
@@ -94,7 +120,9 @@ class SdState extends EventTarget {
94120
};
95121

96122
try {
97-
const $themes = JSON.parse(await promises.readFile("$themes.json"));
123+
const $themes = JSON.parse(
124+
await promises.readFile(posix.join(this.rootDir, "$themes.json"))
125+
);
98126

99127
if ($themes.length > 0) {
100128
// 1) adjust config source and platform files names to themed
@@ -246,7 +274,9 @@ class SdState extends EventTarget {
246274
injectThemeVariables(cfg, theme, tokensets) {
247275
const reg = new RegExp(THEME_STRING, "g");
248276
const newCfg = JSON.parse(JSON.stringify(cfg).replace(reg, theme));
249-
newCfg.source = tokensets.map((set) => `${set}.json`);
277+
newCfg.source = tokensets.map((set) =>
278+
posix.join(this.rootDir, `${set}.json`)
279+
);
250280
return newCfg;
251281
}
252282

src/utils/file-tree.js

+11-102
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,7 @@ async function createFilesFromURL(project) {
6868
snackbar.show(
6969
"Flate could not be loaded to decode the URL to project files.\nCreating default tokens studio template instead."
7070
);
71-
createConfig();
72-
createStudioTokens();
71+
await Promise.all([createConfig(), createStudioTokens()]);
7372
return;
7473
}
7574

@@ -85,111 +84,19 @@ async function createFilesFromURL(project) {
8584
return fs.promises.writeFile(file, content);
8685
})
8786
);
87+
await sdState.determineRootFolder();
8888
}
8989

9090
export async function createStudioTokens() {
9191
const tokens = await (
9292
await fetch(new URL("./core.json", import.meta.url).href)
9393
).json();
9494

95-
fs.writeFileSync("studio.json", JSON.stringify(tokens, null, 2));
95+
fs.promises.writeFile("studio.json", JSON.stringify(tokens, null, 2));
9696
}
9797

98-
export function createStandardTokens() {
99-
fs.mkdirSync(`color`);
100-
fs.mkdirSync(`card`);
101-
fs.mkdirSync(`radii`);
102-
fs.writeFileSync(
103-
path.join(`color`, "base.json"),
104-
JSON.stringify(
105-
{
106-
color: {
107-
base: {
108-
gray: {
109-
light: { value: "#CCCCCC" },
110-
medium: { value: "#999999" },
111-
dark: { value: "#111111" },
112-
},
113-
red: { value: "#FF0000" },
114-
green: { value: "#00FF00" },
115-
},
116-
},
117-
},
118-
null,
119-
2
120-
)
121-
);
122-
123-
fs.writeFileSync(
124-
path.join(`color`, "font.json"),
125-
JSON.stringify(
126-
{
127-
color: {
128-
font: {
129-
base: { value: "{color.base.red}" },
130-
secondary: { value: "{color.base.green}" },
131-
tertiary: { value: "{color.base.gray.dark}" },
132-
},
133-
},
134-
},
135-
null,
136-
2
137-
)
138-
);
139-
140-
fs.writeFileSync(
141-
path.join(`card`, "card.json"),
142-
JSON.stringify(
143-
{
144-
card: {
145-
border: {
146-
radius: {
147-
mobile: {
148-
value: "{radii.none}",
149-
},
150-
desktop: {
151-
value: "{radii.sm}",
152-
},
153-
},
154-
},
155-
heading: {
156-
color: {
157-
value: "{color.font.base}",
158-
},
159-
},
160-
text: {
161-
color: {
162-
value: "{color.font.tertiary}",
163-
},
164-
},
165-
},
166-
},
167-
null,
168-
2
169-
)
170-
);
171-
172-
fs.writeFileSync(
173-
path.join(`radii`, "base.json"),
174-
JSON.stringify(
175-
{
176-
radii: {
177-
none: {
178-
value: "0",
179-
},
180-
sm: {
181-
value: "8px",
182-
},
183-
},
184-
},
185-
null,
186-
2
187-
)
188-
);
189-
}
190-
191-
export function createConfig() {
192-
fs.writeFileSync(
98+
export async function createConfig() {
99+
fs.promises.writeFile(
193100
// take the .js by default
194101
SD_CONFIG_PATH,
195102
JSON.stringify(
@@ -221,7 +128,8 @@ export function createConfig() {
221128
},
222129
null,
223130
2
224-
)
131+
),
132+
"utf-8"
225133
);
226134
}
227135

@@ -253,6 +161,8 @@ export async function replaceSource(files, { clear = true, run = true } = {}) {
253161
await switchToFile(findUsedConfigPath(), editorConfig);
254162
resizeMonacoLayout();
255163
if (run) {
164+
// reset rootDir
165+
await sdState.determineRootFolder();
256166
await sdState.runStyleDictionary({ force: true });
257167
}
258168
await openAllFolders();
@@ -263,8 +173,7 @@ export async function createInputFiles() {
263173
if (urlSplit.length > 1 && window.__configurator_standalone__) {
264174
await createFilesFromURL(urlSplit[1]);
265175
} else {
266-
createConfig();
267-
createStudioTokens();
176+
await Promise.all([createConfig(), createStudioTokens()]);
268177
}
269178
}
270179

@@ -282,12 +191,12 @@ export async function createFolder(foldername) {
282191
resolve();
283192
});
284193
});
194+
await sdState.determineRootFolder();
285195
}
286196

287197
export async function editFileName(filePath, newName, isFolder = false) {
288198
const newPath = path.join(path.dirname(filePath), newName);
289199
fs.renameSync(filePath, newPath);
290-
// await sdState.runStyleDictionary();
291200
}
292201

293202
export async function removeFile(file) {

0 commit comments

Comments
 (0)