@supernovaio/cli 0.9.13 → 0.9.15
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.
|
@@ -12,6 +12,7 @@ exports.SyncDesignTokens = void 0;
|
|
|
12
12
|
// MARK: - Imports
|
|
13
13
|
const core_1 = require("@oclif/core");
|
|
14
14
|
const supernova_sdk_1 = require("@supernovaio/supernova-sdk");
|
|
15
|
+
const figma_tokens_data_loader_1 = require("../utils/figma-tokens-data-loader");
|
|
15
16
|
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
|
16
17
|
// MARK: - Configuration
|
|
17
18
|
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
|
@@ -25,11 +26,15 @@ class SyncDesignTokens extends core_1.Command {
|
|
|
25
26
|
// Get workspace -> design system –> version
|
|
26
27
|
let connected = await this.getWritableVersion(flags);
|
|
27
28
|
let dsTool = new supernova_sdk_1.SupernovaToolsDesignTokensPlugin(connected.version);
|
|
29
|
+
let dataLoader = new figma_tokens_data_loader_1.FigmaTokensDataLoader();
|
|
30
|
+
let configDefinition = dataLoader.loadConfigFromPath(flags.configFilePath);
|
|
28
31
|
if (flags.tokenDirPath) {
|
|
29
|
-
await
|
|
32
|
+
let tokenDefinition = await dataLoader.loadTokensFromDirectory(flags.tokenDirPath, flags.configFilePath);
|
|
33
|
+
await dsTool.synchronizeTokensFromData(tokenDefinition, configDefinition.mapping, configDefinition.settings);
|
|
30
34
|
}
|
|
31
35
|
else if (flags.tokenFilePath) {
|
|
32
|
-
await
|
|
36
|
+
let tokenDefinition = await dataLoader.loadTokensFromPath(flags.tokenFilePath);
|
|
37
|
+
await dsTool.synchronizeTokensFromData(tokenDefinition, configDefinition.mapping, configDefinition.settings);
|
|
33
38
|
}
|
|
34
39
|
this.log(`Tokens synchronized`);
|
|
35
40
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { DTPluginToSupernovaSettings, DTPluginToSupernovaMapPack } from "@supernovaio/supernova-sdk";
|
|
2
|
+
export declare class FigmaTokensDataLoader {
|
|
3
|
+
/** Load token definitions from path */
|
|
4
|
+
loadTokensFromPath(pathToFile: string): Promise<object>;
|
|
5
|
+
loadTokensFromDirectory(pathToDirectory: string, settingsPath: string): Promise<object>;
|
|
6
|
+
private getAllJSONFiles;
|
|
7
|
+
private getFileNameWithoutExtension;
|
|
8
|
+
private getSetKey;
|
|
9
|
+
loadConfigFromPath(pathToFile: string): {
|
|
10
|
+
mapping: DTPluginToSupernovaMapPack;
|
|
11
|
+
settings: DTPluginToSupernovaSettings;
|
|
12
|
+
};
|
|
13
|
+
private weakValidateMapping;
|
|
14
|
+
private processFileToMapping;
|
|
15
|
+
private parseDefinition;
|
|
16
|
+
private loadObjectFile;
|
|
17
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FigmaTokensDataLoader = void 0;
|
|
4
|
+
const supernova_sdk_1 = require("@supernovaio/supernova-sdk");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
const path = require('path');
|
|
7
|
+
class FigmaTokensDataLoader {
|
|
8
|
+
/** Load token definitions from path */
|
|
9
|
+
async loadTokensFromPath(pathToFile) {
|
|
10
|
+
try {
|
|
11
|
+
if (!(fs.existsSync(pathToFile) && fs.lstatSync(pathToFile).isFile())) {
|
|
12
|
+
throw Error(`Provided token file directory ${pathToFile} is not a file or doesn't exist`);
|
|
13
|
+
}
|
|
14
|
+
let definition = fs.readFileSync(pathToFile, 'utf8');
|
|
15
|
+
let parsedDefinition = this.parseDefinition(definition);
|
|
16
|
+
return parsedDefinition;
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
throw new Error('Unable to load JSON definition file: ' + error);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async loadTokensFromDirectory(pathToDirectory, settingsPath) {
|
|
23
|
+
try {
|
|
24
|
+
let fullStructuredObject = {};
|
|
25
|
+
if (!(fs.existsSync(pathToDirectory) && fs.lstatSync(pathToDirectory).isDirectory())) {
|
|
26
|
+
throw new Error(`Provided data directory ${pathToDirectory} is not a directory or doesn't exist`);
|
|
27
|
+
}
|
|
28
|
+
let jsonPaths = this.getAllJSONFiles(pathToDirectory);
|
|
29
|
+
for (let path of jsonPaths) {
|
|
30
|
+
if (path.endsWith('json') && path !== settingsPath && !path.includes('$')) {
|
|
31
|
+
let result = await this.loadObjectFile(path);
|
|
32
|
+
if (typeof result === 'object') {
|
|
33
|
+
// let name = this.getFileNameWithoutExtension(path)
|
|
34
|
+
let name = this.getSetKey(path, pathToDirectory);
|
|
35
|
+
fullStructuredObject[name] = result;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Try to load themes, if any
|
|
40
|
+
let themePath = pathToDirectory + '/' + '$themes.json';
|
|
41
|
+
if (fs.existsSync(themePath)) {
|
|
42
|
+
let themes = await this.loadObjectFile(themePath);
|
|
43
|
+
fullStructuredObject['$themes'] = themes;
|
|
44
|
+
}
|
|
45
|
+
// Try to load metadata, if any
|
|
46
|
+
let metadataPath = pathToDirectory + '/' + '$metadata.json';
|
|
47
|
+
if (fs.existsSync(metadataPath)) {
|
|
48
|
+
let metadata = await this.loadObjectFile(themePath);
|
|
49
|
+
fullStructuredObject['$metadata'] = metadata;
|
|
50
|
+
}
|
|
51
|
+
return fullStructuredObject;
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new Error('Unable to load JSON definition file: ' + error);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
getAllJSONFiles(dir) {
|
|
58
|
+
const files = fs.readdirSync(dir);
|
|
59
|
+
const jsonFiles = [];
|
|
60
|
+
for (const file of files) {
|
|
61
|
+
const filePath = `${dir}/${file}`;
|
|
62
|
+
const fileStat = fs.statSync(filePath);
|
|
63
|
+
if (fileStat.isDirectory()) {
|
|
64
|
+
jsonFiles.push(...this.getAllJSONFiles(filePath));
|
|
65
|
+
}
|
|
66
|
+
else if (fileStat.isFile() && filePath.endsWith('.json')) {
|
|
67
|
+
jsonFiles.push(filePath);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return jsonFiles;
|
|
71
|
+
}
|
|
72
|
+
getFileNameWithoutExtension(filePath) {
|
|
73
|
+
const fileStat = fs.statSync(filePath);
|
|
74
|
+
if (!fileStat.isFile()) {
|
|
75
|
+
throw new Error(`${filePath} is not a file`);
|
|
76
|
+
}
|
|
77
|
+
return path.basename(filePath, path.extname(filePath));
|
|
78
|
+
}
|
|
79
|
+
getSetKey(jsonFilePath, loadedDirectory) {
|
|
80
|
+
return jsonFilePath.substring(loadedDirectory.length + 1, jsonFilePath.length - 5);
|
|
81
|
+
}
|
|
82
|
+
loadConfigFromPath(pathToFile) {
|
|
83
|
+
try {
|
|
84
|
+
if (!(fs.existsSync(pathToFile) && fs.lstatSync(pathToFile).isFile())) {
|
|
85
|
+
throw new Error(`Provided configuration file directory ${pathToFile} is not a file or doesn't exist`);
|
|
86
|
+
}
|
|
87
|
+
let definition = fs.readFileSync(pathToFile, 'utf8');
|
|
88
|
+
let parsedDefinition = this.parseDefinition(definition);
|
|
89
|
+
this.weakValidateMapping(parsedDefinition);
|
|
90
|
+
return this.processFileToMapping(parsedDefinition);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
throw new Error('Unable to load JSON definition file: ' + error);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
weakValidateMapping(mapping) {
|
|
97
|
+
if (!mapping.hasOwnProperty('mode') ||
|
|
98
|
+
typeof mapping.mode !== 'string' ||
|
|
99
|
+
(mapping.mode !== 'multi-file' && mapping.mode !== 'single-file')) {
|
|
100
|
+
throw new Error('Unable to load mapping file: `mode` must be provided [single-file or multi-file]`');
|
|
101
|
+
}
|
|
102
|
+
if (!mapping.mapping || !(mapping.mapping instanceof Array)) {
|
|
103
|
+
throw new Error('Unable to load mapping file: `mapping` key must be present and array.');
|
|
104
|
+
}
|
|
105
|
+
let mapPack = mapping.mapping;
|
|
106
|
+
for (let map of mapPack) {
|
|
107
|
+
if (typeof map !== 'object') {
|
|
108
|
+
throw new Error('Unable to load mapping file: `mapping` must contain objects only');
|
|
109
|
+
}
|
|
110
|
+
if (!map.tokenSets && !map.tokensTheme) {
|
|
111
|
+
throw new Error('Unable to load mapping file: `mapping` must contain either `tokensTheme` or `tokenSets`');
|
|
112
|
+
}
|
|
113
|
+
if (map.tokenSets && map.tokensTheme) {
|
|
114
|
+
throw new Error('Unable to load mapping file: `mapping` must not contain both `tokensTheme` or `tokenSets`');
|
|
115
|
+
}
|
|
116
|
+
if (map.tokenSets && (!(map.tokenSets instanceof Array) || map.tokenSets.length === 0)) {
|
|
117
|
+
throw new Error('Unable to load mapping file: `mapping`.`tokenSets` must be an Array with at least one entry');
|
|
118
|
+
}
|
|
119
|
+
if (map.tokensTheme && (typeof map.tokensTheme !== 'string' || map.tokensTheme.length === 0)) {
|
|
120
|
+
throw new Error('Unable to load mapping file: `mapping`.`tokensTheme` must be a non-empty string');
|
|
121
|
+
}
|
|
122
|
+
if (!map.supernovaBrand || typeof map.supernovaBrand !== 'string' || map.supernovaBrand.length === 0) {
|
|
123
|
+
throw new Error('Unable to load mapping file: `supernovaBrand` must be a non-empty string');
|
|
124
|
+
}
|
|
125
|
+
if (map.supernovaTheme && (typeof map.supernovaTheme !== 'string' || map.supernovaTheme.length === 0)) {
|
|
126
|
+
throw new Error('Unable to load mapping file: `supernovaTheme` may be empty but must be non-empty string if not');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (mapping.settings) {
|
|
130
|
+
if (typeof mapping.settings !== 'object') {
|
|
131
|
+
throw new Error('Unable to load mapping file: `settings` must be an object');
|
|
132
|
+
}
|
|
133
|
+
if (mapping.settings.hasOwnProperty('dryRun') && typeof mapping.settings.dryRun !== 'boolean') {
|
|
134
|
+
throw new Error('Unable to load mapping file: `dryRun` must be of boolan type');
|
|
135
|
+
}
|
|
136
|
+
if (mapping.settings.hasOwnProperty('verbose') && typeof mapping.settings.verbose !== 'boolean') {
|
|
137
|
+
throw new Error('Unable to load mapping file: `verbose` must be of boolan type');
|
|
138
|
+
}
|
|
139
|
+
if (mapping.settings.hasOwnProperty('preciseCopy') && typeof mapping.settings.preciseCopy !== 'boolean') {
|
|
140
|
+
throw new Error('Unable to load mapping file: `preciseCopy` must be of boolan type');
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
processFileToMapping(mapping) {
|
|
145
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
146
|
+
let result = new Array();
|
|
147
|
+
for (let map of mapping.mapping) {
|
|
148
|
+
result.push({
|
|
149
|
+
type: map.tokenSets ? supernova_sdk_1.DTPluginToSupernovaMapType.set : supernova_sdk_1.DTPluginToSupernovaMapType.theme,
|
|
150
|
+
pluginSets: (_a = map.tokenSets) !== null && _a !== void 0 ? _a : null,
|
|
151
|
+
pluginTheme: (_b = map.tokensTheme) !== null && _b !== void 0 ? _b : null,
|
|
152
|
+
bindToBrand: map.supernovaBrand,
|
|
153
|
+
bindToTheme: (_c = map.supernovaTheme) !== null && _c !== void 0 ? _c : null,
|
|
154
|
+
nodes: null,
|
|
155
|
+
processedNodes: null,
|
|
156
|
+
processedGroups: null
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
let settings = {
|
|
160
|
+
dryRun: (_e = (_d = mapping.settings) === null || _d === void 0 ? void 0 : _d.dryRun) !== null && _e !== void 0 ? _e : false,
|
|
161
|
+
verbose: (_g = (_f = mapping.settings) === null || _f === void 0 ? void 0 : _f.verbose) !== null && _g !== void 0 ? _g : false,
|
|
162
|
+
preciseCopy: (_j = (_h = mapping.settings) === null || _h === void 0 ? void 0 : _h.preciseCopy) !== null && _j !== void 0 ? _j : false
|
|
163
|
+
};
|
|
164
|
+
return {
|
|
165
|
+
mapping: result,
|
|
166
|
+
settings: settings
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
// --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
|
170
|
+
// MARK: - File Parser
|
|
171
|
+
parseDefinition(definition) {
|
|
172
|
+
try {
|
|
173
|
+
let object = JSON.parse(definition);
|
|
174
|
+
if (typeof object !== 'object') {
|
|
175
|
+
throw new Error('Invalid Supernova mapping definition JSON file - root level entity must be object');
|
|
176
|
+
}
|
|
177
|
+
return object;
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
throw new Error('Invalid Supernova mapping definition JSON file - file structure invalid');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async loadObjectFile(pathToFile) {
|
|
184
|
+
try {
|
|
185
|
+
if (!(fs.existsSync(pathToFile) && fs.lstatSync(pathToFile).isFile())) {
|
|
186
|
+
throw new Error(`Provided token file directory ${pathToFile} is not a file or doesn't exist`);
|
|
187
|
+
}
|
|
188
|
+
let definition = fs.readFileSync(pathToFile, 'utf8');
|
|
189
|
+
let parsedDefinition = this.parseDefinition(definition);
|
|
190
|
+
return parsedDefinition;
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
throw new Error('Unable to load JSON definition file: ' + error);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
exports.FigmaTokensDataLoader = FigmaTokensDataLoader;
|
package/oclif.manifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.9.
|
|
1
|
+
{"version":"0.9.15","commands":{"describe-design-system":{"id":"describe-design-system","description":"Describe structure of single design system by provided ID","strict":true,"pluginName":"@supernovaio/cli","pluginAlias":"@supernovaio/cli","pluginType":"core","aliases":[],"examples":["$ @supernovaio/cli describe-design-system --apiKey=\"{xxx-xxx-xxx}\" --designSystemId=\"{1234}\""],"flags":{"apiKey":{"name":"apiKey","type":"option","description":"API key to use for accessing Supernova instance","required":true,"multiple":false},"designSystemId":{"name":"designSystemId","type":"option","description":"Design System to describe structure of","required":true,"multiple":false},"dev":{"name":"dev","type":"boolean","description":"When enabled, CLI will target dev server","hidden":true,"allowNo":false}},"args":[],"_globalFlags":{}},"describe-workspaces":{"id":"describe-workspaces","description":"Describe structure of all workspaces and design systems available under those workspaces available for specified API key","strict":true,"pluginName":"@supernovaio/cli","pluginAlias":"@supernovaio/cli","pluginType":"core","aliases":[],"examples":["$ @supernovaio/cli describe-workspaces --apiKey=\"{xxx-xxx-xxx}\""],"flags":{"apiKey":{"name":"apiKey","type":"option","description":"API key to use for accessing Supernova instance","required":true,"multiple":false},"dev":{"name":"dev","type":"boolean","description":"When enabled, CLI will target dev server","hidden":true,"allowNo":false}},"args":[],"_globalFlags":{}},"publish-documentation":{"id":"publish-documentation","description":"Publish latest version of the documentation","strict":true,"pluginName":"@supernovaio/cli","pluginAlias":"@supernovaio/cli","pluginType":"core","aliases":[],"examples":["$ @supernovaio/cli publish-documentation --apiKey=\"{xxx-xxx-xxx}\" --designSystemId=\"{1234}\""],"flags":{"apiKey":{"name":"apiKey","type":"option","description":"API key to use for accessing Supernova instance","required":true,"multiple":false},"designSystemId":{"name":"designSystemId","type":"option","description":"Design System to publish the documentation","required":true,"multiple":false},"dev":{"name":"dev","type":"boolean","description":"When enabled, CLI will target dev server","hidden":true,"allowNo":false}},"args":[],"_globalFlags":{}},"sync-tokens":{"id":"sync-tokens","description":"Synchronize tokens from Figma Tokens plugin to Supernova workspaces","strict":true,"pluginName":"@supernovaio/cli","pluginAlias":"@supernovaio/cli","pluginType":"core","aliases":[],"examples":["$ @supernovaio/cli sync-tokens --apiKey=\"{xxx-xxx-xxx}\" --designSystemId={1234} --tokenFilePath \"/path/to/tokens.json\" --configFilePath \"/path/to/config.json\"","$ @supernovaio/cli sync-tokens --apiKey=\"{xxx-xxx-xxx}\" --designSystemId={1234} --tokenDirPath \"/path/to/tokens/\" --configFilePath \"/path/to/config.json\""],"flags":{"apiKey":{"name":"apiKey","type":"option","description":"API key to use for accessing Supernova instance","required":true,"multiple":false},"designSystemId":{"name":"designSystemId","type":"option","description":"Design System to synchronize contents with","required":true,"multiple":false},"tokenFilePath":{"name":"tokenFilePath","type":"option","description":"Path to JSON file containing token definitions","multiple":false},"tokenDirPath":{"name":"tokenDirPath","type":"option","description":"Path to directory of JSON files containing token definitions","multiple":false},"configFilePath":{"name":"configFilePath","type":"option","description":"Path to configuration JSON file","required":true,"multiple":false,"exclusive":[]},"dev":{"name":"dev","type":"boolean","description":"When enabled, CLI will target dev server","hidden":true,"allowNo":false}},"args":[],"_globalFlags":{}}}}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supernovaio/cli",
|
|
3
3
|
"description": "Supernova.io Command Line Interface",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.15",
|
|
5
5
|
"author": "Supernova.io",
|
|
6
6
|
"homepage": "https://supernova.io/",
|
|
7
7
|
"keywords": [
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"@oclif/core": "^1",
|
|
26
26
|
"@oclif/plugin-help": "^5",
|
|
27
27
|
"@oclif/plugin-plugins": "^2.0.1",
|
|
28
|
-
"@supernovaio/supernova-sdk": "1.8.
|
|
28
|
+
"@supernovaio/supernova-sdk": "1.8.64",
|
|
29
29
|
"chalk": "^5.0.1",
|
|
30
30
|
"node-fetch": "^3.2.4",
|
|
31
31
|
"dotenv": "^16.0.0"
|