Skip to content

Commit

Permalink
feat: added json key order linter
Browse files Browse the repository at this point in the history
  • Loading branch information
PKulkoRaccoonGang committed Nov 12, 2024
1 parent b4d560b commit fba33c7
Show file tree
Hide file tree
Showing 118 changed files with 7,667 additions and 3,612 deletions.
149 changes: 149 additions & 0 deletions json-key-order-linter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
const fs = require('fs');
const path = require('path');
const chalk = require('chalk');

const folderPath = 'tokens/';

const KEY_ORDERS = {
main: ['$type', '$value', '$description', 'outputReferences', 'modify', 'source'],
};

const shouldFix = process.argv.includes('--fix');
let warningsCount = 0;
let processedFileCount = 0;

/**
* Reorders the keys in an object based on a specified key order.
* @param {Object} obj - 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 mismatched keys.
*/
function reorderObjectKeys(obj, desiredKeyOrder) {
const reorderedObject = {};
const originalKeyList = Object.keys(obj);
let isKeyOrderMismatched = false;
const mismatchedKeysList = [];

desiredKeyOrder.forEach((key) => {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
reorderedObject[key] = obj[key];
}
});

originalKeyList.forEach((key) => {
if (!Object.prototype.hasOwnProperty.call(reorderedObject, key)) {
reorderedObject[key] = obj[key];
}
});

if (JSON.stringify(originalKeyList) !== JSON.stringify(Object.keys(reorderedObject))) {
isKeyOrderMismatched = true;
mismatchedKeysList.push(...originalKeyList.filter((key, index) => key !== Object.keys(reorderedObject)[index]));
}

return { reorderedObject, isKeyOrderMismatched, mismatchedKeys: mismatchedKeysList };
}

/**
* Recursively reorders keys in JSON data based on specified key orders for nested objects.
* @param {*} data - The JSON data (object, array, or primitive) to process.
* @param {string} currentPath - 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 reorderKeysInJson(data, currentPath = '') {
if (Array.isArray(data)) {
return data.map((item, index) => reorderKeysInJson(item, `${currentPath}[${index}]`));
}

if (typeof data === 'object' && data !== null) {
const {
reorderedObject: reorderedData, isKeyOrderMismatched: mainMismatch, mismatchedKeys: mainMismatchedKeys,
} = reorderObjectKeys(data, KEY_ORDERS.main);
let hasAnyKeyOrderMismatch = mainMismatch;
const mismatches = mainMismatch ? { [currentPath]: mainMismatchedKeys } : {};

Object.keys(reorderedData).forEach((key) => {
if (KEY_ORDERS.main.includes(key)) {
reorderedData[key] = data[key];
return;
}

const result = reorderKeysInJson(reorderedData[key], `${currentPath}.${key}`);
reorderedData[key] = typeof result === 'object' && result !== null ? result.reorderedData || result : result;
if (result.isKeyOrderMismatched) {
Object.assign(mismatches, result.mismatches);
hasAnyKeyOrderMismatch = true;
}
});

return {
reorderedData,
isKeyOrderMismatched: hasAnyKeyOrderMismatch,
mismatches,
};
}

return data;
}

/**
* 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.
*/
function processJsonFilesInDirectory(directoryPath) {
fs.readdirSync(directoryPath).forEach((fileName) => {
const filePath = path.join(directoryPath, fileName);
const fileStats = fs.statSync(filePath);

if (fileStats.isDirectory()) {
processJsonFilesInDirectory(filePath);
} else if (fileStats.isFile() && path.extname(fileName) === '.json') {
try {
let fileContent = fs.readFileSync(filePath, 'utf-8');
const jsonData = JSON.parse(fileContent);

const { reorderedData, isKeyOrderMismatched, mismatches } = reorderKeysInJson(jsonData);

if (isKeyOrderMismatched) {
warningsCount++;
if (shouldFix) {
fs.writeFileSync(filePath, JSON.stringify(reorderedData, null, 2), 'utf-8');
} else {
console.warn(chalk.yellow(`Warning: Key order mismatch in ${filePath}.`));

Check warning on line 114 in json-key-order-linter.js

View workflow job for this annotation

GitHub Actions / tests

Unexpected console statement
console.warn(chalk.red('Mismatched keys by path:'));

Check warning on line 115 in json-key-order-linter.js

View workflow job for this annotation

GitHub Actions / tests

Unexpected console statement
Object.entries(mismatches).forEach(([keyPath, keys]) => {
console.warn(chalk.cyan(` Path: ${keyPath.slice(1)}`));

Check warning on line 117 in json-key-order-linter.js

View workflow job for this annotation

GitHub Actions / tests

Unexpected console statement
console.warn(chalk.magenta(` Mismatched keys: ${keys.join(', ')}`));

Check warning on line 118 in json-key-order-linter.js

View workflow job for this annotation

GitHub Actions / tests

Unexpected console statement
console.warn();

Check warning on line 119 in json-key-order-linter.js

View workflow job for this annotation

GitHub Actions / tests

Unexpected console statement
});
}
}

if (!fileContent.endsWith('\n')) {
fileContent += '\n';
fs.writeFileSync(filePath, fileContent, 'utf-8');
}

processedFileCount++;
} catch (error) {
console.error(chalk.red(`Error processing file ${filePath}:`), error);

Check warning on line 131 in json-key-order-linter.js

View workflow job for this annotation

GitHub Actions / tests

Unexpected console statement
}
}
});
}

processJsonFilesInDirectory(folderPath);

let statusMessage;

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

console.log(statusMessage);

Check warning on line 149 in json-key-order-linter.js

View workflow job for this annotation

GitHub Actions / tests

Unexpected console statement
32 changes: 26 additions & 6 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"
}
}
}
}
}
12 changes: 9 additions & 3 deletions tokens/src/core/components/ActionRow.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@
"$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"
}
}
}
}
}
}
55 changes: 44 additions & 11 deletions tokens/src/core/components/Alert.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,63 @@
"$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"
}
}
}
}
}
}
39 changes: 31 additions & 8 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

0 comments on commit fba33c7

Please sign in to comment.