Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRAFT: added design tokens key order sorter #3331

Draft
wants to merge 2 commits into
base: release-23.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 191 additions & 0 deletions designTokenKeySorter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
/* eslint-disable no-console */
const fs = require('fs').promises;
const path = require('path');
const chalk = require('chalk');

const tokensDirectory = 'tokens/';

const DESIGN_TOKEN_KEY_ORDER = [
'$type',
'$value',
'$description',
'outputReferences',
'modify',
'source',
];

const shouldApplyFix = process.argv.includes('--fix');

let mismatchWarningCount = 0;
let totalProcessedFileCount = 0;

/**
* Reorders the keys in an object based on a specified key order.
* @param {Object} object - The object to reorder.
* @param {string[]} desiredKeyOrder - The desired order for the keys.
* @returns {Object} - An object containing the reordered object and
* a flag indicating if the key order was mismatched and a list of mismatched keys.
*/
function reorderKeysInObject(object, desiredKeyOrder) {
const objectKeys = Object.keys(object);
console.log('objectKeys =====>', objectKeys);
const objectKeySet = new Set(objectKeys);
let isOrderMismatched = false;
const mismatchedKeyList = [];

let index = 0;

const reorderedObject = desiredKeyOrder.reduce((accumulatedObject, key) => {
if (objectKeySet.has(key)) {
accumulatedObject[key] = object[key];
if (key !== objectKeys[index]) {
isOrderMismatched = true;
mismatchedKeyList.push(objectKeys[index]);
}
index++;
}
return accumulatedObject;
}, {});

objectKeys.forEach((key) => {
if (!Object.prototype.hasOwnProperty.call(reorderedObject, key)) {
reorderedObject[key] = object[key];
if (index < objectKeys.length && key !== objectKeys[index]) {
isOrderMismatched = true;
mismatchedKeyList.push(objectKeys[index]);
}
index++;
}
});

return {
reorderedObject,
isOrderMismatched,
mismatchedKeys: mismatchedKeyList,
};
}

/**
* Recursively reorders keys in JSON data based on a specified key order for nested objects.
* @param {*} jsonData - The JSON data (object, array, or primitive) to process.
* @param {string} jsonPath - The path to the current data within the JSON structure.
* @returns {Object} - An object containing the reordered data and
* a flag indicating if any key order mismatches were found.
*/
function recursivelyReorderKeys(jsonData, jsonPath = '') {
if (Array.isArray(jsonData)) {
return jsonData.map((item, index) => recursivelyReorderKeys(item, `${jsonPath}[${index}]`));
}

if (typeof jsonData === 'object' && jsonData !== null) {
const {
reorderedObject: reorderedData,
isOrderMismatched: hasMainMismatch,
mismatchedKeys: mainMismatchedKeys,
} = reorderKeysInObject(jsonData, DESIGN_TOKEN_KEY_ORDER);

let hasAnyMismatch = hasMainMismatch;
const mismatches = hasMainMismatch ? { [jsonPath]: mainMismatchedKeys } : {};

Object.entries(reorderedData).reduce((accumulatedMismatches, [key, value]) => {
if (DESIGN_TOKEN_KEY_ORDER.includes(key)) {
reorderedData[key] = value;
return accumulatedMismatches;
}

const result = recursivelyReorderKeys(value, `${jsonPath}.${key}`);
reorderedData[key] = result.reorderedData || result;

if (result.isOrderMismatched) {
Object.assign(accumulatedMismatches, result.mismatches);
hasAnyMismatch = true;
}
return accumulatedMismatches;
}, mismatches);

return {
reorderedData,
isOrderMismatched: hasAnyMismatch,
mismatches,
};
}

return jsonData;
}

