From dbd11599c49c72fff213c26df54a49316a6c8a63 Mon Sep 17 00:00:00 2001 From: RudyTheDev <3857299+RudyTheDev@users.noreply.github.com> Date: Mon, 11 May 2026 13:03:50 +0300 Subject: [PATCH 1/3] Add a new segregatedCombo field type with additional fallbackKey key --- schemas/field.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/schemas/field.json b/schemas/field.json index 4e0d218..b9693cc 100644 --- a/schemas/field.json +++ b/schemas/field.json @@ -76,6 +76,7 @@ "roadheight", "roadspeed", "schedule", + "segregatedCombo", "semiCombo", "structureRadio", "tel", @@ -210,6 +211,10 @@ "minimum": 1, "type": "integer" }, + "fallbackKey": { + "description": "The field that is shown instead when this field's visibility requirements are not met", + "type": "string" + }, "prerequisiteTag": { "description": "Tagging constraint for showing this field in the editor", "oneOf": [ @@ -379,9 +384,9 @@ { "not": { "required": ["keys"] }} ]}, { "$id": "field-type-with-key-optional-keys", "properties": { "type": { "enum": ["email", "url", "tel", "text", "number"] } }, "required": ["key"] }, - { "$id": "field-type-with-key-and-keys", "properties": { "type": { "enum": ["address", "wikipedia", "wikidata", "directionalCombo"] } }, "required": ["key", "keys"] }, + { "$id": "field-type-with-key-and-keys", "properties": { "type": { "enum": ["address", "wikipedia", "wikidata", "directionalCombo", "segregatedCombo"] } }, "required": ["key", "keys"] }, { "$id": "field-type-with-key-or-keys", "allOf": [ - { "not": { "properties": { "type": { "enum": ["restriction", "email", "url", "tel", "text", "number", "address", "wikipedia", "wikidata", "directionalCombo"] } } } }, + { "not": { "properties": { "type": { "enum": ["restriction", "email", "url", "tel", "text", "number", "address", "wikipedia", "wikidata", "directionalCombo", "segregatedCombo"] } } } }, { "oneOf": [ { "required": ["key"] }, { "required": ["keys"] } From 3d1146df142b8df17693bd06566b5ab586e046cd Mon Sep 17 00:00:00 2001 From: RudyTheDev <3857299+RudyTheDev@users.noreply.github.com> Date: Mon, 11 May 2026 13:03:58 +0300 Subject: [PATCH 2/3] Verify that preset field fallback fields exist and are not double-declared in the preset fields --- lib/build.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/build.js b/lib/build.js index 4bdd914..f652694 100644 --- a/lib/build.js +++ b/lib/build.js @@ -946,6 +946,30 @@ function validatePresetFields(presets, fields) { } } + // Check that no field with a fallbackKey has its fallback field also explicitly listed, + // and that fallbackKey references are valid fields + let allPresetFieldIDs = new Set([ + ...(preset.fields || []), + ...(preset.moreFields || []) + ]); + for (let fieldID of allPresetFieldIDs) { + let field = fields[fieldID]; + if (!field?.fallbackKey) continue; + + let fallbackField = fields[field.fallbackKey]; + if (!fallbackField) { + process.stderr.write('Unknown fallback field "' + field.fallbackKey + '" referenced by field "' + fieldID + '" in preset "' + presetID + '" (' + preset.name + ')\n'); + process.stdout.write('\n'); + process.exit(1); + } + + if (allPresetFieldIDs.has(field.fallbackKey)) { + process.stderr.write('The preset "' + presetID + '" includes repeated field "' + field.fallbackKey + '" already implicitly included by field "' + fieldID + '" as a fallback field\n'); + process.stdout.write('\n'); + process.exit(1); + } + } + if (preset.fields) { // since `moreFields` is available, check that `fields` doesn't get too cluttered let fieldCount = preset.fields.length; From 2eb4799fb6debef0e15989c54456b36f4342e5aa Mon Sep 17 00:00:00 2001 From: RudyTheDev <3857299+RudyTheDev@users.noreply.github.com> Date: Tue, 12 May 2026 13:21:50 +0300 Subject: [PATCH 3/3] Ensure fallback keys do not fall back more than once --- lib/build.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/build.js b/lib/build.js index f652694..7706891 100644 --- a/lib/build.js +++ b/lib/build.js @@ -990,12 +990,23 @@ function validatePresetFields(presets, fields) { } } } - + for (let fieldID in fields) { + let field = fields[fieldID]; + if (!usedFieldIDs.has(fieldID) && - fields[fieldID].universal !== true && - (fields[fieldID].usage || 'preset') === 'preset') { - process.stdout.write('Field "' + fields[fieldID].label + '" (' + fieldID + ') isn\'t used by any presets.\n'); + field.universal !== true && + (field.usage || 'preset') === 'preset') { + process.stdout.write('Field "' + field.label + '" (' + fieldID + ') isn\'t used by any presets.\n'); + } + + if (field.fallbackKey) { + let fallbackField = fields[field.fallbackKey]; + if (fallbackField?.fallbackKey) { + process.stderr.write('Field "' + field.fallbackKey + '" is used as a fallback by field "' + fieldID + '" but itself has a fallbackKey "' + fallbackField.fallbackKey + '". Recursive fallback fields are not allowed.\n'); + process.stdout.write('\n'); + process.exit(1); + } } } }