Scripts: automatically reorder layers and themes into the fixed order

This commit is contained in:
Pieter Vander Vennet 2025-07-05 02:03:39 +02:00
parent 40678a2eb3
commit 8761685fa6
4 changed files with 55 additions and 46 deletions

View file

@ -1,47 +1,14 @@
import ScriptUtils from "./ScriptUtils" import ScriptUtils from "./ScriptUtils"
import { writeFileSync } from "fs" import { writeFileSync } from "fs"
import { import { FixLegacyTheme, UpdateLegacyLayer } from "../src/Models/ThemeConfig/Conversion/LegacyJsonConvert"
FixLegacyTheme,
UpdateLegacyLayer,
} from "../src/Models/ThemeConfig/Conversion/LegacyJsonConvert"
import Translations from "../src/UI/i18n/Translations"
import { Translation } from "../src/UI/i18n/Translation"
import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson" import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson"
import themeconfig from "../src/assets/schemas/layoutconfigmeta.json"
import layerconfig from "../src/assets/schemas/layerconfigmeta.json"
import { Utils } from "../src/Utils"
import { ConfigMeta } from "../src/UI/Studio/configMeta"
import { ConversionContext } from "../src/Models/ThemeConfig/Conversion/ConversionContext" import { ConversionContext } from "../src/Models/ThemeConfig/Conversion/ConversionContext"
/* /*
* This script reads all theme and layer files and reformats them inplace * This script reads all theme and layer files and reformats them inplace
* Use with caution, make a commit beforehand! * Use with caution, make a commit beforehand!
*/ */
const themeAttributesOrder = Utils.Dedup(
(<ConfigMeta[]>themeconfig).filter((c) => c.path.length === 1).map((c) => c.path[0])
)
const layerAttributesOrder = Utils.Dedup(
(<ConfigMeta[]>layerconfig).filter((c) => c.path.length === 1).map((c) => c.path[0])
)
const t: Translation = Translations.t.general.add.addNew
t.OnEveryLanguage((txt, ln) => {
console.log(ln, txt)
return txt
})
function reorder(object: object, order: string[]) {
const allKeys = new Set<string>(Object.keys(object))
const copy = {}
for (const key of order) {
copy[key] = object[key]
allKeys.delete(key)
}
for (const key of allKeys) {
copy[key] = object[key]
}
return copy
}
const layerFiles = ScriptUtils.getLayerFiles() const layerFiles = ScriptUtils.getLayerFiles()
for (const layerFile of layerFiles) { for (const layerFile of layerFiles) {
@ -52,8 +19,7 @@ for (const layerFile of layerFiles) {
ConversionContext.construct([layerFile.path.split("/").at(-1)], ["update legacy"]) ConversionContext.construct([layerFile.path.split("/").at(-1)], ["update legacy"])
) )
) )
const reordered = reorder(fixed, layerAttributesOrder) writeFileSync(layerFile.path, JSON.stringify(fixed, null, " ") + "\n")
writeFileSync(layerFile.path, JSON.stringify(reordered, null, " ") + "\n")
} catch (e) { } catch (e) {
console.error("COULD NOT LINT LAYER" + layerFile.path + ":\n\t" + e) console.error("COULD NOT LINT LAYER" + layerFile.path + ":\n\t" + e)
} }
@ -69,10 +35,9 @@ for (const themeFile of themeFiles) {
// extractInlineLayer(fixed) // extractInlineLayer(fixed)
const endsWithNewline = themeFile.raw.at(-1) === "\n" const endsWithNewline = themeFile.raw.at(-1) === "\n"
const ordered = reorder(fixed, themeAttributesOrder)
writeFileSync( writeFileSync(
themeFile.path, themeFile.path,
JSON.stringify(ordered, null, " ") + (endsWithNewline ? "\n" : "") JSON.stringify(fixed, null, " ") + (endsWithNewline ? "\n" : "")
) )
} catch (e) { } catch (e) {
console.error("COULD NOT LINT THEME" + themeFile.path + ":\n\t" + e) console.error("COULD NOT LINT THEME" + themeFile.path + ":\n\t" + e)

View file

@ -32,6 +32,7 @@ import { ExpandRewrite } from "./ExpandRewrite"
import { TagUtils } from "../../../Logic/Tags/TagUtils" import { TagUtils } from "../../../Logic/Tags/TagUtils"
import { ExpandFilter, PruneFilters } from "./ExpandFilter" import { ExpandFilter, PruneFilters } from "./ExpandFilter"
import { ExpandTagRendering } from "./ExpandTagRendering" import { ExpandTagRendering } from "./ExpandTagRendering"
import layerconfig from "../../../assets/schemas/layerconfigmeta.json"
class AddFiltersFromTagRenderings extends DesugaringStep<LayerConfigJson> { class AddFiltersFromTagRenderings extends DesugaringStep<LayerConfigJson> {
constructor() { constructor() {
@ -1077,6 +1078,20 @@ class DeriveSource extends DesugaringStep<LayerConfigJson> {
} }
} }
class OrderLayer extends DesugaringStep<LayerConfigJson>{
private static readonly layerAttributesOrder: ReadonlyArray<string> = Utils.Dedup(
(<ConfigMeta[]>layerconfig).filter((c) => c.path.length === 1).map((c) => c.path[0])
)
constructor() {
super("OrderLayer", "Reorders the layer to the default order")
}
public convert(json: LayerConfigJson, context: ConversionContext): LayerConfigJson {
return Utils.reorder(json, OrderLayer.layerAttributesOrder)
}
}
export class PrepareLayer extends Fuse<LayerConfigJson> { export class PrepareLayer extends Fuse<LayerConfigJson> {
constructor( constructor(
state: DesugaringContext, state: DesugaringContext,
@ -1125,7 +1140,8 @@ export class PrepareLayer extends Fuse<LayerConfigJson> {
new AddFiltersFromTagRenderings(), new AddFiltersFromTagRenderings(),
new ExpandFilter(state), new ExpandFilter(state),
new MoveUnitConfigs(), new MoveUnitConfigs(),
new PruneFilters() new PruneFilters(),
new OrderLayer()
) )
} }

View file

@ -20,6 +20,8 @@ import DependencyCalculator from "../DependencyCalculator"
import { AddContextToTranslations } from "./AddContextToTranslations" import { AddContextToTranslations } from "./AddContextToTranslations"
import ValidationUtils from "./ValidationUtils" import ValidationUtils from "./ValidationUtils"
import { ConversionContext } from "./ConversionContext" import { ConversionContext } from "./ConversionContext"
import { ConfigMeta } from "../../../UI/Studio/configMeta"
import themeconfig from "../../../assets/schemas/layoutconfigmeta.json"
class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJson[]> { class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJson[]> {
private readonly _state: DesugaringContext private readonly _state: DesugaringContext
@ -28,7 +30,6 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
super( super(
"SubstituteLayer", "SubstituteLayer",
"Converts the identifier of a builtin layer into the actual layer, or converts a 'builtin' syntax with override in the fully expanded form. Note that 'tagRenderings+' will be inserted before 'leftover-questions'", "Converts the identifier of a builtin layer into the actual layer, or converts a 'builtin' syntax with override in the fully expanded form. Note that 'tagRenderings+' will be inserted before 'leftover-questions'",
[]
) )
this._state = state this._state = state
} }
@ -73,13 +74,10 @@ class SubstituteLayer extends Conversion<string | LayerConfigJson, LayerConfigJs
if (found === undefined) { if (found === undefined) {
const nearbyNames = Utils.sortedByLevenshteinDistance(name, Array.from(state.sharedLayers.keys())) const nearbyNames = Utils.sortedByLevenshteinDistance(name, Array.from(state.sharedLayers.keys()))
context.err("Layer with name " + name + " not found. Dit you mean one of "+nearbyNames.slice(0, 3)) context.err("Layer with name " + name + " not found. Dit you mean one of "+nearbyNames.slice(0, 3))
continue
}
found["_basedOn"] = name
if (found === undefined) {
reportNotFound(name) reportNotFound(name)
continue continue
} }
found["_basedOn"] = name
if ( if (
json["override"]["tagRenderings"] !== undefined && json["override"]["tagRenderings"] !== undefined &&
(found["tagRenderings"] ?? []).length > 0 (found["tagRenderings"] ?? []).length > 0
@ -605,7 +603,20 @@ class PostvalidateTheme extends DesugaringStep<ThemeConfigJson> {
return json return json
} }
} }
class OrderTheme extends DesugaringStep<ThemeConfigJson>{
private static readonly themeAttributesOrder: ReadonlyArray<string> = Utils.Dedup(
(<ConfigMeta[]>themeconfig).filter((c) => c.path.length === 1).map((c) => c.path[0])
)
constructor() {
super("OrderLayer", "Reorders the layer to the default order")
}
public convert(json: ThemeConfigJson, context: ConversionContext): ThemeConfigJson {
return Utils.reorder(json, OrderTheme.themeAttributesOrder)
}
}
export class PrepareTheme extends Fuse<ThemeConfigJson> { export class PrepareTheme extends Fuse<ThemeConfigJson> {
private state: DesugaringContext private state: DesugaringContext
@ -646,7 +657,8 @@ export class PrepareTheme extends Fuse<ThemeConfigJson> {
: new AddDefaultLayers(state), : new AddDefaultLayers(state),
new AddDependencyLayersToTheme(state), new AddDependencyLayersToTheme(state),
// new AddImportLayers(), // new AddImportLayers(),
new PostvalidateTheme(state) new PostvalidateTheme(state),
new OrderTheme()
) )
this.state = state this.state = state
} }

View file

@ -1229,6 +1229,8 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
* @param x * @param x
* @constructor * @constructor
*/ */
static Clone<T>(x: Readonly<T>): T
static Clone<T>(x: T): T
static Clone<T>(x: T): T { static Clone<T>(x: T): T {
if (x === undefined) { if (x === undefined) {
return undefined return undefined
@ -1267,7 +1269,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
reference: string, reference: string,
ts: ReadonlyArray<T>, ts: ReadonlyArray<T>,
getName: (t: T) => string getName: (t: T) => string
): string[] ): T[]
public static sortedByLevenshteinDistance<T>( public static sortedByLevenshteinDistance<T>(
reference: string, reference: string,
ts: ReadonlyArray<T>, ts: ReadonlyArray<T>,
@ -1841,4 +1843,18 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
public static concat<T>(param: T[][]): T[] { public static concat<T>(param: T[][]): T[] {
return [].concat(...param) return [].concat(...param)
} }
public static reorder<T extends object>(object: T, order: ReadonlyArray<string>): T {
const allKeys = new Set<string>(Object.keys(object))
const copy = {}
for (const key of order) {
copy[key] = object[key]
allKeys.delete(key)
}
for (const key of allKeys) {
copy[key] = object[key]
}
return <T> copy
}
} }