/**
* Processes all JSON files in a given directory path,
* reordering keys in each file based on predefined key orders.
* @param {string} directoryPath - The path of the directory containing JSON files.
*/
async function processJsonFilesInDirectory(directoryPath) {
try {
const directoryEntries = await fs.readdir(directoryPath, { withFileTypes: true });

const fileProcessingTasks = directoryEntries.map(async (entry) => {
const entryPath = path.join(directoryPath, entry.name);

if (entry.isDirectory()) {
return processJsonFilesInDirectory(entryPath);
}

if (entry.isFile() && path.extname(entry.name) === '.json') {
try {
const fileContent = await fs.readFile(entryPath, 'utf-8');
const jsonData = JSON.parse(fileContent);

const {
reorderedData,
isOrderMismatched,
mismatches,
} = recursivelyReorderKeys(jsonData);

if (isOrderMismatched) {
mismatchWarningCount++;
if (shouldApplyFix) {
await fs.writeFile(entryPath, `${JSON.stringify(reorderedData, null, 2)}\n`, 'utf-8');
} else {
console.warn(chalk.yellow(`Warning: Key order mismatch in ${entryPath}.`));
console.warn(chalk.red('Mismatched info:'));
Object.entries(mismatches).forEach(([keyPath, keys]) => {
console.warn(chalk.cyan(` Path: ${keyPath.slice(1)}`));
console.warn(chalk.magenta(` Mismatched keys: ${keys.join(', ')}`));
console.warn();
});
}
}

if (!fileContent.endsWith('\n')) {
await fs.writeFile(entryPath, `${fileContent}\n`, 'utf-8');
}

totalProcessedFileCount++;
return null;
} catch (error) {
console.error(chalk.red(`Error processing file ${entryPath}:`), error);
return null;
}
}

return null;
});

await Promise.all(fileProcessingTasks);
} catch (error) {
console.error(chalk.red(`Error reading directory ${directoryPath}:`), error);
}
}

