|
| 1 | +import groupBy from "just-group-by"; |
| 2 | + |
| 3 | +type SchemaData = { |
| 4 | + version: string; |
| 5 | + majorVersion: string; |
| 6 | + minorVersion: string; |
| 7 | + patchVersion: string; |
| 8 | + model: string; |
| 9 | + extension: string; |
| 10 | +}; |
| 11 | + |
| 12 | +/** |
| 13 | + * Parses a schema file path into its constituent parts: version (full, major, minor, patch), model, and extension. |
| 14 | + * Assumes the path is in the format "version/model.extension". |
| 15 | + * @param versionPath - The schema file path string (e.g., "1.2.3/MyModel.json"). |
| 16 | + * @returns A {@link SchemaData} object containing the parsed components. |
| 17 | + */ |
| 18 | +function formatVersionPath(versionPath: string): SchemaData { |
| 19 | + const [version, filename] = versionPath.split("/"); |
| 20 | + const [model, extension] = filename.split("."); |
| 21 | + |
| 22 | + const [majorVersion, minorVersion, patchVersion] = version.split("."); |
| 23 | + |
| 24 | + return { |
| 25 | + version, |
| 26 | + majorVersion, |
| 27 | + minorVersion, |
| 28 | + patchVersion, |
| 29 | + model, |
| 30 | + extension, |
| 31 | + }; |
| 32 | +} |
| 33 | + |
| 34 | +type SchemaGroup = { |
| 35 | + version: string; |
| 36 | + schemas: SchemaData[]; |
| 37 | +}; |
| 38 | + |
| 39 | +/** |
| 40 | + * Groups an array of {@link SchemaData} objects by a specified key. |
| 41 | + * |
| 42 | + * @template K - The key of {@link SchemaData} to group by. |
| 43 | + * @param schemas - The array of {@link SchemaData} objects to group. |
| 44 | + * @param key - The key from {@link SchemaData} to use for grouping (e.g., "majorVersion", "model"). |
| 45 | + * @returns An array of {@link SchemaGroup} objects. Each object contains a `version` property (the value of the group key) |
| 46 | + * and a `schemas` property (an array of {@link SchemaData} objects belonging to that group). |
| 47 | + */ |
| 48 | +function groupByKey<K extends keyof SchemaData>( |
| 49 | + schemas: SchemaData[], |
| 50 | + key: K, |
| 51 | +): SchemaGroup[] { |
| 52 | + const grouped = groupBy(schemas, (schema) => schema[key]); |
| 53 | + const groups = Object.entries<SchemaData[]>(grouped); |
| 54 | + |
| 55 | + return groups.map(([version, groupedSchemas]) => ({ |
| 56 | + version, |
| 57 | + schemas: groupedSchemas, |
| 58 | + })); |
| 59 | +} |
| 60 | + |
| 61 | +/** |
| 62 | + * Comparator function to sort an array of {@link SchemaGroup} objects by their `version` property in descending order. |
| 63 | + * @param a - The first {@link SchemaGroup} object for comparison. |
| 64 | + * @param b - The second {@link SchemaGroup} object for comparison. |
| 65 | + * @returns A number indicating the sort order. Negative if `b.version` comes before `a.version`, positive if `a.version` comes before `b.version`, zero if equal. |
| 66 | + */ |
| 67 | +function sortGroup(a: SchemaGroup, b: SchemaGroup): number { |
| 68 | + const aVersion = a.version; |
| 69 | + const bVersion = b.version; |
| 70 | + return bVersion.localeCompare(aVersion); |
| 71 | +} |
| 72 | + |
| 73 | +/** |
| 74 | + * Comparator function to sort an array of {@link SchemaData} objects by their `model` property in ascending alphabetical order. |
| 75 | + * @param a - The first {@link SchemaData} object for comparison. |
| 76 | + * @param b - The second {@link SchemaData} object for comparison. |
| 77 | + * @returns A number indicating the sort order. Negative if `a.model` comes before `b.model`, positive if `b.model` comes before `a.model`, zero if equal. |
| 78 | + */ |
| 79 | +function sortData(a: SchemaData, b: SchemaData): number { |
| 80 | + const aVersion = a.model; |
| 81 | + const bVersion = b.model; |
| 82 | + return aVersion.localeCompare(bVersion); |
| 83 | +} |
| 84 | + |
| 85 | +/** |
| 86 | + * Takes a flat list of schema file paths and groups them hierarchically by major, minor, and patch versions. |
| 87 | + * Schemas within each patch version are sorted by model name. |
| 88 | + * Minor and patch version groups are sorted in descending order. |
| 89 | + * @param schemaFiles - An array of schema file path strings (e.g., ["1.0.0/User.json", "1.0.1/Order.json"]). |
| 90 | + * @returns An array of objects, where each object represents a major version group. These groups contain nested minor version groups, |
| 91 | + * which in turn contain nested patch version groups. Each patch version group lists its {@link SchemaData} objects. |
| 92 | + */ |
| 93 | +export function getGroupedSchemaVersions(schemaFiles: string[]) { |
| 94 | + const schemas = schemaFiles.map(formatVersionPath); |
| 95 | + |
| 96 | + const majorVersions = groupByKey(schemas, "majorVersion").map((major) => { |
| 97 | + const majorVersion = major.version; |
| 98 | + const majorSchemas = groupByKey(major.schemas, "minorVersion").sort( |
| 99 | + sortGroup, |
| 100 | + ); |
| 101 | + |
| 102 | + return { |
| 103 | + version: majorVersion, |
| 104 | + schemas: majorSchemas.map((minor) => { |
| 105 | + const minorVersion = `${major.version}.${minor.version}.x`; |
| 106 | + const minorSchemas = groupByKey(minor.schemas, "patchVersion").sort( |
| 107 | + sortGroup, |
| 108 | + ); |
| 109 | + |
| 110 | + return { |
| 111 | + version: minorVersion, |
| 112 | + schemas: minorSchemas.map((patch) => { |
| 113 | + const patchVersion = `${major.version}.${minor.version}.${patch.version}`; |
| 114 | + |
| 115 | + return { |
| 116 | + version: patchVersion, |
| 117 | + schemas: patch.schemas.sort(sortData), |
| 118 | + }; |
| 119 | + }), |
| 120 | + }; |
| 121 | + }), |
| 122 | + }; |
| 123 | + }); |
| 124 | + |
| 125 | + return majorVersions; |
| 126 | +} |
0 commit comments