processJsonFilesInDirectory(tokensDirectory).then(() => {
let statusMessage;

if (shouldApplyFix) {
statusMessage = chalk.green(`Processed ${totalProcessedFileCount} files. ${mismatchWarningCount} files were updated.`);
} else if (mismatchWarningCount > 0) {
statusMessage = chalk.yellow(`Processed ${totalProcessedFileCount} files. ${mismatchWarningCount} files have key order mismatches.`);
} else {
statusMessage = chalk.green(`Processed ${totalProcessedFileCount} files. All files are in correct order.`);
}

console.log(statusMessage);
});
30 changes: 25 additions & 5 deletions tokens/src/core/alias/size.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,35 @@
"size": {
"$type": "dimension",
"border": {
"width": { "source": "$border-width", "$value": "1px", "$description": "Default border width." },
"width": {
"$value": "1px",
"$description": "Default border width.",
"source": "$border-width"
},
"radius": {
"base": { "source": "$border-radius", "$value": ".375rem", "$description": "Default border radius." },
"lg": { "source": "$border-radius-lg", "$value": ".425rem", "$description": "Large border radius." },
"sm": { "source": "$border-radius-sm", "$value": ".25rem", "$description": "Small border radius." }
"base": {
"$value": ".375rem",
"$description": "Default border radius.",
"source": "$border-radius"
},
"lg": {
"$value": ".425rem",
"$description": "Large border radius.",
"source": "$border-radius-lg"
},
"sm": {
"$value": ".25rem",
"$description": "Small border radius.",
"source": "$border-radius-sm"
}
}
},
"rounded": {
"pill": { "source": "$rounded-pill", "$value": "50rem", "$description": "Pill border radius." }
"pill": {
"$value": "50rem",
"$description": "Pill border radius.",
"source": "$rounded-pill"
}
}
}
}
10 changes: 8 additions & 2 deletions tokens/src/core/components/ActionRow.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@
"$type": "dimension",
"action-row": {
"gap": {
"x": { "source": "$action-row-gap-x", "$value": ".5rem" },
"y": { "source": "$action-row-gap-y", "$value": ".5rem" }
"x": {
"$value": ".5rem",
"source": "$action-row-gap-x"
},
"y": {
"$value": ".5rem",
"source": "$action-row-gap-y"
}
}
}
}
Expand Down
53 changes: 43 additions & 10 deletions tokens/src/core/components/Alert.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,62 @@
"$type": "dimension",
"alert": {
"padding": {
"y": { "source": "$alert-padding-y", "$value": "1.5rem" },
"x": { "source": "$alert-padding-x", "$value": "1.5rem" }
"y": {
"$value": "1.5rem",
"source": "$alert-padding-y"
},
"x": {
"$value": "1.5rem",
"source": "$alert-padding-x"
}
},
"margin-bottom": { "source": "$alert-margin-bottom", "$value": "1rem" },
"actions-gap": { "source": "$alert-actions-gap", "$value": "{spacing.spacer.3}" },
"icon-space": { "source": "$alert-icon-space", "$value": ".8rem" }
"margin-bottom": {
"$value": "1rem",
"source": "$alert-margin-bottom"
},
"actions-gap": {
"$value": "{spacing.spacer.3}",
"source": "$alert-actions-gap"
},
"icon-space": {
"$value": ".8rem",
"source": "$alert-icon-space"
}
}
},
"typography": {
"alert": {
"font": {
"weight-link": { "source": "$alert-link-font-weight", "$value": "{typography.font.weight.normal}", "$type": "fontWeight" },
"size": { "source": "$alert-font-size", "$value": ".875rem", "$type": "dimension" }
"weight-link": {
"$type": "fontWeight",
"$value": "{typography.font.weight.normal}",
"source": "$alert-link-font-weight"
},
"size": {
"$type": "dimension",
"$value": ".875rem",
"source": "$alert-font-size"
}
},
"line-height": { "source": "$alert-line-height", "$value": "1.5rem", "$type": "number" }
"line-height": {
"$type": "number",
"$value": "1.5rem",
"source": "$alert-line-height"
}
}
},
"size": {
"$type": "dimension",
"alert": {
"border": {
"radius": { "source": "$alert-border-radius", "$value": "{size.border.radius.base}" },
"width": { "source": "$alert-border-width", "$value": "0" }
"radius": {
"$value": "{size.border.radius.base}",
"source": "$alert-border-radius"
},
"width": {
"$value": "0",
"source": "$alert-border-width"
}
}
}
}
Expand Down
37 changes: 30 additions & 7 deletions tokens/src/core/components/Annotation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,49 @@
"spacing": {
"$type": "dimension",
"annotation": {
"padding": { "source": "$annotation-padding", "$value": ".5rem" },
"padding": {
"$value": ".5rem",
"source": "$annotation-padding"
},
"arrow-side": {
"margin": { "source": "$annotation-arrow-side-margin", "$value": ".25rem" }
"margin": {
"$value": ".25rem",
"source": "$annotation-arrow-side-margin"
}
}
}
},
"typography": {
"annotation": {
"font-size": { "source": "$annotation-font-size", "$value": "{typography.font.size.sm}", "$type": "dimension" },
"line-height": { "source": "$annotation-line-height", "$value": "{typography.line-height.sm}", "$type": "number" }
"font-size": {
"$type": "dimension",
"$value": "{typography.font.size.sm}",
"source": "$annotation-font-size"
},
"line-height": {
"$type": "number",
"$value": "{typography.line-height.sm}",
"source": "$annotation-line-height"
}
}
},
"size": {
"$type": "dimension",
"annotation": {
"arrow-border": {
"width": { "source": "$annotation-arrow-border-width", "$value": ".5rem" }
"width": {
"$value": ".5rem",
"source": "$annotation-arrow-border-width"
}
},
"max-width": { "source": "$annotation-max-width", "$value": "18.75rem" },
"border-radius": { "source": "$annotation-border-radius", "$value": ".25rem" }
"max-width": {
"$value": "18.75rem",
"source": "$annotation-max-width"
},
"border-radius": {
"$value": ".25rem",
"source": "$annotation-border-radius"
}
}
}
}
Loading
Loading